KekikStream 2.3.3__py3-none-any.whl → 2.3.4__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/HTMLHelper.py +134 -0
- KekikStream/Core/Plugin/PluginBase.py +4 -1
- KekikStream/Core/__init__.py +2 -0
- KekikStream/Extractors/CloseLoad.py +12 -13
- KekikStream/Extractors/ContentX.py +12 -15
- KekikStream/Extractors/DonilasPlay.py +10 -10
- KekikStream/Extractors/DzenRu.py +3 -3
- KekikStream/Extractors/ExPlay.py +10 -10
- KekikStream/Extractors/Filemoon.py +11 -16
- KekikStream/Extractors/JetTv.py +4 -4
- KekikStream/Extractors/MixPlayHD.py +10 -11
- KekikStream/Extractors/MolyStream.py +5 -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 +24 -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 +41 -74
- KekikStream/Plugins/DiziYou.py +95 -88
- KekikStream/Plugins/Dizilla.py +51 -71
- KekikStream/Plugins/FilmBip.py +24 -49
- KekikStream/Plugins/FilmMakinesi.py +35 -52
- KekikStream/Plugins/FilmModu.py +27 -41
- KekikStream/Plugins/FullHDFilm.py +50 -72
- KekikStream/Plugins/FullHDFilmizlesene.py +35 -51
- KekikStream/Plugins/HDFilmCehennemi.py +48 -62
- KekikStream/Plugins/JetFilmizle.py +32 -50
- KekikStream/Plugins/KultFilmler.py +42 -67
- KekikStream/Plugins/RecTV.py +7 -4
- KekikStream/Plugins/RoketDizi.py +30 -50
- KekikStream/Plugins/SelcukFlix.py +15 -29
- KekikStream/Plugins/SetFilmIzle.py +41 -70
- KekikStream/Plugins/SezonlukDizi.py +47 -65
- KekikStream/Plugins/Sinefy.py +34 -50
- 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-2.3.3.dist-info → kekikstream-2.3.4.dist-info}/METADATA +1 -1
- kekikstream-2.3.4.dist-info/RECORD +83 -0
- kekikstream-2.3.3.dist-info/RECORD +0 -82
- {kekikstream-2.3.3.dist-info → kekikstream-2.3.4.dist-info}/WHEEL +0 -0
- {kekikstream-2.3.3.dist-info → kekikstream-2.3.4.dist-info}/entry_points.txt +0 -0
- {kekikstream-2.3.3.dist-info → kekikstream-2.3.4.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-2.3.3.dist-info → kekikstream-2.3.4.dist-info}/top_level.txt +0 -0
KekikStream/Plugins/RoketDizi.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, MovieInfo
|
|
4
|
-
|
|
5
|
-
import re, base64, json
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, MovieInfo, HTMLHelper
|
|
4
|
+
import base64, json
|
|
6
5
|
|
|
7
6
|
class RoketDizi(PluginBase):
|
|
8
7
|
name = "RoketDizi"
|
|
@@ -24,19 +23,15 @@ class RoketDizi(PluginBase):
|
|
|
24
23
|
|
|
25
24
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
26
25
|
istek = await self.httpx.get(f"{url}?&page={page}")
|
|
27
|
-
secici =
|
|
26
|
+
secici = HTMLHelper(istek.text)
|
|
28
27
|
|
|
29
28
|
results = []
|
|
30
29
|
|
|
31
30
|
# Use div.new-added-list to find the container, then get items
|
|
32
|
-
for item in secici.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
title = title_el.text(strip=True) if title_el else None
|
|
38
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
39
|
-
poster = img_el.attrs.get("src") if img_el else None
|
|
31
|
+
for item in secici.select("div.new-added-list > span"):
|
|
32
|
+
title = secici.select_text("span.line-clamp-1", item)
|
|
33
|
+
href = secici.select_attr("a", "href", item)
|
|
34
|
+
poster = secici.select_attr("img", "src", item)
|
|
40
35
|
|
|
41
36
|
if title and href:
|
|
42
37
|
results.append(MainPageResult(
|
|
@@ -92,58 +87,49 @@ class RoketDizi(PluginBase):
|
|
|
92
87
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
93
88
|
# Note: Handling both Movie and Series logic in one, returning SeriesInfo generally or MovieInfo
|
|
94
89
|
resp = await self.httpx.get(url)
|
|
95
|
-
sel =
|
|
90
|
+
sel = HTMLHelper(resp.text)
|
|
96
91
|
html_text = resp.text
|
|
97
92
|
|
|
98
|
-
|
|
99
|
-
title = title_el.text(strip=True) if title_el else None
|
|
93
|
+
title = sel.select_text("h1.text-white")
|
|
100
94
|
|
|
101
|
-
|
|
102
|
-
poster = poster_el.attrs.get("src") if poster_el else None
|
|
95
|
+
poster = sel.select_attr("div.w-full.page-top img", "src")
|
|
103
96
|
|
|
104
|
-
|
|
105
|
-
description = desc_el.text(strip=True) if desc_el else None
|
|
97
|
+
description = sel.select_text("div.mt-2.text-sm")
|
|
106
98
|
|
|
107
99
|
# Tags - genre bilgileri (Detaylar bölümünde)
|
|
108
100
|
tags = []
|
|
109
|
-
|
|
110
|
-
if
|
|
111
|
-
|
|
112
|
-
if genre_text:
|
|
113
|
-
tags = [t.strip() for t in genre_text.split(",")]
|
|
101
|
+
genre_text = sel.select_text("h3.text-white.opacity-90")
|
|
102
|
+
if genre_text:
|
|
103
|
+
tags = [t.strip() for t in genre_text.split(",")]
|
|
114
104
|
|
|
115
105
|
# Rating
|
|
116
|
-
|
|
117
|
-
rating = rating_el.text(strip=True) if rating_el else None
|
|
106
|
+
rating = sel.select_text("span.text-white.text-sm.font-bold")
|
|
118
107
|
|
|
119
108
|
# Year ve Actors - Detaylar (Details) bölümünden
|
|
120
109
|
year = None
|
|
121
110
|
actors = []
|
|
122
111
|
|
|
123
112
|
# Detaylar bölümündeki tüm flex-col div'leri al
|
|
124
|
-
detail_items = sel.
|
|
113
|
+
detail_items = sel.select("div.flex.flex-col")
|
|
125
114
|
for item in detail_items:
|
|
126
|
-
|
|
127
|
-
|
|
115
|
+
label = sel.select_text("span.text-base", item)
|
|
116
|
+
value = sel.select_text("span.text-sm.opacity-90", item)
|
|
128
117
|
|
|
129
|
-
label =
|
|
130
|
-
value =
|
|
118
|
+
label = label if label else None
|
|
119
|
+
value = value if value else None
|
|
131
120
|
|
|
132
121
|
if label and value:
|
|
133
122
|
# Yayın tarihi (yıl)
|
|
134
123
|
if label == "Yayın tarihi":
|
|
135
124
|
# "16 Ekim 2018" formatından yılı çıkar
|
|
136
|
-
|
|
137
|
-
if year_match:
|
|
138
|
-
year = year_match.group()
|
|
139
|
-
|
|
125
|
+
year = HTMLHelper(value).regex_first(r'\d{4}')
|
|
140
126
|
# Yaratıcılar veya Oyuncular
|
|
141
127
|
elif label in ["Yaratıcılar", "Oyuncular"]:
|
|
142
128
|
if value:
|
|
143
129
|
actors.append(value)
|
|
144
130
|
|
|
145
131
|
# Check urls for episodes
|
|
146
|
-
all_urls =
|
|
132
|
+
all_urls = HTMLHelper(html_text).regex_all(r'"url":"([^"]*)"')
|
|
147
133
|
is_series = any("bolum-" in u for u in all_urls)
|
|
148
134
|
|
|
149
135
|
episodes = []
|
|
@@ -152,11 +138,11 @@ class RoketDizi(PluginBase):
|
|
|
152
138
|
episodes_dict = {}
|
|
153
139
|
for u in all_urls:
|
|
154
140
|
if "bolum" in u and u not in episodes_dict:
|
|
155
|
-
|
|
156
|
-
|
|
141
|
+
season = HTMLHelper(u).regex_first(r'/sezon-(\d+)')
|
|
142
|
+
ep_num = HTMLHelper(u).regex_first(r'/bolum-(\d+)')
|
|
157
143
|
|
|
158
|
-
season = int(
|
|
159
|
-
episode_num = int(
|
|
144
|
+
season = int(season) if season else 1
|
|
145
|
+
episode_num = int(ep_num) if ep_num else 1
|
|
160
146
|
|
|
161
147
|
# Key olarak (season, episode) tuple kullan
|
|
162
148
|
key = (season, episode_num)
|
|
@@ -184,13 +170,9 @@ class RoketDizi(PluginBase):
|
|
|
184
170
|
|
|
185
171
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
186
172
|
resp = await self.httpx.get(url)
|
|
187
|
-
sel =
|
|
173
|
+
sel = HTMLHelper(resp.text)
|
|
188
174
|
|
|
189
|
-
|
|
190
|
-
if not next_data_el:
|
|
191
|
-
return []
|
|
192
|
-
|
|
193
|
-
next_data = next_data_el.text(strip=True)
|
|
175
|
+
next_data = sel.select_text("script#__NEXT_DATA__")
|
|
194
176
|
if not next_data:
|
|
195
177
|
return []
|
|
196
178
|
|
|
@@ -208,11 +190,9 @@ class RoketDizi(PluginBase):
|
|
|
208
190
|
source_content = source.get("source_content", "")
|
|
209
191
|
|
|
210
192
|
# iframe URL'ini source_content'ten çıkar
|
|
211
|
-
|
|
212
|
-
if not
|
|
193
|
+
iframe_url = HTMLHelper(source_content).regex_first(r'<iframe[^>]*src=["\']([^"\']*)["\']')
|
|
194
|
+
if not iframe_url:
|
|
213
195
|
continue
|
|
214
|
-
|
|
215
|
-
iframe_url = iframe_match.group(1)
|
|
216
196
|
|
|
217
197
|
# Fix URL protocol
|
|
218
198
|
if not iframe_url.startswith("http"):
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult
|
|
4
|
-
|
|
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,14 +183,10 @@ class SelcukFlix(PluginBase):
|
|
|
188
183
|
|
|
189
184
|
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
190
185
|
resp = await self.httpx.get(url)
|
|
191
|
-
sel =
|
|
192
|
-
|
|
193
|
-
next_data_el = sel.css_first("script#__NEXT_DATA__")
|
|
194
|
-
if not next_data_el:
|
|
195
|
-
return None
|
|
186
|
+
sel = HTMLHelper(resp.text)
|
|
196
187
|
|
|
197
|
-
next_data =
|
|
198
|
-
if not next_data:
|
|
188
|
+
next_data = sel.select_text("script#__NEXT_DATA__")
|
|
189
|
+
if not next_data:
|
|
199
190
|
return None
|
|
200
191
|
|
|
201
192
|
data = json.loads(next_data)
|
|
@@ -266,13 +257,9 @@ class SelcukFlix(PluginBase):
|
|
|
266
257
|
|
|
267
258
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
268
259
|
resp = await self.httpx.get(url)
|
|
269
|
-
sel =
|
|
260
|
+
sel = HTMLHelper(resp.text)
|
|
270
261
|
|
|
271
|
-
|
|
272
|
-
if not next_data_el:
|
|
273
|
-
return []
|
|
274
|
-
|
|
275
|
-
next_data = next_data_el.text(strip=True)
|
|
262
|
+
next_data = sel.select_text("script#__NEXT_DATA__")
|
|
276
263
|
if not next_data:
|
|
277
264
|
return []
|
|
278
265
|
|
|
@@ -312,9 +299,8 @@ class SelcukFlix(PluginBase):
|
|
|
312
299
|
source_content = res[0].get("source_content") or res[0].get("sourceContent")
|
|
313
300
|
|
|
314
301
|
if source_content:
|
|
315
|
-
iframe_sel =
|
|
316
|
-
|
|
317
|
-
iframe_src = iframe_el.attrs.get("src") if iframe_el else None
|
|
302
|
+
iframe_sel = HTMLHelper(source_content)
|
|
303
|
+
iframe_src = iframe_sel.select_attr("iframe", "src")
|
|
318
304
|
if iframe_src:
|
|
319
305
|
iframe_src = self.fix_url(iframe_src)
|
|
320
306
|
# Hotlinger domain değişimi (Kotlin referansı)
|
|
@@ -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, asyncio
|
|
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"
|
|
@@ -53,17 +52,13 @@ class SetFilmIzle(PluginBase):
|
|
|
53
52
|
|
|
54
53
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
55
54
|
istek = self.cloudscraper.get(url)
|
|
56
|
-
secici =
|
|
55
|
+
secici = HTMLHelper(istek.text)
|
|
57
56
|
|
|
58
57
|
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
|
|
58
|
+
for item in secici.select("div.items article"):
|
|
59
|
+
title = secici.select_text("h2", item)
|
|
60
|
+
href = secici.select_attr("a", "href", item)
|
|
61
|
+
poster = secici.select_attr("img", "data-src", item)
|
|
67
62
|
|
|
68
63
|
if title and href:
|
|
69
64
|
results.append(MainPageResult(
|
|
@@ -99,17 +94,13 @@ class SetFilmIzle(PluginBase):
|
|
|
99
94
|
except:
|
|
100
95
|
return []
|
|
101
96
|
|
|
102
|
-
secici =
|
|
97
|
+
secici = HTMLHelper(html)
|
|
103
98
|
results = []
|
|
104
99
|
|
|
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
|
|
100
|
+
for item in secici.select("div.items article"):
|
|
101
|
+
title = secici.select_text("h2", item)
|
|
102
|
+
href = secici.select_attr("a", "href", item)
|
|
103
|
+
poster = secici.select_attr("img", "data-src", item)
|
|
113
104
|
|
|
114
105
|
if title and href:
|
|
115
106
|
results.append(SearchResult(
|
|
@@ -122,78 +113,59 @@ class SetFilmIzle(PluginBase):
|
|
|
122
113
|
|
|
123
114
|
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
124
115
|
istek = await self.httpx.get(url)
|
|
125
|
-
secici =
|
|
116
|
+
secici = HTMLHelper(istek.text)
|
|
126
117
|
html_text = istek.text
|
|
127
118
|
|
|
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()
|
|
119
|
+
raw_title = secici.select_text("h1") or secici.select_text(".titles h1") or secici.select_attr("meta[property='og:title']", "content") or ""
|
|
120
|
+
title = HTMLHelper(raw_title).regex_replace(r"(?i)\s*izle.*$", "", flags=0).strip()
|
|
136
121
|
|
|
137
|
-
|
|
138
|
-
poster = poster_el.attrs.get("src") if poster_el else None
|
|
122
|
+
poster = secici.select_attr("div.poster img", "src")
|
|
139
123
|
|
|
140
|
-
|
|
141
|
-
description = desc_el.text(strip=True) if desc_el else None
|
|
124
|
+
description = secici.select_text("div.wp-content p")
|
|
142
125
|
|
|
143
|
-
|
|
144
|
-
year = None
|
|
145
|
-
if year_el:
|
|
146
|
-
year_text = year_el.text(strip=True)
|
|
147
|
-
year_match = re.search(r"\d{4}", year_text)
|
|
148
|
-
year = year_match.group() if year_match else None
|
|
126
|
+
year_text = secici.select_text("div.extra span.C a")
|
|
127
|
+
year = secici.regex_first(r"\d{4}", year_text) if year_text else None
|
|
149
128
|
|
|
150
|
-
tags = [a.text(strip=True) for a in secici.
|
|
129
|
+
tags = [a.text(strip=True) for a in secici.select("div.sgeneros a") if a.text(strip=True)]
|
|
151
130
|
|
|
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
|
|
131
|
+
duration_text = secici.select_text("span.runtime")
|
|
132
|
+
duration = int(secici.regex_first(r"\d+", duration_text)) if duration_text and secici.regex_first(r"\d+", duration_text) else None
|
|
158
133
|
|
|
159
|
-
actors = [span.text(strip=True) for span in secici.
|
|
134
|
+
actors = [span.text(strip=True) for span in secici.select("span.valor a > span") if span.text(strip=True)]
|
|
160
135
|
|
|
161
|
-
|
|
162
|
-
|
|
136
|
+
trailer = None
|
|
137
|
+
if trailer_id := secici.regex_first(r'embed/([^?]*)\?rel', html_text):
|
|
138
|
+
trailer = f"https://www.youtube.com/embed/{trailer_id}"
|
|
163
139
|
|
|
164
140
|
# Dizi mi film mi kontrol et
|
|
165
141
|
is_series = "/dizi/" in url
|
|
166
142
|
|
|
167
143
|
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
|
|
144
|
+
year_elem = secici.select_text("a[href*='/yil/']")
|
|
145
|
+
if year_elem:
|
|
146
|
+
year = secici.regex_first(r"\d{4}", year_elem) or year
|
|
173
147
|
|
|
174
148
|
# Duration from info section
|
|
175
|
-
for span in secici.
|
|
149
|
+
for span in secici.select("div#info span"):
|
|
176
150
|
span_text = span.text(strip=True) if span.text() else ""
|
|
177
151
|
if "Dakika" in span_text:
|
|
178
|
-
|
|
179
|
-
duration = int(dur_match.group()) if dur_match else duration
|
|
152
|
+
duration = secici.regex_first(r"\d+", span_text) and int(secici.regex_first(r"\d+", span_text))
|
|
180
153
|
break
|
|
181
154
|
|
|
182
155
|
episodes = []
|
|
183
|
-
for ep_item in secici.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
ep_name = ep_title_el.text(strip=True) if ep_title_el else None
|
|
156
|
+
for ep_item in secici.select("div#episodes ul.episodios li"):
|
|
157
|
+
ep_href = secici.select_attr("h4.episodiotitle a", "href", ep_item)
|
|
158
|
+
ep_name = secici.select_text("h4.episodiotitle a", ep_item)
|
|
187
159
|
|
|
188
160
|
if not ep_href or not ep_name:
|
|
189
161
|
continue
|
|
190
162
|
|
|
191
163
|
ep_detail = ep_name
|
|
192
|
-
|
|
193
|
-
|
|
164
|
+
ep_season = secici.regex_first(r"(\d+)\.\s*Sezon", ep_detail) or 1
|
|
165
|
+
ep_episode = secici.regex_first(r"Sezon\s+(\d+)\.\s*Bölüm", ep_detail)
|
|
194
166
|
|
|
195
|
-
ep_season = int(
|
|
196
|
-
ep_episode = int(
|
|
167
|
+
ep_season = int(ep_season) if isinstance(ep_season, str) and ep_season.isdigit() else 1
|
|
168
|
+
ep_episode = int(ep_episode) if isinstance(ep_episode, str) and ep_episode.isdigit() else None
|
|
197
169
|
|
|
198
170
|
episodes.append(Episode(
|
|
199
171
|
season = ep_season,
|
|
@@ -201,7 +173,6 @@ class SetFilmIzle(PluginBase):
|
|
|
201
173
|
title = ep_name,
|
|
202
174
|
url = self.fix_url(ep_href)
|
|
203
175
|
))
|
|
204
|
-
|
|
205
176
|
return SeriesInfo(
|
|
206
177
|
url = url,
|
|
207
178
|
poster = self.fix_url(poster) if poster else None,
|
|
@@ -227,9 +198,9 @@ class SetFilmIzle(PluginBase):
|
|
|
227
198
|
|
|
228
199
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
229
200
|
istek = await self.httpx.get(url)
|
|
230
|
-
secici =
|
|
201
|
+
secici = HTMLHelper(istek.text)
|
|
231
202
|
|
|
232
|
-
nonce = secici.
|
|
203
|
+
nonce = secici.select_attr("div#playex", "data-nonce") or ""
|
|
233
204
|
|
|
234
205
|
# partKey to dil label mapping
|
|
235
206
|
part_key_labels = {
|
|
@@ -279,7 +250,7 @@ class SetFilmIzle(PluginBase):
|
|
|
279
250
|
|
|
280
251
|
return await self.extract(iframe_url, prefix=label if label else None)
|
|
281
252
|
|
|
282
|
-
for player in secici.
|
|
253
|
+
for player in secici.select("nav.player a"):
|
|
283
254
|
tasks.append(fetch_and_extract(player))
|
|
284
255
|
|
|
285
256
|
results = await asyncio.gather(*tasks)
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult
|
|
4
|
-
|
|
5
|
-
import re, asyncio
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
|
|
4
|
+
import asyncio
|
|
6
5
|
|
|
7
6
|
class SezonlukDizi(PluginBase):
|
|
8
7
|
name = "SezonlukDizi"
|
|
@@ -41,26 +40,24 @@ class SezonlukDizi(PluginBase):
|
|
|
41
40
|
|
|
42
41
|
async def _get_asp_data(self) -> dict:
|
|
43
42
|
js_req = await self.httpx.get(f"{self.main_url}/js/site.min.js")
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
js = HTMLHelper(js_req.text)
|
|
44
|
+
alt = js.regex_first(r"dataAlternatif(.*?)\.asp")
|
|
45
|
+
emb = js.regex_first(r"dataEmbed(.*?)\.asp")
|
|
46
46
|
|
|
47
47
|
return {
|
|
48
|
-
"alternatif":
|
|
49
|
-
"embed":
|
|
48
|
+
"alternatif": alt or "",
|
|
49
|
+
"embed": emb or ""
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
53
53
|
istek = await self.httpx.get(f"{url}{page}")
|
|
54
|
-
secici =
|
|
54
|
+
secici = HTMLHelper(istek.text)
|
|
55
55
|
|
|
56
56
|
results = []
|
|
57
|
-
for veri in secici.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
title = desc_el.text(strip=True) if desc_el else None
|
|
62
|
-
href = veri.attrs.get("href")
|
|
63
|
-
poster = img_el.attrs.get("data-src") if img_el else None
|
|
57
|
+
for veri in secici.select("div.afis a"):
|
|
58
|
+
title = secici.select_text("div.description", veri)
|
|
59
|
+
href = secici.select_attr("a", "href", veri)
|
|
60
|
+
poster = secici.select_attr("img", "data-src", veri)
|
|
64
61
|
|
|
65
62
|
if title and href:
|
|
66
63
|
results.append(MainPageResult(
|
|
@@ -74,16 +71,13 @@ class SezonlukDizi(PluginBase):
|
|
|
74
71
|
|
|
75
72
|
async def search(self, query: str) -> list[SearchResult]:
|
|
76
73
|
istek = await self.httpx.get(f"{self.main_url}/diziler.asp?adi={query}")
|
|
77
|
-
secici =
|
|
74
|
+
secici = HTMLHelper(istek.text)
|
|
78
75
|
|
|
79
76
|
results = []
|
|
80
|
-
for afis in secici.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
title = desc_el.text(strip=True) if desc_el else None
|
|
85
|
-
href = afis.attrs.get("href")
|
|
86
|
-
poster = img_el.attrs.get("data-src") if img_el else None
|
|
77
|
+
for afis in secici.select("div.afis a"):
|
|
78
|
+
title = secici.select_text("div.description", veri)
|
|
79
|
+
href = secici.select_attr("a", "href", veri)
|
|
80
|
+
poster = secici.select_attr("img", "data-src", veri)
|
|
87
81
|
|
|
88
82
|
if title and href:
|
|
89
83
|
results.append(SearchResult(
|
|
@@ -96,67 +90,56 @@ class SezonlukDizi(PluginBase):
|
|
|
96
90
|
|
|
97
91
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
98
92
|
istek = await self.httpx.get(url)
|
|
99
|
-
secici =
|
|
93
|
+
secici = HTMLHelper(istek.text)
|
|
100
94
|
|
|
101
|
-
|
|
102
|
-
title = title_el.text(strip=True) if title_el else ""
|
|
95
|
+
title = secici.select_text("div.header") or ""
|
|
103
96
|
|
|
104
|
-
|
|
105
|
-
poster = poster_el.attrs.get("data-src", "").strip() if poster_el else ""
|
|
97
|
+
poster = secici.select_attr("div.image img", "data-src") or ""
|
|
106
98
|
|
|
107
99
|
# year: re_first yerine re.search
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
year_match = re.search(r"(\d{4})", year_text)
|
|
111
|
-
year = year_match.group(1) if year_match else None
|
|
100
|
+
year_text = secici.select_text("div.extra span") or ""
|
|
101
|
+
year = secici.regex_first(r"(\d{4})", year_text)
|
|
112
102
|
|
|
113
103
|
# xpath normalized-space yerine doğrudan ID ile element bulup text al
|
|
114
|
-
|
|
115
|
-
description = desc_el.text(strip=True) if desc_el else ""
|
|
104
|
+
description = secici.select_text("span#tartismayorum-konu") or ""
|
|
116
105
|
|
|
117
|
-
tags = [a.text(strip=True) for a in secici.
|
|
106
|
+
tags = [a.text(strip=True) for a in secici.select("div.labels a[href*='tur']") if a.text(strip=True)]
|
|
118
107
|
|
|
119
|
-
# rating:
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
rating_match = re.search(r"[\d.,]+", rating_text)
|
|
123
|
-
rating = rating_match.group() if rating_match else None
|
|
108
|
+
# rating: regex ile çıkar
|
|
109
|
+
rating_text = secici.select_text("div.dizipuani a div") or ""
|
|
110
|
+
rating = secici.regex_first(r"[\d.,]+", rating_text)
|
|
124
111
|
|
|
125
112
|
actors = []
|
|
126
113
|
|
|
127
114
|
actors_istek = await self.httpx.get(f"{self.main_url}/oyuncular/{url.split('/')[-1]}")
|
|
128
|
-
actors_secici =
|
|
129
|
-
for actor in actors_secici.
|
|
130
|
-
|
|
131
|
-
if
|
|
132
|
-
actors.append(
|
|
115
|
+
actors_secici = HTMLHelper(actors_istek.text)
|
|
116
|
+
for actor in actors_secici.select("div.doubling div.ui"):
|
|
117
|
+
header_text = actors_secici.select_text("div.header", actor)
|
|
118
|
+
if header_text:
|
|
119
|
+
actors.append(header_text)
|
|
133
120
|
|
|
134
121
|
episodes_istek = await self.httpx.get(f"{self.main_url}/bolumler/{url.split('/')[-1]}")
|
|
135
|
-
episodes_secici =
|
|
122
|
+
episodes_secici = HTMLHelper(episodes_istek.text)
|
|
136
123
|
episodes = []
|
|
137
124
|
|
|
138
|
-
for sezon in episodes_secici.
|
|
139
|
-
for bolum in
|
|
125
|
+
for sezon in episodes_secici.select("table.unstackable"):
|
|
126
|
+
for bolum in episodes_secici.select("tbody tr", sezon):
|
|
140
127
|
# td:nth-of-type selectolax'ta desteklenmiyor, alternatif yol: tüm td'leri alıp indexle
|
|
141
|
-
tds =
|
|
128
|
+
tds = episodes_secici.select("td", bolum)
|
|
142
129
|
if len(tds) < 4:
|
|
143
130
|
continue
|
|
144
131
|
|
|
145
132
|
# 4. td'den isim ve href
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
ep_href = ep_name_el.attrs.get("href") if ep_name_el else None
|
|
133
|
+
ep_name = episodes_secici.select_text("a", tds[3])
|
|
134
|
+
ep_href = episodes_secici.select_attr("a", "href", tds[3])
|
|
149
135
|
|
|
150
|
-
# 3. td'den episode (re_first yerine
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
ep_episode_match = re.search(r"(\d+)", ep_episode_text)
|
|
154
|
-
ep_episode = ep_episode_match.group(1) if ep_episode_match else None
|
|
136
|
+
# 3. td'den episode (re_first yerine regex)
|
|
137
|
+
ep_episode_text = episodes_secici.select_text("a", tds[2]) or ""
|
|
138
|
+
ep_episode = episodes_secici.regex_first(r"(\d+)", ep_episode_text)
|
|
155
139
|
|
|
156
|
-
# 2. td'den season (re_first yerine
|
|
140
|
+
# 2. td'den season (re_first yerine regex)
|
|
157
141
|
ep_season_text = tds[1].text(strip=True) if tds[1] else ""
|
|
158
|
-
|
|
159
|
-
ep_season = ep_season_match.group(1) if ep_season_match else None
|
|
142
|
+
ep_season = secici.regex_first(r"(\d+)", ep_season_text)
|
|
160
143
|
|
|
161
144
|
if ep_name and ep_href:
|
|
162
145
|
episode = Episode(
|
|
@@ -181,10 +164,10 @@ class SezonlukDizi(PluginBase):
|
|
|
181
164
|
|
|
182
165
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
183
166
|
istek = await self.httpx.get(url)
|
|
184
|
-
secici =
|
|
167
|
+
secici = HTMLHelper(istek.text)
|
|
185
168
|
asp_data = await self._get_asp_data()
|
|
186
169
|
|
|
187
|
-
bid = secici.
|
|
170
|
+
bid = secici.select_attr("div#dilsec", "data-id")
|
|
188
171
|
if not bid:
|
|
189
172
|
return []
|
|
190
173
|
|
|
@@ -199,9 +182,8 @@ class SezonlukDizi(PluginBase):
|
|
|
199
182
|
headers = {"X-Requested-With": "XMLHttpRequest"},
|
|
200
183
|
data = {"id": str(veri.get("id"))}
|
|
201
184
|
)
|
|
202
|
-
embed_secici =
|
|
203
|
-
|
|
204
|
-
iframe_src = iframe_el.attrs.get("src") if iframe_el else None
|
|
185
|
+
embed_secici = HTMLHelper(embed_resp.text)
|
|
186
|
+
iframe_src = embed_secici.select_attr("iframe", "src")
|
|
205
187
|
|
|
206
188
|
if iframe_src:
|
|
207
189
|
if "link.asp" in iframe_src:
|