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,196 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult
|
|
4
|
+
from parsel import Selector
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
class BelgeselX(PluginBase):
|
|
8
|
+
name = "BelgeselX"
|
|
9
|
+
language = "tr"
|
|
10
|
+
main_url = "https://belgeselx.com"
|
|
11
|
+
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
12
|
+
description = "2022 yılında son çıkan belgeselleri belgeselx.com'da izle. En yeni belgeseller, türkçe altyazılı yada dublaj olarak 1080p kalitesinde hd belgesel izle."
|
|
13
|
+
|
|
14
|
+
main_page = {
|
|
15
|
+
f"{main_url}/konu/turk-tarihi-belgeselleri&page=" : "Türk Tarihi",
|
|
16
|
+
f"{main_url}/konu/tarih-belgeselleri&page=" : "Tarih",
|
|
17
|
+
f"{main_url}/konu/seyehat-belgeselleri&page=" : "Seyahat",
|
|
18
|
+
f"{main_url}/konu/seri-belgeseller&page=" : "Seri",
|
|
19
|
+
f"{main_url}/konu/savas-belgeselleri&page=" : "Savaş",
|
|
20
|
+
f"{main_url}/konu/sanat-belgeselleri&page=" : "Sanat",
|
|
21
|
+
f"{main_url}/konu/psikoloji-belgeselleri&page=" : "Psikoloji",
|
|
22
|
+
f"{main_url}/konu/polisiye-belgeselleri&page=" : "Polisiye",
|
|
23
|
+
f"{main_url}/konu/otomobil-belgeselleri&page=" : "Otomobil",
|
|
24
|
+
f"{main_url}/konu/nazi-belgeselleri&page=" : "Nazi",
|
|
25
|
+
f"{main_url}/konu/muhendislik-belgeselleri&page=" : "Mühendislik",
|
|
26
|
+
f"{main_url}/konu/kultur-din-belgeselleri&page=" : "Kültür Din",
|
|
27
|
+
f"{main_url}/konu/kozmik-belgeseller&page=" : "Kozmik",
|
|
28
|
+
f"{main_url}/konu/hayvan-belgeselleri&page=" : "Hayvan",
|
|
29
|
+
f"{main_url}/konu/eski-tarih-belgeselleri&page=" : "Eski Tarih",
|
|
30
|
+
f"{main_url}/konu/egitim-belgeselleri&page=" : "Eğitim",
|
|
31
|
+
f"{main_url}/konu/dunya-belgeselleri&page=" : "Dünya",
|
|
32
|
+
f"{main_url}/konu/doga-belgeselleri&page=" : "Doğa",
|
|
33
|
+
f"{main_url}/konu/bilim-belgeselleri&page=" : "Bilim"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@staticmethod
|
|
37
|
+
def _to_title_case(text: str) -> str:
|
|
38
|
+
"""Türkçe için title case dönüşümü."""
|
|
39
|
+
return " ".join(
|
|
40
|
+
word.lower().replace("i", "İ").capitalize() if word.lower().startswith("i") else word.capitalize()
|
|
41
|
+
for word in text.split()
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
45
|
+
istek = self.cloudscraper.get(f"{url}{page}")
|
|
46
|
+
secici = Selector(istek.text)
|
|
47
|
+
|
|
48
|
+
results = []
|
|
49
|
+
for item in secici.css("div.gen-movie-contain > div.gen-info-contain > div.gen-movie-info"):
|
|
50
|
+
title = item.css("div.gen-movie-info > h3 a::text").get()
|
|
51
|
+
href = item.css("div.gen-movie-info > h3 a::attr(href)").get()
|
|
52
|
+
parent = item.xpath("../../..")
|
|
53
|
+
poster = parent.css("div.gen-movie-img > img::attr(src)").get()
|
|
54
|
+
|
|
55
|
+
if title and href:
|
|
56
|
+
results.append(MainPageResult(
|
|
57
|
+
category = category,
|
|
58
|
+
title = self._to_title_case(title.strip()),
|
|
59
|
+
url = self.fix_url(href),
|
|
60
|
+
poster = self.fix_url(poster) if poster else None
|
|
61
|
+
))
|
|
62
|
+
|
|
63
|
+
return results
|
|
64
|
+
|
|
65
|
+
async def search(self, query: str) -> list[SearchResult]:
|
|
66
|
+
# Google Custom Search API kullanıyor
|
|
67
|
+
cx = "016376594590146270301:iwmy65ijgrm"
|
|
68
|
+
|
|
69
|
+
token_resp = self.cloudscraper.get(f"https://cse.google.com/cse.js?cx={cx}")
|
|
70
|
+
token_text = token_resp.text
|
|
71
|
+
|
|
72
|
+
cse_lib_match = re.search(r'cselibVersion": "(.*)"', token_text)
|
|
73
|
+
cse_tok_match = re.search(r'cse_token": "(.*)"', token_text)
|
|
74
|
+
|
|
75
|
+
if not cse_lib_match or not cse_tok_match:
|
|
76
|
+
return []
|
|
77
|
+
|
|
78
|
+
cse_lib = cse_lib_match.group(1)
|
|
79
|
+
cse_tok = cse_tok_match.group(1)
|
|
80
|
+
|
|
81
|
+
search_url = (
|
|
82
|
+
f"https://cse.google.com/cse/element/v1?"
|
|
83
|
+
f"rsz=filtered_cse&num=100&hl=tr&source=gcsc&cselibv={cse_lib}&cx={cx}"
|
|
84
|
+
f"&q={query}&safe=off&cse_tok={cse_tok}&sort=&exp=cc%2Capo&oq={query}"
|
|
85
|
+
f"&callback=google.search.cse.api9969&rurl=https%3A%2F%2Fbelgeselx.com%2F"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
resp = self.cloudscraper.get(search_url)
|
|
89
|
+
resp_text = resp.text
|
|
90
|
+
|
|
91
|
+
titles = re.findall(r'"titleNoFormatting": "(.*?)"', resp_text)
|
|
92
|
+
urls = re.findall(r'"url": "(.*?)"', resp_text)
|
|
93
|
+
images = re.findall(r'"ogImage": "(.*?)"', resp_text)
|
|
94
|
+
|
|
95
|
+
results = []
|
|
96
|
+
for i, title in enumerate(titles):
|
|
97
|
+
url_val = urls[i] if i < len(urls) else None
|
|
98
|
+
poster = images[i] if i < len(images) else None
|
|
99
|
+
|
|
100
|
+
if not url_val or "diziresimleri" not in url_val:
|
|
101
|
+
# URL'den belgesel linkini oluştur
|
|
102
|
+
if poster and "diziresimleri" in poster:
|
|
103
|
+
file_name = poster.rsplit("/", 1)[-1]
|
|
104
|
+
file_name = re.sub(r"\.(jpe?g|png|webp)$", "", file_name)
|
|
105
|
+
url_val = f"{self.main_url}/belgeseldizi/{file_name}"
|
|
106
|
+
else:
|
|
107
|
+
continue
|
|
108
|
+
|
|
109
|
+
clean_title = title.split("İzle")[0].strip()
|
|
110
|
+
results.append(SearchResult(
|
|
111
|
+
title = self._to_title_case(clean_title),
|
|
112
|
+
url = url_val,
|
|
113
|
+
poster = poster
|
|
114
|
+
))
|
|
115
|
+
|
|
116
|
+
return results
|
|
117
|
+
|
|
118
|
+
async def load_item(self, url: str) -> SeriesInfo:
|
|
119
|
+
istek = await self.httpx.get(url)
|
|
120
|
+
secici = Selector(istek.text)
|
|
121
|
+
|
|
122
|
+
title = secici.css("h2.gen-title::text").get()
|
|
123
|
+
poster = secici.css("div.gen-tv-show-top img::attr(src)").get()
|
|
124
|
+
description = secici.css("div.gen-single-tv-show-info p::text").get()
|
|
125
|
+
|
|
126
|
+
tags = []
|
|
127
|
+
for tag_link in secici.css("div.gen-socail-share a[href*='belgeselkanali']"):
|
|
128
|
+
tag_href = tag_link.css("::attr(href)").get()
|
|
129
|
+
if tag_href:
|
|
130
|
+
tag_name = tag_href.rsplit("/", 1)[-1].replace("-", " ")
|
|
131
|
+
tags.append(self._to_title_case(tag_name))
|
|
132
|
+
|
|
133
|
+
episodes = []
|
|
134
|
+
counter = 0
|
|
135
|
+
for ep_item in secici.css("div.gen-movie-contain"):
|
|
136
|
+
ep_name = ep_item.css("div.gen-movie-info h3 a::text").get()
|
|
137
|
+
ep_href = ep_item.css("div.gen-movie-info h3 a::attr(href)").get()
|
|
138
|
+
|
|
139
|
+
if not ep_name or not ep_href:
|
|
140
|
+
continue
|
|
141
|
+
|
|
142
|
+
season_text = ep_item.css("div.gen-single-meta-holder ul li::text").get() or ""
|
|
143
|
+
episode_match = re.search(r"Bölüm (\d+)", season_text)
|
|
144
|
+
season_match = re.search(r"Sezon (\d+)", season_text)
|
|
145
|
+
|
|
146
|
+
ep_episode = int(episode_match.group(1)) if episode_match else counter
|
|
147
|
+
ep_season = int(season_match.group(1)) if season_match else 1
|
|
148
|
+
|
|
149
|
+
counter += 1
|
|
150
|
+
|
|
151
|
+
episodes.append(Episode(
|
|
152
|
+
season = ep_season,
|
|
153
|
+
episode = ep_episode,
|
|
154
|
+
title = ep_name.strip(),
|
|
155
|
+
url = self.fix_url(ep_href)
|
|
156
|
+
))
|
|
157
|
+
|
|
158
|
+
return SeriesInfo(
|
|
159
|
+
url = url,
|
|
160
|
+
poster = self.fix_url(poster) if poster else None,
|
|
161
|
+
title = self._to_title_case(title.strip()) if title else None,
|
|
162
|
+
description = description.strip() if description else None,
|
|
163
|
+
tags = tags,
|
|
164
|
+
episodes = episodes
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
168
|
+
istek = await self.httpx.get(url)
|
|
169
|
+
text = istek.text
|
|
170
|
+
|
|
171
|
+
# fnc_addWatch div'inden data-episode ID'sini al
|
|
172
|
+
ep_match = re.search(r'<div[^>]*class=["\'][^"\']*fnc_addWatch[^"\']*["\'][^>]*data-episode=["\'](\d+)["\']', text)
|
|
173
|
+
if not ep_match:
|
|
174
|
+
return []
|
|
175
|
+
|
|
176
|
+
episode_id = ep_match.group(1)
|
|
177
|
+
iframe_url = f"{self.main_url}/video/data/new4.php?id={episode_id}"
|
|
178
|
+
|
|
179
|
+
iframe_resp = await self.httpx.get(iframe_url, headers={"Referer": url})
|
|
180
|
+
iframe_text = iframe_resp.text
|
|
181
|
+
|
|
182
|
+
links = []
|
|
183
|
+
for match in re.finditer(r'file:"([^"]+)", label: "([^"]+)"', iframe_text):
|
|
184
|
+
video_url = match.group(1)
|
|
185
|
+
quality = match.group(2)
|
|
186
|
+
|
|
187
|
+
source_name = "Google" if quality == "FULL" else self.name
|
|
188
|
+
quality_str = "1080p" if quality == "FULL" else quality
|
|
189
|
+
|
|
190
|
+
links.append(ExtractResult(
|
|
191
|
+
url = video_url,
|
|
192
|
+
name = f"{source_name} | {quality_str}",
|
|
193
|
+
referer = url
|
|
194
|
+
))
|
|
195
|
+
|
|
196
|
+
return links
|
KekikStream/Plugins/DiziBox.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult
|
|
4
4
|
from Kekik.Sifreleme import CryptoJS
|
|
5
5
|
from parsel import Selector
|
|
6
6
|
import re, urllib.parse, base64, contextlib, asyncio, time
|
|
@@ -40,15 +40,14 @@ class DiziBox(PluginBase):
|
|
|
40
40
|
f"{main_url}/dizi-arsivi/page/SAYFA/?tur[0]=yarisma&yil&imdb" : "Yarışma"
|
|
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
|
-
self.
|
|
44
|
+
self.httpx.cookies.update({
|
|
46
45
|
"isTrustedUser" : "true",
|
|
47
46
|
"dbxu" : str(time.time() * 1000).split(".")[0]
|
|
48
47
|
})
|
|
49
|
-
istek = await self.
|
|
48
|
+
istek = await self.httpx.get(
|
|
50
49
|
url = f"{url.replace('SAYFA', str(page))}",
|
|
51
|
-
|
|
50
|
+
follow_redirects = True
|
|
52
51
|
)
|
|
53
52
|
secici = Selector(istek.text)
|
|
54
53
|
|
|
@@ -62,13 +61,12 @@ class DiziBox(PluginBase):
|
|
|
62
61
|
for veri in secici.css("article.detailed-article")
|
|
63
62
|
]
|
|
64
63
|
|
|
65
|
-
#@kekik_cache(ttl=60*60)
|
|
66
64
|
async def search(self, query: str) -> list[SearchResult]:
|
|
67
|
-
self.
|
|
65
|
+
self.httpx.cookies.update({
|
|
68
66
|
"isTrustedUser" : "true",
|
|
69
67
|
"dbxu" : str(time.time() * 1000).split(".")[0]
|
|
70
68
|
})
|
|
71
|
-
istek = await self.
|
|
69
|
+
istek = await self.httpx.get(f"{self.main_url}/?s={query}")
|
|
72
70
|
secici = Selector(istek.text)
|
|
73
71
|
|
|
74
72
|
return [
|
|
@@ -80,9 +78,8 @@ class DiziBox(PluginBase):
|
|
|
80
78
|
for item in secici.css("article.detailed-article")
|
|
81
79
|
]
|
|
82
80
|
|
|
83
|
-
#@kekik_cache(ttl=60*60)
|
|
84
81
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
85
|
-
istek = await self.
|
|
82
|
+
istek = await self.httpx.get(url)
|
|
86
83
|
secici = Selector(istek.text)
|
|
87
84
|
|
|
88
85
|
title = secici.css("div.tv-overview h1 a::text").get()
|
|
@@ -96,7 +93,7 @@ class DiziBox(PluginBase):
|
|
|
96
93
|
episodes = []
|
|
97
94
|
for sezon_link in secici.css("div#seasons-list a::attr(href)").getall():
|
|
98
95
|
sezon_url = self.fix_url(sezon_link)
|
|
99
|
-
sezon_istek = await self.
|
|
96
|
+
sezon_istek = await self.httpx.get(sezon_url)
|
|
100
97
|
sezon_secici = Selector(sezon_istek.text)
|
|
101
98
|
|
|
102
99
|
for bolum in sezon_secici.css("article.grid-box"):
|
|
@@ -127,12 +124,11 @@ class DiziBox(PluginBase):
|
|
|
127
124
|
actors = actors,
|
|
128
125
|
)
|
|
129
126
|
|
|
130
|
-
#@kekik_cache(ttl=60*60)
|
|
131
127
|
async def _iframe_decode(self, name:str, iframe_link:str, referer:str) -> list[str]:
|
|
132
128
|
results = []
|
|
133
129
|
|
|
134
|
-
self.
|
|
135
|
-
self.
|
|
130
|
+
self.httpx.headers.update({"Referer": referer})
|
|
131
|
+
self.httpx.cookies.update({
|
|
136
132
|
"isTrustedUser" : "true",
|
|
137
133
|
"dbxu" : str(time.time() * 1000).split(".")[0]
|
|
138
134
|
})
|
|
@@ -140,12 +136,12 @@ class DiziBox(PluginBase):
|
|
|
140
136
|
if "/player/king/king.php" in iframe_link:
|
|
141
137
|
iframe_link = iframe_link.replace("king.php?v=", "king.php?wmode=opaque&v=")
|
|
142
138
|
|
|
143
|
-
istek = await self.
|
|
139
|
+
istek = await self.httpx.get(iframe_link)
|
|
144
140
|
secici = Selector(istek.text)
|
|
145
141
|
iframe = secici.css("div#Player iframe::attr(src)").get()
|
|
146
142
|
|
|
147
|
-
self.
|
|
148
|
-
istek = await self.
|
|
143
|
+
self.httpx.headers.update({"Referer": self.main_url})
|
|
144
|
+
istek = await self.httpx.get(iframe)
|
|
149
145
|
|
|
150
146
|
crypt_data = re.search(r"CryptoJS\.AES\.decrypt\(\"(.*)\",\"", istek.text)[1]
|
|
151
147
|
crypt_pass = re.search(r"\",\"(.*)\"\);", istek.text)[1]
|
|
@@ -161,7 +157,7 @@ class DiziBox(PluginBase):
|
|
|
161
157
|
while True:
|
|
162
158
|
await asyncio.sleep(.3)
|
|
163
159
|
with contextlib.suppress(Exception):
|
|
164
|
-
istek = await self.
|
|
160
|
+
istek = await self.httpx.get(iframe_link)
|
|
165
161
|
|
|
166
162
|
if atob_data := re.search(r"unescape\(\"(.*)\"\)", istek.text):
|
|
167
163
|
decoded_atob = urllib.parse.unquote(atob_data[1])
|
|
@@ -178,20 +174,17 @@ class DiziBox(PluginBase):
|
|
|
178
174
|
|
|
179
175
|
return results
|
|
180
176
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
istek = await self.cffi.get(url)
|
|
177
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
178
|
+
istek = await self.httpx.get(url)
|
|
184
179
|
secici = Selector(istek.text)
|
|
185
180
|
|
|
186
181
|
results = []
|
|
187
182
|
if main_iframe := secici.css("div#video-area iframe::attr(src)").get():
|
|
188
183
|
if decoded := await self._iframe_decode(self.name, main_iframe, url):
|
|
189
184
|
for iframe in decoded:
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
"name" : f"{extractor.name if extractor else 'Main Player'}"
|
|
194
|
-
})
|
|
185
|
+
data = await self.extract(iframe)
|
|
186
|
+
if data:
|
|
187
|
+
results.append(data)
|
|
195
188
|
|
|
196
189
|
for alternatif in secici.css("div.video-toolbar option[value]"):
|
|
197
190
|
alt_name = alternatif.css("::text").get()
|
|
@@ -200,18 +193,16 @@ class DiziBox(PluginBase):
|
|
|
200
193
|
if not alt_link:
|
|
201
194
|
continue
|
|
202
195
|
|
|
203
|
-
self.
|
|
204
|
-
alt_istek = await self.
|
|
196
|
+
self.httpx.headers.update({"Referer": url})
|
|
197
|
+
alt_istek = await self.httpx.get(alt_link)
|
|
205
198
|
alt_istek.raise_for_status()
|
|
206
199
|
|
|
207
200
|
alt_secici = Selector(alt_istek.text)
|
|
208
201
|
if alt_iframe := alt_secici.css("div#video-area iframe::attr(src)").get():
|
|
209
202
|
if decoded := await self._iframe_decode(alt_name, alt_iframe, url):
|
|
210
203
|
for iframe in decoded:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
"name" : f"{extractor.name if extractor else alt_name}"
|
|
215
|
-
})
|
|
204
|
+
data = await self.extract(iframe, prefix=alt_name)
|
|
205
|
+
if data:
|
|
206
|
+
results.append(data)
|
|
216
207
|
|
|
217
|
-
return results
|
|
208
|
+
return results
|
KekikStream/Plugins/DiziPal.py
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode,
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, Subtitle, ExtractResult
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
import re
|
|
6
6
|
|
|
7
7
|
class DiziPal(PluginBase):
|
|
8
8
|
name = "DiziPal"
|
|
9
9
|
language = "tr"
|
|
10
|
-
main_url = "https://
|
|
10
|
+
main_url = "https://dizipal1223.com"
|
|
11
11
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
12
|
-
description = "
|
|
12
|
+
description = "dizipal güncel, dizipal yeni ve gerçek adresi. dizipal en yeni dizi ve filmleri güvenli ve hızlı şekilde sunar."
|
|
13
13
|
|
|
14
14
|
main_page = {
|
|
15
15
|
f"{main_url}/diziler/son-bolumler" : "Son Bölümler",
|
|
@@ -26,7 +26,7 @@ class DiziPal(PluginBase):
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
29
|
-
istek = await self.
|
|
29
|
+
istek = await self.httpx.get(url)
|
|
30
30
|
secici = Selector(istek.text)
|
|
31
31
|
|
|
32
32
|
results = []
|
|
@@ -67,12 +67,12 @@ class DiziPal(PluginBase):
|
|
|
67
67
|
return results
|
|
68
68
|
|
|
69
69
|
async def search(self, query: str) -> list[SearchResult]:
|
|
70
|
-
self.
|
|
70
|
+
self.httpx.headers.update({
|
|
71
71
|
"Accept" : "application/json, text/javascript, */*; q=0.01",
|
|
72
72
|
"X-Requested-With" : "XMLHttpRequest"
|
|
73
73
|
})
|
|
74
74
|
|
|
75
|
-
istek = await self.
|
|
75
|
+
istek = await self.httpx.post(
|
|
76
76
|
url = f"{self.main_url}/api/search-autocomplete",
|
|
77
77
|
data = {"query": query}
|
|
78
78
|
)
|
|
@@ -106,12 +106,12 @@ class DiziPal(PluginBase):
|
|
|
106
106
|
|
|
107
107
|
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
108
108
|
# Reset headers to get HTML response
|
|
109
|
-
self.
|
|
109
|
+
self.httpx.headers.update({
|
|
110
110
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
|
111
111
|
})
|
|
112
|
-
self.
|
|
112
|
+
self.httpx.headers.pop("X-Requested-With", None)
|
|
113
113
|
|
|
114
|
-
istek = await self.
|
|
114
|
+
istek = await self.httpx.get(url)
|
|
115
115
|
secici = Selector(text=istek.text, type="html")
|
|
116
116
|
|
|
117
117
|
poster = self.fix_url(secici.css("meta[property='og:image']::attr(content)").get())
|
|
@@ -177,14 +177,14 @@ class DiziPal(PluginBase):
|
|
|
177
177
|
duration = duration,
|
|
178
178
|
)
|
|
179
179
|
|
|
180
|
-
async def load_links(self, url: str) -> list[
|
|
180
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
181
181
|
# Reset headers to get HTML response
|
|
182
|
-
self.
|
|
182
|
+
self.httpx.headers.update({
|
|
183
183
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
|
184
184
|
})
|
|
185
|
-
self.
|
|
185
|
+
self.httpx.headers.pop("X-Requested-With", None)
|
|
186
186
|
|
|
187
|
-
istek = await self.
|
|
187
|
+
istek = await self.httpx.get(url)
|
|
188
188
|
secici = Selector(istek.text)
|
|
189
189
|
|
|
190
190
|
iframe = secici.css(".series-player-container iframe::attr(src)").get()
|
|
@@ -196,8 +196,8 @@ class DiziPal(PluginBase):
|
|
|
196
196
|
|
|
197
197
|
results = []
|
|
198
198
|
|
|
199
|
-
self.
|
|
200
|
-
i_istek = await self.
|
|
199
|
+
self.httpx.headers.update({"Referer": f"{self.main_url}/"})
|
|
200
|
+
i_istek = await self.httpx.get(iframe)
|
|
201
201
|
i_text = i_istek.text
|
|
202
202
|
|
|
203
203
|
# m3u link çıkar
|
|
@@ -220,27 +220,16 @@ class DiziPal(PluginBase):
|
|
|
220
220
|
sub_url = sub_text.replace(f"[{lang}]", "")
|
|
221
221
|
subtitles.append(Subtitle(name=lang, url=self.fix_url(sub_url)))
|
|
222
222
|
|
|
223
|
-
results.append(
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
223
|
+
results.append(ExtractResult(
|
|
224
|
+
name = self.name,
|
|
225
|
+
url = m3u_link,
|
|
226
|
+
referer = f"{self.main_url}/",
|
|
227
|
+
subtitles = subtitles
|
|
228
|
+
))
|
|
229
229
|
else:
|
|
230
230
|
# Extractor'a yönlendir
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
"url" : iframe,
|
|
235
|
-
"referer" : f"{self.main_url}/",
|
|
236
|
-
})
|
|
231
|
+
data = await self.extract(iframe)
|
|
232
|
+
if data:
|
|
233
|
+
results.append(data)
|
|
237
234
|
|
|
238
235
|
return results
|
|
239
|
-
|
|
240
|
-
async def play(self, name: str, url: str, referer: str, subtitles: list[Subtitle]):
|
|
241
|
-
extract_result = ExtractResult(name=name, url=url, referer=referer, subtitles=subtitles)
|
|
242
|
-
self.media_handler.title = name
|
|
243
|
-
if self.name not in self.media_handler.title:
|
|
244
|
-
self.media_handler.title = f"{self.name} | {self.media_handler.title}"
|
|
245
|
-
|
|
246
|
-
self.media_handler.play_media(extract_result)
|
KekikStream/Plugins/DiziYou.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, Subtitle, ExtractResult
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
import re
|
|
6
6
|
|
|
@@ -29,9 +29,8 @@ class DiziYou(PluginBase):
|
|
|
29
29
|
f"{main_url}/dizi-arsivi/page/SAYFA/?tur=Vah%C5%9Fi+Bat%C4%B1" : "Vahşi Batı"
|
|
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.replace('SAYFA', str(page))}")
|
|
35
34
|
secici = Selector(istek.text)
|
|
36
35
|
|
|
37
36
|
return [
|
|
@@ -44,27 +43,36 @@ class DiziYou(PluginBase):
|
|
|
44
43
|
for veri in secici.css("div.single-item")
|
|
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(f"{self.main_url}/?s={query}")
|
|
50
48
|
secici = Selector(istek.text)
|
|
51
49
|
|
|
52
50
|
return [
|
|
53
51
|
SearchResult(
|
|
54
52
|
title = afis.css("div#categorytitle a::text").get().strip(),
|
|
55
53
|
url = self.fix_url(afis.css("div#categorytitle a::attr(href)").get()),
|
|
56
|
-
poster = self.fix_url(afis.css("img::attr(src)").get())
|
|
54
|
+
poster = self.fix_url(afis.css("img::attr(src)").get() or afis.css("img::attr(data-src)").get())
|
|
57
55
|
)
|
|
58
56
|
for afis in secici.css("div.incontent div#list-series")
|
|
59
57
|
]
|
|
60
58
|
|
|
61
|
-
#@kekik_cache(ttl=60*60)
|
|
62
59
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
63
|
-
istek = await self.
|
|
60
|
+
istek = await self.httpx.get(url)
|
|
64
61
|
secici = Selector(istek.text)
|
|
65
62
|
|
|
66
|
-
title
|
|
67
|
-
|
|
63
|
+
# Title - div.title h1 içinde
|
|
64
|
+
title_raw = secici.css("div.title h1::text").get()
|
|
65
|
+
title = title_raw.strip() if title_raw else ""
|
|
66
|
+
|
|
67
|
+
# Fallback: Eğer title boşsa URL'den çıkar (telif kısıtlaması olan sayfalar için)
|
|
68
|
+
if not title:
|
|
69
|
+
# URL'den slug'ı al: https://www.diziyou.one/jasmine/ -> jasmine -> Jasmine
|
|
70
|
+
slug = url.rstrip('/').split('/')[-1]
|
|
71
|
+
title = slug.replace('-', ' ').title()
|
|
72
|
+
|
|
73
|
+
# Poster
|
|
74
|
+
poster_raw = secici.css("div.category_image img::attr(src)").get()
|
|
75
|
+
poster = self.fix_url(poster_raw) if poster_raw else ""
|
|
68
76
|
year = secici.xpath("//span[contains(., 'Yapım Yılı')]/following-sibling::text()[1]").get()
|
|
69
77
|
description = secici.css("div.diziyou_desc::text").get()
|
|
70
78
|
if description:
|
|
@@ -75,13 +83,21 @@ class DiziYou(PluginBase):
|
|
|
75
83
|
actors = [actor.strip() for actor in _actors.split(",")] if _actors else []
|
|
76
84
|
|
|
77
85
|
episodes = []
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
# Episodes - bolumust her bölüm için bir <a> içinde
|
|
87
|
+
# :has() parsel'de çalışmıyor, XPath kullanıyoruz
|
|
88
|
+
for link in secici.xpath('//a[div[@class="bolumust"]]'):
|
|
89
|
+
ep_name_raw = link.css("div.baslik::text").get()
|
|
90
|
+
if not ep_name_raw:
|
|
91
|
+
continue
|
|
92
|
+
ep_name = ep_name_raw.strip()
|
|
93
|
+
|
|
94
|
+
ep_href = self.fix_url(link.css("::attr(href)").get())
|
|
95
|
+
if not ep_href:
|
|
82
96
|
continue
|
|
83
97
|
|
|
84
|
-
|
|
98
|
+
# Bölüm ismi varsa al
|
|
99
|
+
ep_name_raw_clean = link.css("div.bolumismi::text").get()
|
|
100
|
+
ep_name_clean = ep_name_raw_clean.strip().replace("(", "").replace(")", "").strip() if ep_name_raw_clean else ep_name
|
|
85
101
|
|
|
86
102
|
ep_episode = re.search(r"(\d+)\. Bölüm", ep_name)[1]
|
|
87
103
|
ep_season = re.search(r"(\d+)\. Sezon", ep_name)[1]
|
|
@@ -107,14 +123,23 @@ class DiziYou(PluginBase):
|
|
|
107
123
|
actors = actors
|
|
108
124
|
)
|
|
109
125
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
istek = await self.cffi.get(url)
|
|
126
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
127
|
+
istek = await self.httpx.get(url)
|
|
113
128
|
secici = Selector(istek.text)
|
|
114
129
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
130
|
+
# Title ve episode name - None kontrolü ekle
|
|
131
|
+
item_title_raw = secici.css("div.title h1::text").get()
|
|
132
|
+
item_title = item_title_raw.strip() if item_title_raw else ""
|
|
133
|
+
|
|
134
|
+
ep_name_raw = secici.css("div#bolum-ismi::text").get()
|
|
135
|
+
ep_name = ep_name_raw.strip() if ep_name_raw else ""
|
|
136
|
+
|
|
137
|
+
# Player src'den item_id çıkar
|
|
138
|
+
player_src = secici.css("iframe#diziyouPlayer::attr(src)").get()
|
|
139
|
+
if not player_src:
|
|
140
|
+
return [] # Player bulunamadıysa boş liste döndür
|
|
141
|
+
|
|
142
|
+
item_id = player_src.split("/")[-1].replace(".html", "")
|
|
118
143
|
|
|
119
144
|
subtitles = []
|
|
120
145
|
stream_urls = []
|
|
@@ -154,19 +179,11 @@ class DiziYou(PluginBase):
|
|
|
154
179
|
|
|
155
180
|
results = []
|
|
156
181
|
for stream in stream_urls:
|
|
157
|
-
results.append(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
return results
|
|
165
|
-
|
|
166
|
-
async def play(self, name: str, url: str, referer: str, subtitles: list[Subtitle]):
|
|
167
|
-
extract_result = ExtractResult(name=name, url=url, referer=referer, subtitles=subtitles)
|
|
168
|
-
self.media_handler.title = name
|
|
169
|
-
if self.name not in self.media_handler.title:
|
|
170
|
-
self.media_handler.title = f"{self.name} | {self.media_handler.title}"
|
|
171
|
-
|
|
172
|
-
self.media_handler.play_media(extract_result)
|
|
182
|
+
results.append(ExtractResult(
|
|
183
|
+
url = stream.get("url"),
|
|
184
|
+
name = f"{stream.get('dil')}",
|
|
185
|
+
referer = url,
|
|
186
|
+
subtitles = subtitles
|
|
187
|
+
))
|
|
188
|
+
|
|
189
|
+
return results
|