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.
Potentially problematic release.
This version of KekikStream might be problematic. Click here for more details.
- 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
|
@@ -1,53 +1,72 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core
|
|
4
|
-
from
|
|
5
|
-
|
|
6
|
-
import random, string, re
|
|
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
|
|
7
6
|
|
|
8
7
|
class HDFilmCehennemi(PluginBase):
|
|
9
8
|
name = "HDFilmCehennemi"
|
|
10
9
|
language = "tr"
|
|
11
|
-
main_url = "https://www.hdfilmcehennemi.
|
|
10
|
+
main_url = "https://www.hdfilmcehennemi.nl"
|
|
12
11
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
13
12
|
description = "Türkiye'nin en hızlı hd film izleme sitesi. Tek ve gerçek hdfilmcehennemi sitesi."
|
|
14
13
|
|
|
15
14
|
main_page = {
|
|
16
|
-
f"{main_url}"
|
|
17
|
-
f"{main_url}/yabancidiziizle-
|
|
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}/
|
|
29
|
-
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"
|
|
30
52
|
}
|
|
31
53
|
|
|
32
54
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
33
55
|
istek = await self.httpx.get(f"{url}", follow_redirects=True)
|
|
34
|
-
secici =
|
|
56
|
+
secici = HTMLHelper(istek.text)
|
|
35
57
|
|
|
36
58
|
results = []
|
|
37
|
-
for veri in secici.
|
|
38
|
-
|
|
39
|
-
img_el = veri.css_first("img")
|
|
40
|
-
|
|
41
|
-
title = title_el.text(strip=True) if title_el else None
|
|
59
|
+
for veri in secici.select("div.section-content a.poster"):
|
|
60
|
+
title = secici.select_text("strong.poster-title", veri)
|
|
42
61
|
href = veri.attrs.get("href")
|
|
43
|
-
poster =
|
|
62
|
+
poster = secici.select_attr("img", "data-src", veri)
|
|
44
63
|
|
|
45
64
|
if title and href:
|
|
46
65
|
results.append(MainPageResult(
|
|
47
66
|
category = category,
|
|
48
67
|
title = title,
|
|
49
68
|
url = self.fix_url(href),
|
|
50
|
-
poster = self.fix_url(poster)
|
|
69
|
+
poster = self.fix_url(poster),
|
|
51
70
|
))
|
|
52
71
|
|
|
53
72
|
return results
|
|
@@ -64,85 +83,55 @@ class HDFilmCehennemi(PluginBase):
|
|
|
64
83
|
|
|
65
84
|
results = []
|
|
66
85
|
for veri in istek.json().get("results", []):
|
|
67
|
-
secici =
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
title = title_el.text(strip=True) if title_el else None
|
|
73
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
74
|
-
poster = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
|
|
75
|
-
|
|
86
|
+
secici = HTMLHelper(veri)
|
|
87
|
+
title = secici.select_text("h4.title")
|
|
88
|
+
href = secici.select_attr("a", "href")
|
|
89
|
+
poster = secici.select_attr("img", "data-src") or secici.select_attr("img", "src")
|
|
90
|
+
|
|
76
91
|
if title and href:
|
|
77
92
|
results.append(SearchResult(
|
|
78
93
|
title = title,
|
|
79
94
|
url = self.fix_url(href),
|
|
80
|
-
poster = self.fix_url(poster) if poster else None,
|
|
95
|
+
poster = self.fix_url(poster).replace("/thumb/", "/list/") if poster else None,
|
|
81
96
|
))
|
|
82
|
-
|
|
97
|
+
|
|
83
98
|
return results
|
|
84
99
|
|
|
85
100
|
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
86
101
|
istek = await self.httpx.get(url, headers = {"Referer": f"{self.main_url}/"})
|
|
87
|
-
secici =
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
year_el = secici.css_first("div.post-info-year-country a")
|
|
104
|
-
year = year_el.text(strip=True) if year_el else ""
|
|
105
|
-
|
|
106
|
-
actors = [a.text(strip=True) for a in secici.css("div.post-info-cast a > strong") if a.text(strip=True)]
|
|
107
|
-
|
|
108
|
-
duration_el = secici.css_first("div.post-info-duration")
|
|
109
|
-
duration_str = duration_el.text(strip=True) if duration_el else "0"
|
|
110
|
-
duration_str = duration_str.replace("dakika", "").strip()
|
|
111
|
-
|
|
112
|
-
try:
|
|
113
|
-
duration_match = re.search(r'\d+', duration_str)
|
|
114
|
-
duration_minutes = int(duration_match.group()) if duration_match else 0
|
|
115
|
-
except Exception:
|
|
116
|
-
duration_minutes = 0
|
|
117
|
-
|
|
118
|
-
# Dizi mi film mi kontrol et (Kotlin referansı: div.seasons kontrolü)
|
|
119
|
-
is_series = len(secici.css("div.seasons")) > 0
|
|
120
|
-
|
|
121
|
-
if is_series:
|
|
102
|
+
secici = HTMLHelper(istek.text)
|
|
103
|
+
|
|
104
|
+
title = self.clean_title(secici.select_text("h1.section-title"))
|
|
105
|
+
poster = secici.select_poster("aside.post-info-poster img.lazyload")
|
|
106
|
+
description = secici.select_text("article.post-info-content > p")
|
|
107
|
+
tags = secici.select_texts("div.post-info-genres a")
|
|
108
|
+
rating = secici.select_text("div.post-info-imdb-rating span")
|
|
109
|
+
rating = rating.split("(")[0] if rating else None
|
|
110
|
+
year = secici.select_text("div.post-info-year-country a")
|
|
111
|
+
actors = secici.select_texts("div.post-info-cast a > strong")
|
|
112
|
+
duration = int(secici.regex_first(r"(\d+)", secici.select_text("div.post-info-duration")) or 0)
|
|
113
|
+
|
|
114
|
+
# Dizi mi film mi kontrol et
|
|
115
|
+
ep_links = secici.select("div.seasons-tab-content a")
|
|
116
|
+
|
|
117
|
+
if ep_links:
|
|
122
118
|
episodes = []
|
|
123
|
-
for ep in
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if ep_name and ep_href:
|
|
129
|
-
# Regex ile sezon ve bölüm numarası çıkar
|
|
130
|
-
ep_match = re.search(r'(\d+)\.\s*Bölüm', ep_name)
|
|
131
|
-
sz_match = re.search(r'(\d+)\.\s*Sezon', ep_name)
|
|
132
|
-
ep_num = int(ep_match.group(1)) if ep_match else 1
|
|
133
|
-
sz_num = int(sz_match.group(1)) if sz_match else 1
|
|
134
|
-
|
|
119
|
+
for ep in ep_links:
|
|
120
|
+
name = secici.select_text("h4", ep)
|
|
121
|
+
href = ep.attrs.get("href")
|
|
122
|
+
if name and href:
|
|
123
|
+
s, e = secici.extract_season_episode(name)
|
|
135
124
|
episodes.append(Episode(
|
|
136
|
-
season =
|
|
137
|
-
episode =
|
|
138
|
-
title =
|
|
139
|
-
url = self.fix_url(
|
|
125
|
+
season = s or 1,
|
|
126
|
+
episode = e or 1,
|
|
127
|
+
title = name,
|
|
128
|
+
url = self.fix_url(href)
|
|
140
129
|
))
|
|
141
130
|
|
|
142
131
|
return SeriesInfo(
|
|
143
132
|
url = url,
|
|
144
|
-
poster = self.fix_url(poster)
|
|
145
|
-
title =
|
|
133
|
+
poster = self.fix_url(poster),
|
|
134
|
+
title = title,
|
|
146
135
|
description = description,
|
|
147
136
|
tags = tags,
|
|
148
137
|
rating = rating,
|
|
@@ -150,118 +139,145 @@ class HDFilmCehennemi(PluginBase):
|
|
|
150
139
|
actors = actors,
|
|
151
140
|
episodes = episodes
|
|
152
141
|
)
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
142
|
+
|
|
143
|
+
return MovieInfo(
|
|
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
|
|
153
|
+
)
|
|
165
154
|
|
|
166
155
|
def generate_random_cookie(self):
|
|
167
156
|
return "".join(random.choices(string.ascii_letters + string.digits, k=16))
|
|
168
157
|
|
|
169
|
-
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]:
|
|
170
159
|
results = []
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
"Referer" : f"https://cehennempass.pw/download/{video_id}",
|
|
193
|
-
"X-Requested-With" : "fetch",
|
|
194
|
-
"authority" : "cehennempass.pw",
|
|
195
|
-
"Cookie" : f"PHPSESSID={self.generate_random_cookie()}"
|
|
196
|
-
},
|
|
197
|
-
data = {"video_id": video_id, "selected_quality": "high"},
|
|
198
|
-
)
|
|
199
|
-
if video_url := istek.json().get("download_link"):
|
|
200
|
-
results.append(ExtractResult(
|
|
201
|
-
url = self.fix_url(video_url),
|
|
202
|
-
name = "Yüksek Kalite",
|
|
203
|
-
referer = f"https://cehennempass.pw/download/{video_id}"
|
|
204
|
-
))
|
|
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
|
+
))
|
|
205
181
|
|
|
206
182
|
return results
|
|
207
183
|
|
|
208
|
-
def
|
|
209
|
-
"""
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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>')
|
|
190
|
+
if json_ld:
|
|
191
|
+
with contextlib.suppress(Exception):
|
|
192
|
+
data = json.loads(json_ld.strip())
|
|
216
193
|
if content_url := data.get("contentUrl"):
|
|
217
194
|
if content_url.startswith("http"):
|
|
218
195
|
return content_url
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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
|
+
|
|
224
208
|
return None
|
|
225
209
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
+
)
|
|
232
264
|
|
|
233
|
-
|
|
234
|
-
|
|
265
|
+
# ID'yi güvenli al
|
|
266
|
+
video_id = iframe.rstrip("/").split("/")[-1]
|
|
235
267
|
|
|
236
|
-
#
|
|
237
|
-
|
|
268
|
+
# Boş yanıt kontrolü
|
|
269
|
+
if not istek.text or len(istek.text) < 50:
|
|
270
|
+
return await self.cehennempass(video_id, source, [])
|
|
238
271
|
|
|
239
|
-
#
|
|
240
|
-
|
|
241
|
-
# eval(function...) içeren packed script bul
|
|
242
|
-
eval_match = re.search(r'(eval\(function[\s\S]+)', istek.text)
|
|
243
|
-
if not eval_match:
|
|
244
|
-
return await self.cehennempass(iframe.split("/")[-1])
|
|
272
|
+
# 1. Altyazıları Çıkar
|
|
273
|
+
subtitles = self._extract_subtitles(istek.text)
|
|
245
274
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
video_url = StreamDecoder.extract_stream_url(unpacked)
|
|
249
|
-
except Exception:
|
|
250
|
-
return await self.cehennempass(iframe.split("/")[-1])
|
|
251
|
-
|
|
252
|
-
if not video_url:
|
|
253
|
-
return await self.cehennempass(iframe.split("/")[-1])
|
|
275
|
+
# 2. Video URL'sini Çıkar
|
|
276
|
+
video_url = self._extract_video_url(istek.text)
|
|
254
277
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
for sub in re.findall(r'file":"([^"]+)".*?"language":"([^"]+)"', sub_data, flags=re.DOTALL):
|
|
259
|
-
subtitles.append(Subtitle(
|
|
260
|
-
name = sub[1].upper(),
|
|
261
|
-
url = self.fix_url(sub[0].replace("\\", "")),
|
|
262
|
-
))
|
|
263
|
-
except Exception:
|
|
264
|
-
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)
|
|
265
281
|
|
|
266
282
|
return [ExtractResult(
|
|
267
283
|
url = video_url,
|
|
@@ -270,49 +286,72 @@ class HDFilmCehennemi(PluginBase):
|
|
|
270
286
|
subtitles = subtitles
|
|
271
287
|
)]
|
|
272
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
|
+
|
|
273
327
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
274
328
|
istek = await self.httpx.get(url)
|
|
275
|
-
secici =
|
|
329
|
+
secici = HTMLHelper(istek.text)
|
|
276
330
|
|
|
277
|
-
|
|
278
|
-
for alternatif in secici.
|
|
331
|
+
sources = []
|
|
332
|
+
for alternatif in secici.select("div.alternative-links"):
|
|
279
333
|
lang_code = alternatif.attrs.get("data-lang", "").upper()
|
|
280
334
|
|
|
281
|
-
|
|
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
|
+
|
|
345
|
+
for link in secici.select("button.alternative-link", alternatif):
|
|
282
346
|
source_text = link.text(strip=True).replace('(HDrip Xbet)', '').strip()
|
|
283
|
-
|
|
284
|
-
video_id
|
|
285
|
-
|
|
286
|
-
if not video_id:
|
|
287
|
-
continue
|
|
288
|
-
|
|
289
|
-
api_get = await self.httpx.get(
|
|
290
|
-
url = f"{self.main_url}/video/{video_id}/",
|
|
291
|
-
headers = {
|
|
292
|
-
"Content-Type" : "application/json",
|
|
293
|
-
"X-Requested-With" : "fetch",
|
|
294
|
-
"Referer" : url,
|
|
295
|
-
},
|
|
296
|
-
)
|
|
297
|
-
|
|
298
|
-
match = re.search(r'data-src=\\\"([^"]+)', api_get.text)
|
|
299
|
-
iframe = match[1].replace("\\", "") if match else None
|
|
300
|
-
|
|
301
|
-
if not iframe:
|
|
302
|
-
continue
|
|
303
|
-
|
|
304
|
-
# mobi URL'si varsa direkt kullan (query string'i kaldır)
|
|
305
|
-
if "mobi" in iframe:
|
|
306
|
-
iframe = iframe.split("?")[0] # rapidrame_id query param'ı kaldır
|
|
307
|
-
# mobi değilse ve rapidrame varsa rplayer kullan
|
|
308
|
-
elif "rapidrame" in iframe and "?rapidrame_id=" in iframe:
|
|
309
|
-
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")
|
|
310
349
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
continue
|
|
350
|
+
if video_id:
|
|
351
|
+
sources.append((video_id, source_name, url))
|
|
314
352
|
|
|
315
|
-
|
|
316
|
-
|
|
353
|
+
tasks = []
|
|
354
|
+
for vid, name, ref in sources:
|
|
355
|
+
tasks.append(self._get_video_source(vid, name, ref))
|
|
317
356
|
|
|
318
|
-
return
|
|
357
|
+
return [item for sublist in await asyncio.gather(*tasks) for item in sublist]
|