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/DiziYou.py
CHANGED
|
@@ -69,173 +69,65 @@ class DiziYou(PluginBase):
|
|
|
69
69
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
70
70
|
istek = await self.httpx.get(url)
|
|
71
71
|
secici = HTMLHelper(istek.text)
|
|
72
|
-
html_text = istek.text
|
|
73
72
|
|
|
74
|
-
|
|
75
|
-
title
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
# Poster
|
|
84
|
-
poster_src = secici.select_attr("div.category_image img", "src") or secici.select_attr("meta[property='og:image']", "content")
|
|
85
|
-
poster = self.fix_url(poster_src) if poster_src else ""
|
|
86
|
-
|
|
87
|
-
# Year - regex ile çıkarma (xpath yerine)
|
|
88
|
-
year = secici.regex_first(r"(?is)Yapım Yılı.*?(\d{4})", secici.html)
|
|
89
|
-
|
|
90
|
-
description_el = secici.select("div.diziyou_desc") or secici.select("div#icerikcat")
|
|
91
|
-
description = ""
|
|
92
|
-
if description_el:
|
|
93
|
-
# Scriptleri temizle
|
|
94
|
-
for script in secici.select("script", description_el[0]):
|
|
95
|
-
script.decompose()
|
|
96
|
-
description = secici.select_text(None, description_el[0])
|
|
97
|
-
|
|
98
|
-
tags = [secici.select_text(None, a) for a in secici.select("div.genres a") if secici.select_text(None, a)]
|
|
99
|
-
|
|
100
|
-
# Rating - daha spesifik regex ile
|
|
101
|
-
rating = secici.regex_first(r"(?is)IMDB\s*:\s*</span>([0-9.]+)", secici.html)
|
|
102
|
-
|
|
103
|
-
# Actors - regex ile
|
|
104
|
-
actors_raw = secici.regex_first(r"(?is)Oyuncular.*?</span>([^<]+)", secici.html)
|
|
105
|
-
actors = [actor.strip() for actor in actors_raw.split(",") if actor.strip()] if actors_raw else []
|
|
73
|
+
poster = secici.select_poster("div.category_image img")
|
|
74
|
+
title = secici.select_text("h1.title-border")
|
|
75
|
+
description = secici.select_direct_text("div#icerikcatright")
|
|
76
|
+
tags = secici.select_texts("div.genres a")
|
|
77
|
+
rating = secici.regex_first(r"(?is)IMDB\s*:\s*</span>([0-9.]+)", secici.html)
|
|
78
|
+
year = secici.extract_year("div#icerikcat2")
|
|
79
|
+
actors = secici.meta_value("Oyuncular", container_selector="div#icerikcat2")
|
|
80
|
+
actors = [a.strip() for a in actors.split(",")] if actors else []
|
|
106
81
|
|
|
107
82
|
episodes = []
|
|
108
|
-
# Episodes - div#scrollbar-container a (kısıtlı alan)
|
|
109
83
|
for link in secici.select("div#scrollbar-container a"):
|
|
110
|
-
|
|
111
|
-
if
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
title_child = secici.select_text("div.baslik", link) or secici.select_text("div.bolumismi", link)
|
|
117
|
-
if title_child:
|
|
118
|
-
ep_name = title_child
|
|
119
|
-
|
|
120
|
-
# Önce metin üzerinden sezon/bölüm çıkart
|
|
121
|
-
s_val, e_val = HTMLHelper.extract_season_episode(ep_name)
|
|
122
|
-
|
|
123
|
-
# URL bazlı kalıplar: -1-sezon-2-bolum gibi
|
|
124
|
-
if not (s_val or e_val):
|
|
125
|
-
pairs = HTMLHelper(ep_href).regex_all(r"-(\d+)-sezon-(\d+)-bolum")
|
|
126
|
-
if pairs:
|
|
127
|
-
s_val, e_val = int(pairs[0][0]), int(pairs[0][1])
|
|
128
|
-
else:
|
|
129
|
-
pairs = HTMLHelper(ep_href).regex_all(r"(\d+)-sezon-(\d+)-bolum")
|
|
130
|
-
if pairs:
|
|
131
|
-
s_val, e_val = int(pairs[0][0]), int(pairs[0][1])
|
|
132
|
-
else:
|
|
133
|
-
e_val_str = HTMLHelper(ep_href).regex_first(r"(\d+)-bolum")
|
|
134
|
-
if e_val_str:
|
|
135
|
-
e_val = int(e_val_str)
|
|
136
|
-
# Metin üzerinden son bir deneme
|
|
137
|
-
if not e_val:
|
|
138
|
-
e_str = HTMLHelper(ep_name).regex_first(r"(\d+)\s*\.\s*[Bb]ölüm")
|
|
139
|
-
if e_str:
|
|
140
|
-
e_val = int(e_str)
|
|
141
|
-
if not s_val:
|
|
142
|
-
s_str = HTMLHelper(ep_name).regex_first(r"(\d+)\s*\.\s*[Ss]ezon")
|
|
143
|
-
if s_str:
|
|
144
|
-
s_val = int(s_str)
|
|
145
|
-
|
|
146
|
-
if e_val or HTMLHelper(ep_href).regex_first(r"-\d+-sezon-\d+-bolum"):
|
|
147
|
-
episodes.append(Episode(
|
|
148
|
-
season = s_val,
|
|
149
|
-
episode = e_val,
|
|
150
|
-
title = ep_name if ep_name else None,
|
|
151
|
-
url = self.fix_url(ep_href),
|
|
152
|
-
))
|
|
84
|
+
href = secici.select_attr(None, "href", link)
|
|
85
|
+
if href:
|
|
86
|
+
name = secici.select_text("div.bolumismi", link).strip("()")
|
|
87
|
+
s, e = secici.extract_season_episode(f"{name} {href}")
|
|
88
|
+
if e:
|
|
89
|
+
episodes.append(Episode(season=s or 1, episode=e, title=name, url=self.fix_url(href)))
|
|
153
90
|
|
|
154
91
|
return SeriesInfo(
|
|
155
|
-
url
|
|
156
|
-
|
|
157
|
-
title = title,
|
|
158
|
-
description = description,
|
|
159
|
-
tags = tags,
|
|
160
|
-
rating = rating,
|
|
161
|
-
year = year,
|
|
162
|
-
episodes = episodes,
|
|
163
|
-
actors = actors
|
|
92
|
+
url=url, poster=poster, title=title or "Bilinmiyor", description=description,
|
|
93
|
+
tags=tags, rating=rating, year=str(year) if year else None, episodes=episodes, actors=actors
|
|
164
94
|
)
|
|
165
95
|
|
|
166
96
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
167
97
|
istek = await self.httpx.get(url)
|
|
168
98
|
secici = HTMLHelper(istek.text)
|
|
169
|
-
|
|
170
|
-
# Title ve episode name - None kontrolü ekle
|
|
171
|
-
item_title = secici.select_text("div.title h1")
|
|
172
|
-
ep_name = secici.select_text("div#bolum-ismi")
|
|
173
99
|
|
|
174
|
-
# Player
|
|
175
|
-
#
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
continue
|
|
190
|
-
if HTMLHelper(href).regex_first(r"(-\d+-sezon-\d+-bolum|/bolum|/episode|/episodes|/play)"):
|
|
191
|
-
break
|
|
192
|
-
|
|
193
|
-
if not player_src:
|
|
194
|
-
return [] # Player bulunamadıysa boş liste döndür
|
|
195
|
-
|
|
196
|
-
item_id = player_src.split("/")[-1].replace(".html", "")
|
|
197
|
-
|
|
198
|
-
subtitles = []
|
|
199
|
-
stream_urls = []
|
|
200
|
-
|
|
201
|
-
for secenek in secici.select("span.diziyouOption"):
|
|
202
|
-
opt_id = secici.select_attr("span.diziyouOption", "id", secenek)
|
|
203
|
-
op_name = secici.select_text("span.diziyouOption", secenek)
|
|
204
|
-
|
|
205
|
-
match opt_id:
|
|
206
|
-
case "turkceAltyazili":
|
|
207
|
-
subtitles.append(Subtitle(
|
|
208
|
-
name = op_name,
|
|
209
|
-
url = self.fix_url(f"{self.main_url.replace('www', 'storage')}/subtitles/{item_id}/tr.vtt"),
|
|
210
|
-
))
|
|
211
|
-
veri = {
|
|
212
|
-
"dil": "Orjinal Dil (TR Altyazı)",
|
|
213
|
-
"url": f"{self.main_url.replace('www', 'storage')}/episodes/{item_id}/play.m3u8"
|
|
214
|
-
}
|
|
215
|
-
if veri not in stream_urls:
|
|
216
|
-
stream_urls.append(veri)
|
|
217
|
-
case "ingilizceAltyazili":
|
|
218
|
-
subtitles.append(Subtitle(
|
|
219
|
-
name = op_name,
|
|
220
|
-
url = self.fix_url(f"{self.main_url.replace('www', 'storage')}/subtitles/{item_id}/en.vtt"),
|
|
221
|
-
))
|
|
222
|
-
veri = {
|
|
223
|
-
"dil": "Orjinal Dil (EN Altyazı)",
|
|
224
|
-
"url": f"{self.main_url.replace('www', 'storage')}/episodes/{item_id}/play.m3u8"
|
|
225
|
-
}
|
|
226
|
-
if veri not in stream_urls:
|
|
227
|
-
stream_urls.append(veri)
|
|
228
|
-
case "turkceDublaj":
|
|
229
|
-
stream_urls.append({
|
|
230
|
-
"dil": "Türkçe Dublaj",
|
|
231
|
-
"url": f"{self.main_url.replace('www', 'storage')}/episodes/{item_id}_tr/play.m3u8"
|
|
232
|
-
})
|
|
100
|
+
# Player iframe'inden ID'yi yakala
|
|
101
|
+
iframe_src = secici.select_attr("iframe#diziyouPlayer", "src") or secici.select_attr("iframe[src*='/player/']", "src")
|
|
102
|
+
if not iframe_src:
|
|
103
|
+
return []
|
|
104
|
+
|
|
105
|
+
item_id = iframe_src.split("/")[-1].replace(".html", "")
|
|
106
|
+
base_storage = self.main_url.replace("www", "storage")
|
|
107
|
+
|
|
108
|
+
subtitles = []
|
|
109
|
+
for sub in [("turkceAltyazili", "tr", "Türkçe"), ("ingilizceAltyazili", "en", "İngilizce")]:
|
|
110
|
+
if secici.select_first(f"span#{sub[0]}"):
|
|
111
|
+
subtitles.append(Subtitle(
|
|
112
|
+
name = f"{sub[2]} Altyazı",
|
|
113
|
+
url = f"{base_storage}/subtitles/{item_id}/{sub[1]}.vtt"
|
|
114
|
+
))
|
|
233
115
|
|
|
234
116
|
results = []
|
|
235
|
-
|
|
117
|
+
# Altyazılı Seçenek (Eğer varsa)
|
|
118
|
+
if secici.select_first("span#turkceAltyazili") or secici.select_first("span#ingilizceAltyazili"):
|
|
119
|
+
results.append(ExtractResult(
|
|
120
|
+
name = "Altyazılı",
|
|
121
|
+
url = f"{base_storage}/episodes/{item_id}/play.m3u8",
|
|
122
|
+
referer = url,
|
|
123
|
+
subtitles = subtitles
|
|
124
|
+
))
|
|
125
|
+
|
|
126
|
+
# Dublaj Seçeneği (Eğer varsa)
|
|
127
|
+
if secici.select_first("span#turkceDublaj"):
|
|
236
128
|
results.append(ExtractResult(
|
|
237
|
-
|
|
238
|
-
|
|
129
|
+
name = "Türkçe Dublaj",
|
|
130
|
+
url = f"{base_storage}/episodes/{item_id}_tr/play.m3u8",
|
|
239
131
|
referer = url,
|
|
240
132
|
subtitles = subtitles
|
|
241
133
|
))
|
KekikStream/Plugins/Dizilla.py
CHANGED
|
@@ -62,7 +62,7 @@ class Dizilla(PluginBase):
|
|
|
62
62
|
# Detay sayfasından poster vb. bilgileri al
|
|
63
63
|
ep_req = await self.httpx.get(self.fix_url(href))
|
|
64
64
|
ep_secici = HTMLHelper(ep_req.text)
|
|
65
|
-
poster = ep_secici.
|
|
65
|
+
poster = ep_secici.select_poster('img.imgt') or ep_secici.select_poster('img')
|
|
66
66
|
|
|
67
67
|
ana_sayfa.append(MainPageResult(
|
|
68
68
|
category = category,
|
|
@@ -138,65 +138,39 @@ class Dizilla(PluginBase):
|
|
|
138
138
|
secici = HTMLHelper(istek.text)
|
|
139
139
|
|
|
140
140
|
next_data_text = secici.select_text("script#__NEXT_DATA__")
|
|
141
|
-
if not next_data_text:
|
|
142
|
-
return None
|
|
141
|
+
if not next_data_text: return None
|
|
143
142
|
|
|
144
143
|
next_data = loads(next_data_text)
|
|
145
144
|
secure_data = next_data.get("props", {}).get("pageProps", {}).get("secureData")
|
|
146
|
-
if not secure_data:
|
|
147
|
-
return None
|
|
145
|
+
if not secure_data: return None
|
|
148
146
|
|
|
149
147
|
decrypted = await self.decrypt_response(secure_data)
|
|
150
148
|
content = decrypted.get("contentItem", {})
|
|
151
|
-
if not content:
|
|
152
|
-
return None
|
|
149
|
+
if not content: return None
|
|
153
150
|
|
|
154
151
|
title = content.get("original_title") or content.get("used_title")
|
|
155
152
|
description = content.get("description") or content.get("used_description")
|
|
156
153
|
rating = content.get("imdb_point") or content.get("local_vote_avg")
|
|
157
154
|
year = content.get("release_year")
|
|
158
|
-
|
|
159
|
-
# Poster and Backdrop - prefer backdrop if available for SeriesInfo
|
|
160
|
-
poster = self.fix_poster_url(self.fix_url(content.get("back_url") or content.get("poster_url")))
|
|
161
|
-
|
|
162
|
-
# Tags
|
|
163
|
-
tags = []
|
|
164
|
-
categories = decrypted.get("RelatedResults", {}).get("getSerieCategoriesById", {}).get("result", [])
|
|
165
|
-
for cat in categories:
|
|
166
|
-
tags.append(cat.get("name"))
|
|
167
|
-
|
|
168
|
-
# Actors
|
|
169
|
-
actors = []
|
|
170
|
-
casts = decrypted.get("RelatedResults", {}).get("getSerieCastsById", {}).get("result", [])
|
|
171
|
-
for cast in casts:
|
|
172
|
-
actors.append(cast.get("name"))
|
|
173
|
-
|
|
174
|
-
# Episodes
|
|
175
|
-
episodes = []
|
|
176
|
-
seasons_data = decrypted.get("RelatedResults", {}).get("getSerieSeasonAndEpisodes", {}).get("result", [])
|
|
177
|
-
for season_item in seasons_data:
|
|
178
|
-
season_num = season_item.get("season_no")
|
|
179
|
-
for ep_item in season_item.get("episodes", []):
|
|
180
|
-
ep_num = ep_item.get("episode_no")
|
|
181
|
-
ep_slug = ep_item.get("used_slug")
|
|
182
|
-
ep_name = ep_item.get("episode_text") or ""
|
|
183
|
-
|
|
184
|
-
# Filter out duplicate language entries if any (we just need one link per episode)
|
|
185
|
-
# Usually they share the same slug for the episode page
|
|
186
|
-
if any(e.season == season_num and e.episode == ep_num for e in episodes):
|
|
187
|
-
continue
|
|
155
|
+
poster = self.fix_poster_url(self.fix_url(content.get("back_url") or content.get("poster_url")))
|
|
188
156
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
157
|
+
tags = [cat.get("name") for cat in decrypted.get("RelatedResults", {}).get("getSerieCategoriesById", {}).get("result", [])]
|
|
158
|
+
actors = [cast.get("name") for cast in decrypted.get("RelatedResults", {}).get("getSerieCastsById", {}).get("result", [])]
|
|
159
|
+
|
|
160
|
+
episodes = []
|
|
161
|
+
for season in decrypted.get("RelatedResults", {}).get("getSerieSeasonAndEpisodes", {}).get("result", []):
|
|
162
|
+
s_no = season.get("season_no")
|
|
163
|
+
for ep in season.get("episodes", []):
|
|
164
|
+
e_no = ep.get("episode_no")
|
|
165
|
+
slug = ep.get("used_slug")
|
|
166
|
+
name = ep.get("episode_text") or ""
|
|
167
|
+
if not any(e.season == s_no and e.episode == e_no for e in episodes):
|
|
168
|
+
episodes.append(Episode(season=s_no, episode=e_no, title=name, url=self.fix_url(f"{self.main_url}/{slug}")))
|
|
195
169
|
|
|
196
170
|
return SeriesInfo(
|
|
197
171
|
url = url,
|
|
198
172
|
poster = poster,
|
|
199
|
-
title = title,
|
|
173
|
+
title = title or "Bilinmiyor",
|
|
200
174
|
description = description,
|
|
201
175
|
tags = tags,
|
|
202
176
|
rating = str(rating) if rating else None,
|
KekikStream/Plugins/FilmBip.py
CHANGED
|
@@ -95,38 +95,24 @@ class FilmBip(PluginBase):
|
|
|
95
95
|
async def load_item(self, url: str) -> MovieInfo:
|
|
96
96
|
istek = await self.httpx.get(url)
|
|
97
97
|
secici = HTMLHelper(istek.text)
|
|
98
|
-
html_text = istek.text
|
|
99
|
-
|
|
100
|
-
title = secici.select_text("div.page-title h1") or ""
|
|
101
|
-
|
|
102
|
-
poster = secici.select_attr("meta[property='og:image']", "content")
|
|
103
|
-
|
|
104
|
-
trailer = secici.select_attr("div.series-profile-trailer", "data-yt")
|
|
105
98
|
|
|
99
|
+
title = self.clean_title(secici.select_direct_text("div.page-title h1"))
|
|
100
|
+
poster = secici.select_poster("div.series-profile-image a img")
|
|
106
101
|
description = secici.select_text("div.series-profile-infos-in.article p") or secici.select_text("div.series-profile-summary p")
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
# Fallback: Başlığın sonundaki parantezli yılı yakala
|
|
114
|
-
year = secici.regex_first(r"\((\d{4})\)", title)
|
|
115
|
-
|
|
116
|
-
duration_raw = secici.regex_first(r"(?is)S\u00fcre.*?<p[^>]*>(.*?)<\/p>")
|
|
117
|
-
duration = secici.regex_first(r"(\d+)", duration_raw) if duration_raw else None
|
|
118
|
-
|
|
119
|
-
rating = secici.regex_first(r"(?is)IMDB Puan\u0131.*?<span[^>]*>(.*?)<\/span>")
|
|
120
|
-
|
|
121
|
-
actors = [img.attrs.get("alt") for img in secici.select("div.series-profile-cast ul li a img") if img.attrs.get("alt")]
|
|
102
|
+
tags = secici.select_texts("div.series-profile-type.tv-show-profile-type a")
|
|
103
|
+
year = secici.extract_year("div.series-profile-infos-in") or secici.regex_first(r"\((\d{4})\)", title)
|
|
104
|
+
duration = secici.regex_first(r"(\d+)", secici.meta_value("Süre", container_selector="div.series-profile-infos"))
|
|
105
|
+
rating = secici.meta_value("IMDB Puanı", container_selector="div.series-profile-infos")
|
|
106
|
+
rating = rating.split("(")[0] if rating else None
|
|
107
|
+
actors = secici.select_attrs("div.series-profile-cast ul li a img", "alt")
|
|
122
108
|
|
|
123
109
|
return MovieInfo(
|
|
124
110
|
url = url,
|
|
125
111
|
poster = self.fix_url(poster) if poster else None,
|
|
126
|
-
title =
|
|
112
|
+
title = title or "",
|
|
127
113
|
description = description,
|
|
128
114
|
tags = tags,
|
|
129
|
-
year = year,
|
|
115
|
+
year = str(year) if year else None,
|
|
130
116
|
rating = rating,
|
|
131
117
|
duration = int(duration) if duration else None,
|
|
132
118
|
actors = actors,
|
|
@@ -70,45 +70,25 @@ class FilmEkseni(PluginBase):
|
|
|
70
70
|
istek = await self.httpx.get(url)
|
|
71
71
|
helper = HTMLHelper(istek.text)
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
tags = []
|
|
82
|
-
for tag_str in tags_raw:
|
|
83
|
-
if tag_str.startswith("Tür:"):
|
|
84
|
-
tags.extend([t.strip() for t in tag_str.replace("Tür:", "").split(",")])
|
|
73
|
+
title = self.clean_title(helper.select_text("div.page-title h1"))
|
|
74
|
+
poster = helper.select_poster("picture.poster-auto img")
|
|
75
|
+
description = helper.select_direct_text("article.text-white p")
|
|
76
|
+
year = helper.extract_year("div.page-title", "strong a")
|
|
77
|
+
tags = helper.select_texts("div.pb-2 a[href*='/tur/']")
|
|
78
|
+
rating = helper.select_text("div.rate")
|
|
79
|
+
duration = helper.regex_first(r"(\d+)", helper.select_text("div.d-flex.flex-column.text-nowrap"))
|
|
80
|
+
actors = helper.select_texts("div.card-body.p-0.pt-2 .story-item .story-item-title")
|
|
85
81
|
|
|
86
|
-
rating = helper.select_text("div.rate")
|
|
87
|
-
|
|
88
|
-
duration = None
|
|
89
|
-
duration_text = helper.select_text("div.d-flex.flex-column.text-nowrap")
|
|
90
|
-
if duration_text:
|
|
91
|
-
m = re.search(r"(\d+)", duration_text)
|
|
92
|
-
if m:
|
|
93
|
-
duration = int(m.group(1))
|
|
94
|
-
|
|
95
|
-
actors_raw = helper.select("div.card-body.p-0.pt-2 .story-item")
|
|
96
|
-
actors = []
|
|
97
|
-
for actor in actors_raw:
|
|
98
|
-
name = helper.select_text(".story-item-title", actor)
|
|
99
|
-
if name:
|
|
100
|
-
actors.append(name)
|
|
101
|
-
|
|
102
82
|
return MovieInfo(
|
|
103
83
|
url = url,
|
|
104
|
-
poster = self.fix_url(poster),
|
|
105
|
-
title = title,
|
|
84
|
+
poster = self.fix_url(poster) if poster else None,
|
|
85
|
+
title = title or "Bilinmiyor",
|
|
106
86
|
description = description,
|
|
107
87
|
tags = tags,
|
|
108
88
|
rating = rating,
|
|
109
|
-
year = year,
|
|
89
|
+
year = str(year) if year else None,
|
|
110
90
|
actors = actors if actors else None,
|
|
111
|
-
duration = duration
|
|
91
|
+
duration = int(duration) if duration else None
|
|
112
92
|
)
|
|
113
93
|
|
|
114
94
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
@@ -76,94 +76,41 @@ class FilmMakinesi(PluginBase):
|
|
|
76
76
|
istek = await self.httpx.get(url)
|
|
77
77
|
secici = HTMLHelper(istek.text)
|
|
78
78
|
|
|
79
|
-
title
|
|
79
|
+
title = self.clean_title(secici.select_text("h1.title"))
|
|
80
|
+
poster = secici.select_poster("img.cover-img")
|
|
81
|
+
description = secici.select_text("div.info-description p")
|
|
82
|
+
rating = secici.regex_first(r"(\d+[\d.]*)", secici.select_text("div.score"))
|
|
83
|
+
year = secici.select_text("span.date a")
|
|
84
|
+
actors = secici.select_texts("div.cast-name")
|
|
85
|
+
tags = secici.select_texts("div.type a[href*='/tur/']")
|
|
86
|
+
duration = secici.regex_first(r"(\d+)", secici.select_text("div.time"))
|
|
80
87
|
|
|
81
|
-
poster = secici.select_attr("img.cover-img", "src") or ""
|
|
82
|
-
poster = poster.strip()
|
|
83
|
-
|
|
84
|
-
description = secici.select_text("div.info-description p") or ""
|
|
85
|
-
|
|
86
|
-
rating_text = secici.select_text("div.score") or ""
|
|
87
|
-
rating = None
|
|
88
|
-
if rating_text:
|
|
89
|
-
rating = rating_text.split()[0]
|
|
90
|
-
|
|
91
|
-
year = secici.select_text("span.date a") or ""
|
|
92
|
-
|
|
93
|
-
actors = secici.select_all_text("div.cast-name")
|
|
94
|
-
tags = [a.text(strip=True) for a in secici.select("div.type a") if "/tur/" in (a.attrs.get("href") or "")]
|
|
95
|
-
|
|
96
|
-
duration = None
|
|
97
|
-
duration_text = secici.select_text("div.time") or None
|
|
98
|
-
if duration_text:
|
|
99
|
-
parts = duration_text.split()
|
|
100
|
-
if len(parts) > 1:
|
|
101
|
-
duration = parts[1].strip()
|
|
102
|
-
|
|
103
|
-
# Dizi mi kontrol et - sezon/bölüm linkleri var mı?
|
|
104
88
|
episodes = []
|
|
105
|
-
|
|
106
|
-
for link in all_links:
|
|
89
|
+
for link in secici.select("a[href]"):
|
|
107
90
|
href = link.attrs.get("href", "")
|
|
108
|
-
|
|
109
|
-
if
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
# Bölüm başlığını çıkar - text'ten gerçek ismi al
|
|
114
|
-
# Format: "22 Eylül 2014 / 44 dk /1. Sezon / 1. BölümPilot"
|
|
115
|
-
full_text = link.text(strip=True)
|
|
116
|
-
# "Bölüm" kelimesinden sonraki kısmı al
|
|
117
|
-
ep_title = ""
|
|
118
|
-
if "Bölüm" in full_text:
|
|
119
|
-
parts = full_text.split("Bölüm")
|
|
120
|
-
if len(parts) > 1:
|
|
121
|
-
ep_title = parts[-1].strip()
|
|
122
|
-
|
|
123
|
-
episodes.append(Episode(
|
|
124
|
-
season = season_no,
|
|
125
|
-
episode = ep_no,
|
|
126
|
-
title = ep_title,
|
|
127
|
-
url = self.fix_url(href)
|
|
128
|
-
))
|
|
91
|
+
s, e = secici.extract_season_episode(href)
|
|
92
|
+
if s and e:
|
|
93
|
+
name = link.text(strip=True).split("Bölüm")[-1].strip() if "Bölüm" in link.text() else ""
|
|
94
|
+
episodes.append(Episode(season=s, episode=e, title=name, url=self.fix_url(href)))
|
|
129
95
|
|
|
130
|
-
#
|
|
96
|
+
# Tekrar edenleri temizle ve sırala
|
|
131
97
|
if episodes:
|
|
132
|
-
# Tekrar eden bölümleri kaldır
|
|
133
98
|
seen = set()
|
|
134
|
-
|
|
99
|
+
unique = []
|
|
135
100
|
for ep in episodes:
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
# Sırala
|
|
142
|
-
unique_episodes.sort(key=lambda x: (x.season or 0, x.episode or 0))
|
|
143
|
-
|
|
101
|
+
if (ep.season, ep.episode) not in seen:
|
|
102
|
+
seen.add((ep.season, ep.episode))
|
|
103
|
+
unique.append(ep)
|
|
104
|
+
unique.sort(key=lambda x: (x.season or 0, x.episode or 0))
|
|
105
|
+
|
|
144
106
|
return SeriesInfo(
|
|
145
|
-
url
|
|
146
|
-
|
|
147
|
-
title = self.clean_title(title),
|
|
148
|
-
description = description,
|
|
149
|
-
tags = tags,
|
|
150
|
-
rating = rating,
|
|
151
|
-
year = year,
|
|
152
|
-
actors = actors,
|
|
153
|
-
duration = duration,
|
|
154
|
-
episodes = unique_episodes
|
|
107
|
+
url=url, poster=self.fix_url(poster) if poster else None, title=title, description=description,
|
|
108
|
+
tags=tags, rating=rating, year=year, actors=actors, duration=duration, episodes=unique
|
|
155
109
|
)
|
|
156
110
|
|
|
157
111
|
return MovieInfo(
|
|
158
|
-
url
|
|
159
|
-
|
|
160
|
-
title = self.clean_title(title),
|
|
161
|
-
description = description,
|
|
162
|
-
tags = tags,
|
|
163
|
-
rating = rating,
|
|
164
|
-
year = year,
|
|
165
|
-
actors = actors,
|
|
166
|
-
duration = duration
|
|
112
|
+
url=url, poster=self.fix_url(poster) if poster else None, title=title, description=description,
|
|
113
|
+
tags=tags, rating=rating, year=year, actors=actors, duration=duration
|
|
167
114
|
)
|
|
168
115
|
|
|
169
116
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
KekikStream/Plugins/FilmModu.py
CHANGED
|
@@ -81,23 +81,15 @@ class FilmModu(PluginBase):
|
|
|
81
81
|
istek = await self.httpx.get(url)
|
|
82
82
|
secici = HTMLHelper(istek.text)
|
|
83
83
|
|
|
84
|
-
org_title
|
|
85
|
-
alt_title
|
|
86
|
-
title
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
year = secici.select_text("span[itemprop='dateCreated']") or None
|
|
95
|
-
|
|
96
|
-
actors = []
|
|
97
|
-
for a in secici.select("a[itemprop='actor']"):
|
|
98
|
-
name = secici.select_text("span", a)
|
|
99
|
-
if name:
|
|
100
|
-
actors.append(name)
|
|
84
|
+
org_title = secici.select_text("div.titles h1")
|
|
85
|
+
alt_title = secici.select_text("div.titles h2")
|
|
86
|
+
title = f"{org_title} - {alt_title}" if alt_title else (org_title or "")
|
|
87
|
+
poster = secici.select_poster("img.img-responsive")
|
|
88
|
+
description = secici.select_text("p[itemprop='description']")
|
|
89
|
+
tags = secici.select_texts("a[href*='film-tur/']")
|
|
90
|
+
rating = secici.meta_value("IMDB")
|
|
91
|
+
year = secici.extract_year("span[itemprop='dateCreated']")
|
|
92
|
+
actors = secici.select_texts("a[itemprop='actor'] span")
|
|
101
93
|
|
|
102
94
|
return MovieInfo(
|
|
103
95
|
url = url,
|
|
@@ -105,7 +97,8 @@ class FilmModu(PluginBase):
|
|
|
105
97
|
title = title,
|
|
106
98
|
description = description,
|
|
107
99
|
tags = tags,
|
|
108
|
-
|
|
100
|
+
rating = rating,
|
|
101
|
+
year = str(year) if year else None,
|
|
109
102
|
actors = actors,
|
|
110
103
|
)
|
|
111
104
|
|
KekikStream/Plugins/Filmatek.py
CHANGED
|
@@ -81,52 +81,26 @@ class Filmatek(PluginBase):
|
|
|
81
81
|
return results
|
|
82
82
|
|
|
83
83
|
async def load_item(self, url: str) -> MovieInfo:
|
|
84
|
-
istek
|
|
84
|
+
istek = await self.httpx.get(url)
|
|
85
85
|
helper = HTMLHelper(istek.text)
|
|
86
86
|
|
|
87
|
-
title
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if not description:
|
|
96
|
-
description = helper.select_attr("meta[property='og:description']", "content")
|
|
97
|
-
|
|
98
|
-
year_text = helper.select_text("span.date")
|
|
99
|
-
year = year_text.strip()[-4:] if year_text else None
|
|
100
|
-
|
|
101
|
-
# Rating extraction updated
|
|
102
|
-
rating = helper.select_text("span.dt_rating_vgs") or helper.select_text("span.dt_rating_vmanual")
|
|
103
|
-
|
|
104
|
-
# Duration extraction
|
|
105
|
-
duration = None
|
|
106
|
-
duration_text = helper.select_text("span.runtime")
|
|
107
|
-
if duration_text:
|
|
108
|
-
# "80 Dak." -> "80"
|
|
109
|
-
duration = duration_text.split()[0]
|
|
110
|
-
|
|
111
|
-
tags = helper.select_all_text("div.sgeneros a")
|
|
112
|
-
|
|
113
|
-
# Actors
|
|
114
|
-
actors_list = []
|
|
115
|
-
actor_els = helper.select("div.person")
|
|
116
|
-
for el in actor_els:
|
|
117
|
-
name = helper.select_text("div.name a", el)
|
|
118
|
-
if name:
|
|
119
|
-
actors_list.append(name.strip())
|
|
120
|
-
actors = ", ".join(actors_list) if actors_list else None
|
|
87
|
+
title = self.clean_title(helper.select_text("div.data h1, h1"))
|
|
88
|
+
poster = helper.select_poster("div.poster img") or helper.select_attr("meta[property='og:image']", "content")
|
|
89
|
+
description = helper.select_text("div.wp-content p") or helper.select_attr("meta[property='og:description']", "content")
|
|
90
|
+
year = helper.extract_year("span.date")
|
|
91
|
+
rating = helper.select_text("span.dt_rating_vgs") or helper.select_text("span.dt_rating_vmanual")
|
|
92
|
+
duration = helper.regex_first(r"(\d+)", helper.select_text("span.runtime"))
|
|
93
|
+
tags = helper.select_texts("div.sgeneros a")
|
|
94
|
+
actors = helper.select_texts("div.person div.name a")
|
|
121
95
|
|
|
122
96
|
return MovieInfo(
|
|
123
97
|
url = url,
|
|
124
|
-
title = title,
|
|
98
|
+
title = title or "Bilinmiyor",
|
|
125
99
|
description = description,
|
|
126
|
-
poster = poster,
|
|
127
|
-
year = year,
|
|
100
|
+
poster = self.fix_url(poster) if poster else None,
|
|
101
|
+
year = str(year) if year else None,
|
|
128
102
|
rating = rating,
|
|
129
|
-
duration = duration,
|
|
103
|
+
duration = int(duration) if duration else None,
|
|
130
104
|
tags = tags,
|
|
131
105
|
actors = actors
|
|
132
106
|
)
|