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.
Potentially problematic release.
This version of KekikStream might be problematic. Click here for more details.
- KekikStream/Core/HTMLHelper.py +134 -0
- KekikStream/Core/Plugin/PluginBase.py +22 -4
- KekikStream/Core/Plugin/PluginLoader.py +3 -2
- KekikStream/Core/Plugin/PluginManager.py +2 -2
- KekikStream/Core/__init__.py +2 -0
- KekikStream/Extractors/CloseLoad.py +12 -13
- KekikStream/Extractors/ContentX.py +33 -31
- KekikStream/Extractors/DonilasPlay.py +10 -10
- KekikStream/Extractors/DzenRu.py +3 -3
- KekikStream/Extractors/ExPlay.py +10 -10
- KekikStream/Extractors/Filemoon.py +47 -37
- KekikStream/Extractors/JetTv.py +4 -4
- KekikStream/Extractors/MixPlayHD.py +10 -11
- KekikStream/Extractors/MolyStream.py +16 -9
- KekikStream/Extractors/Odnoklassniki.py +4 -4
- KekikStream/Extractors/PeaceMakerst.py +3 -3
- KekikStream/Extractors/PixelDrain.py +6 -5
- KekikStream/Extractors/PlayerFilmIzle.py +6 -10
- KekikStream/Extractors/RapidVid.py +8 -7
- KekikStream/Extractors/SetPlay.py +10 -10
- KekikStream/Extractors/SetPrime.py +3 -6
- KekikStream/Extractors/SibNet.py +4 -5
- KekikStream/Extractors/Sobreatsesuyp.py +5 -5
- KekikStream/Extractors/TRsTX.py +5 -5
- KekikStream/Extractors/TurboImgz.py +3 -4
- KekikStream/Extractors/TurkeyPlayer.py +5 -5
- KekikStream/Extractors/VidHide.py +4 -7
- KekikStream/Extractors/VidMoly.py +37 -25
- KekikStream/Extractors/VidMoxy.py +8 -9
- KekikStream/Extractors/VidPapi.py +5 -7
- KekikStream/Extractors/VideoSeyred.py +3 -3
- KekikStream/Plugins/BelgeselX.py +40 -51
- KekikStream/Plugins/DiziBox.py +53 -81
- KekikStream/Plugins/DiziPal.py +50 -72
- KekikStream/Plugins/DiziYou.py +96 -83
- KekikStream/Plugins/Dizilla.py +101 -86
- KekikStream/Plugins/FilmBip.py +29 -50
- KekikStream/Plugins/FilmMakinesi.py +84 -46
- KekikStream/Plugins/FilmModu.py +27 -41
- KekikStream/Plugins/FullHDFilm.py +57 -62
- KekikStream/Plugins/FullHDFilmizlesene.py +32 -57
- KekikStream/Plugins/HDFilmCehennemi.py +51 -65
- KekikStream/Plugins/JetFilmizle.py +38 -51
- KekikStream/Plugins/KultFilmler.py +43 -67
- KekikStream/Plugins/RecTV.py +34 -9
- KekikStream/Plugins/RoketDizi.py +89 -111
- KekikStream/Plugins/SelcukFlix.py +102 -93
- KekikStream/Plugins/SetFilmIzle.py +110 -117
- KekikStream/Plugins/SezonlukDizi.py +88 -106
- KekikStream/Plugins/Sinefy.py +70 -70
- KekikStream/Plugins/SinemaCX.py +31 -55
- KekikStream/Plugins/Sinezy.py +27 -54
- KekikStream/Plugins/SuperFilmGeldi.py +25 -44
- KekikStream/Plugins/UgurFilm.py +23 -48
- KekikStream/Plugins/YabanciDizi.py +285 -0
- {kekikstream-2.2.8.dist-info → kekikstream-2.3.9.dist-info}/METADATA +1 -1
- kekikstream-2.3.9.dist-info/RECORD +84 -0
- kekikstream-2.2.8.dist-info/RECORD +0 -82
- {kekikstream-2.2.8.dist-info → kekikstream-2.3.9.dist-info}/WHEEL +0 -0
- {kekikstream-2.2.8.dist-info → kekikstream-2.3.9.dist-info}/entry_points.txt +0 -0
- {kekikstream-2.2.8.dist-info → kekikstream-2.3.9.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-2.2.8.dist-info → kekikstream-2.3.9.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, MovieInfo, SeriesInfo, Episode, ExtractResult
|
|
4
|
-
|
|
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 =
|
|
36
|
+
sel = HTMLHelper(resp.text)
|
|
38
37
|
|
|
39
|
-
for item in sel.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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,91 +183,106 @@ 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 =
|
|
186
|
+
sel = HTMLHelper(resp.text)
|
|
187
|
+
|
|
188
|
+
next_data_text = sel.select_text("script#__NEXT_DATA__")
|
|
189
|
+
if not next_data_text:
|
|
190
|
+
return SeriesInfo(url=url, title=sel.select_text("h1") or "Bilinmeyen")
|
|
192
191
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
192
|
+
try:
|
|
193
|
+
next_data = json.loads(next_data_text)
|
|
194
|
+
secure_data_raw = next_data["props"]["pageProps"].get("secureData")
|
|
195
|
+
if not secure_data_raw:
|
|
196
|
+
return SeriesInfo(url=url, title=sel.select_text("h1") or "Bilinmeyen")
|
|
197
|
+
|
|
198
|
+
# Clean possible quotes from string before decoding
|
|
199
|
+
if isinstance(secure_data_raw, str):
|
|
200
|
+
secure_data_raw = secure_data_raw.strip('"')
|
|
196
201
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
202
|
+
decoded_str = base64.b64decode(secure_data_raw).decode('utf-8')
|
|
203
|
+
content_details = json.loads(decoded_str)
|
|
204
|
+
|
|
205
|
+
# Sometimes content_details might be a string (double encoded)
|
|
206
|
+
if isinstance(content_details, str):
|
|
207
|
+
content_details = json.loads(content_details)
|
|
200
208
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
# Dizi mi film mi kontrol et (Kotlin referansı)
|
|
226
|
-
if series_data:
|
|
227
|
-
episodes = []
|
|
228
|
-
seasons_list = []
|
|
229
|
-
if isinstance(series_data, dict):
|
|
230
|
-
seasons_list = series_data.get("seasons", [])
|
|
231
|
-
elif isinstance(series_data, list):
|
|
232
|
-
seasons_list = series_data
|
|
233
|
-
|
|
234
|
-
for season in seasons_list:
|
|
235
|
-
if not isinstance(season, dict): continue
|
|
236
|
-
s_no = season.get("season_no") or season.get("seasonNo")
|
|
237
|
-
ep_list = season.get("episodes", [])
|
|
238
|
-
for ep in ep_list:
|
|
239
|
-
episodes.append(Episode(
|
|
240
|
-
season = s_no,
|
|
241
|
-
episode = ep.get("episode_no") or ep.get("episodeNo"),
|
|
242
|
-
title = ep.get("ep_text") or ep.get("epText"),
|
|
243
|
-
url = self.fix_url(ep.get("used_slug") or ep.get("usedSlug"))
|
|
244
|
-
))
|
|
209
|
+
print(f"DEBUG: type(content_details)={type(content_details)}")
|
|
210
|
+
item = content_details.get("contentItem", {})
|
|
211
|
+
print(f"DEBUG: type(item)={type(item)}")
|
|
212
|
+
related_results = content_details.get("RelatedResults", {})
|
|
213
|
+
|
|
214
|
+
title = item.get("original_title") or item.get("culture_title") or item.get("originalTitle") or ""
|
|
215
|
+
poster = self.clean_image_url(item.get("poster_url") or item.get("posterUrl") or item.get("face_url"))
|
|
216
|
+
description = item.get("description") or item.get("used_description")
|
|
217
|
+
rating = str(item.get("imdb_point") or item.get("imdbPoint") or "")
|
|
218
|
+
year = str(item.get("release_year") or item.get("releaseYear") or "")
|
|
219
|
+
duration = item.get("total_minutes") or item.get("totalMinutes")
|
|
220
|
+
|
|
221
|
+
tags = []
|
|
222
|
+
tags_raw = item.get("category_names") or item.get("categoryNames") or item.get("categories")
|
|
223
|
+
if isinstance(tags_raw, str):
|
|
224
|
+
tags = [t.strip() for t in tags_raw.split(",")]
|
|
225
|
+
elif isinstance(tags_raw, list):
|
|
226
|
+
tags = [c.get("title") if isinstance(c, dict) else str(c) for c in tags_raw]
|
|
227
|
+
|
|
228
|
+
actors = []
|
|
229
|
+
actors_raw = item.get("actor_names") or item.get("actorNames")
|
|
230
|
+
if isinstance(actors_raw, str):
|
|
231
|
+
actors = [a.strip() for a in actors_raw.split(",")]
|
|
245
232
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
episodes
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
233
|
+
# Casts from RelatedResults
|
|
234
|
+
casts_data = related_results.get("getSerieCastsById") or related_results.get("getMovieCastsById")
|
|
235
|
+
if casts_data and isinstance(casts_data, dict) and casts_data.get("result"):
|
|
236
|
+
actors = [cast.get("name") for cast in casts_data["result"] if cast.get("name")]
|
|
237
|
+
|
|
238
|
+
series_data = related_results.get("getSerieSeasonAndEpisodes")
|
|
239
|
+
if series_data and isinstance(series_data, dict) and series_data.get("result"):
|
|
240
|
+
episodes = []
|
|
241
|
+
for season in series_data["result"]:
|
|
242
|
+
s_no = season.get("season_no") or season.get("seasonNo") or 1
|
|
243
|
+
for ep in season.get("episodes", []):
|
|
244
|
+
ep_slug = ep.get("used_slug") or ep.get("usedSlug")
|
|
245
|
+
if ep_slug:
|
|
246
|
+
episodes.append(Episode(
|
|
247
|
+
season = s_no,
|
|
248
|
+
episode = ep.get("episode_no") or ep.get("episodeNo") or 1,
|
|
249
|
+
title = ep.get("ep_text") or ep.get("epText") or "",
|
|
250
|
+
url = self.fix_url(ep_slug)
|
|
251
|
+
))
|
|
252
|
+
|
|
253
|
+
return SeriesInfo(
|
|
254
|
+
url = url,
|
|
255
|
+
poster = poster,
|
|
256
|
+
title = self.clean_title(title),
|
|
257
|
+
description = description,
|
|
258
|
+
tags = tags,
|
|
259
|
+
rating = rating,
|
|
260
|
+
year = year,
|
|
261
|
+
actors = actors,
|
|
262
|
+
duration = duration,
|
|
263
|
+
episodes = episodes
|
|
264
|
+
)
|
|
265
|
+
else:
|
|
266
|
+
return MovieInfo(
|
|
267
|
+
url = url,
|
|
268
|
+
poster = poster,
|
|
269
|
+
title = self.clean_title(title),
|
|
270
|
+
description = description,
|
|
271
|
+
tags = tags,
|
|
272
|
+
rating = rating,
|
|
273
|
+
year = year,
|
|
274
|
+
actors = actors,
|
|
275
|
+
duration = duration
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
except Exception:
|
|
279
|
+
return SeriesInfo(url=url, title=self.clean_title(sel.select_text("h1")) or "Bilinmeyen")
|
|
266
280
|
|
|
267
281
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
268
282
|
resp = await self.httpx.get(url)
|
|
269
|
-
sel =
|
|
283
|
+
sel = HTMLHelper(resp.text)
|
|
270
284
|
|
|
271
|
-
|
|
272
|
-
if not next_data_el:
|
|
273
|
-
return []
|
|
274
|
-
|
|
275
|
-
next_data = next_data_el.text(strip=True)
|
|
285
|
+
next_data = sel.select_text("script#__NEXT_DATA__")
|
|
276
286
|
if not next_data:
|
|
277
287
|
return []
|
|
278
288
|
|
|
@@ -312,9 +322,8 @@ class SelcukFlix(PluginBase):
|
|
|
312
322
|
source_content = res[0].get("source_content") or res[0].get("sourceContent")
|
|
313
323
|
|
|
314
324
|
if source_content:
|
|
315
|
-
iframe_sel =
|
|
316
|
-
|
|
317
|
-
iframe_src = iframe_el.attrs.get("src") if iframe_el else None
|
|
325
|
+
iframe_sel = HTMLHelper(source_content)
|
|
326
|
+
iframe_src = iframe_sel.select_attr("iframe", "src")
|
|
318
327
|
if iframe_src:
|
|
319
328
|
iframe_src = self.fix_url(iframe_src)
|
|
320
329
|
# Hotlinger domain değişimi (Kotlin referansı)
|
|
@@ -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
|
-
|
|
5
|
-
import re, json
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult, HTMLHelper
|
|
4
|
+
import json, asyncio
|
|
6
5
|
|
|
7
6
|
class SetFilmIzle(PluginBase):
|
|
8
7
|
name = "SetFilmIzle"
|
|
@@ -34,8 +33,8 @@ class SetFilmIzle(PluginBase):
|
|
|
34
33
|
f"{main_url}/tur/western/" : "Western"
|
|
35
34
|
}
|
|
36
35
|
|
|
37
|
-
def _get_nonce(self, nonce_type: str = "
|
|
38
|
-
"""Site cache'lenmiş nonce'ları expire olabiliyor, fresh nonce al"""
|
|
36
|
+
def _get_nonce(self, nonce_type: str = "video", referer: str = None) -> str:
|
|
37
|
+
"""Site cache'lenmiş nonce'ları expire olabiliyor, fresh nonce al veya sayfadan çek"""
|
|
39
38
|
try:
|
|
40
39
|
resp = self.cloudscraper.post(
|
|
41
40
|
f"{self.main_url}/wp-admin/admin-ajax.php",
|
|
@@ -46,24 +45,31 @@ class SetFilmIzle(PluginBase):
|
|
|
46
45
|
},
|
|
47
46
|
data = "action=st_cache_refresh_nonces"
|
|
48
47
|
)
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
data = resp.json()
|
|
49
|
+
if data and data.get("success"):
|
|
50
|
+
nonces = data.get("data", {}).get("nonces", {})
|
|
51
|
+
return nonces.get(nonce_type if nonce_type != "search" else "dt_ajax_search", "")
|
|
52
|
+
except:
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
# AJAX başarısızsa sayfadan çekmeyi dene
|
|
56
|
+
try:
|
|
57
|
+
main_resp = self.cloudscraper.get(referer or self.main_url)
|
|
58
|
+
# STMOVIE_AJAX = { ... nonces: { search: "...", ... } }
|
|
59
|
+
nonce = HTMLHelper(main_resp.text).regex_first(rf'"{nonce_type}":\s*"([^"]+)"')
|
|
60
|
+
return nonce or ""
|
|
51
61
|
except:
|
|
52
62
|
return ""
|
|
53
63
|
|
|
54
64
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
55
65
|
istek = self.cloudscraper.get(url)
|
|
56
|
-
secici =
|
|
66
|
+
secici = HTMLHelper(istek.text)
|
|
57
67
|
|
|
58
68
|
results = []
|
|
59
|
-
for item in secici.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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("data-src") if img_el else None
|
|
69
|
+
for item in secici.select("div.items article"):
|
|
70
|
+
title = secici.select_text("h2", item)
|
|
71
|
+
href = secici.select_attr("a", "href", item)
|
|
72
|
+
poster = secici.select_attr("img", "data-src", item)
|
|
67
73
|
|
|
68
74
|
if title and href:
|
|
69
75
|
results.append(MainPageResult(
|
|
@@ -99,17 +105,13 @@ class SetFilmIzle(PluginBase):
|
|
|
99
105
|
except:
|
|
100
106
|
return []
|
|
101
107
|
|
|
102
|
-
secici =
|
|
108
|
+
secici = HTMLHelper(html)
|
|
103
109
|
results = []
|
|
104
110
|
|
|
105
|
-
for item in secici.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
title = title_el.text(strip=True) if title_el else None
|
|
111
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
112
|
-
poster = img_el.attrs.get("data-src") if img_el else None
|
|
111
|
+
for item in secici.select("div.items article"):
|
|
112
|
+
title = secici.select_text("h2", item)
|
|
113
|
+
href = secici.select_attr("a", "href", item)
|
|
114
|
+
poster = secici.select_attr("img", "data-src", item)
|
|
113
115
|
|
|
114
116
|
if title and href:
|
|
115
117
|
results.append(SearchResult(
|
|
@@ -121,79 +123,66 @@ class SetFilmIzle(PluginBase):
|
|
|
121
123
|
return results
|
|
122
124
|
|
|
123
125
|
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
124
|
-
istek =
|
|
125
|
-
secici =
|
|
126
|
+
istek = self.cloudscraper.get(url)
|
|
127
|
+
secici = HTMLHelper(istek.text)
|
|
126
128
|
html_text = istek.text
|
|
127
129
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if not raw_title:
|
|
131
|
-
# Alternatif title yeri
|
|
132
|
-
title_meta = secici.css_first("meta[property='og:title']")
|
|
133
|
-
raw_title = title_meta.attrs.get("content", "") if title_meta else ""
|
|
134
|
-
|
|
135
|
-
title = re.sub(r"\s*izle.*$", "", raw_title, flags=re.IGNORECASE).strip()
|
|
130
|
+
raw_title = secici.select_text("h1") or secici.select_text(".titles h1") or secici.select_attr("meta[property='og:title']", "content") or ""
|
|
131
|
+
title = HTMLHelper(raw_title).regex_replace(r"(?i)\s*izle.*$", "", flags=0).strip()
|
|
136
132
|
|
|
137
|
-
|
|
138
|
-
poster = poster_el.attrs.get("src") if poster_el else None
|
|
133
|
+
poster = secici.select_attr("div.poster img", "src")
|
|
139
134
|
|
|
140
|
-
|
|
141
|
-
description = desc_el.text(strip=True) if desc_el else None
|
|
135
|
+
description = secici.select_text("div.wp-content p")
|
|
142
136
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
year =
|
|
137
|
+
rating = secici.select_text("b#repimdb strong") or secici.regex_first(r'repimdb"><strong>\s*([^<]+)</strong>', html_text)
|
|
138
|
+
|
|
139
|
+
# Yıl için info bölümünden veya regex ile yakala
|
|
140
|
+
year = secici.regex_first(r'(\d{4})', secici.select_text("div.extra span.valor") or secici.select_text("span.valor") or "")
|
|
141
|
+
if not year:
|
|
142
|
+
year = secici.regex_first(r'<span>(\d{4})</span>', html_text) or secici.regex_first(r'(\d{4})', html_text)
|
|
149
143
|
|
|
150
|
-
tags = [a.text(strip=True) for a in secici.
|
|
144
|
+
tags = [a.text(strip=True) for a in secici.select("div.sgeneros a") if a.text(strip=True)]
|
|
151
145
|
|
|
152
|
-
|
|
153
|
-
duration = None
|
|
154
|
-
if duration_el:
|
|
155
|
-
duration_text = duration_el.text(strip=True)
|
|
156
|
-
dur_match = re.search(r"\d+", duration_text)
|
|
157
|
-
duration = int(dur_match.group()) if dur_match else None
|
|
146
|
+
duration_text = secici.select_text("span.runtime")
|
|
147
|
+
duration = int(secici.regex_first(r"\d+", duration_text)) if duration_text and secici.regex_first(r"\d+", duration_text) else None
|
|
158
148
|
|
|
159
|
-
actors = [
|
|
149
|
+
actors = [a.text(strip=True) for a in secici.select("span.valor a") if "/oyuncu/" in (a.attrs.get("href") or "")]
|
|
150
|
+
if not actors:
|
|
151
|
+
actors = secici.regex_all(r'href="[^"]*/oyuncu/[^"]*">([^<]+)</a>')
|
|
160
152
|
|
|
161
|
-
|
|
162
|
-
|
|
153
|
+
trailer = None
|
|
154
|
+
if trailer_id := secici.regex_first(r'embed/([^?]*)\?rel', html_text):
|
|
155
|
+
trailer = f"https://www.youtube.com/embed/{trailer_id}"
|
|
163
156
|
|
|
164
157
|
# Dizi mi film mi kontrol et
|
|
165
158
|
is_series = "/dizi/" in url
|
|
166
159
|
|
|
167
160
|
if is_series:
|
|
168
|
-
|
|
169
|
-
if
|
|
170
|
-
|
|
171
|
-
year_match = re.search(r"\d{4}", year_elem)
|
|
172
|
-
year = year_match.group() if year_match else year
|
|
161
|
+
year_elem = secici.select_text("a[href*='/yil/']")
|
|
162
|
+
if year_elem:
|
|
163
|
+
year = secici.regex_first(r"\d{4}", year_elem) or year
|
|
173
164
|
|
|
174
165
|
# Duration from info section
|
|
175
|
-
for span in secici.
|
|
166
|
+
for span in secici.select("div#info span"):
|
|
176
167
|
span_text = span.text(strip=True) if span.text() else ""
|
|
177
168
|
if "Dakika" in span_text:
|
|
178
|
-
|
|
179
|
-
duration = int(dur_match.group()) if dur_match else duration
|
|
169
|
+
duration = secici.regex_first(r"\d+", span_text) and int(secici.regex_first(r"\d+", span_text))
|
|
180
170
|
break
|
|
181
171
|
|
|
182
172
|
episodes = []
|
|
183
|
-
for ep_item in secici.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
ep_name = ep_title_el.text(strip=True) if ep_title_el else None
|
|
173
|
+
for ep_item in secici.select("div#episodes ul.episodios li"):
|
|
174
|
+
ep_href = secici.select_attr("h4.episodiotitle a", "href", ep_item)
|
|
175
|
+
ep_name = secici.select_text("h4.episodiotitle a", ep_item)
|
|
187
176
|
|
|
188
177
|
if not ep_href or not ep_name:
|
|
189
178
|
continue
|
|
190
179
|
|
|
191
180
|
ep_detail = ep_name
|
|
192
|
-
|
|
193
|
-
|
|
181
|
+
ep_season = secici.regex_first(r"(\d+)\.\s*Sezon", ep_detail) or 1
|
|
182
|
+
ep_episode = secici.regex_first(r"Sezon\s+(\d+)\.\s*Bölüm", ep_detail)
|
|
194
183
|
|
|
195
|
-
ep_season = int(
|
|
196
|
-
ep_episode = int(
|
|
184
|
+
ep_season = int(ep_season) if isinstance(ep_season, str) and ep_season.isdigit() else 1
|
|
185
|
+
ep_episode = int(ep_episode) if isinstance(ep_episode, str) and ep_episode.isdigit() else None
|
|
197
186
|
|
|
198
187
|
episodes.append(Episode(
|
|
199
188
|
season = ep_season,
|
|
@@ -201,13 +190,13 @@ class SetFilmIzle(PluginBase):
|
|
|
201
190
|
title = ep_name,
|
|
202
191
|
url = self.fix_url(ep_href)
|
|
203
192
|
))
|
|
204
|
-
|
|
205
193
|
return SeriesInfo(
|
|
206
194
|
url = url,
|
|
207
195
|
poster = self.fix_url(poster) if poster else None,
|
|
208
196
|
title = title,
|
|
209
197
|
description = description,
|
|
210
198
|
tags = tags,
|
|
199
|
+
rating = rating,
|
|
211
200
|
year = year,
|
|
212
201
|
duration = duration,
|
|
213
202
|
actors = actors,
|
|
@@ -220,6 +209,7 @@ class SetFilmIzle(PluginBase):
|
|
|
220
209
|
title = title,
|
|
221
210
|
description = description,
|
|
222
211
|
tags = tags,
|
|
212
|
+
rating = rating,
|
|
223
213
|
year = year,
|
|
224
214
|
duration = duration,
|
|
225
215
|
actors = actors
|
|
@@ -227,9 +217,9 @@ class SetFilmIzle(PluginBase):
|
|
|
227
217
|
|
|
228
218
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
229
219
|
istek = await self.httpx.get(url)
|
|
230
|
-
secici =
|
|
220
|
+
secici = HTMLHelper(istek.text)
|
|
231
221
|
|
|
232
|
-
nonce =
|
|
222
|
+
nonce = secici.select_attr("div#playex", "data-nonce") or ""
|
|
233
223
|
|
|
234
224
|
# partKey to dil label mapping
|
|
235
225
|
part_key_labels = {
|
|
@@ -238,46 +228,49 @@ class SetFilmIzle(PluginBase):
|
|
|
238
228
|
"orijinal" : "Orijinal"
|
|
239
229
|
}
|
|
240
230
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
"
|
|
256
|
-
"
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
label
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
231
|
+
semaphore = asyncio.Semaphore(5)
|
|
232
|
+
tasks = []
|
|
233
|
+
|
|
234
|
+
async def fetch_and_extract(player):
|
|
235
|
+
async with semaphore:
|
|
236
|
+
source_id = player.attrs.get("data-post-id")
|
|
237
|
+
player_name = player.attrs.get("data-player-name")
|
|
238
|
+
part_key = player.attrs.get("data-part-key")
|
|
239
|
+
|
|
240
|
+
if not source_id or "event" in source_id or source_id == "":
|
|
241
|
+
return None
|
|
242
|
+
|
|
243
|
+
try:
|
|
244
|
+
resp = self.cloudscraper.post(
|
|
245
|
+
f"{self.main_url}/wp-admin/admin-ajax.php",
|
|
246
|
+
headers = {"Referer": url},
|
|
247
|
+
data = {
|
|
248
|
+
"action" : "get_video_url",
|
|
249
|
+
"nonce" : nonce,
|
|
250
|
+
"post_id" : source_id,
|
|
251
|
+
"player_name" : player_name or "",
|
|
252
|
+
"part_key" : part_key or ""
|
|
253
|
+
}
|
|
254
|
+
)
|
|
255
|
+
data = resp.json()
|
|
256
|
+
except:
|
|
257
|
+
return None
|
|
258
|
+
|
|
259
|
+
iframe_url = data.get("data", {}).get("url")
|
|
260
|
+
if not iframe_url:
|
|
261
|
+
return None
|
|
262
|
+
|
|
263
|
+
if "setplay" not in iframe_url and part_key:
|
|
264
|
+
iframe_url = f"{iframe_url}?partKey={part_key}"
|
|
265
|
+
|
|
266
|
+
label = part_key_labels.get(part_key, "")
|
|
267
|
+
if not label and part_key:
|
|
268
|
+
label = part_key.replace("_", " ").title()
|
|
269
|
+
|
|
270
|
+
return await self.extract(iframe_url, prefix=label if label else None)
|
|
271
|
+
|
|
272
|
+
for player in secici.select("nav.player a"):
|
|
273
|
+
tasks.append(fetch_and_extract(player))
|
|
274
|
+
|
|
275
|
+
results = await asyncio.gather(*tasks)
|
|
276
|
+
return [r for r in results if r]
|