KekikStream 2.3.9__py3-none-any.whl → 2.5.4__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.
Files changed (85) hide show
  1. KekikStream/Core/Extractor/ExtractorBase.py +3 -2
  2. KekikStream/Core/Extractor/ExtractorLoader.py +8 -14
  3. KekikStream/Core/HTMLHelper.py +120 -49
  4. KekikStream/Core/Plugin/PluginBase.py +35 -12
  5. KekikStream/Core/Plugin/PluginLoader.py +12 -14
  6. KekikStream/Core/Plugin/PluginManager.py +2 -2
  7. KekikStream/Core/Plugin/PluginModels.py +0 -3
  8. KekikStream/Extractors/Abstream.py +27 -0
  9. KekikStream/Extractors/CloseLoad.py +30 -54
  10. KekikStream/Extractors/ContentX.py +27 -72
  11. KekikStream/Extractors/DonilasPlay.py +33 -77
  12. KekikStream/Extractors/DzenRu.py +10 -24
  13. KekikStream/Extractors/ExPlay.py +20 -38
  14. KekikStream/Extractors/Filemoon.py +21 -46
  15. KekikStream/Extractors/HDMomPlayer.py +30 -0
  16. KekikStream/Extractors/HDPlayerSystem.py +13 -31
  17. KekikStream/Extractors/HotStream.py +27 -0
  18. KekikStream/Extractors/JFVid.py +3 -24
  19. KekikStream/Extractors/JetTv.py +21 -34
  20. KekikStream/Extractors/JetV.py +55 -0
  21. KekikStream/Extractors/MailRu.py +11 -29
  22. KekikStream/Extractors/MixPlayHD.py +15 -28
  23. KekikStream/Extractors/MixTiger.py +17 -40
  24. KekikStream/Extractors/MolyStream.py +17 -21
  25. KekikStream/Extractors/Odnoklassniki.py +40 -104
  26. KekikStream/Extractors/PeaceMakerst.py +18 -45
  27. KekikStream/Extractors/PixelDrain.py +8 -16
  28. KekikStream/Extractors/PlayerFilmIzle.py +22 -41
  29. KekikStream/Extractors/RapidVid.py +21 -35
  30. KekikStream/Extractors/SetPlay.py +18 -43
  31. KekikStream/Extractors/SibNet.py +7 -17
  32. KekikStream/Extractors/Sobreatsesuyp.py +23 -45
  33. KekikStream/Extractors/TRsTX.py +23 -53
  34. KekikStream/Extractors/TurboImgz.py +7 -14
  35. KekikStream/Extractors/VCTPlay.py +10 -28
  36. KekikStream/Extractors/Veev.py +145 -0
  37. KekikStream/Extractors/VidBiz.py +62 -0
  38. KekikStream/Extractors/VidHide.py +58 -30
  39. KekikStream/Extractors/VidMoly.py +65 -99
  40. KekikStream/Extractors/VidMoxy.py +16 -27
  41. KekikStream/Extractors/VidPapi.py +24 -54
  42. KekikStream/Extractors/VideoSeyred.py +19 -40
  43. KekikStream/Extractors/Videostr.py +58 -0
  44. KekikStream/Extractors/Vidoza.py +18 -0
  45. KekikStream/Extractors/Vtbe.py +38 -0
  46. KekikStream/Extractors/YTDLP.py +2 -2
  47. KekikStream/Extractors/YildizKisaFilm.py +13 -31
  48. KekikStream/Extractors/Zeus.py +61 -0
  49. KekikStream/Plugins/BelgeselX.py +97 -77
  50. KekikStream/Plugins/DiziBox.py +28 -45
  51. KekikStream/Plugins/DiziMom.py +179 -0
  52. KekikStream/Plugins/DiziPal.py +95 -161
  53. KekikStream/Plugins/DiziYou.py +51 -147
  54. KekikStream/Plugins/Dizilla.py +40 -61
  55. KekikStream/Plugins/FilmBip.py +90 -39
  56. KekikStream/Plugins/FilmEkseni.py +199 -0
  57. KekikStream/Plugins/FilmMakinesi.py +72 -73
  58. KekikStream/Plugins/FilmModu.py +25 -35
  59. KekikStream/Plugins/Filmatek.py +184 -0
  60. KekikStream/Plugins/FilmciBaba.py +155 -0
  61. KekikStream/Plugins/FullHDFilmizlesene.py +16 -37
  62. KekikStream/Plugins/HDFilm.py +243 -0
  63. KekikStream/Plugins/HDFilmCehennemi.py +242 -189
  64. KekikStream/Plugins/JetFilmizle.py +101 -69
  65. KekikStream/Plugins/KultFilmler.py +138 -104
  66. KekikStream/Plugins/RecTV.py +52 -73
  67. KekikStream/Plugins/RoketDizi.py +18 -27
  68. KekikStream/Plugins/SelcukFlix.py +30 -48
  69. KekikStream/Plugins/SetFilmIzle.py +76 -104
  70. KekikStream/Plugins/SezonlukDizi.py +90 -94
  71. KekikStream/Plugins/Sinefy.py +195 -167
  72. KekikStream/Plugins/SinemaCX.py +148 -78
  73. KekikStream/Plugins/Sinezy.py +29 -31
  74. KekikStream/Plugins/SuperFilmGeldi.py +12 -17
  75. KekikStream/Plugins/UgurFilm.py +85 -38
  76. KekikStream/Plugins/Watch32.py +160 -0
  77. KekikStream/Plugins/YabanciDizi.py +176 -211
  78. {kekikstream-2.3.9.dist-info → kekikstream-2.5.4.dist-info}/METADATA +1 -1
  79. kekikstream-2.5.4.dist-info/RECORD +99 -0
  80. {kekikstream-2.3.9.dist-info → kekikstream-2.5.4.dist-info}/WHEEL +1 -1
  81. KekikStream/Plugins/FullHDFilm.py +0 -249
  82. kekikstream-2.3.9.dist-info/RECORD +0 -84
  83. {kekikstream-2.3.9.dist-info → kekikstream-2.5.4.dist-info}/entry_points.txt +0 -0
  84. {kekikstream-2.3.9.dist-info → kekikstream-2.5.4.dist-info}/licenses/LICENSE +0 -0
  85. {kekikstream-2.3.9.dist-info → kekikstream-2.5.4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,58 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper, Subtitle
4
+ from urllib.parse import quote
5
+ import re
6
+
7
+ class Videostr(ExtractorBase):
8
+ name = "Videostr"
9
+ main_url = "https://videostr.net"
10
+
11
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
12
+ v_id = url.split("?")[0].split("/")[-1]
13
+ headers = {"Referer": self.main_url, "X-Requested-With": "XMLHttpRequest"}
14
+
15
+ resp = await self.httpx.get(url, headers=headers)
16
+ sel = HTMLHelper(resp.text)
17
+
18
+ # Nonce Bulma
19
+ nonce = sel.regex_first(r"\b[a-zA-Z0-9]{48}\b")
20
+ if not nonce:
21
+ m = re.search(r"\b([a-zA-Z0-9]{16})\b.*?\b([a-zA-Z0-9]{16})\b.*?\b([a-zA-Z0-9]{16})\b", resp.text, re.DOTALL)
22
+ if m: nonce = m.group(1) + m.group(2) + m.group(3)
23
+
24
+ if not nonce:
25
+ raise ValueError(f"Videostr: Nonce bulunamadı. {url}")
26
+
27
+ # Kaynakları Çek
28
+ api_resp = await self.httpx.get(f"{self.main_url}/embed-1/v3/e-1/getSources?id={v_id}&_k={nonce}", headers=headers)
29
+ data = api_resp.json()
30
+
31
+ enc_file = data.get("sources", [{}])[0].get("file")
32
+ if not enc_file:
33
+ raise ValueError("Videostr: Kaynak bulunamadı.")
34
+
35
+ m3u8_url = None
36
+ if ".m3u8" in enc_file:
37
+ m3u8_url = enc_file
38
+ else:
39
+ # Decryption Flow (External Keys)
40
+ with contextlib.suppress(Exception):
41
+ key_resp = await self.httpx.get("https://raw.githubusercontent.com/yogesh-hacker/MegacloudKeys/refs/heads/main/keys.json")
42
+ v_key = key_resp.json().get("vidstr")
43
+ if v_key:
44
+ decode_api = "https://script.google.com/macros/s/AKfycbxHbYHbrGMXYD2-bC-C43D3njIbU-wGiYQuJL61H4vyy6YVXkybMNNEPJNPPuZrD1gRVA/exec"
45
+ dec_resp = await self.httpx.get(f"{decode_api}?encrypted_data={quote(enc_file)}&nonce={quote(nonce)}&secret={quote(v_key)}")
46
+ m3u8_url = re.search(r'"file":"(.*?)"', dec_resp.text).group(1).replace("\\/", "/")
47
+
48
+ if not m3u8_url:
49
+ raise ValueError(f"Videostr: Video URL bulunamadı. {url}")
50
+
51
+ subtitles = [
52
+ Subtitle(name=t.get("label", "Altyazı"), url=t.get("file"))
53
+ for t in data.get("tracks", []) if t.get("kind") in ["captions", "subtitles"]
54
+ ]
55
+
56
+ return ExtractResult(name=self.name, url=m3u8_url, referer=f"{self.main_url}/", subtitles=subtitles)
57
+
58
+ import contextlib
@@ -0,0 +1,18 @@
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 Vidoza(ExtractorBase):
6
+ name = "Vidoza"
7
+ main_url = "https://vidoza.net"
8
+
9
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
10
+ self.httpx.headers.update({"Referer": referer or url})
11
+
12
+ resp = await self.httpx.get(url)
13
+ v_url = HTMLHelper(resp.text).select_attr("source", "src")
14
+
15
+ if not v_url:
16
+ raise ValueError(f"Vidoza: Video bulunamadı. {url}")
17
+
18
+ return ExtractResult(name=self.name, url=v_url, referer=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
+ )
@@ -151,8 +151,8 @@ class YTDLP(ExtractorBase):
151
151
  ydl_opts = {
152
152
  "quiet" : True,
153
153
  "no_warnings" : True,
154
- "extract_flat" : False, # Tam bilgi al
155
- "format" : "best", # En iyi kalite
154
+ "extract_flat" : False, # Tam bilgi al
155
+ "format" : "best/all", # En iyi kalite, yoksa herhangi biri
156
156
  "no_check_certificates" : True,
157
157
  "socket_timeout" : 3,
158
158
  "retries" : 1
@@ -6,36 +6,18 @@ class YildizKisaFilm(ExtractorBase):
6
6
  name = "YildizKisaFilm"
7
7
  main_url = "https://yildizkisafilm.org"
8
8
 
9
- async def extract(self, url, referer=None) -> ExtractResult:
10
- ext_ref = referer or ""
11
-
12
- if "video/" in url:
13
- vid_id = url.split("video/")[-1]
14
- else:
15
- vid_id = url.split("?data=")[-1]
16
-
17
- post_url = f"{self.main_url}/player/index.php?data={vid_id}&do=getVideo"
18
-
19
- response = await self.httpx.post(
20
- url = post_url,
21
- data = {"hash": vid_id, "r": ext_ref},
22
- headers = {
23
- "Referer" : ext_ref,
24
- "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
25
- "X-Requested-With" : "XMLHttpRequest"
26
- }
9
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
10
+ ref = referer or self.main_url
11
+ v_id = url.split("video/")[-1] if "video/" in url else url.split("?data=")[-1]
12
+
13
+ resp = await self.httpx.post(
14
+ f"{self.main_url}/player/index.php?data={v_id}&do=getVideo",
15
+ data = {"hash": v_id, "r": ref},
16
+ headers = {"Referer": ref, "X-Requested-With": "XMLHttpRequest"}
27
17
  )
28
- response.raise_for_status()
18
+
19
+ m3u8_url = resp.json().get("securedLink")
20
+ if not m3u8_url:
21
+ raise ValueError(f"YildizKisaFilm: Video URL bulunamadı. {url}")
29
22
 
30
- video_data = response.json()
31
- m3u_link = video_data.get("securedLink")
32
-
33
- if not m3u_link:
34
- raise ValueError("securedLink not found in response")
35
-
36
- return ExtractResult(
37
- name = self.name,
38
- url = m3u_link,
39
- referer = ext_ref,
40
- subtitles = []
41
- )
23
+ return ExtractResult(name=self.name, url=m3u8_url, referer=ref)
@@ -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
@@ -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, SeriesInfo, Episode, ExtractResult, HTMLHelper
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
4
+ from contextlib import suppress
4
5
 
5
6
  class BelgeselX(PluginBase):
6
7
  name = "BelgeselX"
@@ -34,31 +35,46 @@ class BelgeselX(PluginBase):
34
35
  @staticmethod
35
36
  def _to_title_case(text: str) -> str:
36
37
  """Türkçe için title case dönüşümü."""
37
- return " ".join(
38
- word.lower().replace("i", "İ").capitalize() if word.lower().startswith("i") else word.capitalize()
39
- for word in text.split()
40
- )
38
+ if not text:
39
+ return ""
40
+
41
+ words = text.split()
42
+ new_words = []
43
+
44
+ for word in words:
45
+ # Önce Türkçe karakterleri koruyarak küçült
46
+ # İ -> i, I -> ı
47
+ word = word.replace("İ", "i").replace("I", "ı").lower()
48
+
49
+ # Sonra ilk harfi Türkçe kurallarına göre büyüt
50
+ if word:
51
+ if word[0] == "i":
52
+ word = "İ" + word[1:]
53
+ elif word[0] == "ı":
54
+ word = "I" + word[1:]
55
+ else:
56
+ word = word[0].upper() + word[1:]
57
+
58
+ new_words.append(word)
59
+
60
+ return " ".join(new_words)
41
61
 
42
62
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
43
63
  istek = self.cloudscraper.get(f"{url}{page}")
44
64
  secici = HTMLHelper(istek.text)
45
65
 
46
66
  results = []
47
- # xpath kullanamıyoruz, en üst seviye gen-movie-contain'leri alıp içlerinden bilgileri çekelim
48
67
  for container in secici.select("div.gen-movie-contain"):
49
- # Poster için img'i container'ın içinden alalım
50
68
  poster = secici.select_attr("div.gen-movie-img img", "src", container)
51
-
52
- # Title ve href için gen-movie-info
53
- title = secici.select_text("div.gen-movie-info h3 a", container)
54
- href = secici.select_attr("div.gen-movie-info h3 a", "href", container)
69
+ title = secici.select_text("div.gen-movie-info h3 a", container)
70
+ href = secici.select_attr("div.gen-movie-info h3 a", "href", container)
55
71
 
56
72
  if title and href:
57
73
  results.append(MainPageResult(
58
74
  category = category,
59
75
  title = self._to_title_case(title),
60
76
  url = self.fix_url(href),
61
- poster = self.fix_url(poster) if poster else None
77
+ poster = self.fix_url(poster)
62
78
  ))
63
79
 
64
80
  return results
@@ -70,7 +86,7 @@ class BelgeselX(PluginBase):
70
86
  token_resp = self.cloudscraper.get(f"https://cse.google.com/cse.js?cx={cx}")
71
87
  token_text = token_resp.text
72
88
 
73
- secici = HTMLHelper(token_text)
89
+ secici = HTMLHelper(token_text)
74
90
  cse_lib = secici.regex_first(r'cselibVersion": "(.*)"')
75
91
  cse_tok = secici.regex_first(r'cse_token": "(.*)"')
76
92
 
@@ -84,13 +100,13 @@ class BelgeselX(PluginBase):
84
100
  f"&callback=google.search.cse.api9969&rurl=https%3A%2F%2Fbelgeselx.com%2F"
85
101
  )
86
102
 
87
- resp = self.cloudscraper.get(search_url)
103
+ resp = self.cloudscraper.get(search_url)
88
104
  resp_text = resp.text
89
105
 
90
106
  secici2 = HTMLHelper(resp_text)
91
- titles = secici2.regex_all(r'"titleNoFormatting": "(.*?)"')
92
- urls = secici2.regex_all(r'"url": "(.*?)"')
93
- images = secici2.regex_all(r'"ogImage": "(.*?)"')
107
+ titles = secici2.regex_all(r'"titleNoFormatting": "(.*?)"')
108
+ urls = secici2.regex_all(r'"url": "(.*?)"')
109
+ images = secici2.regex_all(r'"ogImage": "(.*?)"')
94
110
 
95
111
  results = []
96
112
  for i, title in enumerate(titles):
@@ -98,11 +114,9 @@ class BelgeselX(PluginBase):
98
114
  poster = images[i] if i < len(images) else None
99
115
 
100
116
  if not url_val or "diziresimleri" not in url_val:
101
- # URL'den belgesel linkini oluştur
102
117
  if poster and "diziresimleri" in poster:
103
118
  file_name = poster.rsplit("/", 1)[-1]
104
- secici3 = HTMLHelper(file_name)
105
- file_name = secici3.regex_replace(r"\.(jpe?g|png|webp)$", "")
119
+ file_name = HTMLHelper(file_name).regex_replace(r"\.(jpe?g|png|webp)$", "")
106
120
  url_val = f"{self.main_url}/belgeseldizi/{file_name}"
107
121
  else:
108
122
  continue
@@ -120,85 +134,91 @@ class BelgeselX(PluginBase):
120
134
  istek = await self.httpx.get(url)
121
135
  secici = HTMLHelper(istek.text)
122
136
 
123
- title = secici.select_text("h2.gen-title")
124
-
125
- poster = secici.select_attr("div.gen-tv-show-top img", "src")
126
-
137
+ title = self._to_title_case(secici.select_text("h2.gen-title"))
138
+ poster = secici.select_poster("div.gen-tv-show-top img")
127
139
  description = secici.select_text("div.gen-single-tv-show-info p")
128
-
129
- tags = []
130
- for tag_link in secici.select("div.gen-socail-share a[href*='belgeselkanali']"):
131
- tag_href = secici.select_attr("a", "href", tag_link)
132
- if tag_href:
133
- tag_name = tag_href.rsplit("/", 1)[-1].replace("-", " ")
134
- tags.append(self._to_title_case(tag_name))
140
+ tags = [self._to_title_case(t.rsplit("/", 1)[-1].replace("-", " ")) for t in secici.select_attrs("div.gen-socail-share a[href*='belgeselkanali']", "href")]
141
+
142
+ # Meta bilgilerinden yıl ve puanı çıkar
143
+ meta_items = secici.select_texts("div.gen-single-meta-holder ul li")
144
+ year = None
145
+ rating = None
146
+ for item in meta_items:
147
+ if not year:
148
+ if y_match := secici.regex_first(r"\b((?:19|20)\d{2})\b", item):
149
+ year = int(y_match)
150
+ if not rating:
151
+ if r_match := secici.regex_first(r"%\s*(\d+)\s*Puan", item):
152
+ rating = float(r_match) / 10
153
+ rating = rating or None
135
154
 
136
155
  episodes = []
137
- counter = 0
138
- for ep_item in secici.select("div.gen-movie-contain"):
139
- ep_name = secici.select_text("div.gen-movie-info h3 a", ep_item)
140
- ep_href = secici.select_attr("div.gen-movie-info h3 a", "href", ep_item)
141
-
142
- if not ep_name or not ep_href:
143
- continue
144
-
145
- season_text = secici.select_text("div.gen-single-meta-holder ul li", ep_item)
146
-
147
- episode_num = secici.regex_first(r"Bölüm (\d+)", season_text)
148
- season_num = secici.regex_first(r"Sezon (\d+)", season_text)
149
-
150
- ep_episode = int(episode_num) if episode_num else counter
151
- ep_season = int(season_num) if season_num else 1
152
-
153
- counter += 1
154
-
155
- episodes.append(Episode(
156
- season = ep_season,
157
- episode = ep_episode,
158
- title = ep_name,
159
- url = self.fix_url(ep_href)
160
- ))
156
+ for i, ep in enumerate(secici.select("div.gen-movie-contain")):
157
+ name = secici.select_text("div.gen-movie-info h3 a", ep)
158
+ href = secici.select_attr("div.gen-movie-info h3 a", "href", ep)
159
+ item_id = secici.select_attr("div.gen-movie-info h3 a", "id", ep)
160
+ if name and href:
161
+ s, e = secici.extract_season_episode(secici.select_text("div.gen-single-meta-holder ul li", ep))
162
+ # ID'yi URL'ye ekle ki load_links doğru bölümü çekebilsin
163
+ final_url = self.fix_url(href)
164
+ if item_id:
165
+ final_url = f"{final_url}?id={item_id}"
166
+
167
+ episodes.append(Episode(
168
+ season = s or 1,
169
+ episode = e or (i + 1),
170
+ title = name,
171
+ url = final_url
172
+ ))
161
173
 
162
174
  return SeriesInfo(
163
175
  url = url,
164
- poster = self.fix_url(poster) if poster else None,
165
- title = self._to_title_case(title) if title else None,
176
+ poster = self.fix_url(poster),
177
+ title = title,
166
178
  description = description,
167
179
  tags = tags,
180
+ year = year,
181
+ rating = rating,
168
182
  episodes = episodes
169
183
  )
170
184
 
171
185
  async def load_links(self, url: str) -> list[ExtractResult]:
172
- istek = await self.httpx.get(url)
173
- text = istek.text
186
+ # URL'den ID'yi ayıkla
187
+ params = dict([x.split('=') for x in url.split('?')[-1].split('&')]) if '?' in url else {}
188
+ episode_id = params.get('id')
189
+ main_url = url.split('?')[0]
190
+
191
+ istek = await self.httpx.get(main_url)
192
+ secici = HTMLHelper(istek.text)
174
193
 
175
- secici = HTMLHelper(text)
176
- # fnc_addWatch div'inden data-episode ID'sini al
177
- episode_id = secici.regex_first(r'<div[^>]*class=["\'][^"\']*fnc_addWatch[^"\']*["\'][^>]*data-episode=["\'](\d+)["\']')
178
194
  if not episode_id:
179
- return []
195
+ episode_id = secici.regex_first(r'data-episode=["\'](\d+)["\']')
180
196
 
181
- iframe_url = f"{self.main_url}/video/data/new4.php?id={episode_id}"
197
+ if not episode_id:
198
+ return []
182
199
 
183
- iframe_resp = await self.httpx.get(iframe_url, headers={"Referer": url})
184
- iframe_text = iframe_resp.text
200
+ iframe_resp = await self.httpx.get(f"{self.main_url}/video/data/new4.php?id={episode_id}", headers={"Referer": main_url})
201
+ secici = HTMLHelper(iframe_resp.text)
185
202
 
186
- secici2 = HTMLHelper(iframe_text)
187
- # file:"url", label: "quality" patternlerini al
188
- file_matches = secici2.regex_all(r'file:"([^"]+)"')
189
- label_matches = secici2.regex_all(r'label: "([^"]+)"')
203
+ links = []
204
+ files = secici.regex_all(r'file:"([^"]+)"')
205
+ labels = secici.regex_all(r'label: "([^"]+)"')
190
206
 
191
- links = []
192
- for i, video_url in enumerate(file_matches):
193
- quality = label_matches[i] if i < len(label_matches) else "Unknown"
207
+ for i, video_url in enumerate(files):
208
+ quality = labels[i] if i < len(labels) else "HD"
209
+ name = f"{'Google' if 'google' in video_url.lower() or 'blogspot' in video_url.lower() or quality == 'FULL' else self.name} | {'1080p' if quality == 'FULL' else quality}"
194
210
 
195
- source_name = "Google" if quality == "FULL" else self.name
196
- quality_str = "1080p" if quality == "FULL" else quality
211
+ # belgeselx.php redirect'ini çöz
212
+ if "belgeselx.php" in video_url or "belgeselx2.php" in video_url:
213
+ with suppress(Exception):
214
+ # HEAD isteği ile lokasyonu alalım
215
+ resp = await self.httpx.head(video_url, headers={"Referer": main_url}, follow_redirects=True)
216
+ video_url = str(resp.url)
197
217
 
198
218
  links.append(ExtractResult(
199
219
  url = video_url,
200
- name = f"{source_name} | {quality_str}",
201
- referer = url
220
+ name = name,
221
+ referer = main_url
202
222
  ))
203
223
 
204
224
  return links
@@ -1,7 +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, SeriesInfo, Episode, ExtractResult, HTMLHelper
4
- from Kekik.Sifreleme import CryptoJS
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
4
+ from Kekik.Sifreleme import CryptoJS
5
5
  import urllib.parse, base64, contextlib, asyncio, time
6
6
 
7
7
  class DiziBox(PluginBase):
@@ -52,8 +52,8 @@ class DiziBox(PluginBase):
52
52
 
53
53
  results = []
54
54
  for veri in secici.select("article.detailed-article"):
55
- title = secici.select_text("h3 a", veri)
56
- href = secici.select_attr("h3 a", "href", veri)
55
+ title = secici.select_text("h3 a", veri)
56
+ href = secici.select_attr("h3 a", "href", veri)
57
57
  poster = secici.select_attr("img", "src", veri)
58
58
 
59
59
  if title and href:
@@ -61,7 +61,7 @@ class DiziBox(PluginBase):
61
61
  category = category,
62
62
  title = title,
63
63
  url = self.fix_url(href),
64
- poster = self.fix_url(poster) if poster else None,
64
+ poster = self.fix_url(poster),
65
65
  ))
66
66
 
67
67
  return results
@@ -84,7 +84,7 @@ class DiziBox(PluginBase):
84
84
  results.append(SearchResult(
85
85
  title = title,
86
86
  url = self.fix_url(href),
87
- poster = self.fix_url(poster) if poster else None,
87
+ poster = self.fix_url(poster),
88
88
  ))
89
89
 
90
90
  return results
@@ -93,48 +93,28 @@ class DiziBox(PluginBase):
93
93
  istek = await self.httpx.get(url)
94
94
  secici = HTMLHelper(istek.text)
95
95
 
96
- title = secici.select_text("div.tv-overview h1 a")
97
-
98
- poster = secici.select_attr("div.tv-overview figure img", "src")
99
-
96
+ title = secici.select_text("div.tv-overview h1 a")
97
+ poster = secici.select_poster("div.tv-overview figure img")
100
98
  description = secici.select_text("div.tv-story p")
101
-
102
- # year
103
- year_text = secici.select_text("a[href*='/yil/']")
104
- year = secici.regex_first(r"(\d{4})", year_text)
105
-
106
- tags = secici.select_all_text("a[href*='/tur/']")
107
-
108
- # rating
109
- rating_text = secici.select_text("span.label-imdb b")
110
- rating = secici.regex_first(r"[\d.,]+", rating_text)
111
-
112
- actors = secici.select_all_text("a[href*='/oyuncu/']")
99
+ year = secici.extract_year("a[href*='/yil/']")
100
+ tags = secici.select_texts("a[href*='/tur/']")
101
+ rating = secici.regex_first(r"[\d.,]+", secici.select_text("span.label-imdb b"))
102
+ actors = secici.select_texts("a[href*='/oyuncu/']")
113
103
 
114
104
  episodes = []
115
- for sezon_link in secici.select_all_attr("div#seasons-list a", "href"):
116
- sezon_url = self.fix_url(sezon_link)
117
- sezon_istek = await self.httpx.get(sezon_url)
118
- sezon_secici = HTMLHelper(sezon_istek.text)
119
-
120
- for bolum in sezon_secici.select("article.grid-box"):
121
- ep_title = sezon_secici.select_text("div.post-title a", bolum)
122
- ep_href = sezon_secici.select_attr("div.post-title a", "href", bolum)
123
-
124
- ep_season = sezon_secici.regex_first(r"(\d+)\. ?Sezon", ep_title)
125
- ep_episode = sezon_secici.regex_first(r"(\d+)\. ?Bölüm", ep_title)
126
-
127
- if ep_title and ep_href:
128
- episodes.append(Episode(
129
- season = ep_season,
130
- episode = ep_episode,
131
- title = ep_title,
132
- url = self.fix_url(ep_href),
133
- ))
105
+ for link in secici.select_attrs("div#seasons-list a", "href"):
106
+ r = await self.httpx.get(self.fix_url(link))
107
+ s_secici = HTMLHelper(r.text)
108
+ for bolum in s_secici.select("article.grid-box"):
109
+ name = s_secici.select_text("div.post-title a", bolum)
110
+ href = s_secici.select_attr("div.post-title a", "href", bolum)
111
+ if name and href:
112
+ s, e = s_secici.extract_season_episode(name)
113
+ episodes.append(Episode(season=s, episode=e, title=name, url=self.fix_url(href)))
134
114
 
135
115
  return SeriesInfo(
136
116
  url = url,
137
- poster = self.fix_url(poster) if poster else None,
117
+ poster = self.fix_url(poster),
138
118
  title = title,
139
119
  description = description,
140
120
  tags = tags,
@@ -202,13 +182,16 @@ class DiziBox(PluginBase):
202
182
  istek = await self.httpx.get(url)
203
183
  secici = HTMLHelper(istek.text)
204
184
 
205
- results = []
185
+ # Aktif kaynağın adını bul (DBX Pro vs.)
186
+ current_source_name = secici.select_text("div.video-toolbar option[selected]") or self.name
187
+
188
+ results = []
206
189
  main_iframe = secici.select_attr("div#video-area iframe", "src")
207
190
 
208
191
  if main_iframe:
209
192
  if decoded := await self._iframe_decode(self.name, main_iframe, url):
210
193
  for iframe in decoded:
211
- data = await self.extract(iframe)
194
+ data = await self.extract(iframe, name_override=current_source_name)
212
195
  if data:
213
196
  results.append(data)
214
197
 
@@ -229,7 +212,7 @@ class DiziBox(PluginBase):
229
212
  if alt_iframe:
230
213
  if decoded := await self._iframe_decode(alt_name, alt_iframe, url):
231
214
  for iframe in decoded:
232
- data = await self.extract(iframe, prefix=alt_name)
215
+ data = await self.extract(iframe, name_override=alt_name)
233
216
  if data:
234
217
  results.append(data)
235
218