KekikStream 2.0.2__py3-none-any.whl → 2.2.0__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.
- KekikStream/Core/Extractor/ExtractorBase.py +7 -2
- KekikStream/Core/Plugin/PluginBase.py +61 -13
- KekikStream/Extractors/CloseLoad.py +17 -2
- KekikStream/Extractors/ContentX.py +19 -2
- KekikStream/Extractors/DonilasPlay.py +86 -0
- KekikStream/Extractors/Filemoon.py +78 -0
- KekikStream/Extractors/MixTiger.py +5 -5
- KekikStream/Extractors/Odnoklassniki.py +6 -0
- KekikStream/Extractors/PeaceMakerst.py +6 -0
- KekikStream/Extractors/PlayerFilmIzle.py +8 -5
- KekikStream/Extractors/RapidVid.py +21 -5
- KekikStream/Extractors/SetPlay.py +13 -4
- KekikStream/Extractors/VCTPlay.py +41 -0
- KekikStream/Extractors/VidHide.py +11 -2
- KekikStream/Extractors/VidMoly.py +52 -30
- KekikStream/Extractors/YTDLP.py +88 -54
- KekikStream/Plugins/BelgeselX.py +196 -0
- KekikStream/Plugins/DiziBox.py +8 -12
- KekikStream/Plugins/DiziPal.py +11 -22
- KekikStream/Plugins/DiziYou.py +9 -17
- KekikStream/Plugins/Dizilla.py +19 -14
- KekikStream/Plugins/FilmBip.py +5 -8
- KekikStream/Plugins/FilmMakinesi.py +31 -21
- KekikStream/Plugins/FilmModu.py +14 -18
- KekikStream/Plugins/FullHDFilm.py +83 -27
- KekikStream/Plugins/FullHDFilmizlesene.py +6 -8
- KekikStream/Plugins/HDFilmCehennemi.py +133 -57
- KekikStream/Plugins/JetFilmizle.py +29 -14
- KekikStream/Plugins/KultFilmler.py +13 -15
- KekikStream/Plugins/RecTV.py +16 -24
- KekikStream/Plugins/RoketDizi.py +22 -32
- KekikStream/Plugins/SelcukFlix.py +99 -80
- KekikStream/Plugins/SetFilmIzle.py +252 -0
- KekikStream/Plugins/SezonlukDizi.py +43 -9
- KekikStream/Plugins/SineWix.py +13 -21
- KekikStream/Plugins/Sinefy.py +13 -10
- KekikStream/Plugins/SinemaCX.py +35 -38
- KekikStream/Plugins/Sinezy.py +5 -8
- KekikStream/Plugins/SuperFilmGeldi.py +36 -27
- KekikStream/Plugins/UgurFilm.py +7 -9
- KekikStream/__init__.py +17 -36
- {kekikstream-2.0.2.dist-info → kekikstream-2.2.0.dist-info}/METADATA +6 -3
- kekikstream-2.2.0.dist-info/RECORD +81 -0
- KekikStream/Extractors/ContentX_.py +0 -40
- KekikStream/Extractors/FirePlayer.py +0 -60
- KekikStream/Extractors/Odnoklassniki_.py +0 -11
- KekikStream/Extractors/PeaceMakerst_.py +0 -7
- KekikStream/Extractors/RapidVid_.py +0 -7
- KekikStream/Extractors/VidMoly_.py +0 -7
- kekikstream-2.0.2.dist-info/RECORD +0 -82
- {kekikstream-2.0.2.dist-info → kekikstream-2.2.0.dist-info}/WHEEL +0 -0
- {kekikstream-2.0.2.dist-info → kekikstream-2.2.0.dist-info}/entry_points.txt +0 -0
- {kekikstream-2.0.2.dist-info → kekikstream-2.2.0.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-2.0.2.dist-info → kekikstream-2.2.0.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +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
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
import re, base64, json, urllib.parse
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ class SelcukFlix(PluginBase):
|
|
|
9
9
|
lang = "tr"
|
|
10
10
|
main_url = "https://selcukflix.net"
|
|
11
11
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
12
|
-
description = "Selcukflix
|
|
12
|
+
description = "Selcukflix'te her türden en yeni ve en popüler dizi ve filmleri izlemenin keyfini çıkarın. Aksiyondan romantiğe, bilim kurgudan dramaya, geniş kütüphanemizde herkes için bir şey var."
|
|
13
13
|
|
|
14
14
|
main_page = {
|
|
15
15
|
f"{main_url}/tum-bolumler" : "Yeni Eklenen Bölümler",
|
|
@@ -137,8 +137,13 @@ class SelcukFlix(PluginBase):
|
|
|
137
137
|
search_url = f"{self.main_url}/api/bg/searchcontent?searchterm={query}"
|
|
138
138
|
|
|
139
139
|
headers = {
|
|
140
|
+
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0",
|
|
140
141
|
"Accept" : "application/json, text/plain, */*",
|
|
142
|
+
"Accept-Language" : "en-US,en;q=0.5",
|
|
141
143
|
"X-Requested-With" : "XMLHttpRequest",
|
|
144
|
+
"Sec-Fetch-Site" : "same-origin",
|
|
145
|
+
"Sec-Fetch-Mode" : "cors",
|
|
146
|
+
"Sec-Fetch-Dest" : "empty",
|
|
142
147
|
"Referer" : f"{self.main_url}/"
|
|
143
148
|
}
|
|
144
149
|
|
|
@@ -151,15 +156,16 @@ class SelcukFlix(PluginBase):
|
|
|
151
156
|
try:
|
|
152
157
|
decoded_str = raw_data.decode('utf-8')
|
|
153
158
|
except UnicodeDecodeError:
|
|
154
|
-
decoded_str = raw_data.decode('iso-8859-1')
|
|
159
|
+
decoded_str = raw_data.decode('iso-8859-1')
|
|
155
160
|
|
|
156
161
|
search_data = json.loads(decoded_str)
|
|
157
162
|
|
|
158
163
|
results = []
|
|
159
164
|
for item in search_data.get("result", []):
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
165
|
+
# API field isimleri: object_name, used_slug, object_poster_url
|
|
166
|
+
title = item.get("object_name") or item.get("title")
|
|
167
|
+
slug = item.get("used_slug") or item.get("slug")
|
|
168
|
+
poster = item.get("object_poster_url") or item.get("poster")
|
|
163
169
|
|
|
164
170
|
if poster:
|
|
165
171
|
poster = self.clean_image_url(poster)
|
|
@@ -176,7 +182,7 @@ class SelcukFlix(PluginBase):
|
|
|
176
182
|
except Exception:
|
|
177
183
|
return []
|
|
178
184
|
|
|
179
|
-
async def load_item(self, url: str) -> SeriesInfo:
|
|
185
|
+
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
180
186
|
resp = await self.httpx.get(url)
|
|
181
187
|
sel = Selector(resp.text)
|
|
182
188
|
|
|
@@ -190,15 +196,17 @@ class SelcukFlix(PluginBase):
|
|
|
190
196
|
try:
|
|
191
197
|
decoded_str = raw_data.decode('utf-8')
|
|
192
198
|
except UnicodeDecodeError:
|
|
193
|
-
decoded_str = raw_data.decode('iso-8859-1')
|
|
199
|
+
decoded_str = raw_data.decode('iso-8859-1')
|
|
194
200
|
|
|
195
201
|
content_details = json.loads(decoded_str)
|
|
196
202
|
item = content_details.get("contentItem", {})
|
|
197
203
|
|
|
198
|
-
title = item.get("original_title") or item.get("originalTitle")
|
|
204
|
+
title = item.get("original_title") or item.get("originalTitle") or ""
|
|
199
205
|
poster = self.clean_image_url(item.get("poster_url") or item.get("posterUrl"))
|
|
200
206
|
description = item.get("description") or item.get("used_description")
|
|
201
207
|
rating = str(item.get("imdb_point") or item.get("imdbPoint", ""))
|
|
208
|
+
year = item.get("release_year") or item.get("releaseYear")
|
|
209
|
+
duration = item.get("total_minutes") or item.get("totalMinutes")
|
|
202
210
|
|
|
203
211
|
series_data = content_details.get("relatedData", {}).get("seriesData")
|
|
204
212
|
if not series_data and "RelatedResults" in content_details:
|
|
@@ -206,17 +214,18 @@ class SelcukFlix(PluginBase):
|
|
|
206
214
|
if series_data and isinstance(series_data, list):
|
|
207
215
|
pass
|
|
208
216
|
|
|
209
|
-
|
|
217
|
+
# Dizi mi film mi kontrol et (Kotlin referansı)
|
|
210
218
|
if series_data:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
219
|
+
episodes = []
|
|
220
|
+
seasons_list = []
|
|
221
|
+
if isinstance(series_data, dict):
|
|
222
|
+
seasons_list = series_data.get("seasons", [])
|
|
223
|
+
elif isinstance(series_data, list):
|
|
224
|
+
seasons_list = series_data
|
|
225
|
+
|
|
226
|
+
for season in seasons_list:
|
|
218
227
|
if not isinstance(season, dict): continue
|
|
219
|
-
s_no = season.get("season_no") or season.get("seasonNo")
|
|
228
|
+
s_no = season.get("season_no") or season.get("seasonNo")
|
|
220
229
|
ep_list = season.get("episodes", [])
|
|
221
230
|
for ep in ep_list:
|
|
222
231
|
episodes.append(Episode(
|
|
@@ -225,75 +234,85 @@ class SelcukFlix(PluginBase):
|
|
|
225
234
|
title = ep.get("ep_text") or ep.get("epText"),
|
|
226
235
|
url = self.fix_url(ep.get("used_slug") or ep.get("usedSlug"))
|
|
227
236
|
))
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
237
|
+
|
|
238
|
+
return SeriesInfo(
|
|
239
|
+
title = title,
|
|
240
|
+
url = url,
|
|
241
|
+
poster = poster,
|
|
242
|
+
description = description,
|
|
243
|
+
rating = rating,
|
|
244
|
+
year = year,
|
|
245
|
+
episodes = episodes
|
|
246
|
+
)
|
|
247
|
+
else:
|
|
248
|
+
# Film ise MovieInfo döndür
|
|
249
|
+
return MovieInfo(
|
|
250
|
+
title = title,
|
|
251
|
+
url = url,
|
|
252
|
+
poster = poster,
|
|
253
|
+
description = description,
|
|
254
|
+
rating = rating,
|
|
255
|
+
year = year,
|
|
256
|
+
duration = duration
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
239
260
|
resp = await self.httpx.get(url)
|
|
240
261
|
sel = Selector(resp.text)
|
|
241
262
|
|
|
242
263
|
next_data = sel.css("script#__NEXT_DATA__::text").get()
|
|
243
|
-
if not next_data:
|
|
264
|
+
if not next_data:
|
|
265
|
+
return []
|
|
244
266
|
|
|
245
267
|
try:
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
try:
|
|
250
|
-
decoded_str = raw_data.decode('utf-8')
|
|
251
|
-
except UnicodeDecodeError:
|
|
252
|
-
decoded_str = raw_data.decode('iso-8859-1')
|
|
268
|
+
data = json.loads(next_data)
|
|
269
|
+
secure_data = data["props"]["pageProps"]["secureData"]
|
|
270
|
+
raw_data = base64.b64decode(secure_data.replace('"', ''))
|
|
253
271
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
272
|
+
try:
|
|
273
|
+
decoded_str = raw_data.decode('utf-8')
|
|
274
|
+
except UnicodeDecodeError:
|
|
275
|
+
decoded_str = raw_data.decode('iso-8859-1')
|
|
276
|
+
|
|
277
|
+
content_details = json.loads(decoded_str)
|
|
278
|
+
related_results = content_details.get("RelatedResults", {})
|
|
279
|
+
|
|
280
|
+
source_content = None
|
|
281
|
+
|
|
282
|
+
# Dizi (bölüm) için
|
|
283
|
+
if "/dizi/" in url:
|
|
284
|
+
episode_sources = related_results.get("getEpisodeSources", {})
|
|
285
|
+
if episode_sources.get("state"):
|
|
286
|
+
res = episode_sources.get("result", [])
|
|
287
|
+
if res:
|
|
288
|
+
source_content = res[0].get("source_content") or res[0].get("sourceContent")
|
|
289
|
+
else:
|
|
290
|
+
# Film için
|
|
291
|
+
movie_parts = related_results.get("getMoviePartsById", {})
|
|
292
|
+
if movie_parts.get("state"):
|
|
293
|
+
parts = movie_parts.get("result", [])
|
|
294
|
+
if parts:
|
|
295
|
+
first_part_id = parts[0].get("id")
|
|
296
|
+
key = f"getMoviePartSourcesById_{first_part_id}"
|
|
297
|
+
if key in related_results:
|
|
298
|
+
res = related_results[key].get("result", [])
|
|
299
|
+
if res:
|
|
300
|
+
source_content = res[0].get("source_content") or res[0].get("sourceContent")
|
|
301
|
+
|
|
302
|
+
if source_content:
|
|
303
|
+
iframe_sel = Selector(source_content)
|
|
304
|
+
iframe_src = iframe_sel.css("iframe::attr(src)").get()
|
|
305
|
+
if iframe_src:
|
|
306
|
+
iframe_src = self.fix_url(iframe_src)
|
|
307
|
+
# Hotlinger domain değişimi (Kotlin referansı)
|
|
308
|
+
if "sn.dplayer74.site" in iframe_src:
|
|
309
|
+
iframe_src = iframe_src.replace("sn.dplayer74.site", "sn.hotlinger.com")
|
|
310
|
+
|
|
311
|
+
data = await self.extract(iframe_src)
|
|
312
|
+
if data:
|
|
313
|
+
return [data]
|
|
314
|
+
|
|
315
|
+
return []
|
|
297
316
|
|
|
298
317
|
except Exception:
|
|
299
318
|
return []
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult
|
|
4
|
+
from parsel import Selector
|
|
5
|
+
import re, json
|
|
6
|
+
|
|
7
|
+
class SetFilmIzle(PluginBase):
|
|
8
|
+
name = "SetFilmIzle"
|
|
9
|
+
language = "tr"
|
|
10
|
+
main_url = "https://www.setfilmizle.uk"
|
|
11
|
+
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
12
|
+
description = "Setfilmizle sitemizde, donma yaşamadan Türkçe dublaj ve altyazılı filmleri ile dizileri muhteşem 1080p full HD kalitesinde izleyebilirsiniz."
|
|
13
|
+
|
|
14
|
+
main_page = {
|
|
15
|
+
f"{main_url}/tur/aile/" : "Aile",
|
|
16
|
+
f"{main_url}/tur/aksiyon/" : "Aksiyon",
|
|
17
|
+
f"{main_url}/tur/animasyon/" : "Animasyon",
|
|
18
|
+
f"{main_url}/tur/belgesel/" : "Belgesel",
|
|
19
|
+
f"{main_url}/tur/bilim-kurgu/" : "Bilim-Kurgu",
|
|
20
|
+
f"{main_url}/tur/biyografi/" : "Biyografi",
|
|
21
|
+
f"{main_url}/tur/dini/" : "Dini",
|
|
22
|
+
f"{main_url}/tur/dram/" : "Dram",
|
|
23
|
+
f"{main_url}/tur/fantastik/" : "Fantastik",
|
|
24
|
+
f"{main_url}/tur/genclik/" : "Gençlik",
|
|
25
|
+
f"{main_url}/tur/gerilim/" : "Gerilim",
|
|
26
|
+
f"{main_url}/tur/gizem/" : "Gizem",
|
|
27
|
+
f"{main_url}/tur/komedi/" : "Komedi",
|
|
28
|
+
f"{main_url}/tur/korku/" : "Korku",
|
|
29
|
+
f"{main_url}/tur/macera/" : "Macera",
|
|
30
|
+
f"{main_url}/tur/romantik/" : "Romantik",
|
|
31
|
+
f"{main_url}/tur/savas/" : "Savaş",
|
|
32
|
+
f"{main_url}/tur/suc/" : "Suç",
|
|
33
|
+
f"{main_url}/tur/tarih/" : "Tarih",
|
|
34
|
+
f"{main_url}/tur/western/" : "Western"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
def _get_nonce(self, nonce_type: str = "video_nonce", referer: str = None) -> str:
|
|
38
|
+
"""Site cache'lenmiş nonce'ları expire olabiliyor, fresh nonce al"""
|
|
39
|
+
try:
|
|
40
|
+
resp = self.cloudscraper.post(
|
|
41
|
+
f"{self.main_url}/wp-admin/admin-ajax.php",
|
|
42
|
+
headers = {
|
|
43
|
+
"Referer" : referer or self.main_url,
|
|
44
|
+
"Origin" : self.main_url,
|
|
45
|
+
"Content-Type" : "application/x-www-form-urlencoded",
|
|
46
|
+
},
|
|
47
|
+
data = "action=st_cache_refresh_nonces"
|
|
48
|
+
)
|
|
49
|
+
nonces = resp.json().get("data", {}).get("nonces", {})
|
|
50
|
+
return nonces.get(nonce_type, "")
|
|
51
|
+
except:
|
|
52
|
+
return ""
|
|
53
|
+
|
|
54
|
+
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
55
|
+
istek = self.cloudscraper.get(url)
|
|
56
|
+
secici = Selector(istek.text)
|
|
57
|
+
|
|
58
|
+
results = []
|
|
59
|
+
for item in secici.css("div.items article"):
|
|
60
|
+
title = item.css("h2::text").get()
|
|
61
|
+
href = item.css("a::attr(href)").get()
|
|
62
|
+
poster = item.css("img::attr(data-src)").get()
|
|
63
|
+
|
|
64
|
+
if title and href:
|
|
65
|
+
results.append(MainPageResult(
|
|
66
|
+
category = category,
|
|
67
|
+
title = title.strip(),
|
|
68
|
+
url = self.fix_url(href),
|
|
69
|
+
poster = self.fix_url(poster) if poster else None
|
|
70
|
+
))
|
|
71
|
+
|
|
72
|
+
return results
|
|
73
|
+
|
|
74
|
+
async def search(self, query: str) -> list[SearchResult]:
|
|
75
|
+
nonce = self._get_nonce("search")
|
|
76
|
+
|
|
77
|
+
search_resp = self.cloudscraper.post(
|
|
78
|
+
f"{self.main_url}/wp-admin/admin-ajax.php",
|
|
79
|
+
headers = {
|
|
80
|
+
"X-Requested-With" : "XMLHttpRequest",
|
|
81
|
+
"Content-Type" : "application/x-www-form-urlencoded",
|
|
82
|
+
"Referer" : f"{self.main_url}/"
|
|
83
|
+
},
|
|
84
|
+
data = {
|
|
85
|
+
"action" : "ajax_search",
|
|
86
|
+
"search" : query,
|
|
87
|
+
"original_search" : query,
|
|
88
|
+
"nonce" : nonce
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
data = search_resp.json()
|
|
94
|
+
html = data.get("html", "")
|
|
95
|
+
except:
|
|
96
|
+
return []
|
|
97
|
+
|
|
98
|
+
secici = Selector(text=html)
|
|
99
|
+
results = []
|
|
100
|
+
|
|
101
|
+
for item in secici.css("div.items article"):
|
|
102
|
+
title = item.css("h2::text").get()
|
|
103
|
+
href = item.css("a::attr(href)").get()
|
|
104
|
+
poster = item.css("img::attr(data-src)").get()
|
|
105
|
+
|
|
106
|
+
if title and href:
|
|
107
|
+
results.append(SearchResult(
|
|
108
|
+
title = title.strip(),
|
|
109
|
+
url = self.fix_url(href),
|
|
110
|
+
poster = self.fix_url(poster) if poster else None
|
|
111
|
+
))
|
|
112
|
+
|
|
113
|
+
return results
|
|
114
|
+
|
|
115
|
+
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
116
|
+
istek = await self.httpx.get(url)
|
|
117
|
+
secici = Selector(istek.text)
|
|
118
|
+
|
|
119
|
+
raw_title = secici.css("h1::text").get() or ""
|
|
120
|
+
title = re.sub(r"\s*izle.*$", "", raw_title, flags=re.IGNORECASE).strip()
|
|
121
|
+
poster = secici.css("div.poster img::attr(src)").get()
|
|
122
|
+
description = secici.css("div.wp-content p::text").get()
|
|
123
|
+
year = secici.css("div.extra span.C a::text").get()
|
|
124
|
+
if year:
|
|
125
|
+
year_match = re.search(r"\d{4}", year)
|
|
126
|
+
year = year_match.group() if year_match else None
|
|
127
|
+
tags = [a.css("::text").get().strip() for a in secici.css("div.sgeneros a") if a.css("::text").get()]
|
|
128
|
+
duration = secici.css("span.runtime::text").get()
|
|
129
|
+
if duration:
|
|
130
|
+
dur_match = re.search(r"\d+", duration)
|
|
131
|
+
duration = int(dur_match.group()) if dur_match else None
|
|
132
|
+
|
|
133
|
+
actors = [span.css("::text").get().strip() for span in secici.css("span.valor a > span") if span.css("::text").get()]
|
|
134
|
+
|
|
135
|
+
trailer_match = re.search(r'embed/([^?]*)\?rel', istek.text)
|
|
136
|
+
trailer = f"https://www.youtube.com/embed/{trailer_match.group(1)}" if trailer_match else None
|
|
137
|
+
|
|
138
|
+
# Dizi mi film mi kontrol et
|
|
139
|
+
is_series = "/dizi/" in url
|
|
140
|
+
|
|
141
|
+
if is_series:
|
|
142
|
+
year_elem = secici.css("a[href*='/yil/']::text").get()
|
|
143
|
+
if year_elem:
|
|
144
|
+
year_match = re.search(r"\d{4}", year_elem)
|
|
145
|
+
year = year_match.group() if year_match else year
|
|
146
|
+
|
|
147
|
+
dur_elem = secici.css("div#info span:contains('Dakika')::text").get()
|
|
148
|
+
if dur_elem:
|
|
149
|
+
dur_match = re.search(r"\d+", dur_elem)
|
|
150
|
+
duration = int(dur_match.group()) if dur_match else duration
|
|
151
|
+
|
|
152
|
+
episodes = []
|
|
153
|
+
for ep_item in secici.css("div#episodes ul.episodios li"):
|
|
154
|
+
ep_href = ep_item.css("h4.episodiotitle a::attr(href)").get()
|
|
155
|
+
ep_name = ep_item.css("h4.episodiotitle a::text").get()
|
|
156
|
+
|
|
157
|
+
if not ep_href or not ep_name:
|
|
158
|
+
continue
|
|
159
|
+
|
|
160
|
+
ep_detail = ep_name.strip()
|
|
161
|
+
season_match = re.search(r"(\d+)\.\s*Sezon", ep_detail)
|
|
162
|
+
episode_match = re.search(r"Sezon\s+(\d+)\.\s*Bölüm", ep_detail)
|
|
163
|
+
|
|
164
|
+
ep_season = int(season_match.group(1)) if season_match else 1
|
|
165
|
+
ep_episode = int(episode_match.group(1)) if episode_match else None
|
|
166
|
+
|
|
167
|
+
episodes.append(Episode(
|
|
168
|
+
season = ep_season,
|
|
169
|
+
episode = ep_episode,
|
|
170
|
+
title = ep_name.strip(),
|
|
171
|
+
url = self.fix_url(ep_href)
|
|
172
|
+
))
|
|
173
|
+
|
|
174
|
+
return SeriesInfo(
|
|
175
|
+
url = url,
|
|
176
|
+
poster = self.fix_url(poster) if poster else None,
|
|
177
|
+
title = title,
|
|
178
|
+
description = description.strip() if description else None,
|
|
179
|
+
tags = tags,
|
|
180
|
+
year = year,
|
|
181
|
+
duration = duration,
|
|
182
|
+
actors = actors,
|
|
183
|
+
episodes = episodes
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
return MovieInfo(
|
|
187
|
+
url = url,
|
|
188
|
+
poster = self.fix_url(poster) if poster else None,
|
|
189
|
+
title = title,
|
|
190
|
+
description = description.strip() if description else None,
|
|
191
|
+
tags = tags,
|
|
192
|
+
year = year,
|
|
193
|
+
duration = duration,
|
|
194
|
+
actors = actors
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
198
|
+
istek = await self.httpx.get(url)
|
|
199
|
+
secici = Selector(istek.text)
|
|
200
|
+
|
|
201
|
+
nonce = self._get_nonce("video_nonce", referer=url)
|
|
202
|
+
|
|
203
|
+
# partKey to dil label mapping
|
|
204
|
+
part_key_labels = {
|
|
205
|
+
"turkcedublaj" : "Türkçe Dublaj",
|
|
206
|
+
"turkcealtyazi" : "Türkçe Altyazı",
|
|
207
|
+
"orijinal" : "Orijinal"
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
links = []
|
|
211
|
+
for player in secici.css("nav.player a"):
|
|
212
|
+
source_id = player.css("::attr(data-post-id)").get()
|
|
213
|
+
player_name = player.css("::attr(data-player-name)").get()
|
|
214
|
+
part_key = player.css("::attr(data-part-key)").get()
|
|
215
|
+
|
|
216
|
+
if not source_id or "event" in source_id or source_id == "":
|
|
217
|
+
continue
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
resp = self.cloudscraper.post(
|
|
221
|
+
f"{self.main_url}/wp-admin/admin-ajax.php",
|
|
222
|
+
headers = {"Referer": url},
|
|
223
|
+
data = {
|
|
224
|
+
"action" : "get_video_url",
|
|
225
|
+
"nonce" : nonce,
|
|
226
|
+
"post_id" : source_id,
|
|
227
|
+
"player_name" : player_name or "",
|
|
228
|
+
"part_key" : part_key or ""
|
|
229
|
+
}
|
|
230
|
+
)
|
|
231
|
+
data = resp.json()
|
|
232
|
+
except:
|
|
233
|
+
continue
|
|
234
|
+
|
|
235
|
+
iframe_url = data.get("data", {}).get("url")
|
|
236
|
+
if not iframe_url:
|
|
237
|
+
continue
|
|
238
|
+
|
|
239
|
+
# SetPlay URL'si için part_key ekleme
|
|
240
|
+
if "setplay" not in iframe_url and part_key:
|
|
241
|
+
iframe_url = f"{iframe_url}?partKey={part_key}"
|
|
242
|
+
|
|
243
|
+
# Dil etiketi oluştur
|
|
244
|
+
label = part_key_labels.get(part_key, "")
|
|
245
|
+
if not label and part_key:
|
|
246
|
+
label = part_key.replace("_", " ").title()
|
|
247
|
+
|
|
248
|
+
data = await self.extract(iframe_url, prefix=label if label else None)
|
|
249
|
+
if data:
|
|
250
|
+
links.append(data)
|
|
251
|
+
|
|
252
|
+
return links
|
|
@@ -1,7 +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
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult
|
|
4
4
|
from parsel import Selector
|
|
5
|
+
import re
|
|
5
6
|
|
|
6
7
|
class SezonlukDizi(PluginBase):
|
|
7
8
|
name = "SezonlukDizi"
|
|
@@ -19,6 +20,23 @@ class SezonlukDizi(PluginBase):
|
|
|
19
20
|
f"{main_url}/diziler.asp?siralama_tipi=id&kat=4&s=" : "Animasyonlar",
|
|
20
21
|
f"{main_url}/diziler.asp?siralama_tipi=id&kat=5&s=" : "Animeler",
|
|
21
22
|
f"{main_url}/diziler.asp?siralama_tipi=id&kat=6&s=" : "Belgeseller",
|
|
23
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=aile&s=" : "Aile",
|
|
24
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=aksiyon&s=" : "Aksiyon",
|
|
25
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=bilimkurgu&s=" : "Bilim Kurgu",
|
|
26
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=biyografik&s=" : "Biyografi",
|
|
27
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=dram&s=" : "Dram",
|
|
28
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=fantastik&s=" : "Fantastik",
|
|
29
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=gerilim&s=" : "Gerilim",
|
|
30
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=gizem&s=" : "Gizem",
|
|
31
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=korku&s=" : "Korku",
|
|
32
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=komedi&s=" : "Komedi",
|
|
33
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=macera&s=" : "Macera",
|
|
34
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=muzikal&s=" : "Müzikal",
|
|
35
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=suc&s=" : "Suç",
|
|
36
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=romantik&s=" : "Romantik",
|
|
37
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=savas&s=" : "Savaş",
|
|
38
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=tarihi&s=" : "Tarihi",
|
|
39
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=western&s=" : "Western"
|
|
22
40
|
}
|
|
23
41
|
|
|
24
42
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
@@ -99,7 +117,21 @@ class SezonlukDizi(PluginBase):
|
|
|
99
117
|
actors = actors
|
|
100
118
|
)
|
|
101
119
|
|
|
102
|
-
async def
|
|
120
|
+
async def get_asp_data(self) -> tuple[str, str]:
|
|
121
|
+
"""Fetch dynamic ASP version numbers from site.min.js"""
|
|
122
|
+
try:
|
|
123
|
+
js_content = await self.httpx.get(f"{self.main_url}/js/site.min.js")
|
|
124
|
+
alternatif_match = re.search(r'dataAlternatif(.*?)\.asp', js_content.text)
|
|
125
|
+
embed_match = re.search(r'dataEmbed(.*?)\.asp', js_content.text)
|
|
126
|
+
|
|
127
|
+
alternatif_ver = alternatif_match.group(1) if alternatif_match else "22"
|
|
128
|
+
embed_ver = embed_match.group(1) if embed_match else "22"
|
|
129
|
+
|
|
130
|
+
return (alternatif_ver, embed_ver)
|
|
131
|
+
except Exception:
|
|
132
|
+
return ("22", "22") # Fallback to default versions
|
|
133
|
+
|
|
134
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
103
135
|
istek = await self.httpx.get(url)
|
|
104
136
|
secici = Selector(istek.text)
|
|
105
137
|
|
|
@@ -107,10 +139,13 @@ class SezonlukDizi(PluginBase):
|
|
|
107
139
|
if not bid:
|
|
108
140
|
return []
|
|
109
141
|
|
|
142
|
+
# Get dynamic ASP versions
|
|
143
|
+
alternatif_ver, embed_ver = await self.get_asp_data()
|
|
144
|
+
|
|
110
145
|
results = []
|
|
111
146
|
for dil, label in [("1", "Altyazı"), ("0", "Dublaj")]:
|
|
112
147
|
dil_istek = await self.httpx.post(
|
|
113
|
-
url = f"{self.main_url}/ajax/
|
|
148
|
+
url = f"{self.main_url}/ajax/dataAlternatif{alternatif_ver}.asp",
|
|
114
149
|
headers = {"X-Requested-With": "XMLHttpRequest"},
|
|
115
150
|
data = {"bid": bid, "dil": dil},
|
|
116
151
|
)
|
|
@@ -123,7 +158,7 @@ class SezonlukDizi(PluginBase):
|
|
|
123
158
|
if dil_json.get("status") == "success":
|
|
124
159
|
for idx, veri in enumerate(dil_json.get("data", [])):
|
|
125
160
|
veri_response = await self.httpx.post(
|
|
126
|
-
url = f"{self.main_url}/ajax/
|
|
161
|
+
url = f"{self.main_url}/ajax/dataEmbed{embed_ver}.asp",
|
|
127
162
|
headers = {"X-Requested-With": "XMLHttpRequest"},
|
|
128
163
|
data = {"id": veri.get("id")},
|
|
129
164
|
)
|
|
@@ -133,10 +168,9 @@ class SezonlukDizi(PluginBase):
|
|
|
133
168
|
if "link.asp" in iframe:
|
|
134
169
|
continue
|
|
135
170
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
})
|
|
171
|
+
iframe_url = self.fix_url(iframe)
|
|
172
|
+
data = await self.extract(iframe_url, prefix=label)
|
|
173
|
+
if data:
|
|
174
|
+
results.append(data)
|
|
141
175
|
|
|
142
176
|
return results
|