KekikStream 2.3.3__py3-none-any.whl → 2.3.5__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/HTMLHelper.py +134 -0
- KekikStream/Core/Plugin/PluginBase.py +12 -2
- KekikStream/Core/__init__.py +2 -0
- KekikStream/Extractors/CloseLoad.py +12 -13
- KekikStream/Extractors/ContentX.py +33 -31
- KekikStream/Extractors/DonilasPlay.py +10 -10
- KekikStream/Extractors/DzenRu.py +3 -3
- KekikStream/Extractors/ExPlay.py +10 -10
- KekikStream/Extractors/Filemoon.py +11 -16
- KekikStream/Extractors/JetTv.py +4 -4
- KekikStream/Extractors/MixPlayHD.py +10 -11
- KekikStream/Extractors/MolyStream.py +15 -9
- KekikStream/Extractors/Odnoklassniki.py +4 -4
- KekikStream/Extractors/PeaceMakerst.py +3 -3
- KekikStream/Extractors/PixelDrain.py +6 -5
- KekikStream/Extractors/PlayerFilmIzle.py +6 -10
- KekikStream/Extractors/RapidVid.py +8 -7
- KekikStream/Extractors/SetPlay.py +10 -10
- KekikStream/Extractors/SetPrime.py +3 -6
- KekikStream/Extractors/SibNet.py +4 -5
- KekikStream/Extractors/Sobreatsesuyp.py +5 -5
- KekikStream/Extractors/TRsTX.py +5 -5
- KekikStream/Extractors/TurboImgz.py +3 -4
- KekikStream/Extractors/TurkeyPlayer.py +5 -5
- KekikStream/Extractors/VidHide.py +4 -7
- KekikStream/Extractors/VidMoly.py +24 -25
- KekikStream/Extractors/VidMoxy.py +8 -9
- KekikStream/Extractors/VidPapi.py +5 -7
- KekikStream/Extractors/VideoSeyred.py +3 -3
- KekikStream/Plugins/BelgeselX.py +40 -51
- KekikStream/Plugins/DiziBox.py +53 -81
- KekikStream/Plugins/DiziPal.py +41 -74
- KekikStream/Plugins/DiziWatch.py +217 -0
- KekikStream/Plugins/DiziYou.py +95 -88
- KekikStream/Plugins/Dizilla.py +54 -72
- KekikStream/Plugins/FilmBip.py +24 -49
- KekikStream/Plugins/FilmMakinesi.py +35 -52
- KekikStream/Plugins/FilmModu.py +27 -41
- KekikStream/Plugins/FullHDFilm.py +50 -72
- KekikStream/Plugins/FullHDFilmizlesene.py +35 -51
- KekikStream/Plugins/HDFilmCehennemi.py +48 -62
- KekikStream/Plugins/JetFilmizle.py +32 -50
- KekikStream/Plugins/KultFilmler.py +42 -67
- KekikStream/Plugins/RecTV.py +7 -4
- KekikStream/Plugins/RoketDizi.py +30 -50
- KekikStream/Plugins/SelcukFlix.py +15 -29
- KekikStream/Plugins/SetFilmIzle.py +41 -70
- KekikStream/Plugins/SezonlukDizi.py +47 -65
- KekikStream/Plugins/Sinefy.py +39 -50
- KekikStream/Plugins/SinemaCX.py +31 -55
- KekikStream/Plugins/Sinezy.py +27 -54
- KekikStream/Plugins/SuperFilmGeldi.py +25 -44
- KekikStream/Plugins/UgurFilm.py +23 -48
- KekikStream/Plugins/YabanciDizi.py +274 -0
- {kekikstream-2.3.3.dist-info → kekikstream-2.3.5.dist-info}/METADATA +1 -1
- kekikstream-2.3.5.dist-info/RECORD +85 -0
- kekikstream-2.3.3.dist-info/RECORD +0 -82
- {kekikstream-2.3.3.dist-info → kekikstream-2.3.5.dist-info}/WHEEL +0 -0
- {kekikstream-2.3.3.dist-info → kekikstream-2.3.5.dist-info}/entry_points.txt +0 -0
- {kekikstream-2.3.3.dist-info → kekikstream-2.3.5.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-2.3.3.dist-info → kekikstream-2.3.5.dist-info}/top_level.txt +0 -0
KekikStream/Plugins/Dizilla.py
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult
|
|
4
|
-
from selectolax.parser import HTMLParser
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
|
|
5
4
|
from json import loads
|
|
6
5
|
from urllib.parse import urlparse, urlunparse
|
|
7
6
|
from Crypto.Cipher import AES
|
|
8
7
|
from base64 import b64decode
|
|
9
|
-
import re
|
|
10
8
|
|
|
11
9
|
class Dizilla(PluginBase):
|
|
12
10
|
name = "Dizilla"
|
|
@@ -52,45 +50,26 @@ class Dizilla(PluginBase):
|
|
|
52
50
|
])
|
|
53
51
|
else:
|
|
54
52
|
istek = await self.httpx.get(url.replace("SAYFA", str(page)))
|
|
55
|
-
secici =
|
|
53
|
+
secici = HTMLHelper(istek.text)
|
|
56
54
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
opacity_el = veri.css_first("div[class*='opacity-80']")
|
|
63
|
-
ep_name = opacity_el.text(strip=True) if opacity_el else None
|
|
64
|
-
if not ep_name:
|
|
55
|
+
# Genel olarak dizi sayfalarına giden linkleri al
|
|
56
|
+
for veri in secici.select('a[href*="/dizi/"]'):
|
|
57
|
+
href = secici.select_attr('a', 'href', veri)
|
|
58
|
+
title = secici.select_text(None, veri)
|
|
59
|
+
if not href or not title:
|
|
65
60
|
continue
|
|
66
61
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
79
|
-
else:
|
|
80
|
-
href = None
|
|
81
|
-
|
|
82
|
-
poster_el = ep_secici.css_first("img.imgt")
|
|
83
|
-
poster = poster_el.attrs.get("src") if poster_el else None
|
|
84
|
-
|
|
85
|
-
if href:
|
|
86
|
-
ana_sayfa.append(
|
|
87
|
-
MainPageResult(
|
|
88
|
-
category = category,
|
|
89
|
-
title = title,
|
|
90
|
-
url = self.fix_url(href),
|
|
91
|
-
poster = self.fix_url(poster) if poster else None
|
|
92
|
-
)
|
|
93
|
-
)
|
|
62
|
+
# Detay sayfasından poster vb. bilgileri al
|
|
63
|
+
ep_req = await self.httpx.get(self.fix_url(href))
|
|
64
|
+
ep_secici = HTMLHelper(ep_req.text)
|
|
65
|
+
poster = ep_secici.select_attr('img.imgt', 'src') or ep_secici.select_attr('img', 'src')
|
|
66
|
+
|
|
67
|
+
ana_sayfa.append(MainPageResult(
|
|
68
|
+
category = category,
|
|
69
|
+
title = title,
|
|
70
|
+
url = self.fix_url(href),
|
|
71
|
+
poster = self.fix_url(poster) if poster else None
|
|
72
|
+
))
|
|
94
73
|
|
|
95
74
|
return ana_sayfa
|
|
96
75
|
|
|
@@ -124,9 +103,10 @@ class Dizilla(PluginBase):
|
|
|
124
103
|
# -> https://images.macellan.online/...
|
|
125
104
|
if "cdn.ampproject.org" in url:
|
|
126
105
|
# /i/s/ veya /ii/s/ gibi AMP prefix'lerinden sonraki kısmı al
|
|
127
|
-
|
|
106
|
+
helper = HTMLHelper(url)
|
|
107
|
+
match = helper.regex_first(r"cdn\.ampproject\.org/[^/]+/s/(.+)$")
|
|
128
108
|
if match:
|
|
129
|
-
return f"https://{match
|
|
109
|
+
return f"https://{match}"
|
|
130
110
|
return url
|
|
131
111
|
|
|
132
112
|
async def search(self, query: str) -> list[SearchResult]:
|
|
@@ -155,64 +135,64 @@ class Dizilla(PluginBase):
|
|
|
155
135
|
|
|
156
136
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
157
137
|
istek = await self.httpx.get(url)
|
|
158
|
-
secici =
|
|
138
|
+
secici = HTMLHelper(istek.text)
|
|
159
139
|
|
|
160
|
-
title = secici.
|
|
161
|
-
title = title.text(strip=True) if title else None
|
|
140
|
+
title = secici.select_text("div.poster.poster h2")
|
|
162
141
|
if not title:
|
|
163
142
|
return None
|
|
164
143
|
|
|
165
|
-
|
|
166
|
-
poster = self.fix_url(
|
|
144
|
+
poster = secici.select_attr("div.w-full.page-top.relative img", "src")
|
|
145
|
+
poster = self.fix_url(poster) if poster else None
|
|
167
146
|
|
|
168
147
|
# Year extraction (Kotlin: [1] index for w-fit min-w-fit)
|
|
169
|
-
info_boxes = secici.
|
|
148
|
+
info_boxes = secici.select("div.w-fit.min-w-fit")
|
|
170
149
|
year = None
|
|
171
150
|
if len(info_boxes) > 1:
|
|
172
|
-
|
|
173
|
-
if
|
|
174
|
-
year_text = year_el.text(strip=True)
|
|
151
|
+
year_text = secici.select_text("span.text-sm.opacity-60", info_boxes[1])
|
|
152
|
+
if year_text:
|
|
175
153
|
year = year_text.split(" ")[-1] if " " in year_text else year_text
|
|
176
154
|
|
|
177
|
-
|
|
178
|
-
description = description_el.text(strip=True) if description_el else None
|
|
155
|
+
description = secici.select_text("div.mt-2.text-sm")
|
|
179
156
|
|
|
180
|
-
|
|
181
|
-
tags = [t.strip() for t in
|
|
157
|
+
tags_text = secici.select_text("div.poster.poster h3")
|
|
158
|
+
tags = [t.strip() for t in tags_text.split(",")] if tags_text else []
|
|
182
159
|
|
|
183
|
-
actors =
|
|
160
|
+
actors = secici.select_all_text("div.global-box h5")
|
|
184
161
|
|
|
185
162
|
episodeses = []
|
|
186
163
|
# Seasons links iteration
|
|
187
|
-
season_links = secici.
|
|
164
|
+
season_links = secici.select("div.flex.items-center.flex-wrap.gap-2.mb-4 a")
|
|
188
165
|
for sezon in season_links:
|
|
189
|
-
sezon_href =
|
|
166
|
+
sezon_href = secici.select_attr("a", "href", sezon)
|
|
167
|
+
sezon_href = self.fix_url(sezon_href)
|
|
190
168
|
sezon_req = await self.httpx.get(sezon_href)
|
|
191
169
|
|
|
192
170
|
season_num = None
|
|
193
171
|
try:
|
|
194
172
|
# URL'den sezon numarasını çek: ...-N-sezon formatı
|
|
195
|
-
season_match =
|
|
173
|
+
season_match = secici.regex_first(r"-(\d+)-sezon", sezon_href)
|
|
196
174
|
if season_match:
|
|
197
|
-
season_num = int(season_match
|
|
175
|
+
season_num = int(season_match)
|
|
198
176
|
except:
|
|
199
177
|
pass
|
|
200
178
|
|
|
201
|
-
sezon_secici =
|
|
202
|
-
for bolum in sezon_secici.
|
|
179
|
+
sezon_secici = HTMLHelper(sezon_req.text)
|
|
180
|
+
for bolum in sezon_secici.select("div.episodes div.cursor-pointer"):
|
|
203
181
|
# Kotlin: bolum.select("a").last()
|
|
204
|
-
links =
|
|
182
|
+
links = sezon_secici.select("a", bolum)
|
|
205
183
|
if not links:
|
|
206
184
|
continue
|
|
207
185
|
|
|
208
186
|
ep_link = links[-1]
|
|
209
|
-
ep_name =
|
|
210
|
-
ep_href =
|
|
187
|
+
ep_name = sezon_secici.select_text("a", ep_link)
|
|
188
|
+
ep_href = sezon_secici.select_attr("a", "href", ep_link)
|
|
189
|
+
ep_href = self.fix_url(ep_href)
|
|
211
190
|
|
|
212
191
|
# Episode number (first link's text usually)
|
|
213
192
|
ep_num = None
|
|
214
193
|
try:
|
|
215
|
-
|
|
194
|
+
ep_num_text = sezon_secici.select_text("a", links[0])
|
|
195
|
+
ep_num = int(ep_num_text) if ep_num_text else None
|
|
216
196
|
except:
|
|
217
197
|
pass
|
|
218
198
|
|
|
@@ -236,13 +216,13 @@ class Dizilla(PluginBase):
|
|
|
236
216
|
|
|
237
217
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
238
218
|
istek = await self.httpx.get(url)
|
|
239
|
-
secici =
|
|
219
|
+
secici = HTMLHelper(istek.text)
|
|
240
220
|
|
|
241
|
-
|
|
242
|
-
if not
|
|
221
|
+
next_data_text = secici.select_text("script#__NEXT_DATA__")
|
|
222
|
+
if not next_data_text:
|
|
243
223
|
return []
|
|
244
224
|
|
|
245
|
-
next_data
|
|
225
|
+
next_data = loads(next_data_text)
|
|
246
226
|
secure_data = next_data.get("props", {}).get("pageProps", {}).get("secureData", {})
|
|
247
227
|
decrypted = await self.decrypt_response(secure_data)
|
|
248
228
|
results = decrypted.get("RelatedResults", {}).get("getEpisodeSources", {}).get("result", [])
|
|
@@ -258,8 +238,8 @@ class Dizilla(PluginBase):
|
|
|
258
238
|
cleaned_source = source_content.replace('"', '').replace('\\', '')
|
|
259
239
|
|
|
260
240
|
# Parse cleaned HTML
|
|
261
|
-
|
|
262
|
-
iframe_src =
|
|
241
|
+
iframe_secici = HTMLHelper(cleaned_source)
|
|
242
|
+
iframe_src = iframe_secici.select_attr("iframe", "src")
|
|
263
243
|
|
|
264
244
|
# Referer check (matching Kotlin: loadExtractor(iframe, "${mainUrl}/", ...))
|
|
265
245
|
iframe_url = self.fix_url(iframe_src) if iframe_src else None
|
|
@@ -268,4 +248,6 @@ class Dizilla(PluginBase):
|
|
|
268
248
|
return []
|
|
269
249
|
|
|
270
250
|
data = await self.extract(iframe_url, referer=f"{self.main_url}/", prefix=first_result.get('language_name', 'Unknown'))
|
|
271
|
-
|
|
251
|
+
if not data:
|
|
252
|
+
return []
|
|
253
|
+
return data if isinstance(data, list) else [data]
|
KekikStream/Plugins/FilmBip.py
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
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, ExtractResult
|
|
4
|
-
from selectolax.parser import HTMLParser
|
|
5
|
-
import re
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult, HTMLHelper
|
|
6
4
|
|
|
7
5
|
class FilmBip(PluginBase):
|
|
8
6
|
name = "FilmBip"
|
|
@@ -37,16 +35,13 @@ class FilmBip(PluginBase):
|
|
|
37
35
|
page_url = page_url.rstrip("/")
|
|
38
36
|
|
|
39
37
|
istek = await self.httpx.get(page_url)
|
|
40
|
-
secici =
|
|
38
|
+
secici = HTMLHelper(istek.text)
|
|
41
39
|
|
|
42
40
|
results = []
|
|
43
|
-
for veri in secici.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
title = img.attrs.get("alt") if img else None
|
|
48
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
49
|
-
poster = (img.attrs.get("data-src") or img.attrs.get("src")) if img else None
|
|
41
|
+
for veri in secici.select("div.poster-long"):
|
|
42
|
+
title = secici.select_attr("a.block img.lazy", "alt", veri)
|
|
43
|
+
href = secici.select_attr("a.block", "href", veri)
|
|
44
|
+
poster = secici.select_poster("a.block img.lazy", veri)
|
|
50
45
|
|
|
51
46
|
if title and href:
|
|
52
47
|
results.append(MainPageResult(
|
|
@@ -80,17 +75,13 @@ class FilmBip(PluginBase):
|
|
|
80
75
|
except Exception:
|
|
81
76
|
return []
|
|
82
77
|
|
|
83
|
-
secici =
|
|
78
|
+
secici = HTMLHelper(html_content)
|
|
84
79
|
|
|
85
80
|
results = []
|
|
86
|
-
for veri in secici.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
title = link_el.text(strip=True) if link_el else None
|
|
92
|
-
href = href_el.attrs.get("href") if href_el else None
|
|
93
|
-
poster = img_el.attrs.get("data-src") if img_el else None
|
|
81
|
+
for veri in secici.select("li"):
|
|
82
|
+
title = secici.select_text("a.block.truncate", veri)
|
|
83
|
+
href = secici.select_attr("a", "href", veri)
|
|
84
|
+
poster = secici.select_attr("img.lazy", "data-src", veri)
|
|
94
85
|
|
|
95
86
|
if title and href:
|
|
96
87
|
results.append(SearchResult(
|
|
@@ -103,42 +94,27 @@ class FilmBip(PluginBase):
|
|
|
103
94
|
|
|
104
95
|
async def load_item(self, url: str) -> MovieInfo:
|
|
105
96
|
istek = await self.httpx.get(url)
|
|
106
|
-
secici =
|
|
97
|
+
secici = HTMLHelper(istek.text)
|
|
107
98
|
html_text = istek.text
|
|
108
99
|
|
|
109
|
-
|
|
110
|
-
title = title_el.text(strip=True) if title_el else ""
|
|
100
|
+
title = secici.select_text("div.page-title h1") or ""
|
|
111
101
|
|
|
112
|
-
|
|
113
|
-
poster = og_image.attrs.get("content") if og_image else None
|
|
102
|
+
poster = secici.select_attr("meta[property='og:image']", "content")
|
|
114
103
|
|
|
115
|
-
|
|
116
|
-
trailer = trailer_el.attrs.get("data-yt") if trailer_el else None
|
|
104
|
+
trailer = secici.select_attr("div.series-profile-trailer", "data-yt")
|
|
117
105
|
|
|
118
|
-
|
|
119
|
-
if not desc_el:
|
|
120
|
-
desc_el = secici.css_first("div.series-profile-summary p")
|
|
121
|
-
description = desc_el.text(strip=True) if desc_el else None
|
|
106
|
+
description = secici.select_text("div.series-profile-infos-in.article p") or secici.select_text("div.series-profile-summary p")
|
|
122
107
|
|
|
123
|
-
tags =
|
|
108
|
+
tags = secici.select_all_text("div.series-profile-type.tv-show-profile-type a")
|
|
124
109
|
|
|
125
110
|
# XPath yerine regex kullanarak yıl, süre vs. çıkarma
|
|
126
|
-
year =
|
|
127
|
-
year_match = re.search(r'Yapım yılı.*?<p[^>]*>(\d{4})</p>', html_text, re.IGNORECASE | re.DOTALL)
|
|
128
|
-
if year_match:
|
|
129
|
-
year = year_match.group(1)
|
|
111
|
+
year = secici.regex_first(r'(?i)Yapım yılı.*?<p[^>]*>(\d{4})</p>', secici.html)
|
|
130
112
|
|
|
131
|
-
duration =
|
|
132
|
-
duration_match = re.search(r'Süre.*?<p[^>]*>(\d+)', html_text, re.IGNORECASE | re.DOTALL)
|
|
133
|
-
if duration_match:
|
|
134
|
-
duration = duration_match.group(1)
|
|
113
|
+
duration = secici.regex_first(r'(?i)Süre.*?<p[^>]*>(\d+)', secici.html)
|
|
135
114
|
|
|
136
|
-
rating =
|
|
137
|
-
rating_match = re.search(r'IMDB Puanı.*?<span[^>]*>([0-9.]+)</span>', html_text, re.IGNORECASE | re.DOTALL)
|
|
138
|
-
if rating_match:
|
|
139
|
-
rating = rating_match.group(1)
|
|
115
|
+
rating = secici.regex_first(r'(?i)IMDB Puanı.*?<span[^>]*>([0-9.]+)</span>', secici.html)
|
|
140
116
|
|
|
141
|
-
actors = [img.attrs.get("alt") for img in secici.
|
|
117
|
+
actors = [img.attrs.get("alt") for img in secici.select("div.series-profile-cast ul li a img") if img.attrs.get("alt")]
|
|
142
118
|
|
|
143
119
|
return MovieInfo(
|
|
144
120
|
url = url,
|
|
@@ -154,13 +130,12 @@ class FilmBip(PluginBase):
|
|
|
154
130
|
|
|
155
131
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
156
132
|
istek = await self.httpx.get(url)
|
|
157
|
-
secici =
|
|
133
|
+
secici = HTMLHelper(istek.text)
|
|
158
134
|
|
|
159
135
|
results = []
|
|
160
136
|
|
|
161
|
-
for player in secici.
|
|
162
|
-
|
|
163
|
-
iframe = iframe_el.attrs.get("src") if iframe_el else None
|
|
137
|
+
for player in secici.select("div#tv-spoox2"):
|
|
138
|
+
iframe = secici.select_attr("iframe", "src", player)
|
|
164
139
|
|
|
165
140
|
if iframe:
|
|
166
141
|
iframe = self.fix_url(iframe)
|
|
@@ -1,8 +1,6 @@
|
|
|
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, ExtractResult
|
|
4
|
-
from selectolax.parser import HTMLParser
|
|
5
|
-
import re
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult, HTMLHelper
|
|
6
4
|
|
|
7
5
|
class FilmMakinesi(PluginBase):
|
|
8
6
|
name = "FilmMakinesi"
|
|
@@ -37,17 +35,13 @@ class FilmMakinesi(PluginBase):
|
|
|
37
35
|
|
|
38
36
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
39
37
|
istek = self.cloudscraper.get(f"{url}{'' if page == 1 else f'page/{page}/'}")
|
|
40
|
-
secici =
|
|
38
|
+
secici = HTMLHelper(istek.text)
|
|
41
39
|
|
|
42
40
|
results = []
|
|
43
|
-
for veri in secici.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
title = title_el.text(strip=True) if title_el else None
|
|
49
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
50
|
-
poster = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
|
|
41
|
+
for veri in secici.select("div.item-relative"):
|
|
42
|
+
title = secici.select_text("div.title", veri)
|
|
43
|
+
href = secici.select_attr("a", "href", veri)
|
|
44
|
+
poster = secici.select_poster("img", veri)
|
|
51
45
|
|
|
52
46
|
if title and href:
|
|
53
47
|
results.append(MainPageResult(
|
|
@@ -61,17 +55,13 @@ class FilmMakinesi(PluginBase):
|
|
|
61
55
|
|
|
62
56
|
async def search(self, query: str) -> list[SearchResult]:
|
|
63
57
|
istek = await self.httpx.get(f"{self.main_url}/arama/?s={query}")
|
|
64
|
-
secici =
|
|
58
|
+
secici = HTMLHelper(istek.text)
|
|
65
59
|
|
|
66
60
|
results = []
|
|
67
|
-
for article in secici.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
title = title_el.text(strip=True) if title_el else None
|
|
73
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
74
|
-
poster = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
|
|
61
|
+
for article in secici.select("div.item-relative"):
|
|
62
|
+
title = secici.select_text("div.title", article)
|
|
63
|
+
href = secici.select_attr("a", "href", article)
|
|
64
|
+
poster = secici.select_poster("img", article)
|
|
75
65
|
|
|
76
66
|
if title and href:
|
|
77
67
|
results.append(SearchResult(
|
|
@@ -84,48 +74,42 @@ class FilmMakinesi(PluginBase):
|
|
|
84
74
|
|
|
85
75
|
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
86
76
|
istek = await self.httpx.get(url)
|
|
87
|
-
secici =
|
|
77
|
+
secici = HTMLHelper(istek.text)
|
|
88
78
|
|
|
89
|
-
|
|
90
|
-
title = title_el.text(strip=True) if title_el else ""
|
|
79
|
+
title = secici.select_text("h1.title") or ""
|
|
91
80
|
|
|
92
|
-
|
|
93
|
-
poster
|
|
81
|
+
poster = secici.select_attr("img.cover-img", "src") or ""
|
|
82
|
+
poster = poster.strip()
|
|
94
83
|
|
|
95
|
-
|
|
96
|
-
description = desc_el.text(strip=True) if desc_el else ""
|
|
84
|
+
description = secici.select_text("div.info-description p") or ""
|
|
97
85
|
|
|
98
|
-
|
|
99
|
-
rating
|
|
100
|
-
if
|
|
101
|
-
|
|
102
|
-
if rating_text:
|
|
103
|
-
rating = rating_text.split()[0]
|
|
86
|
+
rating_text = secici.select_text("div.score") or ""
|
|
87
|
+
rating = None
|
|
88
|
+
if rating_text:
|
|
89
|
+
rating = rating_text.split()[0]
|
|
104
90
|
|
|
105
|
-
|
|
106
|
-
year = year_el.text(strip=True) if year_el else ""
|
|
91
|
+
year = secici.select_text("span.date a") or ""
|
|
107
92
|
|
|
108
|
-
actors =
|
|
109
|
-
tags
|
|
93
|
+
actors = secici.select_all_text("div.cast-name")
|
|
94
|
+
tags = secici.select_all_text("div.genre a")
|
|
110
95
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if
|
|
114
|
-
duration_text = duration_el.text(strip=True)
|
|
96
|
+
duration = None
|
|
97
|
+
duration_text = secici.select_text("div.time") or None
|
|
98
|
+
if duration_text:
|
|
115
99
|
parts = duration_text.split()
|
|
116
100
|
if len(parts) > 1:
|
|
117
101
|
duration = parts[1].strip()
|
|
118
102
|
|
|
119
103
|
# Dizi mi kontrol et - sezon/bölüm linkleri var mı?
|
|
120
104
|
episodes = []
|
|
121
|
-
all_links = secici.
|
|
105
|
+
all_links = secici.select("a[href]")
|
|
122
106
|
for link in all_links:
|
|
123
107
|
href = link.attrs.get("href", "")
|
|
124
|
-
|
|
125
|
-
if
|
|
126
|
-
season_no = int(
|
|
127
|
-
ep_no = int(
|
|
128
|
-
|
|
108
|
+
pairs = HTMLHelper(href).regex_all(r"/sezon-(\d+)/bolum-(\d+)")
|
|
109
|
+
if pairs:
|
|
110
|
+
season_no = int(pairs[0][0])
|
|
111
|
+
ep_no = int(pairs[0][1])
|
|
112
|
+
|
|
129
113
|
# Bölüm başlığını çıkar - text'ten gerçek ismi al
|
|
130
114
|
# Format: "22 Eylül 2014 / 44 dk /1. Sezon / 1. BölümPilot"
|
|
131
115
|
full_text = link.text(strip=True)
|
|
@@ -184,12 +168,12 @@ class FilmMakinesi(PluginBase):
|
|
|
184
168
|
|
|
185
169
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
186
170
|
istek = await self.httpx.get(url)
|
|
187
|
-
secici =
|
|
171
|
+
secici = HTMLHelper(istek.text)
|
|
188
172
|
|
|
189
173
|
response = []
|
|
190
174
|
|
|
191
175
|
# Video parts linklerini ve etiketlerini al
|
|
192
|
-
for link in secici.
|
|
176
|
+
for link in secici.select("div.video-parts a[data-video_url]"):
|
|
193
177
|
video_url = link.attrs.get("data-video_url")
|
|
194
178
|
label = link.text(strip=True) if link.text(strip=True) else ""
|
|
195
179
|
|
|
@@ -200,8 +184,7 @@ class FilmMakinesi(PluginBase):
|
|
|
200
184
|
|
|
201
185
|
# Eğer video-parts yoksa iframe kullan
|
|
202
186
|
if not response:
|
|
203
|
-
|
|
204
|
-
iframe_src = iframe_el.attrs.get("data-src") if iframe_el else None
|
|
187
|
+
iframe_src = secici.select_attr("iframe", "data-src")
|
|
205
188
|
if iframe_src:
|
|
206
189
|
data = await self.extract(iframe_src)
|
|
207
190
|
if data:
|
KekikStream/Plugins/FilmModu.py
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
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, Subtitle, ExtractResult
|
|
4
|
-
from selectolax.parser import HTMLParser
|
|
5
|
-
import re
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, Subtitle, ExtractResult, HTMLHelper
|
|
6
4
|
|
|
7
5
|
class FilmModu(PluginBase):
|
|
8
6
|
name = "FilmModu"
|
|
@@ -42,16 +40,13 @@ class FilmModu(PluginBase):
|
|
|
42
40
|
|
|
43
41
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
44
42
|
istek = await self.httpx.get(url.replace("SAYFA", str(page)))
|
|
45
|
-
secici =
|
|
43
|
+
secici = HTMLHelper(istek.text)
|
|
46
44
|
|
|
47
45
|
results = []
|
|
48
|
-
for veri in secici.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
title = link_el.text(strip=True) if link_el else None
|
|
53
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
54
|
-
poster = img_el.attrs.get("data-src") if img_el else None
|
|
46
|
+
for veri in secici.select("div.movie"):
|
|
47
|
+
title = secici.select_text("a", veri)
|
|
48
|
+
href = secici.select_attr("a", "href", veri)
|
|
49
|
+
poster = secici.select_attr("picture img", "data-src", veri)
|
|
55
50
|
|
|
56
51
|
if title and href:
|
|
57
52
|
results.append(MainPageResult(
|
|
@@ -65,16 +60,13 @@ class FilmModu(PluginBase):
|
|
|
65
60
|
|
|
66
61
|
async def search(self, query: str) -> list[SearchResult]:
|
|
67
62
|
istek = await self.httpx.get(f"{self.main_url}/film-ara?term={query}")
|
|
68
|
-
secici =
|
|
63
|
+
secici = HTMLHelper(istek.text)
|
|
69
64
|
|
|
70
65
|
results = []
|
|
71
|
-
for veri in secici.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
title = link_el.text(strip=True) if link_el else None
|
|
76
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
77
|
-
poster = img_el.attrs.get("data-src") if img_el else None
|
|
66
|
+
for veri in secici.select("div.movie"):
|
|
67
|
+
title = secici.select_text("a", veri)
|
|
68
|
+
href = secici.select_attr("a", "href", veri)
|
|
69
|
+
poster = secici.select_attr("picture img", "data-src", veri)
|
|
78
70
|
|
|
79
71
|
if title and href:
|
|
80
72
|
results.append(SearchResult(
|
|
@@ -87,31 +79,25 @@ class FilmModu(PluginBase):
|
|
|
87
79
|
|
|
88
80
|
async def load_item(self, url: str) -> MovieInfo:
|
|
89
81
|
istek = await self.httpx.get(url)
|
|
90
|
-
secici =
|
|
91
|
-
|
|
92
|
-
org_title_el = secici.css_first("div.titles h1")
|
|
93
|
-
alt_title_el = secici.css_first("div.titles h2")
|
|
82
|
+
secici = HTMLHelper(istek.text)
|
|
94
83
|
|
|
95
|
-
org_title =
|
|
96
|
-
alt_title =
|
|
84
|
+
org_title = secici.select_text("div.titles h1") or ""
|
|
85
|
+
alt_title = secici.select_text("div.titles h2") or ""
|
|
97
86
|
title = f"{org_title} - {alt_title}" if alt_title else org_title
|
|
98
87
|
|
|
99
|
-
|
|
100
|
-
poster = poster_el.attrs.get("src") if poster_el else None
|
|
88
|
+
poster = secici.select_attr("img.img-responsive", "src") if secici.select_attr("img.img-responsive", "src") else None
|
|
101
89
|
|
|
102
|
-
|
|
103
|
-
description = desc_el.text(strip=True) if desc_el else None
|
|
90
|
+
description = secici.select_text("p[itemprop='description']") or None
|
|
104
91
|
|
|
105
|
-
tags =
|
|
92
|
+
tags = secici.select_all_text("a[href*='film-tur/']")
|
|
106
93
|
|
|
107
|
-
|
|
108
|
-
year = year_el.text(strip=True) if year_el else None
|
|
94
|
+
year = secici.select_text("span[itemprop='dateCreated']") or None
|
|
109
95
|
|
|
110
96
|
actors = []
|
|
111
|
-
for a in secici.
|
|
112
|
-
|
|
113
|
-
if
|
|
114
|
-
actors.append(
|
|
97
|
+
for a in secici.select("a[itemprop='actor']"):
|
|
98
|
+
name = secici.select_text("span", a)
|
|
99
|
+
if name:
|
|
100
|
+
actors.append(name)
|
|
115
101
|
|
|
116
102
|
return MovieInfo(
|
|
117
103
|
url = url,
|
|
@@ -125,9 +111,9 @@ class FilmModu(PluginBase):
|
|
|
125
111
|
|
|
126
112
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
127
113
|
istek = await self.httpx.get(url)
|
|
128
|
-
secici =
|
|
114
|
+
secici = HTMLHelper(istek.text)
|
|
129
115
|
|
|
130
|
-
alternates = secici.
|
|
116
|
+
alternates = secici.select("div.alternates a")
|
|
131
117
|
if not alternates:
|
|
132
118
|
return []
|
|
133
119
|
|
|
@@ -144,14 +130,14 @@ class FilmModu(PluginBase):
|
|
|
144
130
|
alt_istek = await self.httpx.get(alt_link)
|
|
145
131
|
alt_text = alt_istek.text
|
|
146
132
|
|
|
147
|
-
vid_id =
|
|
148
|
-
vid_type =
|
|
133
|
+
vid_id = HTMLHelper(alt_text).regex_first(r"var videoId = '([^']*)'")
|
|
134
|
+
vid_type = HTMLHelper(alt_text).regex_first(r"var videoType = '([^']*)'")
|
|
149
135
|
|
|
150
136
|
if not vid_id or not vid_type:
|
|
151
137
|
continue
|
|
152
138
|
|
|
153
139
|
source_istek = await self.httpx.get(
|
|
154
|
-
f"{self.main_url}/get-source?movie_id={vid_id
|
|
140
|
+
f"{self.main_url}/get-source?movie_id={vid_id}&type={vid_type}"
|
|
155
141
|
)
|
|
156
142
|
source_data = source_istek.json()
|
|
157
143
|
|