KekikStream 2.2.8__py3-none-any.whl → 2.3.9__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.
Potentially problematic release.
This version of KekikStream might be problematic. Click here for more details.
- KekikStream/Core/HTMLHelper.py +134 -0
- KekikStream/Core/Plugin/PluginBase.py +22 -4
- KekikStream/Core/Plugin/PluginLoader.py +3 -2
- KekikStream/Core/Plugin/PluginManager.py +2 -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 +47 -37
- KekikStream/Extractors/JetTv.py +4 -4
- KekikStream/Extractors/MixPlayHD.py +10 -11
- KekikStream/Extractors/MolyStream.py +16 -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 +37 -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 +50 -72
- KekikStream/Plugins/DiziYou.py +96 -83
- KekikStream/Plugins/Dizilla.py +101 -86
- KekikStream/Plugins/FilmBip.py +29 -50
- KekikStream/Plugins/FilmMakinesi.py +84 -46
- KekikStream/Plugins/FilmModu.py +27 -41
- KekikStream/Plugins/FullHDFilm.py +57 -62
- KekikStream/Plugins/FullHDFilmizlesene.py +32 -57
- KekikStream/Plugins/HDFilmCehennemi.py +51 -65
- KekikStream/Plugins/JetFilmizle.py +38 -51
- KekikStream/Plugins/KultFilmler.py +43 -67
- KekikStream/Plugins/RecTV.py +34 -9
- KekikStream/Plugins/RoketDizi.py +89 -111
- KekikStream/Plugins/SelcukFlix.py +102 -93
- KekikStream/Plugins/SetFilmIzle.py +110 -117
- KekikStream/Plugins/SezonlukDizi.py +88 -106
- KekikStream/Plugins/Sinefy.py +70 -70
- 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 +285 -0
- {kekikstream-2.2.8.dist-info → kekikstream-2.3.9.dist-info}/METADATA +1 -1
- kekikstream-2.3.9.dist-info/RECORD +84 -0
- kekikstream-2.2.8.dist-info/RECORD +0 -82
- {kekikstream-2.2.8.dist-info → kekikstream-2.3.9.dist-info}/WHEEL +0 -0
- {kekikstream-2.2.8.dist-info → kekikstream-2.3.9.dist-info}/entry_points.txt +0 -0
- {kekikstream-2.2.8.dist-info → kekikstream-2.3.9.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-2.2.8.dist-info → kekikstream-2.3.9.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
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
|
-
|
|
5
|
-
import re
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
|
|
4
|
+
import asyncio
|
|
6
5
|
|
|
7
6
|
class SezonlukDizi(PluginBase):
|
|
8
7
|
name = "SezonlukDizi"
|
|
@@ -39,18 +38,26 @@ class SezonlukDizi(PluginBase):
|
|
|
39
38
|
f"{main_url}/diziler.asp?siralama_tipi=id&tur=western&s=" : "Western"
|
|
40
39
|
}
|
|
41
40
|
|
|
41
|
+
async def _get_asp_data(self) -> dict:
|
|
42
|
+
js_req = await self.httpx.get(f"{self.main_url}/js/site.min.js")
|
|
43
|
+
js = HTMLHelper(js_req.text)
|
|
44
|
+
alt = js.regex_first(r"dataAlternatif(.*?)\.asp")
|
|
45
|
+
emb = js.regex_first(r"dataEmbed(.*?)\.asp")
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
"alternatif": alt or "",
|
|
49
|
+
"embed": emb or ""
|
|
50
|
+
}
|
|
51
|
+
|
|
42
52
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
43
53
|
istek = await self.httpx.get(f"{url}{page}")
|
|
44
|
-
secici =
|
|
54
|
+
secici = HTMLHelper(istek.text)
|
|
45
55
|
|
|
46
56
|
results = []
|
|
47
|
-
for veri in secici.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
title = desc_el.text(strip=True) if desc_el else None
|
|
52
|
-
href = veri.attrs.get("href")
|
|
53
|
-
poster = img_el.attrs.get("data-src") if img_el else None
|
|
57
|
+
for veri in secici.select("div.afis a"):
|
|
58
|
+
title = secici.select_text("div.description", veri)
|
|
59
|
+
href = secici.select_attr("a", "href", veri)
|
|
60
|
+
poster = secici.select_attr("img", "data-src", veri)
|
|
54
61
|
|
|
55
62
|
if title and href:
|
|
56
63
|
results.append(MainPageResult(
|
|
@@ -64,16 +71,13 @@ class SezonlukDizi(PluginBase):
|
|
|
64
71
|
|
|
65
72
|
async def search(self, query: str) -> list[SearchResult]:
|
|
66
73
|
istek = await self.httpx.get(f"{self.main_url}/diziler.asp?adi={query}")
|
|
67
|
-
secici =
|
|
74
|
+
secici = HTMLHelper(istek.text)
|
|
68
75
|
|
|
69
76
|
results = []
|
|
70
|
-
for afis in secici.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
title = desc_el.text(strip=True) if desc_el else None
|
|
75
|
-
href = afis.attrs.get("href")
|
|
76
|
-
poster = img_el.attrs.get("data-src") if img_el else None
|
|
77
|
+
for afis in secici.select("div.afis a"):
|
|
78
|
+
title = secici.select_text("div.description", afis)
|
|
79
|
+
href = secici.select_attr("a", "href", afis)
|
|
80
|
+
poster = secici.select_attr("img", "data-src", afis)
|
|
77
81
|
|
|
78
82
|
if title and href:
|
|
79
83
|
results.append(SearchResult(
|
|
@@ -86,67 +90,56 @@ class SezonlukDizi(PluginBase):
|
|
|
86
90
|
|
|
87
91
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
88
92
|
istek = await self.httpx.get(url)
|
|
89
|
-
secici =
|
|
93
|
+
secici = HTMLHelper(istek.text)
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
title = title_el.text(strip=True) if title_el else ""
|
|
95
|
+
title = secici.select_text("div.header") or ""
|
|
93
96
|
|
|
94
|
-
|
|
95
|
-
poster = poster_el.attrs.get("data-src", "").strip() if poster_el else ""
|
|
97
|
+
poster = secici.select_attr("div.image img", "data-src") or ""
|
|
96
98
|
|
|
97
99
|
# year: re_first yerine re.search
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
year_match = re.search(r"(\d{4})", year_text)
|
|
101
|
-
year = year_match.group(1) if year_match else None
|
|
100
|
+
year_text = secici.select_text("div.extra span") or ""
|
|
101
|
+
year = secici.regex_first(r"(\d{4})", year_text)
|
|
102
102
|
|
|
103
103
|
# xpath normalized-space yerine doğrudan ID ile element bulup text al
|
|
104
|
-
|
|
105
|
-
description = desc_el.text(strip=True) if desc_el else ""
|
|
104
|
+
description = secici.select_text("span#tartismayorum-konu") or ""
|
|
106
105
|
|
|
107
|
-
tags = [a.text(strip=True) for a in secici.
|
|
106
|
+
tags = [a.text(strip=True) for a in secici.select("div.labels a[href*='tur']") if a.text(strip=True)]
|
|
108
107
|
|
|
109
|
-
# rating:
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
rating_match = re.search(r"[\d.,]+", rating_text)
|
|
113
|
-
rating = rating_match.group() if rating_match else None
|
|
108
|
+
# rating: regex ile çıkar
|
|
109
|
+
rating_text = secici.select_text("div.dizipuani a div") or ""
|
|
110
|
+
rating = secici.regex_first(r"[\d.,]+", rating_text)
|
|
114
111
|
|
|
115
112
|
actors = []
|
|
116
113
|
|
|
117
114
|
actors_istek = await self.httpx.get(f"{self.main_url}/oyuncular/{url.split('/')[-1]}")
|
|
118
|
-
actors_secici =
|
|
119
|
-
for actor in actors_secici.
|
|
120
|
-
|
|
121
|
-
if
|
|
122
|
-
actors.append(
|
|
115
|
+
actors_secici = HTMLHelper(actors_istek.text)
|
|
116
|
+
for actor in actors_secici.select("div.doubling div.ui"):
|
|
117
|
+
header_text = actors_secici.select_text("div.header", actor)
|
|
118
|
+
if header_text:
|
|
119
|
+
actors.append(header_text)
|
|
123
120
|
|
|
124
121
|
episodes_istek = await self.httpx.get(f"{self.main_url}/bolumler/{url.split('/')[-1]}")
|
|
125
|
-
episodes_secici =
|
|
122
|
+
episodes_secici = HTMLHelper(episodes_istek.text)
|
|
126
123
|
episodes = []
|
|
127
124
|
|
|
128
|
-
for sezon in episodes_secici.
|
|
129
|
-
for bolum in
|
|
125
|
+
for sezon in episodes_secici.select("table.unstackable"):
|
|
126
|
+
for bolum in episodes_secici.select("tbody tr", sezon):
|
|
130
127
|
# td:nth-of-type selectolax'ta desteklenmiyor, alternatif yol: tüm td'leri alıp indexle
|
|
131
|
-
tds =
|
|
128
|
+
tds = episodes_secici.select("td", bolum)
|
|
132
129
|
if len(tds) < 4:
|
|
133
130
|
continue
|
|
134
131
|
|
|
135
132
|
# 4. td'den isim ve href
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
ep_href = ep_name_el.attrs.get("href") if ep_name_el else None
|
|
133
|
+
ep_name = episodes_secici.select_text("a", tds[3])
|
|
134
|
+
ep_href = episodes_secici.select_attr("a", "href", tds[3])
|
|
139
135
|
|
|
140
|
-
# 3. td'den episode (re_first yerine
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
ep_episode_match = re.search(r"(\d+)", ep_episode_text)
|
|
144
|
-
ep_episode = ep_episode_match.group(1) if ep_episode_match else None
|
|
136
|
+
# 3. td'den episode (re_first yerine regex)
|
|
137
|
+
ep_episode_text = episodes_secici.select_text("a", tds[2]) or ""
|
|
138
|
+
ep_episode = episodes_secici.regex_first(r"(\d+)", ep_episode_text)
|
|
145
139
|
|
|
146
|
-
# 2. td'den season (re_first yerine
|
|
140
|
+
# 2. td'den season (re_first yerine regex)
|
|
147
141
|
ep_season_text = tds[1].text(strip=True) if tds[1] else ""
|
|
148
|
-
|
|
149
|
-
ep_season = ep_season_match.group(1) if ep_season_match else None
|
|
142
|
+
ep_season = secici.regex_first(r"(\d+)", ep_season_text)
|
|
150
143
|
|
|
151
144
|
if ep_name and ep_href:
|
|
152
145
|
episode = Episode(
|
|
@@ -169,64 +162,53 @@ class SezonlukDizi(PluginBase):
|
|
|
169
162
|
actors = actors
|
|
170
163
|
)
|
|
171
164
|
|
|
172
|
-
async def get_asp_data(self) -> tuple[str, str]:
|
|
173
|
-
"""Fetch dynamic ASP version numbers from site.min.js"""
|
|
174
|
-
try:
|
|
175
|
-
js_content = await self.httpx.get(f"{self.main_url}/js/site.min.js")
|
|
176
|
-
alternatif_match = re.search(r'dataAlternatif(.*?)\.asp', js_content.text)
|
|
177
|
-
embed_match = re.search(r'dataEmbed(.*?)\.asp', js_content.text)
|
|
178
|
-
|
|
179
|
-
alternatif_ver = alternatif_match.group(1) if alternatif_match else "22"
|
|
180
|
-
embed_ver = embed_match.group(1) if embed_match else "22"
|
|
181
|
-
|
|
182
|
-
return (alternatif_ver, embed_ver)
|
|
183
|
-
except Exception:
|
|
184
|
-
return ("22", "22") # Fallback to default versions
|
|
185
|
-
|
|
186
165
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
187
166
|
istek = await self.httpx.get(url)
|
|
188
|
-
secici =
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
bid =
|
|
167
|
+
secici = HTMLHelper(istek.text)
|
|
168
|
+
asp_data = await self._get_asp_data()
|
|
169
|
+
|
|
170
|
+
bid = secici.select_attr("div#dilsec", "data-id")
|
|
192
171
|
if not bid:
|
|
193
172
|
return []
|
|
194
173
|
|
|
195
|
-
|
|
196
|
-
|
|
174
|
+
semaphore = asyncio.Semaphore(5)
|
|
175
|
+
tasks = []
|
|
197
176
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
177
|
+
async def fetch_and_extract(veri, dil_etiketi):
|
|
178
|
+
async with semaphore:
|
|
179
|
+
try:
|
|
180
|
+
embed_resp = await self.httpx.post(
|
|
181
|
+
f"{self.main_url}/ajax/dataEmbed{asp_data['embed']}.asp",
|
|
182
|
+
headers = {"X-Requested-With": "XMLHttpRequest"},
|
|
183
|
+
data = {"id": str(veri.get("id"))}
|
|
184
|
+
)
|
|
185
|
+
embed_secici = HTMLHelper(embed_resp.text)
|
|
186
|
+
iframe_src = embed_secici.select_attr("iframe", "src")
|
|
187
|
+
|
|
188
|
+
if iframe_src:
|
|
189
|
+
if "link.asp" in iframe_src:
|
|
190
|
+
return None
|
|
191
|
+
|
|
192
|
+
iframe_url = self.fix_url(iframe_src)
|
|
193
|
+
return await self.extract(iframe_url, referer=f"{self.main_url}/", prefix=f"{dil_etiketi} - {veri.get('baslik')}")
|
|
194
|
+
except:
|
|
195
|
+
pass
|
|
196
|
+
return None
|
|
197
|
+
|
|
198
|
+
for dil_kodu, dil_etiketi in [("1", "Altyazı"), ("0", "Dublaj")]:
|
|
199
|
+
altyazi_resp = await self.httpx.post(
|
|
200
|
+
f"{self.main_url}/ajax/dataAlternatif{asp_data['alternatif']}.asp",
|
|
202
201
|
headers = {"X-Requested-With": "XMLHttpRequest"},
|
|
203
|
-
data = {"bid": bid, "dil":
|
|
202
|
+
data = {"bid": bid, "dil": dil_kodu}
|
|
204
203
|
)
|
|
205
|
-
|
|
204
|
+
|
|
206
205
|
try:
|
|
207
|
-
|
|
208
|
-
|
|
206
|
+
data_json = altyazi_resp.json()
|
|
207
|
+
if data_json.get("status") == "success" and data_json.get("data"):
|
|
208
|
+
for veri in data_json["data"]:
|
|
209
|
+
tasks.append(fetch_and_extract(veri, dil_etiketi))
|
|
210
|
+
except:
|
|
209
211
|
continue
|
|
210
212
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
veri_response = await self.httpx.post(
|
|
214
|
-
url = f"{self.main_url}/ajax/dataEmbed{embed_ver}.asp",
|
|
215
|
-
headers = {"X-Requested-With": "XMLHttpRequest"},
|
|
216
|
-
data = {"id": veri.get("id")},
|
|
217
|
-
)
|
|
218
|
-
veri_secici = HTMLParser(veri_response.text)
|
|
219
|
-
|
|
220
|
-
iframe_el = veri_secici.css_first("iframe")
|
|
221
|
-
iframe = iframe_el.attrs.get("src") if iframe_el else None
|
|
222
|
-
|
|
223
|
-
if iframe:
|
|
224
|
-
if "link.asp" in iframe:
|
|
225
|
-
continue
|
|
226
|
-
|
|
227
|
-
iframe_url = self.fix_url(iframe)
|
|
228
|
-
data = await self.extract(iframe_url, prefix=label)
|
|
229
|
-
if data:
|
|
230
|
-
results.append(data)
|
|
231
|
-
|
|
232
|
-
return results
|
|
213
|
+
results = await asyncio.gather(*tasks)
|
|
214
|
+
return [r for r in results if r]
|
KekikStream/Plugins/Sinefy.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
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, MovieInfo, ExtractResult
|
|
4
|
-
|
|
5
|
-
import re, json, urllib.parse
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, MovieInfo, ExtractResult, HTMLHelper
|
|
4
|
+
import json, urllib.parse
|
|
6
5
|
|
|
7
6
|
class Sinefy(PluginBase):
|
|
8
7
|
name = "Sinefy"
|
|
@@ -44,17 +43,13 @@ class Sinefy(PluginBase):
|
|
|
44
43
|
full_url = f"{url}&page={page}"
|
|
45
44
|
|
|
46
45
|
resp = await self.httpx.get(full_url)
|
|
47
|
-
sel =
|
|
46
|
+
sel = HTMLHelper(resp.text)
|
|
48
47
|
|
|
49
48
|
results = []
|
|
50
|
-
for item in sel.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
title = h2_el.text(strip=True) if h2_el else None
|
|
56
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
57
|
-
poster = img_el.attrs.get("data-srcset") if img_el else None
|
|
49
|
+
for item in sel.select("div.poster-with-subject, div.dark-segment div.poster-md.poster"):
|
|
50
|
+
title = sel.select_text("h2", item)
|
|
51
|
+
href = sel.select_attr("a", "href", item)
|
|
52
|
+
poster = sel.select_attr("img", "data-srcset", item)
|
|
58
53
|
|
|
59
54
|
if poster:
|
|
60
55
|
poster = poster.split(",")[0].split(" ")[0]
|
|
@@ -76,13 +71,10 @@ class Sinefy(PluginBase):
|
|
|
76
71
|
|
|
77
72
|
try:
|
|
78
73
|
resp = await self.httpx.get(self.main_url)
|
|
79
|
-
sel =
|
|
80
|
-
|
|
81
|
-
cke_el = sel.css_first("input[name='cKey']")
|
|
82
|
-
cval_el = sel.css_first("input[name='cValue']")
|
|
74
|
+
sel = HTMLHelper(resp.text)
|
|
83
75
|
|
|
84
|
-
cke =
|
|
85
|
-
cval =
|
|
76
|
+
cke = sel.select_attr("input[name='cKey']", "value")
|
|
77
|
+
cval = sel.select_attr("input[name='cValue']", "value")
|
|
86
78
|
|
|
87
79
|
if cke and cval:
|
|
88
80
|
c_key = cke
|
|
@@ -145,79 +137,88 @@ class Sinefy(PluginBase):
|
|
|
145
137
|
|
|
146
138
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
147
139
|
resp = await self.httpx.get(url)
|
|
148
|
-
sel =
|
|
140
|
+
sel = HTMLHelper(resp.text)
|
|
149
141
|
|
|
150
|
-
|
|
151
|
-
title = title_el.text(strip=True) if title_el else None
|
|
142
|
+
title = sel.select_text("h1")
|
|
152
143
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
poster = None
|
|
144
|
+
poster_info = sel.select_attr("div.ui.items img", "data-srcset")
|
|
145
|
+
poster = None
|
|
156
146
|
if poster_info:
|
|
157
|
-
# take 1x
|
|
158
147
|
parts = str(poster_info).split(",")
|
|
159
148
|
for p in parts:
|
|
160
149
|
if "1x" in p:
|
|
161
150
|
poster = p.strip().split(" ")[0]
|
|
162
151
|
break
|
|
163
|
-
|
|
164
|
-
desc_el = sel.css_first("p#tv-series-desc")
|
|
165
|
-
description = desc_el.text(strip=True) if desc_el else None
|
|
166
152
|
|
|
167
|
-
|
|
153
|
+
description = sel.select_text("p#tv-series-desc")
|
|
168
154
|
|
|
169
|
-
|
|
170
|
-
rating = rating_el.text(strip=True) if rating_el else None
|
|
155
|
+
tags = [a.text(strip=True) for a in sel.select("div.item.categories a") if a.text(strip=True)]
|
|
171
156
|
|
|
172
|
-
|
|
157
|
+
rating = sel.select_text("span.color-imdb")
|
|
173
158
|
|
|
174
|
-
|
|
175
|
-
|
|
159
|
+
actors = [h5.text(strip=True) for h5 in sel.select("div.content h5") if h5.text(strip=True)]
|
|
160
|
+
|
|
161
|
+
year = sel.select_text("span.item.year")
|
|
162
|
+
if not year and title:
|
|
163
|
+
# Try to extract year from title like "Movie Name(2024)"
|
|
164
|
+
year_match = sel.regex_first(r"\((\d{4})\)", title)
|
|
165
|
+
if year_match:
|
|
166
|
+
year = year_match
|
|
176
167
|
|
|
177
168
|
episodes = []
|
|
178
|
-
|
|
169
|
+
episodes_box_list = sel.select("section.episodes-box")
|
|
179
170
|
|
|
180
|
-
if
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
for link in menu:
|
|
185
|
-
href = link.attrs.get("href")
|
|
186
|
-
if href:
|
|
187
|
-
season_links.append(self.fix_url(href))
|
|
171
|
+
if episodes_box_list:
|
|
172
|
+
episodes_box = episodes_box_list[0]
|
|
173
|
+
# Sezon menüsünden sezon linklerini al
|
|
174
|
+
season_menu = sel.select("div.ui.vertical.fluid.tabular.menu a.item", episodes_box)
|
|
188
175
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
176
|
+
# Sezon tab içeriklerini al
|
|
177
|
+
season_tabs = sel.select("div.ui.tab", episodes_box)
|
|
178
|
+
|
|
179
|
+
# Eğer birden fazla sezon varsa, her sezon tab'ından bölümleri çek
|
|
180
|
+
if season_tabs:
|
|
181
|
+
for idx, season_tab in enumerate(season_tabs):
|
|
182
|
+
# Sezon numarasını belirle
|
|
183
|
+
current_season_no = idx + 1
|
|
184
|
+
|
|
185
|
+
# Menüden sezon numarasını almaya çalış
|
|
186
|
+
if idx < len(season_menu):
|
|
187
|
+
menu_href = season_menu[idx].attrs.get("href", "")
|
|
188
|
+
match = sel.regex_first(r"sezon-(\d+)", menu_href)
|
|
189
|
+
if match:
|
|
190
|
+
current_season_no = int(match)
|
|
196
191
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if match:
|
|
200
|
-
current_season_no = int(match.group(1))
|
|
192
|
+
# Bu sezon tab'ından bölüm linklerini çek
|
|
193
|
+
ep_links = sel.select("a[href*='bolum']", season_tab)
|
|
201
194
|
|
|
195
|
+
seen_urls = set()
|
|
202
196
|
for ep_link in ep_links:
|
|
203
197
|
href = ep_link.attrs.get("href")
|
|
204
|
-
|
|
205
|
-
|
|
198
|
+
if not href or href in seen_urls:
|
|
199
|
+
continue
|
|
200
|
+
seen_urls.add(href)
|
|
201
|
+
|
|
202
|
+
# Bölüm numarasını URL'den çıkar
|
|
203
|
+
ep_no = 0
|
|
204
|
+
match_ep = sel.regex_first(r"bolum-(\d+)", href)
|
|
205
|
+
if match_ep:
|
|
206
|
+
ep_no = int(match_ep)
|
|
206
207
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
208
|
+
# Bölüm başlığını çıkar (önce title attribute, sonra text)
|
|
209
|
+
name = ep_link.attrs.get("title", "")
|
|
210
|
+
if not name:
|
|
211
|
+
name = sel.select_text("div.content div.header", ep_link)
|
|
212
|
+
if not name:
|
|
213
|
+
name = ep_link.text(strip=True)
|
|
214
|
+
|
|
215
|
+
if href and ep_no > 0:
|
|
213
216
|
episodes.append(Episode(
|
|
214
|
-
season
|
|
217
|
+
season = current_season_no,
|
|
215
218
|
episode = ep_no,
|
|
216
|
-
title
|
|
217
|
-
url
|
|
219
|
+
title = name.strip() if name else f"{ep_no}. Bölüm",
|
|
220
|
+
url = self.fix_url(href)
|
|
218
221
|
))
|
|
219
|
-
except Exception:
|
|
220
|
-
pass
|
|
221
222
|
|
|
222
223
|
if episodes:
|
|
223
224
|
return SeriesInfo(
|
|
@@ -245,10 +246,9 @@ class Sinefy(PluginBase):
|
|
|
245
246
|
|
|
246
247
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
247
248
|
resp = await self.httpx.get(url)
|
|
248
|
-
sel =
|
|
249
|
+
sel = HTMLHelper(resp.text)
|
|
249
250
|
|
|
250
|
-
|
|
251
|
-
iframe = iframe_el.attrs.get("src") if iframe_el else None
|
|
251
|
+
iframe = sel.select_attr("iframe", "src")
|
|
252
252
|
|
|
253
253
|
if not iframe:
|
|
254
254
|
return []
|
KekikStream/Plugins/SinemaCX.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
3
|
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, Subtitle, ExtractResult
|
|
4
|
-
from
|
|
5
|
-
import re
|
|
4
|
+
from KekikStream.Core.HTMLHelper import HTMLHelper
|
|
6
5
|
|
|
7
6
|
class SinemaCX(PluginBase):
|
|
8
7
|
name = "SinemaCX"
|
|
@@ -39,23 +38,16 @@ class SinemaCX(PluginBase):
|
|
|
39
38
|
|
|
40
39
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
41
40
|
istek = await self.httpx.get(url.replace("SAYFA", str(page)))
|
|
42
|
-
secici =
|
|
41
|
+
secici = HTMLHelper(istek.text)
|
|
43
42
|
|
|
44
43
|
results = []
|
|
45
|
-
for veri in secici.
|
|
46
|
-
|
|
47
|
-
if not span_el:
|
|
48
|
-
continue
|
|
49
|
-
|
|
50
|
-
title = span_el.text(strip=True)
|
|
44
|
+
for veri in secici.select("div.son div.frag-k, div.icerik div.frag-k"):
|
|
45
|
+
title = secici.select_text("div.yanac span", veri)
|
|
51
46
|
if not title:
|
|
52
47
|
continue
|
|
53
48
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
58
|
-
poster = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
|
|
49
|
+
href = secici.select_attr("div.yanac a", "href", veri)
|
|
50
|
+
poster = secici.select_attr("a.resim img", "data-src", veri) or secici.select_attr("a.resim img", "src", veri)
|
|
59
51
|
|
|
60
52
|
results.append(MainPageResult(
|
|
61
53
|
category = category,
|
|
@@ -68,23 +60,16 @@ class SinemaCX(PluginBase):
|
|
|
68
60
|
|
|
69
61
|
async def search(self, query: str) -> list[SearchResult]:
|
|
70
62
|
istek = await self.httpx.get(f"{self.main_url}/?s={query}")
|
|
71
|
-
secici =
|
|
63
|
+
secici = HTMLHelper(istek.text)
|
|
72
64
|
|
|
73
65
|
results = []
|
|
74
|
-
for veri in secici.
|
|
75
|
-
|
|
76
|
-
if not span_el:
|
|
77
|
-
continue
|
|
78
|
-
|
|
79
|
-
title = span_el.text(strip=True)
|
|
66
|
+
for veri in secici.select("div.icerik div.frag-k"):
|
|
67
|
+
title = secici.select_text("div.yanac span", veri)
|
|
80
68
|
if not title:
|
|
81
69
|
continue
|
|
82
70
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
87
|
-
poster = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
|
|
71
|
+
href = secici.select_attr("div.yanac a", "href", veri)
|
|
72
|
+
poster = secici.select_attr("a.resim img", "data-src", veri) or secici.select_attr("a.resim img", "src", veri)
|
|
88
73
|
|
|
89
74
|
results.append(SearchResult(
|
|
90
75
|
title = title,
|
|
@@ -96,29 +81,21 @@ class SinemaCX(PluginBase):
|
|
|
96
81
|
|
|
97
82
|
async def load_item(self, url: str) -> MovieInfo:
|
|
98
83
|
istek = await self.httpx.get(url)
|
|
99
|
-
secici =
|
|
84
|
+
secici = HTMLHelper(istek.text)
|
|
100
85
|
|
|
101
|
-
duration_match =
|
|
86
|
+
duration_match = secici.regex_first(r"Süre:.*?(\d+)\s*Dakika")
|
|
102
87
|
|
|
103
|
-
|
|
104
|
-
description = desc_el.text(strip=True) if desc_el else None
|
|
88
|
+
description = secici.select_text("div.ackl div.scroll-liste")
|
|
105
89
|
|
|
106
|
-
|
|
107
|
-
poster = link_el.attrs.get("href") if link_el else None
|
|
90
|
+
poster = secici.select_attr("link[rel='image_src']", "href")
|
|
108
91
|
|
|
109
|
-
|
|
110
|
-
title = title_el.text(strip=True) if title_el else None
|
|
92
|
+
title = secici.select_text("div.f-bilgi h1")
|
|
111
93
|
|
|
112
|
-
tags
|
|
94
|
+
tags = secici.select_all_text("div.f-bilgi div.tur a")
|
|
113
95
|
|
|
114
|
-
|
|
115
|
-
year = year_el.text(strip=True) if year_el else None
|
|
96
|
+
year = secici.select_text("div.f-bilgi ul.detay a[href*='yapim']")
|
|
116
97
|
|
|
117
|
-
actors
|
|
118
|
-
for li in secici.css("li.oync li.oyuncu-k"):
|
|
119
|
-
isim_el = li.css_first("span.isim")
|
|
120
|
-
if isim_el and isim_el.text(strip=True):
|
|
121
|
-
actors.append(isim_el.text(strip=True))
|
|
98
|
+
actors = secici.select_all_text("li.oync li.oyuncu-k span.isim")
|
|
122
99
|
|
|
123
100
|
return MovieInfo(
|
|
124
101
|
url = url,
|
|
@@ -128,14 +105,14 @@ class SinemaCX(PluginBase):
|
|
|
128
105
|
tags = tags,
|
|
129
106
|
year = year,
|
|
130
107
|
actors = actors,
|
|
131
|
-
duration = int(duration_match
|
|
108
|
+
duration = int(duration_match) if duration_match else None,
|
|
132
109
|
)
|
|
133
110
|
|
|
134
111
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
135
112
|
istek = await self.httpx.get(url)
|
|
136
|
-
secici =
|
|
113
|
+
secici = HTMLHelper(istek.text)
|
|
137
114
|
|
|
138
|
-
iframe_list =
|
|
115
|
+
iframe_list = secici.select_all_attr("iframe", "data-vsrc")
|
|
139
116
|
|
|
140
117
|
# Sadece fragman varsa /2/ sayfasından dene
|
|
141
118
|
has_only_trailer = all(
|
|
@@ -146,8 +123,9 @@ class SinemaCX(PluginBase):
|
|
|
146
123
|
if has_only_trailer:
|
|
147
124
|
alt_url = url.rstrip("/") + "/2/"
|
|
148
125
|
alt_istek = await self.httpx.get(alt_url)
|
|
149
|
-
|
|
150
|
-
|
|
126
|
+
alt_istek = await self.httpx.get(alt_url)
|
|
127
|
+
alt_sec = HTMLHelper(alt_istek.text)
|
|
128
|
+
iframe_list = alt_sec.select_all_attr("iframe", "data-vsrc")
|
|
151
129
|
|
|
152
130
|
if not iframe_list:
|
|
153
131
|
return []
|
|
@@ -164,17 +142,15 @@ class SinemaCX(PluginBase):
|
|
|
164
142
|
iframe_text = iframe_istek.text
|
|
165
143
|
|
|
166
144
|
subtitles = []
|
|
167
|
-
|
|
168
|
-
if
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
subtitles.append(Subtitle(name=sub[1], url=self.fix_url(sub[2])))
|
|
145
|
+
sub_section = HTMLHelper(iframe_text).regex_first(r'playerjsSubtitle\s*=\s*"(.+?)"')
|
|
146
|
+
if sub_section:
|
|
147
|
+
for lang, link in HTMLHelper(sub_section).regex_all(r'\[(.*?)](https?://[^\s\",]+)'):
|
|
148
|
+
subtitles.append(Subtitle(name=lang, url=self.fix_url(link)))
|
|
172
149
|
|
|
173
150
|
# player.filmizle.in kontrolü
|
|
174
151
|
if "player.filmizle.in" in iframe.lower():
|
|
175
|
-
|
|
176
|
-
if
|
|
177
|
-
base_url = base_match[1]
|
|
152
|
+
base_url = HTMLHelper(iframe).regex_first(r"https?://([^/]+)")
|
|
153
|
+
if base_url:
|
|
178
154
|
vid_id = iframe.split("/")[-1]
|
|
179
155
|
|
|
180
156
|
self.httpx.headers.update({"X-Requested-With": "XMLHttpRequest"})
|