KekikStream 2.2.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 +205 -0
- KekikStream/Core/Plugin/PluginBase.py +48 -12
- KekikStream/Core/Plugin/PluginLoader.py +13 -14
- KekikStream/Core/Plugin/PluginManager.py +2 -2
- KekikStream/Core/Plugin/PluginModels.py +0 -3
- KekikStream/Core/__init__.py +2 -0
- KekikStream/Extractors/Abstream.py +27 -0
- KekikStream/Extractors/CloseLoad.py +31 -56
- KekikStream/Extractors/ContentX.py +28 -71
- KekikStream/Extractors/DonilasPlay.py +34 -78
- KekikStream/Extractors/DzenRu.py +11 -25
- KekikStream/Extractors/ExPlay.py +20 -38
- KekikStream/Extractors/Filemoon.py +23 -53
- 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 +17 -31
- KekikStream/Extractors/MixTiger.py +17 -40
- KekikStream/Extractors/MolyStream.py +25 -22
- KekikStream/Extractors/Odnoklassniki.py +41 -105
- KekikStream/Extractors/PeaceMakerst.py +20 -47
- KekikStream/Extractors/PixelDrain.py +9 -16
- KekikStream/Extractors/PlayerFilmIzle.py +23 -46
- KekikStream/Extractors/RapidVid.py +23 -36
- KekikStream/Extractors/SetPlay.py +19 -44
- KekikStream/Extractors/SetPrime.py +3 -6
- KekikStream/Extractors/SibNet.py +8 -19
- KekikStream/Extractors/Sobreatsesuyp.py +25 -47
- KekikStream/Extractors/TRsTX.py +25 -55
- KekikStream/Extractors/TurboImgz.py +8 -16
- KekikStream/Extractors/TurkeyPlayer.py +5 -5
- KekikStream/Extractors/VCTPlay.py +10 -28
- KekikStream/Extractors/Veev.py +145 -0
- KekikStream/Extractors/VidBiz.py +62 -0
- KekikStream/Extractors/VidHide.py +59 -34
- KekikStream/Extractors/VidMoly.py +67 -89
- KekikStream/Extractors/VidMoxy.py +17 -29
- KekikStream/Extractors/VidPapi.py +26 -58
- KekikStream/Extractors/VideoSeyred.py +21 -42
- 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 +108 -99
- KekikStream/Plugins/DiziBox.py +61 -106
- KekikStream/Plugins/DiziMom.py +179 -0
- KekikStream/Plugins/DiziPal.py +104 -192
- KekikStream/Plugins/DiziYou.py +66 -149
- KekikStream/Plugins/Dizilla.py +93 -126
- KekikStream/Plugins/FilmBip.py +102 -72
- KekikStream/Plugins/FilmEkseni.py +199 -0
- KekikStream/Plugins/FilmMakinesi.py +101 -64
- KekikStream/Plugins/FilmModu.py +35 -59
- KekikStream/Plugins/Filmatek.py +184 -0
- KekikStream/Plugins/FilmciBaba.py +155 -0
- KekikStream/Plugins/FullHDFilmizlesene.py +32 -78
- KekikStream/Plugins/HDFilm.py +243 -0
- KekikStream/Plugins/HDFilmCehennemi.py +261 -222
- KekikStream/Plugins/JetFilmizle.py +117 -98
- KekikStream/Plugins/KultFilmler.py +153 -143
- KekikStream/Plugins/RecTV.py +53 -49
- KekikStream/Plugins/RoketDizi.py +92 -123
- KekikStream/Plugins/SelcukFlix.py +86 -95
- KekikStream/Plugins/SetFilmIzle.py +105 -143
- KekikStream/Plugins/SezonlukDizi.py +106 -128
- KekikStream/Plugins/Sinefy.py +194 -166
- KekikStream/Plugins/SinemaCX.py +159 -113
- KekikStream/Plugins/Sinezy.py +44 -73
- KekikStream/Plugins/SuperFilmGeldi.py +28 -52
- KekikStream/Plugins/UgurFilm.py +94 -72
- KekikStream/Plugins/Watch32.py +160 -0
- KekikStream/Plugins/YabanciDizi.py +250 -0
- {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/METADATA +1 -1
- kekikstream-2.5.3.dist-info/RECORD +99 -0
- {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/WHEEL +1 -1
- KekikStream/Plugins/FullHDFilm.py +0 -254
- kekikstream-2.2.9.dist-info/RECORD +0 -82
- {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/entry_points.txt +0 -0
- {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/top_level.txt +0 -0
KekikStream/Plugins/DiziYou.py
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core
|
|
4
|
-
from selectolax.parser import HTMLParser
|
|
5
|
-
import re
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, Subtitle, ExtractResult, HTMLHelper
|
|
6
4
|
|
|
7
5
|
class DiziYou(PluginBase):
|
|
8
6
|
name = "DiziYou"
|
|
@@ -31,125 +29,69 @@ class DiziYou(PluginBase):
|
|
|
31
29
|
|
|
32
30
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
33
31
|
istek = await self.httpx.get(f"{url.replace('SAYFA', str(page))}")
|
|
34
|
-
secici =
|
|
32
|
+
secici = HTMLHelper(istek.text)
|
|
35
33
|
|
|
36
34
|
results = []
|
|
37
|
-
for veri in secici.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
title = title_el.text(strip=True) if title_el else None
|
|
42
|
-
href = title_el.attrs.get("href") if title_el else None
|
|
43
|
-
poster = img_el.attrs.get("src") if img_el else None
|
|
35
|
+
for veri in secici.select("div.single-item"):
|
|
36
|
+
title = secici.select_text("div#categorytitle a", veri)
|
|
37
|
+
href = secici.select_attr("div#categorytitle a", "href", veri)
|
|
38
|
+
poster = secici.select_attr("img", "src", veri)
|
|
44
39
|
|
|
45
40
|
if title and href:
|
|
46
41
|
results.append(MainPageResult(
|
|
47
42
|
category = category,
|
|
48
43
|
title = title,
|
|
49
44
|
url = self.fix_url(href),
|
|
50
|
-
poster = self.fix_url(poster)
|
|
45
|
+
poster = self.fix_url(poster),
|
|
51
46
|
))
|
|
52
47
|
|
|
53
48
|
return results
|
|
54
49
|
|
|
55
50
|
async def search(self, query: str) -> list[SearchResult]:
|
|
56
51
|
istek = await self.httpx.get(f"{self.main_url}/?s={query}")
|
|
57
|
-
secici =
|
|
52
|
+
secici = HTMLHelper(istek.text)
|
|
58
53
|
|
|
59
54
|
results = []
|
|
60
|
-
for afis in secici.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
title = title_el.text(strip=True) if title_el else None
|
|
65
|
-
href = title_el.attrs.get("href") if title_el else None
|
|
66
|
-
poster = (img_el.attrs.get("src") or img_el.attrs.get("data-src")) if img_el else None
|
|
55
|
+
for afis in secici.select("div.incontent div#list-series"):
|
|
56
|
+
title = secici.select_text("div#categorytitle a", afis)
|
|
57
|
+
href = secici.select_attr("div#categorytitle a", "href", afis)
|
|
58
|
+
poster = (secici.select_attr("img", "src", afis) or secici.select_attr("img", "data-src", afis))
|
|
67
59
|
|
|
68
60
|
if title and href:
|
|
69
61
|
results.append(SearchResult(
|
|
70
62
|
title = title,
|
|
71
63
|
url = self.fix_url(href),
|
|
72
|
-
poster = self.fix_url(poster)
|
|
64
|
+
poster = self.fix_url(poster),
|
|
73
65
|
))
|
|
74
66
|
|
|
75
67
|
return results
|
|
76
68
|
|
|
77
69
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
78
70
|
istek = await self.httpx.get(url)
|
|
79
|
-
secici =
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
slug = url.rstrip('/').split('/')[-1]
|
|
90
|
-
title = slug.replace('-', ' ').title()
|
|
91
|
-
|
|
92
|
-
# Poster
|
|
93
|
-
poster_el = secici.css_first("div.category_image img")
|
|
94
|
-
poster = self.fix_url(poster_el.attrs.get("src")) if poster_el else ""
|
|
95
|
-
|
|
96
|
-
# Year - regex ile çıkarma (xpath yerine)
|
|
97
|
-
year = None
|
|
98
|
-
year_match = re.search(r"Yapım Yılı.*?(\d{4})", html_text, re.DOTALL | re.IGNORECASE)
|
|
99
|
-
if year_match:
|
|
100
|
-
year = year_match.group(1)
|
|
101
|
-
|
|
102
|
-
desc_el = secici.css_first("div.diziyou_desc")
|
|
103
|
-
description = desc_el.text(strip=True) if desc_el else None
|
|
104
|
-
|
|
105
|
-
tags = [a.text(strip=True) for a in secici.css("div.genres a") if a.text(strip=True)]
|
|
106
|
-
|
|
107
|
-
# Rating - regex ile
|
|
108
|
-
rating = None
|
|
109
|
-
rating_match = re.search(r"IMDB.*?([0-9.]+)", html_text, re.DOTALL | re.IGNORECASE)
|
|
110
|
-
if rating_match:
|
|
111
|
-
rating = rating_match.group(1)
|
|
112
|
-
|
|
113
|
-
# Actors - regex ile
|
|
114
|
-
actors = []
|
|
115
|
-
actors_match = re.search(r"Oyuncular.*?</span>([^<]+)", html_text, re.DOTALL | re.IGNORECASE)
|
|
116
|
-
if actors_match:
|
|
117
|
-
actors = [actor.strip() for actor in actors_match.group(1).split(",") if actor.strip()]
|
|
71
|
+
secici = HTMLHelper(istek.text)
|
|
72
|
+
|
|
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
|
|
118
81
|
|
|
119
82
|
episodes = []
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if not ep_href:
|
|
133
|
-
continue
|
|
134
|
-
|
|
135
|
-
# Bölüm ismi varsa al
|
|
136
|
-
bolumismi_el = link.css_first("div.bolumismi")
|
|
137
|
-
ep_name_clean = bolumismi_el.text(strip=True).replace("(", "").replace(")", "").strip() if bolumismi_el else ep_name
|
|
138
|
-
|
|
139
|
-
ep_episode_match = re.search(r"(\d+)\. Bölüm", ep_name)
|
|
140
|
-
ep_season_match = re.search(r"(\d+)\. Sezon", ep_name)
|
|
141
|
-
|
|
142
|
-
ep_episode = ep_episode_match.group(1) if ep_episode_match else None
|
|
143
|
-
ep_season = ep_season_match.group(1) if ep_season_match else None
|
|
144
|
-
|
|
145
|
-
if ep_episode and ep_season:
|
|
146
|
-
episode = Episode(
|
|
147
|
-
season = ep_season,
|
|
148
|
-
episode = ep_episode,
|
|
149
|
-
title = ep_name_clean,
|
|
150
|
-
url = self.fix_url(ep_href),
|
|
151
|
-
)
|
|
152
|
-
episodes.append(episode)
|
|
83
|
+
for link in secici.select("div#scrollbar-container a"):
|
|
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,
|
|
@@ -165,66 +107,41 @@ class DiziYou(PluginBase):
|
|
|
165
107
|
|
|
166
108
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
167
109
|
istek = await self.httpx.get(url)
|
|
168
|
-
secici =
|
|
169
|
-
|
|
170
|
-
#
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
subtitles = []
|
|
186
|
-
stream_urls = []
|
|
187
|
-
|
|
188
|
-
for secenek in secici.css("span.diziyouOption"):
|
|
189
|
-
opt_id = secenek.attrs.get("id")
|
|
190
|
-
op_name = secenek.text(strip=True)
|
|
191
|
-
|
|
192
|
-
match opt_id:
|
|
193
|
-
case "turkceAltyazili":
|
|
194
|
-
subtitles.append(Subtitle(
|
|
195
|
-
name = op_name,
|
|
196
|
-
url = self.fix_url(f"{self.main_url.replace('www', 'storage')}/subtitles/{item_id}/tr.vtt"),
|
|
197
|
-
))
|
|
198
|
-
veri = {
|
|
199
|
-
"dil": "Orjinal Dil (TR Altyazı)",
|
|
200
|
-
"url": f"{self.main_url.replace('www', 'storage')}/episodes/{item_id}/play.m3u8"
|
|
201
|
-
}
|
|
202
|
-
if veri not in stream_urls:
|
|
203
|
-
stream_urls.append(veri)
|
|
204
|
-
case "ingilizceAltyazili":
|
|
205
|
-
subtitles.append(Subtitle(
|
|
206
|
-
name = op_name,
|
|
207
|
-
url = self.fix_url(f"{self.main_url.replace('www', 'storage')}/subtitles/{item_id}/en.vtt"),
|
|
208
|
-
))
|
|
209
|
-
veri = {
|
|
210
|
-
"dil": "Orjinal Dil (EN Altyazı)",
|
|
211
|
-
"url": f"{self.main_url.replace('www', 'storage')}/episodes/{item_id}/play.m3u8"
|
|
212
|
-
}
|
|
213
|
-
if veri not in stream_urls:
|
|
214
|
-
stream_urls.append(veri)
|
|
215
|
-
case "turkceDublaj":
|
|
216
|
-
stream_urls.append({
|
|
217
|
-
"dil": "Türkçe Dublaj",
|
|
218
|
-
"url": f"{self.main_url.replace('www', 'storage')}/episodes/{item_id}_tr/play.m3u8"
|
|
219
|
-
})
|
|
110
|
+
secici = HTMLHelper(istek.text)
|
|
111
|
+
|
|
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
|
+
))
|
|
220
127
|
|
|
221
128
|
results = []
|
|
222
|
-
|
|
129
|
+
# Altyazılı Seçenek (Eğer varsa)
|
|
130
|
+
if secici.select_first("span#turkceAltyazili") or secici.select_first("span#ingilizceAltyazili"):
|
|
223
131
|
results.append(ExtractResult(
|
|
224
|
-
|
|
225
|
-
|
|
132
|
+
name = "Altyazılı",
|
|
133
|
+
url = f"{base_storage}/episodes/{item_id}/play.m3u8",
|
|
226
134
|
referer = url,
|
|
227
135
|
subtitles = subtitles
|
|
228
136
|
))
|
|
229
137
|
|
|
230
|
-
|
|
138
|
+
# Dublaj Seçeneği (Eğer varsa)
|
|
139
|
+
if secici.select_first("span#turkceDublaj"):
|
|
140
|
+
results.append(ExtractResult(
|
|
141
|
+
name = "Türkçe Dublaj",
|
|
142
|
+
url = f"{base_storage}/episodes/{item_id}_tr/play.m3u8",
|
|
143
|
+
referer = url,
|
|
144
|
+
subtitles = subtitles
|
|
145
|
+
))
|
|
146
|
+
|
|
147
|
+
return results
|
KekikStream/Plugins/Dizilla.py
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from
|
|
7
|
-
from
|
|
8
|
-
from base64 import b64decode
|
|
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
|
|
9
8
|
|
|
10
9
|
class Dizilla(PluginBase):
|
|
11
10
|
name = "Dizilla"
|
|
@@ -45,51 +44,32 @@ class Dizilla(PluginBase):
|
|
|
45
44
|
category = category,
|
|
46
45
|
title = veri.get("original_title"),
|
|
47
46
|
url = self.fix_url(f"{self.main_url}/{veri.get('used_slug')}"),
|
|
48
|
-
poster = self.fix_url(veri.get("
|
|
47
|
+
poster = self.fix_poster_url(self.fix_url(veri.get("poster_url"))),
|
|
49
48
|
)
|
|
50
49
|
for veri in veriler
|
|
51
50
|
])
|
|
52
51
|
else:
|
|
53
52
|
istek = await self.httpx.get(url.replace("SAYFA", str(page)))
|
|
54
|
-
secici =
|
|
53
|
+
secici = HTMLHelper(istek.text)
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
opacity_el = veri.css_first("div[class*='opacity-80']")
|
|
62
|
-
ep_name = opacity_el.text(strip=True) if opacity_el else None
|
|
63
|
-
if not ep_name:
|
|
55
|
+
# Genel olarak dizi sayfalarına giden linkleri al
|
|
56
|
+
for veri in secici.select('a[href*="/dizi/"]'):
|
|
57
|
+
href = secici.select_attr('a', 'href', veri)
|
|
58
|
+
title = secici.select_text(None, veri)
|
|
59
|
+
if not href or not title:
|
|
64
60
|
continue
|
|
65
61
|
|
|
66
|
-
|
|
67
|
-
title = f"{name} - {ep_name}"
|
|
68
|
-
|
|
69
|
-
href = veri.attrs.get("href")
|
|
62
|
+
# Detay sayfasından poster vb. bilgileri al
|
|
70
63
|
ep_req = await self.httpx.get(self.fix_url(href))
|
|
71
|
-
ep_secici =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
poster_el = ep_secici.css_first("img.imgt")
|
|
82
|
-
poster = poster_el.attrs.get("src") if poster_el else None
|
|
83
|
-
|
|
84
|
-
if href:
|
|
85
|
-
ana_sayfa.append(
|
|
86
|
-
MainPageResult(
|
|
87
|
-
category = category,
|
|
88
|
-
title = title,
|
|
89
|
-
url = self.fix_url(href),
|
|
90
|
-
poster = self.fix_url(poster) if poster else None
|
|
91
|
-
)
|
|
92
|
-
)
|
|
64
|
+
ep_secici = HTMLHelper(ep_req.text)
|
|
65
|
+
poster = ep_secici.select_poster('img.imgt') or ep_secici.select_poster('img')
|
|
66
|
+
|
|
67
|
+
ana_sayfa.append(MainPageResult(
|
|
68
|
+
category = category,
|
|
69
|
+
title = title,
|
|
70
|
+
url = self.fix_url(href),
|
|
71
|
+
poster = self.fix_url(poster)
|
|
72
|
+
))
|
|
93
73
|
|
|
94
74
|
return ana_sayfa
|
|
95
75
|
|
|
@@ -114,6 +94,21 @@ class Dizilla(PluginBase):
|
|
|
114
94
|
# JSON decode
|
|
115
95
|
return loads(decrypted.decode("utf-8"))
|
|
116
96
|
|
|
97
|
+
def fix_poster_url(self, url: str) -> str:
|
|
98
|
+
"""AMP CDN URL'lerini düzelt."""
|
|
99
|
+
if not url:
|
|
100
|
+
return url
|
|
101
|
+
# AMP CDN URL'lerini orijinal URL'ye çevir
|
|
102
|
+
# https://images-macellan-online.cdn.ampproject.org/i/s/images.macellan.online/...
|
|
103
|
+
# -> https://images.macellan.online/...
|
|
104
|
+
if "cdn.ampproject.org" in url:
|
|
105
|
+
# /i/s/ veya /ii/s/ gibi AMP prefix'lerinden sonraki kısmı al
|
|
106
|
+
helper = HTMLHelper(url)
|
|
107
|
+
match = helper.regex_first(r"cdn\.ampproject\.org/[^/]+/s/(.+)$")
|
|
108
|
+
if match:
|
|
109
|
+
return f"https://{match}"
|
|
110
|
+
return url
|
|
111
|
+
|
|
117
112
|
async def search(self, query: str) -> list[SearchResult]:
|
|
118
113
|
arama_istek = await self.httpx.post(f"{self.main_url}/api/bg/searchcontent?searchterm={query}")
|
|
119
114
|
decrypted = await self.decrypt_response(arama_istek.json().get("response"))
|
|
@@ -123,7 +118,7 @@ class Dizilla(PluginBase):
|
|
|
123
118
|
SearchResult(
|
|
124
119
|
title = veri.get("object_name"),
|
|
125
120
|
url = self.fix_url(f"{self.main_url}/{veri.get('used_slug')}"),
|
|
126
|
-
poster = self.fix_url(veri.get("object_poster_url")),
|
|
121
|
+
poster = self.fix_poster_url(self.fix_url(veri.get("object_poster_url"))),
|
|
127
122
|
)
|
|
128
123
|
for veri in arama_veri
|
|
129
124
|
]
|
|
@@ -140,73 +135,45 @@ class Dizilla(PluginBase):
|
|
|
140
135
|
|
|
141
136
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
142
137
|
istek = await self.httpx.get(url)
|
|
143
|
-
secici =
|
|
138
|
+
secici = HTMLHelper(istek.text)
|
|
144
139
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if not title:
|
|
140
|
+
next_data_text = secici.select_text("script#__NEXT_DATA__")
|
|
141
|
+
if not next_data_text:
|
|
148
142
|
return None
|
|
149
143
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
tags
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
except:
|
|
184
|
-
pass
|
|
185
|
-
|
|
186
|
-
sezon_secici = HTMLParser(sezon_req.text)
|
|
187
|
-
for bolum in sezon_secici.css("div.episodes div.cursor-pointer"):
|
|
188
|
-
# Kotlin: bolum.select("a").last()
|
|
189
|
-
links = bolum.css("a")
|
|
190
|
-
if not links:
|
|
191
|
-
continue
|
|
192
|
-
|
|
193
|
-
ep_link = links[-1]
|
|
194
|
-
ep_name = ep_link.text(strip=True)
|
|
195
|
-
ep_href = self.fix_url(ep_link.attrs.get("href"))
|
|
196
|
-
|
|
197
|
-
# Episode number (first link's text usually)
|
|
198
|
-
ep_num = None
|
|
199
|
-
try:
|
|
200
|
-
ep_num = int(links[0].text(strip=True))
|
|
201
|
-
except:
|
|
202
|
-
pass
|
|
203
|
-
|
|
204
|
-
episodeses.append(Episode(
|
|
205
|
-
season = season_num,
|
|
206
|
-
episode = ep_num,
|
|
207
|
-
title = ep_name,
|
|
208
|
-
url = ep_href
|
|
209
|
-
))
|
|
144
|
+
next_data = loads(next_data_text)
|
|
145
|
+
secure_data = next_data.get("props", {}).get("pageProps", {}).get("secureData")
|
|
146
|
+
if not secure_data:
|
|
147
|
+
return None
|
|
148
|
+
|
|
149
|
+
decrypted = await self.decrypt_response(secure_data)
|
|
150
|
+
content = decrypted.get("contentItem", {})
|
|
151
|
+
if not content:
|
|
152
|
+
return None
|
|
153
|
+
|
|
154
|
+
title = content.get("original_title") or content.get("used_title")
|
|
155
|
+
description = content.get("description") or content.get("used_description")
|
|
156
|
+
rating = content.get("imdb_point") or content.get("local_vote_avg")
|
|
157
|
+
year = content.get("release_year")
|
|
158
|
+
poster = self.fix_poster_url(self.fix_url(content.get("back_url") or content.get("poster_url")))
|
|
159
|
+
|
|
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
|
+
))
|
|
210
177
|
|
|
211
178
|
return SeriesInfo(
|
|
212
179
|
url = url,
|
|
@@ -214,20 +181,21 @@ class Dizilla(PluginBase):
|
|
|
214
181
|
title = title,
|
|
215
182
|
description = description,
|
|
216
183
|
tags = tags,
|
|
217
|
-
|
|
218
|
-
|
|
184
|
+
rating = rating,
|
|
185
|
+
year = year,
|
|
186
|
+
episodes = episodes,
|
|
219
187
|
actors = actors
|
|
220
188
|
)
|
|
221
189
|
|
|
222
190
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
223
|
-
istek
|
|
224
|
-
secici
|
|
191
|
+
istek = await self.httpx.get(url)
|
|
192
|
+
secici = HTMLHelper(istek.text)
|
|
225
193
|
|
|
226
|
-
|
|
227
|
-
if not
|
|
194
|
+
next_data_text = secici.select_text("script#__NEXT_DATA__")
|
|
195
|
+
if not next_data_text:
|
|
228
196
|
return []
|
|
229
197
|
|
|
230
|
-
next_data = loads(
|
|
198
|
+
next_data = loads(next_data_text)
|
|
231
199
|
secure_data = next_data.get("props", {}).get("pageProps", {}).get("secureData", {})
|
|
232
200
|
decrypted = await self.decrypt_response(secure_data)
|
|
233
201
|
results = decrypted.get("RelatedResults", {}).get("getEpisodeSources", {}).get("result", [])
|
|
@@ -235,22 +203,21 @@ class Dizilla(PluginBase):
|
|
|
235
203
|
if not results:
|
|
236
204
|
return []
|
|
237
205
|
|
|
238
|
-
|
|
239
|
-
first_result = results[0]
|
|
206
|
+
first_result = results[0]
|
|
240
207
|
source_content = str(first_result.get("source_content", ""))
|
|
241
|
-
|
|
242
|
-
# Clean the source_content string (matching Kotlin: .replace("\"", "").replace("\\", ""))
|
|
208
|
+
|
|
243
209
|
cleaned_source = source_content.replace('"', '').replace('\\', '')
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
# Referer check (matching Kotlin: loadExtractor(iframe, "${mainUrl}/", ...))
|
|
210
|
+
|
|
211
|
+
iframe_secici = HTMLHelper(cleaned_source)
|
|
212
|
+
iframe_src = iframe_secici.select_attr("iframe", "src")
|
|
213
|
+
|
|
250
214
|
iframe_url = self.fix_url(iframe_src) if iframe_src else None
|
|
251
|
-
|
|
215
|
+
|
|
252
216
|
if not iframe_url:
|
|
253
217
|
return []
|
|
254
218
|
|
|
255
219
|
data = await self.extract(iframe_url, referer=f"{self.main_url}/", prefix=first_result.get('language_name', 'Unknown'))
|
|
256
|
-
|
|
220
|
+
if not data:
|
|
221
|
+
return []
|
|
222
|
+
|
|
223
|
+
return data if isinstance(data, list) else [data]
|