KekikStream 2.4.2__py3-none-any.whl → 2.4.3__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 +26 -75
- 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.3.dist-info}/METADATA +1 -1
- kekikstream-2.4.3.dist-info/RECORD +93 -0
- kekikstream-2.4.2.dist-info/RECORD +0 -93
- {kekikstream-2.4.2.dist-info → kekikstream-2.4.3.dist-info}/WHEEL +0 -0
- {kekikstream-2.4.2.dist-info → kekikstream-2.4.3.dist-info}/entry_points.txt +0 -0
- {kekikstream-2.4.2.dist-info → kekikstream-2.4.3.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-2.4.2.dist-info → kekikstream-2.4.3.dist-info}/top_level.txt +0 -0
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
|
)
|
|
@@ -98,151 +98,51 @@ class Full4kizle(PluginBase):
|
|
|
98
98
|
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
99
99
|
istek = await self.httpx.get(url)
|
|
100
100
|
helper = HTMLHelper(istek.text)
|
|
101
|
-
|
|
102
|
-
title_raw = helper.select_text("h1") or "Bilinmiyor"
|
|
103
|
-
title = re.sub(r"(?i)izle", "", title_raw).strip()
|
|
104
|
-
|
|
105
|
-
poster_el = helper.select_first(".poster img")
|
|
106
|
-
poster = self.fix_url(poster_el.attrs.get("src")) if poster_el else None
|
|
107
|
-
|
|
108
|
-
description = helper.select_text(".excerpt p")
|
|
109
|
-
|
|
110
|
-
# Robust metadata extraction using Regex
|
|
111
|
-
|
|
112
|
-
# Initialize year first
|
|
113
|
-
year = None
|
|
114
|
-
|
|
115
|
-
# Try .release first (legacy) or directly regex
|
|
116
|
-
rel_text = helper.select_text(".release")
|
|
117
|
-
if rel_text:
|
|
118
|
-
m_y = re.search(r"(\d{4})", rel_text)
|
|
119
|
-
if m_y: year = m_y.group(1)
|
|
120
|
-
|
|
121
|
-
# Year fallbacks
|
|
122
|
-
if not year:
|
|
123
|
-
# Try finding year in text like "Yapım: 2024" or just isolated year in release date
|
|
124
|
-
m_year = helper.regex_first(r"Yapım:\s*(\d{4})") or helper.regex_first(r"Yıl:\s*(\d{4})")
|
|
125
|
-
if m_year:
|
|
126
|
-
year = m_year
|
|
127
|
-
|
|
128
|
-
# Rating
|
|
129
|
-
rating_text = helper.select_text(".imdb-rating")
|
|
130
|
-
if rating_text:
|
|
131
|
-
rating = rating_text.replace("IMDB Puanı", "").strip()
|
|
132
|
-
else:
|
|
133
|
-
rating = helper.regex_first(r"IMDB\s*:\s*([\d\.]+)")
|
|
134
|
-
|
|
135
|
-
# Duration
|
|
136
|
-
duration = None
|
|
137
|
-
duration_val = helper.regex_first(r"Süre:\s*(\d+)")
|
|
138
|
-
if duration_val:
|
|
139
|
-
duration = int(duration_val)
|
|
140
101
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
# Fallback: Try .cast-list selector
|
|
151
|
-
if not actors_list:
|
|
152
|
-
actor_els = helper.select(".cast-list .actor-name, .cast-list a")
|
|
153
|
-
if actor_els:
|
|
154
|
-
actors_list = [el.text(strip=True) for el in actor_els if el.text(strip=True)]
|
|
155
|
-
|
|
156
|
-
if actors_list:
|
|
157
|
-
actors = ", ".join(actors_list)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
# Tags (Genres) - Extract from genre links
|
|
161
|
-
tags = None
|
|
162
|
-
tags_list = []
|
|
163
|
-
|
|
164
|
-
# Site uses: <a href=".../tur/...">Genre Name</a> or <a href=".../Kategori/tur/...">
|
|
165
|
-
tag_els = helper.select("a[href*='/tur/'], a[href*='/Kategori/tur/']")
|
|
166
|
-
if tag_els:
|
|
167
|
-
tags_list = [el.text(strip=True) for el in tag_els if el.text(strip=True)]
|
|
168
|
-
|
|
169
|
-
# Fallback: Try .genres selector
|
|
170
|
-
if not tags_list:
|
|
171
|
-
tag_els = helper.select(".genres a, .genre a")
|
|
172
|
-
if tag_els:
|
|
173
|
-
tags_list = [el.text(strip=True) for el in tag_els if el.text(strip=True)]
|
|
174
|
-
|
|
175
|
-
# Remove duplicates while preserving order
|
|
176
|
-
if tags_list:
|
|
177
|
-
seen = set()
|
|
178
|
-
unique_tags = []
|
|
179
|
-
for tag in tags_list:
|
|
180
|
-
if tag not in seen:
|
|
181
|
-
seen.add(tag)
|
|
182
|
-
unique_tags.append(tag)
|
|
183
|
-
tags = unique_tags if unique_tags else None
|
|
102
|
+
title = self.clean_title(helper.select_text("h1"))
|
|
103
|
+
poster = helper.select_poster(".poster img")
|
|
104
|
+
description = helper.select_text(".excerpt p")
|
|
105
|
+
year = helper.extract_year(".release", ".movie-info")
|
|
106
|
+
rating = helper.regex_first(r"([\d\.]+)", helper.select_text(".imdb-rating"))
|
|
107
|
+
duration = int(helper.regex_first(r"(\d+)", helper.select_text(".movie-info")) or 0)
|
|
108
|
+
tags = helper.select_texts("a[href*='/tur/'], a[href*='/Kategori/tur/']")
|
|
109
|
+
actors = helper.select_texts("a[href*='/oyuncular/']") or helper.select_texts(".cast-list .actor-name, .cast-list a")
|
|
184
110
|
|
|
185
|
-
|
|
186
|
-
# Check for Episodes to decide if Series or Movie
|
|
111
|
+
# Bölüm linklerini kontrol et
|
|
187
112
|
ep_elements = helper.select(".parts-middle a, .parts-middle .part.active")
|
|
188
|
-
|
|
113
|
+
|
|
189
114
|
if not ep_elements:
|
|
190
|
-
# Movie
|
|
191
115
|
return MovieInfo(
|
|
192
116
|
url = url,
|
|
193
|
-
title = title,
|
|
117
|
+
title = title or "Bilinmiyor",
|
|
194
118
|
description = description,
|
|
195
|
-
poster = poster,
|
|
196
|
-
year = year,
|
|
119
|
+
poster = self.fix_url(poster) if poster else None,
|
|
120
|
+
year = str(year) if year else None,
|
|
197
121
|
rating = rating,
|
|
198
122
|
duration = duration,
|
|
199
123
|
tags = tags,
|
|
200
124
|
actors = actors
|
|
201
125
|
)
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if s_match:
|
|
223
|
-
season = int(s_match.group(1))
|
|
224
|
-
if e_match:
|
|
225
|
-
episode = int(e_match.group(1))
|
|
226
|
-
|
|
227
|
-
episodes.append(Episode(
|
|
228
|
-
season = season,
|
|
229
|
-
episode = episode,
|
|
230
|
-
title = ep_name,
|
|
231
|
-
url = ep_href
|
|
232
|
-
))
|
|
233
|
-
|
|
234
|
-
return SeriesInfo(
|
|
235
|
-
url = url,
|
|
236
|
-
title = title,
|
|
237
|
-
description = description,
|
|
238
|
-
poster = poster,
|
|
239
|
-
year = year,
|
|
240
|
-
rating = rating,
|
|
241
|
-
duration = duration,
|
|
242
|
-
tags = tags,
|
|
243
|
-
actors = actors,
|
|
244
|
-
episodes = episodes
|
|
245
|
-
)
|
|
126
|
+
|
|
127
|
+
episodes = []
|
|
128
|
+
for i, el in enumerate(ep_elements):
|
|
129
|
+
name = helper.select_text(".part-name", el) or f"Bölüm {i+1}"
|
|
130
|
+
href = el.attrs.get("href") or url
|
|
131
|
+
s, e = helper.extract_season_episode(name)
|
|
132
|
+
episodes.append(Episode(season=s or 1, episode=e or (i + 1), title=name, url=self.fix_url(href)))
|
|
133
|
+
|
|
134
|
+
return SeriesInfo(
|
|
135
|
+
url = url,
|
|
136
|
+
title = title or "Bilinmiyor",
|
|
137
|
+
description = description,
|
|
138
|
+
poster = self.fix_url(poster) if poster else None,
|
|
139
|
+
year = str(year) if year else None,
|
|
140
|
+
rating = rating,
|
|
141
|
+
duration = duration,
|
|
142
|
+
tags = tags,
|
|
143
|
+
actors = actors,
|
|
144
|
+
episodes = episodes
|
|
145
|
+
)
|
|
246
146
|
|
|
247
147
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
248
148
|
istek = await self.httpx.get(url)
|