KekikStream 2.2.8__py3-none-any.whl → 2.3.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.
Files changed (62) hide show
  1. KekikStream/Core/HTMLHelper.py +134 -0
  2. KekikStream/Core/Plugin/PluginBase.py +22 -4
  3. KekikStream/Core/Plugin/PluginLoader.py +3 -2
  4. KekikStream/Core/Plugin/PluginManager.py +2 -2
  5. KekikStream/Core/__init__.py +2 -0
  6. KekikStream/Extractors/CloseLoad.py +12 -13
  7. KekikStream/Extractors/ContentX.py +33 -31
  8. KekikStream/Extractors/DonilasPlay.py +10 -10
  9. KekikStream/Extractors/DzenRu.py +3 -3
  10. KekikStream/Extractors/ExPlay.py +10 -10
  11. KekikStream/Extractors/Filemoon.py +47 -37
  12. KekikStream/Extractors/JetTv.py +4 -4
  13. KekikStream/Extractors/MixPlayHD.py +10 -11
  14. KekikStream/Extractors/MolyStream.py +16 -9
  15. KekikStream/Extractors/Odnoklassniki.py +4 -4
  16. KekikStream/Extractors/PeaceMakerst.py +3 -3
  17. KekikStream/Extractors/PixelDrain.py +6 -5
  18. KekikStream/Extractors/PlayerFilmIzle.py +6 -10
  19. KekikStream/Extractors/RapidVid.py +8 -7
  20. KekikStream/Extractors/SetPlay.py +10 -10
  21. KekikStream/Extractors/SetPrime.py +3 -6
  22. KekikStream/Extractors/SibNet.py +4 -5
  23. KekikStream/Extractors/Sobreatsesuyp.py +5 -5
  24. KekikStream/Extractors/TRsTX.py +5 -5
  25. KekikStream/Extractors/TurboImgz.py +3 -4
  26. KekikStream/Extractors/TurkeyPlayer.py +5 -5
  27. KekikStream/Extractors/VidHide.py +4 -7
  28. KekikStream/Extractors/VidMoly.py +37 -25
  29. KekikStream/Extractors/VidMoxy.py +8 -9
  30. KekikStream/Extractors/VidPapi.py +5 -7
  31. KekikStream/Extractors/VideoSeyred.py +3 -3
  32. KekikStream/Plugins/BelgeselX.py +40 -51
  33. KekikStream/Plugins/DiziBox.py +53 -81
  34. KekikStream/Plugins/DiziPal.py +50 -72
  35. KekikStream/Plugins/DiziYou.py +96 -83
  36. KekikStream/Plugins/Dizilla.py +101 -86
  37. KekikStream/Plugins/FilmBip.py +29 -50
  38. KekikStream/Plugins/FilmMakinesi.py +84 -46
  39. KekikStream/Plugins/FilmModu.py +27 -41
  40. KekikStream/Plugins/FullHDFilm.py +57 -62
  41. KekikStream/Plugins/FullHDFilmizlesene.py +32 -57
  42. KekikStream/Plugins/HDFilmCehennemi.py +51 -65
  43. KekikStream/Plugins/JetFilmizle.py +38 -51
  44. KekikStream/Plugins/KultFilmler.py +43 -67
  45. KekikStream/Plugins/RecTV.py +34 -9
  46. KekikStream/Plugins/RoketDizi.py +89 -111
  47. KekikStream/Plugins/SelcukFlix.py +102 -93
  48. KekikStream/Plugins/SetFilmIzle.py +110 -117
  49. KekikStream/Plugins/SezonlukDizi.py +88 -106
  50. KekikStream/Plugins/Sinefy.py +70 -70
  51. KekikStream/Plugins/SinemaCX.py +31 -55
  52. KekikStream/Plugins/Sinezy.py +27 -54
  53. KekikStream/Plugins/SuperFilmGeldi.py +25 -44
  54. KekikStream/Plugins/UgurFilm.py +23 -48
  55. KekikStream/Plugins/YabanciDizi.py +285 -0
  56. {kekikstream-2.2.8.dist-info → kekikstream-2.3.9.dist-info}/METADATA +1 -1
  57. kekikstream-2.3.9.dist-info/RECORD +84 -0
  58. kekikstream-2.2.8.dist-info/RECORD +0 -82
  59. {kekikstream-2.2.8.dist-info → kekikstream-2.3.9.dist-info}/WHEEL +0 -0
  60. {kekikstream-2.2.8.dist-info → kekikstream-2.3.9.dist-info}/entry_points.txt +0 -0
  61. {kekikstream-2.2.8.dist-info → kekikstream-2.3.9.dist-info}/licenses/LICENSE +0 -0
  62. {kekikstream-2.2.8.dist-info → kekikstream-2.3.9.dist-info}/top_level.txt +0 -0
@@ -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 ExtractorBase, ExtractResult, Subtitle
4
- import json, re
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle, HTMLHelper
4
+ import json
5
5
 
6
6
  class VideoSeyred(ExtractorBase):
7
7
  name = "VideoSeyred"
@@ -16,7 +16,7 @@ class VideoSeyred(ExtractorBase):
16
16
  kontrol = await self.httpx.get(url)
17
17
  kontrol.raise_for_status()
18
18
 
19
- video_id = re.search(r"playlist\/(.*)\.json", kontrol.text)[1]
19
+ video_id = HTMLHelper(kontrol.text).regex_first(r"playlist\/(.*)\.json")
20
20
 
21
21
  video_url = f"{self.main_url}/playlist/{video_id}.json"
22
22
 
@@ -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, SeriesInfo, Episode, ExtractResult
4
- from selectolax.parser import HTMLParser
5
- import re
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
6
4
 
7
5
  class BelgeselX(PluginBase):
8
6
  name = "BelgeselX"
@@ -43,22 +41,17 @@ class BelgeselX(PluginBase):
43
41
 
44
42
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
45
43
  istek = self.cloudscraper.get(f"{url}{page}")
46
- secici = HTMLParser(istek.text)
44
+ secici = HTMLHelper(istek.text)
47
45
 
48
46
  results = []
49
47
  # 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"):
48
+ for container in secici.select("div.gen-movie-contain"):
51
49
  # 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
50
+ poster = secici.select_attr("div.gen-movie-img img", "src", container)
54
51
 
55
52
  # 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")
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)
62
55
 
63
56
  if title and href:
64
57
  results.append(MainPageResult(
@@ -77,15 +70,13 @@ class BelgeselX(PluginBase):
77
70
  token_resp = self.cloudscraper.get(f"https://cse.google.com/cse.js?cx={cx}")
78
71
  token_text = token_resp.text
79
72
 
80
- cse_lib_match = re.search(r'cselibVersion": "(.*)"', token_text)
81
- cse_tok_match = re.search(r'cse_token": "(.*)"', token_text)
73
+ secici = HTMLHelper(token_text)
74
+ cse_lib = secici.regex_first(r'cselibVersion": "(.*)"')
75
+ cse_tok = secici.regex_first(r'cse_token": "(.*)"')
82
76
 
83
- if not cse_lib_match or not cse_tok_match:
77
+ if not cse_lib or not cse_tok:
84
78
  return []
85
79
 
86
- cse_lib = cse_lib_match.group(1)
87
- cse_tok = cse_tok_match.group(1)
88
-
89
80
  search_url = (
90
81
  f"https://cse.google.com/cse/element/v1?"
91
82
  f"rsz=filtered_cse&num=100&hl=tr&source=gcsc&cselibv={cse_lib}&cx={cx}"
@@ -96,9 +87,10 @@ class BelgeselX(PluginBase):
96
87
  resp = self.cloudscraper.get(search_url)
97
88
  resp_text = resp.text
98
89
 
99
- titles = re.findall(r'"titleNoFormatting": "(.*?)"', resp_text)
100
- urls = re.findall(r'"url": "(.*?)"', resp_text)
101
- images = re.findall(r'"ogImage": "(.*?)"', resp_text)
90
+ 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": "(.*?)"')
102
94
 
103
95
  results = []
104
96
  for i, title in enumerate(titles):
@@ -109,7 +101,8 @@ class BelgeselX(PluginBase):
109
101
  # URL'den belgesel linkini oluştur
110
102
  if poster and "diziresimleri" in poster:
111
103
  file_name = poster.rsplit("/", 1)[-1]
112
- file_name = re.sub(r"\.(jpe?g|png|webp)$", "", file_name)
104
+ secici3 = HTMLHelper(file_name)
105
+ file_name = secici3.regex_replace(r"\.(jpe?g|png|webp)$", "")
113
106
  url_val = f"{self.main_url}/belgeseldizi/{file_name}"
114
107
  else:
115
108
  continue
@@ -125,45 +118,37 @@ class BelgeselX(PluginBase):
125
118
 
126
119
  async def load_item(self, url: str) -> SeriesInfo:
127
120
  istek = await self.httpx.get(url)
128
- secici = HTMLParser(istek.text)
121
+ secici = HTMLHelper(istek.text)
129
122
 
130
- title_el = secici.css_first("h2.gen-title")
131
- title = title_el.text(strip=True) if title_el else None
123
+ title = secici.select_text("h2.gen-title")
132
124
 
133
- poster_el = secici.css_first("div.gen-tv-show-top img")
134
- poster = poster_el.attrs.get("src") if poster_el else None
125
+ poster = secici.select_attr("div.gen-tv-show-top img", "src")
135
126
 
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
127
+ description = secici.select_text("div.gen-single-tv-show-info p")
138
128
 
139
129
  tags = []
140
- for tag_link in secici.css("div.gen-socail-share a[href*='belgeselkanali']"):
141
- tag_href = tag_link.attrs.get("href")
130
+ for tag_link in secici.select("div.gen-socail-share a[href*='belgeselkanali']"):
131
+ tag_href = secici.select_attr("a", "href", tag_link)
142
132
  if tag_href:
143
133
  tag_name = tag_href.rsplit("/", 1)[-1].replace("-", " ")
144
134
  tags.append(self._to_title_case(tag_name))
145
135
 
146
136
  episodes = []
147
137
  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")
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)
155
141
 
156
142
  if not ep_name or not ep_href:
157
143
  continue
158
144
 
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 ""
145
+ season_text = secici.select_text("div.gen-single-meta-holder ul li", ep_item)
161
146
 
162
- episode_match = re.search(r"Bölüm (\d+)", season_text)
163
- season_match = re.search(r"Sezon (\d+)", season_text)
147
+ episode_num = secici.regex_first(r"Bölüm (\d+)", season_text)
148
+ season_num = secici.regex_first(r"Sezon (\d+)", season_text)
164
149
 
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
150
+ ep_episode = int(episode_num) if episode_num else counter
151
+ ep_season = int(season_num) if season_num else 1
167
152
 
168
153
  counter += 1
169
154
 
@@ -187,21 +172,25 @@ class BelgeselX(PluginBase):
187
172
  istek = await self.httpx.get(url)
188
173
  text = istek.text
189
174
 
175
+ secici = HTMLHelper(text)
190
176
  # 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:
177
+ episode_id = secici.regex_first(r'<div[^>]*class=["\'][^"\']*fnc_addWatch[^"\']*["\'][^>]*data-episode=["\'](\d+)["\']')
178
+ if not episode_id:
193
179
  return []
194
180
 
195
- episode_id = ep_match.group(1)
196
181
  iframe_url = f"{self.main_url}/video/data/new4.php?id={episode_id}"
197
182
 
198
183
  iframe_resp = await self.httpx.get(iframe_url, headers={"Referer": url})
199
184
  iframe_text = iframe_resp.text
200
185
 
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: "([^"]+)"')
190
+
201
191
  links = []
202
- for match in re.finditer(r'file:"([^"]+)", label: "([^"]+)"', iframe_text):
203
- video_url = match.group(1)
204
- quality = match.group(2)
192
+ for i, video_url in enumerate(file_matches):
193
+ quality = label_matches[i] if i < len(label_matches) else "Unknown"
205
194
 
206
195
  source_name = "Google" if quality == "FULL" else self.name
207
196
  quality_str = "1080p" if quality == "FULL" else quality
@@ -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
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
4
4
  from Kekik.Sifreleme import CryptoJS
5
- from selectolax.parser import HTMLParser
6
- import re, urllib.parse, base64, contextlib, asyncio, time
5
+ import urllib.parse, base64, contextlib, asyncio, time
7
6
 
8
7
  class DiziBox(PluginBase):
9
8
  name = "DiziBox"
@@ -49,16 +48,13 @@ 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(
@@ -76,16 +72,13 @@ 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(
@@ -98,58 +91,38 @@ class DiziBox(PluginBase):
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)
94
+ secici = HTMLHelper(istek.text)
102
95
 
103
- title_el = secici.css_first("div.tv-overview h1 a")
104
- title = title_el.text(strip=True) if title_el else None
96
+ title = secici.select_text("div.tv-overview h1 a")
105
97
 
106
- poster_el = secici.css_first("div.tv-overview figure img")
107
- poster = poster_el.attrs.get("src") if poster_el else None
98
+ poster = secici.select_attr("div.tv-overview figure img", "src")
108
99
 
109
- desc_el = secici.css_first("div.tv-story p")
110
- description = desc_el.text(strip=True) if desc_el else None
100
+ description = secici.select_text("div.tv-story p")
111
101
 
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
102
+ # year
103
+ year_text = secici.select_text("a[href*='/yil/']")
104
+ year = secici.regex_first(r"(\d{4})", year_text)
117
105
 
118
- tags = [a.text(strip=True) for a in secici.css("a[href*='/tur/']") if a.text(strip=True)]
106
+ tags = secici.select_all_text("a[href*='/tur/']")
119
107
 
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
108
+ # rating
109
+ rating_text = secici.select_text("span.label-imdb b")
110
+ rating = secici.regex_first(r"[\d.,]+", rating_text)
125
111
 
126
- actors = [a.text(strip=True) for a in secici.css("a[href*='/oyuncu/']") if a.text(strip=True)]
112
+ actors = secici.select_all_text("a[href*='/oyuncu/']")
127
113
 
128
114
  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
-
115
+ for sezon_link in secici.select_all_attr("div#seasons-list a", "href"):
134
116
  sezon_url = self.fix_url(sezon_link)
135
117
  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")
118
+ sezon_secici = HTMLHelper(sezon_istek.text)
145
119
 
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)
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)
150
123
 
151
- ep_season = season_match.group(1) if season_match else None
152
- ep_episode = episode_match.group(1) if episode_match else None
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)
153
126
 
154
127
  if ep_title and ep_href:
155
128
  episodes.append(Episode(
@@ -184,20 +157,20 @@ class DiziBox(PluginBase):
184
157
  iframe_link = iframe_link.replace("king.php?v=", "king.php?wmode=opaque&v=")
185
158
 
186
159
  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
160
+ secici = HTMLHelper(istek.text)
161
+ iframe = secici.select_attr("div#Player iframe", "src")
190
162
 
191
163
  if iframe:
192
164
  self.httpx.headers.update({"Referer": self.main_url})
193
- istek = await self.httpx.get(iframe)
165
+ iframe_istek = await self.httpx.get(iframe)
166
+ iframe_secici = HTMLHelper(iframe_istek.text)
194
167
 
195
- crypt_data = re.search(r"CryptoJS\.AES\.decrypt\(\"(.*)\",\"", istek.text)[1]
196
- crypt_pass = re.search(r"\",\"(.*)\"\);", istek.text)[1]
168
+ crypt_data = iframe_secici.regex_first(r"CryptoJS\.AES\.decrypt\(\"(.*)\",\"", iframe_istek.text)
169
+ crypt_pass = iframe_secici.regex_first(r"\",\"(.*)\"\);", iframe_istek.text)
197
170
  decode = CryptoJS.decrypt(crypt_pass, crypt_data)
198
171
 
199
- if video_match := re.search(r"file: '(.*)',", decode):
200
- results.append(video_match[1])
172
+ if video_match := iframe_secici.regex_first(r"file: '(.*)',", decode):
173
+ results.append(video_match)
201
174
  else:
202
175
  results.append(decode)
203
176
 
@@ -206,15 +179,16 @@ class DiziBox(PluginBase):
206
179
  while True:
207
180
  await asyncio.sleep(.3)
208
181
  with contextlib.suppress(Exception):
209
- istek = await self.httpx.get(iframe_link)
182
+ moly_istek = await self.httpx.get(iframe_link)
183
+ moly_secici = HTMLHelper(moly_istek.text)
210
184
 
211
- if atob_data := re.search(r"unescape\(\"(.*)\"\)", istek.text):
212
- decoded_atob = urllib.parse.unquote(atob_data[1])
185
+ if atob_data := moly_secici.regex_first(r"unescape\(\"(.*)\"\)", moly_istek.text):
186
+ decoded_atob = urllib.parse.unquote(atob_data)
213
187
  str_atob = base64.b64decode(decoded_atob).decode("utf-8")
214
188
 
215
- iframe_el = HTMLParser(str_atob).css_first("div#Player iframe")
216
- if iframe_el:
217
- results.append(iframe_el.attrs.get("src"))
189
+ iframe_src = HTMLHelper(str_atob).select_attr("div#Player iframe", "src")
190
+ if iframe_src:
191
+ results.append(iframe_src)
218
192
 
219
193
  break
220
194
 
@@ -226,11 +200,10 @@ class DiziBox(PluginBase):
226
200
 
227
201
  async def load_links(self, url: str) -> list[ExtractResult]:
228
202
  istek = await self.httpx.get(url)
229
- secici = HTMLParser(istek.text)
203
+ secici = HTMLHelper(istek.text)
230
204
 
231
205
  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
206
+ main_iframe = secici.select_attr("div#video-area iframe", "src")
234
207
 
235
208
  if main_iframe:
236
209
  if decoded := await self._iframe_decode(self.name, main_iframe, url):
@@ -239,9 +212,9 @@ class DiziBox(PluginBase):
239
212
  if data:
240
213
  results.append(data)
241
214
 
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")
215
+ for alternatif in secici.select("div.video-toolbar option[value]"):
216
+ alt_name = secici.select_text(None, alternatif)
217
+ alt_link = secici.select_attr(None, "value", alternatif)
245
218
 
246
219
  if not alt_link:
247
220
  continue
@@ -250,9 +223,8 @@ class DiziBox(PluginBase):
250
223
  alt_istek = await self.httpx.get(alt_link)
251
224
  alt_istek.raise_for_status()
252
225
 
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
226
+ alt_secici = HTMLHelper(alt_istek.text)
227
+ alt_iframe = alt_secici.select_attr("div#video-area iframe", "src")
256
228
 
257
229
  if alt_iframe:
258
230
  if decoded := await self._iframe_decode(alt_name, alt_iframe, url):
@@ -1,13 +1,11 @@
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, Subtitle, ExtractResult
4
- from selectolax.parser import HTMLParser
5
- import re
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, Subtitle, ExtractResult, HTMLHelper
6
4
 
7
5
  class DiziPal(PluginBase):
8
6
  name = "DiziPal"
9
7
  language = "tr"
10
- main_url = "https://dizipal1224.com"
8
+ main_url = "https://dizipal1225.com"
11
9
  favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
12
10
  description = "dizipal güncel, dizipal yeni ve gerçek adresi. dizipal en yeni dizi ve filmleri güvenli ve hızlı şekilde sunar."
13
11
 
@@ -27,21 +25,16 @@ class DiziPal(PluginBase):
27
25
 
28
26
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
29
27
  istek = await self.httpx.get(url)
30
- secici = HTMLParser(istek.text)
28
+ secici = HTMLHelper(istek.text)
31
29
 
32
30
  results = []
33
31
 
34
32
  if "/son-bolumler" in url:
35
- for veri in secici.css("div.episode-item"):
36
- name_el = veri.css_first("div.name")
37
- episode_el = veri.css_first("div.episode")
38
- link_el = veri.css_first("a")
39
- img_el = veri.css_first("img")
40
-
41
- name = name_el.text(strip=True) if name_el else None
42
- episode = episode_el.text(strip=True) if episode_el else None
43
- href = link_el.attrs.get("href") if link_el else None
44
- poster = img_el.attrs.get("src") if img_el else None
33
+ for veri in secici.select("div.episode-item"):
34
+ name = secici.select_text("div.name", veri)
35
+ episode = secici.select_text("div.episode", veri)
36
+ href = secici.select_attr("a", "href", veri)
37
+ poster = secici.select_attr("img", "src", veri)
45
38
 
46
39
  if name and href:
47
40
  ep_text = episode.replace(". Sezon ", "x").replace(". Bölüm", "") if episode else ""
@@ -56,14 +49,10 @@ class DiziPal(PluginBase):
56
49
  poster = self.fix_url(poster) if poster else None,
57
50
  ))
58
51
  else:
59
- for veri in secici.css("article.type2 ul li"):
60
- title_el = veri.css_first("span.title")
61
- link_el = veri.css_first("a")
62
- img_el = veri.css_first("img")
63
-
64
- title = title_el.text(strip=True) if title_el else None
65
- href = link_el.attrs.get("href") if link_el else None
66
- poster = img_el.attrs.get("src") if img_el else None
52
+ for veri in secici.select("article.type2 ul li"):
53
+ title = secici.select_text("span.title", veri)
54
+ href = secici.select_attr("a", "href", veri)
55
+ poster = secici.select_attr("img", "src", veri)
67
56
 
68
57
  if title and href:
69
58
  results.append(MainPageResult(
@@ -113,10 +102,10 @@ class DiziPal(PluginBase):
113
102
 
114
103
  return results
115
104
 
116
- def _find_sibling_text(self, secici: HTMLParser, label_text: str) -> str | None:
105
+ def _find_sibling_text(self, secici: HTMLHelper, label_text: str) -> str | None:
117
106
  """Bir label'ın kardeş div'inden text çıkarır (xpath yerine)"""
118
- for div in secici.css("div"):
119
- if div.text(strip=True) == label_text:
107
+ for div in secici.select("div"):
108
+ if secici.select_text(element=div) == label_text:
120
109
  # Sonraki kardeş elementi bul
121
110
  next_sibling = div.next
122
111
  while next_sibling:
@@ -133,50 +122,41 @@ class DiziPal(PluginBase):
133
122
  self.httpx.headers.pop("X-Requested-With", None)
134
123
 
135
124
  istek = await self.httpx.get(url)
136
- secici = HTMLParser(istek.text)
125
+ secici = HTMLHelper(istek.text)
137
126
  html_text = istek.text
138
127
 
139
- og_image = secici.css_first("meta[property='og:image']")
140
- poster = self.fix_url(og_image.attrs.get("content")) if og_image else None
128
+ poster = self.fix_url(secici.select_attr("meta[property='og:image']", "content")) if secici.select_attr("meta[property='og:image']", "content") else None
141
129
 
142
- # XPath yerine regex ile HTML'den çıkarma
143
- year = None
144
- year_match = re.search(r'Yapım Yılı.*?<div[^>]*>(\d{4})</div>', html_text, re.DOTALL | re.IGNORECASE)
145
- if year_match:
146
- year = year_match.group(1)
130
+ # Sidebar bilgilerini topla
131
+ info = {}
132
+ for li in secici.select("li"):
133
+ key = secici.select_text("div.key", li)
134
+ val = secici.select_text("div.value", li)
135
+ if key and val:
136
+ info[key.strip(":")] = val.strip()
147
137
 
148
- desc_el = secici.css_first("div.summary p")
149
- description = desc_el.text(strip=True) if desc_el else None
138
+ year = info.get("Yapım Yılı")
139
+ rating = info.get("IMDB Puanı")
140
+
141
+ tags_raw = info.get("Türler", "")
142
+ tags = [t.strip() for t in tags_raw.split() if t.strip()] if tags_raw else None
150
143
 
151
- rating = None
152
- rating_match = re.search(r'IMDB Puanı.*?<div[^>]*>([0-9.]+)</div>', html_text, re.DOTALL | re.IGNORECASE)
153
- if rating_match:
154
- rating = rating_match.group(1)
144
+ actors_raw = info.get("Oyuncular")
145
+ actors = [a.strip() for a in actors_raw.split(",") if a.strip()] if actors_raw else None
155
146
 
156
- tags = None
157
- tags_match = re.search(r'Türler.*?<div[^>]*>([^<]+)</div>', html_text, re.DOTALL | re.IGNORECASE)
158
- if tags_match:
159
- tags_raw = tags_match.group(1)
160
- tags = [t.strip() for t in tags_raw.split() if t.strip()]
147
+ description = secici.select_text("div.summary p")
161
148
 
162
- duration = None
163
- dur_match = re.search(r'Ortalama Süre.*?<div[^>]*>(\d+)', html_text, re.DOTALL | re.IGNORECASE)
164
- if dur_match:
165
- duration = int(dur_match.group(1))
149
+ duration_raw = info.get("Ortalama Süre")
150
+ duration = int(secici.regex_first(r"(\d+)", duration_raw)) if duration_raw else None
166
151
 
167
152
  if "/dizi/" in url:
168
- title_el = secici.css_first("div.cover h5")
169
- title = title_el.text(strip=True) if title_el else None
153
+ title = secici.select_text("div.cover h5")
170
154
 
171
155
  episodes = []
172
- for ep in secici.css("div.episode-item"):
173
- ep_name_el = ep.css_first("div.name")
174
- ep_link_el = ep.css_first("a")
175
- ep_episode_el = ep.css_first("div.episode")
176
-
177
- ep_name = ep_name_el.text(strip=True) if ep_name_el else None
178
- ep_href = ep_link_el.attrs.get("href") if ep_link_el else None
179
- ep_text = ep_episode_el.text(strip=True) if ep_episode_el else ""
156
+ for ep in secici.select("div.episode-item"):
157
+ ep_name = secici.select_text("div.name", ep)
158
+ ep_href = secici.select_attr("a", "href", ep)
159
+ ep_text = secici.select_text("div.episode", ep)
180
160
  ep_parts = ep_text.split(" ")
181
161
 
182
162
  ep_season = None
@@ -206,11 +186,12 @@ class DiziPal(PluginBase):
206
186
  year = year,
207
187
  duration = duration,
208
188
  episodes = episodes if episodes else None,
189
+ actors = actors,
209
190
  )
210
191
  else:
211
192
  # Film için title - g-title div'lerinin 2. olanı
212
- g_titles = secici.css("div.g-title div")
213
- title = g_titles[1].text(strip=True) if len(g_titles) >= 2 else None
193
+ g_titles = secici.select("div.g-title div")
194
+ title = secici.select_text(element=g_titles[1]) if len(g_titles) >= 2 else None
214
195
 
215
196
  return MovieInfo(
216
197
  url = url,
@@ -221,6 +202,7 @@ class DiziPal(PluginBase):
221
202
  rating = rating,
222
203
  year = year,
223
204
  duration = duration,
205
+ actors = actors,
224
206
  )
225
207
 
226
208
  async def load_links(self, url: str) -> list[ExtractResult]:
@@ -231,13 +213,11 @@ class DiziPal(PluginBase):
231
213
  self.httpx.headers.pop("X-Requested-With", None)
232
214
 
233
215
  istek = await self.httpx.get(url)
234
- secici = HTMLParser(istek.text)
216
+ secici = HTMLHelper(istek.text)
235
217
 
236
- iframe_el = secici.css_first(".series-player-container iframe")
237
- if not iframe_el:
238
- iframe_el = secici.css_first("div#vast_new iframe")
218
+ # iframe presence checked via select_attr below
239
219
 
240
- iframe = iframe_el.attrs.get("src") if iframe_el else None
220
+ iframe = secici.select_attr(".series-player-container iframe", "src") or secici.select_attr("div#vast_new iframe", "src")
241
221
  if not iframe:
242
222
  return []
243
223
 
@@ -248,15 +228,13 @@ class DiziPal(PluginBase):
248
228
  i_text = i_istek.text
249
229
 
250
230
  # m3u link çıkar
251
- m3u_match = re.search(r'file:"([^"]+)"', i_text)
252
- if m3u_match:
253
- m3u_link = m3u_match[1]
231
+ m3u_link = secici.regex_first(r'file:"([^"]+)"', target=i_text)
232
+ if m3u_link:
254
233
 
255
234
  # Altyazıları çıkar
235
+ sub_text = secici.regex_first(r'"subtitle":"([^"]+)"', target=i_text)
256
236
  subtitles = []
257
- sub_match = re.search(r'"subtitle":"([^"]+)"', i_text)
258
- if sub_match:
259
- sub_text = sub_match[1]
237
+ if sub_text:
260
238
  if "," in sub_text:
261
239
  for sub in sub_text.split(","):
262
240
  lang = sub.split("[")[1].split("]")[0] if "[" in sub else "Türkçe"