KekikStream 2.4.8__py3-none-any.whl → 2.4.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,55 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
4
+ import json, re
5
+
6
+ class JetV(ExtractorBase):
7
+ name = "JetV"
8
+ main_url = "https://jetv.xyz"
9
+
10
+ async def extract(self, url: str, referer: str = None) -> list[ExtractResult]:
11
+ istek = await self.httpx.get(url, headers={"Referer": referer} if referer else None)
12
+ text = istek.text
13
+
14
+ # Script içindeki sources kısmını bul
15
+ # "sources": [ ... ]
16
+ sources_str = HTMLHelper(text).regex_first(r'"sources":\s*(\[.*?\])')
17
+ if not sources_str:
18
+ # Altenatif: sources: [ ... ] (tırnaksız sources)
19
+ sources_str = HTMLHelper(text).regex_first(r'sources:\s*(\[.*?\])')
20
+
21
+ if not sources_str:
22
+ raise ValueError(f"JetV: Sources bulunamadı. {url}")
23
+
24
+ # file: -> "file":
25
+ clean_json = re.sub(r'(\w+):', r'"\1":', sources_str)
26
+ # ' -> "
27
+ clean_json = clean_json.replace("'", '"')
28
+
29
+ try:
30
+ sources = json.loads(clean_json)
31
+ except:
32
+ # Basit parser yetmediyse, manuel parse deneyelim (tek kaynak varsa)
33
+ file_url = HTMLHelper(sources_str).regex_first(r'file["\']?:\s*["\']([^"\']+)["\']')
34
+ label = HTMLHelper(sources_str).regex_first(r'label["\']?:\s*["\']([^"\']+)["\']')
35
+ if file_url:
36
+ sources = [{"file": file_url, "label": label or "Unknown"}]
37
+ else:
38
+ raise ValueError("JetV: JSON parse hatası")
39
+
40
+ results = []
41
+ for source in sources:
42
+ file_path = source.get("file")
43
+ label = source.get("label", "Unknown")
44
+
45
+ if not file_path:
46
+ continue
47
+
48
+ results.append(ExtractResult(
49
+ name = f"{self.name} | {label}",
50
+ url = self.fix_url(file_path),
51
+ referer = url,
52
+ user_agent = self.httpx.headers.get("User-Agent", "")
53
+ ))
54
+
55
+ return results
@@ -0,0 +1,145 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
4
+ from contextlib import suppress
5
+
6
+ class Veev(ExtractorBase):
7
+ name = "Veev"
8
+ main_url = "https://veev.to"
9
+
10
+ supported_domains = ["veev.to", "kinoger.to", "poophq.com", "doods.pro", "dood.so", "dood.li", "dood.wf", "dood.cx", "dood.sh", "dood.watch", "dood.pm", "dood.to", "dood.ws"]
11
+
12
+ def can_handle_url(self, url: str) -> bool:
13
+ return any(domain in url for domain in self.supported_domains)
14
+
15
+ def veev_decode(self, encoded: str) -> str:
16
+ if not encoded:
17
+ return ""
18
+
19
+ result = []
20
+ # Python dictionary key integer, value string
21
+ # Başlangıçta 0-255 ascii karakterleri
22
+ lut = {i: chr(i) for i in range(256)}
23
+ n = 256
24
+
25
+ c = encoded[0]
26
+ result.append(c)
27
+
28
+ for char in encoded[1:]:
29
+ code = ord(char)
30
+ if code < 256:
31
+ nc = char
32
+ else:
33
+ nc = lut.get(code, c + c[0])
34
+
35
+ result.append(nc)
36
+ lut[n] = c + nc[0]
37
+ n += 1
38
+ c = nc
39
+
40
+ return "".join(result)
41
+
42
+ def build_array(self, encoded: str) -> list[list[int]]:
43
+ result = []
44
+ iterator = iter(encoded)
45
+
46
+ def next_int_or_zero():
47
+ try:
48
+ char = next(iterator)
49
+ if char.isdigit():
50
+ return int(char)
51
+ return 0
52
+ except StopIteration:
53
+ return 0
54
+
55
+ count = next_int_or_zero()
56
+ while count != 0:
57
+ row = []
58
+ for _ in range(count):
59
+ row.append(next_int_or_zero())
60
+ result.append(list(reversed(row)))
61
+ count = next_int_or_zero()
62
+
63
+ return result
64
+
65
+ def decode_url(self, encoded: str, rules: list[int]) -> str:
66
+ text = encoded
67
+ for r in rules:
68
+ if r == 1:
69
+ text = text[::-1]
70
+
71
+ # Hex decode
72
+ with suppress(Exception):
73
+ # remove optional whitespace just in case
74
+ clean_hex = "".join(text.split())
75
+ arr = bytes.fromhex(clean_hex)
76
+ # utf-8 decode, replace errors
77
+ text = arr.decode('utf-8', errors='replace')
78
+
79
+ text = text.replace("dXRmOA==", "")
80
+
81
+ return text
82
+
83
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
84
+ # URL'den ID çıkar
85
+ # https://veev.to/e/lla8v3k6arev
86
+ video_id = url.split("/")[-1]
87
+
88
+ # Sayfayı al
89
+ # Referer lazım mı? Genelde lazım olabilir.
90
+ page_url = f"{self.main_url}/e/{video_id}"
91
+ resp = await self.httpx.get(page_url, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"})
92
+ html = resp.text
93
+
94
+ # Regex ile şifreli stringleri bul
95
+ # Regex: [.\s'](?:fc|_vvto\[[^]]*)(?:['\]]*)?\s*[:=]\s*['"]([^'"]+)
96
+ # Python regex için düzenleme gerekebilir.
97
+ found_values = HTMLHelper(html).regex_all(r"[.\s'](?:fc|_vvto\[[^]]*)(?:['\]]*)?\s*[:=]\s*['\"]([^'\"]+)")
98
+
99
+ if not found_values:
100
+ raise ValueError(f"Veev: Token bulunamadı. {url}")
101
+
102
+ # Kotlin kodunda sondan başlayıp deniyor (reversed)
103
+ for f in reversed(found_values):
104
+ try:
105
+ ch = self.veev_decode(f)
106
+ if ch == f:
107
+ continue # Decode olmadıysa geç
108
+
109
+ # API Call
110
+ dl_url = f"{self.main_url}/dl?op=player_api&cmd=gi&file_code={video_id}&r={self.main_url}&ch={ch}&ie=1"
111
+ api_resp = await self.httpx.get(dl_url, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"})
112
+
113
+ data = api_resp.json()
114
+ file_obj = data.get("file")
115
+ if not file_obj or file_obj.get("file_status") != "OK":
116
+ continue
117
+
118
+ dv = file_obj.get("dv")
119
+ # dv json string içinde s key'inde olabilir (Kotlin: getString("s"))
120
+ # Ancak api yanıtını görmeden emin olamayız, json yapısına göre file->dv bir string mi object mi?
121
+ # Kotlin: file.getJSONArray("dv").getJSONObject(0).getString("s")
122
+ # Demek ki dv bir array
123
+
124
+ encoded_dv = None
125
+ if isinstance(dv, list) and len(dv) > 0:
126
+ if isinstance(dv[0], dict):
127
+ encoded_dv = dv[0].get("s")
128
+
129
+ if not encoded_dv:
130
+ continue
131
+
132
+ # Decode
133
+ # rules = buildArray(ch)[0]
134
+ rules = self.build_array(ch)[0]
135
+
136
+ final_url = self.decode_url(self.veev_decode(encoded_dv), rules)
137
+
138
+ if final_url.startswith("http"):
139
+ return ExtractResult(name=self.name, url=self.fix_url(final_url), referer=self.main_url)
140
+
141
+ except Exception as e:
142
+ # print(f"Veev Error: {e}")
143
+ continue
144
+
145
+ raise ValueError(f"Veev: Video URL'si çözülemedi. {url}")
@@ -0,0 +1,62 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
4
+ from Kekik.Sifreleme import Packer
5
+
6
+ class VidBiz(ExtractorBase):
7
+ name = "VidBiz"
8
+ main_url = "https://videolar.biz"
9
+
10
+ async def extract(self, url: str, referer: str = None) -> list[ExtractResult]:
11
+ istek = await self.httpx.get(url, headers={"Referer": referer} if referer else None)
12
+ text = istek.text
13
+
14
+ # Eval script bul (kaken içeriyor olmalı)
15
+ eval_script = HTMLHelper(text).regex_first(r'(eval\(function[\s\S]+?)<\/script>') or \
16
+ HTMLHelper(text).regex_first(r'(eval\(function[\s\S]+)')
17
+ if not eval_script:
18
+ raise ValueError(f"VidBiz: Packed script bulunamadı. {url}")
19
+
20
+ unpacked = ""
21
+ try:
22
+ unpacked = Packer.unpack(eval_script)
23
+ except:
24
+ raise ValueError("VidBiz: Unpack hatası")
25
+
26
+ # window.kaken="..."
27
+ kaken = HTMLHelper(unpacked).regex_first(r'window\.kaken\s*=\s*"([^"]+)"')
28
+ if not kaken:
29
+ raise ValueError("VidBiz: Kaken token bulunamadı")
30
+
31
+ # API POST
32
+ # Content-Type: text/plain önemli olabilir
33
+ resp = await self.httpx.post(
34
+ url = "https://s2.videolar.biz/api/",
35
+ content = kaken, # data yerine content=raw string
36
+ headers = {"Content-Type": "text/plain", "Referer": url}
37
+ )
38
+
39
+ try:
40
+ data = resp.json()
41
+ except:
42
+ raise ValueError("VidBiz: API yanıtı JSON değil")
43
+
44
+ if data.get("status") != "ok":
45
+ raise ValueError(f"VidBiz: API hatası {data}")
46
+
47
+ results = []
48
+ for source in data.get("sources", []):
49
+ file_url = source.get("file")
50
+ label = source.get("label", "Unknown")
51
+
52
+ if not file_url:
53
+ continue
54
+
55
+ results.append(ExtractResult(
56
+ name = f"{self.name} | {label}",
57
+ url = self.fix_url(file_url),
58
+ referer = url,
59
+ user_agent = self.httpx.headers.get("User-Agent", "")
60
+ ))
61
+
62
+ return results
@@ -9,7 +9,16 @@ class VidHide(ExtractorBase):
9
9
  main_url = "https://vidhidepro.com"
10
10
 
11
11
  # Birden fazla domain destekle
12
- supported_domains = ["vidhidepro.com", "vidhide.com", "rubyvidhub.com"]
12
+ supported_domains = [
13
+ "vidhidepro.com", "vidhide.com", "rubyvidhub.com",
14
+ "vidhidevip.com", "vidhideplus.com", "vidhidepre.com",
15
+ "movearnpre.com", "oneupload.to",
16
+ "filelions.live", "filelions.online", "filelions.to",
17
+ "kinoger.be",
18
+ "smoothpre.com",
19
+ "dhtpre.com",
20
+ "peytonepre.com"
21
+ ]
13
22
 
14
23
  def can_handle_url(self, url: str) -> bool:
15
24
  return any(domain in url for domain in self.supported_domains)
@@ -21,6 +30,8 @@ class VidHide(ExtractorBase):
21
30
  return url.replace("/download/", "/v/")
22
31
  elif "/file/" in url:
23
32
  return url.replace("/file/", "/v/")
33
+ elif "/embed/" in url:
34
+ return url.replace("/embed/", "/v/")
24
35
  else:
25
36
  return url.replace("/f/", "/v/")
26
37
 
@@ -32,18 +43,56 @@ class VidHide(ExtractorBase):
32
43
  })
33
44
 
34
45
  embed_url = self.get_embed_url(url)
35
- istek = await self.httpx.get(embed_url)
36
- sel = HTMLHelper(istek.text)
46
+ istek = await self.httpx.get(embed_url, follow_redirects=True)
47
+ text = istek.text
48
+
49
+ # Silinmiş dosya kontrolü
50
+ if "File is no longer available" in text or "File Not Found" in text:
51
+ raise ValueError(f"VidHide: Video silinmiş. {url}")
52
+
53
+ # JS Redirect Kontrolü (OneUpload vb.)
54
+ if js_redirect := HTMLHelper(text).regex_first(r"window\.location\.replace\(['\"]([^'\"]+)['\"]\)") or \
55
+ HTMLHelper(text).regex_first(r"window\.location\.href\s*=\s*['\"]([^'\"]+)['\"]"):
56
+ # Redirect url'i al
57
+ target_url = js_redirect
58
+ # Bazen path relative olabilir ama genelde full url
59
+ if not target_url.startswith("http"):
60
+ # urljoin gerekebilir ama şimdilik doğrudan deneyelim veya fix_url
61
+ target_url = self.fix_url(target_url) # fix_url base'e göre düzeltebilir mi? ExtractorBase.fix_url genelde şema ekler.
62
+ pass
63
+
64
+ # Yeniden istek at
65
+ istek = await self.httpx.get(target_url, headers={"Referer": embed_url}, follow_redirects=True)
66
+ text = istek.text
67
+
68
+ sel = HTMLHelper(text)
37
69
 
38
70
  unpacked = ""
39
- if "eval(function" in istek.text:
71
+ # Eval script bul (regex ile daha sağlam)
72
+ if eval_match := sel.regex_first(r'(eval\s*\(\s*function[\s\S]+?)<\/script>'):
40
73
  try:
41
- unpacked = Packer.unpack(istek.text)
74
+ unpacked = Packer.unpack(eval_match)
75
+ if "var links" in unpacked:
76
+ unpacked = unpacked.split("var links")[1]
42
77
  except:
43
78
  pass
44
79
 
45
- content = unpacked or istek.text
46
- m3u8_url = HTMLHelper(content).regex_first(r'[:"]\s*["\']([^"\']+\.m3u8[^"\']*)["\']')
80
+ content = unpacked or text
81
+
82
+ # Regex: Kotlin mantığı (: "url")
83
+ # Ayrıca sources: [...] mantığını da ekle
84
+ m3u8_url = HTMLHelper(content).regex_first(r'sources:\s*\[\s*\{\s*file:\s*"([^"]+)"')
85
+
86
+ if not m3u8_url:
87
+ # Genel arama (hls:, file: vb.)
88
+ # Kotlin Regex: :\s*"(.*?m3u8.*?)"
89
+ match = HTMLHelper(content).regex_first(r':\s*["\']([^"\']+\.m3u8[^"\']*)["\']')
90
+ if match:
91
+ m3u8_url = match
92
+
93
+ if not m3u8_url:
94
+ # Son şans: herhangi bir m3u8 linki
95
+ m3u8_url = HTMLHelper(content).regex_first(r'["\']([^"\']+\.m3u8[^"\']*)["\']')
47
96
 
48
97
  if not m3u8_url:
49
98
  raise ValueError(f"VidHide: Video URL bulunamadı. {url}")
@@ -0,0 +1,38 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
4
+ from Kekik.Sifreleme import Packer
5
+
6
+ class Vtbe(ExtractorBase):
7
+ name = "Vtbe"
8
+ main_url = "https://vtbe.to"
9
+
10
+ async def extract(self, url: str, referer: str = None) -> list[ExtractResult]:
11
+ # Iframe ise embed url'i düzeltmek gerekebilir ama genelde embed-xxxx.html formatı
12
+ istek = await self.httpx.get(url, headers={"Referer": referer or self.main_url})
13
+ text = istek.text
14
+
15
+ # Packed script bul: function(p,a,c,k,e,d)
16
+ packed = HTMLHelper(text).regex_first(r'(eval\s*\(\s*function[\s\S]+?)<\/script>')
17
+
18
+ if not packed:
19
+ raise ValueError(f"Vtbe: Packed script bulunamadı. {url}")
20
+
21
+ unpacked = ""
22
+ try:
23
+ unpacked = Packer.unpack(packed)
24
+ except:
25
+ raise ValueError("Vtbe: Unpack hatası")
26
+
27
+ # sources:[{file:"..."
28
+ file_url = HTMLHelper(unpacked).regex_first(r'sources:\s*\[\s*\{\s*file:\s*"([^"]+)"')
29
+
30
+ if not file_url:
31
+ raise ValueError("Vtbe: Video URL (file) bulunamadı")
32
+
33
+ return ExtractResult(
34
+ name = self.name,
35
+ url = self.fix_url(file_url),
36
+ referer = url,
37
+ user_agent = self.httpx.headers.get("User-Agent", "")
38
+ )
@@ -0,0 +1,61 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
4
+
5
+ class Zeus(ExtractorBase):
6
+ name = "Zeus"
7
+ main_url = "https://d2rs.com"
8
+
9
+ async def extract(self, url: str, referer: str = None) -> list[ExtractResult]:
10
+ # Iframe içeriğini al
11
+ istek = await self.httpx.get(url, headers={"Referer": referer} if referer else None)
12
+ text = istek.text
13
+
14
+ # 'q' parametresini bul
15
+ # form.append("q", "...")
16
+ q_param = HTMLHelper(text).regex_first(r'form\.append\("q",\s*"([^"]+)"\)')
17
+
18
+ if not q_param:
19
+ raise ValueError(f"Zeus: 'q' parametresi bulunamadı. {url}")
20
+
21
+ # API'ye POST at
22
+ resp = await self.httpx.post(
23
+ url = "https://d2rs.com/zeus/api.php",
24
+ data = {"q": q_param},
25
+ headers = {"Referer": url}
26
+ )
27
+
28
+ try:
29
+ sources = resp.json()
30
+ except:
31
+ raise ValueError("Zeus: API yanıtı geçersiz JSON")
32
+
33
+ results = []
34
+ # [{"file": "...", "label": "Full HD", "type": "video/mp4"}, ...]
35
+ for i, source in enumerate(sources, 1):
36
+ file_path = source.get("file")
37
+ label = source.get("label") or ""
38
+ type_ = source.get("type", "")
39
+
40
+ if not file_path:
41
+ continue
42
+
43
+ full_url = f"https://d2rs.com/zeus/{file_path}"
44
+
45
+ # İsimlendirme
46
+ if label:
47
+ source_name = f"{self.name} | {label}"
48
+ else:
49
+ source_name = f"{self.name} | Kaynak {i}"
50
+
51
+ results.append(ExtractResult(
52
+ name = source_name,
53
+ url = self.fix_url(full_url),
54
+ referer = url,
55
+ user_agent = self.httpx.headers.get("User-Agent", "")
56
+ ))
57
+
58
+ if not results:
59
+ raise ValueError("Zeus: Kaynak bulunamadı")
60
+
61
+ return results
@@ -12,20 +12,43 @@ class HDFilmCehennemi(PluginBase):
12
12
  description = "Türkiye'nin en hızlı hd film izleme sitesi. Tek ve gerçek hdfilmcehennemi sitesi."
13
13
 
14
14
  main_page = {
15
- f"{main_url}" : "Yeni Eklenen Filmler",
16
- f"{main_url}/yabancidiziizle-2" : "Yeni Eklenen Diziler",
17
- f"{main_url}/category/tavsiye-filmler-izle2" : "Tavsiye Filmler",
18
- f"{main_url}/imdb-7-puan-uzeri-filmler" : "IMDB 7+ Filmler",
19
- f"{main_url}/en-cok-yorumlananlar-1" : "En Çok Yorumlananlar",
20
- f"{main_url}/en-cok-begenilen-filmleri-izle" : "En Çok Beğenilenler",
21
- f"{main_url}/tur/aile-filmleri-izleyin-6" : "Aile Filmleri",
22
- f"{main_url}/tur/aksiyon-filmleri-izleyin-3" : "Aksiyon Filmleri",
23
- f"{main_url}/tur/animasyon-filmlerini-izleyin-4" : "Animasyon Filmleri",
24
- f"{main_url}/tur/belgesel-filmlerini-izle-1" : "Belgesel Filmleri",
25
- f"{main_url}/tur/bilim-kurgu-filmlerini-izleyin-2" : "Bilim Kurgu Filmleri",
26
- f"{main_url}/tur/komedi-filmlerini-izleyin-1" : "Komedi Filmleri",
27
- f"{main_url}/tur/korku-filmlerini-izle-2/" : "Korku Filmleri",
28
- f"{main_url}/tur/romantik-filmleri-izle-1" : "Romantik Filmleri"
15
+ f"{main_url}" : "Yeni Eklenen Filmler",
16
+ f"{main_url}/yabancidiziizle-5" : "Yeni Eklenen Diziler",
17
+ f"{main_url}/dil/turkce-dublajli-film-izleyin-5" : "Türkçe Dublaj Filmler",
18
+ f"{main_url}/dil/turkce-altyazili-filmleri-izleme-sitesi-3" : "Türkçe Altyazılı Filmler",
19
+ f"{main_url}/category/tavsiye-filmler-izle3" : "Tavsiye Filmler",
20
+ f"{main_url}/imdb-7-puan-uzeri-filmler-2" : "IMDB 7+ Filmler",
21
+ f"{main_url}/en-cok-yorumlananlar-2" : "En Çok Yorumlananlar",
22
+ f"{main_url}/en-cok-begenilen-filmleri-izle-4" : "En Çok Beğenilenler",
23
+ f"{main_url}/serifilmlerim-4" : "Seri Filmler",
24
+ f"{main_url}/category/nette-ilk-filmler" : "Nette İlk Filmler",
25
+ f"{main_url}/category/4k-film-izle-5" : "4K Filmler",
26
+ f"{main_url}/category/1080p-hd-film-izle-5" : "1080p Filmler",
27
+ f"{main_url}/category/amazon-yapimlarini-izle" : "Amazon Yapımları",
28
+ f"{main_url}/category/netflix-yapimlari-izle" : "Netflix Yapımları",
29
+ f"{main_url}/category/marvel-yapimlarini-izle-5" : "Marvel Filmleri",
30
+ f"{main_url}/category/dc-yapimlarini-izle-1" : "DC Filmleri",
31
+ f"{main_url}/tur/aile-filmleri-izleyin-7" : "Aile Filmleri",
32
+ f"{main_url}/tur/aksiyon-filmleri-izleyin-6" : "Aksiyon Filmleri",
33
+ f"{main_url}/tur/animasyon-filmlerini-izleyin-5" : "Animasyon Filmleri",
34
+ f"{main_url}/tur/belgesel-filmlerini-izle-2" : "Belgesel Filmleri",
35
+ f"{main_url}/tur/bilim-kurgu-filmlerini-izleyin-5" : "Bilim Kurgu Filmleri",
36
+ f"{main_url}/tur/biyografi-filmleri-izle-3" : "Biyografi Filmleri",
37
+ f"{main_url}/tur/dram-filmlerini-izle-2" : "Dram Filmleri",
38
+ f"{main_url}/tur/fantastik-filmlerini-izleyin-3" : "Fantastik Filmleri",
39
+ f"{main_url}/tur/gerilim-filmlerini-izle-2" : "Gerilim Filmleri",
40
+ f"{main_url}/tur/gizem-filmleri-izle-3" : "Gizem Filmleri",
41
+ f"{main_url}/tur/komedi-filmlerini-izleyin-2" : "Komedi Filmleri",
42
+ f"{main_url}/tur/korku-filmlerini-izle-5" : "Korku Filmleri",
43
+ f"{main_url}/tur/macera-filmlerini-izleyin-4" : "Macera Filmleri",
44
+ f"{main_url}/tur/muzik-filmlerini-izle-844" : "Müzik Filmleri",
45
+ f"{main_url}/tur/polisiye-filmleri-izle" : "Polisiye Filmleri",
46
+ f"{main_url}/tur/romantik-filmleri-izle-3" : "Romantik Filmleri",
47
+ f"{main_url}/tur/savas-filmleri-izle-5" : "Savaş Filmleri",
48
+ f"{main_url}/tur/spor-filmleri-izle-3" : "Spor Filmleri",
49
+ f"{main_url}/tur/suc-filmleri-izle-3" : "Suç Filmleri",
50
+ f"{main_url}/tur/tarih-filmleri-izle-5" : "Tarih Filmleri",
51
+ f"{main_url}/tur/western-filmleri-izle-3" : "Western Filmleri"
29
52
  }
30
53
 
31
54
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
@@ -1,6 +1,7 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult, HTMLHelper
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult, HTMLHelper
4
+ import asyncio
4
5
 
5
6
  class JetFilmizle(PluginBase):
6
7
  name = "JetFilmizle"
@@ -42,17 +43,15 @@ class JetFilmizle(PluginBase):
42
43
 
43
44
  results = []
44
45
  for veri in secici.select("article.movie"):
45
- # h2-h6 içindeki a linki
46
46
  title_text = None
47
47
  for h_tag in ["h2", "h3", "h4", "h5", "h6"]:
48
48
  title_text = secici.select_text(f"{h_tag} a", veri)
49
49
  if title_text:
50
50
  break
51
51
 
52
- href = secici.select_attr("a", "href", veri)
53
- poster = secici.select_poster("img", veri)
54
-
55
52
  title = self.clean_title(title_text) if title_text else None
53
+ href = secici.select_attr("a", "href", veri)
54
+ poster = secici.select_poster("img", veri)
56
55
 
57
56
  if title and href:
58
57
  results.append(MainPageResult(
@@ -74,17 +73,15 @@ class JetFilmizle(PluginBase):
74
73
 
75
74
  results = []
76
75
  for article in secici.select("article.movie"):
77
- # h2-h6 içindeki a linki
78
76
  title_text = None
79
77
  for h_tag in ["h2", "h3", "h4", "h5", "h6"]:
80
78
  title_text = secici.select_text(f"{h_tag} a", article)
81
79
  if title_text:
82
80
  break
83
81
 
84
- href = secici.select_attr("a", "href", article)
85
- poster = secici.select_poster("img", article)
86
-
87
82
  title = self.clean_title(title_text) if title_text else None
83
+ href = secici.select_attr("a", "href", article)
84
+ poster = secici.select_poster("img", article)
88
85
 
89
86
  if title and href:
90
87
  results.append(SearchResult(
@@ -126,53 +123,89 @@ class JetFilmizle(PluginBase):
126
123
  rating = rating,
127
124
  year = year,
128
125
  actors = actors,
129
- duration = int(total_minutes) if duration else None
126
+ duration = total_minutes if total_minutes else None
130
127
  )
131
128
 
132
- async def load_links(self, url: str) -> list[ExtractResult]:
133
- istek = await self.httpx.get(url)
134
- secici = HTMLHelper(istek.text)
135
-
129
+ async def _process_source(self, url: str, name: str, html: str | None) -> list[ExtractResult]:
136
130
  results = []
137
-
138
- # 1) Ana iframe'leri kontrol et
139
- for iframe in secici.select("iframe"):
140
- src = (iframe.attrs.get("src") or
141
- iframe.attrs.get("data-src") or
142
- iframe.attrs.get("data-lazy-src"))
143
-
144
- if src and src != "about:blank":
145
- iframe_url = self.fix_url(src)
146
- data = await self.extract(iframe_url)
147
- if data:
148
- results.append(data)
149
-
150
- # 2) Sayfa numaralarından linkleri topla (Fragman hariç)
151
- page_links = []
152
- for link in secici.select("a.post-page-numbers"):
153
- isim = secici.select_text("span", link) or ""
154
- if isim != "Fragman":
155
- href = link.attrs.get("href")
156
- if href:
157
- page_links.append((self.fix_url(href), isim))
158
-
159
- # 3) Her sayfa linkindeki iframe'leri bul
160
- for page_url, isim in page_links:
161
- try:
162
- page_resp = await self.httpx.get(page_url)
163
- page_sel = HTMLHelper(page_resp.text)
164
-
165
- for iframe in page_sel.select("div#movie iframe"):
131
+ try:
132
+ if html:
133
+ secici = HTMLHelper(html)
134
+ else:
135
+ resp = await self.httpx.get(url)
136
+ secici = HTMLHelper(resp.text)
137
+
138
+ # Iframe'leri bul
139
+ container = secici.select_first("div#movie") or secici.select_first("div.film-content")
140
+
141
+ if container:
142
+ for iframe in secici.select("iframe", container):
166
143
  src = (iframe.attrs.get("src") or
167
144
  iframe.attrs.get("data-src") or
168
145
  iframe.attrs.get("data-lazy-src"))
169
-
146
+
170
147
  if src and src != "about:blank":
171
148
  iframe_url = self.fix_url(src)
172
- data = await self.extract(iframe_url, prefix=isim)
149
+ # name_override KULLANMA, extractor kendi ismini versin
150
+ # Sonra biz düzenleriz
151
+ data = await self.extract(iframe_url)
152
+
173
153
  if data:
174
- results.append(data)
175
- except Exception:
176
- continue
154
+ items = data if isinstance(data, list) else [data]
155
+
156
+ for item in items:
157
+ # Sadece kalite bilgisi içeriyorsa ekle, yoksa sadece buton adını kullan
158
+ # Özellikle Zeus için kalite önemli (1080p, 720p)
159
+ # Diğerlerinde plugin adı (Apollo, JetPlay vb.) önemsiz
160
+
161
+ # Kalite kontrolü (basitçe)
162
+ quality_indicators = ["1080p", "720p", "480p", "360p", "240p", "144p", "4k", "2k"]
163
+ has_quality = any(q in item.name.lower() for q in quality_indicators)
164
+
165
+ if has_quality:
166
+ # Buton Adı | Extractor Adı (Kalite içerdiği için)
167
+ # Örn: Zeus | 1080p
168
+ # Eğer Extractor adı zaten Buton adını içeriyorsa (Zeus | 1080p -> Zeus) tekrar ekleme
169
+ if name.lower() not in item.name.lower():
170
+ item.name = f"{name} | {item.name}"
171
+ else:
172
+ # Kalite yoksa sadece Buton adını kullan
173
+ # Örn: Apollo | JetTv -> JetTv
174
+ item.name = name
175
+
176
+ results.append(item)
177
+ return results
178
+ except Exception:
179
+ return []
177
180
 
178
- return results
181
+ async def load_links(self, url: str) -> list[ExtractResult]:
182
+ istek = await self.httpx.get(url)
183
+ secici = HTMLHelper(istek.text)
184
+
185
+ sources = []
186
+ if film_part := secici.select_first("div.film_part"):
187
+ # Tüm spanları gez
188
+ for span in secici.select("span", film_part):
189
+ # Eğer bu span bir <a> etiketi içinde değilse, aktif kaynaktır
190
+ if span.parent.tag != "a":
191
+ name = span.text(strip=True)
192
+ if name:
193
+ sources.append((url, name, istek.text)) # html content var
194
+ break
195
+
196
+ # Diğer kaynak linkleri
197
+ for link in secici.select("a.post-page-numbers", film_part):
198
+ name = secici.select_text("span", link) or link.text(strip=True)
199
+ href = link.attrs.get("href")
200
+ if name != "Fragman" and href:
201
+ sources.append((self.fix_url(href), name, None)) # html yok, çekilecek
202
+
203
+ # Eğer film_part yoksa, sadece mevcut sayfayı tara (Tek part olabilir)
204
+ if not sources:
205
+ sources.append((url, "JetFilmizle", istek.text))
206
+
207
+ tasks = []
208
+ for page_url, source_name, html_content in sources:
209
+ tasks.append(self._process_source(page_url, source_name, html_content))
210
+
211
+ return [item for sublist in await asyncio.gather(*tasks) for item in sublist]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: KekikStream
3
- Version: 2.4.8
3
+ Version: 2.4.9
4
4
  Summary: terminal üzerinden medya içeriği aramanızı ve VLC/MPV gibi popüler medya oynatıcılar aracılığıyla doğrudan izlemenizi sağlayan modüler ve genişletilebilir bir bıdı bıdı
5
5
  Home-page: https://github.com/keyiflerolsun/KekikStream
6
6
  Author: keyiflerolsun
@@ -28,6 +28,7 @@ KekikStream/Extractors/HDPlayerSystem.py,sha256=hoPN7fqVRBK97BnQ7vF_5TlEO28BD3Dr
28
28
  KekikStream/Extractors/HotStream.py,sha256=37H9pK4HSEqGR6QKgxz887JCBXfXB1NXDpBGuhvPmXo,1078
29
29
  KekikStream/Extractors/JFVid.py,sha256=rdy0bmqZIruejn1G1YNxVM3wlqxkdFRd4zunxxZlev4,746
30
30
  KekikStream/Extractors/JetTv.py,sha256=Cdx1XZEtQZkrmOdZdgM9E1iBkCNzVTExjrI_F-3Nv-I,1176
31
+ KekikStream/Extractors/JetV.py,sha256=knyDiOCSBMC1eQHo5LRFx5apn3NQflKY3xyloLDGkaI,2069
31
32
  KekikStream/Extractors/MailRu.py,sha256=n87wBc9jQ4nP8OJbqS7LsHHCKuRxlsgdtL_xHVn0rdY,779
32
33
  KekikStream/Extractors/MixPlayHD.py,sha256=otA2SKDnJisY4Zt9DCuNdjNVHtSquHoMVvP3_5Q0poY,1205
33
34
  KekikStream/Extractors/MixTiger.py,sha256=kF_AKkJoyAS6peQ94eu3pLzS-VeZ_8IYjpaDrTo3x_I,1135
@@ -46,15 +47,19 @@ KekikStream/Extractors/TauVideo.py,sha256=2ai9BwwM6qlCgxK7E0B642LtOF5y4hEb9tQ2aD
46
47
  KekikStream/Extractors/TurboImgz.py,sha256=-RyC4EWtJdK85Ei01lntqivnSmk4tXOlmSXv70cQJ70,679
47
48
  KekikStream/Extractors/TurkeyPlayer.py,sha256=zdX0IOO3M-kgAYWex2WwJJu9aGf8WhOY-ZIrRmZRiC0,1246
48
49
  KekikStream/Extractors/VCTPlay.py,sha256=MdCH9GhhKod4oPT3ePH8rhicUWuNT-GsE42S72o1NJ4,876
49
- KekikStream/Extractors/VidHide.py,sha256=xJSferkaCLOQ-kLgsA_eDZCmGagiL2711boOdogOlWw,1918
50
+ KekikStream/Extractors/Veev.py,sha256=DowOuKhCAmVs0sMeQRxxhWRUf4MR6fhx1yeNUmy_Le4,5271
51
+ KekikStream/Extractors/VidBiz.py,sha256=V9nTt8Uaqn5F9x9WMZbW3wqaeajGLdBhLryXoeStChk,2212
52
+ KekikStream/Extractors/VidHide.py,sha256=YswpcBz6Eqq_qGZhHpRcxcvTK0S3hZSNPfNjQRrn_W4,4109
50
53
  KekikStream/Extractors/VidMoly.py,sha256=LUUomzPvf4J7PG3rf7drV4WM-sBHOupsllj017eluew,4106
51
54
  KekikStream/Extractors/VidMoxy.py,sha256=qTkTFRqTgQVi-E94zY5lQC2-AYFhkl8LqaOJpgGdErc,1452
52
55
  KekikStream/Extractors/VidPapi.py,sha256=yqjA5gadCE2lZ9ksT6zZOz-1zCcCYJxZsg0Ccgz2X10,1988
53
56
  KekikStream/Extractors/VideoSeyred.py,sha256=sNxw5OHQ8AzRJIRGXGjql8nK1E6Cbg9qhKP5PuOyeM8,1216
54
57
  KekikStream/Extractors/Videostr.py,sha256=CGL9GDzN0QzDir6ss8oUvDYYbGt2k8323P2_z5tVZVI,2563
55
58
  KekikStream/Extractors/Vidoza.py,sha256=VSqCI-SYnLh6COnLHpg0feRX37t2WhPxbo08us5wCcc,655
59
+ KekikStream/Extractors/Vtbe.py,sha256=d_ZnLHnYiQltwMOWsop-EbLb0cqMiRyp5foiOm5k2es,1392
56
60
  KekikStream/Extractors/YTDLP.py,sha256=vE08jS9kLrLxiZA8TpofPQg2-ec_6d5DkM9esoh_GI8,7419
57
61
  KekikStream/Extractors/YildizKisaFilm.py,sha256=jeCCSIwZvQUr-CSylleUIP--JtN18_wUGl0vQXMCsV4,936
62
+ KekikStream/Extractors/Zeus.py,sha256=OifOjIVZWeXSoGu4F2wpxv0c-ABm-2UYD9g5L4dwkjs,2003
58
63
  KekikStream/Plugins/BelgeselX.py,sha256=tJw1GZQoqxE7HISCVYUEL2ZP-8Mftdl4WytYA0ftSUc,9648
59
64
  KekikStream/Plugins/DiziBox.py,sha256=SuRQxNZetwJJTlobuxB0h7NMeHUMrYMv_94JuCXydds,10204
60
65
  KekikStream/Plugins/DiziMom.py,sha256=mRu9YUHs7XeLzXOqKIWcsI82yeltTW-6Q423wt71D5U,8044
@@ -69,8 +74,8 @@ KekikStream/Plugins/Filmatek.py,sha256=AdOeBVP1rfq5R1YJlQj2saT77rnzVHX54tEOAH-t9
69
74
  KekikStream/Plugins/FilmciBaba.py,sha256=miwQ7ODHGcAOBacUZf0lqolBElpvOk8oeckWVJYJau0,6936
70
75
  KekikStream/Plugins/FullHDFilmizlesene.py,sha256=dJ1xo1D3ujPCQE6PewpqdvSMKlBbifA67uU7BAMmvVM,6274
71
76
  KekikStream/Plugins/HDFilm.py,sha256=m6tjV1O1l5U_jqkGKizi62GOdSMd5osyOS2_9jehS-w,10754
72
- KekikStream/Plugins/HDFilmCehennemi.py,sha256=8uaQPRprs64kdyGeC1pCkocCWPNHmddjcp_tfmHMCBE,15176
73
- KekikStream/Plugins/JetFilmizle.py,sha256=D3feoxmTNhOMH6d0LwGdYnGVfvUkMmjrNdj3Yo5teOQ,8181
77
+ KekikStream/Plugins/HDFilmCehennemi.py,sha256=h3FTKN-psrzvN0Juw8Am83MV8QL9aX-RSWhYqXRQU-E,17368
78
+ KekikStream/Plugins/JetFilmizle.py,sha256=YyZmOWoh_SFGRARrKioq8fhv8VgzTiURFypJMoW8nzU,10279
74
79
  KekikStream/Plugins/KultFilmler.py,sha256=iHk3X8CwNxHRgGFZRK6BDqvZLs0p9GK5oi8IAm6w3Lw,8441
75
80
  KekikStream/Plugins/RecTV.py,sha256=MRoP8KQF2V9kVlRNTQkRz9YFkBmMy3_skiNE47-RAlk,7151
76
81
  KekikStream/Plugins/RoketDizi.py,sha256=2OIDct56NgmQJyv0gIi9ZprpxSL3u41ZdEst5q1mhq4,9222
@@ -85,9 +90,9 @@ KekikStream/Plugins/SuperFilmGeldi.py,sha256=jJKBrLPI4rXI8n55lIdZOTyzNccPAEEIkmT
85
90
  KekikStream/Plugins/UgurFilm.py,sha256=NO6c1hHlylCfoP8fM-aVsxpBIyTAyu4uBHVM8CjybuI,5037
86
91
  KekikStream/Plugins/Watch32.py,sha256=NeESk1unb5SYs6kwkb3dDymv2yYOkRU2QJCPI9izXKk,7915
87
92
  KekikStream/Plugins/YabanciDizi.py,sha256=m4I8OM7Br_RRUSY0RAMpqcZ-_BwyjKXWHQuF_jS4EnE,9876
88
- kekikstream-2.4.8.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
89
- kekikstream-2.4.8.dist-info/METADATA,sha256=O9lxMnAoFFOSn8TH6Hp4AEwiJ35fMOQVjqVvQp8pTvc,10745
90
- kekikstream-2.4.8.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
91
- kekikstream-2.4.8.dist-info/entry_points.txt,sha256=dFwdiTx8djyehI0Gsz-rZwjAfZzUzoBSrmzRu9ubjJc,50
92
- kekikstream-2.4.8.dist-info/top_level.txt,sha256=DNmGJDXl27Drdfobrak8KYLmocW_uznVYFJOzcjUgmY,12
93
- kekikstream-2.4.8.dist-info/RECORD,,
93
+ kekikstream-2.4.9.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
94
+ kekikstream-2.4.9.dist-info/METADATA,sha256=AuylDm8bUfwDBeEQ4CBg0hi6csQXcMrS1dvytuP-Qr0,10745
95
+ kekikstream-2.4.9.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
96
+ kekikstream-2.4.9.dist-info/entry_points.txt,sha256=dFwdiTx8djyehI0Gsz-rZwjAfZzUzoBSrmzRu9ubjJc,50
97
+ kekikstream-2.4.9.dist-info/top_level.txt,sha256=DNmGJDXl27Drdfobrak8KYLmocW_uznVYFJOzcjUgmY,12
98
+ kekikstream-2.4.9.dist-info/RECORD,,