KekikStream 2.3.9__py3-none-any.whl → 2.5.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/Extractor/ExtractorLoader.py +8 -14
- KekikStream/Core/HTMLHelper.py +120 -49
- KekikStream/Core/Plugin/PluginBase.py +30 -12
- KekikStream/Core/Plugin/PluginLoader.py +12 -14
- KekikStream/Core/Plugin/PluginManager.py +2 -2
- KekikStream/Core/Plugin/PluginModels.py +0 -3
- KekikStream/Extractors/Abstream.py +27 -0
- 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 +21 -46
- KekikStream/Extractors/HDMomPlayer.py +30 -0
- KekikStream/Extractors/HDPlayerSystem.py +13 -31
- KekikStream/Extractors/HotStream.py +27 -0
- KekikStream/Extractors/JFVid.py +3 -24
- KekikStream/Extractors/JetTv.py +21 -34
- KekikStream/Extractors/JetV.py +55 -0
- 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 +40 -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/Veev.py +145 -0
- KekikStream/Extractors/VidBiz.py +62 -0
- KekikStream/Extractors/VidHide.py +58 -30
- 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 +58 -0
- KekikStream/Extractors/Vidoza.py +18 -0
- KekikStream/Extractors/Vtbe.py +38 -0
- KekikStream/Extractors/YTDLP.py +2 -2
- KekikStream/Extractors/YildizKisaFilm.py +13 -31
- KekikStream/Extractors/Zeus.py +61 -0
- KekikStream/Plugins/BelgeselX.py +97 -77
- KekikStream/Plugins/DiziBox.py +28 -45
- KekikStream/Plugins/DiziMom.py +179 -0
- KekikStream/Plugins/DiziPal.py +95 -161
- KekikStream/Plugins/DiziYou.py +51 -147
- KekikStream/Plugins/Dizilla.py +40 -61
- KekikStream/Plugins/FilmBip.py +90 -39
- KekikStream/Plugins/FilmEkseni.py +199 -0
- KekikStream/Plugins/FilmMakinesi.py +72 -73
- KekikStream/Plugins/FilmModu.py +25 -35
- KekikStream/Plugins/Filmatek.py +184 -0
- KekikStream/Plugins/FilmciBaba.py +155 -0
- KekikStream/Plugins/FullHDFilmizlesene.py +16 -37
- KekikStream/Plugins/HDFilm.py +243 -0
- KekikStream/Plugins/HDFilmCehennemi.py +242 -189
- KekikStream/Plugins/JetFilmizle.py +101 -69
- KekikStream/Plugins/KultFilmler.py +138 -104
- KekikStream/Plugins/RecTV.py +52 -73
- KekikStream/Plugins/RoketDizi.py +18 -27
- KekikStream/Plugins/SelcukFlix.py +30 -48
- KekikStream/Plugins/SetFilmIzle.py +76 -104
- KekikStream/Plugins/SezonlukDizi.py +90 -94
- KekikStream/Plugins/Sinefy.py +195 -167
- KekikStream/Plugins/SinemaCX.py +148 -78
- KekikStream/Plugins/Sinezy.py +29 -31
- KekikStream/Plugins/SuperFilmGeldi.py +12 -17
- KekikStream/Plugins/UgurFilm.py +85 -38
- KekikStream/Plugins/Watch32.py +160 -0
- KekikStream/Plugins/YabanciDizi.py +176 -211
- {kekikstream-2.3.9.dist-info → kekikstream-2.5.3.dist-info}/METADATA +1 -1
- kekikstream-2.5.3.dist-info/RECORD +99 -0
- {kekikstream-2.3.9.dist-info → kekikstream-2.5.3.dist-info}/WHEEL +1 -1
- KekikStream/Plugins/FullHDFilm.py +0 -249
- kekikstream-2.3.9.dist-info/RECORD +0 -84
- {kekikstream-2.3.9.dist-info → kekikstream-2.5.3.dist-info}/entry_points.txt +0 -0
- {kekikstream-2.3.9.dist-info → kekikstream-2.5.3.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-2.3.9.dist-info → kekikstream-2.5.3.dist-info}/top_level.txt +0 -0
KekikStream/Plugins/DiziYou.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, Subtitle, ExtractResult, HTMLHelper
|
|
4
4
|
|
|
5
5
|
class DiziYou(PluginBase):
|
|
6
6
|
name = "DiziYou"
|
|
@@ -42,7 +42,7 @@ class DiziYou(PluginBase):
|
|
|
42
42
|
category = category,
|
|
43
43
|
title = title,
|
|
44
44
|
url = self.fix_url(href),
|
|
45
|
-
poster = self.fix_url(poster)
|
|
45
|
+
poster = self.fix_url(poster),
|
|
46
46
|
))
|
|
47
47
|
|
|
48
48
|
return results
|
|
@@ -61,7 +61,7 @@ class DiziYou(PluginBase):
|
|
|
61
61
|
results.append(SearchResult(
|
|
62
62
|
title = title,
|
|
63
63
|
url = self.fix_url(href),
|
|
64
|
-
poster = self.fix_url(poster)
|
|
64
|
+
poster = self.fix_url(poster),
|
|
65
65
|
))
|
|
66
66
|
|
|
67
67
|
return results
|
|
@@ -69,87 +69,29 @@ 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
|
+
raw_actors = secici.meta_value("Oyuncular", container_selector="div#icerikcat2")
|
|
80
|
+
actors = [x.strip() for x in raw_actors.split(",")] if raw_actors else None
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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(
|
|
90
|
+
season = s or 1,
|
|
91
|
+
episode = e,
|
|
92
|
+
title = name,
|
|
93
|
+
url = self.fix_url(href)
|
|
94
|
+
))
|
|
153
95
|
|
|
154
96
|
return SeriesInfo(
|
|
155
97
|
url = url,
|
|
@@ -167,77 +109,39 @@ class DiziYou(PluginBase):
|
|
|
167
109
|
istek = await self.httpx.get(url)
|
|
168
110
|
secici = HTMLHelper(istek.text)
|
|
169
111
|
|
|
170
|
-
#
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
if not player_src:
|
|
186
|
-
for a in secici.select("a"):
|
|
187
|
-
href = secici.select_attr("a", "href", a)
|
|
188
|
-
if not href:
|
|
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
|
-
})
|
|
112
|
+
# Player iframe'inden ID'yi yakala
|
|
113
|
+
iframe_src = secici.select_attr("iframe#diziyouPlayer", "src") or secici.select_attr("iframe[src*='/player/']", "src")
|
|
114
|
+
if not iframe_src:
|
|
115
|
+
return []
|
|
116
|
+
|
|
117
|
+
item_id = iframe_src.split("/")[-1].replace(".html", "")
|
|
118
|
+
base_storage = self.main_url.replace("www", "storage")
|
|
119
|
+
|
|
120
|
+
subtitles = []
|
|
121
|
+
for sub in [("turkceAltyazili", "tr", "Türkçe"), ("ingilizceAltyazili", "en", "İngilizce")]:
|
|
122
|
+
if secici.select_first(f"span#{sub[0]}"):
|
|
123
|
+
subtitles.append(Subtitle(
|
|
124
|
+
name = f"{sub[2]} Altyazı",
|
|
125
|
+
url = f"{base_storage}/subtitles/{item_id}/{sub[1]}.vtt"
|
|
126
|
+
))
|
|
233
127
|
|
|
234
128
|
results = []
|
|
235
|
-
|
|
129
|
+
# Altyazılı Seçenek (Eğer varsa)
|
|
130
|
+
if secici.select_first("span#turkceAltyazili") or secici.select_first("span#ingilizceAltyazili"):
|
|
131
|
+
results.append(ExtractResult(
|
|
132
|
+
name = "Altyazılı",
|
|
133
|
+
url = f"{base_storage}/episodes/{item_id}/play.m3u8",
|
|
134
|
+
referer = url,
|
|
135
|
+
subtitles = subtitles
|
|
136
|
+
))
|
|
137
|
+
|
|
138
|
+
# Dublaj Seçeneği (Eğer varsa)
|
|
139
|
+
if secici.select_first("span#turkceDublaj"):
|
|
236
140
|
results.append(ExtractResult(
|
|
237
|
-
|
|
238
|
-
|
|
141
|
+
name = "Türkçe Dublaj",
|
|
142
|
+
url = f"{base_storage}/episodes/{item_id}_tr/play.m3u8",
|
|
239
143
|
referer = url,
|
|
240
144
|
subtitles = subtitles
|
|
241
145
|
))
|
|
242
146
|
|
|
243
|
-
return results
|
|
147
|
+
return results
|
KekikStream/Plugins/Dizilla.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core
|
|
4
|
-
from json
|
|
5
|
-
from urllib.parse
|
|
6
|
-
from Crypto.Cipher
|
|
7
|
-
from base64
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
|
|
4
|
+
from json import loads
|
|
5
|
+
from urllib.parse import urlparse, urlunparse
|
|
6
|
+
from Crypto.Cipher import AES
|
|
7
|
+
from base64 import b64decode
|
|
8
8
|
|
|
9
9
|
class Dizilla(PluginBase):
|
|
10
10
|
name = "Dizilla"
|
|
@@ -44,7 +44,7 @@ class Dizilla(PluginBase):
|
|
|
44
44
|
category = category,
|
|
45
45
|
title = veri.get("original_title"),
|
|
46
46
|
url = self.fix_url(f"{self.main_url}/{veri.get('used_slug')}"),
|
|
47
|
-
poster = self.fix_poster_url(self.fix_url(veri.get("
|
|
47
|
+
poster = self.fix_poster_url(self.fix_url(veri.get("poster_url"))),
|
|
48
48
|
)
|
|
49
49
|
for veri in veriler
|
|
50
50
|
])
|
|
@@ -54,21 +54,21 @@ class Dizilla(PluginBase):
|
|
|
54
54
|
|
|
55
55
|
# Genel olarak dizi sayfalarına giden linkleri al
|
|
56
56
|
for veri in secici.select('a[href*="/dizi/"]'):
|
|
57
|
-
href
|
|
57
|
+
href = secici.select_attr('a', 'href', veri)
|
|
58
58
|
title = secici.select_text(None, veri)
|
|
59
59
|
if not href or not title:
|
|
60
60
|
continue
|
|
61
61
|
|
|
62
62
|
# Detay sayfasından poster vb. bilgileri al
|
|
63
|
-
ep_req
|
|
63
|
+
ep_req = await self.httpx.get(self.fix_url(href))
|
|
64
64
|
ep_secici = HTMLHelper(ep_req.text)
|
|
65
|
-
poster
|
|
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,
|
|
69
69
|
title = title,
|
|
70
70
|
url = self.fix_url(href),
|
|
71
|
-
poster = self.fix_url(poster)
|
|
71
|
+
poster = self.fix_url(poster)
|
|
72
72
|
))
|
|
73
73
|
|
|
74
74
|
return ana_sayfa
|
|
@@ -155,43 +155,25 @@ class Dizilla(PluginBase):
|
|
|
155
155
|
description = content.get("description") or content.get("used_description")
|
|
156
156
|
rating = content.get("imdb_point") or content.get("local_vote_avg")
|
|
157
157
|
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
|
|
158
|
+
poster = self.fix_poster_url(self.fix_url(content.get("back_url") or content.get("poster_url")))
|
|
188
159
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
160
|
+
tags = [cat.get("name") for cat in decrypted.get("RelatedResults", {}).get("getSerieCategoriesById", {}).get("result", [])]
|
|
161
|
+
actors = [cast.get("name") for cast in decrypted.get("RelatedResults", {}).get("getSerieCastsById", {}).get("result", [])]
|
|
162
|
+
|
|
163
|
+
episodes = []
|
|
164
|
+
for season in decrypted.get("RelatedResults", {}).get("getSerieSeasonAndEpisodes", {}).get("result", []):
|
|
165
|
+
s_no = season.get("season_no")
|
|
166
|
+
for ep in season.get("episodes", []):
|
|
167
|
+
e_no = ep.get("episode_no")
|
|
168
|
+
slug = ep.get("used_slug")
|
|
169
|
+
name = ep.get("episode_text") or ""
|
|
170
|
+
if not any(e.season == s_no and e.episode == e_no for e in episodes):
|
|
171
|
+
episodes.append(Episode(
|
|
172
|
+
season = s_no,
|
|
173
|
+
episode = e_no,
|
|
174
|
+
title = name,
|
|
175
|
+
url = self.fix_url(f"{self.main_url}/{slug}")
|
|
176
|
+
))
|
|
195
177
|
|
|
196
178
|
return SeriesInfo(
|
|
197
179
|
url = url,
|
|
@@ -199,21 +181,21 @@ class Dizilla(PluginBase):
|
|
|
199
181
|
title = title,
|
|
200
182
|
description = description,
|
|
201
183
|
tags = tags,
|
|
202
|
-
rating =
|
|
203
|
-
year =
|
|
184
|
+
rating = rating,
|
|
185
|
+
year = year,
|
|
204
186
|
episodes = episodes,
|
|
205
187
|
actors = actors
|
|
206
188
|
)
|
|
207
189
|
|
|
208
190
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
209
|
-
istek
|
|
210
|
-
secici
|
|
191
|
+
istek = await self.httpx.get(url)
|
|
192
|
+
secici = HTMLHelper(istek.text)
|
|
211
193
|
|
|
212
194
|
next_data_text = secici.select_text("script#__NEXT_DATA__")
|
|
213
195
|
if not next_data_text:
|
|
214
196
|
return []
|
|
215
197
|
|
|
216
|
-
next_data
|
|
198
|
+
next_data = loads(next_data_text)
|
|
217
199
|
secure_data = next_data.get("props", {}).get("pageProps", {}).get("secureData", {})
|
|
218
200
|
decrypted = await self.decrypt_response(secure_data)
|
|
219
201
|
results = decrypted.get("RelatedResults", {}).get("getEpisodeSources", {}).get("result", [])
|
|
@@ -221,24 +203,21 @@ class Dizilla(PluginBase):
|
|
|
221
203
|
if not results:
|
|
222
204
|
return []
|
|
223
205
|
|
|
224
|
-
|
|
225
|
-
first_result = results[0]
|
|
206
|
+
first_result = results[0]
|
|
226
207
|
source_content = str(first_result.get("source_content", ""))
|
|
227
|
-
|
|
228
|
-
# Clean the source_content string (matching Kotlin: .replace("\"", "").replace("\\", ""))
|
|
208
|
+
|
|
229
209
|
cleaned_source = source_content.replace('"', '').replace('\\', '')
|
|
230
|
-
|
|
231
|
-
# Parse cleaned HTML
|
|
210
|
+
|
|
232
211
|
iframe_secici = HTMLHelper(cleaned_source)
|
|
233
|
-
iframe_src
|
|
234
|
-
|
|
235
|
-
# Referer check (matching Kotlin: loadExtractor(iframe, "${mainUrl}/", ...))
|
|
212
|
+
iframe_src = iframe_secici.select_attr("iframe", "src")
|
|
213
|
+
|
|
236
214
|
iframe_url = self.fix_url(iframe_src) if iframe_src else None
|
|
237
|
-
|
|
215
|
+
|
|
238
216
|
if not iframe_url:
|
|
239
217
|
return []
|
|
240
218
|
|
|
241
219
|
data = await self.extract(iframe_url, referer=f"{self.main_url}/", prefix=first_result.get('language_name', 'Unknown'))
|
|
242
220
|
if not data:
|
|
243
221
|
return []
|
|
222
|
+
|
|
244
223
|
return data if isinstance(data, list) else [data]
|
KekikStream/Plugins/FilmBip.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult, HTMLHelper
|
|
4
|
+
from contextlib import suppress
|
|
4
5
|
|
|
5
6
|
class FilmBip(PluginBase):
|
|
6
7
|
name = "FilmBip"
|
|
@@ -39,8 +40,8 @@ class FilmBip(PluginBase):
|
|
|
39
40
|
|
|
40
41
|
results = []
|
|
41
42
|
for veri in secici.select("div.poster-long"):
|
|
42
|
-
title
|
|
43
|
-
href
|
|
43
|
+
title = secici.select_attr("a.block img.lazy", "alt", veri)
|
|
44
|
+
href = secici.select_attr("a.block", "href", veri)
|
|
44
45
|
poster = secici.select_poster("a.block img.lazy", veri)
|
|
45
46
|
|
|
46
47
|
if title and href:
|
|
@@ -48,7 +49,7 @@ class FilmBip(PluginBase):
|
|
|
48
49
|
category = category,
|
|
49
50
|
title = title,
|
|
50
51
|
url = self.fix_url(href),
|
|
51
|
-
poster = self.fix_url(poster)
|
|
52
|
+
poster = self.fix_url(poster),
|
|
52
53
|
))
|
|
53
54
|
|
|
54
55
|
return results
|
|
@@ -87,7 +88,7 @@ class FilmBip(PluginBase):
|
|
|
87
88
|
results.append(SearchResult(
|
|
88
89
|
title = title.strip(),
|
|
89
90
|
url = self.fix_url(href),
|
|
90
|
-
poster = self.fix_url(poster)
|
|
91
|
+
poster = self.fix_url(poster),
|
|
91
92
|
))
|
|
92
93
|
|
|
93
94
|
return results
|
|
@@ -95,40 +96,26 @@ class FilmBip(PluginBase):
|
|
|
95
96
|
async def load_item(self, url: str) -> MovieInfo:
|
|
96
97
|
istek = await self.httpx.get(url)
|
|
97
98
|
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
99
|
|
|
100
|
+
title = self.clean_title(secici.select_direct_text("div.page-title h1"))
|
|
101
|
+
poster = secici.select_poster("div.series-profile-image a img")
|
|
106
102
|
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")]
|
|
103
|
+
tags = secici.select_texts("div.series-profile-type.tv-show-profile-type a")
|
|
104
|
+
year = secici.extract_year("div.series-profile-infos-in") or secici.regex_first(r"\((\d{4})\)", title)
|
|
105
|
+
duration = secici.regex_first(r"(\d+)", secici.meta_value("Süre", container_selector="div.series-profile-infos"))
|
|
106
|
+
rating = secici.meta_value("IMDB Puanı", container_selector="div.series-profile-infos")
|
|
107
|
+
rating = rating.split("(")[0] if rating else None
|
|
108
|
+
actors = secici.select_attrs("div.series-profile-cast ul li a img", "alt")
|
|
122
109
|
|
|
123
110
|
return MovieInfo(
|
|
124
111
|
url = url,
|
|
125
|
-
poster = self.fix_url(poster)
|
|
126
|
-
title =
|
|
112
|
+
poster = self.fix_url(poster),
|
|
113
|
+
title = title,
|
|
127
114
|
description = description,
|
|
128
115
|
tags = tags,
|
|
129
116
|
year = year,
|
|
130
117
|
rating = rating,
|
|
131
|
-
duration =
|
|
118
|
+
duration = duration,
|
|
132
119
|
actors = actors,
|
|
133
120
|
)
|
|
134
121
|
|
|
@@ -137,14 +124,78 @@ class FilmBip(PluginBase):
|
|
|
137
124
|
secici = HTMLHelper(istek.text)
|
|
138
125
|
|
|
139
126
|
results = []
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
127
|
+
for tab in secici.select("ul.tab.alternative-group li[data-number]"):
|
|
128
|
+
tab_id = tab.attrs.get("data-number")
|
|
129
|
+
tab_name = secici.select_text(None, tab)
|
|
130
|
+
tab_hash = tab.attrs.get("data-group-hash")
|
|
131
|
+
|
|
132
|
+
if not tab_id:
|
|
133
|
+
continue
|
|
134
|
+
|
|
135
|
+
button_data = [] # (player_name, iframe_url)
|
|
136
|
+
|
|
137
|
+
# İlgili content divini bul
|
|
138
|
+
content_div = secici.select_first(f"div#{tab_id}")
|
|
139
|
+
|
|
140
|
+
# Eğer div var ve içi doluysa oradan al
|
|
141
|
+
if content_div and secici.select("ul li button", content_div):
|
|
142
|
+
buttons = secici.select("ul li button", content_div)
|
|
143
|
+
for btn in buttons:
|
|
144
|
+
button_data.append((btn.text(strip=True), btn.attrs.get("data-hhs")))
|
|
145
|
+
|
|
146
|
+
elif tab_hash:
|
|
147
|
+
# Div yok veya boş, AJAX ile çek
|
|
148
|
+
with suppress(Exception):
|
|
149
|
+
hash_resp = await self.httpx.post(
|
|
150
|
+
url = f"{self.main_url}/get/video/group",
|
|
151
|
+
headers = {
|
|
152
|
+
"X-Requested-With" : "XMLHttpRequest",
|
|
153
|
+
"Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
|
|
154
|
+
"Referer" : url
|
|
155
|
+
},
|
|
156
|
+
data = {"hash": tab_hash}
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
if hash_resp.status_code == 200:
|
|
160
|
+
json_data = hash_resp.json()
|
|
161
|
+
if json_data.get("success"):
|
|
162
|
+
# 1. Videos listesi (API yanıtı)
|
|
163
|
+
if videos := json_data.get("videos"):
|
|
164
|
+
for vid in videos:
|
|
165
|
+
button_data.append((vid.get("name"), vid.get("link")))
|
|
166
|
+
|
|
167
|
+
# 2. HTML content (Fallback)
|
|
168
|
+
else:
|
|
169
|
+
html_content = json_data.get("content") or json_data.get("html") or json_data.get("theme")
|
|
170
|
+
if html_content:
|
|
171
|
+
sub_helper = HTMLHelper(html_content)
|
|
172
|
+
sub_btns = sub_helper.select("ul li button")
|
|
173
|
+
for btn in sub_btns:
|
|
174
|
+
button_data.append((btn.text(strip=True), btn.attrs.get("data-hhs")))
|
|
175
|
+
|
|
176
|
+
for player_name, iframe_url in button_data:
|
|
177
|
+
with suppress(Exception):
|
|
178
|
+
if iframe_url:
|
|
179
|
+
data = await self.extract(
|
|
180
|
+
url = self.fix_url(iframe_url),
|
|
181
|
+
name_override = f"{tab_name} | {player_name}"
|
|
182
|
+
)
|
|
183
|
+
if data:
|
|
184
|
+
if isinstance(data, list):
|
|
185
|
+
results.extend(data)
|
|
186
|
+
else:
|
|
187
|
+
results.append(data)
|
|
188
|
+
|
|
189
|
+
# Eğer hiç sonuç bulunamazsa fallback
|
|
190
|
+
if not results:
|
|
191
|
+
for player in secici.select("div#tv-spoox2"):
|
|
192
|
+
if iframe := secici.select_attr("iframe", "src", player):
|
|
193
|
+
iframe = self.fix_url(iframe)
|
|
194
|
+
data = await self.extract(iframe)
|
|
195
|
+
if data:
|
|
196
|
+
if isinstance(data, list):
|
|
197
|
+
results.extend(data)
|
|
198
|
+
else:
|
|
199
|
+
results.append(data)
|
|
149
200
|
|
|
150
201
|
return results
|