KekikStream 2.1.4__py3-none-any.whl → 2.1.9__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/Plugin/PluginBase.py +20 -21
- KekikStream/Extractors/CloseLoad.py +17 -2
- KekikStream/Extractors/Filemoon.py +78 -0
- KekikStream/Extractors/RapidVid.py +15 -5
- KekikStream/Extractors/VidHide.py +11 -2
- KekikStream/Plugins/BelgeselX.py +7 -7
- KekikStream/Plugins/DiziBox.py +2 -2
- KekikStream/Plugins/DiziPal.py +8 -8
- KekikStream/Plugins/DiziYou.py +8 -8
- KekikStream/Plugins/Dizilla.py +2 -2
- KekikStream/Plugins/FilmBip.py +2 -2
- KekikStream/Plugins/FilmMakinesi.py +2 -2
- KekikStream/Plugins/FilmModu.py +8 -8
- KekikStream/Plugins/FullHDFilm.py +81 -22
- KekikStream/Plugins/FullHDFilmizlesene.py +2 -2
- KekikStream/Plugins/HDFilmCehennemi.py +79 -39
- KekikStream/Plugins/JetFilmizle.py +2 -2
- KekikStream/Plugins/KultFilmler.py +10 -9
- KekikStream/Plugins/RecTV.py +15 -15
- KekikStream/Plugins/RoketDizi.py +2 -2
- KekikStream/Plugins/SelcukFlix.py +68 -44
- KekikStream/Plugins/SetFilmIzle.py +21 -21
- KekikStream/Plugins/SezonlukDizi.py +19 -2
- KekikStream/Plugins/SineWix.py +13 -13
- KekikStream/Plugins/Sinefy.py +6 -6
- KekikStream/Plugins/SinemaCX.py +31 -22
- KekikStream/Plugins/Sinezy.py +2 -2
- KekikStream/Plugins/SuperFilmGeldi.py +30 -19
- KekikStream/Plugins/UgurFilm.py +2 -2
- KekikStream/__init__.py +15 -15
- {kekikstream-2.1.4.dist-info → kekikstream-2.1.9.dist-info}/METADATA +5 -3
- {kekikstream-2.1.4.dist-info → kekikstream-2.1.9.dist-info}/RECORD +36 -35
- {kekikstream-2.1.4.dist-info → kekikstream-2.1.9.dist-info}/WHEEL +0 -0
- {kekikstream-2.1.4.dist-info → kekikstream-2.1.9.dist-info}/entry_points.txt +0 -0
- {kekikstream-2.1.4.dist-info → kekikstream-2.1.9.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-2.1.4.dist-info → kekikstream-2.1.9.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
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
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
from Kekik.Sifreleme import StringCodec
|
|
6
6
|
import json, re
|
|
@@ -100,7 +100,7 @@ class FullHDFilmizlesene(PluginBase):
|
|
|
100
100
|
duration = duration
|
|
101
101
|
)
|
|
102
102
|
|
|
103
|
-
async def load_links(self, url: str) -> list[
|
|
103
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
104
104
|
istek = await self.httpx.get(url)
|
|
105
105
|
secici = Selector(istek.text)
|
|
106
106
|
|
|
@@ -1,6 +1,6 @@
|
|
|
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, Subtitle
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, Subtitle, ExtractResult
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
from Kekik.Sifreleme import Packer, StreamDecoder
|
|
6
6
|
import random, string, re
|
|
@@ -71,41 +71,81 @@ class HDFilmCehennemi(PluginBase):
|
|
|
71
71
|
|
|
72
72
|
return results
|
|
73
73
|
|
|
74
|
-
async def load_item(self, url: str) -> MovieInfo:
|
|
74
|
+
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
75
75
|
istek = await self.httpx.get(url, headers = {"Referer": f"{self.main_url}/"})
|
|
76
76
|
secici = Selector(istek.text)
|
|
77
77
|
|
|
78
|
-
title = secici.css("h1.section-title::text").get()
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
title = secici.css("h1.section-title::text").get()
|
|
79
|
+
title = title.strip() if title else ""
|
|
80
|
+
poster = secici.css("aside.post-info-poster img.lazyload::attr(data-src)").get() or ""
|
|
81
|
+
poster = poster.strip() if poster else ""
|
|
82
|
+
description = secici.css("article.post-info-content > p::text").get() or ""
|
|
83
|
+
description = description.strip() if description else ""
|
|
81
84
|
tags = secici.css("div.post-info-genres a::text").getall()
|
|
82
|
-
rating = secici.css("div.post-info-imdb-rating span::text").get()
|
|
83
|
-
|
|
85
|
+
rating = secici.css("div.post-info-imdb-rating span::text").get() or ""
|
|
86
|
+
rating = rating.strip() if rating else ""
|
|
87
|
+
year = secici.css("div.post-info-year-country a::text").get() or ""
|
|
88
|
+
year = year.strip() if year else ""
|
|
84
89
|
actors = secici.css("div.post-info-cast a > strong::text").getall()
|
|
85
|
-
duration = secici.css("div.post-info-duration::text").get()
|
|
90
|
+
duration = secici.css("div.post-info-duration::text").get() or "0"
|
|
91
|
+
duration = duration.replace("dakika", "").strip()
|
|
86
92
|
|
|
87
|
-
|
|
88
93
|
try:
|
|
89
|
-
duration_minutes = int(duration
|
|
94
|
+
duration_minutes = int(re.search(r'\d+', duration).group()) if re.search(r'\d+', duration) else 0
|
|
90
95
|
except Exception:
|
|
91
96
|
duration_minutes = 0
|
|
92
97
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
# Dizi mi film mi kontrol et (Kotlin referansı: div.seasons kontrolü)
|
|
99
|
+
is_series = len(secici.css("div.seasons").getall()) > 0
|
|
100
|
+
|
|
101
|
+
if is_series:
|
|
102
|
+
episodes = []
|
|
103
|
+
for ep in secici.css("div.seasons-tab-content a"):
|
|
104
|
+
ep_name = ep.css("h4::text").get()
|
|
105
|
+
ep_href = ep.css("::attr(href)").get()
|
|
106
|
+
if ep_name and ep_href:
|
|
107
|
+
ep_name = ep_name.strip()
|
|
108
|
+
# Regex ile sezon ve bölüm numarası çıkar
|
|
109
|
+
ep_match = re.search(r'(\d+)\.\s*Bölüm', ep_name)
|
|
110
|
+
sz_match = re.search(r'(\d+)\.\s*Sezon', ep_name)
|
|
111
|
+
ep_num = int(ep_match.group(1)) if ep_match else 1
|
|
112
|
+
sz_num = int(sz_match.group(1)) if sz_match else 1
|
|
113
|
+
|
|
114
|
+
episodes.append(Episode(
|
|
115
|
+
season = sz_num,
|
|
116
|
+
episode = ep_num,
|
|
117
|
+
title = ep_name,
|
|
118
|
+
url = self.fix_url(ep_href)
|
|
119
|
+
))
|
|
120
|
+
|
|
121
|
+
return SeriesInfo(
|
|
122
|
+
url = url,
|
|
123
|
+
poster = self.fix_url(poster),
|
|
124
|
+
title = self.clean_title(title),
|
|
125
|
+
description = description,
|
|
126
|
+
tags = tags,
|
|
127
|
+
rating = rating,
|
|
128
|
+
year = year,
|
|
129
|
+
actors = actors,
|
|
130
|
+
episodes = episodes
|
|
131
|
+
)
|
|
132
|
+
else:
|
|
133
|
+
return MovieInfo(
|
|
134
|
+
url = url,
|
|
135
|
+
poster = self.fix_url(poster),
|
|
136
|
+
title = self.clean_title(title),
|
|
137
|
+
description = description,
|
|
138
|
+
tags = tags,
|
|
139
|
+
rating = rating,
|
|
140
|
+
year = year,
|
|
141
|
+
actors = actors,
|
|
142
|
+
duration = duration_minutes
|
|
143
|
+
)
|
|
104
144
|
|
|
105
145
|
def generate_random_cookie(self):
|
|
106
146
|
return "".join(random.choices(string.ascii_letters + string.digits, k=16))
|
|
107
147
|
|
|
108
|
-
async def cehennempass(self, video_id: str) -> list
|
|
148
|
+
async def cehennempass(self, video_id: str) -> list:
|
|
109
149
|
results = []
|
|
110
150
|
|
|
111
151
|
istek = await self.httpx.post(
|
|
@@ -119,11 +159,11 @@ class HDFilmCehennemi(PluginBase):
|
|
|
119
159
|
data = {"video_id": video_id, "selected_quality": "low"},
|
|
120
160
|
)
|
|
121
161
|
if video_url := istek.json().get("download_link"):
|
|
122
|
-
results.append(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
162
|
+
results.append(ExtractResult(
|
|
163
|
+
url = self.fix_url(video_url),
|
|
164
|
+
name = "Düşük Kalite",
|
|
165
|
+
referer = f"https://cehennempass.pw/download/{video_id}"
|
|
166
|
+
))
|
|
127
167
|
|
|
128
168
|
istek = await self.httpx.post(
|
|
129
169
|
url = "https://cehennempass.pw/process_quality_selection.php",
|
|
@@ -136,11 +176,11 @@ class HDFilmCehennemi(PluginBase):
|
|
|
136
176
|
data = {"video_id": video_id, "selected_quality": "high"},
|
|
137
177
|
)
|
|
138
178
|
if video_url := istek.json().get("download_link"):
|
|
139
|
-
results.append(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
179
|
+
results.append(ExtractResult(
|
|
180
|
+
url = self.fix_url(video_url),
|
|
181
|
+
name = "Yüksek Kalite",
|
|
182
|
+
referer = f"https://cehennempass.pw/download/{video_id}"
|
|
183
|
+
))
|
|
144
184
|
|
|
145
185
|
return results
|
|
146
186
|
|
|
@@ -206,14 +246,14 @@ class HDFilmCehennemi(PluginBase):
|
|
|
206
246
|
except Exception:
|
|
207
247
|
pass
|
|
208
248
|
|
|
209
|
-
return [
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
249
|
+
return [ExtractResult(
|
|
250
|
+
url = video_url,
|
|
251
|
+
name = source,
|
|
252
|
+
referer = url,
|
|
253
|
+
subtitles = subtitles
|
|
254
|
+
)]
|
|
215
255
|
|
|
216
|
-
async def load_links(self, url: str) -> list[
|
|
256
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
217
257
|
istek = await self.httpx.get(url)
|
|
218
258
|
secici = Selector(istek.text)
|
|
219
259
|
|
|
@@ -1,6 +1,6 @@
|
|
|
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
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
|
|
6
6
|
class JetFilmizle(PluginBase):
|
|
@@ -96,7 +96,7 @@ class JetFilmizle(PluginBase):
|
|
|
96
96
|
actors = actors
|
|
97
97
|
)
|
|
98
98
|
|
|
99
|
-
async def load_links(self, url: str) -> list[
|
|
99
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
100
100
|
istek = await self.httpx.get(url)
|
|
101
101
|
secici = Selector(istek.text)
|
|
102
102
|
|
|
@@ -160,7 +160,7 @@ class KultFilmler(PluginBase):
|
|
|
160
160
|
match = re.search(r"(https?://[^\s\"]+\.srt)", source_code)
|
|
161
161
|
return match[1] if match else None
|
|
162
162
|
|
|
163
|
-
async def load_links(self, url: str) -> list[
|
|
163
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
164
164
|
istek = await self.httpx.get(url)
|
|
165
165
|
secici = Selector(istek.text)
|
|
166
166
|
|
|
@@ -195,12 +195,12 @@ class KultFilmler(PluginBase):
|
|
|
195
195
|
m3u_match = re.search(r'file:"([^"]+)"', iframe_istek.text)
|
|
196
196
|
|
|
197
197
|
if m3u_match:
|
|
198
|
-
results.append(
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
198
|
+
results.append(ExtractResult(
|
|
199
|
+
name = "VidMoly",
|
|
200
|
+
url = m3u_match[1],
|
|
201
|
+
referer = self.main_url,
|
|
202
|
+
subtitles = []
|
|
203
|
+
))
|
|
204
204
|
continue
|
|
205
205
|
|
|
206
206
|
# Altyazı çıkar
|
|
@@ -210,7 +210,8 @@ class KultFilmler(PluginBase):
|
|
|
210
210
|
|
|
211
211
|
data = await self.extract(iframe)
|
|
212
212
|
if data:
|
|
213
|
-
|
|
214
|
-
|
|
213
|
+
# ExtractResult objesi immutable, yeni bir kopya oluştur
|
|
214
|
+
updated_data = data.model_copy(update={"subtitles": subtitles}) if subtitles else data
|
|
215
|
+
results.append(updated_data)
|
|
215
216
|
|
|
216
217
|
return results
|
KekikStream/Plugins/RecTV.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 import PluginBase, MainPageResult, SearchResult, MovieInfo, Episode, SeriesInfo
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, Episode, SeriesInfo, ExtractResult
|
|
4
4
|
from json import dumps, loads
|
|
5
5
|
import re
|
|
6
6
|
|
|
@@ -116,21 +116,21 @@ class RecTV(PluginBase):
|
|
|
116
116
|
actors = []
|
|
117
117
|
)
|
|
118
118
|
|
|
119
|
-
async def load_links(self, url: str) -> list[
|
|
119
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
120
120
|
try:
|
|
121
121
|
veri = loads(url)
|
|
122
122
|
except Exception:
|
|
123
123
|
# JSON değilse düz URL'dir (eski yapı veya hata)
|
|
124
|
-
return [
|
|
124
|
+
return [ExtractResult(url=url, name="Video")]
|
|
125
125
|
|
|
126
126
|
# Eğer dizi bölümü ise (bizim oluşturduğumuz yapı)
|
|
127
127
|
if veri.get("is_episode"):
|
|
128
|
-
return [
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
128
|
+
return [ExtractResult(
|
|
129
|
+
url = veri.get("url"),
|
|
130
|
+
name = veri.get("title", "Bölüm"),
|
|
131
|
+
user_agent = "googleusercontent",
|
|
132
|
+
referer = "https://twitter.com/"
|
|
133
|
+
)]
|
|
134
134
|
|
|
135
135
|
# Film ise (RecTV API yapısı)
|
|
136
136
|
results = []
|
|
@@ -140,11 +140,11 @@ class RecTV(PluginBase):
|
|
|
140
140
|
if "otolinkaff" in video_link:
|
|
141
141
|
continue
|
|
142
142
|
|
|
143
|
-
results.append(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
results.append(ExtractResult(
|
|
144
|
+
url = video_link,
|
|
145
|
+
name = f"{veri.get('title')} - {kaynak.get('title')}",
|
|
146
|
+
user_agent = "googleusercontent",
|
|
147
|
+
referer = "https://twitter.com/"
|
|
148
|
+
))
|
|
149
149
|
|
|
150
150
|
return results
|
KekikStream/Plugins/RoketDizi.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 import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, MovieInfo
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, MovieInfo
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
import re, base64, json
|
|
6
6
|
|
|
@@ -169,7 +169,7 @@ class RoketDizi(PluginBase):
|
|
|
169
169
|
year = year
|
|
170
170
|
)
|
|
171
171
|
|
|
172
|
-
async def load_links(self, url: str) -> list[
|
|
172
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
173
173
|
resp = await self.httpx.get(url)
|
|
174
174
|
sel = Selector(resp.text)
|
|
175
175
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
import re, base64, json, urllib.parse
|
|
6
6
|
|
|
@@ -137,8 +137,13 @@ class SelcukFlix(PluginBase):
|
|
|
137
137
|
search_url = f"{self.main_url}/api/bg/searchcontent?searchterm={query}"
|
|
138
138
|
|
|
139
139
|
headers = {
|
|
140
|
+
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0",
|
|
140
141
|
"Accept" : "application/json, text/plain, */*",
|
|
142
|
+
"Accept-Language" : "en-US,en;q=0.5",
|
|
141
143
|
"X-Requested-With" : "XMLHttpRequest",
|
|
144
|
+
"Sec-Fetch-Site" : "same-origin",
|
|
145
|
+
"Sec-Fetch-Mode" : "cors",
|
|
146
|
+
"Sec-Fetch-Dest" : "empty",
|
|
142
147
|
"Referer" : f"{self.main_url}/"
|
|
143
148
|
}
|
|
144
149
|
|
|
@@ -151,15 +156,16 @@ class SelcukFlix(PluginBase):
|
|
|
151
156
|
try:
|
|
152
157
|
decoded_str = raw_data.decode('utf-8')
|
|
153
158
|
except UnicodeDecodeError:
|
|
154
|
-
decoded_str = raw_data.decode('iso-8859-1')
|
|
159
|
+
decoded_str = raw_data.decode('iso-8859-1')
|
|
155
160
|
|
|
156
161
|
search_data = json.loads(decoded_str)
|
|
157
162
|
|
|
158
163
|
results = []
|
|
159
164
|
for item in search_data.get("result", []):
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
165
|
+
# API field isimleri: object_name, used_slug, object_poster_url
|
|
166
|
+
title = item.get("object_name") or item.get("title")
|
|
167
|
+
slug = item.get("used_slug") or item.get("slug")
|
|
168
|
+
poster = item.get("object_poster_url") or item.get("poster")
|
|
163
169
|
|
|
164
170
|
if poster:
|
|
165
171
|
poster = self.clean_image_url(poster)
|
|
@@ -176,7 +182,7 @@ class SelcukFlix(PluginBase):
|
|
|
176
182
|
except Exception:
|
|
177
183
|
return []
|
|
178
184
|
|
|
179
|
-
async def load_item(self, url: str) -> SeriesInfo:
|
|
185
|
+
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
180
186
|
resp = await self.httpx.get(url)
|
|
181
187
|
sel = Selector(resp.text)
|
|
182
188
|
|
|
@@ -190,15 +196,17 @@ class SelcukFlix(PluginBase):
|
|
|
190
196
|
try:
|
|
191
197
|
decoded_str = raw_data.decode('utf-8')
|
|
192
198
|
except UnicodeDecodeError:
|
|
193
|
-
decoded_str = raw_data.decode('iso-8859-1')
|
|
199
|
+
decoded_str = raw_data.decode('iso-8859-1')
|
|
194
200
|
|
|
195
201
|
content_details = json.loads(decoded_str)
|
|
196
202
|
item = content_details.get("contentItem", {})
|
|
197
203
|
|
|
198
|
-
title = item.get("original_title") or item.get("originalTitle")
|
|
204
|
+
title = item.get("original_title") or item.get("originalTitle") or ""
|
|
199
205
|
poster = self.clean_image_url(item.get("poster_url") or item.get("posterUrl"))
|
|
200
206
|
description = item.get("description") or item.get("used_description")
|
|
201
207
|
rating = str(item.get("imdb_point") or item.get("imdbPoint", ""))
|
|
208
|
+
year = item.get("release_year") or item.get("releaseYear")
|
|
209
|
+
duration = item.get("total_minutes") or item.get("totalMinutes")
|
|
202
210
|
|
|
203
211
|
series_data = content_details.get("relatedData", {}).get("seriesData")
|
|
204
212
|
if not series_data and "RelatedResults" in content_details:
|
|
@@ -206,17 +214,18 @@ class SelcukFlix(PluginBase):
|
|
|
206
214
|
if series_data and isinstance(series_data, list):
|
|
207
215
|
pass
|
|
208
216
|
|
|
209
|
-
|
|
217
|
+
# Dizi mi film mi kontrol et (Kotlin referansı)
|
|
210
218
|
if series_data:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
219
|
+
episodes = []
|
|
220
|
+
seasons_list = []
|
|
221
|
+
if isinstance(series_data, dict):
|
|
222
|
+
seasons_list = series_data.get("seasons", [])
|
|
223
|
+
elif isinstance(series_data, list):
|
|
224
|
+
seasons_list = series_data
|
|
225
|
+
|
|
226
|
+
for season in seasons_list:
|
|
218
227
|
if not isinstance(season, dict): continue
|
|
219
|
-
s_no = season.get("season_no") or season.get("seasonNo")
|
|
228
|
+
s_no = season.get("season_no") or season.get("seasonNo")
|
|
220
229
|
ep_list = season.get("episodes", [])
|
|
221
230
|
for ep in ep_list:
|
|
222
231
|
episodes.append(Episode(
|
|
@@ -225,17 +234,29 @@ class SelcukFlix(PluginBase):
|
|
|
225
234
|
title = ep.get("ep_text") or ep.get("epText"),
|
|
226
235
|
url = self.fix_url(ep.get("used_slug") or ep.get("usedSlug"))
|
|
227
236
|
))
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
237
|
+
|
|
238
|
+
return SeriesInfo(
|
|
239
|
+
title = title,
|
|
240
|
+
url = url,
|
|
241
|
+
poster = poster,
|
|
242
|
+
description = description,
|
|
243
|
+
rating = rating,
|
|
244
|
+
year = year,
|
|
245
|
+
episodes = episodes
|
|
246
|
+
)
|
|
247
|
+
else:
|
|
248
|
+
# Film ise MovieInfo döndür
|
|
249
|
+
return MovieInfo(
|
|
250
|
+
title = title,
|
|
251
|
+
url = url,
|
|
252
|
+
poster = poster,
|
|
253
|
+
description = description,
|
|
254
|
+
rating = rating,
|
|
255
|
+
year = year,
|
|
256
|
+
duration = duration
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
239
260
|
resp = await self.httpx.get(url)
|
|
240
261
|
sel = Selector(resp.text)
|
|
241
262
|
|
|
@@ -248,42 +269,45 @@ class SelcukFlix(PluginBase):
|
|
|
248
269
|
secure_data = data["props"]["pageProps"]["secureData"]
|
|
249
270
|
raw_data = base64.b64decode(secure_data.replace('"', ''))
|
|
250
271
|
|
|
251
|
-
# Try UTF-8 first, fallback to ISO-8859-1 (matching Kotlin)
|
|
252
272
|
try:
|
|
253
273
|
decoded_str = raw_data.decode('utf-8')
|
|
254
274
|
except UnicodeDecodeError:
|
|
255
275
|
decoded_str = raw_data.decode('iso-8859-1')
|
|
256
276
|
|
|
257
277
|
content_details = json.loads(decoded_str)
|
|
258
|
-
|
|
278
|
+
related_results = content_details.get("RelatedResults", {})
|
|
259
279
|
|
|
260
280
|
source_content = None
|
|
261
281
|
|
|
262
|
-
#
|
|
282
|
+
# Dizi (bölüm) için
|
|
263
283
|
if "/dizi/" in url:
|
|
264
|
-
|
|
265
|
-
|
|
284
|
+
episode_sources = related_results.get("getEpisodeSources", {})
|
|
285
|
+
if episode_sources.get("state"):
|
|
286
|
+
res = episode_sources.get("result", [])
|
|
266
287
|
if res:
|
|
267
|
-
source_content = res[0].get("sourceContent")
|
|
288
|
+
source_content = res[0].get("source_content") or res[0].get("sourceContent")
|
|
268
289
|
else:
|
|
269
|
-
#
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
rr = content_details.get("RelatedResults", {})
|
|
290
|
+
# Film için
|
|
291
|
+
movie_parts = related_results.get("getMoviePartsById", {})
|
|
292
|
+
if movie_parts.get("state"):
|
|
293
|
+
parts = movie_parts.get("result", [])
|
|
294
|
+
if parts:
|
|
295
|
+
first_part_id = parts[0].get("id")
|
|
276
296
|
key = f"getMoviePartSourcesById_{first_part_id}"
|
|
277
|
-
if key in
|
|
278
|
-
res =
|
|
297
|
+
if key in related_results:
|
|
298
|
+
res = related_results[key].get("result", [])
|
|
279
299
|
if res:
|
|
280
|
-
source_content = res[0].get("source_content")
|
|
300
|
+
source_content = res[0].get("source_content") or res[0].get("sourceContent")
|
|
281
301
|
|
|
282
302
|
if source_content:
|
|
283
303
|
iframe_sel = Selector(source_content)
|
|
284
304
|
iframe_src = iframe_sel.css("iframe::attr(src)").get()
|
|
285
305
|
if iframe_src:
|
|
286
306
|
iframe_src = self.fix_url(iframe_src)
|
|
307
|
+
# Hotlinger domain değişimi (Kotlin referansı)
|
|
308
|
+
if "sn.dplayer74.site" in iframe_src:
|
|
309
|
+
iframe_src = iframe_src.replace("sn.dplayer74.site", "sn.hotlinger.com")
|
|
310
|
+
|
|
287
311
|
data = await self.extract(iframe_src)
|
|
288
312
|
if data:
|
|
289
313
|
return [data]
|
|
@@ -1,6 +1,6 @@
|
|
|
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
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
import re, json
|
|
6
6
|
|
|
@@ -34,6 +34,23 @@ class SetFilmIzle(PluginBase):
|
|
|
34
34
|
f"{main_url}/tur/western/" : "Western"
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
def _get_nonce(self, nonce_type: str = "video_nonce", referer: str = None) -> str:
|
|
38
|
+
"""Site cache'lenmiş nonce'ları expire olabiliyor, fresh nonce al"""
|
|
39
|
+
try:
|
|
40
|
+
resp = self.cloudscraper.post(
|
|
41
|
+
f"{self.main_url}/wp-admin/admin-ajax.php",
|
|
42
|
+
headers = {
|
|
43
|
+
"Referer" : referer or self.main_url,
|
|
44
|
+
"Origin" : self.main_url,
|
|
45
|
+
"Content-Type" : "application/x-www-form-urlencoded",
|
|
46
|
+
},
|
|
47
|
+
data = "action=st_cache_refresh_nonces"
|
|
48
|
+
)
|
|
49
|
+
nonces = resp.json().get("data", {}).get("nonces", {})
|
|
50
|
+
return nonces.get(nonce_type, "")
|
|
51
|
+
except:
|
|
52
|
+
return ""
|
|
53
|
+
|
|
37
54
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
38
55
|
istek = self.cloudscraper.get(url)
|
|
39
56
|
secici = Selector(istek.text)
|
|
@@ -55,23 +72,7 @@ class SetFilmIzle(PluginBase):
|
|
|
55
72
|
return results
|
|
56
73
|
|
|
57
74
|
async def search(self, query: str) -> list[SearchResult]:
|
|
58
|
-
|
|
59
|
-
main_resp = self.cloudscraper.get(self.main_url)
|
|
60
|
-
|
|
61
|
-
# Birden fazla nonce pattern dene
|
|
62
|
-
nonce = ""
|
|
63
|
-
nonce_patterns = [
|
|
64
|
-
r'nonces:\s*\{\s*search:\s*"([^"]+)"', # STMOVIE_AJAX.nonces.search
|
|
65
|
-
r'"search":\s*"([a-zA-Z0-9]+)"', # JSON format
|
|
66
|
-
r"nonce:\s*'([^']*)'",
|
|
67
|
-
r'"nonce":"([^"]+)"',
|
|
68
|
-
r'data-nonce="([^"]+)"',
|
|
69
|
-
]
|
|
70
|
-
for pattern in nonce_patterns:
|
|
71
|
-
match = re.search(pattern, main_resp.text)
|
|
72
|
-
if match:
|
|
73
|
-
nonce = match.group(1)
|
|
74
|
-
break
|
|
75
|
+
nonce = self._get_nonce("search")
|
|
75
76
|
|
|
76
77
|
search_resp = self.cloudscraper.post(
|
|
77
78
|
f"{self.main_url}/wp-admin/admin-ajax.php",
|
|
@@ -193,11 +194,11 @@ class SetFilmIzle(PluginBase):
|
|
|
193
194
|
actors = actors
|
|
194
195
|
)
|
|
195
196
|
|
|
196
|
-
async def load_links(self, url: str) -> list[
|
|
197
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
197
198
|
istek = await self.httpx.get(url)
|
|
198
199
|
secici = Selector(istek.text)
|
|
199
200
|
|
|
200
|
-
nonce =
|
|
201
|
+
nonce = self._get_nonce("video_nonce", referer=url)
|
|
201
202
|
|
|
202
203
|
# partKey to dil label mapping
|
|
203
204
|
part_key_labels = {
|
|
@@ -215,7 +216,6 @@ class SetFilmIzle(PluginBase):
|
|
|
215
216
|
if not source_id or "event" in source_id or source_id == "":
|
|
216
217
|
continue
|
|
217
218
|
|
|
218
|
-
# Multipart form request
|
|
219
219
|
try:
|
|
220
220
|
resp = self.cloudscraper.post(
|
|
221
221
|
f"{self.main_url}/wp-admin/admin-ajax.php",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
import re
|
|
6
6
|
|
|
@@ -20,6 +20,23 @@ class SezonlukDizi(PluginBase):
|
|
|
20
20
|
f"{main_url}/diziler.asp?siralama_tipi=id&kat=4&s=" : "Animasyonlar",
|
|
21
21
|
f"{main_url}/diziler.asp?siralama_tipi=id&kat=5&s=" : "Animeler",
|
|
22
22
|
f"{main_url}/diziler.asp?siralama_tipi=id&kat=6&s=" : "Belgeseller",
|
|
23
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=aile&s=" : "Aile",
|
|
24
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=aksiyon&s=" : "Aksiyon",
|
|
25
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=bilimkurgu&s=" : "Bilim Kurgu",
|
|
26
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=biyografik&s=" : "Biyografi",
|
|
27
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=dram&s=" : "Dram",
|
|
28
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=fantastik&s=" : "Fantastik",
|
|
29
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=gerilim&s=" : "Gerilim",
|
|
30
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=gizem&s=" : "Gizem",
|
|
31
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=korku&s=" : "Korku",
|
|
32
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=komedi&s=" : "Komedi",
|
|
33
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=macera&s=" : "Macera",
|
|
34
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=muzikal&s=" : "Müzikal",
|
|
35
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=suc&s=" : "Suç",
|
|
36
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=romantik&s=" : "Romantik",
|
|
37
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=savas&s=" : "Savaş",
|
|
38
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=tarihi&s=" : "Tarihi",
|
|
39
|
+
f"{main_url}/diziler.asp?siralama_tipi=id&tur=western&s=" : "Western"
|
|
23
40
|
}
|
|
24
41
|
|
|
25
42
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
@@ -114,7 +131,7 @@ class SezonlukDizi(PluginBase):
|
|
|
114
131
|
except Exception:
|
|
115
132
|
return ("22", "22") # Fallback to default versions
|
|
116
133
|
|
|
117
|
-
async def load_links(self, url: str) -> list[
|
|
134
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
118
135
|
istek = await self.httpx.get(url)
|
|
119
136
|
secici = Selector(istek.text)
|
|
120
137
|
|