KekikStream 2.2.2__py3-none-any.whl → 2.2.8__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/Extractors/CloseLoad.py +47 -11
- KekikStream/Extractors/Filemoon.py +7 -6
- KekikStream/Extractors/MolyStream.py +6 -5
- KekikStream/Extractors/PlayerFilmIzle.py +6 -2
- KekikStream/Extractors/VidHide.py +0 -1
- KekikStream/Extractors/VidMoly.py +17 -9
- KekikStream/Plugins/BelgeselX.py +39 -20
- KekikStream/Plugins/DiziBox.py +115 -59
- KekikStream/Plugins/DiziPal.py +87 -40
- KekikStream/Plugins/DiziYou.py +105 -64
- KekikStream/Plugins/Dizilla.py +58 -29
- KekikStream/Plugins/FilmBip.py +60 -31
- KekikStream/Plugins/FilmMakinesi.py +75 -51
- KekikStream/Plugins/FilmModu.py +73 -36
- KekikStream/Plugins/FullHDFilm.py +82 -48
- KekikStream/Plugins/FullHDFilmizlesene.py +94 -39
- KekikStream/Plugins/HDFilmCehennemi.py +109 -88
- KekikStream/Plugins/JetFilmizle.py +78 -50
- KekikStream/Plugins/KultFilmler.py +64 -34
- KekikStream/Plugins/RoketDizi.py +43 -26
- KekikStream/Plugins/SelcukFlix.py +27 -14
- KekikStream/Plugins/SetFilmIzle.py +74 -43
- KekikStream/Plugins/SezonlukDizi.py +102 -46
- KekikStream/Plugins/Sinefy.py +130 -101
- KekikStream/Plugins/SinemaCX.py +82 -37
- KekikStream/Plugins/Sinezy.py +61 -47
- KekikStream/Plugins/SuperFilmGeldi.py +72 -36
- KekikStream/Plugins/UgurFilm.py +72 -34
- KekikStream/requirements.txt +1 -1
- {kekikstream-2.2.2.dist-info → kekikstream-2.2.8.dist-info}/METADATA +39 -32
- {kekikstream-2.2.2.dist-info → kekikstream-2.2.8.dist-info}/RECORD +35 -35
- {kekikstream-2.2.2.dist-info → kekikstream-2.2.8.dist-info}/WHEEL +0 -0
- {kekikstream-2.2.2.dist-info → kekikstream-2.2.8.dist-info}/entry_points.txt +0 -0
- {kekikstream-2.2.2.dist-info → kekikstream-2.2.8.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-2.2.2.dist-info → kekikstream-2.2.8.dist-info}/top_level.txt +0 -0
KekikStream/Plugins/DiziPal.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core
|
|
4
|
-
from
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, Subtitle, ExtractResult
|
|
4
|
+
from selectolax.parser import HTMLParser
|
|
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://dizipal1224.com"
|
|
11
11
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
12
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
|
|
|
@@ -27,19 +27,24 @@ class DiziPal(PluginBase):
|
|
|
27
27
|
|
|
28
28
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
29
29
|
istek = await self.httpx.get(url)
|
|
30
|
-
secici =
|
|
30
|
+
secici = HTMLParser(istek.text)
|
|
31
31
|
|
|
32
32
|
results = []
|
|
33
33
|
|
|
34
34
|
if "/son-bolumler" in url:
|
|
35
35
|
for veri in secici.css("div.episode-item"):
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
name_el = veri.css_first("div.name")
|
|
37
|
+
episode_el = veri.css_first("div.episode")
|
|
38
|
+
link_el = veri.css_first("a")
|
|
39
|
+
img_el = veri.css_first("img")
|
|
40
|
+
|
|
41
|
+
name = name_el.text(strip=True) if name_el else None
|
|
42
|
+
episode = episode_el.text(strip=True) if episode_el else None
|
|
43
|
+
href = link_el.attrs.get("href") if link_el else None
|
|
44
|
+
poster = img_el.attrs.get("src") if img_el else None
|
|
40
45
|
|
|
41
46
|
if name and href:
|
|
42
|
-
ep_text = episode.
|
|
47
|
+
ep_text = episode.replace(". Sezon ", "x").replace(". Bölüm", "") if episode else ""
|
|
43
48
|
title = f"{name} {ep_text}"
|
|
44
49
|
# Son bölümler linkini dizi sayfasına çevir
|
|
45
50
|
dizi_url = href.split("/sezon")[0] if "/sezon" in href else href
|
|
@@ -52,9 +57,13 @@ class DiziPal(PluginBase):
|
|
|
52
57
|
))
|
|
53
58
|
else:
|
|
54
59
|
for veri in secici.css("article.type2 ul li"):
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
title_el = veri.css_first("span.title")
|
|
61
|
+
link_el = veri.css_first("a")
|
|
62
|
+
img_el = veri.css_first("img")
|
|
63
|
+
|
|
64
|
+
title = title_el.text(strip=True) if title_el else None
|
|
65
|
+
href = link_el.attrs.get("href") if link_el else None
|
|
66
|
+
poster = img_el.attrs.get("src") if img_el else None
|
|
58
67
|
|
|
59
68
|
if title and href:
|
|
60
69
|
results.append(MainPageResult(
|
|
@@ -104,6 +113,18 @@ class DiziPal(PluginBase):
|
|
|
104
113
|
|
|
105
114
|
return results
|
|
106
115
|
|
|
116
|
+
def _find_sibling_text(self, secici: HTMLParser, label_text: str) -> str | None:
|
|
117
|
+
"""Bir label'ın kardeş div'inden text çıkarır (xpath yerine)"""
|
|
118
|
+
for div in secici.css("div"):
|
|
119
|
+
if div.text(strip=True) == label_text:
|
|
120
|
+
# Sonraki kardeş elementi bul
|
|
121
|
+
next_sibling = div.next
|
|
122
|
+
while next_sibling:
|
|
123
|
+
if hasattr(next_sibling, 'text') and next_sibling.text(strip=True):
|
|
124
|
+
return next_sibling.text(strip=True)
|
|
125
|
+
next_sibling = next_sibling.next if hasattr(next_sibling, 'next') else None
|
|
126
|
+
return None
|
|
127
|
+
|
|
107
128
|
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
108
129
|
# Reset headers to get HTML response
|
|
109
130
|
self.httpx.headers.update({
|
|
@@ -112,28 +133,51 @@ class DiziPal(PluginBase):
|
|
|
112
133
|
self.httpx.headers.pop("X-Requested-With", None)
|
|
113
134
|
|
|
114
135
|
istek = await self.httpx.get(url)
|
|
115
|
-
secici =
|
|
136
|
+
secici = HTMLParser(istek.text)
|
|
137
|
+
html_text = istek.text
|
|
138
|
+
|
|
139
|
+
og_image = secici.css_first("meta[property='og:image']")
|
|
140
|
+
poster = self.fix_url(og_image.attrs.get("content")) if og_image else None
|
|
141
|
+
|
|
142
|
+
# XPath yerine regex ile HTML'den çıkarma
|
|
143
|
+
year = None
|
|
144
|
+
year_match = re.search(r'Yapım Yılı.*?<div[^>]*>(\d{4})</div>', html_text, re.DOTALL | re.IGNORECASE)
|
|
145
|
+
if year_match:
|
|
146
|
+
year = year_match.group(1)
|
|
116
147
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
description = secici.css("div.summary p::text").get()
|
|
120
|
-
rating = secici.xpath("//div[text()='IMDB Puanı']//following-sibling::div/text()").get()
|
|
121
|
-
tags_raw = secici.xpath("//div[text()='Türler']//following-sibling::div/text()").get()
|
|
122
|
-
tags = [t.strip() for t in tags_raw.split() if t.strip()] if tags_raw else None
|
|
148
|
+
desc_el = secici.css_first("div.summary p")
|
|
149
|
+
description = desc_el.text(strip=True) if desc_el else None
|
|
123
150
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
151
|
+
rating = None
|
|
152
|
+
rating_match = re.search(r'IMDB Puanı.*?<div[^>]*>([0-9.]+)</div>', html_text, re.DOTALL | re.IGNORECASE)
|
|
153
|
+
if rating_match:
|
|
154
|
+
rating = rating_match.group(1)
|
|
155
|
+
|
|
156
|
+
tags = None
|
|
157
|
+
tags_match = re.search(r'Türler.*?<div[^>]*>([^<]+)</div>', html_text, re.DOTALL | re.IGNORECASE)
|
|
158
|
+
if tags_match:
|
|
159
|
+
tags_raw = tags_match.group(1)
|
|
160
|
+
tags = [t.strip() for t in tags_raw.split() if t.strip()]
|
|
161
|
+
|
|
162
|
+
duration = None
|
|
163
|
+
dur_match = re.search(r'Ortalama Süre.*?<div[^>]*>(\d+)', html_text, re.DOTALL | re.IGNORECASE)
|
|
164
|
+
if dur_match:
|
|
165
|
+
duration = int(dur_match.group(1))
|
|
127
166
|
|
|
128
167
|
if "/dizi/" in url:
|
|
129
|
-
|
|
168
|
+
title_el = secici.css_first("div.cover h5")
|
|
169
|
+
title = title_el.text(strip=True) if title_el else None
|
|
130
170
|
|
|
131
171
|
episodes = []
|
|
132
172
|
for ep in secici.css("div.episode-item"):
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
173
|
+
ep_name_el = ep.css_first("div.name")
|
|
174
|
+
ep_link_el = ep.css_first("a")
|
|
175
|
+
ep_episode_el = ep.css_first("div.episode")
|
|
176
|
+
|
|
177
|
+
ep_name = ep_name_el.text(strip=True) if ep_name_el else None
|
|
178
|
+
ep_href = ep_link_el.attrs.get("href") if ep_link_el else None
|
|
179
|
+
ep_text = ep_episode_el.text(strip=True) if ep_episode_el else ""
|
|
180
|
+
ep_parts = ep_text.split(" ")
|
|
137
181
|
|
|
138
182
|
ep_season = None
|
|
139
183
|
ep_episode = None
|
|
@@ -148,7 +192,7 @@ class DiziPal(PluginBase):
|
|
|
148
192
|
episodes.append(Episode(
|
|
149
193
|
season = ep_season,
|
|
150
194
|
episode = ep_episode,
|
|
151
|
-
title = ep_name
|
|
195
|
+
title = ep_name,
|
|
152
196
|
url = self.fix_url(ep_href),
|
|
153
197
|
))
|
|
154
198
|
|
|
@@ -156,24 +200,26 @@ class DiziPal(PluginBase):
|
|
|
156
200
|
url = url,
|
|
157
201
|
poster = poster,
|
|
158
202
|
title = title,
|
|
159
|
-
description = description
|
|
203
|
+
description = description,
|
|
160
204
|
tags = tags,
|
|
161
|
-
rating = rating
|
|
162
|
-
year = year
|
|
205
|
+
rating = rating,
|
|
206
|
+
year = year,
|
|
163
207
|
duration = duration,
|
|
164
208
|
episodes = episodes if episodes else None,
|
|
165
209
|
)
|
|
166
210
|
else:
|
|
167
|
-
title
|
|
211
|
+
# Film için title - g-title div'lerinin 2. olanı
|
|
212
|
+
g_titles = secici.css("div.g-title div")
|
|
213
|
+
title = g_titles[1].text(strip=True) if len(g_titles) >= 2 else None
|
|
168
214
|
|
|
169
215
|
return MovieInfo(
|
|
170
216
|
url = url,
|
|
171
217
|
poster = poster,
|
|
172
|
-
title = title
|
|
173
|
-
description = description
|
|
218
|
+
title = title,
|
|
219
|
+
description = description,
|
|
174
220
|
tags = tags,
|
|
175
|
-
rating = rating
|
|
176
|
-
year = year
|
|
221
|
+
rating = rating,
|
|
222
|
+
year = year,
|
|
177
223
|
duration = duration,
|
|
178
224
|
)
|
|
179
225
|
|
|
@@ -185,12 +231,13 @@ class DiziPal(PluginBase):
|
|
|
185
231
|
self.httpx.headers.pop("X-Requested-With", None)
|
|
186
232
|
|
|
187
233
|
istek = await self.httpx.get(url)
|
|
188
|
-
secici =
|
|
234
|
+
secici = HTMLParser(istek.text)
|
|
189
235
|
|
|
190
|
-
|
|
191
|
-
if not
|
|
192
|
-
|
|
236
|
+
iframe_el = secici.css_first(".series-player-container iframe")
|
|
237
|
+
if not iframe_el:
|
|
238
|
+
iframe_el = secici.css_first("div#vast_new iframe")
|
|
193
239
|
|
|
240
|
+
iframe = iframe_el.attrs.get("src") if iframe_el else None
|
|
194
241
|
if not iframe:
|
|
195
242
|
return []
|
|
196
243
|
|
KekikStream/Plugins/DiziYou.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core
|
|
4
|
-
from
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, Subtitle, ExtractResult
|
|
4
|
+
from selectolax.parser import HTMLParser
|
|
5
5
|
import re
|
|
6
6
|
|
|
7
7
|
class DiziYou(PluginBase):
|
|
@@ -31,38 +31,57 @@ class DiziYou(PluginBase):
|
|
|
31
31
|
|
|
32
32
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
33
33
|
istek = await self.httpx.get(f"{url.replace('SAYFA', str(page))}")
|
|
34
|
-
secici =
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
|
|
34
|
+
secici = HTMLParser(istek.text)
|
|
35
|
+
|
|
36
|
+
results = []
|
|
37
|
+
for veri in secici.css("div.single-item"):
|
|
38
|
+
title_el = veri.css_first("div#categorytitle a")
|
|
39
|
+
img_el = veri.css_first("img")
|
|
40
|
+
|
|
41
|
+
title = title_el.text(strip=True) if title_el else None
|
|
42
|
+
href = title_el.attrs.get("href") if title_el else None
|
|
43
|
+
poster = img_el.attrs.get("src") if img_el else None
|
|
44
|
+
|
|
45
|
+
if title and href:
|
|
46
|
+
results.append(MainPageResult(
|
|
47
|
+
category = category,
|
|
48
|
+
title = title,
|
|
49
|
+
url = self.fix_url(href),
|
|
50
|
+
poster = self.fix_url(poster) if poster else None,
|
|
51
|
+
))
|
|
52
|
+
|
|
53
|
+
return results
|
|
45
54
|
|
|
46
55
|
async def search(self, query: str) -> list[SearchResult]:
|
|
47
56
|
istek = await self.httpx.get(f"{self.main_url}/?s={query}")
|
|
48
|
-
secici =
|
|
57
|
+
secici = HTMLParser(istek.text)
|
|
58
|
+
|
|
59
|
+
results = []
|
|
60
|
+
for afis in secici.css("div.incontent div#list-series"):
|
|
61
|
+
title_el = afis.css_first("div#categorytitle a")
|
|
62
|
+
img_el = afis.css_first("img")
|
|
63
|
+
|
|
64
|
+
title = title_el.text(strip=True) if title_el else None
|
|
65
|
+
href = title_el.attrs.get("href") if title_el else None
|
|
66
|
+
poster = (img_el.attrs.get("src") or img_el.attrs.get("data-src")) if img_el else None
|
|
67
|
+
|
|
68
|
+
if title and href:
|
|
69
|
+
results.append(SearchResult(
|
|
70
|
+
title = title,
|
|
71
|
+
url = self.fix_url(href),
|
|
72
|
+
poster = self.fix_url(poster) if poster else None,
|
|
73
|
+
))
|
|
49
74
|
|
|
50
|
-
return
|
|
51
|
-
SearchResult(
|
|
52
|
-
title = afis.css("div#categorytitle a::text").get().strip(),
|
|
53
|
-
url = self.fix_url(afis.css("div#categorytitle a::attr(href)").get()),
|
|
54
|
-
poster = self.fix_url(afis.css("img::attr(src)").get() or afis.css("img::attr(data-src)").get())
|
|
55
|
-
)
|
|
56
|
-
for afis in secici.css("div.incontent div#list-series")
|
|
57
|
-
]
|
|
75
|
+
return results
|
|
58
76
|
|
|
59
77
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
60
78
|
istek = await self.httpx.get(url)
|
|
61
|
-
secici =
|
|
79
|
+
secici = HTMLParser(istek.text)
|
|
80
|
+
html_text = istek.text
|
|
62
81
|
|
|
63
82
|
# Title - div.title h1 içinde
|
|
64
|
-
|
|
65
|
-
title
|
|
83
|
+
title_el = secici.css_first("div.title h1")
|
|
84
|
+
title = title_el.text(strip=True) if title_el else ""
|
|
66
85
|
|
|
67
86
|
# Fallback: Eğer title boşsa URL'den çıkar (telif kısıtlaması olan sayfalar için)
|
|
68
87
|
if not title:
|
|
@@ -71,45 +90,66 @@ class DiziYou(PluginBase):
|
|
|
71
90
|
title = slug.replace('-', ' ').title()
|
|
72
91
|
|
|
73
92
|
# Poster
|
|
74
|
-
|
|
75
|
-
poster
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
93
|
+
poster_el = secici.css_first("div.category_image img")
|
|
94
|
+
poster = self.fix_url(poster_el.attrs.get("src")) if poster_el else ""
|
|
95
|
+
|
|
96
|
+
# Year - regex ile çıkarma (xpath yerine)
|
|
97
|
+
year = None
|
|
98
|
+
year_match = re.search(r"Yapım Yılı.*?(\d{4})", html_text, re.DOTALL | re.IGNORECASE)
|
|
99
|
+
if year_match:
|
|
100
|
+
year = year_match.group(1)
|
|
101
|
+
|
|
102
|
+
desc_el = secici.css_first("div.diziyou_desc")
|
|
103
|
+
description = desc_el.text(strip=True) if desc_el else None
|
|
104
|
+
|
|
105
|
+
tags = [a.text(strip=True) for a in secici.css("div.genres a") if a.text(strip=True)]
|
|
106
|
+
|
|
107
|
+
# Rating - regex ile
|
|
108
|
+
rating = None
|
|
109
|
+
rating_match = re.search(r"IMDB.*?([0-9.]+)", html_text, re.DOTALL | re.IGNORECASE)
|
|
110
|
+
if rating_match:
|
|
111
|
+
rating = rating_match.group(1)
|
|
112
|
+
|
|
113
|
+
# Actors - regex ile
|
|
114
|
+
actors = []
|
|
115
|
+
actors_match = re.search(r"Oyuncular.*?</span>([^<]+)", html_text, re.DOTALL | re.IGNORECASE)
|
|
116
|
+
if actors_match:
|
|
117
|
+
actors = [actor.strip() for actor in actors_match.group(1).split(",") if actor.strip()]
|
|
118
|
+
|
|
119
|
+
episodes = []
|
|
120
|
+
# Episodes - bolumust div içeren a linklerini bul
|
|
121
|
+
for link in secici.css("a"):
|
|
122
|
+
bolumust = link.css_first("div.bolumust")
|
|
123
|
+
if not bolumust:
|
|
91
124
|
continue
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
125
|
+
|
|
126
|
+
baslik_el = link.css_first("div.baslik")
|
|
127
|
+
if not baslik_el:
|
|
128
|
+
continue
|
|
129
|
+
|
|
130
|
+
ep_name = baslik_el.text(strip=True)
|
|
131
|
+
ep_href = link.attrs.get("href")
|
|
95
132
|
if not ep_href:
|
|
96
133
|
continue
|
|
97
134
|
|
|
98
135
|
# Bölüm ismi varsa al
|
|
99
|
-
|
|
100
|
-
ep_name_clean =
|
|
136
|
+
bolumismi_el = link.css_first("div.bolumismi")
|
|
137
|
+
ep_name_clean = bolumismi_el.text(strip=True).replace("(", "").replace(")", "").strip() if bolumismi_el else ep_name
|
|
101
138
|
|
|
102
|
-
|
|
103
|
-
|
|
139
|
+
ep_episode_match = re.search(r"(\d+)\. Bölüm", ep_name)
|
|
140
|
+
ep_season_match = re.search(r"(\d+)\. Sezon", ep_name)
|
|
104
141
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
episode = ep_episode,
|
|
108
|
-
title = ep_name_clean,
|
|
109
|
-
url = ep_href,
|
|
110
|
-
)
|
|
142
|
+
ep_episode = ep_episode_match.group(1) if ep_episode_match else None
|
|
143
|
+
ep_season = ep_season_match.group(1) if ep_season_match else None
|
|
111
144
|
|
|
112
|
-
|
|
145
|
+
if ep_episode and ep_season:
|
|
146
|
+
episode = Episode(
|
|
147
|
+
season = ep_season,
|
|
148
|
+
episode = ep_episode,
|
|
149
|
+
title = ep_name_clean,
|
|
150
|
+
url = self.fix_url(ep_href),
|
|
151
|
+
)
|
|
152
|
+
episodes.append(episode)
|
|
113
153
|
|
|
114
154
|
return SeriesInfo(
|
|
115
155
|
url = url,
|
|
@@ -125,17 +165,18 @@ class DiziYou(PluginBase):
|
|
|
125
165
|
|
|
126
166
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
127
167
|
istek = await self.httpx.get(url)
|
|
128
|
-
secici =
|
|
168
|
+
secici = HTMLParser(istek.text)
|
|
129
169
|
|
|
130
170
|
# Title ve episode name - None kontrolü ekle
|
|
131
|
-
|
|
132
|
-
item_title =
|
|
171
|
+
title_el = secici.css_first("div.title h1")
|
|
172
|
+
item_title = title_el.text(strip=True) if title_el else ""
|
|
133
173
|
|
|
134
|
-
|
|
135
|
-
ep_name =
|
|
174
|
+
ep_name_el = secici.css_first("div#bolum-ismi")
|
|
175
|
+
ep_name = ep_name_el.text(strip=True) if ep_name_el else ""
|
|
136
176
|
|
|
137
177
|
# Player src'den item_id çıkar
|
|
138
|
-
|
|
178
|
+
player_el = secici.css_first("iframe#diziyouPlayer")
|
|
179
|
+
player_src = player_el.attrs.get("src") if player_el else None
|
|
139
180
|
if not player_src:
|
|
140
181
|
return [] # Player bulunamadıysa boş liste döndür
|
|
141
182
|
|
|
@@ -145,8 +186,8 @@ class DiziYou(PluginBase):
|
|
|
145
186
|
stream_urls = []
|
|
146
187
|
|
|
147
188
|
for secenek in secici.css("span.diziyouOption"):
|
|
148
|
-
opt_id = secenek.
|
|
149
|
-
op_name = secenek.
|
|
189
|
+
opt_id = secenek.attrs.get("id")
|
|
190
|
+
op_name = secenek.text(strip=True)
|
|
150
191
|
|
|
151
192
|
match opt_id:
|
|
152
193
|
case "turkceAltyazili":
|
KekikStream/Plugins/Dizilla.py
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core
|
|
4
|
-
from
|
|
5
|
-
from json
|
|
6
|
-
from urllib.parse
|
|
7
|
-
from Crypto.Cipher
|
|
8
|
-
from base64
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult
|
|
4
|
+
from selectolax.parser import HTMLParser
|
|
5
|
+
from json import loads
|
|
6
|
+
from urllib.parse import urlparse, urlunparse
|
|
7
|
+
from Crypto.Cipher import AES
|
|
8
|
+
from base64 import b64decode
|
|
9
9
|
|
|
10
10
|
class Dizilla(PluginBase):
|
|
11
11
|
name = "Dizilla"
|
|
12
12
|
language = "tr"
|
|
13
|
-
main_url = "https://
|
|
13
|
+
main_url = "https://dizilla.to"
|
|
14
14
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
15
15
|
description = "1080p yabancı dizi izle. Türkçe altyazılı veya dublaj seçenekleriyle 1080p çözünürlükte yabancı dizilere anında ulaş. Popüler dizileri kesintisiz izle."
|
|
16
16
|
|
|
@@ -51,30 +51,45 @@ class Dizilla(PluginBase):
|
|
|
51
51
|
])
|
|
52
52
|
else:
|
|
53
53
|
istek = await self.httpx.get(url.replace("SAYFA", str(page)))
|
|
54
|
-
secici =
|
|
54
|
+
secici = HTMLParser(istek.text)
|
|
55
55
|
|
|
56
56
|
for veri in secici.css("div.tab-content > div.grid a"):
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
h2_el = veri.css_first("h2")
|
|
58
|
+
name = h2_el.text(strip=True) if h2_el else None
|
|
59
|
+
|
|
60
|
+
# opacity-80 div'den episode bilgisi - normalize-space yerine doğrudan text
|
|
61
|
+
opacity_el = veri.css_first("div[class*='opacity-80']")
|
|
62
|
+
ep_name = opacity_el.text(strip=True) if opacity_el else None
|
|
59
63
|
if not ep_name:
|
|
60
64
|
continue
|
|
61
65
|
|
|
62
66
|
ep_name = ep_name.replace(". Sezon", "x").replace(". Bölüm", "").replace("x ", "x")
|
|
63
67
|
title = f"{name} - {ep_name}"
|
|
64
68
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
69
|
+
href = veri.attrs.get("href")
|
|
70
|
+
ep_req = await self.httpx.get(self.fix_url(href))
|
|
71
|
+
ep_secici = HTMLParser(ep_req.text)
|
|
72
|
+
|
|
73
|
+
# nav li'leri alıp 3. elemana erişme (nth-of-type yerine)
|
|
74
|
+
nav_lis = ep_secici.css("nav li")
|
|
75
|
+
if len(nav_lis) >= 3:
|
|
76
|
+
link_el = nav_lis[2].css_first("a")
|
|
77
|
+
href = link_el.attrs.get("href") if link_el else None
|
|
78
|
+
else:
|
|
79
|
+
href = None
|
|
80
|
+
|
|
81
|
+
poster_el = ep_secici.css_first("img.imgt")
|
|
82
|
+
poster = poster_el.attrs.get("src") if poster_el else None
|
|
83
|
+
|
|
84
|
+
if href:
|
|
85
|
+
ana_sayfa.append(
|
|
86
|
+
MainPageResult(
|
|
87
|
+
category = category,
|
|
88
|
+
title = title,
|
|
89
|
+
url = self.fix_url(href),
|
|
90
|
+
poster = self.fix_url(poster) if poster else None
|
|
91
|
+
)
|
|
76
92
|
)
|
|
77
|
-
)
|
|
78
93
|
|
|
79
94
|
return ana_sayfa
|
|
80
95
|
|
|
@@ -125,8 +140,16 @@ class Dizilla(PluginBase):
|
|
|
125
140
|
|
|
126
141
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
127
142
|
istek = await self.httpx.get(url)
|
|
128
|
-
secici =
|
|
129
|
-
|
|
143
|
+
secici = HTMLParser(istek.text)
|
|
144
|
+
|
|
145
|
+
# application/ld+json script'lerini al
|
|
146
|
+
ld_json_scripts = secici.css("script[type='application/ld+json']")
|
|
147
|
+
if not ld_json_scripts:
|
|
148
|
+
return None
|
|
149
|
+
|
|
150
|
+
# Son script'i al
|
|
151
|
+
last_script = ld_json_scripts[-1]
|
|
152
|
+
veri = loads(last_script.text(strip=True))
|
|
130
153
|
|
|
131
154
|
title = veri.get("name")
|
|
132
155
|
if alt_title := veri.get("alternateName"):
|
|
@@ -137,7 +160,8 @@ class Dizilla(PluginBase):
|
|
|
137
160
|
year = veri.get("datePublished").split("-")[0]
|
|
138
161
|
|
|
139
162
|
# Tags extraction from page content (h3 tag)
|
|
140
|
-
|
|
163
|
+
tags_el = secici.css_first("div.poster.poster h3")
|
|
164
|
+
tags_raw = tags_el.text(strip=True) if tags_el else ""
|
|
141
165
|
tags = [t.strip() for t in tags_raw.split(",")] if tags_raw else []
|
|
142
166
|
|
|
143
167
|
rating = veri.get("aggregateRating", {}).get("ratingValue")
|
|
@@ -172,9 +196,13 @@ class Dizilla(PluginBase):
|
|
|
172
196
|
|
|
173
197
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
174
198
|
istek = await self.httpx.get(url)
|
|
175
|
-
secici =
|
|
199
|
+
secici = HTMLParser(istek.text)
|
|
200
|
+
|
|
201
|
+
next_data_el = secici.css_first("script#__NEXT_DATA__")
|
|
202
|
+
if not next_data_el:
|
|
203
|
+
return []
|
|
176
204
|
|
|
177
|
-
next_data = loads(
|
|
205
|
+
next_data = loads(next_data_el.text(strip=True))
|
|
178
206
|
secure_data = next_data.get("props", {}).get("pageProps", {}).get("secureData", {})
|
|
179
207
|
decrypted = await self.decrypt_response(secure_data)
|
|
180
208
|
results = decrypted.get("RelatedResults", {}).get("getEpisodeSources", {}).get("result", [])
|
|
@@ -190,8 +218,9 @@ class Dizilla(PluginBase):
|
|
|
190
218
|
cleaned_source = source_content.replace('"', '').replace('\\', '')
|
|
191
219
|
|
|
192
220
|
# Parse cleaned HTML
|
|
193
|
-
|
|
194
|
-
|
|
221
|
+
iframe_el = HTMLParser(cleaned_source).css_first("iframe")
|
|
222
|
+
iframe_src = iframe_el.attrs.get("src") if iframe_el else None
|
|
223
|
+
iframe_url = self.fix_url(iframe_src) if iframe_src else None
|
|
195
224
|
|
|
196
225
|
if not iframe_url:
|
|
197
226
|
return []
|