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
|
@@ -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 JetFilmizle(PluginBase):
|
|
8
6
|
name = "JetFilmizle"
|
|
@@ -40,23 +38,21 @@ class JetFilmizle(PluginBase):
|
|
|
40
38
|
|
|
41
39
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
42
40
|
istek = await self.httpx.get(f"{url}{page}", follow_redirects=True)
|
|
43
|
-
secici =
|
|
41
|
+
secici = HTMLHelper(istek.text)
|
|
44
42
|
|
|
45
43
|
results = []
|
|
46
|
-
for veri in secici.
|
|
44
|
+
for veri in secici.select("article.movie"):
|
|
47
45
|
# h2-h6 içindeki a linki
|
|
48
|
-
|
|
46
|
+
title_text = None
|
|
49
47
|
for h_tag in ["h2", "h3", "h4", "h5", "h6"]:
|
|
50
|
-
|
|
51
|
-
if
|
|
48
|
+
title_text = secici.select_text(f"{h_tag} a", veri)
|
|
49
|
+
if title_text:
|
|
52
50
|
break
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
href = secici.select_attr("a", "href", veri)
|
|
53
|
+
poster = secici.select_poster("img", veri)
|
|
56
54
|
|
|
57
|
-
title = self.clean_title(
|
|
58
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
59
|
-
poster = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
|
|
55
|
+
title = self.clean_title(title_text) if title_text else None
|
|
60
56
|
|
|
61
57
|
if title and href:
|
|
62
58
|
results.append(MainPageResult(
|
|
@@ -74,23 +70,21 @@ class JetFilmizle(PluginBase):
|
|
|
74
70
|
data = {"s": query},
|
|
75
71
|
headers = {"Referer": f"{self.main_url}/"}
|
|
76
72
|
)
|
|
77
|
-
secici =
|
|
73
|
+
secici = HTMLHelper(istek.text)
|
|
78
74
|
|
|
79
75
|
results = []
|
|
80
|
-
for article in secici.
|
|
76
|
+
for article in secici.select("article.movie"):
|
|
81
77
|
# h2-h6 içindeki a linki
|
|
82
|
-
|
|
78
|
+
title_text = None
|
|
83
79
|
for h_tag in ["h2", "h3", "h4", "h5", "h6"]:
|
|
84
|
-
|
|
85
|
-
if
|
|
80
|
+
title_text = secici.select_text(f"{h_tag} a", article)
|
|
81
|
+
if title_text:
|
|
86
82
|
break
|
|
87
83
|
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
href = secici.select_attr("a", "href", article)
|
|
85
|
+
poster = secici.select_poster("img", article)
|
|
90
86
|
|
|
91
|
-
title = self.clean_title(
|
|
92
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
93
|
-
poster = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
|
|
87
|
+
title = self.clean_title(title_text) if title_text else None
|
|
94
88
|
|
|
95
89
|
if title and href:
|
|
96
90
|
results.append(SearchResult(
|
|
@@ -103,33 +97,22 @@ class JetFilmizle(PluginBase):
|
|
|
103
97
|
|
|
104
98
|
async def load_item(self, url: str) -> MovieInfo:
|
|
105
99
|
istek = await self.httpx.get(url)
|
|
106
|
-
secici =
|
|
107
|
-
html_text = istek.text
|
|
100
|
+
secici = HTMLHelper(istek.text)
|
|
108
101
|
|
|
109
|
-
|
|
110
|
-
title = self.clean_title(title_el.text(strip=True)) if title_el else None
|
|
102
|
+
title = self.clean_title(secici.select_text("div.movie-exp-title")) if secici.select_text("div.movie-exp-title") else None
|
|
111
103
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
poster = poster_raw.strip() if poster_raw else None
|
|
104
|
+
poster = secici.select_poster("section.movie-exp img")
|
|
105
|
+
poster = poster.strip() if poster else None
|
|
115
106
|
|
|
116
|
-
|
|
117
|
-
description = desc_el.text(strip=True) if desc_el else None
|
|
107
|
+
description = secici.select_text("section.movie-exp p.aciklama")
|
|
118
108
|
|
|
119
|
-
tags =
|
|
109
|
+
tags = secici.select_all_text("section.movie-exp div.catss a")
|
|
120
110
|
|
|
121
|
-
|
|
122
|
-
rating = rating_el.text(strip=True) if rating_el else None
|
|
111
|
+
rating = secici.select_text("section.movie-exp div.imdb_puan span")
|
|
123
112
|
|
|
124
|
-
|
|
125
|
-
year = None
|
|
126
|
-
yap_match = re.search(r'<div class="yap"[^>]*>([^<]*(?:Vizyon|Yapım)[^<]*)</div>', html_text, re.IGNORECASE)
|
|
127
|
-
if yap_match:
|
|
128
|
-
year_match = re.search(r'(\d{4})', yap_match.group(1))
|
|
129
|
-
if year_match:
|
|
130
|
-
year = year_match.group(1)
|
|
113
|
+
year = secici.extract_year("div.yap")
|
|
131
114
|
|
|
132
|
-
actors =
|
|
115
|
+
actors = secici.select_all_text("div[itemprop='actor'] a span")
|
|
133
116
|
|
|
134
117
|
return MovieInfo(
|
|
135
118
|
url = url,
|
|
@@ -144,12 +127,12 @@ class JetFilmizle(PluginBase):
|
|
|
144
127
|
|
|
145
128
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
146
129
|
istek = await self.httpx.get(url)
|
|
147
|
-
secici =
|
|
130
|
+
secici = HTMLHelper(istek.text)
|
|
148
131
|
|
|
149
132
|
results = []
|
|
150
133
|
|
|
151
134
|
# 1) Ana iframe'leri kontrol et
|
|
152
|
-
for iframe in secici.
|
|
135
|
+
for iframe in secici.select("iframe"):
|
|
153
136
|
src = (iframe.attrs.get("src") or
|
|
154
137
|
iframe.attrs.get("data-src") or
|
|
155
138
|
iframe.attrs.get("data-lazy-src"))
|
|
@@ -162,9 +145,8 @@ class JetFilmizle(PluginBase):
|
|
|
162
145
|
|
|
163
146
|
# 2) Sayfa numaralarından linkleri topla (Fragman hariç)
|
|
164
147
|
page_links = []
|
|
165
|
-
for link in secici.
|
|
166
|
-
|
|
167
|
-
isim = span_el.text(strip=True) if span_el else ""
|
|
148
|
+
for link in secici.select("a.post-page-numbers"):
|
|
149
|
+
isim = secici.select_text("span", link) or ""
|
|
168
150
|
if isim != "Fragman":
|
|
169
151
|
href = link.attrs.get("href")
|
|
170
152
|
if href:
|
|
@@ -174,9 +156,9 @@ class JetFilmizle(PluginBase):
|
|
|
174
156
|
for page_url, isim in page_links:
|
|
175
157
|
try:
|
|
176
158
|
page_resp = await self.httpx.get(page_url)
|
|
177
|
-
page_sel =
|
|
159
|
+
page_sel = HTMLHelper(page_resp.text)
|
|
178
160
|
|
|
179
|
-
for iframe in page_sel.
|
|
161
|
+
for iframe in page_sel.select("div#movie iframe"):
|
|
180
162
|
src = (iframe.attrs.get("src") or
|
|
181
163
|
iframe.attrs.get("data-src") or
|
|
182
164
|
iframe.attrs.get("data-lazy-src"))
|
|
@@ -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, MovieInfo, SeriesInfo, Episode, ExtractResult, Subtitle
|
|
4
|
-
|
|
5
|
-
import re, base64
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult, Subtitle, HTMLHelper
|
|
4
|
+
import base64
|
|
6
5
|
|
|
7
6
|
class KultFilmler(PluginBase):
|
|
8
7
|
name = "KultFilmler"
|
|
@@ -38,16 +37,13 @@ class KultFilmler(PluginBase):
|
|
|
38
37
|
|
|
39
38
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
40
39
|
istek = await self.httpx.get(url)
|
|
41
|
-
secici =
|
|
40
|
+
secici = HTMLHelper(istek.text)
|
|
42
41
|
|
|
43
42
|
results = []
|
|
44
|
-
for veri in secici.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
title = img_el.attrs.get("alt") if img_el else None
|
|
49
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
50
|
-
poster = img_el.attrs.get("src") if img_el else None
|
|
43
|
+
for veri in secici.select("div.col-md-12 div.movie-box"):
|
|
44
|
+
title = secici.select_attr("div.img img", "alt", veri)
|
|
45
|
+
href = secici.select_attr("a", "href", veri)
|
|
46
|
+
poster = secici.select_attr("div.img img", "src", veri)
|
|
51
47
|
|
|
52
48
|
if title and href:
|
|
53
49
|
results.append(MainPageResult(
|
|
@@ -61,16 +57,13 @@ class KultFilmler(PluginBase):
|
|
|
61
57
|
|
|
62
58
|
async def search(self, query: str) -> list[SearchResult]:
|
|
63
59
|
istek = await self.httpx.get(f"{self.main_url}?s={query}")
|
|
64
|
-
secici =
|
|
60
|
+
secici = HTMLHelper(istek.text)
|
|
65
61
|
|
|
66
62
|
results = []
|
|
67
|
-
for veri in secici.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
title = img_el.attrs.get("alt") if img_el else None
|
|
72
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
73
|
-
poster = img_el.attrs.get("src") if img_el else None
|
|
63
|
+
for veri in secici.select("div.movie-box"):
|
|
64
|
+
title = secici.select_attr("div.img img", "alt", veri)
|
|
65
|
+
href = secici.select_attr("a", "href", veri)
|
|
66
|
+
poster = secici.select_attr("div.img img", "src", veri)
|
|
74
67
|
|
|
75
68
|
if title and href:
|
|
76
69
|
results.append(SearchResult(
|
|
@@ -83,58 +76,43 @@ class KultFilmler(PluginBase):
|
|
|
83
76
|
|
|
84
77
|
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
85
78
|
istek = await self.httpx.get(url)
|
|
86
|
-
secici =
|
|
87
|
-
|
|
88
|
-
film_img = secici.css_first("div.film-bilgileri img")
|
|
89
|
-
og_title = secici.css_first("[property='og:title']")
|
|
90
|
-
og_image = secici.css_first("[property='og:image']")
|
|
79
|
+
secici = HTMLHelper(istek.text)
|
|
91
80
|
|
|
92
|
-
title =
|
|
93
|
-
poster = self.fix_url(
|
|
81
|
+
title = secici.select_attr("div.film-bilgileri img", "alt") or secici.select_attr("[property='og:title']", "content")
|
|
82
|
+
poster = self.fix_url(secici.select_attr("[property='og:image']", "content")) if secici.select_attr("[property='og:image']", "content") else None
|
|
94
83
|
|
|
95
|
-
|
|
96
|
-
description = desc_el.text(strip=True) if desc_el else None
|
|
84
|
+
description = secici.select_text("div.description")
|
|
97
85
|
|
|
98
|
-
tags = [a.text(strip=True) for a in secici.
|
|
86
|
+
tags = [a.text(strip=True) for a in secici.select("ul.post-categories a") if a.text(strip=True)]
|
|
99
87
|
|
|
100
88
|
# HTML analizine göre güncellenen alanlar
|
|
101
|
-
|
|
102
|
-
year = year_el.text(strip=True) if year_el else None
|
|
89
|
+
year = secici.select_text("li.release span a")
|
|
103
90
|
|
|
104
|
-
|
|
105
|
-
duration = None
|
|
106
|
-
if time_el:
|
|
107
|
-
time_text = time_el.text(strip=True)
|
|
108
|
-
dur_match = re.search(r"(\d+)", time_text)
|
|
109
|
-
duration = dur_match.group(1) if dur_match else None
|
|
91
|
+
time_text = secici.select_text("li.time span")
|
|
92
|
+
duration = secici.regex_first(r"(\d+)", time_text) if time_text else None
|
|
110
93
|
|
|
111
|
-
|
|
112
|
-
rating = rating_el.text(strip=True) if rating_el else None
|
|
94
|
+
rating = secici.select_text("div.imdb-count")
|
|
113
95
|
|
|
114
|
-
actors = [a.text(strip=True) for a in secici.
|
|
96
|
+
actors = [a.text(strip=True) for a in secici.select("div.actors a") if a.text(strip=True)]
|
|
115
97
|
|
|
116
98
|
# Dizi mi kontrol et
|
|
117
99
|
if "/dizi/" in url:
|
|
118
100
|
episodes = []
|
|
119
|
-
for bolum in secici.
|
|
120
|
-
|
|
121
|
-
ep_href = name_link.attrs.get("href") if name_link else None
|
|
101
|
+
for bolum in secici.select("div.episode-box"):
|
|
102
|
+
ep_href = secici.select_attr("div.name a", "href", bolum)
|
|
122
103
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
ep_b_el = bolum.css_first("span.episodetitle b")
|
|
127
|
-
ep_detail = ep_b_el.text(strip=True) if ep_b_el else ""
|
|
104
|
+
ssn_detail = secici.select_text("span.episodetitle", bolum) or ""
|
|
105
|
+
ep_detail = secici.select_text("span.episodetitle b", bolum) or ""
|
|
128
106
|
|
|
129
107
|
ep_name = f"{ssn_detail} - {ep_detail}"
|
|
130
108
|
|
|
131
109
|
if ep_href:
|
|
132
|
-
ep_season =
|
|
133
|
-
ep_episode =
|
|
110
|
+
ep_season = secici.regex_first(r"(\d+)\.", ssn_detail)
|
|
111
|
+
ep_episode = secici.regex_first(r"(\d+)\.", ep_detail)
|
|
134
112
|
|
|
135
113
|
episodes.append(Episode(
|
|
136
|
-
season = int(ep_season
|
|
137
|
-
episode = int(ep_episode
|
|
114
|
+
season = int(ep_season) if ep_season else 1,
|
|
115
|
+
episode = int(ep_episode) if ep_episode else 1,
|
|
138
116
|
title = ep_name.strip(" -"),
|
|
139
117
|
url = self.fix_url(ep_href),
|
|
140
118
|
))
|
|
@@ -165,12 +143,10 @@ class KultFilmler(PluginBase):
|
|
|
165
143
|
|
|
166
144
|
def _get_iframe(self, source_code: str) -> str:
|
|
167
145
|
"""Base64 kodlu iframe'i çözümle"""
|
|
168
|
-
|
|
169
|
-
if not
|
|
146
|
+
atob = HTMLHelper(source_code).regex_first(r"PHA\+[0-9a-zA-Z+/=]*")
|
|
147
|
+
if not atob:
|
|
170
148
|
return ""
|
|
171
149
|
|
|
172
|
-
atob = atob_match.group()
|
|
173
|
-
|
|
174
150
|
# Padding düzelt
|
|
175
151
|
padding = 4 - len(atob) % 4
|
|
176
152
|
if padding < 4:
|
|
@@ -178,20 +154,19 @@ class KultFilmler(PluginBase):
|
|
|
178
154
|
|
|
179
155
|
try:
|
|
180
156
|
decoded = base64.b64decode(atob).decode("utf-8")
|
|
181
|
-
secici =
|
|
182
|
-
|
|
183
|
-
return self.fix_url(
|
|
157
|
+
secici = HTMLHelper(decoded)
|
|
158
|
+
iframe_src = secici.select_attr("iframe", "src")
|
|
159
|
+
return self.fix_url(iframe_src) if iframe_src else ""
|
|
184
160
|
except Exception:
|
|
185
161
|
return ""
|
|
186
162
|
|
|
187
163
|
def _extract_subtitle_url(self, source_code: str) -> str | None:
|
|
188
164
|
"""Altyazı URL'sini çıkar"""
|
|
189
|
-
|
|
190
|
-
return match[1] if match else None
|
|
165
|
+
return HTMLHelper(source_code).regex_first(r"(https?://[^\s\"]+\.srt)")
|
|
191
166
|
|
|
192
167
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
193
168
|
istek = await self.httpx.get(url)
|
|
194
|
-
secici =
|
|
169
|
+
secici = HTMLHelper(istek.text)
|
|
195
170
|
|
|
196
171
|
iframes = set()
|
|
197
172
|
|
|
@@ -201,9 +176,9 @@ class KultFilmler(PluginBase):
|
|
|
201
176
|
iframes.add(main_frame)
|
|
202
177
|
|
|
203
178
|
# Alternatif player'lar
|
|
204
|
-
for player in secici.
|
|
205
|
-
|
|
206
|
-
alt_iframe = self.fix_url(
|
|
179
|
+
for player in secici.select("div.container#player"):
|
|
180
|
+
iframe_src = secici.select_attr("iframe", "src", player)
|
|
181
|
+
alt_iframe = self.fix_url(iframe_src) if iframe_src else None
|
|
207
182
|
if alt_iframe:
|
|
208
183
|
alt_istek = await self.httpx.get(alt_iframe)
|
|
209
184
|
alt_frame = self._get_iframe(alt_istek.text)
|
|
@@ -222,12 +197,12 @@ class KultFilmler(PluginBase):
|
|
|
222
197
|
"Sec-Fetch-Dest" : "iframe"
|
|
223
198
|
}
|
|
224
199
|
iframe_istek = await self.httpx.get(iframe, headers=headers)
|
|
225
|
-
m3u_match =
|
|
200
|
+
m3u_match = HTMLHelper(iframe_istek.text).regex_first(r'file:"([^"]+)"')
|
|
226
201
|
|
|
227
202
|
if m3u_match:
|
|
228
203
|
results.append(ExtractResult(
|
|
229
204
|
name = "VidMoly",
|
|
230
|
-
url = m3u_match
|
|
205
|
+
url = m3u_match,
|
|
231
206
|
referer = self.main_url,
|
|
232
207
|
subtitles = []
|
|
233
208
|
))
|
KekikStream/Plugins/RecTV.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, MovieInfo, Episode, SeriesInfo, ExtractResult
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, Episode, SeriesInfo, ExtractResult, HTMLHelper
|
|
4
4
|
from json import dumps, loads
|
|
5
|
-
import re
|
|
6
5
|
|
|
7
6
|
class RecTV(PluginBase):
|
|
8
7
|
name = "RecTV"
|
|
@@ -84,9 +83,13 @@ class RecTV(PluginBase):
|
|
|
84
83
|
"is_episode" : True
|
|
85
84
|
}
|
|
86
85
|
|
|
86
|
+
# Extract season/episode numbers using helper
|
|
87
|
+
s1, _ = HTMLHelper.extract_season_episode(season.get("title") or "")
|
|
88
|
+
_, e2 = HTMLHelper.extract_season_episode(episode.get("title") or "")
|
|
89
|
+
|
|
87
90
|
ep_model = Episode(
|
|
88
|
-
season =
|
|
89
|
-
episode =
|
|
91
|
+
season = s1 or 1,
|
|
92
|
+
episode = e2 or 1,
|
|
90
93
|
title = episode.get("title"),
|
|
91
94
|
url = dumps(ep_data),
|
|
92
95
|
)
|
KekikStream/Plugins/RoketDizi.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, ExtractResult, MovieInfo
|
|
4
|
-
|
|
5
|
-
import re, base64, json
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, MovieInfo, HTMLHelper
|
|
4
|
+
import base64, json
|
|
6
5
|
|
|
7
6
|
class RoketDizi(PluginBase):
|
|
8
7
|
name = "RoketDizi"
|
|
@@ -24,19 +23,15 @@ class RoketDizi(PluginBase):
|
|
|
24
23
|
|
|
25
24
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
26
25
|
istek = await self.httpx.get(f"{url}?&page={page}")
|
|
27
|
-
secici =
|
|
26
|
+
secici = HTMLHelper(istek.text)
|
|
28
27
|
|
|
29
28
|
results = []
|
|
30
29
|
|
|
31
30
|
# Use div.new-added-list to find the container, then get items
|
|
32
|
-
for item in secici.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
title = title_el.text(strip=True) if title_el else None
|
|
38
|
-
href = link_el.attrs.get("href") if link_el else None
|
|
39
|
-
poster = img_el.attrs.get("src") if img_el else None
|
|
31
|
+
for item in secici.select("div.new-added-list > span"):
|
|
32
|
+
title = secici.select_text("span.line-clamp-1", item)
|
|
33
|
+
href = secici.select_attr("a", "href", item)
|
|
34
|
+
poster = secici.select_attr("img", "src", item)
|
|
40
35
|
|
|
41
36
|
if title and href:
|
|
42
37
|
results.append(MainPageResult(
|
|
@@ -92,58 +87,49 @@ class RoketDizi(PluginBase):
|
|
|
92
87
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
93
88
|
# Note: Handling both Movie and Series logic in one, returning SeriesInfo generally or MovieInfo
|
|
94
89
|
resp = await self.httpx.get(url)
|
|
95
|
-
sel =
|
|
90
|
+
sel = HTMLHelper(resp.text)
|
|
96
91
|
html_text = resp.text
|
|
97
92
|
|
|
98
|
-
|
|
99
|
-
title = title_el.text(strip=True) if title_el else None
|
|
93
|
+
title = sel.select_text("h1.text-white")
|
|
100
94
|
|
|
101
|
-
|
|
102
|
-
poster = poster_el.attrs.get("src") if poster_el else None
|
|
95
|
+
poster = sel.select_attr("div.w-full.page-top img", "src")
|
|
103
96
|
|
|
104
|
-
|
|
105
|
-
description = desc_el.text(strip=True) if desc_el else None
|
|
97
|
+
description = sel.select_text("div.mt-2.text-sm")
|
|
106
98
|
|
|
107
99
|
# Tags - genre bilgileri (Detaylar bölümünde)
|
|
108
100
|
tags = []
|
|
109
|
-
|
|
110
|
-
if
|
|
111
|
-
|
|
112
|
-
if genre_text:
|
|
113
|
-
tags = [t.strip() for t in genre_text.split(",")]
|
|
101
|
+
genre_text = sel.select_text("h3.text-white.opacity-90")
|
|
102
|
+
if genre_text:
|
|
103
|
+
tags = [t.strip() for t in genre_text.split(",")]
|
|
114
104
|
|
|
115
105
|
# Rating
|
|
116
|
-
|
|
117
|
-
rating = rating_el.text(strip=True) if rating_el else None
|
|
106
|
+
rating = sel.select_text("span.text-white.text-sm.font-bold")
|
|
118
107
|
|
|
119
108
|
# Year ve Actors - Detaylar (Details) bölümünden
|
|
120
109
|
year = None
|
|
121
110
|
actors = []
|
|
122
111
|
|
|
123
112
|
# Detaylar bölümündeki tüm flex-col div'leri al
|
|
124
|
-
detail_items = sel.
|
|
113
|
+
detail_items = sel.select("div.flex.flex-col")
|
|
125
114
|
for item in detail_items:
|
|
126
|
-
|
|
127
|
-
|
|
115
|
+
label = sel.select_text("span.text-base", item)
|
|
116
|
+
value = sel.select_text("span.text-sm.opacity-90", item)
|
|
128
117
|
|
|
129
|
-
label =
|
|
130
|
-
value =
|
|
118
|
+
label = label if label else None
|
|
119
|
+
value = value if value else None
|
|
131
120
|
|
|
132
121
|
if label and value:
|
|
133
122
|
# Yayın tarihi (yıl)
|
|
134
123
|
if label == "Yayın tarihi":
|
|
135
124
|
# "16 Ekim 2018" formatından yılı çıkar
|
|
136
|
-
|
|
137
|
-
if year_match:
|
|
138
|
-
year = year_match.group()
|
|
139
|
-
|
|
125
|
+
year = HTMLHelper(value).regex_first(r'\d{4}')
|
|
140
126
|
# Yaratıcılar veya Oyuncular
|
|
141
127
|
elif label in ["Yaratıcılar", "Oyuncular"]:
|
|
142
128
|
if value:
|
|
143
129
|
actors.append(value)
|
|
144
130
|
|
|
145
131
|
# Check urls for episodes
|
|
146
|
-
all_urls =
|
|
132
|
+
all_urls = HTMLHelper(html_text).regex_all(r'"url":"([^"]*)"')
|
|
147
133
|
is_series = any("bolum-" in u for u in all_urls)
|
|
148
134
|
|
|
149
135
|
episodes = []
|
|
@@ -152,11 +138,11 @@ class RoketDizi(PluginBase):
|
|
|
152
138
|
episodes_dict = {}
|
|
153
139
|
for u in all_urls:
|
|
154
140
|
if "bolum" in u and u not in episodes_dict:
|
|
155
|
-
|
|
156
|
-
|
|
141
|
+
season = HTMLHelper(u).regex_first(r'/sezon-(\d+)')
|
|
142
|
+
ep_num = HTMLHelper(u).regex_first(r'/bolum-(\d+)')
|
|
157
143
|
|
|
158
|
-
season = int(
|
|
159
|
-
episode_num = int(
|
|
144
|
+
season = int(season) if season else 1
|
|
145
|
+
episode_num = int(ep_num) if ep_num else 1
|
|
160
146
|
|
|
161
147
|
# Key olarak (season, episode) tuple kullan
|
|
162
148
|
key = (season, episode_num)
|
|
@@ -184,13 +170,9 @@ class RoketDizi(PluginBase):
|
|
|
184
170
|
|
|
185
171
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
186
172
|
resp = await self.httpx.get(url)
|
|
187
|
-
sel =
|
|
173
|
+
sel = HTMLHelper(resp.text)
|
|
188
174
|
|
|
189
|
-
|
|
190
|
-
if not next_data_el:
|
|
191
|
-
return []
|
|
192
|
-
|
|
193
|
-
next_data = next_data_el.text(strip=True)
|
|
175
|
+
next_data = sel.select_text("script#__NEXT_DATA__")
|
|
194
176
|
if not next_data:
|
|
195
177
|
return []
|
|
196
178
|
|
|
@@ -208,11 +190,9 @@ class RoketDizi(PluginBase):
|
|
|
208
190
|
source_content = source.get("source_content", "")
|
|
209
191
|
|
|
210
192
|
# iframe URL'ini source_content'ten çıkar
|
|
211
|
-
|
|
212
|
-
if not
|
|
193
|
+
iframe_url = HTMLHelper(source_content).regex_first(r'<iframe[^>]*src=["\']([^"\']*)["\']')
|
|
194
|
+
if not iframe_url:
|
|
213
195
|
continue
|
|
214
|
-
|
|
215
|
-
iframe_url = iframe_match.group(1)
|
|
216
196
|
|
|
217
197
|
# Fix URL protocol
|
|
218
198
|
if not iframe_url.startswith("http"):
|
|
@@ -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, MovieInfo, SeriesInfo, Episode, ExtractResult
|
|
4
|
-
|
|
5
|
-
import re, base64, json, urllib.parse
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult, HTMLHelper
|
|
4
|
+
import base64, json, urllib.parse
|
|
6
5
|
|
|
7
6
|
class SelcukFlix(PluginBase):
|
|
8
7
|
name = "SelcukFlix"
|
|
@@ -34,17 +33,13 @@ class SelcukFlix(PluginBase):
|
|
|
34
33
|
if "tum-bolumler" in url:
|
|
35
34
|
try:
|
|
36
35
|
resp = await self.httpx.get(url)
|
|
37
|
-
sel =
|
|
36
|
+
sel = HTMLHelper(resp.text)
|
|
38
37
|
|
|
39
|
-
for item in sel.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
name = name_el.text(strip=True) if name_el else None
|
|
45
|
-
ep_info = ep_el.text(strip=True) if ep_el else None
|
|
46
|
-
href = item.attrs.get("href")
|
|
47
|
-
poster = img_el.attrs.get("src") if img_el else None
|
|
38
|
+
for item in sel.select("div.col-span-3 a"):
|
|
39
|
+
name = sel.select_text("h2", item)
|
|
40
|
+
ep_info = sel.select_text("div.opacity-80", item)
|
|
41
|
+
href = sel.select_attr("a", "href", item)
|
|
42
|
+
poster = sel.select_attr("div.image img", "src", item)
|
|
48
43
|
|
|
49
44
|
if name and href:
|
|
50
45
|
title = f"{name} - {ep_info}" if ep_info else name
|
|
@@ -188,14 +183,10 @@ class SelcukFlix(PluginBase):
|
|
|
188
183
|
|
|
189
184
|
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
190
185
|
resp = await self.httpx.get(url)
|
|
191
|
-
sel =
|
|
192
|
-
|
|
193
|
-
next_data_el = sel.css_first("script#__NEXT_DATA__")
|
|
194
|
-
if not next_data_el:
|
|
195
|
-
return None
|
|
186
|
+
sel = HTMLHelper(resp.text)
|
|
196
187
|
|
|
197
|
-
next_data =
|
|
198
|
-
if not next_data:
|
|
188
|
+
next_data = sel.select_text("script#__NEXT_DATA__")
|
|
189
|
+
if not next_data:
|
|
199
190
|
return None
|
|
200
191
|
|
|
201
192
|
data = json.loads(next_data)
|
|
@@ -266,13 +257,9 @@ class SelcukFlix(PluginBase):
|
|
|
266
257
|
|
|
267
258
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
268
259
|
resp = await self.httpx.get(url)
|
|
269
|
-
sel =
|
|
260
|
+
sel = HTMLHelper(resp.text)
|
|
270
261
|
|
|
271
|
-
|
|
272
|
-
if not next_data_el:
|
|
273
|
-
return []
|
|
274
|
-
|
|
275
|
-
next_data = next_data_el.text(strip=True)
|
|
262
|
+
next_data = sel.select_text("script#__NEXT_DATA__")
|
|
276
263
|
if not next_data:
|
|
277
264
|
return []
|
|
278
265
|
|
|
@@ -312,9 +299,8 @@ class SelcukFlix(PluginBase):
|
|
|
312
299
|
source_content = res[0].get("source_content") or res[0].get("sourceContent")
|
|
313
300
|
|
|
314
301
|
if source_content:
|
|
315
|
-
iframe_sel =
|
|
316
|
-
|
|
317
|
-
iframe_src = iframe_el.attrs.get("src") if iframe_el else None
|
|
302
|
+
iframe_sel = HTMLHelper(source_content)
|
|
303
|
+
iframe_src = iframe_sel.select_attr("iframe", "src")
|
|
318
304
|
if iframe_src:
|
|
319
305
|
iframe_src = self.fix_url(iframe_src)
|
|
320
306
|
# Hotlinger domain değişimi (Kotlin referansı)
|