KekikStream 1.4.4__py3-none-any.whl → 2.0.2__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/CLI/pypi_kontrol.py +6 -6
- KekikStream/Core/Extractor/ExtractorBase.py +13 -12
- 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 +52 -31
- KekikStream/Core/Media/MediaManager.py +0 -3
- KekikStream/Core/Plugin/PluginBase.py +47 -21
- KekikStream/Core/Plugin/PluginLoader.py +11 -7
- KekikStream/Core/Plugin/PluginModels.py +25 -25
- KekikStream/Core/__init__.py +1 -0
- KekikStream/Extractors/CloseLoad.py +6 -26
- KekikStream/Extractors/ContentX_.py +40 -0
- KekikStream/Extractors/DzenRu.py +38 -0
- KekikStream/Extractors/ExPlay.py +53 -0
- KekikStream/Extractors/FirePlayer.py +60 -0
- KekikStream/Extractors/HDPlayerSystem.py +41 -0
- KekikStream/Extractors/JetTv.py +45 -0
- KekikStream/Extractors/MailRu.py +2 -4
- KekikStream/Extractors/MixTiger.py +57 -0
- KekikStream/Extractors/MolyStream.py +25 -7
- KekikStream/Extractors/Odnoklassniki.py +16 -11
- KekikStream/Extractors/{OkRuHTTP.py → Odnoklassniki_.py} +5 -1
- KekikStream/Extractors/{HDStreamAble.py → PeaceMakerst_.py} +1 -1
- KekikStream/Extractors/PixelDrain.py +0 -1
- KekikStream/Extractors/PlayerFilmIzle.py +62 -0
- KekikStream/Extractors/RapidVid.py +30 -13
- KekikStream/Extractors/RapidVid_.py +7 -0
- KekikStream/Extractors/SetPlay.py +57 -0
- KekikStream/Extractors/SetPrime.py +45 -0
- KekikStream/Extractors/SibNet.py +0 -1
- KekikStream/Extractors/TurkeyPlayer.py +34 -0
- KekikStream/Extractors/VidHide.py +72 -0
- KekikStream/Extractors/VidMoly.py +20 -19
- KekikStream/Extractors/{VidMolyMe.py → VidMoly_.py} +1 -1
- KekikStream/Extractors/VidMoxy.py +0 -1
- KekikStream/Extractors/VidPapi.py +89 -0
- KekikStream/Extractors/YTDLP.py +177 -0
- KekikStream/Extractors/YildizKisaFilm.py +41 -0
- KekikStream/Plugins/DiziBox.py +28 -16
- KekikStream/Plugins/DiziPal.py +246 -0
- KekikStream/Plugins/DiziYou.py +58 -31
- KekikStream/Plugins/Dizilla.py +97 -68
- KekikStream/Plugins/FilmBip.py +145 -0
- KekikStream/Plugins/FilmMakinesi.py +61 -52
- KekikStream/Plugins/FilmModu.py +138 -0
- KekikStream/Plugins/FullHDFilm.py +164 -0
- KekikStream/Plugins/FullHDFilmizlesene.py +38 -37
- KekikStream/Plugins/HDFilmCehennemi.py +44 -54
- KekikStream/Plugins/JetFilmizle.py +68 -42
- KekikStream/Plugins/KultFilmler.py +219 -0
- KekikStream/Plugins/RecTV.py +41 -37
- KekikStream/Plugins/RoketDizi.py +232 -0
- KekikStream/Plugins/SelcukFlix.py +309 -0
- KekikStream/Plugins/SezonlukDizi.py +16 -14
- KekikStream/Plugins/SineWix.py +39 -30
- KekikStream/Plugins/Sinefy.py +238 -0
- KekikStream/Plugins/SinemaCX.py +157 -0
- KekikStream/Plugins/Sinezy.py +146 -0
- KekikStream/Plugins/SuperFilmGeldi.py +121 -0
- KekikStream/Plugins/UgurFilm.py +10 -10
- KekikStream/__init__.py +296 -319
- KekikStream/requirements.txt +3 -4
- kekikstream-2.0.2.dist-info/METADATA +309 -0
- kekikstream-2.0.2.dist-info/RECORD +82 -0
- {kekikstream-1.4.4.dist-info → kekikstream-2.0.2.dist-info}/WHEEL +1 -1
- KekikStream/Extractors/FourCX.py +0 -7
- KekikStream/Extractors/FourPichive.py +0 -7
- KekikStream/Extractors/FourPlayRu.py +0 -7
- KekikStream/Extractors/Hotlinger.py +0 -7
- KekikStream/Extractors/OkRuSSL.py +0 -7
- KekikStream/Extractors/Pichive.py +0 -7
- KekikStream/Extractors/PlayRu.py +0 -7
- KekikStream/Helpers/Unpack.py +0 -75
- KekikStream/Plugins/Shorten.py +0 -225
- kekikstream-1.4.4.dist-info/METADATA +0 -108
- kekikstream-1.4.4.dist-info/RECORD +0 -63
- {kekikstream-1.4.4.dist-info → kekikstream-2.0.2.dist-info}/entry_points.txt +0 -0
- {kekikstream-1.4.4.dist-info → kekikstream-2.0.2.dist-info/licenses}/LICENSE +0 -0
- {kekikstream-1.4.4.dist-info → kekikstream-2.0.2.dist-info}/top_level.txt +0 -0
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core
|
|
4
|
-
from parsel
|
|
5
|
-
from
|
|
6
|
-
import random, string, re
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult, Subtitle
|
|
4
|
+
from parsel import Selector
|
|
5
|
+
from Kekik.Sifreleme import Packer, StreamDecoder
|
|
6
|
+
import random, string, re
|
|
7
7
|
|
|
8
8
|
class HDFilmCehennemi(PluginBase):
|
|
9
9
|
name = "HDFilmCehennemi"
|
|
10
10
|
language = "tr"
|
|
11
|
-
main_url = "https://www.hdfilmcehennemi.
|
|
11
|
+
main_url = "https://www.hdfilmcehennemi.ws"
|
|
12
12
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
13
13
|
description = "Türkiye'nin en hızlı hd film izleme sitesi"
|
|
14
|
+
|
|
15
|
+
|
|
14
16
|
|
|
15
17
|
main_page = {
|
|
16
18
|
f"{main_url}" : "Yeni Eklenen Filmler",
|
|
@@ -29,9 +31,8 @@ class HDFilmCehennemi(PluginBase):
|
|
|
29
31
|
f"{main_url}/tur/romantik-filmleri-izle-1" : "Romantik Filmleri"
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
@kekik_cache(ttl=60*60)
|
|
33
34
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
34
|
-
istek = await self.httpx.get(f"{url}")
|
|
35
|
+
istek = await self.httpx.get(f"{url}", follow_redirects=True)
|
|
35
36
|
secici = Selector(istek.text)
|
|
36
37
|
|
|
37
38
|
return [
|
|
@@ -44,10 +45,9 @@ class HDFilmCehennemi(PluginBase):
|
|
|
44
45
|
for veri in secici.css("div.section-content a.poster")
|
|
45
46
|
]
|
|
46
47
|
|
|
47
|
-
@kekik_cache(ttl=60*60)
|
|
48
48
|
async def search(self, query: str) -> list[SearchResult]:
|
|
49
49
|
istek = await self.httpx.get(
|
|
50
|
-
url = f"{self.main_url}/search
|
|
50
|
+
url = f"{self.main_url}/search/?q={query}",
|
|
51
51
|
headers = {
|
|
52
52
|
"Referer" : f"{self.main_url}/",
|
|
53
53
|
"X-Requested-With" : "fetch",
|
|
@@ -73,7 +73,6 @@ class HDFilmCehennemi(PluginBase):
|
|
|
73
73
|
|
|
74
74
|
return results
|
|
75
75
|
|
|
76
|
-
@kekik_cache(ttl=60*60)
|
|
77
76
|
async def load_item(self, url: str) -> MovieInfo:
|
|
78
77
|
istek = await self.httpx.get(url, headers = {"Referer": f"{self.main_url}/"})
|
|
79
78
|
secici = Selector(istek.text)
|
|
@@ -96,7 +95,7 @@ class HDFilmCehennemi(PluginBase):
|
|
|
96
95
|
return MovieInfo(
|
|
97
96
|
url = url,
|
|
98
97
|
poster = self.fix_url(poster),
|
|
99
|
-
title = title,
|
|
98
|
+
title = self.clean_title(title),
|
|
100
99
|
description = description,
|
|
101
100
|
tags = tags,
|
|
102
101
|
rating = rating,
|
|
@@ -108,8 +107,9 @@ class HDFilmCehennemi(PluginBase):
|
|
|
108
107
|
def generate_random_cookie(self):
|
|
109
108
|
return "".join(random.choices(string.ascii_letters + string.digits, k=16))
|
|
110
109
|
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
async def cehennempass(self, video_id: str) -> list[dict]:
|
|
111
|
+
results = []
|
|
112
|
+
|
|
113
113
|
istek = await self.httpx.post(
|
|
114
114
|
url = "https://cehennempass.pw/process_quality_selection.php",
|
|
115
115
|
headers = {
|
|
@@ -120,15 +120,12 @@ class HDFilmCehennemi(PluginBase):
|
|
|
120
120
|
},
|
|
121
121
|
data = {"video_id": video_id, "selected_quality": "low"},
|
|
122
122
|
)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
"referer" : f"https://cehennempass.pw/download/{video_id}",
|
|
130
|
-
"subtitles" : []
|
|
131
|
-
}
|
|
123
|
+
if video_url := istek.json().get("download_link"):
|
|
124
|
+
results.append({
|
|
125
|
+
"url" : self.fix_url(video_url),
|
|
126
|
+
"name" : "Düşük Kalite",
|
|
127
|
+
"referer" : f"https://cehennempass.pw/download/{video_id}"
|
|
128
|
+
})
|
|
132
129
|
|
|
133
130
|
istek = await self.httpx.post(
|
|
134
131
|
url = "https://cehennempass.pw/process_quality_selection.php",
|
|
@@ -140,19 +137,15 @@ class HDFilmCehennemi(PluginBase):
|
|
|
140
137
|
},
|
|
141
138
|
data = {"video_id": video_id, "selected_quality": "high"},
|
|
142
139
|
)
|
|
140
|
+
if video_url := istek.json().get("download_link"):
|
|
141
|
+
results.append({
|
|
142
|
+
"url" : self.fix_url(video_url),
|
|
143
|
+
"name" : "Yüksek Kalite",
|
|
144
|
+
"referer" : f"https://cehennempass.pw/download/{video_id}"
|
|
145
|
+
})
|
|
143
146
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
self._data[self.fix_url(video_url)] = {
|
|
147
|
-
"ext_name" : f"{self.name} | Yüksek Kalite",
|
|
148
|
-
"name" : "Yüksek Kalite",
|
|
149
|
-
"referer" : f"https://cehennempass.pw/download/{video_id}",
|
|
150
|
-
"subtitles" : []
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return None
|
|
147
|
+
return results
|
|
154
148
|
|
|
155
|
-
@kekik_cache(ttl=15*60)
|
|
156
149
|
async def invoke_local_source(self, iframe: str, source: str, url: str):
|
|
157
150
|
self.httpx.headers.update({"Referer": f"{self.main_url}/"})
|
|
158
151
|
istek = await self.httpx.get(iframe)
|
|
@@ -160,12 +153,10 @@ class HDFilmCehennemi(PluginBase):
|
|
|
160
153
|
try:
|
|
161
154
|
eval_func = re.compile(r'\s*(eval\(function[\s\S].*)\s*').findall(istek.text)[0]
|
|
162
155
|
except Exception:
|
|
163
|
-
await self.cehennempass(iframe.split("/")[-1])
|
|
164
|
-
return None, None
|
|
156
|
+
return await self.cehennempass(iframe.split("/")[-1])
|
|
165
157
|
|
|
166
|
-
unpacked = unpack(eval_func)
|
|
167
|
-
|
|
168
|
-
video_url = base64.b64decode(b64_url).decode("utf-8")
|
|
158
|
+
unpacked = Packer.unpack(eval_func)
|
|
159
|
+
video_url = StreamDecoder.extract_stream_url(unpacked)
|
|
169
160
|
|
|
170
161
|
subtitles = []
|
|
171
162
|
try:
|
|
@@ -178,20 +169,18 @@ class HDFilmCehennemi(PluginBase):
|
|
|
178
169
|
except Exception:
|
|
179
170
|
pass
|
|
180
171
|
|
|
181
|
-
|
|
182
|
-
"
|
|
183
|
-
"name" :
|
|
172
|
+
return [{
|
|
173
|
+
"url" : video_url,
|
|
174
|
+
"name" : source,
|
|
184
175
|
"referer" : url,
|
|
185
176
|
"subtitles" : subtitles
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
return video_url, data
|
|
177
|
+
}]
|
|
189
178
|
|
|
190
|
-
|
|
191
|
-
async def load_links(self, url: str) -> list[str]:
|
|
179
|
+
async def load_links(self, url: str) -> list[dict]:
|
|
192
180
|
istek = await self.httpx.get(url)
|
|
193
181
|
secici = Selector(istek.text)
|
|
194
182
|
|
|
183
|
+
results = []
|
|
195
184
|
for alternatif in secici.css("div.alternative-links"):
|
|
196
185
|
lang_code = alternatif.css("::attr(data-lang)").get().upper()
|
|
197
186
|
|
|
@@ -208,23 +197,24 @@ class HDFilmCehennemi(PluginBase):
|
|
|
208
197
|
},
|
|
209
198
|
)
|
|
210
199
|
|
|
211
|
-
match = re.search(r'data-src
|
|
200
|
+
match = re.search(r'data-src=\\\"([^"]+)', api_get.text)
|
|
212
201
|
iframe = match[1].replace("\\", "") if match else None
|
|
213
202
|
|
|
214
203
|
if iframe and "?rapidrame_id=" in iframe:
|
|
215
204
|
iframe = f"{self.main_url}/playerr/{iframe.split('?rapidrame_id=')[1]}"
|
|
216
205
|
|
|
217
|
-
|
|
218
|
-
if not
|
|
206
|
+
video_data_list = await self.invoke_local_source(iframe, source, url)
|
|
207
|
+
if not video_data_list:
|
|
219
208
|
continue
|
|
220
209
|
|
|
221
|
-
|
|
210
|
+
for video_data in video_data_list:
|
|
211
|
+
results.append(video_data)
|
|
222
212
|
|
|
223
|
-
return
|
|
213
|
+
return results
|
|
224
214
|
|
|
225
|
-
async def play(self,
|
|
226
|
-
extract_result = ExtractResult(
|
|
227
|
-
self.media_handler.title = name
|
|
215
|
+
async def play(self, **kwargs):
|
|
216
|
+
extract_result = ExtractResult(**kwargs)
|
|
217
|
+
self.media_handler.title = kwargs.get("name")
|
|
228
218
|
if self.name not in self.media_handler.title:
|
|
229
219
|
self.media_handler.title = f"{self.name} | {self.media_handler.title}"
|
|
230
220
|
|
|
@@ -1,12 +1,12 @@
|
|
|
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
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
|
|
6
6
|
class JetFilmizle(PluginBase):
|
|
7
7
|
name = "JetFilmizle"
|
|
8
8
|
language = "tr"
|
|
9
|
-
main_url = "https://jetfilmizle.
|
|
9
|
+
main_url = "https://jetfilmizle.website"
|
|
10
10
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
11
11
|
description = "Binlerce Film İzleme Seçeneğiyle En İyi Film İzleme Sitesi"
|
|
12
12
|
|
|
@@ -19,9 +19,8 @@ class JetFilmizle(PluginBase):
|
|
|
19
19
|
f"{main_url}/kategoriler/yesilcam-filmleri-izlee/page/" : "Yeşilçam Filmleri"
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
@kekik_cache(ttl=60*60)
|
|
23
22
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
24
|
-
istek = await self.httpx.get(f"{url}{page}")
|
|
23
|
+
istek = await self.httpx.get(f"{url}{page}", follow_redirects=True)
|
|
25
24
|
secici = Selector(istek.text)
|
|
26
25
|
|
|
27
26
|
return [
|
|
@@ -31,10 +30,9 @@ class JetFilmizle(PluginBase):
|
|
|
31
30
|
url = self.fix_url(veri.css("a::attr(href)").get()),
|
|
32
31
|
poster = self.fix_url(veri.css("img::attr(data-src)").get() or veri.css("img::attr(src)").get()),
|
|
33
32
|
)
|
|
34
|
-
for veri in secici.css("article.movie")
|
|
33
|
+
for veri in secici.css("article.movie") if veri.css("h2 a::text, h3 a::text, h4 a::text, h5 a::text, h6 a::text").get()
|
|
35
34
|
]
|
|
36
35
|
|
|
37
|
-
@kekik_cache(ttl=60*60)
|
|
38
36
|
async def search(self, query: str) -> list[SearchResult]:
|
|
39
37
|
istek = await self.httpx.post(
|
|
40
38
|
url = f"{self.main_url}/filmara.php",
|
|
@@ -60,18 +58,31 @@ class JetFilmizle(PluginBase):
|
|
|
60
58
|
|
|
61
59
|
return results
|
|
62
60
|
|
|
63
|
-
@kekik_cache(ttl=60*60)
|
|
64
61
|
async def load_item(self, url: str) -> MovieInfo:
|
|
65
62
|
istek = await self.httpx.get(url)
|
|
66
63
|
secici = Selector(istek.text)
|
|
67
64
|
|
|
68
65
|
title = self.clean_title(secici.css("div.movie-exp-title::text").get())
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
poster_raw = secici.css("section.movie-exp img::attr(data-src), section.movie-exp img::attr(src)").get()
|
|
67
|
+
poster = poster_raw.strip() if poster_raw else None
|
|
68
|
+
|
|
69
|
+
desc_raw = secici.css("section.movie-exp p.aciklama::text").get()
|
|
70
|
+
description = desc_raw.strip() if desc_raw else None
|
|
71
|
+
|
|
71
72
|
tags = secici.css("section.movie-exp div.catss a::text").getall()
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
|
|
74
|
+
rating_raw = secici.css("section.movie-exp div.imdb_puan span::text").get()
|
|
75
|
+
rating = rating_raw.strip() if rating_raw else None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# Year - div.yap içinde 4 haneli sayı ara
|
|
79
|
+
year_div = secici.xpath("//div[@class='yap' and (contains(., 'Vizyon') or contains(., 'Yapım'))]/text()").get()
|
|
80
|
+
year = None
|
|
81
|
+
if year_div:
|
|
82
|
+
year_match = re.search(r'(\d{4})', year_div.strip())
|
|
83
|
+
if year_match:
|
|
84
|
+
year = year_match.group(1)
|
|
85
|
+
|
|
75
86
|
actors = secici.css("div[itemprop='actor'] a span::text").getall()
|
|
76
87
|
|
|
77
88
|
return MovieInfo(
|
|
@@ -85,39 +96,54 @@ class JetFilmizle(PluginBase):
|
|
|
85
96
|
actors = actors
|
|
86
97
|
)
|
|
87
98
|
|
|
88
|
-
|
|
89
|
-
async def load_links(self, url: str) -> list[str]:
|
|
99
|
+
async def load_links(self, url: str) -> list[dict]:
|
|
90
100
|
istek = await self.httpx.get(url)
|
|
91
101
|
secici = Selector(istek.text)
|
|
92
102
|
|
|
93
|
-
|
|
94
|
-
if main_iframe := secici.css("div#movie iframe::attr(data-src), div#movie iframe::attr(data), div#movie iframe::attr(src)").get():
|
|
95
|
-
iframes.append(self.fix_url(main_iframe))
|
|
103
|
+
results = []
|
|
96
104
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
105
|
+
# 1) Ana iframe'leri kontrol et
|
|
106
|
+
for iframe in secici.css("iframe"):
|
|
107
|
+
src = (iframe.css("::attr(src)").get() or
|
|
108
|
+
iframe.css("::attr(data-src)").get() or
|
|
109
|
+
iframe.css("::attr(data-lazy-src)").get())
|
|
110
|
+
|
|
111
|
+
if src and src != "about:blank":
|
|
112
|
+
iframe_url = self.fix_url(src)
|
|
113
|
+
extractor = self.ex_manager.find_extractor(iframe_url)
|
|
114
|
+
results.append({
|
|
115
|
+
"url": iframe_url,
|
|
116
|
+
"name": extractor.name if extractor else "Ana Player"
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
# 2) Sayfa numaralarından linkleri topla (Fragman hariç)
|
|
120
|
+
page_links = []
|
|
121
|
+
for link in secici.css("a.post-page-numbers"):
|
|
122
|
+
isim = link.css("span::text").get() or ""
|
|
123
|
+
if isim != "Fragman":
|
|
124
|
+
href = link.css("::attr(href)").get()
|
|
125
|
+
if href:
|
|
126
|
+
page_links.append((self.fix_url(href), isim))
|
|
127
|
+
|
|
128
|
+
# 3) Her sayfa linkindeki iframe'leri bul
|
|
129
|
+
for page_url, isim in page_links:
|
|
130
|
+
try:
|
|
131
|
+
page_resp = await self.httpx.get(page_url)
|
|
132
|
+
page_sel = Selector(page_resp.text)
|
|
133
|
+
|
|
134
|
+
for iframe in page_sel.css("div#movie iframe"):
|
|
135
|
+
src = (iframe.css("::attr(src)").get() or
|
|
136
|
+
iframe.css("::attr(data-src)").get() or
|
|
137
|
+
iframe.css("::attr(data-lazy-src)").get())
|
|
138
|
+
|
|
139
|
+
if src and src != "about:blank":
|
|
140
|
+
iframe_url = self.fix_url(src)
|
|
141
|
+
extractor = self.ex_manager.find_extractor(iframe_url)
|
|
142
|
+
results.append({
|
|
143
|
+
"url": iframe_url,
|
|
144
|
+
"name": f"{extractor.name if extractor else 'Player'} | {isim}"
|
|
145
|
+
})
|
|
146
|
+
except Exception:
|
|
100
147
|
continue
|
|
101
148
|
|
|
102
|
-
|
|
103
|
-
part_secici = Selector(part_istek.text)
|
|
104
|
-
|
|
105
|
-
if iframe := part_secici.css("div#movie iframe::attr(data-src), div#movie iframe::attr(data), div#movie iframe::attr(src)").get():
|
|
106
|
-
iframes.append(self.fix_url(iframe))
|
|
107
|
-
else:
|
|
108
|
-
for link in part_secici.css("div#movie p a"):
|
|
109
|
-
if download_link := link.attrib.get("href"):
|
|
110
|
-
iframes.append(self.fix_url(download_link))
|
|
111
|
-
|
|
112
|
-
processed_iframes = []
|
|
113
|
-
for iframe in iframes:
|
|
114
|
-
if "jetv.xyz" in iframe:
|
|
115
|
-
jetv_istek = await self.httpx.get(iframe)
|
|
116
|
-
jetv_secici = Selector(jetv_istek.text)
|
|
117
|
-
|
|
118
|
-
if jetv_iframe := jetv_secici.css("iframe::attr(src)").get():
|
|
119
|
-
processed_iframes.append(self.fix_url(jetv_iframe))
|
|
120
|
-
else:
|
|
121
|
-
processed_iframes.append(iframe)
|
|
122
|
-
|
|
123
|
-
return processed_iframes
|
|
149
|
+
return results
|
|
@@ -0,0 +1,219 @@
|
|
|
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 KultFilmler(PluginBase):
|
|
8
|
+
name = "KultFilmler"
|
|
9
|
+
language = "tr"
|
|
10
|
+
main_url = "https://kultfilmler.net"
|
|
11
|
+
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
12
|
+
description = "Kült film ve dizi izleme sitesi."
|
|
13
|
+
|
|
14
|
+
main_page = {
|
|
15
|
+
f"{main_url}/category/aile-filmleri-izle" : "Aile",
|
|
16
|
+
f"{main_url}/category/aksiyon-filmleri-izle" : "Aksiyon",
|
|
17
|
+
f"{main_url}/category/animasyon-filmleri-izle" : "Animasyon",
|
|
18
|
+
f"{main_url}/category/belgesel-izle" : "Belgesel",
|
|
19
|
+
f"{main_url}/category/bilim-kurgu-filmleri-izle": "Bilim Kurgu",
|
|
20
|
+
f"{main_url}/category/biyografi-filmleri-izle" : "Biyografi",
|
|
21
|
+
f"{main_url}/category/dram-filmleri-izle" : "Dram",
|
|
22
|
+
f"{main_url}/category/fantastik-filmleri-izle" : "Fantastik",
|
|
23
|
+
f"{main_url}/category/gerilim-filmleri-izle" : "Gerilim",
|
|
24
|
+
f"{main_url}/category/gizem-filmleri-izle" : "Gizem",
|
|
25
|
+
f"{main_url}/category/kara-filmleri-izle" : "Kara Film",
|
|
26
|
+
f"{main_url}/category/kisa-film-izle" : "Kısa Metraj",
|
|
27
|
+
f"{main_url}/category/komedi-filmleri-izle" : "Komedi",
|
|
28
|
+
f"{main_url}/category/korku-filmleri-izle" : "Korku",
|
|
29
|
+
f"{main_url}/category/macera-filmleri-izle" : "Macera",
|
|
30
|
+
f"{main_url}/category/muzik-filmleri-izle" : "Müzik",
|
|
31
|
+
f"{main_url}/category/polisiye-filmleri-izle" : "Polisiye",
|
|
32
|
+
f"{main_url}/category/romantik-filmleri-izle" : "Romantik",
|
|
33
|
+
f"{main_url}/category/savas-filmleri-izle" : "Savaş",
|
|
34
|
+
f"{main_url}/category/suc-filmleri-izle" : "Suç",
|
|
35
|
+
f"{main_url}/category/tarih-filmleri-izle" : "Tarih",
|
|
36
|
+
f"{main_url}/category/yerli-filmleri-izle" : "Yerli",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
40
|
+
istek = await self.httpx.get(url)
|
|
41
|
+
secici = Selector(istek.text)
|
|
42
|
+
|
|
43
|
+
results = []
|
|
44
|
+
for veri in secici.css("div.col-md-12 div.movie-box"):
|
|
45
|
+
title = veri.css("div.img img::attr(alt)").get()
|
|
46
|
+
href = self.fix_url(veri.css("a::attr(href)").get())
|
|
47
|
+
poster = self.fix_url(veri.css("div.img img::attr(src)").get())
|
|
48
|
+
|
|
49
|
+
if title and href:
|
|
50
|
+
results.append(MainPageResult(
|
|
51
|
+
category = category,
|
|
52
|
+
title = title,
|
|
53
|
+
url = href,
|
|
54
|
+
poster = poster,
|
|
55
|
+
))
|
|
56
|
+
|
|
57
|
+
return results
|
|
58
|
+
|
|
59
|
+
async def search(self, query: str) -> list[SearchResult]:
|
|
60
|
+
istek = await self.httpx.get(f"{self.main_url}?s={query}")
|
|
61
|
+
secici = Selector(istek.text)
|
|
62
|
+
|
|
63
|
+
results = []
|
|
64
|
+
for veri in secici.css("div.movie-box"):
|
|
65
|
+
title = veri.css("div.img img::attr(alt)").get()
|
|
66
|
+
href = self.fix_url(veri.css("a::attr(href)").get())
|
|
67
|
+
poster = self.fix_url(veri.css("div.img img::attr(src)").get())
|
|
68
|
+
|
|
69
|
+
if title and href:
|
|
70
|
+
results.append(SearchResult(
|
|
71
|
+
title = title,
|
|
72
|
+
url = href,
|
|
73
|
+
poster = poster,
|
|
74
|
+
))
|
|
75
|
+
|
|
76
|
+
return results
|
|
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("div.film-bilgileri img::attr(alt)").get() or secici.css("[property='og:title']::attr(content)").get()
|
|
83
|
+
poster = self.fix_url(secici.css("[property='og:image']::attr(content)").get())
|
|
84
|
+
description = secici.css("div.description::text").get()
|
|
85
|
+
tags = secici.css("ul.post-categories a::text").getall()
|
|
86
|
+
# HTML analizine göre güncellenen alanlar
|
|
87
|
+
year = secici.css("li.release span a::text").get()
|
|
88
|
+
duration = secici.css("li.time span::text").re_first(r"(\d+)")
|
|
89
|
+
rating = secici.css("div.imdb-count::text").get()
|
|
90
|
+
actors = secici.css("div.actors a::text").getall()
|
|
91
|
+
if rating:
|
|
92
|
+
rating = rating.strip()
|
|
93
|
+
|
|
94
|
+
# Dizi mi kontrol et
|
|
95
|
+
if "/dizi/" in url:
|
|
96
|
+
episodes = []
|
|
97
|
+
for bolum in secici.css("div.episode-box"):
|
|
98
|
+
ep_href = self.fix_url(bolum.css("div.name a::attr(href)").get())
|
|
99
|
+
ssn_detail = bolum.css("span.episodetitle::text").get() or ""
|
|
100
|
+
ep_detail = bolum.css("span.episodetitle b::text").get() or ""
|
|
101
|
+
ep_name = f"{ssn_detail} - {ep_detail}"
|
|
102
|
+
|
|
103
|
+
if ep_href:
|
|
104
|
+
ep_season = re.search(r"(\d+)\.", ssn_detail)
|
|
105
|
+
ep_episode = re.search(r"(\d+)\.", ep_detail)
|
|
106
|
+
|
|
107
|
+
episodes.append(Episode(
|
|
108
|
+
season = int(ep_season[1]) if ep_season else 1,
|
|
109
|
+
episode = int(ep_episode[1]) if ep_episode else 1,
|
|
110
|
+
title = ep_name.strip(" -"),
|
|
111
|
+
url = ep_href,
|
|
112
|
+
))
|
|
113
|
+
|
|
114
|
+
return SeriesInfo(
|
|
115
|
+
url = url,
|
|
116
|
+
poster = poster,
|
|
117
|
+
title = self.clean_title(title) if title else "",
|
|
118
|
+
description = description,
|
|
119
|
+
tags = tags,
|
|
120
|
+
year = year,
|
|
121
|
+
actors = actors,
|
|
122
|
+
rating = rating,
|
|
123
|
+
episodes = episodes,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
return MovieInfo(
|
|
127
|
+
url = url,
|
|
128
|
+
poster = poster,
|
|
129
|
+
title = self.clean_title(title) if title else "",
|
|
130
|
+
description = description,
|
|
131
|
+
tags = tags,
|
|
132
|
+
year = year,
|
|
133
|
+
rating = rating,
|
|
134
|
+
actors = actors,
|
|
135
|
+
duration = int(duration) if duration else None,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
def _get_iframe(self, source_code: str) -> str:
|
|
139
|
+
"""Base64 kodlu iframe'i çözümle"""
|
|
140
|
+
atob_match = re.search(r"PHA\+[0-9a-zA-Z+/=]*", source_code)
|
|
141
|
+
if not atob_match:
|
|
142
|
+
return ""
|
|
143
|
+
|
|
144
|
+
atob = atob_match.group()
|
|
145
|
+
|
|
146
|
+
# Padding düzelt
|
|
147
|
+
padding = 4 - len(atob) % 4
|
|
148
|
+
if padding < 4:
|
|
149
|
+
atob = atob + "=" * padding
|
|
150
|
+
|
|
151
|
+
try:
|
|
152
|
+
decoded = base64.b64decode(atob).decode("utf-8")
|
|
153
|
+
secici = Selector(text=decoded)
|
|
154
|
+
return self.fix_url(secici.css("iframe::attr(src)").get()) or ""
|
|
155
|
+
except Exception:
|
|
156
|
+
return ""
|
|
157
|
+
|
|
158
|
+
def _extract_subtitle_url(self, source_code: str) -> str | None:
|
|
159
|
+
"""Altyazı URL'sini çıkar"""
|
|
160
|
+
match = re.search(r"(https?://[^\s\"]+\.srt)", source_code)
|
|
161
|
+
return match[1] if match else None
|
|
162
|
+
|
|
163
|
+
async def load_links(self, url: str) -> list[dict]:
|
|
164
|
+
istek = await self.httpx.get(url)
|
|
165
|
+
secici = Selector(istek.text)
|
|
166
|
+
|
|
167
|
+
iframes = set()
|
|
168
|
+
|
|
169
|
+
# Ana iframe
|
|
170
|
+
main_frame = self._get_iframe(istek.text)
|
|
171
|
+
if main_frame:
|
|
172
|
+
iframes.add(main_frame)
|
|
173
|
+
|
|
174
|
+
# Alternatif player'lar
|
|
175
|
+
for player in secici.css("div.container#player"):
|
|
176
|
+
alt_iframe = self.fix_url(player.css("iframe::attr(src)").get())
|
|
177
|
+
if alt_iframe:
|
|
178
|
+
alt_istek = await self.httpx.get(alt_iframe)
|
|
179
|
+
alt_frame = self._get_iframe(alt_istek.text)
|
|
180
|
+
if alt_frame:
|
|
181
|
+
iframes.add(alt_frame)
|
|
182
|
+
|
|
183
|
+
results = []
|
|
184
|
+
|
|
185
|
+
for iframe in iframes:
|
|
186
|
+
subtitles = []
|
|
187
|
+
|
|
188
|
+
# VidMoly özel işleme
|
|
189
|
+
if "vidmoly" in iframe:
|
|
190
|
+
headers = {
|
|
191
|
+
"User-Agent" : "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36",
|
|
192
|
+
"Sec-Fetch-Dest" : "iframe"
|
|
193
|
+
}
|
|
194
|
+
iframe_istek = await self.httpx.get(iframe, headers=headers)
|
|
195
|
+
m3u_match = re.search(r'file:"([^"]+)"', iframe_istek.text)
|
|
196
|
+
|
|
197
|
+
if m3u_match:
|
|
198
|
+
results.append({
|
|
199
|
+
"name" : "VidMoly",
|
|
200
|
+
"url" : m3u_match[1],
|
|
201
|
+
"referer" : self.main_url,
|
|
202
|
+
"subtitles" : []
|
|
203
|
+
})
|
|
204
|
+
continue
|
|
205
|
+
|
|
206
|
+
# Altyazı çıkar
|
|
207
|
+
subtitle_url = self._extract_subtitle_url(url)
|
|
208
|
+
if subtitle_url:
|
|
209
|
+
subtitles.append(Subtitle(name="Türkçe", url=subtitle_url))
|
|
210
|
+
|
|
211
|
+
extractor = self.ex_manager.find_extractor(iframe)
|
|
212
|
+
results.append({
|
|
213
|
+
"name" : extractor.name if extractor else "Player",
|
|
214
|
+
"url" : iframe,
|
|
215
|
+
"referer" : f"{self.main_url}/",
|
|
216
|
+
"subtitles" : subtitles
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
return results
|