KekikStream 2.2.8__tar.gz → 2.2.9__tar.gz

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 (88) hide show
  1. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/Filemoon.py +41 -26
  2. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/Dizilla.py +64 -37
  3. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/SetFilmIzle.py +47 -44
  4. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/SezonlukDizi.py +51 -51
  5. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream.egg-info/PKG-INFO +1 -1
  6. {kekikstream-2.2.8 → kekikstream-2.2.9}/PKG-INFO +1 -1
  7. {kekikstream-2.2.8 → kekikstream-2.2.9}/setup.py +1 -1
  8. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/CLI/__init__.py +0 -0
  9. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/CLI/pypi_kontrol.py +0 -0
  10. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Core/Extractor/ExtractorBase.py +0 -0
  11. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Core/Extractor/ExtractorLoader.py +0 -0
  12. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Core/Extractor/ExtractorManager.py +0 -0
  13. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Core/Extractor/ExtractorModels.py +0 -0
  14. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Core/Extractor/YTDLPCache.py +0 -0
  15. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Core/Media/MediaHandler.py +0 -0
  16. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Core/Media/MediaManager.py +0 -0
  17. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Core/Plugin/PluginBase.py +0 -0
  18. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Core/Plugin/PluginLoader.py +0 -0
  19. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Core/Plugin/PluginManager.py +0 -0
  20. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Core/Plugin/PluginModels.py +0 -0
  21. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Core/UI/UIManager.py +0 -0
  22. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Core/__init__.py +0 -0
  23. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/CloseLoad.py +0 -0
  24. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/ContentX.py +0 -0
  25. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/DonilasPlay.py +0 -0
  26. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/DzenRu.py +0 -0
  27. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/ExPlay.py +0 -0
  28. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/HDPlayerSystem.py +0 -0
  29. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/JFVid.py +0 -0
  30. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/JetTv.py +0 -0
  31. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/MailRu.py +0 -0
  32. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/MixPlayHD.py +0 -0
  33. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/MixTiger.py +0 -0
  34. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/MolyStream.py +0 -0
  35. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/Odnoklassniki.py +0 -0
  36. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/PeaceMakerst.py +0 -0
  37. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/PixelDrain.py +0 -0
  38. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/PlayerFilmIzle.py +0 -0
  39. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/RapidVid.py +0 -0
  40. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/SetPlay.py +0 -0
  41. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/SetPrime.py +0 -0
  42. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/SibNet.py +0 -0
  43. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/Sobreatsesuyp.py +0 -0
  44. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/TRsTX.py +0 -0
  45. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/TauVideo.py +0 -0
  46. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/TurboImgz.py +0 -0
  47. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/TurkeyPlayer.py +0 -0
  48. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/VCTPlay.py +0 -0
  49. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/VidHide.py +0 -0
  50. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/VidMoly.py +0 -0
  51. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/VidMoxy.py +0 -0
  52. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/VidPapi.py +0 -0
  53. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/VideoSeyred.py +0 -0
  54. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/YTDLP.py +0 -0
  55. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Extractors/YildizKisaFilm.py +0 -0
  56. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/BelgeselX.py +0 -0
  57. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/DiziBox.py +0 -0
  58. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/DiziPal.py +0 -0
  59. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/DiziYou.py +0 -0
  60. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/FilmBip.py +0 -0
  61. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/FilmMakinesi.py +0 -0
  62. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/FilmModu.py +0 -0
  63. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/FullHDFilm.py +0 -0
  64. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/FullHDFilmizlesene.py +0 -0
  65. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/HDFilmCehennemi.py +0 -0
  66. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/JetFilmizle.py +0 -0
  67. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/KultFilmler.py +0 -0
  68. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/RecTV.py +0 -0
  69. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/RoketDizi.py +0 -0
  70. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/SelcukFlix.py +0 -0
  71. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/SineWix.py +0 -0
  72. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/Sinefy.py +0 -0
  73. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/SinemaCX.py +0 -0
  74. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/Sinezy.py +0 -0
  75. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/SuperFilmGeldi.py +0 -0
  76. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/Plugins/UgurFilm.py +0 -0
  77. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/__init__.py +0 -0
  78. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/__main__.py +0 -0
  79. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream/requirements.txt +0 -0
  80. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream.egg-info/SOURCES.txt +0 -0
  81. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream.egg-info/dependency_links.txt +0 -0
  82. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream.egg-info/entry_points.txt +0 -0
  83. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream.egg-info/requires.txt +0 -0
  84. {kekikstream-2.2.8 → kekikstream-2.2.9}/KekikStream.egg-info/top_level.txt +0 -0
  85. {kekikstream-2.2.8 → kekikstream-2.2.9}/LICENSE +0 -0
  86. {kekikstream-2.2.8 → kekikstream-2.2.9}/MANIFEST.in +0 -0
  87. {kekikstream-2.2.8 → kekikstream-2.2.9}/README.md +0 -0
  88. {kekikstream-2.2.8 → kekikstream-2.2.9}/setup.cfg +0 -0
@@ -22,13 +22,14 @@ class Filemoon(ExtractorBase):
22
22
  return any(domain in url for domain in self.supported_domains)
23
23
 
24
24
  async def extract(self, url: str, referer: str = None) -> ExtractResult:
25
- headers = {
26
- "Referer" : url,
27
- "Sec-Fetch-Dest" : "iframe",
28
- "Sec-Fetch-Mode" : "navigate",
29
- "Sec-Fetch-Site" : "cross-site",
25
+ default_headers = {
26
+ "Referer" : url,
27
+ "Sec-Fetch-Dest" : "iframe",
28
+ "Sec-Fetch-Mode" : "navigate",
29
+ "Sec-Fetch-Site" : "cross-site",
30
+ "User-Agent" : "Mozilla/5.0 (X11; Linux x86_64; rv:137.0) Gecko/20100101 Firefox/137.0"
30
31
  }
31
- self.httpx.headers.update(headers)
32
+ self.httpx.headers.update(default_headers)
32
33
 
33
34
  # İlk sayfayı al
34
35
  istek = await self.httpx.get(url)
@@ -38,31 +39,44 @@ class Filemoon(ExtractorBase):
38
39
  # Eğer iframe varsa, iframe'e git
39
40
  iframe_el = secici.css_first("iframe")
40
41
  iframe_src = iframe_el.attrs.get("src") if iframe_el else None
41
- if iframe_src:
42
- iframe_url = self.fix_url(iframe_src)
43
- self.httpx.headers.update({
44
- "Accept-Language" : "en-US,en;q=0.5",
45
- "Sec-Fetch-Dest" : "iframe"
46
- })
47
- istek = await self.httpx.get(iframe_url)
48
- response = istek.text
49
-
50
- # Packed script'i bul ve unpack et
42
+
51
43
  m3u8_url = None
52
-
53
- if Packer.detect_packed(response):
54
- try:
55
- unpacked = Packer.unpack(response)
56
- # sources:[{file:"...» pattern'ını ara
57
- if match := re.search(r'sources:\s*\[\s*\{\s*file:\s*"([^"]+)"', unpacked):
44
+
45
+ if not iframe_src:
46
+ # Fallback: Script içinde ara (Kotlin: selectFirst("script:containsData(function(p,a,c,k,e,d))"))
47
+ script_data = ""
48
+ for script in secici.css("script"):
49
+ if "function(p,a,c,k,e,d)" in script.text():
50
+ script_data = script.text()
51
+ break
52
+
53
+ if script_data:
54
+ unpacked = Packer.unpack(script_data)
55
+ if match := re.search(r'sources:\[\{file:"(.*?)"', unpacked):
58
56
  m3u8_url = match.group(1)
59
- elif match := re.search(r'file:\s*"([^"]*?\.m3u8[^"]*)"', unpacked):
57
+ else:
58
+ # Iframe varsa devam et
59
+ iframe_url = self.fix_url(iframe_src)
60
+ iframe_headers = default_headers.copy()
61
+ iframe_headers["Accept-Language"] = "en-US,en;q=0.5"
62
+
63
+ istek = await self.httpx.get(iframe_url, headers=iframe_headers)
64
+ response = istek.text
65
+ secici = HTMLParser(response)
66
+
67
+ script_data = ""
68
+ for script in secici.css("script"):
69
+ if "function(p,a,c,k,e,d)" in script.text():
70
+ script_data = script.text()
71
+ break
72
+
73
+ if script_data:
74
+ unpacked = Packer.unpack(script_data)
75
+ if match := re.search(r'sources:\[\{file:"(.*?)"', unpacked):
60
76
  m3u8_url = match.group(1)
61
- except Exception:
62
- pass
63
77
 
64
- # Fallback: Doğrudan response'ta ara
65
78
  if not m3u8_url:
79
+ # Son çare: Normal response içinde ara
66
80
  if match := re.search(r'sources:\s*\[\s*\{\s*file:\s*"([^"]+)"', response):
67
81
  m3u8_url = match.group(1)
68
82
  elif match := re.search(r'file:\s*"([^"]*?\.m3u8[^"]*)"', response):
@@ -75,5 +89,6 @@ class Filemoon(ExtractorBase):
75
89
  name = self.name,
76
90
  url = self.fix_url(m3u8_url),
77
91
  referer = f"{self.main_url}/",
92
+ user_agent = default_headers["User-Agent"],
78
93
  subtitles = []
79
94
  )
@@ -142,44 +142,70 @@ class Dizilla(PluginBase):
142
142
  istek = await self.httpx.get(url)
143
143
  secici = HTMLParser(istek.text)
144
144
 
145
- # application/ld+json script'lerini al
146
- ld_json_scripts = secici.css("script[type='application/ld+json']")
147
- if not ld_json_scripts:
145
+ title = secici.css_first("div.poster.poster h2")
146
+ title = title.text(strip=True) if title else None
147
+ if not title:
148
148
  return None
149
149
 
150
- # Son script'i al
151
- last_script = ld_json_scripts[-1]
152
- veri = loads(last_script.text(strip=True))
150
+ poster_el = secici.css_first("div.w-full.page-top.relative img")
151
+ poster = self.fix_url(poster_el.attrs.get("src")) if poster_el else None
153
152
 
154
- title = veri.get("name")
155
- if alt_title := veri.get("alternateName"):
156
- title += f" - ({alt_title})"
153
+ # Year extraction (Kotlin: [1] index for w-fit min-w-fit)
154
+ info_boxes = secici.css("div.w-fit.min-w-fit")
155
+ year = None
156
+ if len(info_boxes) > 1:
157
+ year_el = info_boxes[1].css_first("span.text-sm.opacity-60")
158
+ if year_el:
159
+ year_text = year_el.text(strip=True)
160
+ year = year_text.split(" ")[-1] if " " in year_text else year_text
161
+
162
+ description_el = secici.css_first("div.mt-2.text-sm")
163
+ description = description_el.text(strip=True) if description_el else None
157
164
 
158
- poster = self.fix_url(veri.get("image"))
159
- description = veri.get("description")
160
- year = veri.get("datePublished").split("-")[0]
161
-
162
- # Tags extraction from page content (h3 tag)
163
165
  tags_el = secici.css_first("div.poster.poster h3")
164
- tags_raw = tags_el.text(strip=True) if tags_el else ""
165
- tags = [t.strip() for t in tags_raw.split(",")] if tags_raw else []
166
-
167
- rating = veri.get("aggregateRating", {}).get("ratingValue")
168
- actors = [actor.get("name") for actor in veri.get("actor", []) if actor.get("name")]
169
-
170
- bolumler = []
171
- sezonlar = veri.get("containsSeason") if isinstance(veri.get("containsSeason"), list) else [veri.get("containsSeason")]
172
- for sezon in sezonlar:
173
- episodes = sezon.get("episode")
174
- if isinstance(episodes, dict):
175
- episodes = [episodes]
166
+ tags = [t.strip() for t in tags_el.text(strip=True).split(",")] if tags_el else []
167
+
168
+ actors = [h5.text(strip=True) for h5 in secici.css("div.global-box h5")]
169
+
170
+ episodeses = []
171
+ # Seasons links iteration
172
+ season_links = secici.css("div.flex.items-center.flex-wrap.gap-2.mb-4 a")
173
+ for sezon in season_links:
174
+ sezon_href = self.fix_url(sezon.attrs.get("href"))
175
+ sezon_req = await self.httpx.get(sezon_href)
176
176
 
177
- for bolum in episodes:
178
- bolumler.append(Episode(
179
- season = sezon.get("seasonNumber"),
180
- episode = bolum.get("episodeNumber"),
181
- title = bolum.get("name"),
182
- url = await self.url_base_degis(bolum.get("url"), self.main_url),
177
+ season_num = None
178
+ try:
179
+ # URL'den sezon numarasını çek: ...-sezon-X
180
+ season_match = re.search(r"sezon-(\d+)", sezon_href)
181
+ if season_match:
182
+ season_num = int(season_match.group(1))
183
+ except:
184
+ pass
185
+
186
+ sezon_secici = HTMLParser(sezon_req.text)
187
+ for bolum in sezon_secici.css("div.episodes div.cursor-pointer"):
188
+ # Kotlin: bolum.select("a").last()
189
+ links = bolum.css("a")
190
+ if not links:
191
+ continue
192
+
193
+ ep_link = links[-1]
194
+ ep_name = ep_link.text(strip=True)
195
+ ep_href = self.fix_url(ep_link.attrs.get("href"))
196
+
197
+ # Episode number (first link's text usually)
198
+ ep_num = None
199
+ try:
200
+ ep_num = int(links[0].text(strip=True))
201
+ except:
202
+ pass
203
+
204
+ episodeses.append(Episode(
205
+ season = season_num,
206
+ episode = ep_num,
207
+ title = ep_name,
208
+ url = ep_href
183
209
  ))
184
210
 
185
211
  return SeriesInfo(
@@ -188,9 +214,8 @@ class Dizilla(PluginBase):
188
214
  title = title,
189
215
  description = description,
190
216
  tags = tags,
191
- rating = rating,
192
- year = year,
193
- episodes = bolumler,
217
+ year = str(year) if year else None,
218
+ episodes = episodeses,
194
219
  actors = actors
195
220
  )
196
221
 
@@ -212,7 +237,7 @@ class Dizilla(PluginBase):
212
237
 
213
238
  # Get first source (matching Kotlin)
214
239
  first_result = results[0]
215
- source_content = first_result.get("source_content", "")
240
+ source_content = str(first_result.get("source_content", ""))
216
241
 
217
242
  # Clean the source_content string (matching Kotlin: .replace("\"", "").replace("\\", ""))
218
243
  cleaned_source = source_content.replace('"', '').replace('\\', '')
@@ -220,10 +245,12 @@ class Dizilla(PluginBase):
220
245
  # Parse cleaned HTML
221
246
  iframe_el = HTMLParser(cleaned_source).css_first("iframe")
222
247
  iframe_src = iframe_el.attrs.get("src") if iframe_el else None
248
+
249
+ # Referer check (matching Kotlin: loadExtractor(iframe, "${mainUrl}/", ...))
223
250
  iframe_url = self.fix_url(iframe_src) if iframe_src else None
224
251
 
225
252
  if not iframe_url:
226
253
  return []
227
254
 
228
- data = await self.extract(iframe_url, prefix=first_result.get('language_name', 'Unknown'))
255
+ data = await self.extract(iframe_url, referer=f"{self.main_url}/", prefix=first_result.get('language_name', 'Unknown'))
229
256
  return [data] if data else []
@@ -2,7 +2,7 @@
2
2
 
3
3
  from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult
4
4
  from selectolax.parser import HTMLParser
5
- import re, json
5
+ import re, json, asyncio
6
6
 
7
7
  class SetFilmIzle(PluginBase):
8
8
  name = "SetFilmIzle"
@@ -229,7 +229,7 @@ class SetFilmIzle(PluginBase):
229
229
  istek = await self.httpx.get(url)
230
230
  secici = HTMLParser(istek.text)
231
231
 
232
- nonce = self._get_nonce("video_nonce", referer=url)
232
+ nonce = secici.css_first("div#playex").attrs.get("data-nonce") if secici.css_first("div#playex") else ""
233
233
 
234
234
  # partKey to dil label mapping
235
235
  part_key_labels = {
@@ -238,46 +238,49 @@ class SetFilmIzle(PluginBase):
238
238
  "orijinal" : "Orijinal"
239
239
  }
240
240
 
241
- links = []
241
+ semaphore = asyncio.Semaphore(5)
242
+ tasks = []
243
+
244
+ async def fetch_and_extract(player):
245
+ async with semaphore:
246
+ source_id = player.attrs.get("data-post-id")
247
+ player_name = player.attrs.get("data-player-name")
248
+ part_key = player.attrs.get("data-part-key")
249
+
250
+ if not source_id or "event" in source_id or source_id == "":
251
+ return None
252
+
253
+ try:
254
+ resp = self.cloudscraper.post(
255
+ f"{self.main_url}/wp-admin/admin-ajax.php",
256
+ headers = {"Referer": url},
257
+ data = {
258
+ "action" : "get_video_url",
259
+ "nonce" : nonce,
260
+ "post_id" : source_id,
261
+ "player_name" : player_name or "",
262
+ "part_key" : part_key or ""
263
+ }
264
+ )
265
+ data = resp.json()
266
+ except:
267
+ return None
268
+
269
+ iframe_url = data.get("data", {}).get("url")
270
+ if not iframe_url:
271
+ return None
272
+
273
+ if "setplay" not in iframe_url and part_key:
274
+ iframe_url = f"{iframe_url}?partKey={part_key}"
275
+
276
+ label = part_key_labels.get(part_key, "")
277
+ if not label and part_key:
278
+ label = part_key.replace("_", " ").title()
279
+
280
+ return await self.extract(iframe_url, prefix=label if label else None)
281
+
242
282
  for player in secici.css("nav.player a"):
243
- source_id = player.attrs.get("data-post-id")
244
- player_name = player.attrs.get("data-player-name")
245
- part_key = player.attrs.get("data-part-key")
246
-
247
- if not source_id or "event" in source_id or source_id == "":
248
- continue
249
-
250
- try:
251
- resp = self.cloudscraper.post(
252
- f"{self.main_url}/wp-admin/admin-ajax.php",
253
- headers = {"Referer": url},
254
- data = {
255
- "action" : "get_video_url",
256
- "nonce" : nonce,
257
- "post_id" : source_id,
258
- "player_name" : player_name or "",
259
- "part_key" : part_key or ""
260
- }
261
- )
262
- data = resp.json()
263
- except:
264
- continue
265
-
266
- iframe_url = data.get("data", {}).get("url")
267
- if not iframe_url:
268
- continue
269
-
270
- # SetPlay URL'si için part_key ekleme
271
- if "setplay" not in iframe_url and part_key:
272
- iframe_url = f"{iframe_url}?partKey={part_key}"
273
-
274
- # Dil etiketi oluştur
275
- label = part_key_labels.get(part_key, "")
276
- if not label and part_key:
277
- label = part_key.replace("_", " ").title()
278
-
279
- data = await self.extract(iframe_url, prefix=label if label else None)
280
- if data:
281
- links.append(data)
282
-
283
- return links
283
+ tasks.append(fetch_and_extract(player))
284
+
285
+ results = await asyncio.gather(*tasks)
286
+ return [r for r in results if r]
@@ -2,7 +2,7 @@
2
2
 
3
3
  from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult
4
4
  from selectolax.parser import HTMLParser
5
- import re
5
+ import re, asyncio
6
6
 
7
7
  class SezonlukDizi(PluginBase):
8
8
  name = "SezonlukDizi"
@@ -39,6 +39,16 @@ class SezonlukDizi(PluginBase):
39
39
  f"{main_url}/diziler.asp?siralama_tipi=id&tur=western&s=" : "Western"
40
40
  }
41
41
 
42
+ async def _get_asp_data(self) -> dict:
43
+ js_req = await self.httpx.get(f"{self.main_url}/js/site.min.js")
44
+ alt_match = re.search(r"dataAlternatif(.*?)\.asp", js_req.text)
45
+ embed_match = re.search(r"dataEmbed(.*?)\.asp", js_req.text)
46
+
47
+ return {
48
+ "alternatif": alt_match.group(1) if alt_match else "",
49
+ "embed": embed_match.group(1) if embed_match else ""
50
+ }
51
+
42
52
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
43
53
  istek = await self.httpx.get(f"{url}{page}")
44
54
  secici = HTMLParser(istek.text)
@@ -67,7 +77,7 @@ class SezonlukDizi(PluginBase):
67
77
  secici = HTMLParser(istek.text)
68
78
 
69
79
  results = []
70
- for afis in secici.css("div.afis a.column"):
80
+ for afis in secici.css("div.afis a"):
71
81
  desc_el = afis.css_first("div.description")
72
82
  img_el = afis.css_first("img")
73
83
 
@@ -169,64 +179,54 @@ class SezonlukDizi(PluginBase):
169
179
  actors = actors
170
180
  )
171
181
 
172
- async def get_asp_data(self) -> tuple[str, str]:
173
- """Fetch dynamic ASP version numbers from site.min.js"""
174
- try:
175
- js_content = await self.httpx.get(f"{self.main_url}/js/site.min.js")
176
- alternatif_match = re.search(r'dataAlternatif(.*?)\.asp', js_content.text)
177
- embed_match = re.search(r'dataEmbed(.*?)\.asp', js_content.text)
178
-
179
- alternatif_ver = alternatif_match.group(1) if alternatif_match else "22"
180
- embed_ver = embed_match.group(1) if embed_match else "22"
181
-
182
- return (alternatif_ver, embed_ver)
183
- except Exception:
184
- return ("22", "22") # Fallback to default versions
185
-
186
182
  async def load_links(self, url: str) -> list[ExtractResult]:
187
183
  istek = await self.httpx.get(url)
188
184
  secici = HTMLParser(istek.text)
189
-
190
- dilsec_el = secici.css_first("div#dilsec")
191
- bid = dilsec_el.attrs.get("data-id") if dilsec_el else None
185
+ asp_data = await self._get_asp_data()
186
+
187
+ bid = secici.css_first("div#dilsec").attrs.get("data-id") if secici.css_first("div#dilsec") else None
192
188
  if not bid:
193
189
  return []
194
190
 
195
- # Get dynamic ASP versions
196
- alternatif_ver, embed_ver = await self.get_asp_data()
191
+ semaphore = asyncio.Semaphore(5)
192
+ tasks = []
197
193
 
198
- results = []
199
- for dil, label in [("1", "Altyazı"), ("0", "Dublaj")]:
200
- dil_istek = await self.httpx.post(
201
- url = f"{self.main_url}/ajax/dataAlternatif{alternatif_ver}.asp",
194
+ async def fetch_and_extract(veri, dil_etiketi):
195
+ async with semaphore:
196
+ try:
197
+ embed_resp = await self.httpx.post(
198
+ f"{self.main_url}/ajax/dataEmbed{asp_data['embed']}.asp",
199
+ headers = {"X-Requested-With": "XMLHttpRequest"},
200
+ data = {"id": str(veri.get("id"))}
201
+ )
202
+ embed_secici = HTMLParser(embed_resp.text)
203
+ iframe_el = embed_secici.css_first("iframe")
204
+ iframe_src = iframe_el.attrs.get("src") if iframe_el else None
205
+
206
+ if iframe_src:
207
+ if "link.asp" in iframe_src:
208
+ return None
209
+
210
+ iframe_url = self.fix_url(iframe_src)
211
+ return await self.extract(iframe_url, referer=f"{self.main_url}/", prefix=f"{dil_etiketi} - {veri.get('baslik')}")
212
+ except:
213
+ pass
214
+ return None
215
+
216
+ for dil_kodu, dil_etiketi in [("1", "Altyazı"), ("0", "Dublaj")]:
217
+ altyazi_resp = await self.httpx.post(
218
+ f"{self.main_url}/ajax/dataAlternatif{asp_data['alternatif']}.asp",
202
219
  headers = {"X-Requested-With": "XMLHttpRequest"},
203
- data = {"bid": bid, "dil": dil},
220
+ data = {"bid": bid, "dil": dil_kodu}
204
221
  )
205
-
222
+
206
223
  try:
207
- dil_json = dil_istek.json()
208
- except Exception:
224
+ data_json = altyazi_resp.json()
225
+ if data_json.get("status") == "success" and data_json.get("data"):
226
+ for veri in data_json["data"]:
227
+ tasks.append(fetch_and_extract(veri, dil_etiketi))
228
+ except:
209
229
  continue
210
230
 
211
- if dil_json.get("status") == "success":
212
- for idx, veri in enumerate(dil_json.get("data", [])):
213
- veri_response = await self.httpx.post(
214
- url = f"{self.main_url}/ajax/dataEmbed{embed_ver}.asp",
215
- headers = {"X-Requested-With": "XMLHttpRequest"},
216
- data = {"id": veri.get("id")},
217
- )
218
- veri_secici = HTMLParser(veri_response.text)
219
-
220
- iframe_el = veri_secici.css_first("iframe")
221
- iframe = iframe_el.attrs.get("src") if iframe_el else None
222
-
223
- if iframe:
224
- if "link.asp" in iframe:
225
- continue
226
-
227
- iframe_url = self.fix_url(iframe)
228
- data = await self.extract(iframe_url, prefix=label)
229
- if data:
230
- results.append(data)
231
-
232
- return results
231
+ results = await asyncio.gather(*tasks)
232
+ return [r for r in results if r]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: KekikStream
3
- Version: 2.2.8
3
+ Version: 2.2.9
4
4
  Summary: terminal üzerinden medya içeriği aramanızı ve VLC/MPV gibi popüler medya oynatıcılar aracılığıyla doğrudan izlemenizi sağlayan modüler ve genişletilebilir bir bıdı bıdı
5
5
  Home-page: https://github.com/keyiflerolsun/KekikStream
6
6
  Author: keyiflerolsun
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: KekikStream
3
- Version: 2.2.8
3
+ Version: 2.2.9
4
4
  Summary: terminal üzerinden medya içeriği aramanızı ve VLC/MPV gibi popüler medya oynatıcılar aracılığıyla doğrudan izlemenizi sağlayan modüler ve genişletilebilir bir bıdı bıdı
5
5
  Home-page: https://github.com/keyiflerolsun/KekikStream
6
6
  Author: keyiflerolsun
@@ -6,7 +6,7 @@ from io import open
6
6
  setup(
7
7
  # ? Genel Bilgiler
8
8
  name = "KekikStream",
9
- version = "2.2.8",
9
+ version = "2.2.9",
10
10
  url = "https://github.com/keyiflerolsun/KekikStream",
11
11
  description = "terminal üzerinden medya içeriği aramanızı ve VLC/MPV gibi popüler medya oynatıcılar aracılığıyla doğrudan izlemenizi sağlayan modüler ve genişletilebilir bir bıdı bıdı",
12
12
  keywords = ["KekikStream", "KekikAkademi", "keyiflerolsun"],
File without changes
File without changes
File without changes
File without changes