KekikStream 2.3.3__py3-none-any.whl → 2.3.5__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 (61) hide show
  1. KekikStream/Core/HTMLHelper.py +134 -0
  2. KekikStream/Core/Plugin/PluginBase.py +12 -2
  3. KekikStream/Core/__init__.py +2 -0
  4. KekikStream/Extractors/CloseLoad.py +12 -13
  5. KekikStream/Extractors/ContentX.py +33 -31
  6. KekikStream/Extractors/DonilasPlay.py +10 -10
  7. KekikStream/Extractors/DzenRu.py +3 -3
  8. KekikStream/Extractors/ExPlay.py +10 -10
  9. KekikStream/Extractors/Filemoon.py +11 -16
  10. KekikStream/Extractors/JetTv.py +4 -4
  11. KekikStream/Extractors/MixPlayHD.py +10 -11
  12. KekikStream/Extractors/MolyStream.py +15 -9
  13. KekikStream/Extractors/Odnoklassniki.py +4 -4
  14. KekikStream/Extractors/PeaceMakerst.py +3 -3
  15. KekikStream/Extractors/PixelDrain.py +6 -5
  16. KekikStream/Extractors/PlayerFilmIzle.py +6 -10
  17. KekikStream/Extractors/RapidVid.py +8 -7
  18. KekikStream/Extractors/SetPlay.py +10 -10
  19. KekikStream/Extractors/SetPrime.py +3 -6
  20. KekikStream/Extractors/SibNet.py +4 -5
  21. KekikStream/Extractors/Sobreatsesuyp.py +5 -5
  22. KekikStream/Extractors/TRsTX.py +5 -5
  23. KekikStream/Extractors/TurboImgz.py +3 -4
  24. KekikStream/Extractors/TurkeyPlayer.py +5 -5
  25. KekikStream/Extractors/VidHide.py +4 -7
  26. KekikStream/Extractors/VidMoly.py +24 -25
  27. KekikStream/Extractors/VidMoxy.py +8 -9
  28. KekikStream/Extractors/VidPapi.py +5 -7
  29. KekikStream/Extractors/VideoSeyred.py +3 -3
  30. KekikStream/Plugins/BelgeselX.py +40 -51
  31. KekikStream/Plugins/DiziBox.py +53 -81
  32. KekikStream/Plugins/DiziPal.py +41 -74
  33. KekikStream/Plugins/DiziWatch.py +217 -0
  34. KekikStream/Plugins/DiziYou.py +95 -88
  35. KekikStream/Plugins/Dizilla.py +54 -72
  36. KekikStream/Plugins/FilmBip.py +24 -49
  37. KekikStream/Plugins/FilmMakinesi.py +35 -52
  38. KekikStream/Plugins/FilmModu.py +27 -41
  39. KekikStream/Plugins/FullHDFilm.py +50 -72
  40. KekikStream/Plugins/FullHDFilmizlesene.py +35 -51
  41. KekikStream/Plugins/HDFilmCehennemi.py +48 -62
  42. KekikStream/Plugins/JetFilmizle.py +32 -50
  43. KekikStream/Plugins/KultFilmler.py +42 -67
  44. KekikStream/Plugins/RecTV.py +7 -4
  45. KekikStream/Plugins/RoketDizi.py +30 -50
  46. KekikStream/Plugins/SelcukFlix.py +15 -29
  47. KekikStream/Plugins/SetFilmIzle.py +41 -70
  48. KekikStream/Plugins/SezonlukDizi.py +47 -65
  49. KekikStream/Plugins/Sinefy.py +39 -50
  50. KekikStream/Plugins/SinemaCX.py +31 -55
  51. KekikStream/Plugins/Sinezy.py +27 -54
  52. KekikStream/Plugins/SuperFilmGeldi.py +25 -44
  53. KekikStream/Plugins/UgurFilm.py +23 -48
  54. KekikStream/Plugins/YabanciDizi.py +274 -0
  55. {kekikstream-2.3.3.dist-info → kekikstream-2.3.5.dist-info}/METADATA +1 -1
  56. kekikstream-2.3.5.dist-info/RECORD +85 -0
  57. kekikstream-2.3.3.dist-info/RECORD +0 -82
  58. {kekikstream-2.3.3.dist-info → kekikstream-2.3.5.dist-info}/WHEEL +0 -0
  59. {kekikstream-2.3.3.dist-info → kekikstream-2.3.5.dist-info}/entry_points.txt +0 -0
  60. {kekikstream-2.3.3.dist-info → kekikstream-2.3.5.dist-info}/licenses/LICENSE +0 -0
  61. {kekikstream-2.3.3.dist-info → kekikstream-2.3.5.dist-info}/top_level.txt +0 -0
@@ -1,8 +1,6 @@
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
4
- from selectolax.parser import HTMLParser
5
- import re
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult, HTMLHelper
6
4
 
7
5
  class JetFilmizle(PluginBase):
8
6
  name = "JetFilmizle"
@@ -40,23 +38,21 @@ class JetFilmizle(PluginBase):
40
38
 
41
39
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
42
40
  istek = await self.httpx.get(f"{url}{page}", follow_redirects=True)
43
- secici = HTMLParser(istek.text)
41
+ secici = HTMLHelper(istek.text)
44
42
 
45
43
  results = []
46
- for veri in secici.css("article.movie"):
44
+ for veri in secici.select("article.movie"):
47
45
  # h2-h6 içindeki a linki
48
- title_link = None
46
+ title_text = None
49
47
  for h_tag in ["h2", "h3", "h4", "h5", "h6"]:
50
- title_link = veri.css_first(f"{h_tag} a")
51
- if title_link:
48
+ title_text = secici.select_text(f"{h_tag} a", veri)
49
+ if title_text:
52
50
  break
53
51
 
54
- link_el = veri.css_first("a")
55
- img_el = veri.css_first("img")
52
+ href = secici.select_attr("a", "href", veri)
53
+ poster = secici.select_poster("img", veri)
56
54
 
57
- title = self.clean_title(title_link.text(strip=True)) if title_link else None
58
- href = link_el.attrs.get("href") if link_el else None
59
- poster = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
55
+ title = self.clean_title(title_text) if title_text else None
60
56
 
61
57
  if title and href:
62
58
  results.append(MainPageResult(
@@ -74,23 +70,21 @@ class JetFilmizle(PluginBase):
74
70
  data = {"s": query},
75
71
  headers = {"Referer": f"{self.main_url}/"}
76
72
  )
77
- secici = HTMLParser(istek.text)
73
+ secici = HTMLHelper(istek.text)
78
74
 
79
75
  results = []
80
- for article in secici.css("article.movie"):
76
+ for article in secici.select("article.movie"):
81
77
  # h2-h6 içindeki a linki
82
- title_link = None
78
+ title_text = None
83
79
  for h_tag in ["h2", "h3", "h4", "h5", "h6"]:
84
- title_link = article.css_first(f"{h_tag} a")
85
- if title_link:
80
+ title_text = secici.select_text(f"{h_tag} a", article)
81
+ if title_text:
86
82
  break
87
83
 
88
- link_el = article.css_first("a")
89
- img_el = article.css_first("img")
84
+ href = secici.select_attr("a", "href", article)
85
+ poster = secici.select_poster("img", article)
90
86
 
91
- title = self.clean_title(title_link.text(strip=True)) if title_link else None
92
- href = link_el.attrs.get("href") if link_el else None
93
- poster = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
87
+ title = self.clean_title(title_text) if title_text else None
94
88
 
95
89
  if title and href:
96
90
  results.append(SearchResult(
@@ -103,33 +97,22 @@ class JetFilmizle(PluginBase):
103
97
 
104
98
  async def load_item(self, url: str) -> MovieInfo:
105
99
  istek = await self.httpx.get(url)
106
- secici = HTMLParser(istek.text)
107
- html_text = istek.text
100
+ secici = HTMLHelper(istek.text)
108
101
 
109
- title_el = secici.css_first("div.movie-exp-title")
110
- title = self.clean_title(title_el.text(strip=True)) if title_el else None
102
+ title = self.clean_title(secici.select_text("div.movie-exp-title")) if secici.select_text("div.movie-exp-title") else None
111
103
 
112
- img_el = secici.css_first("section.movie-exp img")
113
- poster_raw = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
114
- poster = poster_raw.strip() if poster_raw else None
104
+ poster = secici.select_poster("section.movie-exp img")
105
+ poster = poster.strip() if poster else None
115
106
 
116
- desc_el = secici.css_first("section.movie-exp p.aciklama")
117
- description = desc_el.text(strip=True) if desc_el else None
107
+ description = secici.select_text("section.movie-exp p.aciklama")
118
108
 
119
- tags = [a.text(strip=True) for a in secici.css("section.movie-exp div.catss a") if a.text(strip=True)]
109
+ tags = secici.select_all_text("section.movie-exp div.catss a")
120
110
 
121
- rating_el = secici.css_first("section.movie-exp div.imdb_puan span")
122
- rating = rating_el.text(strip=True) if rating_el else None
111
+ rating = secici.select_text("section.movie-exp div.imdb_puan span")
123
112
 
124
- # Year - div.yap içinde 4 haneli sayı ara (xpath yerine regex)
125
- year = None
126
- yap_match = re.search(r'<div class="yap"[^>]*>([^<]*(?:Vizyon|Yapım)[^<]*)</div>', html_text, re.IGNORECASE)
127
- if yap_match:
128
- year_match = re.search(r'(\d{4})', yap_match.group(1))
129
- if year_match:
130
- year = year_match.group(1)
113
+ year = secici.extract_year("div.yap")
131
114
 
132
- actors = [a.text(strip=True) for a in secici.css("div[itemprop='actor'] a span") if a.text(strip=True)]
115
+ actors = secici.select_all_text("div[itemprop='actor'] a span")
133
116
 
134
117
  return MovieInfo(
135
118
  url = url,
@@ -144,12 +127,12 @@ class JetFilmizle(PluginBase):
144
127
 
145
128
  async def load_links(self, url: str) -> list[ExtractResult]:
146
129
  istek = await self.httpx.get(url)
147
- secici = HTMLParser(istek.text)
130
+ secici = HTMLHelper(istek.text)
148
131
 
149
132
  results = []
150
133
 
151
134
  # 1) Ana iframe'leri kontrol et
152
- for iframe in secici.css("iframe"):
135
+ for iframe in secici.select("iframe"):
153
136
  src = (iframe.attrs.get("src") or
154
137
  iframe.attrs.get("data-src") or
155
138
  iframe.attrs.get("data-lazy-src"))
@@ -162,9 +145,8 @@ class JetFilmizle(PluginBase):
162
145
 
163
146
  # 2) Sayfa numaralarından linkleri topla (Fragman hariç)
164
147
  page_links = []
165
- for link in secici.css("a.post-page-numbers"):
166
- span_el = link.css_first("span")
167
- isim = span_el.text(strip=True) if span_el else ""
148
+ for link in secici.select("a.post-page-numbers"):
149
+ isim = secici.select_text("span", link) or ""
168
150
  if isim != "Fragman":
169
151
  href = link.attrs.get("href")
170
152
  if href:
@@ -174,9 +156,9 @@ class JetFilmizle(PluginBase):
174
156
  for page_url, isim in page_links:
175
157
  try:
176
158
  page_resp = await self.httpx.get(page_url)
177
- page_sel = HTMLParser(page_resp.text)
159
+ page_sel = HTMLHelper(page_resp.text)
178
160
 
179
- for iframe in page_sel.css("div#movie iframe"):
161
+ for iframe in page_sel.select("div#movie iframe"):
180
162
  src = (iframe.attrs.get("src") or
181
163
  iframe.attrs.get("data-src") or
182
164
  iframe.attrs.get("data-lazy-src"))
@@ -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, MovieInfo, SeriesInfo, Episode, ExtractResult, Subtitle
4
- from selectolax.parser import HTMLParser
5
- import re, base64
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult, Subtitle, HTMLHelper
4
+ import base64
6
5
 
7
6
  class KultFilmler(PluginBase):
8
7
  name = "KultFilmler"
@@ -38,16 +37,13 @@ class KultFilmler(PluginBase):
38
37
 
39
38
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
40
39
  istek = await self.httpx.get(url)
41
- secici = HTMLParser(istek.text)
40
+ secici = HTMLHelper(istek.text)
42
41
 
43
42
  results = []
44
- for veri in secici.css("div.col-md-12 div.movie-box"):
45
- img_el = veri.css_first("div.img img")
46
- link_el = veri.css_first("a")
47
-
48
- title = img_el.attrs.get("alt") if img_el else None
49
- href = link_el.attrs.get("href") if link_el else None
50
- poster = img_el.attrs.get("src") if img_el else None
43
+ for veri in secici.select("div.col-md-12 div.movie-box"):
44
+ title = secici.select_attr("div.img img", "alt", veri)
45
+ href = secici.select_attr("a", "href", veri)
46
+ poster = secici.select_attr("div.img img", "src", veri)
51
47
 
52
48
  if title and href:
53
49
  results.append(MainPageResult(
@@ -61,16 +57,13 @@ class KultFilmler(PluginBase):
61
57
 
62
58
  async def search(self, query: str) -> list[SearchResult]:
63
59
  istek = await self.httpx.get(f"{self.main_url}?s={query}")
64
- secici = HTMLParser(istek.text)
60
+ secici = HTMLHelper(istek.text)
65
61
 
66
62
  results = []
67
- for veri in secici.css("div.movie-box"):
68
- img_el = veri.css_first("div.img img")
69
- link_el = veri.css_first("a")
70
-
71
- title = img_el.attrs.get("alt") if img_el else None
72
- href = link_el.attrs.get("href") if link_el else None
73
- poster = img_el.attrs.get("src") if img_el else None
63
+ for veri in secici.select("div.movie-box"):
64
+ title = secici.select_attr("div.img img", "alt", veri)
65
+ href = secici.select_attr("a", "href", veri)
66
+ poster = secici.select_attr("div.img img", "src", veri)
74
67
 
75
68
  if title and href:
76
69
  results.append(SearchResult(
@@ -83,58 +76,43 @@ class KultFilmler(PluginBase):
83
76
 
84
77
  async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
85
78
  istek = await self.httpx.get(url)
86
- secici = HTMLParser(istek.text)
87
-
88
- film_img = secici.css_first("div.film-bilgileri img")
89
- og_title = secici.css_first("[property='og:title']")
90
- og_image = secici.css_first("[property='og:image']")
79
+ secici = HTMLHelper(istek.text)
91
80
 
92
- title = (film_img.attrs.get("alt") if film_img else None) or (og_title.attrs.get("content") if og_title else None)
93
- poster = self.fix_url(og_image.attrs.get("content")) if og_image else None
81
+ title = secici.select_attr("div.film-bilgileri img", "alt") or secici.select_attr("[property='og:title']", "content")
82
+ poster = self.fix_url(secici.select_attr("[property='og:image']", "content")) if secici.select_attr("[property='og:image']", "content") else None
94
83
 
95
- desc_el = secici.css_first("div.description")
96
- description = desc_el.text(strip=True) if desc_el else None
84
+ description = secici.select_text("div.description")
97
85
 
98
- tags = [a.text(strip=True) for a in secici.css("ul.post-categories a") if a.text(strip=True)]
86
+ tags = [a.text(strip=True) for a in secici.select("ul.post-categories a") if a.text(strip=True)]
99
87
 
100
88
  # HTML analizine göre güncellenen alanlar
101
- year_el = secici.css_first("li.release span a")
102
- year = year_el.text(strip=True) if year_el else None
89
+ year = secici.select_text("li.release span a")
103
90
 
104
- time_el = secici.css_first("li.time span")
105
- duration = None
106
- if time_el:
107
- time_text = time_el.text(strip=True)
108
- dur_match = re.search(r"(\d+)", time_text)
109
- duration = dur_match.group(1) if dur_match else None
91
+ time_text = secici.select_text("li.time span")
92
+ duration = secici.regex_first(r"(\d+)", time_text) if time_text else None
110
93
 
111
- rating_el = secici.css_first("div.imdb-count")
112
- rating = rating_el.text(strip=True) if rating_el else None
94
+ rating = secici.select_text("div.imdb-count")
113
95
 
114
- actors = [a.text(strip=True) for a in secici.css("div.actors a") if a.text(strip=True)]
96
+ actors = [a.text(strip=True) for a in secici.select("div.actors a") if a.text(strip=True)]
115
97
 
116
98
  # Dizi mi kontrol et
117
99
  if "/dizi/" in url:
118
100
  episodes = []
119
- for bolum in secici.css("div.episode-box"):
120
- name_link = bolum.css_first("div.name a")
121
- ep_href = name_link.attrs.get("href") if name_link else None
101
+ for bolum in secici.select("div.episode-box"):
102
+ ep_href = secici.select_attr("div.name a", "href", bolum)
122
103
 
123
- ssn_el = bolum.css_first("span.episodetitle")
124
- ssn_detail = ssn_el.text(strip=True) if ssn_el else ""
125
-
126
- ep_b_el = bolum.css_first("span.episodetitle b")
127
- ep_detail = ep_b_el.text(strip=True) if ep_b_el else ""
104
+ ssn_detail = secici.select_text("span.episodetitle", bolum) or ""
105
+ ep_detail = secici.select_text("span.episodetitle b", bolum) or ""
128
106
 
129
107
  ep_name = f"{ssn_detail} - {ep_detail}"
130
108
 
131
109
  if ep_href:
132
- ep_season = re.search(r"(\d+)\.", ssn_detail)
133
- ep_episode = re.search(r"(\d+)\.", ep_detail)
110
+ ep_season = secici.regex_first(r"(\d+)\.", ssn_detail)
111
+ ep_episode = secici.regex_first(r"(\d+)\.", ep_detail)
134
112
 
135
113
  episodes.append(Episode(
136
- season = int(ep_season[1]) if ep_season else 1,
137
- episode = int(ep_episode[1]) if ep_episode else 1,
114
+ season = int(ep_season) if ep_season else 1,
115
+ episode = int(ep_episode) if ep_episode else 1,
138
116
  title = ep_name.strip(" -"),
139
117
  url = self.fix_url(ep_href),
140
118
  ))
@@ -165,12 +143,10 @@ class KultFilmler(PluginBase):
165
143
 
166
144
  def _get_iframe(self, source_code: str) -> str:
167
145
  """Base64 kodlu iframe'i çözümle"""
168
- atob_match = re.search(r"PHA\+[0-9a-zA-Z+/=]*", source_code)
169
- if not atob_match:
146
+ atob = HTMLHelper(source_code).regex_first(r"PHA\+[0-9a-zA-Z+/=]*")
147
+ if not atob:
170
148
  return ""
171
149
 
172
- atob = atob_match.group()
173
-
174
150
  # Padding düzelt
175
151
  padding = 4 - len(atob) % 4
176
152
  if padding < 4:
@@ -178,20 +154,19 @@ class KultFilmler(PluginBase):
178
154
 
179
155
  try:
180
156
  decoded = base64.b64decode(atob).decode("utf-8")
181
- secici = HTMLParser(decoded)
182
- iframe_el = secici.css_first("iframe")
183
- return self.fix_url(iframe_el.attrs.get("src")) if iframe_el else ""
157
+ secici = HTMLHelper(decoded)
158
+ iframe_src = secici.select_attr("iframe", "src")
159
+ return self.fix_url(iframe_src) if iframe_src else ""
184
160
  except Exception:
185
161
  return ""
186
162
 
187
163
  def _extract_subtitle_url(self, source_code: str) -> str | None:
188
164
  """Altyazı URL'sini çıkar"""
189
- match = re.search(r"(https?://[^\s\"]+\.srt)", source_code)
190
- return match[1] if match else None
165
+ return HTMLHelper(source_code).regex_first(r"(https?://[^\s\"]+\.srt)")
191
166
 
192
167
  async def load_links(self, url: str) -> list[ExtractResult]:
193
168
  istek = await self.httpx.get(url)
194
- secici = HTMLParser(istek.text)
169
+ secici = HTMLHelper(istek.text)
195
170
 
196
171
  iframes = set()
197
172
 
@@ -201,9 +176,9 @@ class KultFilmler(PluginBase):
201
176
  iframes.add(main_frame)
202
177
 
203
178
  # Alternatif player'lar
204
- for player in secici.css("div.container#player"):
205
- iframe_el = player.css_first("iframe")
206
- alt_iframe = self.fix_url(iframe_el.attrs.get("src")) if iframe_el else None
179
+ for player in secici.select("div.container#player"):
180
+ iframe_src = secici.select_attr("iframe", "src", player)
181
+ alt_iframe = self.fix_url(iframe_src) if iframe_src else None
207
182
  if alt_iframe:
208
183
  alt_istek = await self.httpx.get(alt_iframe)
209
184
  alt_frame = self._get_iframe(alt_istek.text)
@@ -222,12 +197,12 @@ class KultFilmler(PluginBase):
222
197
  "Sec-Fetch-Dest" : "iframe"
223
198
  }
224
199
  iframe_istek = await self.httpx.get(iframe, headers=headers)
225
- m3u_match = re.search(r'file:"([^"]+)"', iframe_istek.text)
200
+ m3u_match = HTMLHelper(iframe_istek.text).regex_first(r'file:"([^"]+)"')
226
201
 
227
202
  if m3u_match:
228
203
  results.append(ExtractResult(
229
204
  name = "VidMoly",
230
- url = m3u_match[1],
205
+ url = m3u_match,
231
206
  referer = self.main_url,
232
207
  subtitles = []
233
208
  ))
@@ -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, MovieInfo, Episode, SeriesInfo, ExtractResult
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, Episode, SeriesInfo, ExtractResult, HTMLHelper
4
4
  from json import dumps, loads
5
- import re
6
5
 
7
6
  class RecTV(PluginBase):
8
7
  name = "RecTV"
@@ -84,9 +83,13 @@ class RecTV(PluginBase):
84
83
  "is_episode" : True
85
84
  }
86
85
 
86
+ # Extract season/episode numbers using helper
87
+ s1, _ = HTMLHelper.extract_season_episode(season.get("title") or "")
88
+ _, e2 = HTMLHelper.extract_season_episode(episode.get("title") or "")
89
+
87
90
  ep_model = Episode(
88
- season = int(re.search(r"(\d+)\.S", season.get("title")).group(1)) if re.search(r"(\d+)\.S", season.get("title")) else 1,
89
- episode = int(re.search(r"Bölüm (\d+)", episode.get("title")).group(1)) if re.search(r"Bölüm (\d+)", episode.get("title")) else 1,
91
+ season = s1 or 1,
92
+ episode = e2 or 1,
90
93
  title = episode.get("title"),
91
94
  url = dumps(ep_data),
92
95
  )
@@ -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, MovieInfo
4
- from selectolax.parser import HTMLParser
5
- import re, base64, json
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, MovieInfo, HTMLHelper
4
+ import base64, json
6
5
 
7
6
  class RoketDizi(PluginBase):
8
7
  name = "RoketDizi"
@@ -24,19 +23,15 @@ class RoketDizi(PluginBase):
24
23
 
25
24
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
26
25
  istek = await self.httpx.get(f"{url}?&page={page}")
27
- secici = HTMLParser(istek.text)
26
+ secici = HTMLHelper(istek.text)
28
27
 
29
28
  results = []
30
29
 
31
30
  # Use div.new-added-list to find the container, then get items
32
- for item in secici.css("div.new-added-list > span"):
33
- title_el = item.css_first("span.line-clamp-1")
34
- link_el = item.css_first("a")
35
- img_el = item.css_first("img")
36
-
37
- title = title_el.text(strip=True) if title_el else None
38
- href = link_el.attrs.get("href") if link_el else None
39
- poster = img_el.attrs.get("src") if img_el else None
31
+ for item in secici.select("div.new-added-list > span"):
32
+ title = secici.select_text("span.line-clamp-1", item)
33
+ href = secici.select_attr("a", "href", item)
34
+ poster = secici.select_attr("img", "src", item)
40
35
 
41
36
  if title and href:
42
37
  results.append(MainPageResult(
@@ -92,58 +87,49 @@ class RoketDizi(PluginBase):
92
87
  async def load_item(self, url: str) -> SeriesInfo:
93
88
  # Note: Handling both Movie and Series logic in one, returning SeriesInfo generally or MovieInfo
94
89
  resp = await self.httpx.get(url)
95
- sel = HTMLParser(resp.text)
90
+ sel = HTMLHelper(resp.text)
96
91
  html_text = resp.text
97
92
 
98
- title_el = sel.css_first("h1.text-white")
99
- title = title_el.text(strip=True) if title_el else None
93
+ title = sel.select_text("h1.text-white")
100
94
 
101
- poster_el = sel.css_first("div.w-full.page-top img")
102
- poster = poster_el.attrs.get("src") if poster_el else None
95
+ poster = sel.select_attr("div.w-full.page-top img", "src")
103
96
 
104
- desc_el = sel.css_first("div.mt-2.text-sm")
105
- description = desc_el.text(strip=True) if desc_el else None
97
+ description = sel.select_text("div.mt-2.text-sm")
106
98
 
107
99
  # Tags - genre bilgileri (Detaylar bölümünde)
108
100
  tags = []
109
- genre_el = sel.css_first("h3.text-white.opacity-90")
110
- if genre_el:
111
- genre_text = genre_el.text(strip=True)
112
- if genre_text:
113
- tags = [t.strip() for t in genre_text.split(",")]
101
+ genre_text = sel.select_text("h3.text-white.opacity-90")
102
+ if genre_text:
103
+ tags = [t.strip() for t in genre_text.split(",")]
114
104
 
115
105
  # Rating
116
- rating_el = sel.css_first("span.text-white.text-sm.font-bold")
117
- rating = rating_el.text(strip=True) if rating_el else None
106
+ rating = sel.select_text("span.text-white.text-sm.font-bold")
118
107
 
119
108
  # Year ve Actors - Detaylar (Details) bölümünden
120
109
  year = None
121
110
  actors = []
122
111
 
123
112
  # Detaylar bölümündeki tüm flex-col div'leri al
124
- detail_items = sel.css("div.flex.flex-col")
113
+ detail_items = sel.select("div.flex.flex-col")
125
114
  for item in detail_items:
126
- label_el = item.css_first("span.text-base")
127
- value_el = item.css_first("span.text-sm.opacity-90")
115
+ label = sel.select_text("span.text-base", item)
116
+ value = sel.select_text("span.text-sm.opacity-90", item)
128
117
 
129
- label = label_el.text(strip=True) if label_el else None
130
- value = value_el.text(strip=True) if value_el else None
118
+ label = label if label else None
119
+ value = value if value else None
131
120
 
132
121
  if label and value:
133
122
  # Yayın tarihi (yıl)
134
123
  if label == "Yayın tarihi":
135
124
  # "16 Ekim 2018" formatından yılı çıkar
136
- year_match = re.search(r'\d{4}', value)
137
- if year_match:
138
- year = year_match.group()
139
-
125
+ year = HTMLHelper(value).regex_first(r'\d{4}')
140
126
  # Yaratıcılar veya Oyuncular
141
127
  elif label in ["Yaratıcılar", "Oyuncular"]:
142
128
  if value:
143
129
  actors.append(value)
144
130
 
145
131
  # Check urls for episodes
146
- all_urls = re.findall(r'"url":"([^"]*)"', html_text)
132
+ all_urls = HTMLHelper(html_text).regex_all(r'"url":"([^"]*)"')
147
133
  is_series = any("bolum-" in u for u in all_urls)
148
134
 
149
135
  episodes = []
@@ -152,11 +138,11 @@ class RoketDizi(PluginBase):
152
138
  episodes_dict = {}
153
139
  for u in all_urls:
154
140
  if "bolum" in u and u not in episodes_dict:
155
- season_match = re.search(r'/sezon-(\d+)', u)
156
- ep_match = re.search(r'/bolum-(\d+)', u)
141
+ season = HTMLHelper(u).regex_first(r'/sezon-(\d+)')
142
+ ep_num = HTMLHelper(u).regex_first(r'/bolum-(\d+)')
157
143
 
158
- season = int(season_match.group(1)) if season_match else 1
159
- episode_num = int(ep_match.group(1)) if ep_match else 1
144
+ season = int(season) if season else 1
145
+ episode_num = int(ep_num) if ep_num else 1
160
146
 
161
147
  # Key olarak (season, episode) tuple kullan
162
148
  key = (season, episode_num)
@@ -184,13 +170,9 @@ class RoketDizi(PluginBase):
184
170
 
185
171
  async def load_links(self, url: str) -> list[ExtractResult]:
186
172
  resp = await self.httpx.get(url)
187
- sel = HTMLParser(resp.text)
173
+ sel = HTMLHelper(resp.text)
188
174
 
189
- next_data_el = sel.css_first("script#__NEXT_DATA__")
190
- if not next_data_el:
191
- return []
192
-
193
- next_data = next_data_el.text(strip=True)
175
+ next_data = sel.select_text("script#__NEXT_DATA__")
194
176
  if not next_data:
195
177
  return []
196
178
 
@@ -208,11 +190,9 @@ class RoketDizi(PluginBase):
208
190
  source_content = source.get("source_content", "")
209
191
 
210
192
  # iframe URL'ini source_content'ten çıkar
211
- iframe_match = re.search(r'<iframe[^>]*src=["\']([^"\']*)["\']', source_content)
212
- if not iframe_match:
193
+ iframe_url = HTMLHelper(source_content).regex_first(r'<iframe[^>]*src=["\']([^"\']*)["\']')
194
+ if not iframe_url:
213
195
  continue
214
-
215
- iframe_url = iframe_match.group(1)
216
196
 
217
197
  # Fix URL protocol
218
198
  if not iframe_url.startswith("http"):
@@ -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, MovieInfo, SeriesInfo, Episode, ExtractResult
4
- from selectolax.parser import HTMLParser
5
- import re, base64, json, urllib.parse
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult, HTMLHelper
4
+ import base64, json, urllib.parse
6
5
 
7
6
  class SelcukFlix(PluginBase):
8
7
  name = "SelcukFlix"
@@ -34,17 +33,13 @@ class SelcukFlix(PluginBase):
34
33
  if "tum-bolumler" in url:
35
34
  try:
36
35
  resp = await self.httpx.get(url)
37
- sel = HTMLParser(resp.text)
36
+ sel = HTMLHelper(resp.text)
38
37
 
39
- for item in sel.css("div.col-span-3 a"):
40
- name_el = item.css_first("h2")
41
- ep_el = item.css_first("div.opacity-80")
42
- img_el = item.css_first("div.image img")
43
-
44
- name = name_el.text(strip=True) if name_el else None
45
- ep_info = ep_el.text(strip=True) if ep_el else None
46
- href = item.attrs.get("href")
47
- poster = img_el.attrs.get("src") if img_el else None
38
+ for item in sel.select("div.col-span-3 a"):
39
+ name = sel.select_text("h2", item)
40
+ ep_info = sel.select_text("div.opacity-80", item)
41
+ href = sel.select_attr("a", "href", item)
42
+ poster = sel.select_attr("div.image img", "src", item)
48
43
 
49
44
  if name and href:
50
45
  title = f"{name} - {ep_info}" if ep_info else name
@@ -188,14 +183,10 @@ class SelcukFlix(PluginBase):
188
183
 
189
184
  async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
190
185
  resp = await self.httpx.get(url)
191
- sel = HTMLParser(resp.text)
192
-
193
- next_data_el = sel.css_first("script#__NEXT_DATA__")
194
- if not next_data_el:
195
- return None
186
+ sel = HTMLHelper(resp.text)
196
187
 
197
- next_data = next_data_el.text(strip=True)
198
- if not next_data:
188
+ next_data = sel.select_text("script#__NEXT_DATA__")
189
+ if not next_data:
199
190
  return None
200
191
 
201
192
  data = json.loads(next_data)
@@ -266,13 +257,9 @@ class SelcukFlix(PluginBase):
266
257
 
267
258
  async def load_links(self, url: str) -> list[ExtractResult]:
268
259
  resp = await self.httpx.get(url)
269
- sel = HTMLParser(resp.text)
260
+ sel = HTMLHelper(resp.text)
270
261
 
271
- next_data_el = sel.css_first("script#__NEXT_DATA__")
272
- if not next_data_el:
273
- return []
274
-
275
- next_data = next_data_el.text(strip=True)
262
+ next_data = sel.select_text("script#__NEXT_DATA__")
276
263
  if not next_data:
277
264
  return []
278
265
 
@@ -312,9 +299,8 @@ class SelcukFlix(PluginBase):
312
299
  source_content = res[0].get("source_content") or res[0].get("sourceContent")
313
300
 
314
301
  if source_content:
315
- iframe_sel = HTMLParser(source_content)
316
- iframe_el = iframe_sel.css_first("iframe")
317
- iframe_src = iframe_el.attrs.get("src") if iframe_el else None
302
+ iframe_sel = HTMLHelper(source_content)
303
+ iframe_src = iframe_sel.select_attr("iframe", "src")
318
304
  if iframe_src:
319
305
  iframe_src = self.fix_url(iframe_src)
320
306
  # Hotlinger domain değişimi (Kotlin referansı)