KekikStream 2.4.7__py3-none-any.whl → 2.4.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.
Potentially problematic release.
This version of KekikStream might be problematic. Click here for more details.
- KekikStream/Extractors/JetV.py +55 -0
- KekikStream/Extractors/Veev.py +145 -0
- KekikStream/Extractors/VidBiz.py +62 -0
- KekikStream/Extractors/VidHide.py +56 -7
- KekikStream/Extractors/Vtbe.py +38 -0
- KekikStream/Extractors/Zeus.py +61 -0
- KekikStream/Plugins/BelgeselX.py +3 -4
- KekikStream/Plugins/DiziBox.py +3 -3
- KekikStream/Plugins/DiziMom.py +48 -42
- KekikStream/Plugins/DiziPal.py +1 -1
- KekikStream/Plugins/Dizilla.py +2 -2
- KekikStream/Plugins/FilmBip.py +4 -11
- KekikStream/Plugins/FilmEkseni.py +59 -55
- KekikStream/Plugins/FilmMakinesi.py +42 -5
- KekikStream/Plugins/FilmModu.py +0 -1
- KekikStream/Plugins/Filmatek.py +4 -11
- KekikStream/Plugins/{Full4kizle.py → FilmciBaba.py} +55 -74
- KekikStream/Plugins/FullHDFilmizlesene.py +6 -7
- KekikStream/Plugins/HDFilm.py +243 -0
- KekikStream/Plugins/HDFilmCehennemi.py +230 -138
- KekikStream/Plugins/JetFilmizle.py +82 -49
- {kekikstream-2.4.7.dist-info → kekikstream-2.4.9.dist-info}/METADATA +1 -1
- {kekikstream-2.4.7.dist-info → kekikstream-2.4.9.dist-info}/RECORD +27 -22
- KekikStream/Plugins/FullHDFilm.py +0 -179
- {kekikstream-2.4.7.dist-info → kekikstream-2.4.9.dist-info}/WHEEL +0 -0
- {kekikstream-2.4.7.dist-info → kekikstream-2.4.9.dist-info}/entry_points.txt +0 -0
- {kekikstream-2.4.7.dist-info → kekikstream-2.4.9.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-2.4.7.dist-info → kekikstream-2.4.9.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core
|
|
4
|
-
from Kekik.Sifreleme
|
|
5
|
-
import random, string
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, Subtitle, ExtractResult, HTMLHelper
|
|
4
|
+
from Kekik.Sifreleme import Packer, StreamDecoder
|
|
5
|
+
import random, string, json, asyncio, contextlib
|
|
6
6
|
|
|
7
7
|
class HDFilmCehennemi(PluginBase):
|
|
8
8
|
name = "HDFilmCehennemi"
|
|
@@ -12,20 +12,43 @@ class HDFilmCehennemi(PluginBase):
|
|
|
12
12
|
description = "Türkiye'nin en hızlı hd film izleme sitesi. Tek ve gerçek hdfilmcehennemi sitesi."
|
|
13
13
|
|
|
14
14
|
main_page = {
|
|
15
|
-
f"{main_url}"
|
|
16
|
-
f"{main_url}/yabancidiziizle-
|
|
17
|
-
f"{main_url}/
|
|
18
|
-
f"{main_url}/
|
|
19
|
-
f"{main_url}/
|
|
20
|
-
f"{main_url}/
|
|
21
|
-
f"{main_url}/
|
|
22
|
-
f"{main_url}/
|
|
23
|
-
f"{main_url}/
|
|
24
|
-
f"{main_url}/
|
|
25
|
-
f"{main_url}/
|
|
26
|
-
f"{main_url}/
|
|
27
|
-
f"{main_url}/
|
|
28
|
-
f"{main_url}/
|
|
15
|
+
f"{main_url}" : "Yeni Eklenen Filmler",
|
|
16
|
+
f"{main_url}/yabancidiziizle-5" : "Yeni Eklenen Diziler",
|
|
17
|
+
f"{main_url}/dil/turkce-dublajli-film-izleyin-5" : "Türkçe Dublaj Filmler",
|
|
18
|
+
f"{main_url}/dil/turkce-altyazili-filmleri-izleme-sitesi-3" : "Türkçe Altyazılı Filmler",
|
|
19
|
+
f"{main_url}/category/tavsiye-filmler-izle3" : "Tavsiye Filmler",
|
|
20
|
+
f"{main_url}/imdb-7-puan-uzeri-filmler-2" : "IMDB 7+ Filmler",
|
|
21
|
+
f"{main_url}/en-cok-yorumlananlar-2" : "En Çok Yorumlananlar",
|
|
22
|
+
f"{main_url}/en-cok-begenilen-filmleri-izle-4" : "En Çok Beğenilenler",
|
|
23
|
+
f"{main_url}/serifilmlerim-4" : "Seri Filmler",
|
|
24
|
+
f"{main_url}/category/nette-ilk-filmler" : "Nette İlk Filmler",
|
|
25
|
+
f"{main_url}/category/4k-film-izle-5" : "4K Filmler",
|
|
26
|
+
f"{main_url}/category/1080p-hd-film-izle-5" : "1080p Filmler",
|
|
27
|
+
f"{main_url}/category/amazon-yapimlarini-izle" : "Amazon Yapımları",
|
|
28
|
+
f"{main_url}/category/netflix-yapimlari-izle" : "Netflix Yapımları",
|
|
29
|
+
f"{main_url}/category/marvel-yapimlarini-izle-5" : "Marvel Filmleri",
|
|
30
|
+
f"{main_url}/category/dc-yapimlarini-izle-1" : "DC Filmleri",
|
|
31
|
+
f"{main_url}/tur/aile-filmleri-izleyin-7" : "Aile Filmleri",
|
|
32
|
+
f"{main_url}/tur/aksiyon-filmleri-izleyin-6" : "Aksiyon Filmleri",
|
|
33
|
+
f"{main_url}/tur/animasyon-filmlerini-izleyin-5" : "Animasyon Filmleri",
|
|
34
|
+
f"{main_url}/tur/belgesel-filmlerini-izle-2" : "Belgesel Filmleri",
|
|
35
|
+
f"{main_url}/tur/bilim-kurgu-filmlerini-izleyin-5" : "Bilim Kurgu Filmleri",
|
|
36
|
+
f"{main_url}/tur/biyografi-filmleri-izle-3" : "Biyografi Filmleri",
|
|
37
|
+
f"{main_url}/tur/dram-filmlerini-izle-2" : "Dram Filmleri",
|
|
38
|
+
f"{main_url}/tur/fantastik-filmlerini-izleyin-3" : "Fantastik Filmleri",
|
|
39
|
+
f"{main_url}/tur/gerilim-filmlerini-izle-2" : "Gerilim Filmleri",
|
|
40
|
+
f"{main_url}/tur/gizem-filmleri-izle-3" : "Gizem Filmleri",
|
|
41
|
+
f"{main_url}/tur/komedi-filmlerini-izleyin-2" : "Komedi Filmleri",
|
|
42
|
+
f"{main_url}/tur/korku-filmlerini-izle-5" : "Korku Filmleri",
|
|
43
|
+
f"{main_url}/tur/macera-filmlerini-izleyin-4" : "Macera Filmleri",
|
|
44
|
+
f"{main_url}/tur/muzik-filmlerini-izle-844" : "Müzik Filmleri",
|
|
45
|
+
f"{main_url}/tur/polisiye-filmleri-izle" : "Polisiye Filmleri",
|
|
46
|
+
f"{main_url}/tur/romantik-filmleri-izle-3" : "Romantik Filmleri",
|
|
47
|
+
f"{main_url}/tur/savas-filmleri-izle-5" : "Savaş Filmleri",
|
|
48
|
+
f"{main_url}/tur/spor-filmleri-izle-3" : "Spor Filmleri",
|
|
49
|
+
f"{main_url}/tur/suc-filmleri-izle-3" : "Suç Filmleri",
|
|
50
|
+
f"{main_url}/tur/tarih-filmleri-izle-5" : "Tarih Filmleri",
|
|
51
|
+
f"{main_url}/tur/western-filmleri-izle-3" : "Western Filmleri"
|
|
29
52
|
}
|
|
30
53
|
|
|
31
54
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
@@ -34,8 +57,8 @@ class HDFilmCehennemi(PluginBase):
|
|
|
34
57
|
|
|
35
58
|
results = []
|
|
36
59
|
for veri in secici.select("div.section-content a.poster"):
|
|
37
|
-
title
|
|
38
|
-
href
|
|
60
|
+
title = secici.select_text("strong.poster-title", veri)
|
|
61
|
+
href = veri.attrs.get("href")
|
|
39
62
|
poster = secici.select_attr("img", "data-src", veri)
|
|
40
63
|
|
|
41
64
|
if title and href:
|
|
@@ -98,117 +121,163 @@ class HDFilmCehennemi(PluginBase):
|
|
|
98
121
|
href = ep.attrs.get("href")
|
|
99
122
|
if name and href:
|
|
100
123
|
s, e = secici.extract_season_episode(name)
|
|
101
|
-
episodes.append(Episode(
|
|
124
|
+
episodes.append(Episode(
|
|
125
|
+
season = s or 1,
|
|
126
|
+
episode = e or 1,
|
|
127
|
+
title = name,
|
|
128
|
+
url = self.fix_url(href)
|
|
129
|
+
))
|
|
102
130
|
|
|
103
131
|
return SeriesInfo(
|
|
104
|
-
url=url,
|
|
105
|
-
|
|
132
|
+
url = url,
|
|
133
|
+
poster = self.fix_url(poster),
|
|
134
|
+
title = title,
|
|
135
|
+
description = description,
|
|
136
|
+
tags = tags,
|
|
137
|
+
rating = rating,
|
|
138
|
+
year = year,
|
|
139
|
+
actors = actors,
|
|
140
|
+
episodes = episodes
|
|
106
141
|
)
|
|
107
142
|
|
|
108
143
|
return MovieInfo(
|
|
109
|
-
url=url,
|
|
110
|
-
|
|
144
|
+
url = url,
|
|
145
|
+
poster = self.fix_url(poster),
|
|
146
|
+
title = title,
|
|
147
|
+
description = description,
|
|
148
|
+
tags = tags,
|
|
149
|
+
rating = rating,
|
|
150
|
+
year = year,
|
|
151
|
+
actors = actors,
|
|
152
|
+
duration = duration
|
|
111
153
|
)
|
|
112
154
|
|
|
113
155
|
def generate_random_cookie(self):
|
|
114
156
|
return "".join(random.choices(string.ascii_letters + string.digits, k=16))
|
|
115
157
|
|
|
116
|
-
async def cehennempass(self, video_id: str) -> list:
|
|
158
|
+
async def cehennempass(self, video_id: str, name_prefix: str = "", subtitles: list[Subtitle] = None) -> list[ExtractResult]:
|
|
117
159
|
results = []
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
"Referer" : f"https://cehennempass.pw/download/{video_id}",
|
|
140
|
-
"X-Requested-With" : "fetch",
|
|
141
|
-
"authority" : "cehennempass.pw",
|
|
142
|
-
"Cookie" : f"PHPSESSID={self.generate_random_cookie()}"
|
|
143
|
-
},
|
|
144
|
-
data = {"video_id": video_id, "selected_quality": "high"},
|
|
145
|
-
)
|
|
146
|
-
if video_url := istek.json().get("download_link"):
|
|
147
|
-
results.append(ExtractResult(
|
|
148
|
-
url = self.fix_url(video_url),
|
|
149
|
-
name = "Yüksek Kalite",
|
|
150
|
-
referer = f"https://cehennempass.pw/download/{video_id}"
|
|
151
|
-
))
|
|
160
|
+
subs = subtitles or []
|
|
161
|
+
|
|
162
|
+
for quality, label in [("low", "Düşük Kalite"), ("high", "Yüksek Kalite")]:
|
|
163
|
+
with contextlib.suppress(Exception):
|
|
164
|
+
istek = await self.httpx.post(
|
|
165
|
+
url = "https://cehennempass.pw/process_quality_selection.php",
|
|
166
|
+
headers = {
|
|
167
|
+
"Referer" : f"https://cehennempass.pw/download/{video_id}",
|
|
168
|
+
"X-Requested-With" : "fetch",
|
|
169
|
+
"authority" : "cehennempass.pw",
|
|
170
|
+
"Cookie" : f"PHPSESSID={self.generate_random_cookie()}"
|
|
171
|
+
},
|
|
172
|
+
data = {"video_id": video_id, "selected_quality": quality},
|
|
173
|
+
)
|
|
174
|
+
if video_url := istek.json().get("download_link"):
|
|
175
|
+
results.append(ExtractResult(
|
|
176
|
+
url = self.fix_url(video_url),
|
|
177
|
+
name = f"{name_prefix} | {label}" if name_prefix else label,
|
|
178
|
+
referer = f"https://cehennempass.pw/download/{video_id}",
|
|
179
|
+
subtitles = subs
|
|
180
|
+
))
|
|
152
181
|
|
|
153
182
|
return results
|
|
154
183
|
|
|
155
|
-
def
|
|
156
|
-
"""
|
|
157
|
-
|
|
158
|
-
|
|
184
|
+
def _extract_video_url(self, html: str) -> str | None:
|
|
185
|
+
"""Video URL'sini çeşitli yöntemlerle (JSON-LD, Regex, Packer) çıkarır"""
|
|
186
|
+
secici = HTMLHelper(html)
|
|
187
|
+
|
|
188
|
+
# 1. JSON-LD'den dene
|
|
189
|
+
json_ld = secici.regex_first(r'(?s)<script[^>]+type=["\']application/ld\+json["\'][^>]*>(.*?)</script>')
|
|
159
190
|
if json_ld:
|
|
160
|
-
|
|
161
|
-
import json
|
|
191
|
+
with contextlib.suppress(Exception):
|
|
162
192
|
data = json.loads(json_ld.strip())
|
|
163
193
|
if content_url := data.get("contentUrl"):
|
|
164
194
|
if content_url.startswith("http"):
|
|
165
195
|
return content_url
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
196
|
+
|
|
197
|
+
# 2. Regex ile contentUrl dene
|
|
198
|
+
content_url = secici.regex_first(r'"contentUrl"\s*:\s*"([^"]+)"')
|
|
199
|
+
if content_url and content_url.startswith("http"):
|
|
200
|
+
return content_url
|
|
201
|
+
|
|
202
|
+
# 3. Packed JavaScript (eval(function...)) dene
|
|
203
|
+
if eval_script := secici.regex_first(r'(eval\(function[\s\S]+)'):
|
|
204
|
+
with contextlib.suppress(Exception):
|
|
205
|
+
unpacked = Packer.unpack(eval_script)
|
|
206
|
+
return StreamDecoder.extract_stream_url(unpacked)
|
|
207
|
+
|
|
171
208
|
return None
|
|
172
209
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
210
|
+
def _extract_subtitles(self, html: str) -> list[Subtitle]:
|
|
211
|
+
"""HTML içeriğinden çeşitli formatlardaki altyazıları çıkarır"""
|
|
212
|
+
subtitles = []
|
|
213
|
+
secici = HTMLHelper(html)
|
|
214
|
+
|
|
215
|
+
# 1. JWPlayer / Plyr / Generic JS Object (tracks: [ ... ])
|
|
216
|
+
if match := secici.regex_first(r'tracks\s*:\s*(\[[^\]]+\])'):
|
|
217
|
+
# JSON parse denemesi
|
|
218
|
+
with contextlib.suppress(Exception):
|
|
219
|
+
track_data = json.loads(match)
|
|
220
|
+
for t in track_data:
|
|
221
|
+
if file_url := t.get("file"):
|
|
222
|
+
label = t.get("label") or t.get("language") or "TR"
|
|
223
|
+
if t.get("kind", "captions") in ["captions", "subtitles"]:
|
|
224
|
+
subtitles.append(Subtitle(name=label.upper(), url=self.fix_url(file_url)))
|
|
225
|
+
return subtitles # JSON başarılıysa dön
|
|
226
|
+
|
|
227
|
+
# Regex fallback
|
|
228
|
+
for m in HTMLHelper(match).regex_all(r'file\s*:\s*["\']([^"\']+)["\'].*?(?:label|language)\s*:\s*["\']([^"\']+)["\']'):
|
|
229
|
+
file_url, lang = m
|
|
230
|
+
subtitles.append(Subtitle(name=lang.upper(), url=self.fix_url(file_url.replace("\\", ""))))
|
|
231
|
+
|
|
232
|
+
# 2. PlayerJS (subtitle: "url,name;url,name")
|
|
233
|
+
if not subtitles:
|
|
234
|
+
if sub_str := secici.regex_first(r'subtitle\s*:\s*["\']([^"\']+)["\']'):
|
|
235
|
+
for sub_item in sub_str.split(";"):
|
|
236
|
+
if "," in sub_item:
|
|
237
|
+
# [TR]url,[EN]url gibi yapılar için split mantığı
|
|
238
|
+
# Basitçe virgülle ayırıp http kontrolü yapalım
|
|
239
|
+
parts = sub_item.split(",")
|
|
240
|
+
u, n = (parts[0], parts[1]) if "http" in parts[0] else (parts[1], parts[0])
|
|
241
|
+
subtitles.append(Subtitle(name=n.strip(), url=self.fix_url(u.strip())))
|
|
242
|
+
elif "http" in sub_item:
|
|
243
|
+
subtitles.append(Subtitle(name="TR", url=self.fix_url(sub_item.strip())))
|
|
244
|
+
|
|
245
|
+
# 3. HTML5 Track Tags
|
|
246
|
+
if not subtitles:
|
|
247
|
+
for track in secici.select("track[kind='captions'], track[kind='subtitles']"):
|
|
248
|
+
src = track.attrs.get("src")
|
|
249
|
+
label = track.attrs.get("label") or track.attrs.get("srclang") or "TR"
|
|
250
|
+
if src:
|
|
251
|
+
subtitles.append(Subtitle(name=label.upper(), url=self.fix_url(src)))
|
|
252
|
+
|
|
253
|
+
return subtitles
|
|
254
|
+
|
|
255
|
+
async def invoke_local_source(self, iframe: str, source: str, url: str) -> list[ExtractResult]:
|
|
256
|
+
istek = await self.httpx.get(
|
|
257
|
+
url = iframe,
|
|
258
|
+
headers = {
|
|
259
|
+
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
|
260
|
+
"X-Requested-With" : "XMLHttpRequest",
|
|
261
|
+
"Referer" : self.main_url + "/"
|
|
262
|
+
}
|
|
263
|
+
)
|
|
179
264
|
|
|
180
|
-
|
|
181
|
-
|
|
265
|
+
# ID'yi güvenli al
|
|
266
|
+
video_id = iframe.rstrip("/").split("/")[-1]
|
|
182
267
|
|
|
183
|
-
#
|
|
184
|
-
|
|
268
|
+
# Boş yanıt kontrolü
|
|
269
|
+
if not istek.text or len(istek.text) < 50:
|
|
270
|
+
return await self.cehennempass(video_id, source, [])
|
|
185
271
|
|
|
186
|
-
#
|
|
187
|
-
|
|
188
|
-
# eval(function...) içeren packed script bul
|
|
189
|
-
eval_script = HTMLHelper(istek.text).regex_first(r'(eval\(function[\s\S]+)')
|
|
190
|
-
if not eval_script:
|
|
191
|
-
return await self.cehennempass(iframe.split("/")[-1])
|
|
272
|
+
# 1. Altyazıları Çıkar
|
|
273
|
+
subtitles = self._extract_subtitles(istek.text)
|
|
192
274
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
video_url = StreamDecoder.extract_stream_url(unpacked)
|
|
196
|
-
except Exception:
|
|
197
|
-
return await self.cehennempass(iframe.split("/")[-1])
|
|
198
|
-
|
|
199
|
-
if not video_url:
|
|
200
|
-
return await self.cehennempass(iframe.split("/")[-1])
|
|
275
|
+
# 2. Video URL'sini Çıkar
|
|
276
|
+
video_url = self._extract_video_url(istek.text)
|
|
201
277
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
for file_url, lang in HTMLHelper(sub_data).regex_all(r'(?s)file":"([^\\"]+)".*?"language":"([^\\"]+)"'):
|
|
206
|
-
subtitles.append(Subtitle(
|
|
207
|
-
name = lang.upper(),
|
|
208
|
-
url = self.fix_url(file_url.replace("\\", "")),
|
|
209
|
-
))
|
|
210
|
-
except Exception:
|
|
211
|
-
pass
|
|
278
|
+
# 3. Eğer Video URL yoksa CehennemPass'a git
|
|
279
|
+
if not video_url:
|
|
280
|
+
return await self.cehennempass(video_id, source, subtitles)
|
|
212
281
|
|
|
213
282
|
return [ExtractResult(
|
|
214
283
|
url = video_url,
|
|
@@ -217,49 +286,72 @@ class HDFilmCehennemi(PluginBase):
|
|
|
217
286
|
subtitles = subtitles
|
|
218
287
|
)]
|
|
219
288
|
|
|
289
|
+
async def _get_video_source(self, video_id: str, source_name: str, referer: str) -> list[ExtractResult]:
|
|
290
|
+
try:
|
|
291
|
+
api_get = await self.httpx.get(
|
|
292
|
+
url = f"{self.main_url}/video/{video_id}/",
|
|
293
|
+
headers = {
|
|
294
|
+
"Content-Type" : "application/json",
|
|
295
|
+
"X-Requested-With" : "fetch",
|
|
296
|
+
"Referer" : referer,
|
|
297
|
+
}
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
# JSON Parse (Daha güvenli)
|
|
301
|
+
# Response: {"success": true, "data": {"html": "<iframe class=\"rapidrame\" data-src=\"...\" ...></iframe>"}}
|
|
302
|
+
try:
|
|
303
|
+
json_data = api_get.json()
|
|
304
|
+
html_content = json_data.get("data", {}).get("html", "")
|
|
305
|
+
iframe = HTMLHelper(html_content).select_attr("iframe", "data-src")
|
|
306
|
+
except:
|
|
307
|
+
# RegEx fallback
|
|
308
|
+
iframe = HTMLHelper(api_get.text).regex_first(r'data-src=\\\"([^\"]+)')
|
|
309
|
+
iframe = iframe.replace("\\", "") if iframe else None
|
|
310
|
+
|
|
311
|
+
if not iframe:
|
|
312
|
+
return []
|
|
313
|
+
|
|
314
|
+
# mobi URL'si varsa direkt kullan
|
|
315
|
+
if "mobi" in iframe: # m.hdfilmcehennemi.nl veya /mobi/
|
|
316
|
+
iframe = iframe.split("?")[0]
|
|
317
|
+
# rapidrame ve query varsa
|
|
318
|
+
elif "rapidrame" in iframe and "?rapidrame_id=" in iframe:
|
|
319
|
+
# /rplayer/ID/ formatına çevir
|
|
320
|
+
rap_id = iframe.split('?rapidrame_id=')[1]
|
|
321
|
+
iframe = f"{self.main_url}/rplayer/{rap_id}"
|
|
322
|
+
|
|
323
|
+
return await self.invoke_local_source(iframe, source_name, referer)
|
|
324
|
+
except Exception:
|
|
325
|
+
return []
|
|
326
|
+
|
|
220
327
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
221
328
|
istek = await self.httpx.get(url)
|
|
222
329
|
secici = HTMLHelper(istek.text)
|
|
223
330
|
|
|
224
|
-
|
|
331
|
+
sources = []
|
|
225
332
|
for alternatif in secici.select("div.alternative-links"):
|
|
226
333
|
lang_code = alternatif.attrs.get("data-lang", "").upper()
|
|
227
334
|
|
|
335
|
+
# Dil metnini bul
|
|
336
|
+
if lang_code:
|
|
337
|
+
if lang_btn := secici.select_first(f"button.language-link[data-lang='{lang_code.lower()}']"):
|
|
338
|
+
lang_text = lang_btn.text(strip=True)
|
|
339
|
+
# "DUAL (Türkçe Dublaj & Altyazılı)" -> "DUAL" yap, diğerleri aynen kalsın
|
|
340
|
+
if "DUAL" in lang_text:
|
|
341
|
+
lang_code = "DUAL"
|
|
342
|
+
else:
|
|
343
|
+
lang_code = lang_text
|
|
344
|
+
|
|
228
345
|
for link in secici.select("button.alternative-link", alternatif):
|
|
229
346
|
source_text = link.text(strip=True).replace('(HDrip Xbet)', '').strip()
|
|
230
|
-
|
|
231
|
-
video_id
|
|
232
|
-
|
|
233
|
-
if not video_id:
|
|
234
|
-
continue
|
|
235
|
-
|
|
236
|
-
api_get = await self.httpx.get(
|
|
237
|
-
url = f"{self.main_url}/video/{video_id}/",
|
|
238
|
-
headers = {
|
|
239
|
-
"Content-Type" : "application/json",
|
|
240
|
-
"X-Requested-With" : "fetch",
|
|
241
|
-
"Referer" : url,
|
|
242
|
-
},
|
|
243
|
-
)
|
|
244
|
-
|
|
245
|
-
iframe = HTMLHelper(api_get.text).regex_first(r'data-src=\\\"([^\"]+)')
|
|
246
|
-
iframe = iframe.replace("\\", "") if iframe else None
|
|
247
|
-
|
|
248
|
-
if not iframe:
|
|
249
|
-
continue
|
|
250
|
-
|
|
251
|
-
# mobi URL'si varsa direkt kullan (query string'i kaldır)
|
|
252
|
-
if "mobi" in iframe:
|
|
253
|
-
iframe = iframe.split("?")[0] # rapidrame_id query param'ı kaldır
|
|
254
|
-
# mobi değilse ve rapidrame varsa rplayer kullan
|
|
255
|
-
elif "rapidrame" in iframe and "?rapidrame_id=" in iframe:
|
|
256
|
-
iframe = f"{self.main_url}/rplayer/{iframe.split('?rapidrame_id=')[1]}"
|
|
347
|
+
source_name = f"{lang_code} | {source_text}".strip()
|
|
348
|
+
video_id = link.attrs.get("data-video")
|
|
257
349
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
continue
|
|
350
|
+
if video_id:
|
|
351
|
+
sources.append((video_id, source_name, url))
|
|
261
352
|
|
|
262
|
-
|
|
263
|
-
|
|
353
|
+
tasks = []
|
|
354
|
+
for vid, name, ref in sources:
|
|
355
|
+
tasks.append(self._get_video_source(vid, name, ref))
|
|
264
356
|
|
|
265
|
-
return
|
|
357
|
+
return [item for sublist in await asyncio.gather(*tasks) for item in sublist]
|
|
@@ -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
|
+
import asyncio
|
|
4
5
|
|
|
5
6
|
class JetFilmizle(PluginBase):
|
|
6
7
|
name = "JetFilmizle"
|
|
@@ -42,17 +43,15 @@ class JetFilmizle(PluginBase):
|
|
|
42
43
|
|
|
43
44
|
results = []
|
|
44
45
|
for veri in secici.select("article.movie"):
|
|
45
|
-
# h2-h6 içindeki a linki
|
|
46
46
|
title_text = None
|
|
47
47
|
for h_tag in ["h2", "h3", "h4", "h5", "h6"]:
|
|
48
48
|
title_text = secici.select_text(f"{h_tag} a", veri)
|
|
49
49
|
if title_text:
|
|
50
50
|
break
|
|
51
51
|
|
|
52
|
-
href = secici.select_attr("a", "href", veri)
|
|
53
|
-
poster = secici.select_poster("img", veri)
|
|
54
|
-
|
|
55
52
|
title = self.clean_title(title_text) if title_text else None
|
|
53
|
+
href = secici.select_attr("a", "href", veri)
|
|
54
|
+
poster = secici.select_poster("img", veri)
|
|
56
55
|
|
|
57
56
|
if title and href:
|
|
58
57
|
results.append(MainPageResult(
|
|
@@ -74,17 +73,15 @@ class JetFilmizle(PluginBase):
|
|
|
74
73
|
|
|
75
74
|
results = []
|
|
76
75
|
for article in secici.select("article.movie"):
|
|
77
|
-
# h2-h6 içindeki a linki
|
|
78
76
|
title_text = None
|
|
79
77
|
for h_tag in ["h2", "h3", "h4", "h5", "h6"]:
|
|
80
78
|
title_text = secici.select_text(f"{h_tag} a", article)
|
|
81
79
|
if title_text:
|
|
82
80
|
break
|
|
83
81
|
|
|
84
|
-
href = secici.select_attr("a", "href", article)
|
|
85
|
-
poster = secici.select_poster("img", article)
|
|
86
|
-
|
|
87
82
|
title = self.clean_title(title_text) if title_text else None
|
|
83
|
+
href = secici.select_attr("a", "href", article)
|
|
84
|
+
poster = secici.select_poster("img", article)
|
|
88
85
|
|
|
89
86
|
if title and href:
|
|
90
87
|
results.append(SearchResult(
|
|
@@ -126,53 +123,89 @@ class JetFilmizle(PluginBase):
|
|
|
126
123
|
rating = rating,
|
|
127
124
|
year = year,
|
|
128
125
|
actors = actors,
|
|
129
|
-
duration =
|
|
126
|
+
duration = total_minutes if total_minutes else None
|
|
130
127
|
)
|
|
131
128
|
|
|
132
|
-
async def
|
|
133
|
-
istek = await self.httpx.get(url)
|
|
134
|
-
secici = HTMLHelper(istek.text)
|
|
135
|
-
|
|
129
|
+
async def _process_source(self, url: str, name: str, html: str | None) -> list[ExtractResult]:
|
|
136
130
|
results = []
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
# 2) Sayfa numaralarından linkleri topla (Fragman hariç)
|
|
151
|
-
page_links = []
|
|
152
|
-
for link in secici.select("a.post-page-numbers"):
|
|
153
|
-
isim = secici.select_text("span", link) or ""
|
|
154
|
-
if isim != "Fragman":
|
|
155
|
-
href = link.attrs.get("href")
|
|
156
|
-
if href:
|
|
157
|
-
page_links.append((self.fix_url(href), isim))
|
|
158
|
-
|
|
159
|
-
# 3) Her sayfa linkindeki iframe'leri bul
|
|
160
|
-
for page_url, isim in page_links:
|
|
161
|
-
try:
|
|
162
|
-
page_resp = await self.httpx.get(page_url)
|
|
163
|
-
page_sel = HTMLHelper(page_resp.text)
|
|
164
|
-
|
|
165
|
-
for iframe in page_sel.select("div#movie iframe"):
|
|
131
|
+
try:
|
|
132
|
+
if html:
|
|
133
|
+
secici = HTMLHelper(html)
|
|
134
|
+
else:
|
|
135
|
+
resp = await self.httpx.get(url)
|
|
136
|
+
secici = HTMLHelper(resp.text)
|
|
137
|
+
|
|
138
|
+
# Iframe'leri bul
|
|
139
|
+
container = secici.select_first("div#movie") or secici.select_first("div.film-content")
|
|
140
|
+
|
|
141
|
+
if container:
|
|
142
|
+
for iframe in secici.select("iframe", container):
|
|
166
143
|
src = (iframe.attrs.get("src") or
|
|
167
144
|
iframe.attrs.get("data-src") or
|
|
168
145
|
iframe.attrs.get("data-lazy-src"))
|
|
169
|
-
|
|
146
|
+
|
|
170
147
|
if src and src != "about:blank":
|
|
171
148
|
iframe_url = self.fix_url(src)
|
|
172
|
-
|
|
149
|
+
# name_override KULLANMA, extractor kendi ismini versin
|
|
150
|
+
# Sonra biz düzenleriz
|
|
151
|
+
data = await self.extract(iframe_url)
|
|
152
|
+
|
|
173
153
|
if data:
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
154
|
+
items = data if isinstance(data, list) else [data]
|
|
155
|
+
|
|
156
|
+
for item in items:
|
|
157
|
+
# Sadece kalite bilgisi içeriyorsa ekle, yoksa sadece buton adını kullan
|
|
158
|
+
# Özellikle Zeus için kalite önemli (1080p, 720p)
|
|
159
|
+
# Diğerlerinde plugin adı (Apollo, JetPlay vb.) önemsiz
|
|
160
|
+
|
|
161
|
+
# Kalite kontrolü (basitçe)
|
|
162
|
+
quality_indicators = ["1080p", "720p", "480p", "360p", "240p", "144p", "4k", "2k"]
|
|
163
|
+
has_quality = any(q in item.name.lower() for q in quality_indicators)
|
|
164
|
+
|
|
165
|
+
if has_quality:
|
|
166
|
+
# Buton Adı | Extractor Adı (Kalite içerdiği için)
|
|
167
|
+
# Örn: Zeus | 1080p
|
|
168
|
+
# Eğer Extractor adı zaten Buton adını içeriyorsa (Zeus | 1080p -> Zeus) tekrar ekleme
|
|
169
|
+
if name.lower() not in item.name.lower():
|
|
170
|
+
item.name = f"{name} | {item.name}"
|
|
171
|
+
else:
|
|
172
|
+
# Kalite yoksa sadece Buton adını kullan
|
|
173
|
+
# Örn: Apollo | JetTv -> JetTv
|
|
174
|
+
item.name = name
|
|
175
|
+
|
|
176
|
+
results.append(item)
|
|
177
|
+
return results
|
|
178
|
+
except Exception:
|
|
179
|
+
return []
|
|
177
180
|
|
|
178
|
-
|
|
181
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
182
|
+
istek = await self.httpx.get(url)
|
|
183
|
+
secici = HTMLHelper(istek.text)
|
|
184
|
+
|
|
185
|
+
sources = []
|
|
186
|
+
if film_part := secici.select_first("div.film_part"):
|
|
187
|
+
# Tüm spanları gez
|
|
188
|
+
for span in secici.select("span", film_part):
|
|
189
|
+
# Eğer bu span bir <a> etiketi içinde değilse, aktif kaynaktır
|
|
190
|
+
if span.parent.tag != "a":
|
|
191
|
+
name = span.text(strip=True)
|
|
192
|
+
if name:
|
|
193
|
+
sources.append((url, name, istek.text)) # html content var
|
|
194
|
+
break
|
|
195
|
+
|
|
196
|
+
# Diğer kaynak linkleri
|
|
197
|
+
for link in secici.select("a.post-page-numbers", film_part):
|
|
198
|
+
name = secici.select_text("span", link) or link.text(strip=True)
|
|
199
|
+
href = link.attrs.get("href")
|
|
200
|
+
if name != "Fragman" and href:
|
|
201
|
+
sources.append((self.fix_url(href), name, None)) # html yok, çekilecek
|
|
202
|
+
|
|
203
|
+
# Eğer film_part yoksa, sadece mevcut sayfayı tara (Tek part olabilir)
|
|
204
|
+
if not sources:
|
|
205
|
+
sources.append((url, "JetFilmizle", istek.text))
|
|
206
|
+
|
|
207
|
+
tasks = []
|
|
208
|
+
for page_url, source_name, html_content in sources:
|
|
209
|
+
tasks.append(self._process_source(page_url, source_name, html_content))
|
|
210
|
+
|
|
211
|
+
return [item for sublist in await asyncio.gather(*tasks) for item in sublist]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: KekikStream
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.9
|
|
4
4
|
Summary: terminal üzerinden medya içeriği aramanızı ve VLC/MPV gibi popüler medya oynatıcılar aracılığıyla doğrudan izlemenizi sağlayan modüler ve genişletilebilir bir bıdı bıdı
|
|
5
5
|
Home-page: https://github.com/keyiflerolsun/KekikStream
|
|
6
6
|
Author: keyiflerolsun
|