KekikStream 2.4.2__py3-none-any.whl → 2.4.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/Extractor/ExtractorBase.py +3 -2
- KekikStream/Core/HTMLHelper.py +134 -40
- KekikStream/Core/Plugin/PluginBase.py +3 -2
- KekikStream/Extractors/CloseLoad.py +30 -54
- KekikStream/Extractors/ContentX.py +27 -72
- KekikStream/Extractors/DonilasPlay.py +33 -77
- KekikStream/Extractors/DzenRu.py +10 -24
- KekikStream/Extractors/ExPlay.py +20 -38
- KekikStream/Extractors/Filemoon.py +19 -45
- KekikStream/Extractors/HDMomPlayer.py +24 -56
- KekikStream/Extractors/HDPlayerSystem.py +13 -31
- KekikStream/Extractors/HotStream.py +14 -32
- KekikStream/Extractors/JFVid.py +3 -24
- KekikStream/Extractors/JetTv.py +21 -34
- KekikStream/Extractors/MailRu.py +11 -29
- KekikStream/Extractors/MixPlayHD.py +15 -28
- KekikStream/Extractors/MixTiger.py +17 -40
- KekikStream/Extractors/MolyStream.py +17 -21
- KekikStream/Extractors/Odnoklassniki.py +28 -104
- KekikStream/Extractors/PeaceMakerst.py +18 -45
- KekikStream/Extractors/PixelDrain.py +8 -16
- KekikStream/Extractors/PlayerFilmIzle.py +22 -41
- KekikStream/Extractors/RapidVid.py +21 -35
- KekikStream/Extractors/SetPlay.py +18 -43
- KekikStream/Extractors/SibNet.py +7 -17
- KekikStream/Extractors/Sobreatsesuyp.py +23 -45
- KekikStream/Extractors/TRsTX.py +23 -53
- KekikStream/Extractors/TurboImgz.py +7 -14
- KekikStream/Extractors/VCTPlay.py +10 -28
- KekikStream/Extractors/VidHide.py +10 -31
- KekikStream/Extractors/VidMoly.py +65 -99
- KekikStream/Extractors/VidMoxy.py +16 -27
- KekikStream/Extractors/VidPapi.py +24 -54
- KekikStream/Extractors/VideoSeyred.py +19 -40
- KekikStream/Extractors/Videostr.py +42 -99
- KekikStream/Extractors/Vidoza.py +8 -15
- KekikStream/Extractors/YildizKisaFilm.py +13 -31
- KekikStream/Plugins/BelgeselX.py +63 -69
- KekikStream/Plugins/DiziBox.py +16 -36
- KekikStream/Plugins/DiziMom.py +37 -129
- KekikStream/Plugins/DiziPal.py +71 -164
- KekikStream/Plugins/DiziYou.py +44 -152
- KekikStream/Plugins/Dizilla.py +18 -44
- KekikStream/Plugins/FilmBip.py +10 -24
- KekikStream/Plugins/FilmEkseni.py +12 -32
- KekikStream/Plugins/FilmMakinesi.py +24 -77
- KekikStream/Plugins/FilmModu.py +11 -18
- KekikStream/Plugins/Filmatek.py +13 -39
- KekikStream/Plugins/Full4kizle.py +33 -133
- KekikStream/Plugins/FullHDFilm.py +23 -93
- KekikStream/Plugins/FullHDFilmizlesene.py +10 -29
- KekikStream/Plugins/HDFilmCehennemi.py +27 -66
- KekikStream/Plugins/JetFilmizle.py +19 -20
- KekikStream/Plugins/KultFilmler.py +16 -50
- KekikStream/Plugins/RecTV.py +47 -85
- KekikStream/Plugins/SelcukFlix.py +29 -47
- KekikStream/Plugins/SetFilmIzle.py +28 -84
- KekikStream/Plugins/SezonlukDizi.py +27 -59
- KekikStream/Plugins/Sinefy.py +37 -100
- KekikStream/Plugins/SinemaCX.py +12 -18
- KekikStream/Plugins/Sinezy.py +11 -12
- KekikStream/Plugins/SuperFilmGeldi.py +8 -13
- KekikStream/Plugins/UgurFilm.py +14 -14
- KekikStream/Plugins/Watch32.py +42 -74
- KekikStream/Plugins/YabanciDizi.py +33 -87
- {kekikstream-2.4.2.dist-info → kekikstream-2.4.4.dist-info}/METADATA +1 -1
- kekikstream-2.4.4.dist-info/RECORD +93 -0
- kekikstream-2.4.2.dist-info/RECORD +0 -93
- {kekikstream-2.4.2.dist-info → kekikstream-2.4.4.dist-info}/WHEEL +0 -0
- {kekikstream-2.4.2.dist-info → kekikstream-2.4.4.dist-info}/entry_points.txt +0 -0
- {kekikstream-2.4.2.dist-info → kekikstream-2.4.4.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-2.4.2.dist-info → kekikstream-2.4.4.dist-info}/top_level.txt +0 -0
KekikStream/Plugins/RecTV.py
CHANGED
|
@@ -65,94 +65,56 @@ class RecTV(PluginBase):
|
|
|
65
65
|
for veri in tum_veri
|
|
66
66
|
]
|
|
67
67
|
|
|
68
|
-
async def load_item(self, url: str) -> MovieInfo:
|
|
68
|
+
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
69
69
|
self.httpx.headers.update({"user-agent": "okhttp/4.12.0"})
|
|
70
70
|
veri = loads(url)
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
m = int(HTMLHelper(duration_raw).regex_first(r"(\d+)min") or 0)
|
|
119
|
-
duration = h * 60 + m
|
|
120
|
-
except: pass
|
|
121
|
-
|
|
122
|
-
return SeriesInfo(
|
|
123
|
-
url = url,
|
|
124
|
-
poster = self.fix_url(veri.get("image")),
|
|
125
|
-
title = veri.get("title"),
|
|
126
|
-
description = veri.get("description"),
|
|
127
|
-
tags = [genre.get("title") for genre in veri.get("genres")] if veri.get("genres") else [],
|
|
128
|
-
rating = str(veri.get("imdb") or veri.get("rating") or ""),
|
|
129
|
-
year = str(veri.get("year") or ""),
|
|
130
|
-
actors = [],
|
|
131
|
-
duration = duration,
|
|
132
|
-
episodes = episodes
|
|
133
|
-
)
|
|
134
|
-
case _:
|
|
135
|
-
# Süreyi dakikaya çevir
|
|
136
|
-
duration_raw = veri.get("duration")
|
|
137
|
-
duration = None
|
|
138
|
-
if duration_raw:
|
|
139
|
-
try:
|
|
140
|
-
h = int(HTMLHelper(duration_raw).regex_first(r"(\d+)h") or 0)
|
|
141
|
-
m = int(HTMLHelper(duration_raw).regex_first(r"(\d+)min") or 0)
|
|
142
|
-
duration = h * 60 + m
|
|
143
|
-
except: pass
|
|
144
|
-
|
|
145
|
-
return MovieInfo(
|
|
146
|
-
url = url,
|
|
147
|
-
poster = self.fix_url(veri.get("image")),
|
|
148
|
-
title = veri.get("title"),
|
|
149
|
-
description = veri.get("description"),
|
|
150
|
-
tags = [genre.get("title") for genre in veri.get("genres")] if veri.get("genres") else [],
|
|
151
|
-
rating = str(veri.get("imdb") or veri.get("rating") or ""),
|
|
152
|
-
year = str(veri.get("year") or ""),
|
|
153
|
-
actors = [],
|
|
154
|
-
duration = duration
|
|
155
|
-
)
|
|
72
|
+
# Süreyi dakikaya çevir (Örn: "1h 59min")
|
|
73
|
+
duration_raw = veri.get("duration")
|
|
74
|
+
duration = None
|
|
75
|
+
if duration_raw:
|
|
76
|
+
try:
|
|
77
|
+
h = int(HTMLHelper(duration_raw).regex_first(r"(\d+)h") or 0)
|
|
78
|
+
m = int(HTMLHelper(duration_raw).regex_first(r"(\d+)min") or 0)
|
|
79
|
+
duration = h * 60 + m
|
|
80
|
+
except: pass
|
|
81
|
+
|
|
82
|
+
common_info = {
|
|
83
|
+
"url" : url,
|
|
84
|
+
"poster" : self.fix_url(veri.get("image")),
|
|
85
|
+
"title" : veri.get("title"),
|
|
86
|
+
"description" : veri.get("description"),
|
|
87
|
+
"tags" : [genre.get("title") for genre in veri.get("genres")] if veri.get("genres") else [],
|
|
88
|
+
"rating" : str(veri.get("imdb") or veri.get("rating") or ""),
|
|
89
|
+
"year" : str(veri.get("year") or ""),
|
|
90
|
+
"duration" : duration
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if veri.get("type") == "serie":
|
|
94
|
+
dizi_istek = await self.httpx.get(f"{self.main_url}/api/season/by/serie/{veri.get('id')}/{self.sw_key}/")
|
|
95
|
+
dizi_veri = dizi_istek.json()
|
|
96
|
+
|
|
97
|
+
episodes = []
|
|
98
|
+
for season in dizi_veri:
|
|
99
|
+
s_title = season.get("title", "").strip()
|
|
100
|
+
s, _ = HTMLHelper.extract_season_episode(s_title)
|
|
101
|
+
for ep in season.get("episodes"):
|
|
102
|
+
e_title = ep.get("title", "").strip()
|
|
103
|
+
_, e = HTMLHelper.extract_season_episode(e_title)
|
|
104
|
+
for source in ep.get("sources"):
|
|
105
|
+
tag = ""
|
|
106
|
+
clean_s = s_title
|
|
107
|
+
if "dublaj" in s_title.lower():
|
|
108
|
+
tag = " (Dublaj)"; clean_s = re.sub(r"\s*dublaj\s*", "", s_title, flags=re.I).strip()
|
|
109
|
+
elif "altyaz" in s_title.lower():
|
|
110
|
+
tag = " (Altyazı)"; clean_s = re.sub(r"\s*altyaz[ıi]\s*", "", s_title, flags=re.I).strip()
|
|
111
|
+
|
|
112
|
+
ep_data = {"url": self.fix_url(source.get("url")), "title": f"{veri.get('title')} | {s_title} {e_title} - {source.get('title')}", "is_episode": True}
|
|
113
|
+
episodes.append(Episode(season=s or 1, episode=e or 1, title=f"{clean_s} {e_title}{tag} - {source.get('title')}", url=dumps(ep_data)))
|
|
114
|
+
|
|
115
|
+
return SeriesInfo(**common_info, episodes=episodes, actors=[])
|
|
116
|
+
|
|
117
|
+
return MovieInfo(**common_info, actors=[])
|
|
156
118
|
|
|
157
119
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
158
120
|
try:
|
|
@@ -187,54 +187,55 @@ class SelcukFlix(PluginBase):
|
|
|
187
187
|
|
|
188
188
|
next_data_text = sel.select_text("script#__NEXT_DATA__")
|
|
189
189
|
if not next_data_text:
|
|
190
|
-
return SeriesInfo(url=url, title=sel.select_text("h1") or "Bilinmeyen")
|
|
190
|
+
return SeriesInfo(url=url, title=self.clean_title(sel.select_text("h1")) or "Bilinmeyen")
|
|
191
191
|
|
|
192
192
|
try:
|
|
193
193
|
next_data = json.loads(next_data_text)
|
|
194
194
|
secure_data_raw = next_data["props"]["pageProps"].get("secureData")
|
|
195
195
|
if not secure_data_raw:
|
|
196
|
-
|
|
196
|
+
return SeriesInfo(url=url, title=self.clean_title(sel.select_text("h1")) or "Bilinmeyen")
|
|
197
197
|
|
|
198
198
|
# Clean possible quotes from string before decoding
|
|
199
199
|
if isinstance(secure_data_raw, str):
|
|
200
200
|
secure_data_raw = secure_data_raw.strip('"')
|
|
201
201
|
|
|
202
|
-
|
|
203
|
-
content_details = json.loads(
|
|
204
|
-
|
|
205
|
-
# Sometimes content_details might be a string (double encoded)
|
|
206
|
-
if isinstance(content_details, str):
|
|
207
|
-
content_details = json.loads(content_details)
|
|
202
|
+
content_details = json.loads(base64.b64decode(secure_data_raw).decode('utf-8'))
|
|
203
|
+
if isinstance(content_details, str): content_details = json.loads(content_details)
|
|
208
204
|
|
|
209
|
-
print(f"DEBUG: type(content_details)={type(content_details)}")
|
|
210
205
|
item = content_details.get("contentItem", {})
|
|
211
|
-
print(f"DEBUG: type(item)={type(item)}")
|
|
212
206
|
related_results = content_details.get("RelatedResults", {})
|
|
213
207
|
|
|
214
|
-
title
|
|
215
|
-
poster
|
|
216
|
-
description
|
|
217
|
-
rating
|
|
218
|
-
year
|
|
219
|
-
duration
|
|
208
|
+
title = self.clean_title(item.get("original_title") or item.get("culture_title") or item.get("originalTitle") or "")
|
|
209
|
+
poster = self.clean_image_url(item.get("poster_url") or item.get("posterUrl") or item.get("face_url"))
|
|
210
|
+
description = item.get("description") or item.get("used_description")
|
|
211
|
+
rating = str(item.get("imdb_point") or item.get("imdbPoint") or "")
|
|
212
|
+
year = str(item.get("release_year") or item.get("releaseYear") or "")
|
|
213
|
+
duration = item.get("total_minutes") or item.get("totalMinutes")
|
|
220
214
|
|
|
221
215
|
tags = []
|
|
222
216
|
tags_raw = item.get("category_names") or item.get("categoryNames") or item.get("categories")
|
|
223
217
|
if isinstance(tags_raw, str):
|
|
224
|
-
tags = [t.strip() for t in tags_raw.split(",")]
|
|
218
|
+
tags = [t.strip() for t in tags_raw.split(",") if t.strip()]
|
|
225
219
|
elif isinstance(tags_raw, list):
|
|
226
220
|
tags = [c.get("title") if isinstance(c, dict) else str(c) for c in tags_raw]
|
|
227
221
|
|
|
228
222
|
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(",")]
|
|
232
|
-
|
|
233
|
-
# Casts from RelatedResults
|
|
234
223
|
casts_data = related_results.get("getSerieCastsById") or related_results.get("getMovieCastsById")
|
|
235
224
|
if casts_data and isinstance(casts_data, dict) and casts_data.get("result"):
|
|
236
225
|
actors = [cast.get("name") for cast in casts_data["result"] if cast.get("name")]
|
|
237
226
|
|
|
227
|
+
common_info = {
|
|
228
|
+
"url" : url,
|
|
229
|
+
"poster" : poster,
|
|
230
|
+
"title" : title or "Bilinmiyor",
|
|
231
|
+
"description" : description,
|
|
232
|
+
"tags" : tags,
|
|
233
|
+
"rating" : rating,
|
|
234
|
+
"year" : year,
|
|
235
|
+
"actors" : actors,
|
|
236
|
+
"duration" : duration
|
|
237
|
+
}
|
|
238
|
+
|
|
238
239
|
series_data = related_results.get("getSerieSeasonAndEpisodes")
|
|
239
240
|
if series_data and isinstance(series_data, dict) and series_data.get("result"):
|
|
240
241
|
episodes = []
|
|
@@ -249,31 +250,12 @@ class SelcukFlix(PluginBase):
|
|
|
249
250
|
title = ep.get("ep_text") or ep.get("epText") or "",
|
|
250
251
|
url = self.fix_url(ep_slug)
|
|
251
252
|
))
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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
|
-
)
|
|
253
|
+
return SeriesInfo(**common_info, episodes=episodes)
|
|
254
|
+
|
|
255
|
+
return MovieInfo(**common_info)
|
|
256
|
+
|
|
257
|
+
except Exception:
|
|
258
|
+
return SeriesInfo(url=url, title=self.clean_title(sel.select_text("h1")) or "Bilinmeyen")
|
|
277
259
|
|
|
278
260
|
except Exception:
|
|
279
261
|
return SeriesInfo(url=url, title=self.clean_title(sel.select_text("h1")) or "Bilinmeyen")
|
|
@@ -125,95 +125,39 @@ class SetFilmIzle(PluginBase):
|
|
|
125
125
|
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
126
126
|
istek = self.cloudscraper.get(url)
|
|
127
127
|
secici = HTMLHelper(istek.text)
|
|
128
|
-
html_text = istek.text
|
|
129
|
-
|
|
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()
|
|
132
|
-
|
|
133
|
-
poster = secici.select_attr("div.poster img", "src")
|
|
134
128
|
|
|
129
|
+
title = self.clean_title(secici.select_text("h1") or secici.select_text(".titles h1") or secici.select_attr("meta[property='og:title']", "content"))
|
|
130
|
+
poster = secici.select_poster("div.poster img")
|
|
135
131
|
description = secici.select_text("div.wp-content p")
|
|
132
|
+
rating = secici.select_text("b#repimdb strong") or secici.regex_first(r"([\d.]+)", secici.select_text("div.imdb"))
|
|
133
|
+
year = secici.extract_year("div.extra span.valor")
|
|
134
|
+
tags = secici.select_texts("div.sgeneros a")
|
|
135
|
+
duration = int(secici.regex_first(r"(\d+)", secici.select_text("span.runtime")) or 0)
|
|
136
|
+
actors = secici.select_texts("span.valor a[href*='/oyuncu/']")
|
|
137
|
+
|
|
138
|
+
common_info = {
|
|
139
|
+
"url" : url,
|
|
140
|
+
"poster" : self.fix_url(poster) if poster else None,
|
|
141
|
+
"title" : title or "Bilinmiyor",
|
|
142
|
+
"description" : description,
|
|
143
|
+
"tags" : tags,
|
|
144
|
+
"rating" : rating,
|
|
145
|
+
"year" : str(year) if year else None,
|
|
146
|
+
"duration" : duration,
|
|
147
|
+
"actors" : actors
|
|
148
|
+
}
|
|
136
149
|
|
|
137
|
-
|
|
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)
|
|
143
|
-
|
|
144
|
-
tags = [a.text(strip=True) for a in secici.select("div.sgeneros a") if a.text(strip=True)]
|
|
145
|
-
|
|
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
|
|
148
|
-
|
|
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>')
|
|
152
|
-
|
|
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}"
|
|
156
|
-
|
|
157
|
-
# Dizi mi film mi kontrol et
|
|
158
|
-
is_series = "/dizi/" in url
|
|
159
|
-
|
|
160
|
-
if is_series:
|
|
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
|
|
164
|
-
|
|
165
|
-
# Duration from info section
|
|
166
|
-
for span in secici.select("div#info span"):
|
|
167
|
-
span_text = span.text(strip=True) if span.text() else ""
|
|
168
|
-
if "Dakika" in span_text:
|
|
169
|
-
duration = secici.regex_first(r"\d+", span_text) and int(secici.regex_first(r"\d+", span_text))
|
|
170
|
-
break
|
|
171
|
-
|
|
150
|
+
if "/dizi/" in url:
|
|
172
151
|
episodes = []
|
|
173
152
|
for ep_item in secici.select("div#episodes ul.episodios li"):
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
ep_episode = secici.regex_first(r"Sezon\s+(\d+)\.\s*Bölüm", ep_detail)
|
|
183
|
-
|
|
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
|
|
186
|
-
|
|
187
|
-
episodes.append(Episode(
|
|
188
|
-
season = ep_season,
|
|
189
|
-
episode = ep_episode,
|
|
190
|
-
title = ep_name,
|
|
191
|
-
url = self.fix_url(ep_href)
|
|
192
|
-
))
|
|
193
|
-
return SeriesInfo(
|
|
194
|
-
url = url,
|
|
195
|
-
poster = self.fix_url(poster) if poster else None,
|
|
196
|
-
title = title,
|
|
197
|
-
description = description,
|
|
198
|
-
tags = tags,
|
|
199
|
-
rating = rating,
|
|
200
|
-
year = year,
|
|
201
|
-
duration = duration,
|
|
202
|
-
actors = actors,
|
|
203
|
-
episodes = episodes
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
return MovieInfo(
|
|
207
|
-
url = url,
|
|
208
|
-
poster = self.fix_url(poster) if poster else None,
|
|
209
|
-
title = title,
|
|
210
|
-
description = description,
|
|
211
|
-
tags = tags,
|
|
212
|
-
rating = rating,
|
|
213
|
-
year = year,
|
|
214
|
-
duration = duration,
|
|
215
|
-
actors = actors
|
|
216
|
-
)
|
|
153
|
+
href = secici.select_attr("h4.episodiotitle a", "href", ep_item)
|
|
154
|
+
name = secici.select_direct_text("h4.episodiotitle a", ep_item)
|
|
155
|
+
if href and name:
|
|
156
|
+
s, e = secici.extract_season_episode(name)
|
|
157
|
+
episodes.append(Episode(season=s or 1, episode=e or 1, title=name, url=self.fix_url(href)))
|
|
158
|
+
return SeriesInfo(**common_info, episodes=episodes)
|
|
159
|
+
|
|
160
|
+
return MovieInfo(**common_info)
|
|
217
161
|
|
|
218
162
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
219
163
|
istek = await self.httpx.get(url)
|
|
@@ -70,7 +70,7 @@ class SezonlukDizi(PluginBase):
|
|
|
70
70
|
return results
|
|
71
71
|
|
|
72
72
|
async def search(self, query: str) -> list[SearchResult]:
|
|
73
|
-
istek = await self.httpx.get(f"{self.main_url}/diziler.asp?
|
|
73
|
+
istek = await self.httpx.get(f"{self.main_url}/diziler.asp?q={query}")
|
|
74
74
|
secici = HTMLHelper(istek.text)
|
|
75
75
|
|
|
76
76
|
results = []
|
|
@@ -92,63 +92,31 @@ class SezonlukDizi(PluginBase):
|
|
|
92
92
|
istek = await self.httpx.get(url)
|
|
93
93
|
secici = HTMLHelper(istek.text)
|
|
94
94
|
|
|
95
|
-
title
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
#
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
episodes_istek = await self.httpx.get(f"{self.main_url}/bolumler/{url.split('/')[-1]}")
|
|
122
|
-
episodes_secici = HTMLHelper(episodes_istek.text)
|
|
123
|
-
episodes = []
|
|
124
|
-
|
|
125
|
-
for sezon in episodes_secici.select("table.unstackable"):
|
|
126
|
-
for bolum in episodes_secici.select("tbody tr", sezon):
|
|
127
|
-
# td:nth-of-type selectolax'ta desteklenmiyor, alternatif yol: tüm td'leri alıp indexle
|
|
128
|
-
tds = episodes_secici.select("td", bolum)
|
|
129
|
-
if len(tds) < 4:
|
|
130
|
-
continue
|
|
131
|
-
|
|
132
|
-
# 4. td'den isim ve href
|
|
133
|
-
ep_name = episodes_secici.select_text("a", tds[3])
|
|
134
|
-
ep_href = episodes_secici.select_attr("a", "href", tds[3])
|
|
135
|
-
|
|
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)
|
|
139
|
-
|
|
140
|
-
# 2. td'den season (re_first yerine regex)
|
|
141
|
-
ep_season_text = tds[1].text(strip=True) if tds[1] else ""
|
|
142
|
-
ep_season = secici.regex_first(r"(\d+)", ep_season_text)
|
|
143
|
-
|
|
144
|
-
if ep_name and ep_href:
|
|
145
|
-
episode = Episode(
|
|
146
|
-
season = ep_season,
|
|
147
|
-
episode = ep_episode,
|
|
148
|
-
title = ep_name,
|
|
149
|
-
url = self.fix_url(ep_href),
|
|
150
|
-
)
|
|
151
|
-
episodes.append(episode)
|
|
95
|
+
title = secici.select_text("div.header") or ""
|
|
96
|
+
poster = secici.select_poster("div.image img")
|
|
97
|
+
year = secici.extract_year("div.extra span")
|
|
98
|
+
description = secici.select_text("span#tartismayorum-konu")
|
|
99
|
+
tags = secici.select_texts("div.labels a[href*='tur']")
|
|
100
|
+
rating = secici.regex_first(r"[\d.,]+", secici.select_text("div.dizipuani a div"))
|
|
101
|
+
|
|
102
|
+
# Actors extraction
|
|
103
|
+
id_slug = url.split('/')[-1]
|
|
104
|
+
a_resp = await self.httpx.get(f"{self.main_url}/oyuncular/{id_slug}")
|
|
105
|
+
a_sel = HTMLHelper(a_resp.text)
|
|
106
|
+
actors = a_sel.select_texts("div.doubling div.ui div.header")
|
|
107
|
+
|
|
108
|
+
# Episodes extraction
|
|
109
|
+
e_resp = await self.httpx.get(f"{self.main_url}/bolumler/{id_slug}")
|
|
110
|
+
e_sel = HTMLHelper(e_resp.text)
|
|
111
|
+
episodes = []
|
|
112
|
+
for row in e_sel.select("table.unstackable tbody tr"):
|
|
113
|
+
tds = e_sel.select("td", row)
|
|
114
|
+
if len(tds) >= 4:
|
|
115
|
+
name = e_sel.select_text("a", tds[3])
|
|
116
|
+
href = e_sel.select_attr("a", "href", tds[3])
|
|
117
|
+
if name and href:
|
|
118
|
+
s, e = e_sel.extract_season_episode(f"{tds[1].text(strip=True)} {tds[2].text(strip=True)}")
|
|
119
|
+
episodes.append(Episode(season=s or 1, episode=e or 1, title=name, url=self.fix_url(href)))
|
|
152
120
|
|
|
153
121
|
return SeriesInfo(
|
|
154
122
|
url = url,
|
|
@@ -157,7 +125,7 @@ class SezonlukDizi(PluginBase):
|
|
|
157
125
|
description = description,
|
|
158
126
|
tags = tags,
|
|
159
127
|
rating = rating,
|
|
160
|
-
year = year,
|
|
128
|
+
year = str(year) if year else None,
|
|
161
129
|
episodes = episodes,
|
|
162
130
|
actors = actors
|
|
163
131
|
)
|
KekikStream/Plugins/Sinefy.py
CHANGED
|
@@ -135,114 +135,51 @@ class Sinefy(PluginBase):
|
|
|
135
135
|
pass
|
|
136
136
|
return []
|
|
137
137
|
|
|
138
|
-
async def load_item(self, url: str) -> SeriesInfo:
|
|
138
|
+
async def load_item(self, url: str) -> SeriesInfo | MovieInfo:
|
|
139
139
|
resp = await self.httpx.get(url)
|
|
140
140
|
sel = HTMLHelper(resp.text)
|
|
141
141
|
|
|
142
|
-
title
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if "1x" in p:
|
|
150
|
-
poster = p.strip().split(" ")[0]
|
|
151
|
-
break
|
|
152
|
-
|
|
142
|
+
title = sel.select_direct_text("h1")
|
|
143
|
+
poster_attr = sel.select_attr("img.series-profile-thumb", "data-srcset") or sel.select_attr("img.series-profile-thumb", "srcset")
|
|
144
|
+
if poster_attr:
|
|
145
|
+
# "url 1x, url 2x" -> en sondakini (en yüksek kalite) al
|
|
146
|
+
poster = poster_attr.split(",")[-1].strip().split(" ")[0]
|
|
147
|
+
else:
|
|
148
|
+
poster = sel.select_poster("img.series-profile-thumb")
|
|
153
149
|
description = sel.select_text("p#tv-series-desc")
|
|
150
|
+
tags = sel.select_texts("div.item.categories a")
|
|
151
|
+
rating = sel.select_text("span.color-imdb")
|
|
152
|
+
actors = sel.select_texts("div.content h5")
|
|
153
|
+
year = sel.extract_year("div.truncate")
|
|
154
|
+
duration = sel.regex_first(r"(\d+)", sel.select_text(".media-meta td:last-child"))
|
|
155
|
+
if duration == year or int(duration) < 40:
|
|
156
|
+
duration = None
|
|
157
|
+
|
|
158
|
+
common_info = {
|
|
159
|
+
"url" : url,
|
|
160
|
+
"poster" : self.fix_url(poster) if poster else None,
|
|
161
|
+
"title" : title or "Bilinmiyor",
|
|
162
|
+
"description" : description,
|
|
163
|
+
"tags" : tags,
|
|
164
|
+
"rating" : rating,
|
|
165
|
+
"year" : str(year) if year else None,
|
|
166
|
+
"actors" : actors,
|
|
167
|
+
"duration" : duration
|
|
168
|
+
}
|
|
154
169
|
|
|
155
|
-
tags = [a.text(strip=True) for a in sel.select("div.item.categories a") if a.text(strip=True)]
|
|
156
|
-
|
|
157
|
-
rating = sel.select_text("span.color-imdb")
|
|
158
|
-
|
|
159
|
-
actors = [h5.text(strip=True) for h5 in sel.select("div.content h5") if h5.text(strip=True)]
|
|
160
|
-
|
|
161
|
-
year = sel.select_text("span.item.year")
|
|
162
|
-
if not year and title:
|
|
163
|
-
# Try to extract year from title like "Movie Name(2024)"
|
|
164
|
-
year_match = sel.regex_first(r"\((\d{4})\)", title)
|
|
165
|
-
if year_match:
|
|
166
|
-
year = year_match
|
|
167
|
-
|
|
168
170
|
episodes = []
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
# Sezon tab içeriklerini al
|
|
177
|
-
season_tabs = sel.select("div.ui.tab", episodes_box)
|
|
178
|
-
|
|
179
|
-
# Eğer birden fazla sezon varsa, her sezon tab'ından bölümleri çek
|
|
180
|
-
if season_tabs:
|
|
181
|
-
for idx, season_tab in enumerate(season_tabs):
|
|
182
|
-
# Sezon numarasını belirle
|
|
183
|
-
current_season_no = idx + 1
|
|
184
|
-
|
|
185
|
-
# Menüden sezon numarasını almaya çalış
|
|
186
|
-
if idx < len(season_menu):
|
|
187
|
-
menu_href = season_menu[idx].attrs.get("href", "")
|
|
188
|
-
match = sel.regex_first(r"sezon-(\d+)", menu_href)
|
|
189
|
-
if match:
|
|
190
|
-
current_season_no = int(match)
|
|
191
|
-
|
|
192
|
-
# Bu sezon tab'ından bölüm linklerini çek
|
|
193
|
-
ep_links = sel.select("a[href*='bolum']", season_tab)
|
|
194
|
-
|
|
195
|
-
seen_urls = set()
|
|
196
|
-
for ep_link in ep_links:
|
|
197
|
-
href = ep_link.attrs.get("href")
|
|
198
|
-
if not href or href in seen_urls:
|
|
199
|
-
continue
|
|
200
|
-
seen_urls.add(href)
|
|
201
|
-
|
|
202
|
-
# Bölüm numarasını URL'den çıkar
|
|
203
|
-
ep_no = 0
|
|
204
|
-
match_ep = sel.regex_first(r"bolum-(\d+)", href)
|
|
205
|
-
if match_ep:
|
|
206
|
-
ep_no = int(match_ep)
|
|
207
|
-
|
|
208
|
-
# Bölüm başlığını çıkar (önce title attribute, sonra text)
|
|
209
|
-
name = ep_link.attrs.get("title", "")
|
|
210
|
-
if not name:
|
|
211
|
-
name = sel.select_text("div.content div.header", ep_link)
|
|
212
|
-
if not name:
|
|
213
|
-
name = ep_link.text(strip=True)
|
|
214
|
-
|
|
215
|
-
if href and ep_no > 0:
|
|
216
|
-
episodes.append(Episode(
|
|
217
|
-
season = current_season_no,
|
|
218
|
-
episode = ep_no,
|
|
219
|
-
title = name.strip() if name else f"{ep_no}. Bölüm",
|
|
220
|
-
url = self.fix_url(href)
|
|
221
|
-
))
|
|
171
|
+
for tab in sel.select("div.ui.tab"):
|
|
172
|
+
for link in sel.select("a[href*='bolum']", tab):
|
|
173
|
+
href = link.attrs.get("href")
|
|
174
|
+
if href:
|
|
175
|
+
s, e = sel.extract_season_episode(href)
|
|
176
|
+
name = sel.select_text("div.content div.header", link) or link.text(strip=True)
|
|
177
|
+
episodes.append(Episode(season=s or 1, episode=e or 1, title=name, url=self.fix_url(href)))
|
|
222
178
|
|
|
223
179
|
if episodes:
|
|
224
|
-
return SeriesInfo(
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
poster = self.fix_url(poster) if poster else None,
|
|
228
|
-
description = description,
|
|
229
|
-
rating = rating,
|
|
230
|
-
tags = tags,
|
|
231
|
-
actors = actors,
|
|
232
|
-
year = year,
|
|
233
|
-
episodes = episodes
|
|
234
|
-
)
|
|
235
|
-
else:
|
|
236
|
-
return MovieInfo(
|
|
237
|
-
title = title,
|
|
238
|
-
url = url,
|
|
239
|
-
poster = self.fix_url(poster) if poster else None,
|
|
240
|
-
description = description,
|
|
241
|
-
rating = rating,
|
|
242
|
-
tags = tags,
|
|
243
|
-
actors = actors,
|
|
244
|
-
year = year
|
|
245
|
-
)
|
|
180
|
+
return SeriesInfo(**common_info, episodes=episodes)
|
|
181
|
+
|
|
182
|
+
return MovieInfo(**common_info)
|
|
246
183
|
|
|
247
184
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
248
185
|
resp = await self.httpx.get(url)
|