KekikStream 2.4.5__py3-none-any.whl → 2.4.7__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 +20 -43
- KekikStream/Core/Plugin/PluginBase.py +15 -4
- KekikStream/Extractors/Odnoklassniki.py +14 -2
- KekikStream/Extractors/VidMoly.py +2 -2
- KekikStream/Extractors/YTDLP.py +2 -2
- KekikStream/Plugins/BelgeselX.py +44 -17
- KekikStream/Plugins/DiziBox.py +11 -8
- KekikStream/Plugins/DiziMom.py +72 -54
- KekikStream/Plugins/DiziPal.py +37 -23
- KekikStream/Plugins/DiziYou.py +23 -11
- KekikStream/Plugins/Dizilla.py +35 -30
- KekikStream/Plugins/FilmBip.py +90 -18
- KekikStream/Plugins/FilmEkseni.py +78 -40
- KekikStream/Plugins/FilmMakinesi.py +29 -14
- KekikStream/Plugins/FilmModu.py +17 -19
- KekikStream/Plugins/Filmatek.py +103 -91
- KekikStream/Plugins/Full4kizle.py +6 -6
- KekikStream/Plugins/FullHDFilm.py +6 -6
- KekikStream/Plugins/FullHDFilmizlesene.py +6 -7
- KekikStream/Plugins/HDFilmCehennemi.py +3 -3
- KekikStream/Plugins/JetFilmizle.py +5 -5
- KekikStream/Plugins/KultFilmler.py +6 -6
- KekikStream/Plugins/RoketDizi.py +5 -5
- KekikStream/Plugins/SelcukFlix.py +2 -2
- KekikStream/Plugins/SetFilmIzle.py +5 -5
- KekikStream/Plugins/SezonlukDizi.py +4 -4
- KekikStream/Plugins/Sinefy.py +5 -5
- KekikStream/Plugins/SinemaCX.py +6 -6
- KekikStream/Plugins/Sinezy.py +5 -5
- KekikStream/Plugins/SuperFilmGeldi.py +5 -5
- KekikStream/Plugins/UgurFilm.py +4 -4
- KekikStream/Plugins/YabanciDizi.py +5 -5
- {kekikstream-2.4.5.dist-info → kekikstream-2.4.7.dist-info}/METADATA +1 -1
- {kekikstream-2.4.5.dist-info → kekikstream-2.4.7.dist-info}/RECORD +38 -38
- {kekikstream-2.4.5.dist-info → kekikstream-2.4.7.dist-info}/WHEEL +0 -0
- {kekikstream-2.4.5.dist-info → kekikstream-2.4.7.dist-info}/entry_points.txt +0 -0
- {kekikstream-2.4.5.dist-info → kekikstream-2.4.7.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-2.4.5.dist-info → kekikstream-2.4.7.dist-info}/top_level.txt +0 -0
KekikStream/Core/HTMLHelper.py
CHANGED
|
@@ -33,22 +33,22 @@ class HTMLHelper:
|
|
|
33
33
|
return element
|
|
34
34
|
return self._root(element).css_first(selector)
|
|
35
35
|
|
|
36
|
-
def select_text(self, selector: str | None = None, element: Node | None = None
|
|
36
|
+
def select_text(self, selector: str | None = None, element: Node | None = None) -> str | None:
|
|
37
37
|
"""CSS selector ile element bul ve text içeriğini döndür."""
|
|
38
38
|
el = self.select_first(selector, element)
|
|
39
39
|
if not el:
|
|
40
40
|
return None
|
|
41
|
-
val = el.text(strip=
|
|
41
|
+
val = el.text(strip=True)
|
|
42
42
|
return val or None
|
|
43
43
|
|
|
44
|
-
def select_texts(self, selector: str, element: Node | None = None
|
|
44
|
+
def select_texts(self, selector: str, element: Node | None = None) -> list[str] | None:
|
|
45
45
|
"""CSS selector ile tüm eşleşen elementlerin text içeriklerini döndür."""
|
|
46
46
|
out: list[str] = []
|
|
47
47
|
for el in self.select(selector, element):
|
|
48
|
-
txt = el.text(strip=
|
|
48
|
+
txt = el.text(strip=True)
|
|
49
49
|
if txt:
|
|
50
50
|
out.append(txt)
|
|
51
|
-
return out
|
|
51
|
+
return out or None
|
|
52
52
|
|
|
53
53
|
def select_attr(self, selector: str | None, attr: str, element: Node | None = None) -> str | None:
|
|
54
54
|
"""CSS selector ile element bul ve attribute değerini döndür."""
|
|
@@ -71,42 +71,23 @@ class HTMLHelper:
|
|
|
71
71
|
return None
|
|
72
72
|
return el.attrs.get("data-src") or el.attrs.get("src")
|
|
73
73
|
|
|
74
|
-
def select_direct_text(self, selector: str, element: Node | None = None
|
|
74
|
+
def select_direct_text(self, selector: str, element: Node | None = None) -> str | None:
|
|
75
75
|
"""
|
|
76
76
|
Elementin yalnızca "kendi" düz metnini döndürür (child elementlerin text'ini katmadan).
|
|
77
|
-
Selectolax sürüm farklarına göre deep=False dene, yoksa node sibling-walk ile fallback yapar.
|
|
78
77
|
"""
|
|
79
78
|
el = self.select_first(selector, element)
|
|
80
79
|
if not el:
|
|
81
80
|
return None
|
|
82
81
|
|
|
83
|
-
#
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return val or None
|
|
87
|
-
except TypeError:
|
|
88
|
-
pass # deep parametresi yok, fallback'e geç
|
|
89
|
-
|
|
90
|
-
# 2) Fallback: direct children'ı el.child + next ile dolaş
|
|
91
|
-
parts: list[str] = []
|
|
92
|
-
ch = el.child
|
|
93
|
-
while ch is not None:
|
|
94
|
-
if ch.tag == "-text":
|
|
95
|
-
t = ch.text(strip=strip)
|
|
96
|
-
if t:
|
|
97
|
-
parts.append(t)
|
|
98
|
-
elif ch.tag == "br":
|
|
99
|
-
parts.append("\n")
|
|
100
|
-
ch = ch.next
|
|
101
|
-
|
|
102
|
-
out = "".join(parts).strip()
|
|
103
|
-
return out or None
|
|
82
|
+
# type: ignore[call-arg]
|
|
83
|
+
val = el.text(strip=True, deep=False)
|
|
84
|
+
return val or None
|
|
104
85
|
|
|
105
86
|
# ========================
|
|
106
87
|
# META (LABEL -> VALUE) İŞLEMLERİ
|
|
107
88
|
# ========================
|
|
108
89
|
|
|
109
|
-
def meta_value(self, label: str, container_selector: str | None = None
|
|
90
|
+
def meta_value(self, label: str, container_selector: str | None = None) -> str | None:
|
|
110
91
|
"""
|
|
111
92
|
Herhangi bir container içinde: LABEL metnini içeren bir elementten SONRA gelen metni döndürür.
|
|
112
93
|
label örn: "Oyuncular", "Yapım Yılı", "IMDB"
|
|
@@ -127,7 +108,7 @@ class HTMLHelper:
|
|
|
127
108
|
|
|
128
109
|
# 1) Elementin kendi içindeki text'te LABEL: VALUE formatı olabilir
|
|
129
110
|
# "Oyuncular: Brad Pitt" gibi. LABEL: sonrasını al.
|
|
130
|
-
full_txt = label_el.text(strip=
|
|
111
|
+
full_txt = label_el.text(strip=True)
|
|
131
112
|
if ":" in full_txt and needle in full_txt.split(":")[0].casefold():
|
|
132
113
|
val = full_txt.split(":", 1)[1].strip()
|
|
133
114
|
if val: return val
|
|
@@ -136,10 +117,10 @@ class HTMLHelper:
|
|
|
136
117
|
curr = label_el.next
|
|
137
118
|
while curr:
|
|
138
119
|
if curr.tag == "-text":
|
|
139
|
-
val = curr.text(strip=
|
|
120
|
+
val = curr.text(strip=True).strip(" :")
|
|
140
121
|
if val: return val
|
|
141
122
|
elif curr.tag != "br":
|
|
142
|
-
val = curr.text(strip=
|
|
123
|
+
val = curr.text(strip=True).strip(" :")
|
|
143
124
|
if val: return val
|
|
144
125
|
else: # <br> gördüysek satır bitmiştir
|
|
145
126
|
break
|
|
@@ -175,29 +156,25 @@ class HTMLHelper:
|
|
|
175
156
|
"""Regex için kaynak metni döndürür."""
|
|
176
157
|
return target if isinstance(target, str) else self.html
|
|
177
158
|
|
|
178
|
-
def
|
|
179
|
-
"""Regex flags değerini döndürür."""
|
|
180
|
-
return target if isinstance(target, int) else flags
|
|
181
|
-
|
|
182
|
-
def regex_first(self, pattern: str, target: str | int | None = None, flags: int = 0, group: int | None = 1) -> str | tuple | None:
|
|
159
|
+
def regex_first(self, pattern: str, target: str | int | None = None, group: int | None = 1) -> str | tuple | None:
|
|
183
160
|
"""Regex ile arama yap, istenen grubu döndür (group=None ise tüm grupları tuple olarak döndür)."""
|
|
184
|
-
match = re.search(pattern, self._regex_source(target)
|
|
161
|
+
match = re.search(pattern, self._regex_source(target))
|
|
185
162
|
if not match:
|
|
186
163
|
return None
|
|
187
|
-
|
|
164
|
+
|
|
188
165
|
if group is None:
|
|
189
166
|
return match.groups()
|
|
190
167
|
|
|
191
168
|
last_idx = match.lastindex or 0
|
|
192
169
|
return match.group(group) if last_idx >= group else match.group(0)
|
|
193
170
|
|
|
194
|
-
def regex_all(self, pattern: str, target: str | int | None = None
|
|
171
|
+
def regex_all(self, pattern: str, target: str | int | None = None) -> list[str] | list[tuple]:
|
|
195
172
|
"""Regex ile tüm eşleşmeleri döndür."""
|
|
196
|
-
return re.findall(pattern, self._regex_source(target)
|
|
173
|
+
return re.findall(pattern, self._regex_source(target))
|
|
197
174
|
|
|
198
|
-
def regex_replace(self, pattern: str, repl: str, target: str | int | None = None
|
|
175
|
+
def regex_replace(self, pattern: str, repl: str, target: str | int | None = None) -> str:
|
|
199
176
|
"""Regex ile replace yap."""
|
|
200
|
-
return re.sub(pattern, repl, self._regex_source(target)
|
|
177
|
+
return re.sub(pattern, repl, self._regex_source(target))
|
|
201
178
|
|
|
202
179
|
# ========================
|
|
203
180
|
# ÖZEL AYIKLAYICILAR
|
|
@@ -106,7 +106,13 @@ class PluginBase(ABC):
|
|
|
106
106
|
url = f"https:{url}" if url.startswith("//") else urljoin(self.main_url, url)
|
|
107
107
|
return url.replace("\\", "")
|
|
108
108
|
|
|
109
|
-
async def extract(
|
|
109
|
+
async def extract(
|
|
110
|
+
self,
|
|
111
|
+
url: str,
|
|
112
|
+
referer: str = None,
|
|
113
|
+
prefix: str | None = None,
|
|
114
|
+
name_override: str | None = None
|
|
115
|
+
) -> ExtractResult | list[ExtractResult] | None:
|
|
110
116
|
"""
|
|
111
117
|
Extractor ile video URL'sini çıkarır.
|
|
112
118
|
|
|
@@ -114,6 +120,7 @@ class PluginBase(ABC):
|
|
|
114
120
|
url: Iframe veya video URL'si
|
|
115
121
|
referer: Referer header (varsayılan: plugin main_url)
|
|
116
122
|
prefix: İsmin başına eklenecek opsiyonel etiket (örn: "Türkçe Dublaj")
|
|
123
|
+
name_override: İsmi tamamen değiştirecek opsiyonel etiket (Extractor adını ezer)
|
|
117
124
|
|
|
118
125
|
Returns:
|
|
119
126
|
ExtractResult: Extractor sonucu (name prefix ile birleştirilmiş) veya None
|
|
@@ -131,15 +138,19 @@ class PluginBase(ABC):
|
|
|
131
138
|
try:
|
|
132
139
|
data = await extractor.extract(url, referer=referer)
|
|
133
140
|
|
|
134
|
-
# Liste ise her bir öğe için prefix ekle
|
|
141
|
+
# Liste ise her bir öğe için prefix/override ekle
|
|
135
142
|
if isinstance(data, list):
|
|
136
143
|
for item in data:
|
|
137
|
-
if
|
|
144
|
+
if name_override:
|
|
145
|
+
item.name = name_override
|
|
146
|
+
elif prefix and item.name:
|
|
138
147
|
item.name = f"{prefix} | {item.name}"
|
|
139
148
|
return data
|
|
140
149
|
|
|
141
150
|
# Tekil öğe ise
|
|
142
|
-
if
|
|
151
|
+
if name_override:
|
|
152
|
+
data.name = name_override
|
|
153
|
+
elif prefix and data.name:
|
|
143
154
|
data.name = f"{prefix} | {data.name}"
|
|
144
155
|
|
|
145
156
|
return data
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
3
|
from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
|
|
4
|
-
import json
|
|
4
|
+
import json, html
|
|
5
5
|
|
|
6
6
|
class Odnoklassniki(ExtractorBase):
|
|
7
7
|
name = "Odnoklassniki"
|
|
@@ -19,12 +19,18 @@ class Odnoklassniki(ExtractorBase):
|
|
|
19
19
|
resp = await self.httpx.get(url, follow_redirects=True)
|
|
20
20
|
sel = HTMLHelper(resp.text)
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
# Metadata içinden videos array'ini al (esnek regex)
|
|
23
|
+
v_data = sel.regex_first(r'videos[^:]+:(\[.*?\])')
|
|
23
24
|
if not v_data:
|
|
25
|
+
if "Видео заблокировано" in resp.text or "copyrightsRestricted" in resp.text:
|
|
26
|
+
raise ValueError("Odnoklassniki: Video telif nedeniyle silinmiş/erişilemiyor.")
|
|
24
27
|
raise ValueError(f"Odnoklassniki: Video verisi bulunamadı. {url}")
|
|
25
28
|
|
|
26
29
|
# Kalite sıralaması (En yüksekten düşüğe)
|
|
27
30
|
order = ["ULTRA", "QUAD", "FULL", "HD", "SD", "LOW", "MOBILE"]
|
|
31
|
+
# Escaped string'i temizle
|
|
32
|
+
v_data = html.unescape(v_data)
|
|
33
|
+
v_data = v_data.replace('\\"', '"').replace('\\/', '/')
|
|
28
34
|
videos = json.loads(v_data)
|
|
29
35
|
|
|
30
36
|
best_url = None
|
|
@@ -38,4 +44,10 @@ class Odnoklassniki(ExtractorBase):
|
|
|
38
44
|
if not best_url:
|
|
39
45
|
raise ValueError("Odnoklassniki: Geçerli video URL'si bulunamadı.")
|
|
40
46
|
|
|
47
|
+
# URL temizliği (u0026 -> & ve olası unicode kaçışları)
|
|
48
|
+
best_url = best_url.replace("u0026", "&").replace("\\u0026", "&")
|
|
49
|
+
# Eğer hala \uXXXX formatında unicode kaçışları varsa çöz
|
|
50
|
+
if "\\u" in best_url:
|
|
51
|
+
best_url = best_url.encode().decode('unicode-escape')
|
|
52
|
+
|
|
41
53
|
return ExtractResult(name=self.name, url=self.fix_url(best_url), referer=referer)
|
|
@@ -47,7 +47,7 @@ class VidMoly(ExtractorBase):
|
|
|
47
47
|
|
|
48
48
|
# Altyazı kaynaklarını ayrıştır
|
|
49
49
|
subtitles = []
|
|
50
|
-
if sub_str := sel.regex_first(r"tracks:\s*\[(.*?)\]"
|
|
50
|
+
if sub_str := sel.regex_first(r"(?s)tracks:\s*\[(.*?)\]"):
|
|
51
51
|
sub_data = self._add_marks(sub_str, "file")
|
|
52
52
|
sub_data = self._add_marks(sub_data, "label")
|
|
53
53
|
sub_data = self._add_marks(sub_data, "kind")
|
|
@@ -68,7 +68,7 @@ class VidMoly(ExtractorBase):
|
|
|
68
68
|
break
|
|
69
69
|
|
|
70
70
|
if not video_url:
|
|
71
|
-
if src_str := sel.regex_first(r"sources:\s*\[(.*?)\],"
|
|
71
|
+
if src_str := sel.regex_first(r"(?s)sources:\s*\[(.*?)\],"):
|
|
72
72
|
vid_data = self._add_marks(src_str, "file")
|
|
73
73
|
with contextlib.suppress(json.JSONDecodeError):
|
|
74
74
|
vid_sources = json.loads(f"[{vid_data}]")
|
KekikStream/Extractors/YTDLP.py
CHANGED
|
@@ -151,8 +151,8 @@ class YTDLP(ExtractorBase):
|
|
|
151
151
|
ydl_opts = {
|
|
152
152
|
"quiet" : True,
|
|
153
153
|
"no_warnings" : True,
|
|
154
|
-
"extract_flat" : False,
|
|
155
|
-
"format" : "best", # En iyi kalite
|
|
154
|
+
"extract_flat" : False, # Tam bilgi al
|
|
155
|
+
"format" : "best/all", # En iyi kalite, yoksa herhangi biri
|
|
156
156
|
"no_check_certificates" : True,
|
|
157
157
|
"socket_timeout" : 3,
|
|
158
158
|
"retries" : 1
|
KekikStream/Plugins/BelgeselX.py
CHANGED
|
@@ -34,31 +34,46 @@ class BelgeselX(PluginBase):
|
|
|
34
34
|
@staticmethod
|
|
35
35
|
def _to_title_case(text: str) -> str:
|
|
36
36
|
"""Türkçe için title case dönüşümü."""
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
)
|
|
37
|
+
if not text:
|
|
38
|
+
return ""
|
|
39
|
+
|
|
40
|
+
words = text.split()
|
|
41
|
+
new_words = []
|
|
42
|
+
|
|
43
|
+
for word in words:
|
|
44
|
+
# Önce Türkçe karakterleri koruyarak küçült
|
|
45
|
+
# İ -> i, I -> ı
|
|
46
|
+
word = word.replace("İ", "i").replace("I", "ı").lower()
|
|
47
|
+
|
|
48
|
+
# Sonra ilk harfi Türkçe kurallarına göre büyüt
|
|
49
|
+
if word:
|
|
50
|
+
if word[0] == "i":
|
|
51
|
+
word = "İ" + word[1:]
|
|
52
|
+
elif word[0] == "ı":
|
|
53
|
+
word = "I" + word[1:]
|
|
54
|
+
else:
|
|
55
|
+
word = word[0].upper() + word[1:]
|
|
56
|
+
|
|
57
|
+
new_words.append(word)
|
|
58
|
+
|
|
59
|
+
return " ".join(new_words)
|
|
41
60
|
|
|
42
61
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
43
62
|
istek = self.cloudscraper.get(f"{url}{page}")
|
|
44
63
|
secici = HTMLHelper(istek.text)
|
|
45
64
|
|
|
46
65
|
results = []
|
|
47
|
-
# xpath kullanamıyoruz, en üst seviye gen-movie-contain'leri alıp içlerinden bilgileri çekelim
|
|
48
66
|
for container in secici.select("div.gen-movie-contain"):
|
|
49
|
-
# Poster için img'i container'ın içinden alalım
|
|
50
67
|
poster = secici.select_attr("div.gen-movie-img img", "src", container)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
title = secici.select_text("div.gen-movie-info h3 a", container)
|
|
54
|
-
href = secici.select_attr("div.gen-movie-info h3 a", "href", container)
|
|
68
|
+
title = secici.select_text("div.gen-movie-info h3 a", container)
|
|
69
|
+
href = secici.select_attr("div.gen-movie-info h3 a", "href", container)
|
|
55
70
|
|
|
56
71
|
if title and href:
|
|
57
72
|
results.append(MainPageResult(
|
|
58
73
|
category = category,
|
|
59
74
|
title = self._to_title_case(title),
|
|
60
75
|
url = self.fix_url(href),
|
|
61
|
-
poster = self.fix_url(poster)
|
|
76
|
+
poster = self.fix_url(poster)
|
|
62
77
|
))
|
|
63
78
|
|
|
64
79
|
return results
|
|
@@ -98,7 +113,6 @@ class BelgeselX(PluginBase):
|
|
|
98
113
|
poster = images[i] if i < len(images) else None
|
|
99
114
|
|
|
100
115
|
if not url_val or "diziresimleri" not in url_val:
|
|
101
|
-
# URL'den belgesel linkini oluştur
|
|
102
116
|
if poster and "diziresimleri" in poster:
|
|
103
117
|
file_name = poster.rsplit("/", 1)[-1]
|
|
104
118
|
file_name = HTMLHelper(file_name).regex_replace(r"\.(jpe?g|png|webp)$", "")
|
|
@@ -135,6 +149,7 @@ class BelgeselX(PluginBase):
|
|
|
135
149
|
if not rating:
|
|
136
150
|
if r_match := secici.regex_first(r"%\s*(\d+)\s*Puan", item):
|
|
137
151
|
rating = float(r_match) / 10
|
|
152
|
+
rating = rating or None
|
|
138
153
|
|
|
139
154
|
episodes = []
|
|
140
155
|
for i, ep in enumerate(secici.select("div.gen-movie-contain")):
|
|
@@ -147,12 +162,23 @@ class BelgeselX(PluginBase):
|
|
|
147
162
|
final_url = self.fix_url(href)
|
|
148
163
|
if item_id:
|
|
149
164
|
final_url = f"{final_url}?id={item_id}"
|
|
150
|
-
|
|
151
|
-
episodes.append(Episode(
|
|
165
|
+
|
|
166
|
+
episodes.append(Episode(
|
|
167
|
+
season = s or 1,
|
|
168
|
+
episode = e or (i + 1),
|
|
169
|
+
title = name,
|
|
170
|
+
url = final_url
|
|
171
|
+
))
|
|
152
172
|
|
|
153
173
|
return SeriesInfo(
|
|
154
|
-
url=url,
|
|
155
|
-
|
|
174
|
+
url = url,
|
|
175
|
+
poster = self.fix_url(poster),
|
|
176
|
+
title = title,
|
|
177
|
+
description = description,
|
|
178
|
+
tags = tags,
|
|
179
|
+
year = year,
|
|
180
|
+
rating = rating,
|
|
181
|
+
episodes = episodes
|
|
156
182
|
)
|
|
157
183
|
|
|
158
184
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
@@ -179,6 +205,7 @@ class BelgeselX(PluginBase):
|
|
|
179
205
|
|
|
180
206
|
for i, video_url in enumerate(files):
|
|
181
207
|
quality = labels[i] if i < len(labels) else "HD"
|
|
208
|
+
name = f"{'Google' if 'google' in video_url.lower() or 'blogspot' in video_url.lower() or quality == 'FULL' else self.name} | {'1080p' if quality == 'FULL' else quality}"
|
|
182
209
|
|
|
183
210
|
# belgeselx.php redirect'ini çöz
|
|
184
211
|
if "belgeselx.php" in video_url or "belgeselx2.php" in video_url:
|
|
@@ -191,7 +218,7 @@ class BelgeselX(PluginBase):
|
|
|
191
218
|
|
|
192
219
|
links.append(ExtractResult(
|
|
193
220
|
url = video_url,
|
|
194
|
-
name =
|
|
221
|
+
name = name,
|
|
195
222
|
referer = main_url
|
|
196
223
|
))
|
|
197
224
|
|
KekikStream/Plugins/DiziBox.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 Kekik.Sifreleme
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
|
|
4
|
+
from Kekik.Sifreleme import CryptoJS
|
|
5
5
|
import urllib.parse, base64, contextlib, asyncio, time
|
|
6
6
|
|
|
7
7
|
class DiziBox(PluginBase):
|
|
@@ -61,7 +61,7 @@ class DiziBox(PluginBase):
|
|
|
61
61
|
category = category,
|
|
62
62
|
title = title,
|
|
63
63
|
url = self.fix_url(href),
|
|
64
|
-
poster = self.fix_url(poster)
|
|
64
|
+
poster = self.fix_url(poster),
|
|
65
65
|
))
|
|
66
66
|
|
|
67
67
|
return results
|
|
@@ -84,7 +84,7 @@ class DiziBox(PluginBase):
|
|
|
84
84
|
results.append(SearchResult(
|
|
85
85
|
title = title,
|
|
86
86
|
url = self.fix_url(href),
|
|
87
|
-
poster = self.fix_url(poster)
|
|
87
|
+
poster = self.fix_url(poster),
|
|
88
88
|
))
|
|
89
89
|
|
|
90
90
|
return results
|
|
@@ -114,12 +114,12 @@ class DiziBox(PluginBase):
|
|
|
114
114
|
|
|
115
115
|
return SeriesInfo(
|
|
116
116
|
url = url,
|
|
117
|
-
poster = self.fix_url(poster)
|
|
117
|
+
poster = self.fix_url(poster),
|
|
118
118
|
title = title,
|
|
119
119
|
description = description,
|
|
120
120
|
tags = tags,
|
|
121
121
|
rating = rating,
|
|
122
|
-
year =
|
|
122
|
+
year = year,
|
|
123
123
|
episodes = episodes,
|
|
124
124
|
actors = actors,
|
|
125
125
|
)
|
|
@@ -182,13 +182,16 @@ class DiziBox(PluginBase):
|
|
|
182
182
|
istek = await self.httpx.get(url)
|
|
183
183
|
secici = HTMLHelper(istek.text)
|
|
184
184
|
|
|
185
|
+
# Aktif kaynağın adını bul (DBX Pro vs.)
|
|
186
|
+
current_source_name = secici.select_text("div.video-toolbar option[selected]") or self.name
|
|
187
|
+
|
|
185
188
|
results = []
|
|
186
189
|
main_iframe = secici.select_attr("div#video-area iframe", "src")
|
|
187
190
|
|
|
188
191
|
if main_iframe:
|
|
189
192
|
if decoded := await self._iframe_decode(self.name, main_iframe, url):
|
|
190
193
|
for iframe in decoded:
|
|
191
|
-
data = await self.extract(iframe)
|
|
194
|
+
data = await self.extract(iframe, name_override=current_source_name)
|
|
192
195
|
if data:
|
|
193
196
|
results.append(data)
|
|
194
197
|
|
|
@@ -209,7 +212,7 @@ class DiziBox(PluginBase):
|
|
|
209
212
|
if alt_iframe:
|
|
210
213
|
if decoded := await self._iframe_decode(alt_name, alt_iframe, url):
|
|
211
214
|
for iframe in decoded:
|
|
212
|
-
data = await self.extract(iframe,
|
|
215
|
+
data = await self.extract(iframe, name_override=alt_name)
|
|
213
216
|
if data:
|
|
214
217
|
results.append(data)
|
|
215
218
|
|
KekikStream/Plugins/DiziMom.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,
|
|
4
|
-
from json import dumps, loads
|
|
5
|
-
import re
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
|
|
6
4
|
|
|
7
5
|
class DiziMom(PluginBase):
|
|
8
6
|
name = "DiziMom"
|
|
@@ -31,23 +29,33 @@ class DiziMom(PluginBase):
|
|
|
31
29
|
href = helper.select_attr("div.episode-name a", "href", item)
|
|
32
30
|
img = helper.select_poster("div.cat-img img", item)
|
|
33
31
|
if title and href:
|
|
34
|
-
results.append(MainPageResult(
|
|
32
|
+
results.append(MainPageResult(
|
|
33
|
+
category = category,
|
|
34
|
+
title = title.split(" izle")[0],
|
|
35
|
+
url = self.fix_url(href),
|
|
36
|
+
poster = self.fix_url(img)
|
|
37
|
+
))
|
|
35
38
|
else:
|
|
36
39
|
for item in helper.select("div.single-item"):
|
|
37
40
|
title = helper.select_text("div.categorytitle a", item)
|
|
38
41
|
href = helper.select_attr("div.categorytitle a", "href", item)
|
|
39
42
|
img = helper.select_poster("div.cat-img img", item)
|
|
40
43
|
if title and href:
|
|
41
|
-
results.append(MainPageResult(
|
|
44
|
+
results.append(MainPageResult(
|
|
45
|
+
category = category,
|
|
46
|
+
title = title.split(" izle")[0],
|
|
47
|
+
url = self.fix_url(href),
|
|
48
|
+
poster = self.fix_url(img)
|
|
49
|
+
))
|
|
42
50
|
|
|
43
51
|
return results
|
|
44
52
|
|
|
45
53
|
async def search(self, query: str) -> list[SearchResult]:
|
|
46
|
-
url
|
|
47
|
-
istek
|
|
54
|
+
url = f"{self.main_url}/?s={query}"
|
|
55
|
+
istek = await self.httpx.get(url)
|
|
48
56
|
helper = HTMLHelper(istek.text)
|
|
49
|
-
items
|
|
50
|
-
|
|
57
|
+
items = helper.select("div.single-item")
|
|
58
|
+
|
|
51
59
|
return [
|
|
52
60
|
SearchResult(
|
|
53
61
|
title = helper.select_text("div.categorytitle a", item).split(" izle")[0],
|
|
@@ -65,7 +73,7 @@ class DiziMom(PluginBase):
|
|
|
65
73
|
poster = helper.select_poster("div.category_image img")
|
|
66
74
|
description = helper.select_direct_text("div.category_desc")
|
|
67
75
|
tags = helper.select_texts("div.genres a")
|
|
68
|
-
rating = helper.regex_first(r"IMDB\s*:\s*(?:</span>)?\s*([\d\.]+)", helper.html
|
|
76
|
+
rating = helper.regex_first(r"(?s)IMDB\s*:\s*(?:</span>)?\s*([\d\.]+)", helper.html)
|
|
69
77
|
year = helper.extract_year("div.category_text")
|
|
70
78
|
actors = helper.meta_list("Oyuncular", container_selector="div#icerikcat2")
|
|
71
79
|
|
|
@@ -78,68 +86,78 @@ class DiziMom(PluginBase):
|
|
|
78
86
|
episodes.append(Episode(
|
|
79
87
|
season = s or 1,
|
|
80
88
|
episode = e or 1,
|
|
81
|
-
title = self.clean_title(name.replace(title
|
|
89
|
+
title = self.clean_title(name.replace(title, "").strip()),
|
|
82
90
|
url = self.fix_url(href)
|
|
83
91
|
))
|
|
84
92
|
|
|
85
93
|
return SeriesInfo(
|
|
86
94
|
url = url,
|
|
87
|
-
poster = self.fix_url(poster)
|
|
88
|
-
title = title
|
|
95
|
+
poster = self.fix_url(poster),
|
|
96
|
+
title = title,
|
|
89
97
|
description = description,
|
|
90
98
|
tags = tags,
|
|
91
99
|
rating = rating,
|
|
92
|
-
year =
|
|
100
|
+
year = year,
|
|
93
101
|
actors = actors,
|
|
94
102
|
episodes = episodes
|
|
95
103
|
)
|
|
96
104
|
|
|
97
105
|
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
await self.httpx.post(login_url, headers=headers, data=login_data)
|
|
116
|
-
|
|
117
|
-
istek = await self.httpx.get(url, headers=headers)
|
|
106
|
+
await self.httpx.post(
|
|
107
|
+
url = f"{self.main_url}/wp-login.php",
|
|
108
|
+
headers = {
|
|
109
|
+
"User-Agent" : "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
|
|
110
|
+
"sec-ch-ua" : 'Not/A)Brand";v="8", "Chromium";v="137", "Google Chrome";v="137"',
|
|
111
|
+
"sec-ch-ua-mobile" : "?1",
|
|
112
|
+
"sec-ch-ua-platform" : "Android"
|
|
113
|
+
},
|
|
114
|
+
data = {
|
|
115
|
+
"log" : "keyiflerolsun",
|
|
116
|
+
"pwd" : "12345",
|
|
117
|
+
"rememberme" : "forever",
|
|
118
|
+
"redirect_to" : self.main_url
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
istek = await self.httpx.get(url)
|
|
118
123
|
helper = HTMLHelper(istek.text)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
|
|
125
|
+
iframe_data = []
|
|
126
|
+
|
|
127
|
+
# Aktif kaynağın (main iframe) adını bul
|
|
128
|
+
current_name = helper.select_text("div.sources span.current_dil") or ""
|
|
122
129
|
main_iframe = helper.select_attr("iframe[src]", "src")
|
|
130
|
+
|
|
131
|
+
# Bazen iframe doğrudan video p içinde olabilir
|
|
132
|
+
if not main_iframe:
|
|
133
|
+
main_iframe = helper.select_attr("div.video p iframe", "src")
|
|
134
|
+
|
|
123
135
|
if main_iframe:
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
136
|
+
iframe_data.append((main_iframe, current_name))
|
|
137
|
+
|
|
138
|
+
# Diğer kaynakları (Partlar) gez
|
|
139
|
+
sources = helper.select("div.sources a.post-page-numbers")
|
|
127
140
|
for source in sources:
|
|
128
|
-
href =
|
|
141
|
+
href = helper.select_attr(None, "href", source)
|
|
142
|
+
name = helper.select_text("span.dil", source)
|
|
143
|
+
|
|
129
144
|
if href:
|
|
130
|
-
|
|
145
|
+
# Part sayfasına git
|
|
146
|
+
sub_istek = await self.httpx.get(href)
|
|
131
147
|
sub_helper = HTMLHelper(sub_istek.text)
|
|
132
|
-
sub_iframe = sub_helper.select_attr("div.video p iframe", "src")
|
|
148
|
+
sub_iframe = sub_helper.select_attr("div.video p iframe", "src") or sub_helper.select_attr("iframe[src]", "src")
|
|
149
|
+
|
|
133
150
|
if sub_iframe:
|
|
134
|
-
|
|
135
|
-
|
|
151
|
+
iframe_data.append((sub_iframe, name or f"{len(iframe_data)+1}.Kısım"))
|
|
152
|
+
|
|
136
153
|
results = []
|
|
137
|
-
for iframe_url in
|
|
138
|
-
#
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
extract_result = await self.extract(iframe_url)
|
|
154
|
+
for iframe_url, source_name in iframe_data:
|
|
155
|
+
# URL düzeltme
|
|
156
|
+
iframe_url = self.fix_url(iframe_url)
|
|
157
|
+
|
|
158
|
+
# Prefix olarak kaynak adını kullan (1.Kısım | HDMomPlayer)
|
|
159
|
+
extract_result = await self.extract(iframe_url, prefix=source_name)
|
|
160
|
+
|
|
143
161
|
if extract_result:
|
|
144
162
|
if isinstance(extract_result, list):
|
|
145
163
|
results.extend(extract_result)
|
|
@@ -147,9 +165,9 @@ class DiziMom(PluginBase):
|
|
|
147
165
|
results.append(extract_result)
|
|
148
166
|
else:
|
|
149
167
|
results.append(ExtractResult(
|
|
150
|
-
url
|
|
151
|
-
name
|
|
168
|
+
url = iframe_url,
|
|
169
|
+
name = f"{source_name} | External",
|
|
152
170
|
referer = self.main_url
|
|
153
171
|
))
|
|
154
|
-
|
|
172
|
+
|
|
155
173
|
return results
|