KekikStream 1.7.1__py3-none-any.whl → 2.2.0__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 +20 -9
- KekikStream/Core/Extractor/ExtractorLoader.py +25 -17
- KekikStream/Core/Extractor/ExtractorManager.py +53 -9
- KekikStream/Core/Extractor/ExtractorModels.py +5 -7
- KekikStream/Core/Extractor/YTDLPCache.py +35 -0
- KekikStream/Core/Media/MediaHandler.py +44 -26
- KekikStream/Core/Media/MediaManager.py +0 -3
- KekikStream/Core/Plugin/PluginBase.py +82 -22
- KekikStream/Core/Plugin/PluginLoader.py +11 -7
- KekikStream/Core/Plugin/PluginModels.py +25 -26
- KekikStream/Core/__init__.py +1 -0
- KekikStream/Extractors/CloseLoad.py +21 -7
- KekikStream/Extractors/ContentX.py +21 -6
- KekikStream/Extractors/DonilasPlay.py +86 -0
- KekikStream/Extractors/DzenRu.py +38 -0
- KekikStream/Extractors/ExPlay.py +53 -0
- KekikStream/Extractors/Filemoon.py +78 -0
- KekikStream/Extractors/HDPlayerSystem.py +41 -0
- KekikStream/Extractors/JetTv.py +45 -0
- KekikStream/Extractors/MailRu.py +3 -4
- KekikStream/Extractors/MixPlayHD.py +2 -3
- KekikStream/Extractors/MixTiger.py +57 -0
- KekikStream/Extractors/MolyStream.py +5 -5
- KekikStream/Extractors/Odnoklassniki.py +13 -7
- KekikStream/Extractors/PeaceMakerst.py +10 -5
- KekikStream/Extractors/PixelDrain.py +1 -2
- KekikStream/Extractors/PlayerFilmIzle.py +65 -0
- KekikStream/Extractors/RapidVid.py +23 -8
- KekikStream/Extractors/SetPlay.py +66 -0
- KekikStream/Extractors/SetPrime.py +45 -0
- KekikStream/Extractors/SibNet.py +2 -3
- KekikStream/Extractors/Sobreatsesuyp.py +4 -5
- KekikStream/Extractors/TRsTX.py +4 -5
- KekikStream/Extractors/TauVideo.py +2 -3
- KekikStream/Extractors/TurboImgz.py +2 -3
- KekikStream/Extractors/TurkeyPlayer.py +34 -0
- KekikStream/Extractors/VCTPlay.py +41 -0
- KekikStream/Extractors/VidHide.py +81 -0
- KekikStream/Extractors/VidMoly.py +55 -34
- KekikStream/Extractors/VidMoxy.py +2 -3
- KekikStream/Extractors/VidPapi.py +89 -0
- KekikStream/Extractors/VideoSeyred.py +3 -4
- KekikStream/Extractors/YTDLP.py +211 -0
- KekikStream/Extractors/YildizKisaFilm.py +41 -0
- KekikStream/Plugins/BelgeselX.py +196 -0
- KekikStream/Plugins/DiziBox.py +25 -34
- KekikStream/Plugins/DiziPal.py +24 -35
- KekikStream/Plugins/DiziYou.py +54 -37
- KekikStream/Plugins/Dizilla.py +66 -46
- KekikStream/Plugins/FilmBip.py +142 -0
- KekikStream/Plugins/FilmMakinesi.py +36 -28
- KekikStream/Plugins/FilmModu.py +20 -24
- KekikStream/Plugins/FullHDFilm.py +220 -0
- KekikStream/Plugins/FullHDFilmizlesene.py +9 -15
- KekikStream/Plugins/HDFilmCehennemi.py +141 -69
- KekikStream/Plugins/JetFilmizle.py +85 -52
- KekikStream/Plugins/KultFilmler.py +217 -0
- KekikStream/Plugins/RecTV.py +22 -34
- KekikStream/Plugins/RoketDizi.py +222 -0
- KekikStream/Plugins/SelcukFlix.py +328 -0
- KekikStream/Plugins/SetFilmIzle.py +252 -0
- KekikStream/Plugins/SezonlukDizi.py +54 -21
- KekikStream/Plugins/SineWix.py +17 -29
- KekikStream/Plugins/Sinefy.py +241 -0
- KekikStream/Plugins/SinemaCX.py +154 -0
- KekikStream/Plugins/Sinezy.py +143 -0
- KekikStream/Plugins/SuperFilmGeldi.py +130 -0
- KekikStream/Plugins/UgurFilm.py +13 -19
- KekikStream/__init__.py +47 -56
- KekikStream/requirements.txt +3 -4
- kekikstream-2.2.0.dist-info/METADATA +312 -0
- kekikstream-2.2.0.dist-info/RECORD +81 -0
- KekikStream/Extractors/FourCX.py +0 -7
- KekikStream/Extractors/FourPichive.py +0 -7
- KekikStream/Extractors/FourPlayRu.py +0 -7
- KekikStream/Extractors/HDStreamAble.py +0 -7
- KekikStream/Extractors/Hotlinger.py +0 -7
- KekikStream/Extractors/OkRuHTTP.py +0 -7
- KekikStream/Extractors/OkRuSSL.py +0 -7
- KekikStream/Extractors/Pichive.py +0 -7
- KekikStream/Extractors/PlayRu.py +0 -7
- KekikStream/Extractors/VidMolyMe.py +0 -7
- kekikstream-1.7.1.dist-info/METADATA +0 -109
- kekikstream-1.7.1.dist-info/RECORD +0 -63
- {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.dist-info}/WHEEL +0 -0
- {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.dist-info}/entry_points.txt +0 -0
- {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult, Subtitle
|
|
4
|
+
from parsel import Selector
|
|
5
|
+
import re, base64
|
|
6
|
+
|
|
7
|
+
class FullHDFilm(PluginBase):
|
|
8
|
+
name = "FullHDFilm"
|
|
9
|
+
language = "tr"
|
|
10
|
+
main_url = "https://hdfilm.us"
|
|
11
|
+
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
12
|
+
description = "Full HD Film izle, Türkçe Dublaj ve Altyazılı filmler."
|
|
13
|
+
|
|
14
|
+
main_page = {
|
|
15
|
+
f"{main_url}/tur/turkce-altyazili-film-izle" : "Altyazılı Filmler",
|
|
16
|
+
f"{main_url}/tur/netflix-filmleri-izle" : "Netflix",
|
|
17
|
+
f"{main_url}/tur/yerli-film-izle" : "Yerli Film",
|
|
18
|
+
f"{main_url}/category/aile-filmleri-izle" : "Aile",
|
|
19
|
+
f"{main_url}/category/aksiyon-filmleri-izle" : "Aksiyon",
|
|
20
|
+
f"{main_url}/category/animasyon-filmleri-izle" : "Animasyon",
|
|
21
|
+
f"{main_url}/category/belgesel-filmleri-izle" : "Belgesel",
|
|
22
|
+
f"{main_url}/category/bilim-kurgu-filmleri-izle" : "Bilim Kurgu",
|
|
23
|
+
f"{main_url}/category/biyografi-filmleri-izle" : "Biyografi",
|
|
24
|
+
f"{main_url}/category/dram-filmleri-izle" : "Dram",
|
|
25
|
+
f"{main_url}/category/fantastik-filmler-izle" : "Fantastik",
|
|
26
|
+
f"{main_url}/category/gerilim-filmleri-izle" : "Gerilim",
|
|
27
|
+
f"{main_url}/category/gizem-filmleri-izle" : "Gizem",
|
|
28
|
+
f"{main_url}/category/kisa" : "Kısa",
|
|
29
|
+
f"{main_url}/category/komedi-filmleri-izle" : "Komedi",
|
|
30
|
+
f"{main_url}/category/korku-filmleri-izle" : "Korku",
|
|
31
|
+
f"{main_url}/category/macera-filmleri-izle" : "Macera",
|
|
32
|
+
f"{main_url}/category/muzik" : "Müzik",
|
|
33
|
+
f"{main_url}/category/muzikal-filmleri-izle" : "Müzikal",
|
|
34
|
+
f"{main_url}/category/romantik-filmler-izle" : "Romantik",
|
|
35
|
+
f"{main_url}/category/savas-filmleri-izle" : "Savaş",
|
|
36
|
+
f"{main_url}/category/spor-filmleri-izle" : "Spor",
|
|
37
|
+
f"{main_url}/category/suc-filmleri-izle" : "Suç",
|
|
38
|
+
f"{main_url}/category/tarih-filmleri-izle" : "Tarih",
|
|
39
|
+
f"{main_url}/category/western-filmleri-izle" : "Western",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
43
|
+
page_url = url if page == 1 else f"{url}/page/{page}"
|
|
44
|
+
|
|
45
|
+
self.httpx.headers.update({
|
|
46
|
+
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
|
|
47
|
+
"Referer" : f"{self.main_url}/"
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
istek = await self.httpx.get(page_url)
|
|
51
|
+
secici = Selector(istek.text)
|
|
52
|
+
|
|
53
|
+
return [
|
|
54
|
+
MainPageResult(
|
|
55
|
+
category = category,
|
|
56
|
+
title = veri.css("img::attr(alt)").get(),
|
|
57
|
+
url = self.fix_url(veri.css("a::attr(href)").get()),
|
|
58
|
+
poster = self.fix_url(veri.css("img::attr(src)").get()),
|
|
59
|
+
)
|
|
60
|
+
for veri in secici.css("div.movie-poster")
|
|
61
|
+
if veri.css("img::attr(alt)").get()
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
async def search(self, query: str) -> list[SearchResult]:
|
|
65
|
+
istek = await self.httpx.get(f"{self.main_url}/?s={query}")
|
|
66
|
+
secici = Selector(istek.text)
|
|
67
|
+
|
|
68
|
+
return [
|
|
69
|
+
SearchResult(
|
|
70
|
+
title = veri.css("img::attr(alt)").get(),
|
|
71
|
+
url = self.fix_url(veri.css("a::attr(href)").get()),
|
|
72
|
+
poster = self.fix_url(veri.css("img::attr(src)").get()),
|
|
73
|
+
)
|
|
74
|
+
for veri in secici.css("div.movie-poster")
|
|
75
|
+
if veri.css("img::attr(alt)").get()
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
79
|
+
istek = await self.httpx.get(url)
|
|
80
|
+
secici = Selector(istek.text)
|
|
81
|
+
|
|
82
|
+
title = secici.css("h1::text").get() or ""
|
|
83
|
+
title = title.strip() if title else ""
|
|
84
|
+
poster = self.fix_url(secici.css("div.poster img::attr(src)").get() or "")
|
|
85
|
+
|
|
86
|
+
actors_text = secici.css("div.oyuncular.info::text").get()
|
|
87
|
+
if actors_text:
|
|
88
|
+
actors_text = actors_text.replace("Oyuncular:", "").strip()
|
|
89
|
+
actors = [a.strip() for a in actors_text.split(",")]
|
|
90
|
+
else:
|
|
91
|
+
actors = []
|
|
92
|
+
|
|
93
|
+
year = secici.css("div.yayin-tarihi.info::text").re_first(r"(\d{4})")
|
|
94
|
+
tags = secici.css("div.tur.info a::text").getall()
|
|
95
|
+
rating = secici.css("div.imdb::text").re_first(r"IMDb\s*([\d\.]+)")
|
|
96
|
+
|
|
97
|
+
# Description
|
|
98
|
+
description = secici.xpath("//div[contains(@class, 'others')]/preceding-sibling::div[1]//text()").getall()
|
|
99
|
+
description = "".join(description).strip() if description else None
|
|
100
|
+
|
|
101
|
+
# Kotlin referansı: URL'de -dizi kontrolü veya tags içinde "dizi" kontrolü
|
|
102
|
+
is_series = "-dizi" in url.lower() or any("dizi" in tag.lower() for tag in tags)
|
|
103
|
+
|
|
104
|
+
if is_series:
|
|
105
|
+
episodes = []
|
|
106
|
+
part_elements = secici.css("li.psec")
|
|
107
|
+
part_names = secici.css("li.psec a::text").getall()
|
|
108
|
+
|
|
109
|
+
# pdata değerlerini çıkar
|
|
110
|
+
pdata_matches = re.findall(r"pdata\['([^']+)'\]\s*=\s*'([^']+)'", istek.text)
|
|
111
|
+
|
|
112
|
+
for idx, (part_id, part_name) in enumerate(zip([el.css("::attr(id)").get() for el in part_elements], part_names)):
|
|
113
|
+
if not part_name:
|
|
114
|
+
continue
|
|
115
|
+
|
|
116
|
+
part_name = part_name.strip()
|
|
117
|
+
|
|
118
|
+
# Fragman'ları atla
|
|
119
|
+
if "fragman" in part_name.lower() or (part_id and "fragman" in part_id.lower()):
|
|
120
|
+
continue
|
|
121
|
+
|
|
122
|
+
# Sezon ve bölüm numarası çıkar
|
|
123
|
+
sz_match = re.search(r'(\d+)\s*sezon', part_id.lower() if part_id else "")
|
|
124
|
+
ep_match = re.search(r'^(\d+)\.', part_name)
|
|
125
|
+
|
|
126
|
+
sz_num = int(sz_match.group(1)) if sz_match else 1
|
|
127
|
+
ep_num = int(ep_match.group(1)) if ep_match else idx + 1
|
|
128
|
+
|
|
129
|
+
# pdata'dan video URL'si çık (varsa)
|
|
130
|
+
video_url = url # Varsayılan olarak ana URL kullan
|
|
131
|
+
if idx < len(pdata_matches):
|
|
132
|
+
video_url = pdata_matches[idx][1] if pdata_matches[idx][1] else url
|
|
133
|
+
|
|
134
|
+
episodes.append(Episode(
|
|
135
|
+
season = sz_num,
|
|
136
|
+
episode = ep_num,
|
|
137
|
+
title = f"{sz_num}. Sezon {ep_num}. Bölüm",
|
|
138
|
+
url = url # Bölüm URL'leri load_links'te işlenecek
|
|
139
|
+
))
|
|
140
|
+
|
|
141
|
+
return SeriesInfo(
|
|
142
|
+
url = url,
|
|
143
|
+
poster = poster,
|
|
144
|
+
title = self.clean_title(title) if title else "",
|
|
145
|
+
description = description,
|
|
146
|
+
tags = tags,
|
|
147
|
+
year = year,
|
|
148
|
+
actors = actors,
|
|
149
|
+
rating = rating.strip() if rating else None,
|
|
150
|
+
episodes = episodes
|
|
151
|
+
)
|
|
152
|
+
else:
|
|
153
|
+
return MovieInfo(
|
|
154
|
+
url = url,
|
|
155
|
+
poster = poster,
|
|
156
|
+
title = self.clean_title(title) if title else "",
|
|
157
|
+
description = description,
|
|
158
|
+
tags = tags,
|
|
159
|
+
year = year,
|
|
160
|
+
actors = actors,
|
|
161
|
+
rating = rating.strip() if rating else None,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
def _get_iframe(self, source_code: str) -> str:
|
|
165
|
+
"""Base64 kodlu iframe'i çözümle"""
|
|
166
|
+
match = re.search(r'<script[^>]*>(PCEtLWJhc2xpazp[^<]*)</script>', source_code)
|
|
167
|
+
if not match:
|
|
168
|
+
return ""
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
decoded_html = base64.b64decode(match[1]).decode("utf-8")
|
|
172
|
+
iframe_match = re.search(r'<iframe[^>]+src=["\']([^"\']+)["\']', decoded_html)
|
|
173
|
+
return self.fix_url(iframe_match[1]) if iframe_match else ""
|
|
174
|
+
except Exception:
|
|
175
|
+
return ""
|
|
176
|
+
|
|
177
|
+
def _extract_subtitle_url(self, source_code: str) -> str | None:
|
|
178
|
+
"""playerjsSubtitle değişkeninden .srt URL çıkar"""
|
|
179
|
+
patterns = [
|
|
180
|
+
r'var playerjsSubtitle = "\[Türkçe\](https?://[^\s"]+?\.srt)";',
|
|
181
|
+
r'var playerjsSubtitle = "(https?://[^\s"]+?\.srt)";',
|
|
182
|
+
r'subtitle:\s*"(https?://[^\s"]+?\.srt)"',
|
|
183
|
+
]
|
|
184
|
+
|
|
185
|
+
for pattern in patterns:
|
|
186
|
+
if match := re.search(pattern, source_code):
|
|
187
|
+
return match[1]
|
|
188
|
+
|
|
189
|
+
return None
|
|
190
|
+
|
|
191
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
192
|
+
self.httpx.headers.update({
|
|
193
|
+
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
|
|
194
|
+
"Referer" : self.main_url
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
istek = await self.httpx.get(url)
|
|
198
|
+
source_code = istek.text
|
|
199
|
+
|
|
200
|
+
# Ana sayfadan altyazı URL'sini çek
|
|
201
|
+
subtitle_url = self._extract_subtitle_url(source_code)
|
|
202
|
+
|
|
203
|
+
# Iframe'den altyazı URL'sini çek
|
|
204
|
+
iframe_src = self._get_iframe(source_code)
|
|
205
|
+
|
|
206
|
+
if not subtitle_url and iframe_src:
|
|
207
|
+
iframe_istek = await self.httpx.get(iframe_src)
|
|
208
|
+
subtitle_url = self._extract_subtitle_url(iframe_istek.text)
|
|
209
|
+
|
|
210
|
+
results = []
|
|
211
|
+
|
|
212
|
+
if iframe_src:
|
|
213
|
+
data = await self.extract(iframe_src)
|
|
214
|
+
if data:
|
|
215
|
+
# ExtractResult objesi immutable, yeni bir kopya oluştur
|
|
216
|
+
subtitles = [Subtitle(name="Türkçe", url=subtitle_url)] if subtitle_url else []
|
|
217
|
+
updated_data = data.model_copy(update={"subtitles": subtitles}) if subtitles else data
|
|
218
|
+
results.append(updated_data)
|
|
219
|
+
|
|
220
|
+
return results
|
|
@@ -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
|
|
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
|
|
@@ -10,7 +10,7 @@ class FullHDFilmizlesene(PluginBase):
|
|
|
10
10
|
language = "tr"
|
|
11
11
|
main_url = "https://www.fullhdfilmizlesene.tv"
|
|
12
12
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
13
|
-
description = "
|
|
13
|
+
description = "Türkiye'nin ilk ve lider HD film izleme platformu, kaliteli ve sorunsuz hizmetiyle sinema keyfini zirveye taşır."
|
|
14
14
|
|
|
15
15
|
main_page = {
|
|
16
16
|
f"{main_url}/en-cok-izlenen-hd-filmler/" : "En Çok izlenen Filmler",
|
|
@@ -40,7 +40,6 @@ class FullHDFilmizlesene(PluginBase):
|
|
|
40
40
|
f"{main_url}/filmizle/yerli-filmler-hd-izle/" : "Yerli Filmler"
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
#@kekik_cache(ttl=60*60)
|
|
44
43
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
45
44
|
istek = self.cloudscraper.get(f"{url}{page}")
|
|
46
45
|
secici = Selector(istek.text)
|
|
@@ -55,9 +54,8 @@ class FullHDFilmizlesene(PluginBase):
|
|
|
55
54
|
for veri in secici.css("li.film")
|
|
56
55
|
]
|
|
57
56
|
|
|
58
|
-
#@kekik_cache(ttl=60*60)
|
|
59
57
|
async def search(self, query: str) -> list[SearchResult]:
|
|
60
|
-
istek = await self.
|
|
58
|
+
istek = await self.httpx.get(f"{self.main_url}/arama/{query}")
|
|
61
59
|
secici = Selector(istek.text)
|
|
62
60
|
|
|
63
61
|
results = []
|
|
@@ -77,9 +75,8 @@ class FullHDFilmizlesene(PluginBase):
|
|
|
77
75
|
|
|
78
76
|
return results
|
|
79
77
|
|
|
80
|
-
#@kekik_cache(ttl=60*60)
|
|
81
78
|
async def load_item(self, url: str) -> MovieInfo:
|
|
82
|
-
istek = await self.
|
|
79
|
+
istek = await self.httpx.get(url)
|
|
83
80
|
secici = Selector(istek.text)
|
|
84
81
|
|
|
85
82
|
title = secici.xpath("normalize-space(//div[@class='izle-titles'])").get().strip()
|
|
@@ -103,9 +100,8 @@ class FullHDFilmizlesene(PluginBase):
|
|
|
103
100
|
duration = duration
|
|
104
101
|
)
|
|
105
102
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
istek = await self.cffi.get(url)
|
|
103
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
104
|
+
istek = await self.httpx.get(url)
|
|
109
105
|
secici = Selector(istek.text)
|
|
110
106
|
|
|
111
107
|
script = secici.xpath("(//script)[1]").get()
|
|
@@ -123,10 +119,8 @@ class FullHDFilmizlesene(PluginBase):
|
|
|
123
119
|
response = []
|
|
124
120
|
for link in link_list:
|
|
125
121
|
link = f"https:{link}" if link.startswith("//") else link
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
"name" : extractor.name if extractor else "Direct Link"
|
|
130
|
-
})
|
|
122
|
+
data = await self.extract(link)
|
|
123
|
+
if data:
|
|
124
|
+
response.append(data)
|
|
131
125
|
|
|
132
126
|
return response
|
|
@@ -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
|
|
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
|
|
@@ -10,7 +10,7 @@ class HDFilmCehennemi(PluginBase):
|
|
|
10
10
|
language = "tr"
|
|
11
11
|
main_url = "https://www.hdfilmcehennemi.ws"
|
|
12
12
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
13
|
-
description = "Türkiye'nin en hızlı hd film izleme sitesi"
|
|
13
|
+
description = "Türkiye'nin en hızlı hd film izleme sitesi. Tek ve gerçek hdfilmcehennemi sitesi."
|
|
14
14
|
|
|
15
15
|
main_page = {
|
|
16
16
|
f"{main_url}" : "Yeni Eklenen Filmler",
|
|
@@ -29,9 +29,8 @@ class HDFilmCehennemi(PluginBase):
|
|
|
29
29
|
f"{main_url}/tur/romantik-filmleri-izle-1" : "Romantik Filmleri"
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
#@kekik_cache(ttl=60*60)
|
|
33
32
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
34
|
-
istek = await self.
|
|
33
|
+
istek = await self.httpx.get(f"{url}", follow_redirects=True)
|
|
35
34
|
secici = Selector(istek.text)
|
|
36
35
|
|
|
37
36
|
return [
|
|
@@ -44,9 +43,8 @@ class HDFilmCehennemi(PluginBase):
|
|
|
44
43
|
for veri in secici.css("div.section-content a.poster")
|
|
45
44
|
]
|
|
46
45
|
|
|
47
|
-
#@kekik_cache(ttl=60*60)
|
|
48
46
|
async def search(self, query: str) -> list[SearchResult]:
|
|
49
|
-
istek = await self.
|
|
47
|
+
istek = await self.httpx.get(
|
|
50
48
|
url = f"{self.main_url}/search/?q={query}",
|
|
51
49
|
headers = {
|
|
52
50
|
"Referer" : f"{self.main_url}/",
|
|
@@ -73,46 +71,84 @@ class HDFilmCehennemi(PluginBase):
|
|
|
73
71
|
|
|
74
72
|
return results
|
|
75
73
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
istek = await self.cffi.get(url, headers = {"Referer": f"{self.main_url}/"})
|
|
74
|
+
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
75
|
+
istek = await self.httpx.get(url, headers = {"Referer": f"{self.main_url}/"})
|
|
79
76
|
secici = Selector(istek.text)
|
|
80
77
|
|
|
81
|
-
title = secici.css("h1.section-title::text").get()
|
|
82
|
-
|
|
83
|
-
|
|
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 ""
|
|
84
84
|
tags = secici.css("div.post-info-genres a::text").getall()
|
|
85
|
-
rating = secici.css("div.post-info-imdb-rating span::text").get()
|
|
86
|
-
|
|
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 ""
|
|
87
89
|
actors = secici.css("div.post-info-cast a > strong::text").getall()
|
|
88
|
-
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()
|
|
89
92
|
|
|
90
|
-
|
|
91
93
|
try:
|
|
92
|
-
duration_minutes = int(duration
|
|
94
|
+
duration_minutes = int(re.search(r'\d+', duration).group()) if re.search(r'\d+', duration) else 0
|
|
93
95
|
except Exception:
|
|
94
96
|
duration_minutes = 0
|
|
95
97
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
+
)
|
|
107
144
|
|
|
108
145
|
def generate_random_cookie(self):
|
|
109
146
|
return "".join(random.choices(string.ascii_letters + string.digits, k=16))
|
|
110
147
|
|
|
111
|
-
|
|
112
|
-
async def cehennempass(self, video_id: str) -> list[dict]:
|
|
148
|
+
async def cehennempass(self, video_id: str) -> list:
|
|
113
149
|
results = []
|
|
114
150
|
|
|
115
|
-
istek = await self.
|
|
151
|
+
istek = await self.httpx.post(
|
|
116
152
|
url = "https://cehennempass.pw/process_quality_selection.php",
|
|
117
153
|
headers = {
|
|
118
154
|
"Referer" : f"https://cehennempass.pw/download/{video_id}",
|
|
@@ -123,13 +159,13 @@ class HDFilmCehennemi(PluginBase):
|
|
|
123
159
|
data = {"video_id": video_id, "selected_quality": "low"},
|
|
124
160
|
)
|
|
125
161
|
if video_url := istek.json().get("download_link"):
|
|
126
|
-
results.append(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
+
))
|
|
131
167
|
|
|
132
|
-
istek = await self.
|
|
168
|
+
istek = await self.httpx.post(
|
|
133
169
|
url = "https://cehennempass.pw/process_quality_selection.php",
|
|
134
170
|
headers = {
|
|
135
171
|
"Referer" : f"https://cehennempass.pw/download/{video_id}",
|
|
@@ -140,26 +176,64 @@ class HDFilmCehennemi(PluginBase):
|
|
|
140
176
|
data = {"video_id": video_id, "selected_quality": "high"},
|
|
141
177
|
)
|
|
142
178
|
if video_url := istek.json().get("download_link"):
|
|
143
|
-
results.append(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
+
))
|
|
148
184
|
|
|
149
185
|
return results
|
|
150
186
|
|
|
151
|
-
|
|
187
|
+
def extract_hdch_url(self, unpacked: str) -> str:
|
|
188
|
+
"""HDFilmCehennemi unpacked script'ten video URL'sini çıkar"""
|
|
189
|
+
# 1) Decode fonksiyonunun adını bul: function <NAME>(value_parts)
|
|
190
|
+
match_fn = re.search(r'function\s+(\w+)\s*\(\s*value_parts\s*\)', unpacked)
|
|
191
|
+
if not match_fn:
|
|
192
|
+
return ""
|
|
193
|
+
|
|
194
|
+
fn_name = match_fn.group(1)
|
|
195
|
+
|
|
196
|
+
# 2) Bu fonksiyonun array ile çağrıldığı yeri bul: <NAME>([ ... ])
|
|
197
|
+
array_call_regex = re.compile(rf'{re.escape(fn_name)}\(\s*\[(.*?)\]\s*\)', re.DOTALL)
|
|
198
|
+
match_call = array_call_regex.search(unpacked)
|
|
199
|
+
if not match_call:
|
|
200
|
+
return ""
|
|
201
|
+
|
|
202
|
+
array_body = match_call.group(1)
|
|
203
|
+
|
|
204
|
+
# 3) Array içindeki string parçalarını topla
|
|
205
|
+
parts = re.findall(r'["\']([^"\']+)["\']', array_body)
|
|
206
|
+
if not parts:
|
|
207
|
+
return ""
|
|
208
|
+
|
|
209
|
+
# 4) Özel decoder ile çöz
|
|
210
|
+
return StreamDecoder._brute_force(parts)
|
|
211
|
+
|
|
152
212
|
async def invoke_local_source(self, iframe: str, source: str, url: str):
|
|
153
|
-
self.
|
|
154
|
-
|
|
213
|
+
self.httpx.headers.update({
|
|
214
|
+
"Referer": f"{self.main_url}/",
|
|
215
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0"
|
|
216
|
+
})
|
|
217
|
+
istek = await self.httpx.get(iframe)
|
|
218
|
+
|
|
219
|
+
if not istek.text:
|
|
220
|
+
return await self.cehennempass(iframe.split("/")[-1])
|
|
221
|
+
|
|
222
|
+
# eval(function...) içeren packed script bul
|
|
223
|
+
eval_match = re.search(r'(eval\(function[\s\S]+)', istek.text)
|
|
224
|
+
if not eval_match:
|
|
225
|
+
return await self.cehennempass(iframe.split("/")[-1])
|
|
155
226
|
|
|
156
227
|
try:
|
|
157
|
-
|
|
228
|
+
unpacked = Packer.unpack(eval_match.group(1))
|
|
158
229
|
except Exception:
|
|
159
230
|
return await self.cehennempass(iframe.split("/")[-1])
|
|
160
231
|
|
|
161
|
-
|
|
162
|
-
video_url =
|
|
232
|
+
# HDFilmCehennemi özel decoder ile video URL'sini çıkar
|
|
233
|
+
video_url = self.extract_hdch_url(unpacked)
|
|
234
|
+
|
|
235
|
+
if not video_url:
|
|
236
|
+
return await self.cehennempass(iframe.split("/")[-1])
|
|
163
237
|
|
|
164
238
|
subtitles = []
|
|
165
239
|
try:
|
|
@@ -172,16 +246,15 @@ class HDFilmCehennemi(PluginBase):
|
|
|
172
246
|
except Exception:
|
|
173
247
|
pass
|
|
174
248
|
|
|
175
|
-
return [
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
249
|
+
return [ExtractResult(
|
|
250
|
+
url = video_url,
|
|
251
|
+
name = source,
|
|
252
|
+
referer = url,
|
|
253
|
+
subtitles = subtitles
|
|
254
|
+
)]
|
|
181
255
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
istek = await self.cffi.get(url)
|
|
256
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
257
|
+
istek = await self.httpx.get(url)
|
|
185
258
|
secici = Selector(istek.text)
|
|
186
259
|
|
|
187
260
|
results = []
|
|
@@ -192,7 +265,7 @@ class HDFilmCehennemi(PluginBase):
|
|
|
192
265
|
source = f"{link.css('::text').get().replace('(HDrip Xbet)', '').strip()} {lang_code}"
|
|
193
266
|
video_id = link.css("::attr(data-video)").get()
|
|
194
267
|
|
|
195
|
-
api_get = await self.
|
|
268
|
+
api_get = await self.httpx.get(
|
|
196
269
|
url = f"{self.main_url}/video/{video_id}/",
|
|
197
270
|
headers = {
|
|
198
271
|
"Content-Type" : "application/json",
|
|
@@ -204,8 +277,15 @@ class HDFilmCehennemi(PluginBase):
|
|
|
204
277
|
match = re.search(r'data-src=\\\"([^"]+)', api_get.text)
|
|
205
278
|
iframe = match[1].replace("\\", "") if match else None
|
|
206
279
|
|
|
207
|
-
if
|
|
208
|
-
|
|
280
|
+
if not iframe:
|
|
281
|
+
continue
|
|
282
|
+
|
|
283
|
+
# mobi URL'si varsa direkt kullan (query string'i kaldır)
|
|
284
|
+
if "mobi" in iframe:
|
|
285
|
+
iframe = iframe.split("?")[0] # rapidrame_id query param'ı kaldır
|
|
286
|
+
# mobi değilse ve rapidrame varsa rplayer kullan
|
|
287
|
+
elif "rapidrame" in iframe and "?rapidrame_id=" in iframe:
|
|
288
|
+
iframe = f"{self.main_url}/rplayer/{iframe.split('?rapidrame_id=')[1]}"
|
|
209
289
|
|
|
210
290
|
video_data_list = await self.invoke_local_source(iframe, source, url)
|
|
211
291
|
if not video_data_list:
|
|
@@ -214,12 +294,4 @@ class HDFilmCehennemi(PluginBase):
|
|
|
214
294
|
for video_data in video_data_list:
|
|
215
295
|
results.append(video_data)
|
|
216
296
|
|
|
217
|
-
return results
|
|
218
|
-
|
|
219
|
-
async def play(self, name: str, url: str, referer: str, subtitles: list[Subtitle]):
|
|
220
|
-
extract_result = ExtractResult(name=name, url=url, referer=referer, subtitles=subtitles)
|
|
221
|
-
self.media_handler.title = name
|
|
222
|
-
if self.name not in self.media_handler.title:
|
|
223
|
-
self.media_handler.title = f"{self.name} | {self.media_handler.title}"
|
|
224
|
-
|
|
225
|
-
self.media_handler.play_media(extract_result)
|
|
297
|
+
return results
|