KekikStream 2.2.9__py3-none-any.whl → 2.5.3__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.

Potentially problematic release.


This version of KekikStream might be problematic. Click here for more details.

Files changed (88) hide show
  1. KekikStream/Core/Extractor/ExtractorBase.py +3 -2
  2. KekikStream/Core/Extractor/ExtractorLoader.py +8 -14
  3. KekikStream/Core/HTMLHelper.py +205 -0
  4. KekikStream/Core/Plugin/PluginBase.py +48 -12
  5. KekikStream/Core/Plugin/PluginLoader.py +13 -14
  6. KekikStream/Core/Plugin/PluginManager.py +2 -2
  7. KekikStream/Core/Plugin/PluginModels.py +0 -3
  8. KekikStream/Core/__init__.py +2 -0
  9. KekikStream/Extractors/Abstream.py +27 -0
  10. KekikStream/Extractors/CloseLoad.py +31 -56
  11. KekikStream/Extractors/ContentX.py +28 -71
  12. KekikStream/Extractors/DonilasPlay.py +34 -78
  13. KekikStream/Extractors/DzenRu.py +11 -25
  14. KekikStream/Extractors/ExPlay.py +20 -38
  15. KekikStream/Extractors/Filemoon.py +23 -53
  16. KekikStream/Extractors/HDMomPlayer.py +30 -0
  17. KekikStream/Extractors/HDPlayerSystem.py +13 -31
  18. KekikStream/Extractors/HotStream.py +27 -0
  19. KekikStream/Extractors/JFVid.py +3 -24
  20. KekikStream/Extractors/JetTv.py +21 -34
  21. KekikStream/Extractors/JetV.py +55 -0
  22. KekikStream/Extractors/MailRu.py +11 -29
  23. KekikStream/Extractors/MixPlayHD.py +17 -31
  24. KekikStream/Extractors/MixTiger.py +17 -40
  25. KekikStream/Extractors/MolyStream.py +25 -22
  26. KekikStream/Extractors/Odnoklassniki.py +41 -105
  27. KekikStream/Extractors/PeaceMakerst.py +20 -47
  28. KekikStream/Extractors/PixelDrain.py +9 -16
  29. KekikStream/Extractors/PlayerFilmIzle.py +23 -46
  30. KekikStream/Extractors/RapidVid.py +23 -36
  31. KekikStream/Extractors/SetPlay.py +19 -44
  32. KekikStream/Extractors/SetPrime.py +3 -6
  33. KekikStream/Extractors/SibNet.py +8 -19
  34. KekikStream/Extractors/Sobreatsesuyp.py +25 -47
  35. KekikStream/Extractors/TRsTX.py +25 -55
  36. KekikStream/Extractors/TurboImgz.py +8 -16
  37. KekikStream/Extractors/TurkeyPlayer.py +5 -5
  38. KekikStream/Extractors/VCTPlay.py +10 -28
  39. KekikStream/Extractors/Veev.py +145 -0
  40. KekikStream/Extractors/VidBiz.py +62 -0
  41. KekikStream/Extractors/VidHide.py +59 -34
  42. KekikStream/Extractors/VidMoly.py +67 -89
  43. KekikStream/Extractors/VidMoxy.py +17 -29
  44. KekikStream/Extractors/VidPapi.py +26 -58
  45. KekikStream/Extractors/VideoSeyred.py +21 -42
  46. KekikStream/Extractors/Videostr.py +58 -0
  47. KekikStream/Extractors/Vidoza.py +18 -0
  48. KekikStream/Extractors/Vtbe.py +38 -0
  49. KekikStream/Extractors/YTDLP.py +2 -2
  50. KekikStream/Extractors/YildizKisaFilm.py +13 -31
  51. KekikStream/Extractors/Zeus.py +61 -0
  52. KekikStream/Plugins/BelgeselX.py +108 -99
  53. KekikStream/Plugins/DiziBox.py +61 -106
  54. KekikStream/Plugins/DiziMom.py +179 -0
  55. KekikStream/Plugins/DiziPal.py +104 -192
  56. KekikStream/Plugins/DiziYou.py +66 -149
  57. KekikStream/Plugins/Dizilla.py +93 -126
  58. KekikStream/Plugins/FilmBip.py +102 -72
  59. KekikStream/Plugins/FilmEkseni.py +199 -0
  60. KekikStream/Plugins/FilmMakinesi.py +101 -64
  61. KekikStream/Plugins/FilmModu.py +35 -59
  62. KekikStream/Plugins/Filmatek.py +184 -0
  63. KekikStream/Plugins/FilmciBaba.py +155 -0
  64. KekikStream/Plugins/FullHDFilmizlesene.py +32 -78
  65. KekikStream/Plugins/HDFilm.py +243 -0
  66. KekikStream/Plugins/HDFilmCehennemi.py +261 -222
  67. KekikStream/Plugins/JetFilmizle.py +117 -98
  68. KekikStream/Plugins/KultFilmler.py +153 -143
  69. KekikStream/Plugins/RecTV.py +53 -49
  70. KekikStream/Plugins/RoketDizi.py +92 -123
  71. KekikStream/Plugins/SelcukFlix.py +86 -95
  72. KekikStream/Plugins/SetFilmIzle.py +105 -143
  73. KekikStream/Plugins/SezonlukDizi.py +106 -128
  74. KekikStream/Plugins/Sinefy.py +194 -166
  75. KekikStream/Plugins/SinemaCX.py +159 -113
  76. KekikStream/Plugins/Sinezy.py +44 -73
  77. KekikStream/Plugins/SuperFilmGeldi.py +28 -52
  78. KekikStream/Plugins/UgurFilm.py +94 -72
  79. KekikStream/Plugins/Watch32.py +160 -0
  80. KekikStream/Plugins/YabanciDizi.py +250 -0
  81. {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/METADATA +1 -1
  82. kekikstream-2.5.3.dist-info/RECORD +99 -0
  83. {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/WHEEL +1 -1
  84. KekikStream/Plugins/FullHDFilm.py +0 -254
  85. kekikstream-2.2.9.dist-info/RECORD +0 -82
  86. {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/entry_points.txt +0 -0
  87. {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/licenses/LICENSE +0 -0
  88. {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/top_level.txt +0 -0
@@ -1,8 +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
4
- from selectolax.parser import HTMLParser
5
- import re
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
4
+ from contextlib import suppress
6
5
 
7
6
  class BelgeselX(PluginBase):
8
7
  name = "BelgeselX"
@@ -36,36 +35,46 @@ class BelgeselX(PluginBase):
36
35
  @staticmethod
37
36
  def _to_title_case(text: str) -> str:
38
37
  """Türkçe için title case dönüşümü."""
39
- return " ".join(
40
- word.lower().replace("i", "İ").capitalize() if word.lower().startswith("i") else word.capitalize()
41
- for word in text.split()
42
- )
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)
43
61
 
44
62
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
45
63
  istek = self.cloudscraper.get(f"{url}{page}")
46
- secici = HTMLParser(istek.text)
64
+ secici = HTMLHelper(istek.text)
47
65
 
48
66
  results = []
49
- # xpath kullanamıyoruz, en üst seviye gen-movie-contain'leri alıp içlerinden bilgileri çekelim
50
- for container in secici.css("div.gen-movie-contain"):
51
- # Poster için img'i container'ın içinden alalım
52
- img_el = container.css_first("div.gen-movie-img img")
53
- poster = img_el.attrs.get("src") if img_el else None
54
-
55
- # Title ve href için gen-movie-info
56
- h3_link = container.css_first("div.gen-movie-info h3 a")
57
- if not h3_link:
58
- continue
59
-
60
- title = h3_link.text(strip=True)
61
- href = h3_link.attrs.get("href")
67
+ for container in secici.select("div.gen-movie-contain"):
68
+ poster = secici.select_attr("div.gen-movie-img img", "src", 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)
62
71
 
63
72
  if title and href:
64
73
  results.append(MainPageResult(
65
74
  category = category,
66
75
  title = self._to_title_case(title),
67
76
  url = self.fix_url(href),
68
- poster = self.fix_url(poster) if poster else None
77
+ poster = self.fix_url(poster)
69
78
  ))
70
79
 
71
80
  return results
@@ -77,15 +86,13 @@ class BelgeselX(PluginBase):
77
86
  token_resp = self.cloudscraper.get(f"https://cse.google.com/cse.js?cx={cx}")
78
87
  token_text = token_resp.text
79
88
 
80
- cse_lib_match = re.search(r'cselibVersion": "(.*)"', token_text)
81
- cse_tok_match = re.search(r'cse_token": "(.*)"', token_text)
89
+ secici = HTMLHelper(token_text)
90
+ cse_lib = secici.regex_first(r'cselibVersion": "(.*)"')
91
+ cse_tok = secici.regex_first(r'cse_token": "(.*)"')
82
92
 
83
- if not cse_lib_match or not cse_tok_match:
93
+ if not cse_lib or not cse_tok:
84
94
  return []
85
95
 
86
- cse_lib = cse_lib_match.group(1)
87
- cse_tok = cse_tok_match.group(1)
88
-
89
96
  search_url = (
90
97
  f"https://cse.google.com/cse/element/v1?"
91
98
  f"rsz=filtered_cse&num=100&hl=tr&source=gcsc&cselibv={cse_lib}&cx={cx}"
@@ -93,12 +100,13 @@ class BelgeselX(PluginBase):
93
100
  f"&callback=google.search.cse.api9969&rurl=https%3A%2F%2Fbelgeselx.com%2F"
94
101
  )
95
102
 
96
- resp = self.cloudscraper.get(search_url)
103
+ resp = self.cloudscraper.get(search_url)
97
104
  resp_text = resp.text
98
105
 
99
- titles = re.findall(r'"titleNoFormatting": "(.*?)"', resp_text)
100
- urls = re.findall(r'"url": "(.*?)"', resp_text)
101
- images = re.findall(r'"ogImage": "(.*?)"', resp_text)
106
+ secici2 = HTMLHelper(resp_text)
107
+ titles = secici2.regex_all(r'"titleNoFormatting": "(.*?)"')
108
+ urls = secici2.regex_all(r'"url": "(.*?)"')
109
+ images = secici2.regex_all(r'"ogImage": "(.*?)"')
102
110
 
103
111
  results = []
104
112
  for i, title in enumerate(titles):
@@ -106,10 +114,9 @@ class BelgeselX(PluginBase):
106
114
  poster = images[i] if i < len(images) else None
107
115
 
108
116
  if not url_val or "diziresimleri" not in url_val:
109
- # URL'den belgesel linkini oluştur
110
117
  if poster and "diziresimleri" in poster:
111
118
  file_name = poster.rsplit("/", 1)[-1]
112
- file_name = re.sub(r"\.(jpe?g|png|webp)$", "", file_name)
119
+ file_name = HTMLHelper(file_name).regex_replace(r"\.(jpe?g|png|webp)$", "")
113
120
  url_val = f"{self.main_url}/belgeseldizi/{file_name}"
114
121
  else:
115
122
  continue
@@ -125,91 +132,93 @@ class BelgeselX(PluginBase):
125
132
 
126
133
  async def load_item(self, url: str) -> SeriesInfo:
127
134
  istek = await self.httpx.get(url)
128
- secici = HTMLParser(istek.text)
129
-
130
- title_el = secici.css_first("h2.gen-title")
131
- title = title_el.text(strip=True) if title_el else None
132
-
133
- poster_el = secici.css_first("div.gen-tv-show-top img")
134
- poster = poster_el.attrs.get("src") if poster_el else None
135
-
136
- desc_el = secici.css_first("div.gen-single-tv-show-info p")
137
- description = desc_el.text(strip=True) if desc_el else None
138
-
139
- tags = []
140
- for tag_link in secici.css("div.gen-socail-share a[href*='belgeselkanali']"):
141
- tag_href = tag_link.attrs.get("href")
142
- if tag_href:
143
- tag_name = tag_href.rsplit("/", 1)[-1].replace("-", " ")
144
- tags.append(self._to_title_case(tag_name))
135
+ secici = HTMLHelper(istek.text)
136
+
137
+ title = self._to_title_case(secici.select_text("h2.gen-title"))
138
+ poster = secici.select_poster("div.gen-tv-show-top img")
139
+ description = secici.select_text("div.gen-single-tv-show-info p")
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
145
154
 
146
155
  episodes = []
147
- counter = 0
148
- for ep_item in secici.css("div.gen-movie-contain"):
149
- ep_link = ep_item.css_first("div.gen-movie-info h3 a")
150
- if not ep_link:
151
- continue
152
-
153
- ep_name = ep_link.text(strip=True)
154
- ep_href = ep_link.attrs.get("href")
155
-
156
- if not ep_name or not ep_href:
157
- continue
158
-
159
- meta_el = ep_item.css_first("div.gen-single-meta-holder ul li")
160
- season_text = meta_el.text(strip=True) if meta_el else ""
161
-
162
- episode_match = re.search(r"Bölüm (\d+)", season_text)
163
- season_match = re.search(r"Sezon (\d+)", season_text)
164
-
165
- ep_episode = int(episode_match.group(1)) if episode_match else counter
166
- ep_season = int(season_match.group(1)) if season_match else 1
167
-
168
- counter += 1
169
-
170
- episodes.append(Episode(
171
- season = ep_season,
172
- episode = ep_episode,
173
- title = ep_name,
174
- url = self.fix_url(ep_href)
175
- ))
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
+ ))
176
173
 
177
174
  return SeriesInfo(
178
175
  url = url,
179
- poster = self.fix_url(poster) if poster else None,
180
- title = self._to_title_case(title) if title else None,
176
+ poster = self.fix_url(poster),
177
+ title = title,
181
178
  description = description,
182
179
  tags = tags,
180
+ year = year,
181
+ rating = rating,
183
182
  episodes = episodes
184
183
  )
185
184
 
186
185
  async def load_links(self, url: str) -> list[ExtractResult]:
187
- istek = await self.httpx.get(url)
188
- 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)
193
+
194
+ if not episode_id:
195
+ episode_id = secici.regex_first(r'data-episode=["\'](\d+)["\']')
189
196
 
190
- # fnc_addWatch div'inden data-episode ID'sini al
191
- ep_match = re.search(r'<div[^>]*class=["\'][^"\']*fnc_addWatch[^"\']*["\'][^>]*data-episode=["\'](\d+)["\']', text)
192
- if not ep_match:
197
+ if not episode_id:
193
198
  return []
194
199
 
195
- episode_id = ep_match.group(1)
196
- iframe_url = f"{self.main_url}/video/data/new4.php?id={episode_id}"
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)
197
202
 
198
- iframe_resp = await self.httpx.get(iframe_url, headers={"Referer": url})
199
- iframe_text = iframe_resp.text
203
+ links = []
204
+ files = secici.regex_all(r'file:"([^"]+)"')
205
+ labels = secici.regex_all(r'label: "([^"]+)"')
200
206
 
201
- links = []
202
- for match in re.finditer(r'file:"([^"]+)", label: "([^"]+)"', iframe_text):
203
- video_url = match.group(1)
204
- quality = match.group(2)
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}"
205
210
 
206
- source_name = "Google" if quality == "FULL" else self.name
207
- 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)
208
217
 
209
218
  links.append(ExtractResult(
210
219
  url = video_url,
211
- name = f"{source_name} | {quality_str}",
212
- referer = url
220
+ name = name,
221
+ referer = main_url
213
222
  ))
214
223
 
215
224
  return links
@@ -1,9 +1,8 @@
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
4
- from Kekik.Sifreleme import CryptoJS
5
- from selectolax.parser import HTMLParser
6
- import re, urllib.parse, base64, contextlib, asyncio, time
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
4
+ from Kekik.Sifreleme import CryptoJS
5
+ import urllib.parse, base64, contextlib, asyncio, time
7
6
 
8
7
  class DiziBox(PluginBase):
9
8
  name = "DiziBox"
@@ -49,23 +48,20 @@ class DiziBox(PluginBase):
49
48
  url = f"{url.replace('SAYFA', str(page))}",
50
49
  follow_redirects = True
51
50
  )
52
- secici = HTMLParser(istek.text)
51
+ secici = HTMLHelper(istek.text)
53
52
 
54
53
  results = []
55
- for veri in secici.css("article.detailed-article"):
56
- h3_link = veri.css_first("h3 a")
57
- img_el = veri.css_first("img")
58
-
59
- title = h3_link.text(strip=True) if h3_link else None
60
- href = h3_link.attrs.get("href") if h3_link else None
61
- poster = img_el.attrs.get("src") if img_el else None
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)
57
+ poster = secici.select_attr("img", "src", veri)
62
58
 
63
59
  if title and href:
64
60
  results.append(MainPageResult(
65
61
  category = category,
66
62
  title = title,
67
63
  url = self.fix_url(href),
68
- poster = self.fix_url(poster) if poster else None,
64
+ poster = self.fix_url(poster),
69
65
  ))
70
66
 
71
67
  return results
@@ -76,92 +72,49 @@ class DiziBox(PluginBase):
76
72
  "dbxu" : str(time.time() * 1000).split(".")[0]
77
73
  })
78
74
  istek = await self.httpx.get(f"{self.main_url}/?s={query}")
79
- secici = HTMLParser(istek.text)
75
+ secici = HTMLHelper(istek.text)
80
76
 
81
77
  results = []
82
- for item in secici.css("article.detailed-article"):
83
- h3_link = item.css_first("h3 a")
84
- img_el = item.css_first("img")
85
-
86
- title = h3_link.text(strip=True) if h3_link else None
87
- href = h3_link.attrs.get("href") if h3_link else None
88
- poster = img_el.attrs.get("src") if img_el else None
78
+ for item in secici.select("article.detailed-article"):
79
+ title = secici.select_text("h3 a", item)
80
+ href = secici.select_attr("h3 a", "href", item)
81
+ poster = secici.select_attr("img", "src", item)
89
82
 
90
83
  if title and href:
91
84
  results.append(SearchResult(
92
85
  title = title,
93
86
  url = self.fix_url(href),
94
- poster = self.fix_url(poster) if poster else None,
87
+ poster = self.fix_url(poster),
95
88
  ))
96
89
 
97
90
  return results
98
91
 
99
92
  async def load_item(self, url: str) -> SeriesInfo:
100
93
  istek = await self.httpx.get(url)
101
- secici = HTMLParser(istek.text)
102
-
103
- title_el = secici.css_first("div.tv-overview h1 a")
104
- title = title_el.text(strip=True) if title_el else None
105
-
106
- poster_el = secici.css_first("div.tv-overview figure img")
107
- poster = poster_el.attrs.get("src") if poster_el else None
108
-
109
- desc_el = secici.css_first("div.tv-story p")
110
- description = desc_el.text(strip=True) if desc_el else None
94
+ secici = HTMLHelper(istek.text)
111
95
 
112
- # year: re_first yerine re.search
113
- year_el = secici.css_first("a[href*='/yil/']")
114
- year_text = year_el.text(strip=True) if year_el else ""
115
- year_match = re.search(r"(\d{4})", year_text)
116
- year = year_match.group(1) if year_match else None
117
-
118
- tags = [a.text(strip=True) for a in secici.css("a[href*='/tur/']") if a.text(strip=True)]
119
-
120
- # rating: re_first yerine re.search
121
- rating_el = secici.css_first("span.label-imdb b")
122
- rating_text = rating_el.text(strip=True) if rating_el else ""
123
- rating_match = re.search(r"[\d.,]+", rating_text)
124
- rating = rating_match.group() if rating_match else None
125
-
126
- actors = [a.text(strip=True) for a in secici.css("a[href*='/oyuncu/']") if a.text(strip=True)]
96
+ title = secici.select_text("div.tv-overview h1 a")
97
+ poster = secici.select_poster("div.tv-overview figure img")
98
+ description = secici.select_text("div.tv-story p")
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/']")
127
103
 
128
104
  episodes = []
129
- for sezon_link_el in secici.css("div#seasons-list a"):
130
- sezon_link = sezon_link_el.attrs.get("href")
131
- if not sezon_link:
132
- continue
133
-
134
- sezon_url = self.fix_url(sezon_link)
135
- sezon_istek = await self.httpx.get(sezon_url)
136
- sezon_secici = HTMLParser(sezon_istek.text)
137
-
138
- for bolum in sezon_secici.css("article.grid-box"):
139
- ep_link = bolum.css_first("div.post-title a")
140
- if not ep_link:
141
- continue
142
-
143
- ep_title = ep_link.text(strip=True)
144
- ep_href = ep_link.attrs.get("href")
145
-
146
- # re_first yerine re.search
147
- ep_title_text = ep_title or ""
148
- season_match = re.search(r"(\d+)\. ?Sezon", ep_title_text)
149
- episode_match = re.search(r"(\d+)\. ?Bölüm", ep_title_text)
150
-
151
- ep_season = season_match.group(1) if season_match else None
152
- ep_episode = episode_match.group(1) if episode_match else None
153
-
154
- if ep_title and ep_href:
155
- episodes.append(Episode(
156
- season = ep_season,
157
- episode = ep_episode,
158
- title = ep_title,
159
- url = self.fix_url(ep_href),
160
- ))
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)))
161
114
 
162
115
  return SeriesInfo(
163
116
  url = url,
164
- poster = self.fix_url(poster) if poster else None,
117
+ poster = self.fix_url(poster),
165
118
  title = title,
166
119
  description = description,
167
120
  tags = tags,
@@ -184,20 +137,20 @@ class DiziBox(PluginBase):
184
137
  iframe_link = iframe_link.replace("king.php?v=", "king.php?wmode=opaque&v=")
185
138
 
186
139
  istek = await self.httpx.get(iframe_link)
187
- secici = HTMLParser(istek.text)
188
- iframe_el = secici.css_first("div#Player iframe")
189
- iframe = iframe_el.attrs.get("src") if iframe_el else None
140
+ secici = HTMLHelper(istek.text)
141
+ iframe = secici.select_attr("div#Player iframe", "src")
190
142
 
191
143
  if iframe:
192
144
  self.httpx.headers.update({"Referer": self.main_url})
193
- istek = await self.httpx.get(iframe)
145
+ iframe_istek = await self.httpx.get(iframe)
146
+ iframe_secici = HTMLHelper(iframe_istek.text)
194
147
 
195
- crypt_data = re.search(r"CryptoJS\.AES\.decrypt\(\"(.*)\",\"", istek.text)[1]
196
- crypt_pass = re.search(r"\",\"(.*)\"\);", istek.text)[1]
148
+ crypt_data = iframe_secici.regex_first(r"CryptoJS\.AES\.decrypt\(\"(.*)\",\"", iframe_istek.text)
149
+ crypt_pass = iframe_secici.regex_first(r"\",\"(.*)\"\);", iframe_istek.text)
197
150
  decode = CryptoJS.decrypt(crypt_pass, crypt_data)
198
151
 
199
- if video_match := re.search(r"file: '(.*)',", decode):
200
- results.append(video_match[1])
152
+ if video_match := iframe_secici.regex_first(r"file: '(.*)',", decode):
153
+ results.append(video_match)
201
154
  else:
202
155
  results.append(decode)
203
156
 
@@ -206,15 +159,16 @@ class DiziBox(PluginBase):
206
159
  while True:
207
160
  await asyncio.sleep(.3)
208
161
  with contextlib.suppress(Exception):
209
- istek = await self.httpx.get(iframe_link)
162
+ moly_istek = await self.httpx.get(iframe_link)
163
+ moly_secici = HTMLHelper(moly_istek.text)
210
164
 
211
- if atob_data := re.search(r"unescape\(\"(.*)\"\)", istek.text):
212
- decoded_atob = urllib.parse.unquote(atob_data[1])
165
+ if atob_data := moly_secici.regex_first(r"unescape\(\"(.*)\"\)", moly_istek.text):
166
+ decoded_atob = urllib.parse.unquote(atob_data)
213
167
  str_atob = base64.b64decode(decoded_atob).decode("utf-8")
214
168
 
215
- iframe_el = HTMLParser(str_atob).css_first("div#Player iframe")
216
- if iframe_el:
217
- results.append(iframe_el.attrs.get("src"))
169
+ iframe_src = HTMLHelper(str_atob).select_attr("div#Player iframe", "src")
170
+ if iframe_src:
171
+ results.append(iframe_src)
218
172
 
219
173
  break
220
174
 
@@ -226,22 +180,24 @@ class DiziBox(PluginBase):
226
180
 
227
181
  async def load_links(self, url: str) -> list[ExtractResult]:
228
182
  istek = await self.httpx.get(url)
229
- secici = HTMLParser(istek.text)
183
+ secici = HTMLHelper(istek.text)
230
184
 
231
- results = []
232
- main_iframe_el = secici.css_first("div#video-area iframe")
233
- main_iframe = main_iframe_el.attrs.get("src") if main_iframe_el else None
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 = []
189
+ main_iframe = secici.select_attr("div#video-area iframe", "src")
234
190
 
235
191
  if main_iframe:
236
192
  if decoded := await self._iframe_decode(self.name, main_iframe, url):
237
193
  for iframe in decoded:
238
- data = await self.extract(iframe)
194
+ data = await self.extract(iframe, name_override=current_source_name)
239
195
  if data:
240
196
  results.append(data)
241
197
 
242
- for alternatif in secici.css("div.video-toolbar option[value]"):
243
- alt_name = alternatif.text(strip=True)
244
- alt_link = alternatif.attrs.get("value")
198
+ for alternatif in secici.select("div.video-toolbar option[value]"):
199
+ alt_name = secici.select_text(None, alternatif)
200
+ alt_link = secici.select_attr(None, "value", alternatif)
245
201
 
246
202
  if not alt_link:
247
203
  continue
@@ -250,14 +206,13 @@ class DiziBox(PluginBase):
250
206
  alt_istek = await self.httpx.get(alt_link)
251
207
  alt_istek.raise_for_status()
252
208
 
253
- alt_secici = HTMLParser(alt_istek.text)
254
- alt_iframe_el = alt_secici.css_first("div#video-area iframe")
255
- alt_iframe = alt_iframe_el.attrs.get("src") if alt_iframe_el else None
209
+ alt_secici = HTMLHelper(alt_istek.text)
210
+ alt_iframe = alt_secici.select_attr("div#video-area iframe", "src")
256
211
 
257
212
  if alt_iframe:
258
213
  if decoded := await self._iframe_decode(alt_name, alt_iframe, url):
259
214
  for iframe in decoded:
260
- data = await self.extract(iframe, prefix=alt_name)
215
+ data = await self.extract(iframe, name_override=alt_name)
261
216
  if data:
262
217
  results.append(data)
263
218