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/RecTV.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, Episode, SeriesInfo, ExtractResult
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, Episode, SeriesInfo, ExtractResult, HTMLHelper
|
|
4
4
|
from json import dumps, loads
|
|
5
|
-
import re
|
|
5
|
+
import re, contextlib
|
|
6
6
|
|
|
7
7
|
class RecTV(PluginBase):
|
|
8
8
|
name = "RecTV"
|
|
@@ -65,56 +65,60 @@ class RecTV(PluginBase):
|
|
|
65
65
|
for veri in tum_veri
|
|
66
66
|
]
|
|
67
67
|
|
|
68
|
-
async def load_item(self, url: str) -> MovieInfo:
|
|
68
|
+
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
69
69
|
self.httpx.headers.update({"user-agent": "okhttp/4.12.0"})
|
|
70
70
|
veri = loads(url)
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
72
|
+
# Süreyi dakikaya çevir (Örn: "1h 59min")
|
|
73
|
+
duration_raw = veri.get("duration")
|
|
74
|
+
duration = None
|
|
75
|
+
if duration_raw:
|
|
76
|
+
with contextlib.suppress(Exception):
|
|
77
|
+
h = int(HTMLHelper(duration_raw).regex_first(r"(\d+)h") or 0)
|
|
78
|
+
m = int(HTMLHelper(duration_raw).regex_first(r"(\d+)min") or 0)
|
|
79
|
+
duration = h * 60 + m
|
|
80
|
+
|
|
81
|
+
common_info = {
|
|
82
|
+
"url" : url,
|
|
83
|
+
"poster" : self.fix_url(veri.get("image")),
|
|
84
|
+
"title" : veri.get("title"),
|
|
85
|
+
"description" : veri.get("description"),
|
|
86
|
+
"tags" : [genre.get("title") for genre in veri.get("genres")] if veri.get("genres") else [],
|
|
87
|
+
"rating" : str(veri.get("imdb") or veri.get("rating") or ""),
|
|
88
|
+
"year" : str(veri.get("year") or ""),
|
|
89
|
+
"duration" : duration
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if veri.get("type") == "serie":
|
|
93
|
+
dizi_istek = await self.httpx.get(f"{self.main_url}/api/season/by/serie/{veri.get('id')}/{self.sw_key}/")
|
|
94
|
+
dizi_veri = dizi_istek.json()
|
|
95
|
+
|
|
96
|
+
episodes = []
|
|
97
|
+
for season in dizi_veri:
|
|
98
|
+
s_title = season.get("title", "").strip()
|
|
99
|
+
s, _ = HTMLHelper.extract_season_episode(s_title)
|
|
100
|
+
for ep in season.get("episodes"):
|
|
101
|
+
e_title = ep.get("title", "").strip()
|
|
102
|
+
_, e = HTMLHelper.extract_season_episode(e_title)
|
|
103
|
+
for source in ep.get("sources"):
|
|
104
|
+
tag = ""
|
|
105
|
+
clean_s = s_title
|
|
106
|
+
if "dublaj" in s_title.lower():
|
|
107
|
+
tag = " (Dublaj)"; clean_s = re.sub(r"\s*dublaj\s*", "", s_title, flags=re.I).strip()
|
|
108
|
+
elif "altyaz" in s_title.lower():
|
|
109
|
+
tag = " (Altyazı)"; clean_s = re.sub(r"\s*altyaz[ıi]\s*", "", s_title, flags=re.I).strip()
|
|
110
|
+
|
|
111
|
+
ep_data = {"url": self.fix_url(source.get("url")), "title": f"{veri.get('title')} | {s_title} {e_title} - {source.get('title')}", "is_episode": True}
|
|
112
|
+
episodes.append(Episode(
|
|
113
|
+
season = s or 1,
|
|
114
|
+
episode = e or 1,
|
|
115
|
+
title = f"{clean_s} {e_title}{tag} - {source.get('title')}",
|
|
116
|
+
url = dumps(ep_data)
|
|
117
|
+
))
|
|
118
|
+
|
|
119
|
+
return SeriesInfo(**common_info, episodes=episodes, actors=[])
|
|
120
|
+
|
|
121
|
+
return MovieInfo(**common_info, actors=[])
|
|
118
122
|
|
|
119
123
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
120
124
|
try:
|
KekikStream/Plugins/RoketDizi.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core
|
|
4
|
-
|
|
5
|
-
import re, base64, json
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, MovieInfo, HTMLHelper
|
|
4
|
+
import base64, json
|
|
6
5
|
|
|
7
6
|
class RoketDizi(PluginBase):
|
|
8
7
|
name = "RoketDizi"
|
|
@@ -24,26 +23,20 @@ class RoketDizi(PluginBase):
|
|
|
24
23
|
|
|
25
24
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
26
25
|
istek = await self.httpx.get(f"{url}?&page={page}")
|
|
27
|
-
secici =
|
|
26
|
+
secici = HTMLHelper(istek.text)
|
|
28
27
|
|
|
29
28
|
results = []
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
link_el = item.css_first("a")
|
|
35
|
-
img_el = item.css_first("img")
|
|
36
|
-
|
|
37
|
-
title = title_el.text(strip=True) if title_el else None
|
|
38
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
39
|
-
poster = img_el.attrs.get("src") if img_el else None
|
|
29
|
+
for item in secici.select("div.new-added-list > span"):
|
|
30
|
+
title = secici.select_text("span.line-clamp-1", item)
|
|
31
|
+
href = secici.select_attr("a", "href", item)
|
|
32
|
+
poster = secici.select_attr("img", "src", item)
|
|
40
33
|
|
|
41
34
|
if title and href:
|
|
42
35
|
results.append(MainPageResult(
|
|
43
36
|
category = category,
|
|
44
37
|
title = self.clean_title(title),
|
|
45
38
|
url = self.fix_url(href),
|
|
46
|
-
poster = self.fix_url(poster)
|
|
39
|
+
poster = self.fix_url(poster)
|
|
47
40
|
))
|
|
48
41
|
|
|
49
42
|
return results
|
|
@@ -57,7 +50,7 @@ class RoketDizi(PluginBase):
|
|
|
57
50
|
"Referer" : f"{self.main_url}/",
|
|
58
51
|
}
|
|
59
52
|
)
|
|
60
|
-
|
|
53
|
+
|
|
61
54
|
try:
|
|
62
55
|
veri = istek.json()
|
|
63
56
|
encoded = veri.get("response", "")
|
|
@@ -81,7 +74,7 @@ class RoketDizi(PluginBase):
|
|
|
81
74
|
results.append(SearchResult(
|
|
82
75
|
title = self.clean_title(title.strip()),
|
|
83
76
|
url = self.fix_url(f"{self.main_url}/{slug}"),
|
|
84
|
-
poster = self.fix_url(poster)
|
|
77
|
+
poster = self.fix_url(poster)
|
|
85
78
|
))
|
|
86
79
|
|
|
87
80
|
return results
|
|
@@ -89,117 +82,95 @@ class RoketDizi(PluginBase):
|
|
|
89
82
|
except Exception:
|
|
90
83
|
return []
|
|
91
84
|
|
|
92
|
-
async def load_item(self, url: str) -> SeriesInfo:
|
|
93
|
-
# Note: Handling both Movie and Series logic in one, returning SeriesInfo generally or MovieInfo
|
|
85
|
+
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
94
86
|
resp = await self.httpx.get(url)
|
|
95
|
-
sel =
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
# Sıralı liste oluştur
|
|
171
|
-
episodes = [episodes_dict[key] for key in sorted(episodes_dict.keys())]
|
|
172
|
-
|
|
173
|
-
return SeriesInfo(
|
|
174
|
-
title = title,
|
|
175
|
-
url = url,
|
|
176
|
-
poster = self.fix_url(poster) if poster else None,
|
|
177
|
-
description = description,
|
|
178
|
-
tags = tags,
|
|
179
|
-
rating = rating,
|
|
180
|
-
actors = actors,
|
|
181
|
-
episodes = episodes,
|
|
182
|
-
year = year
|
|
183
|
-
)
|
|
87
|
+
sel = HTMLHelper(resp.text)
|
|
88
|
+
|
|
89
|
+
next_data_text = sel.select_text("script#__NEXT_DATA__")
|
|
90
|
+
if not next_data_text:
|
|
91
|
+
return SeriesInfo(url=url, title=sel.select_text("h1") or "Bilinmeyen")
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
next_data = json.loads(next_data_text)
|
|
95
|
+
secure_data_raw = next_data["props"]["pageProps"]["secureData"]
|
|
96
|
+
secure_data = json.loads(base64.b64decode(secure_data_raw).decode('utf-8'))
|
|
97
|
+
|
|
98
|
+
content_item = secure_data.get("contentItem", {})
|
|
99
|
+
content = secure_data.get("content", {}).get("result", {})
|
|
100
|
+
|
|
101
|
+
title = content_item.get("original_title") or content_item.get("culture_title")
|
|
102
|
+
poster = content_item.get("poster_url") or content_item.get("face_url")
|
|
103
|
+
description = content_item.get("description")
|
|
104
|
+
rating = str(content_item.get("imdb_point") or "")
|
|
105
|
+
year = str(content_item.get("release_year") or "")
|
|
106
|
+
tags = content_item.get("categories", "").split(",")
|
|
107
|
+
|
|
108
|
+
actors = []
|
|
109
|
+
casts_data = content.get("getSerieCastsById") or content.get("getMovieCastsById")
|
|
110
|
+
if casts_data and casts_data.get("result"):
|
|
111
|
+
actors = [cast.get("name") for cast in casts_data["result"] if cast.get("name")]
|
|
112
|
+
|
|
113
|
+
episodes = []
|
|
114
|
+
if "Series" in str(content.get("FindedType")):
|
|
115
|
+
all_urls = HTMLHelper(resp.text).regex_all(r'"url":"([^"]*)"')
|
|
116
|
+
episodes_dict = {}
|
|
117
|
+
for u in all_urls:
|
|
118
|
+
if "bolum" in u and u not in episodes_dict:
|
|
119
|
+
s_match = HTMLHelper(u).regex_first(r'/sezon-(\d+)')
|
|
120
|
+
e_match = HTMLHelper(u).regex_first(r'/bolum-(\d+)')
|
|
121
|
+
s_val = int(s_match) if s_match else 1
|
|
122
|
+
e_val = int(e_match) if e_match else 1
|
|
123
|
+
episodes_dict[(s_val, e_val)] = Episode(
|
|
124
|
+
season = s_val,
|
|
125
|
+
episode = e_val,
|
|
126
|
+
title = f"{s_val}. Sezon {e_val}. Bölüm",
|
|
127
|
+
url = self.fix_url(u)
|
|
128
|
+
)
|
|
129
|
+
episodes = [episodes_dict[key] for key in sorted(episodes_dict.keys())]
|
|
130
|
+
|
|
131
|
+
return SeriesInfo(
|
|
132
|
+
url = url,
|
|
133
|
+
poster = self.fix_url(poster),
|
|
134
|
+
title = self.clean_title(title),
|
|
135
|
+
description = description,
|
|
136
|
+
tags = tags,
|
|
137
|
+
rating = rating,
|
|
138
|
+
year = year,
|
|
139
|
+
actors = actors,
|
|
140
|
+
episodes = episodes
|
|
141
|
+
)
|
|
142
|
+
else:
|
|
143
|
+
return MovieInfo(
|
|
144
|
+
url = url,
|
|
145
|
+
poster = self.fix_url(poster),
|
|
146
|
+
title = self.clean_title(title),
|
|
147
|
+
description = description,
|
|
148
|
+
tags = tags,
|
|
149
|
+
rating = rating,
|
|
150
|
+
year = year,
|
|
151
|
+
actors = actors
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
except Exception:
|
|
155
|
+
# Fallback to simple extraction if JSON parsing fails
|
|
156
|
+
return SeriesInfo(
|
|
157
|
+
url = url,
|
|
158
|
+
title = self.clean_title(sel.select_text("h1")) or "Bilinmeyen"
|
|
159
|
+
)
|
|
184
160
|
|
|
185
161
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
186
162
|
resp = await self.httpx.get(url)
|
|
187
|
-
sel =
|
|
188
|
-
|
|
189
|
-
next_data_el = sel.css_first("script#__NEXT_DATA__")
|
|
190
|
-
if not next_data_el:
|
|
191
|
-
return []
|
|
163
|
+
sel = HTMLHelper(resp.text)
|
|
192
164
|
|
|
193
|
-
next_data =
|
|
165
|
+
next_data = sel.select_text("script#__NEXT_DATA__")
|
|
194
166
|
if not next_data:
|
|
195
167
|
return []
|
|
196
168
|
|
|
197
169
|
try:
|
|
198
|
-
data
|
|
199
|
-
secure_data
|
|
170
|
+
data = json.loads(next_data)
|
|
171
|
+
secure_data = data["props"]["pageProps"]["secureData"]
|
|
200
172
|
decoded_json = json.loads(base64.b64decode(secure_data).decode('utf-8'))
|
|
201
173
|
|
|
202
|
-
# secureData içindeki RelatedResults -> getEpisodeSources -> result dizisini al
|
|
203
174
|
sources = decoded_json.get("RelatedResults", {}).get("getEpisodeSources", {}).get("result", [])
|
|
204
175
|
|
|
205
176
|
seen_urls = set()
|
|
@@ -208,12 +179,10 @@ class RoketDizi(PluginBase):
|
|
|
208
179
|
source_content = source.get("source_content", "")
|
|
209
180
|
|
|
210
181
|
# iframe URL'ini source_content'ten çıkar
|
|
211
|
-
|
|
212
|
-
if not
|
|
182
|
+
iframe_url = HTMLHelper(source_content).regex_first(r'<iframe[^>]*src=["\']([^"\']*)["\']')
|
|
183
|
+
if not iframe_url:
|
|
213
184
|
continue
|
|
214
185
|
|
|
215
|
-
iframe_url = iframe_match.group(1)
|
|
216
|
-
|
|
217
186
|
# Fix URL protocol
|
|
218
187
|
if not iframe_url.startswith("http"):
|
|
219
188
|
if iframe_url.startswith("//"):
|
|
@@ -222,8 +191,8 @@ class RoketDizi(PluginBase):
|
|
|
222
191
|
iframe_url = "https://" + iframe_url
|
|
223
192
|
|
|
224
193
|
iframe_url = self.fix_url(iframe_url)
|
|
225
|
-
|
|
226
|
-
# Deduplicate
|
|
194
|
+
|
|
195
|
+
# Deduplicate
|
|
227
196
|
if iframe_url in seen_urls:
|
|
228
197
|
continue
|
|
229
198
|
seen_urls.add(iframe_url)
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult
|
|
4
|
-
|
|
5
|
-
import re, base64, json, urllib.parse
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult, HTMLHelper
|
|
4
|
+
import base64, json, urllib.parse
|
|
6
5
|
|
|
7
6
|
class SelcukFlix(PluginBase):
|
|
8
7
|
name = "SelcukFlix"
|
|
@@ -34,17 +33,13 @@ class SelcukFlix(PluginBase):
|
|
|
34
33
|
if "tum-bolumler" in url:
|
|
35
34
|
try:
|
|
36
35
|
resp = await self.httpx.get(url)
|
|
37
|
-
sel =
|
|
36
|
+
sel = HTMLHelper(resp.text)
|
|
38
37
|
|
|
39
|
-
for item in sel.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
name = name_el.text(strip=True) if name_el else None
|
|
45
|
-
ep_info = ep_el.text(strip=True) if ep_el else None
|
|
46
|
-
href = item.attrs.get("href")
|
|
47
|
-
poster = img_el.attrs.get("src") if img_el else None
|
|
38
|
+
for item in sel.select("div.col-span-3 a"):
|
|
39
|
+
name = sel.select_text("h2", item)
|
|
40
|
+
ep_info = sel.select_text("div.opacity-80", item)
|
|
41
|
+
href = sel.select_attr("a", "href", item)
|
|
42
|
+
poster = sel.select_attr("div.image img", "src", item)
|
|
48
43
|
|
|
49
44
|
if name and href:
|
|
50
45
|
title = f"{name} - {ep_info}" if ep_info else name
|
|
@@ -57,7 +52,7 @@ class SelcukFlix(PluginBase):
|
|
|
57
52
|
category = category,
|
|
58
53
|
title = title,
|
|
59
54
|
url = final_url,
|
|
60
|
-
poster = self.fix_url(poster)
|
|
55
|
+
poster = self.fix_url(poster)
|
|
61
56
|
))
|
|
62
57
|
except Exception:
|
|
63
58
|
pass
|
|
@@ -188,91 +183,88 @@ class SelcukFlix(PluginBase):
|
|
|
188
183
|
|
|
189
184
|
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
190
185
|
resp = await self.httpx.get(url)
|
|
191
|
-
sel =
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if not
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
next_data = next_data_el.text(strip=True)
|
|
198
|
-
if not next_data:
|
|
199
|
-
return None
|
|
186
|
+
sel = HTMLHelper(resp.text)
|
|
187
|
+
|
|
188
|
+
next_data_text = sel.select_text("script#__NEXT_DATA__")
|
|
189
|
+
if not next_data_text:
|
|
190
|
+
return SeriesInfo(url=url, title=self.clean_title(sel.select_text("h1")) or "Bilinmeyen")
|
|
200
191
|
|
|
201
|
-
data = json.loads(next_data)
|
|
202
|
-
secure_data = data["props"]["pageProps"]["secureData"]
|
|
203
|
-
raw_data = base64.b64decode(secure_data.replace('"', ''))
|
|
204
192
|
try:
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
content_details = json.loads(decoded_str)
|
|
210
|
-
item = content_details.get("contentItem", {})
|
|
211
|
-
|
|
212
|
-
title = item.get("original_title") or item.get("originalTitle") or ""
|
|
213
|
-
poster = self.clean_image_url(item.get("poster_url") or item.get("posterUrl"))
|
|
214
|
-
description = item.get("description") or item.get("used_description")
|
|
215
|
-
rating = str(item.get("imdb_point") or item.get("imdbPoint", ""))
|
|
216
|
-
year = item.get("release_year") or item.get("releaseYear")
|
|
217
|
-
duration = item.get("total_minutes") or item.get("totalMinutes")
|
|
218
|
-
|
|
219
|
-
series_data = content_details.get("relatedData", {}).get("seriesData")
|
|
220
|
-
if not series_data and "RelatedResults" in content_details:
|
|
221
|
-
series_data = content_details["RelatedResults"].get("getSerieSeasonAndEpisodes", {}).get("result")
|
|
222
|
-
if series_data and isinstance(series_data, list):
|
|
223
|
-
pass
|
|
224
|
-
|
|
225
|
-
# Dizi mi film mi kontrol et (Kotlin referansı)
|
|
226
|
-
if series_data:
|
|
227
|
-
episodes = []
|
|
228
|
-
seasons_list = []
|
|
229
|
-
if isinstance(series_data, dict):
|
|
230
|
-
seasons_list = series_data.get("seasons", [])
|
|
231
|
-
elif isinstance(series_data, list):
|
|
232
|
-
seasons_list = series_data
|
|
233
|
-
|
|
234
|
-
for season in seasons_list:
|
|
235
|
-
if not isinstance(season, dict): continue
|
|
236
|
-
s_no = season.get("season_no") or season.get("seasonNo")
|
|
237
|
-
ep_list = season.get("episodes", [])
|
|
238
|
-
for ep in ep_list:
|
|
239
|
-
episodes.append(Episode(
|
|
240
|
-
season = s_no,
|
|
241
|
-
episode = ep.get("episode_no") or ep.get("episodeNo"),
|
|
242
|
-
title = ep.get("ep_text") or ep.get("epText"),
|
|
243
|
-
url = self.fix_url(ep.get("used_slug") or ep.get("usedSlug"))
|
|
244
|
-
))
|
|
193
|
+
next_data = json.loads(next_data_text)
|
|
194
|
+
secure_data_raw = next_data["props"]["pageProps"].get("secureData")
|
|
195
|
+
if not secure_data_raw:
|
|
196
|
+
return SeriesInfo(url=url, title=self.clean_title(sel.select_text("h1")) or "Bilinmeyen")
|
|
245
197
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
)
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
)
|
|
198
|
+
# Clean possible quotes from string before decoding
|
|
199
|
+
if isinstance(secure_data_raw, str):
|
|
200
|
+
secure_data_raw = secure_data_raw.strip('"')
|
|
201
|
+
|
|
202
|
+
content_details = json.loads(base64.b64decode(secure_data_raw).decode('utf-8'))
|
|
203
|
+
if isinstance(content_details, str): content_details = json.loads(content_details)
|
|
204
|
+
|
|
205
|
+
item = content_details.get("contentItem", {})
|
|
206
|
+
related_results = content_details.get("RelatedResults", {})
|
|
207
|
+
|
|
208
|
+
title = self.clean_title(item.get("original_title") or item.get("culture_title") or item.get("originalTitle") or "")
|
|
209
|
+
poster = self.clean_image_url(item.get("poster_url") or item.get("posterUrl") or item.get("face_url"))
|
|
210
|
+
description = item.get("description") or item.get("used_description")
|
|
211
|
+
rating = str(item.get("imdb_point") or item.get("imdbPoint") or "")
|
|
212
|
+
year = str(item.get("release_year") or item.get("releaseYear") or "")
|
|
213
|
+
duration = item.get("total_minutes") or item.get("totalMinutes")
|
|
214
|
+
|
|
215
|
+
tags = []
|
|
216
|
+
tags_raw = item.get("category_names") or item.get("categoryNames") or item.get("categories")
|
|
217
|
+
if isinstance(tags_raw, str):
|
|
218
|
+
tags = [t.strip() for t in tags_raw.split(",") if t.strip()]
|
|
219
|
+
elif isinstance(tags_raw, list):
|
|
220
|
+
tags = [c.get("title") if isinstance(c, dict) else str(c) for c in tags_raw]
|
|
221
|
+
|
|
222
|
+
actors = []
|
|
223
|
+
casts_data = related_results.get("getSerieCastsById") or related_results.get("getMovieCastsById")
|
|
224
|
+
if casts_data and isinstance(casts_data, dict) and casts_data.get("result"):
|
|
225
|
+
actors = [cast.get("name") for cast in casts_data["result"] if cast.get("name")]
|
|
226
|
+
|
|
227
|
+
common_info = {
|
|
228
|
+
"url" : url,
|
|
229
|
+
"poster" : poster,
|
|
230
|
+
"title" : title,
|
|
231
|
+
"description" : description,
|
|
232
|
+
"tags" : tags,
|
|
233
|
+
"rating" : rating,
|
|
234
|
+
"year" : year,
|
|
235
|
+
"actors" : actors,
|
|
236
|
+
"duration" : duration
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
series_data = related_results.get("getSerieSeasonAndEpisodes")
|
|
240
|
+
if series_data and isinstance(series_data, dict) and series_data.get("result"):
|
|
241
|
+
episodes = []
|
|
242
|
+
for season in series_data["result"]:
|
|
243
|
+
s_no = season.get("season_no") or season.get("seasonNo") or 1
|
|
244
|
+
for ep in season.get("episodes", []):
|
|
245
|
+
ep_slug = ep.get("used_slug") or ep.get("usedSlug")
|
|
246
|
+
if ep_slug:
|
|
247
|
+
episodes.append(Episode(
|
|
248
|
+
season = s_no,
|
|
249
|
+
episode = ep.get("episode_no") or ep.get("episodeNo") or 1,
|
|
250
|
+
title = ep.get("ep_text") or ep.get("epText") or "",
|
|
251
|
+
url = self.fix_url(ep_slug)
|
|
252
|
+
))
|
|
253
|
+
return SeriesInfo(**common_info, episodes=episodes)
|
|
254
|
+
|
|
255
|
+
return MovieInfo(**common_info)
|
|
256
|
+
|
|
257
|
+
except Exception:
|
|
258
|
+
return SeriesInfo(url=url, title=self.clean_title(sel.select_text("h1")) or "Bilinmeyen")
|
|
259
|
+
|
|
260
|
+
except Exception:
|
|
261
|
+
return SeriesInfo(url=url, title=self.clean_title(sel.select_text("h1")) or "Bilinmeyen")
|
|
266
262
|
|
|
267
263
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
268
264
|
resp = await self.httpx.get(url)
|
|
269
|
-
sel =
|
|
265
|
+
sel = HTMLHelper(resp.text)
|
|
270
266
|
|
|
271
|
-
|
|
272
|
-
if not next_data_el:
|
|
273
|
-
return []
|
|
274
|
-
|
|
275
|
-
next_data = next_data_el.text(strip=True)
|
|
267
|
+
next_data = sel.select_text("script#__NEXT_DATA__")
|
|
276
268
|
if not next_data:
|
|
277
269
|
return []
|
|
278
270
|
|
|
@@ -312,9 +304,8 @@ class SelcukFlix(PluginBase):
|
|
|
312
304
|
source_content = res[0].get("source_content") or res[0].get("sourceContent")
|
|
313
305
|
|
|
314
306
|
if source_content:
|
|
315
|
-
iframe_sel =
|
|
316
|
-
|
|
317
|
-
iframe_src = iframe_el.attrs.get("src") if iframe_el else None
|
|
307
|
+
iframe_sel = HTMLHelper(source_content)
|
|
308
|
+
iframe_src = iframe_sel.select_attr("iframe", "src")
|
|
318
309
|
if iframe_src:
|
|
319
310
|
iframe_src = self.fix_url(iframe_src)
|
|
320
311
|
# Hotlinger domain değişimi (Kotlin referansı)
|