KekikStream 2.3.2__py3-none-any.whl → 2.3.4__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 +4 -1
- KekikStream/Core/__init__.py +2 -0
- KekikStream/Extractors/CloseLoad.py +12 -13
- KekikStream/Extractors/ContentX.py +12 -15
- 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 +5 -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/DiziYou.py +95 -88
- KekikStream/Plugins/Dizilla.py +51 -71
- KekikStream/Plugins/FilmBip.py +24 -49
- KekikStream/Plugins/FilmMakinesi.py +35 -52
- KekikStream/Plugins/FilmModu.py +27 -41
- KekikStream/Plugins/FullHDFilm.py +57 -62
- 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 +34 -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-2.3.2.dist-info → kekikstream-2.3.4.dist-info}/METADATA +1 -1
- kekikstream-2.3.4.dist-info/RECORD +83 -0
- kekikstream-2.3.2.dist-info/RECORD +0 -82
- {kekikstream-2.3.2.dist-info → kekikstream-2.3.4.dist-info}/WHEEL +0 -0
- {kekikstream-2.3.2.dist-info → kekikstream-2.3.4.dist-info}/entry_points.txt +0 -0
- {kekikstream-2.3.2.dist-info → kekikstream-2.3.4.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-2.3.2.dist-info → kekikstream-2.3.4.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from selectolax.parser import HTMLParser, Node
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class HTMLHelper:
|
|
8
|
+
"""
|
|
9
|
+
Selectolax ile HTML parsing işlemlerini temiz, kısa ve okunabilir hale getiren yardımcı sınıf.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, html: str):
|
|
13
|
+
self.parser = HTMLParser(html)
|
|
14
|
+
self.html = html
|
|
15
|
+
|
|
16
|
+
# ========================
|
|
17
|
+
# TEMEL SELECTOR İŞLEMLERİ
|
|
18
|
+
# ========================
|
|
19
|
+
|
|
20
|
+
def _target(self, element: Node | None) -> Node | HTMLParser:
|
|
21
|
+
"""İşlem yapılacak temel elementi döndürür."""
|
|
22
|
+
return element if element is not None else self.parser
|
|
23
|
+
|
|
24
|
+
def select(self, selector: str, element: Node | None = None) -> list[Node]:
|
|
25
|
+
"""CSS selector ile tüm eşleşen elementleri döndür."""
|
|
26
|
+
return self._target(element).css(selector)
|
|
27
|
+
|
|
28
|
+
def select_first(self, selector: str | None, element: Node | None = None) -> Node | None:
|
|
29
|
+
"""CSS selector ile ilk eşleşen elementi döndür."""
|
|
30
|
+
if not selector:
|
|
31
|
+
return element
|
|
32
|
+
|
|
33
|
+
return self._target(element).css_first(selector)
|
|
34
|
+
|
|
35
|
+
def select_text(self, selector: str | None = None, element: Node | None = None, strip: bool = True) -> str | None:
|
|
36
|
+
"""CSS selector ile element bul ve text içeriğini döndür."""
|
|
37
|
+
el = self.select_first(selector, element)
|
|
38
|
+
if not el:
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
val = el.text(strip=strip)
|
|
42
|
+
return val if val else None
|
|
43
|
+
|
|
44
|
+
def select_attr(self, selector: str | None, attr: str, element: Node | None = None) -> str | None:
|
|
45
|
+
"""CSS selector ile element bul ve attribute değerini döndür."""
|
|
46
|
+
el = self.select_first(selector, element)
|
|
47
|
+
return el.attrs.get(attr) if el else None
|
|
48
|
+
|
|
49
|
+
def select_all_text(self, selector: str, element: Node | None = None, strip: bool = True) -> list[str]:
|
|
50
|
+
"""CSS selector ile tüm eşleşen elementlerin text içeriklerini döndür."""
|
|
51
|
+
return [
|
|
52
|
+
txt for el in self.select(selector, element)
|
|
53
|
+
if (txt := el.text(strip=strip))
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
def select_all_attr(self, selector: str, attr: str, element: Node | None = None) -> list[str]:
|
|
57
|
+
"""CSS selector ile tüm eşleşen elementlerin attribute değerlerini döndür."""
|
|
58
|
+
return [
|
|
59
|
+
val for el in self.select(selector, element)
|
|
60
|
+
if (val := el.attrs.get(attr))
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
# ----------------------------------------------
|
|
64
|
+
|
|
65
|
+
def select_poster(self, selector: str = "img", element: Node | None = None) -> str | None:
|
|
66
|
+
"""Poster URL'sini çıkar. Önce data-src, sonra src dener."""
|
|
67
|
+
el = self.select_first(selector, element)
|
|
68
|
+
if not el:
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
return el.attrs.get("data-src") or el.attrs.get("src")
|
|
72
|
+
|
|
73
|
+
# ========================
|
|
74
|
+
# REGEX İŞLEMLERİ
|
|
75
|
+
# ========================
|
|
76
|
+
|
|
77
|
+
def _source(self, target: str | int | None) -> str:
|
|
78
|
+
"""Regex için kaynak metni döndürür."""
|
|
79
|
+
return target if isinstance(target, str) else self.html
|
|
80
|
+
|
|
81
|
+
def _flags(self, target: str | int | None, flags: int) -> int:
|
|
82
|
+
"""Regex flags değerini döndürür."""
|
|
83
|
+
return target if isinstance(target, int) else flags
|
|
84
|
+
|
|
85
|
+
def regex_first(self, pattern: str, target: str | int | None = None, flags: int = 0) -> str | None:
|
|
86
|
+
"""Regex ile arama yap, ilk grubu döndür (grup yoksa tamamını)."""
|
|
87
|
+
match = re.search(pattern, self._source(target), self._flags(target, flags))
|
|
88
|
+
if not match:
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
return match.group(1)
|
|
93
|
+
except IndexError:
|
|
94
|
+
return match.group(0)
|
|
95
|
+
|
|
96
|
+
def regex_all(self, pattern: str, target: str | int | None = None, flags: int = 0) -> list[str]:
|
|
97
|
+
"""Regex ile tüm eşleşmeleri döndür."""
|
|
98
|
+
return re.findall(pattern, self._source(target), self._flags(target, flags))
|
|
99
|
+
|
|
100
|
+
def regex_replace(self, pattern: str, repl: str, target: str | int | None = None, flags: int = 0) -> str:
|
|
101
|
+
"""Regex ile replace yap."""
|
|
102
|
+
return re.sub(pattern, repl, self._source(target), flags)
|
|
103
|
+
|
|
104
|
+
# ========================
|
|
105
|
+
# ÖZEL AYIKLAYICILAR
|
|
106
|
+
# ========================
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def extract_season_episode(text: str) -> tuple[int | None, int | None]:
|
|
110
|
+
"""Metin içinden sezon ve bölüm numarasını çıkar."""
|
|
111
|
+
# S01E05 formatı
|
|
112
|
+
if m := re.search(r"[Ss](\d+)[Ee](\d+)", text):
|
|
113
|
+
return int(m.group(1)), int(m.group(2))
|
|
114
|
+
|
|
115
|
+
# Ayrı ayrı ara
|
|
116
|
+
s = re.search(r"(\d+)\.\s*[Ss]ezon|[Ss]ezon[- ]?(\d+)|-(\d+)-sezon", text, re.I)
|
|
117
|
+
e = re.search(r"(\d+)\.\s*[Bb]ölüm|[Bb]olum[- ]?(\d+)|-(\d+)-bolum|[Ee](\d+)", text, re.I)
|
|
118
|
+
|
|
119
|
+
# İlk bulunan grubu al (None değilse)
|
|
120
|
+
s_val = next((int(g) for g in s.groups() if g), None) if s else None
|
|
121
|
+
e_val = next((int(g) for g in e.groups() if g), None) if e else None
|
|
122
|
+
|
|
123
|
+
return s_val, e_val
|
|
124
|
+
|
|
125
|
+
def extract_year(self, *selectors: str, pattern: str = r"(\d{4})") -> int | None:
|
|
126
|
+
"""Birden fazla selector veya regex ile yıl bilgisini çıkar."""
|
|
127
|
+
for selector in selectors:
|
|
128
|
+
if text := self.select_text(selector):
|
|
129
|
+
if m := re.search(r"(\d{4})", text):
|
|
130
|
+
return int(m.group(1))
|
|
131
|
+
|
|
132
|
+
val = self.regex_first(pattern)
|
|
133
|
+
return int(val) if val and val.isdigit() else None
|
|
134
|
+
|
KekikStream/Core/__init__.py
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle, HTMLHelper
|
|
4
4
|
from Kekik.Sifreleme import Packer, StreamDecoder
|
|
5
|
-
|
|
6
|
-
import re, json
|
|
5
|
+
import json
|
|
7
6
|
|
|
8
7
|
class CloseLoadExtractor(ExtractorBase):
|
|
9
8
|
name = "CloseLoad"
|
|
@@ -11,8 +10,8 @@ class CloseLoadExtractor(ExtractorBase):
|
|
|
11
10
|
|
|
12
11
|
def _extract_from_json_ld(self, html: str) -> str | None:
|
|
13
12
|
"""JSON-LD script tag'inden contentUrl'i çıkar (Kotlin versiyonundaki gibi)"""
|
|
14
|
-
secici =
|
|
15
|
-
for script in secici.
|
|
13
|
+
secici = HTMLHelper(html)
|
|
14
|
+
for script in secici.select("script[type='application/ld+json']"):
|
|
16
15
|
try:
|
|
17
16
|
data = json.loads(script.text(strip=True))
|
|
18
17
|
if content_url := data.get("contentUrl"):
|
|
@@ -20,17 +19,17 @@ class CloseLoadExtractor(ExtractorBase):
|
|
|
20
19
|
return content_url
|
|
21
20
|
except (json.JSONDecodeError, TypeError):
|
|
22
21
|
# Regex ile contentUrl'i çıkarmayı dene
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
if content_url := secici.regex_first(r'"contentUrl"\s*:\s*"([^\"]+)"', script.text()):
|
|
23
|
+
if content_url.startswith("http"):
|
|
24
|
+
return content_url
|
|
26
25
|
return None
|
|
27
26
|
|
|
28
27
|
def _extract_from_packed(self, html: str) -> str | None:
|
|
29
28
|
"""Packed JavaScript'ten video URL'sini çıkar (fallback)"""
|
|
30
29
|
try:
|
|
31
|
-
|
|
32
|
-
if
|
|
33
|
-
return StreamDecoder.extract_stream_url(Packer.unpack(
|
|
30
|
+
packed = HTMLHelper(html).regex_all(r'\s*(eval\(function[\s\S].*)')
|
|
31
|
+
if packed:
|
|
32
|
+
return StreamDecoder.extract_stream_url(Packer.unpack(packed[0]))
|
|
34
33
|
except Exception:
|
|
35
34
|
pass
|
|
36
35
|
return None
|
|
@@ -59,8 +58,8 @@ class CloseLoadExtractor(ExtractorBase):
|
|
|
59
58
|
|
|
60
59
|
# Subtitle'ları parse et (Kotlin referansı: track elementleri)
|
|
61
60
|
subtitles = []
|
|
62
|
-
secici =
|
|
63
|
-
for track in secici.
|
|
61
|
+
secici = HTMLHelper(istek.text)
|
|
62
|
+
for track in secici.select("track"):
|
|
64
63
|
raw_src = track.attrs.get("src") or ""
|
|
65
64
|
raw_src = raw_src.strip()
|
|
66
65
|
label = track.attrs.get("label") or track.attrs.get("srclang") or "Altyazı"
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
|
|
4
|
-
import re
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle, HTMLHelper
|
|
5
4
|
|
|
6
5
|
class ContentX(ExtractorBase):
|
|
7
6
|
name = "ContentX"
|
|
@@ -31,15 +30,13 @@ class ContentX(ExtractorBase):
|
|
|
31
30
|
istek.raise_for_status()
|
|
32
31
|
i_source = istek.text
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
if not
|
|
33
|
+
i_extract_value = HTMLHelper(i_source).regex_first(r"window\.openPlayer\('([^']+)'\)")
|
|
34
|
+
if not i_extract_value:
|
|
36
35
|
raise ValueError("i_extract is null")
|
|
37
|
-
i_extract_value = i_extract[1]
|
|
38
36
|
|
|
39
37
|
subtitles = []
|
|
40
38
|
sub_urls = set()
|
|
41
|
-
for
|
|
42
|
-
sub_url, sub_lang = match.groups()
|
|
39
|
+
for sub_url, sub_lang in HTMLHelper(i_source).regex_all(r'"file":"([^\"]+)","label":"([^\"]+)"'):
|
|
43
40
|
|
|
44
41
|
if sub_url in sub_urls:
|
|
45
42
|
continue
|
|
@@ -60,11 +57,11 @@ class ContentX(ExtractorBase):
|
|
|
60
57
|
vid_source_request.raise_for_status()
|
|
61
58
|
|
|
62
59
|
vid_source = vid_source_request.text
|
|
63
|
-
|
|
64
|
-
if not
|
|
60
|
+
m3u_link = HTMLHelper(vid_source).regex_first(r'file":"([^\"]+)"')
|
|
61
|
+
if not m3u_link:
|
|
65
62
|
raise ValueError("vidExtract is null")
|
|
66
63
|
|
|
67
|
-
m3u_link =
|
|
64
|
+
m3u_link = m3u_link.replace("\\", "")
|
|
68
65
|
results = [
|
|
69
66
|
ExtractResult(
|
|
70
67
|
name = self.name,
|
|
@@ -74,17 +71,17 @@ class ContentX(ExtractorBase):
|
|
|
74
71
|
)
|
|
75
72
|
]
|
|
76
73
|
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
dublaj_value = HTMLHelper(i_source).regex_first(r',\"([^\"]+)\",\"Türkçe\"')
|
|
75
|
+
if dublaj_value:
|
|
79
76
|
dublaj_source_request = await self.httpx.get(f"{base_url}/source2.php?v={dublaj_value}", headers={"Referer": referer or base_url})
|
|
80
77
|
dublaj_source_request.raise_for_status()
|
|
81
78
|
|
|
82
79
|
dublaj_source = dublaj_source_request.text
|
|
83
|
-
|
|
84
|
-
if not
|
|
80
|
+
dublaj_link = HTMLHelper(dublaj_source).regex_first(r'file":"([^\"]+)"')
|
|
81
|
+
if not dublaj_link:
|
|
85
82
|
raise ValueError("dublajExtract is null")
|
|
86
83
|
|
|
87
|
-
dublaj_link =
|
|
84
|
+
dublaj_link = dublaj_link.replace("\\", "")
|
|
88
85
|
results.append(
|
|
89
86
|
ExtractResult(
|
|
90
87
|
name = f"{self.name} Türkçe Dublaj",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle, HTMLHelper
|
|
4
4
|
from Kekik.Sifreleme import AESManager
|
|
5
|
-
import
|
|
5
|
+
import json
|
|
6
6
|
|
|
7
7
|
class DonilasPlay(ExtractorBase):
|
|
8
8
|
name = "DonilasPlay"
|
|
@@ -20,10 +20,10 @@ class DonilasPlay(ExtractorBase):
|
|
|
20
20
|
subtitles = []
|
|
21
21
|
|
|
22
22
|
# bePlayer pattern
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
be_player_data =
|
|
23
|
+
hp = HTMLHelper(i_source)
|
|
24
|
+
be_player_matches = hp.regex_all(r"bePlayer\('([^']+)',\s*'(\{[^}]+\})'\);")
|
|
25
|
+
if be_player_matches:
|
|
26
|
+
be_player_pass, be_player_data = be_player_matches[0]
|
|
27
27
|
|
|
28
28
|
try:
|
|
29
29
|
# AES decrypt
|
|
@@ -54,15 +54,15 @@ class DonilasPlay(ExtractorBase):
|
|
|
54
54
|
|
|
55
55
|
# Fallback: file pattern
|
|
56
56
|
if not m3u_link:
|
|
57
|
-
file_match =
|
|
57
|
+
file_match = hp.regex_first(r'file:"([^"]+)"')
|
|
58
58
|
if file_match:
|
|
59
|
-
m3u_link = file_match
|
|
59
|
+
m3u_link = file_match
|
|
60
60
|
|
|
61
61
|
# tracks pattern for subtitles
|
|
62
|
-
tracks_match =
|
|
62
|
+
tracks_match = hp.regex_first(r'tracks:\[([^\]]+)')
|
|
63
63
|
if tracks_match:
|
|
64
64
|
try:
|
|
65
|
-
tracks_str = f"[{tracks_match
|
|
65
|
+
tracks_str = f"[{tracks_match}]"
|
|
66
66
|
tracks = json.loads(tracks_str)
|
|
67
67
|
for track in tracks:
|
|
68
68
|
file_url = track.get("file")
|
KekikStream/Extractors/DzenRu.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import ExtractorBase, ExtractResult
|
|
4
|
-
import re
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
|
|
5
4
|
|
|
6
5
|
class DzenRu(ExtractorBase):
|
|
7
6
|
name = "DzenRu"
|
|
@@ -18,7 +17,8 @@ class DzenRu(ExtractorBase):
|
|
|
18
17
|
istek.raise_for_status()
|
|
19
18
|
|
|
20
19
|
# okcdn.ru linklerini bul
|
|
21
|
-
|
|
20
|
+
hp = HTMLHelper(istek.text)
|
|
21
|
+
matches = hp.regex_all(r'https://vd\d+\.okcdn\.ru/\?[^"\'\\\s]+')
|
|
22
22
|
|
|
23
23
|
if not matches:
|
|
24
24
|
raise ValueError("DzenRu video link not found")
|
KekikStream/Extractors/ExPlay.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
|
|
4
|
-
import re
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle, HTMLHelper
|
|
5
4
|
from urllib.parse import urlparse, parse_qs
|
|
6
5
|
|
|
7
6
|
class ExPlay(ExtractorBase):
|
|
@@ -23,21 +22,22 @@ class ExPlay(ExtractorBase):
|
|
|
23
22
|
istek = await self.httpx.get(clean_url)
|
|
24
23
|
istek.raise_for_status()
|
|
25
24
|
|
|
25
|
+
hp = HTMLHelper(istek.text)
|
|
26
|
+
|
|
26
27
|
# videoUrl çıkar
|
|
27
|
-
|
|
28
|
-
if not
|
|
28
|
+
video_url = hp.regex_first(r'videoUrl":"([^",]+)"')
|
|
29
|
+
if not video_url:
|
|
29
30
|
raise ValueError("videoUrl not found")
|
|
30
|
-
video_url =
|
|
31
|
+
video_url = video_url.replace("\\", "")
|
|
31
32
|
|
|
32
33
|
# videoServer çıkar
|
|
33
|
-
|
|
34
|
-
if not
|
|
34
|
+
video_server = hp.regex_first(r'videoServer":"([^",]+)"')
|
|
35
|
+
if not video_server:
|
|
35
36
|
raise ValueError("videoServer not found")
|
|
36
|
-
video_server = video_server_match[1]
|
|
37
37
|
|
|
38
38
|
# title çıkar
|
|
39
|
-
|
|
40
|
-
title =
|
|
39
|
+
title = hp.regex_first(r'title":"([^",]+)"')
|
|
40
|
+
title = title.split(".")[-1] if title else "Unknown"
|
|
41
41
|
|
|
42
42
|
if part_key and "turkce" in part_key.lower():
|
|
43
43
|
title = part_key # Or nicer formatting like SetPlay
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import ExtractorBase, ExtractResult
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
|
|
4
4
|
from Kekik.Sifreleme import Packer
|
|
5
|
-
from selectolax.parser import HTMLParser
|
|
6
|
-
import re
|
|
7
5
|
|
|
8
6
|
class Filemoon(ExtractorBase):
|
|
9
7
|
name = "Filemoon"
|
|
@@ -34,11 +32,10 @@ class Filemoon(ExtractorBase):
|
|
|
34
32
|
# İlk sayfayı al
|
|
35
33
|
istek = await self.httpx.get(url)
|
|
36
34
|
response = istek.text
|
|
37
|
-
secici =
|
|
35
|
+
secici = HTMLHelper(response)
|
|
38
36
|
|
|
39
37
|
# Eğer iframe varsa, iframe'e git
|
|
40
|
-
|
|
41
|
-
iframe_src = iframe_el.attrs.get("src") if iframe_el else None
|
|
38
|
+
iframe_src = secici.select_attr("iframe", "src")
|
|
42
39
|
|
|
43
40
|
m3u8_url = None
|
|
44
41
|
|
|
@@ -52,8 +49,8 @@ class Filemoon(ExtractorBase):
|
|
|
52
49
|
|
|
53
50
|
if script_data:
|
|
54
51
|
unpacked = Packer.unpack(script_data)
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
unpacked_sec = HTMLHelper(unpacked)
|
|
53
|
+
m3u8_url = unpacked_sec.regex_first(r'sources:\[\{file:"(.*?)"')
|
|
57
54
|
else:
|
|
58
55
|
# Iframe varsa devam et
|
|
59
56
|
iframe_url = self.fix_url(iframe_src)
|
|
@@ -62,25 +59,23 @@ class Filemoon(ExtractorBase):
|
|
|
62
59
|
|
|
63
60
|
istek = await self.httpx.get(iframe_url, headers=iframe_headers)
|
|
64
61
|
response = istek.text
|
|
65
|
-
secici =
|
|
62
|
+
secici = HTMLHelper(response)
|
|
66
63
|
|
|
67
64
|
script_data = ""
|
|
68
|
-
for script in secici.
|
|
65
|
+
for script in secici.select("script"):
|
|
69
66
|
if "function(p,a,c,k,e,d)" in script.text():
|
|
70
67
|
script_data = script.text()
|
|
71
68
|
break
|
|
72
69
|
|
|
73
70
|
if script_data:
|
|
74
71
|
unpacked = Packer.unpack(script_data)
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
unpacked_sec = HTMLHelper(unpacked)
|
|
73
|
+
m3u8_url = unpacked_sec.regex_first(r'sources:\[\{file:"(.*?)"')
|
|
77
74
|
|
|
78
75
|
if not m3u8_url:
|
|
79
76
|
# Son çare: Normal response içinde ara
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
elif match := re.search(r'file:\s*"([^"]*?\.m3u8[^"]*)"', response):
|
|
83
|
-
m3u8_url = match.group(1)
|
|
77
|
+
resp_sec = HTMLHelper(response)
|
|
78
|
+
m3u8_url = resp_sec.regex_first(r'sources:\s*\[\s*\{\s*file:\s*"([^"]+)"') or resp_sec.regex_first(r'file:\s*"([^\"]*?\.m3u8[^"]*)"')
|
|
84
79
|
|
|
85
80
|
if not m3u8_url:
|
|
86
81
|
raise ValueError(f"Filemoon: Video URL bulunamadı. {url}")
|
KekikStream/Extractors/JetTv.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 import ExtractorBase, ExtractResult, Subtitle
|
|
4
|
-
import
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle, HTMLHelper
|
|
4
|
+
import json
|
|
5
5
|
|
|
6
6
|
class JetTv(ExtractorBase):
|
|
7
7
|
name = "JetTv"
|
|
@@ -31,8 +31,8 @@ class JetTv(ExtractorBase):
|
|
|
31
31
|
|
|
32
32
|
# 2. Yöntem: Regex Fallback
|
|
33
33
|
if not master_url:
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
hp = HTMLHelper(document)
|
|
35
|
+
master_url = hp.regex_first(r"(?i)file: '([^']*)'") or master_url
|
|
36
36
|
|
|
37
37
|
if not master_url:
|
|
38
38
|
raise ValueError(f"JetTv: Video kaynağı bulunamadı. {url}")
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import ExtractorBase, ExtractResult
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
|
|
4
4
|
from Kekik.Sifreleme import AESManager
|
|
5
|
-
import
|
|
5
|
+
import json
|
|
6
6
|
|
|
7
7
|
class MixPlayHD(ExtractorBase):
|
|
8
8
|
name = "MixPlayHD"
|
|
@@ -15,12 +15,12 @@ class MixPlayHD(ExtractorBase):
|
|
|
15
15
|
istek = await self.httpx.get(url)
|
|
16
16
|
istek.raise_for_status()
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
hp = HTMLHelper(istek.text)
|
|
19
|
+
be_player_matches = hp.regex_all(r"bePlayer\('([^']+)',\s*'(\{[^\}]+\})'\);")
|
|
20
|
+
if not be_player_matches:
|
|
20
21
|
raise ValueError("bePlayer not found in the response.")
|
|
21
22
|
|
|
22
|
-
be_player_pass =
|
|
23
|
-
be_player_data = be_player_match[2]
|
|
23
|
+
be_player_pass, be_player_data = be_player_matches[0]
|
|
24
24
|
|
|
25
25
|
try:
|
|
26
26
|
decrypted_data = AESManager.decrypt(be_player_data, be_player_pass).replace("\\", "")
|
|
@@ -28,13 +28,12 @@ class MixPlayHD(ExtractorBase):
|
|
|
28
28
|
except Exception as hata:
|
|
29
29
|
raise RuntimeError(f"Decryption failed: {hata}") from hata
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
):
|
|
31
|
+
client_str = decrypted_json.get("schedule", {}).get("client", "")
|
|
32
|
+
video_url = HTMLHelper(client_str).regex_first(r'"video_location":"([^"]+)"')
|
|
33
|
+
if video_url:
|
|
35
34
|
return ExtractResult(
|
|
36
35
|
name = self.name,
|
|
37
|
-
url =
|
|
36
|
+
url = video_url,
|
|
38
37
|
referer = self.main_url,
|
|
39
38
|
subtitles = []
|
|
40
39
|
)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
|
|
4
|
-
from selectolax.parser import HTMLParser
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle, HTMLHelper
|
|
5
4
|
import re
|
|
6
5
|
|
|
7
6
|
class MolyStream(ExtractorBase):
|
|
@@ -10,16 +9,13 @@ class MolyStream(ExtractorBase):
|
|
|
10
9
|
|
|
11
10
|
async def extract(self, url, referer=None) -> ExtractResult:
|
|
12
11
|
if "doctype html" in url:
|
|
13
|
-
secici =
|
|
14
|
-
|
|
15
|
-
video = video_el.attrs.get("src") if video_el else None
|
|
12
|
+
secici = HTMLHelper(url)
|
|
13
|
+
video = secici.select_attr("video#sheplayer source", "src")
|
|
16
14
|
else:
|
|
17
15
|
video = url
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
string = url
|
|
22
|
-
)
|
|
17
|
+
resp_sec = HTMLHelper(url)
|
|
18
|
+
matches = resp_sec.regex_all(r"addSrtFile\(['\"]([^'\"]+\.srt)['\"]\s*,\s*['\"][a-z]{2}['\"]\s*,\s*['\"]([^'\"]+)['\"]")
|
|
23
19
|
|
|
24
20
|
subtitles = [
|
|
25
21
|
Subtitle(name = name, url = self.fix_url(url))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import ExtractorBase, ExtractResult
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
|
|
4
4
|
import re, json
|
|
5
5
|
|
|
6
6
|
class Odnoklassniki(ExtractorBase):
|
|
@@ -45,12 +45,12 @@ class Odnoklassniki(ExtractorBase):
|
|
|
45
45
|
response_text
|
|
46
46
|
)
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
if not
|
|
48
|
+
videos_json = HTMLHelper(response_text).regex_first(r'"videos":(\[.*?\])')
|
|
49
|
+
if not videos_json:
|
|
50
50
|
raise ValueError("No video data found in the response.")
|
|
51
51
|
|
|
52
52
|
try:
|
|
53
|
-
videos = json.loads(
|
|
53
|
+
videos = json.loads(videos_json)
|
|
54
54
|
except json.JSONDecodeError as hata:
|
|
55
55
|
raise ValueError("Failed to parse video data.") from hata
|
|
56
56
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import ExtractorBase, ExtractResult
|
|
4
|
-
import
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
|
|
4
|
+
import json
|
|
5
5
|
|
|
6
6
|
class PeaceMakerst(ExtractorBase):
|
|
7
7
|
name = "PeaceMakerst"
|
|
@@ -36,7 +36,7 @@ class PeaceMakerst(ExtractorBase):
|
|
|
36
36
|
m3u_link = None
|
|
37
37
|
|
|
38
38
|
if "teve2.com.tr\\/embed\\/" in response_text:
|
|
39
|
-
teve2_id =
|
|
39
|
+
teve2_id = HTMLHelper(response_text).regex_first(r"teve2\.com\.tr\\\/embed\\\/(\d+)")
|
|
40
40
|
teve2_url = f"https://www.teve2.com.tr/action/media/{teve2_id}"
|
|
41
41
|
|
|
42
42
|
teve2_response = await self.httpx.get(teve2_url, headers={"Referer": f"https://www.teve2.com.tr/embed/{teve2_id}"})
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import ExtractorBase, ExtractResult
|
|
4
|
-
import re
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
|
|
5
4
|
|
|
6
5
|
class PixelDrain(ExtractorBase):
|
|
7
6
|
name = "PixelDrain"
|
|
@@ -11,11 +10,13 @@ class PixelDrain(ExtractorBase):
|
|
|
11
10
|
if referer:
|
|
12
11
|
self.httpx.headers.update({"Referer": referer})
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
hp = HTMLHelper(url)
|
|
14
|
+
matches = hp.regex_all(r"/u/([^/?]+)|([^\/]+)(?=\?download)")
|
|
15
|
+
if not matches:
|
|
16
16
|
raise ValueError("PixelDrain bağlantısından ID çıkarılamadı.")
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
m = matches[0]
|
|
19
|
+
pixel_id = next((g for g in m if g), None)
|
|
19
20
|
download_link = f"{self.main_url}/api/file/{pixel_id}?download"
|
|
20
21
|
referer_link = f"{self.main_url}/u/{pixel_id}?download"
|
|
21
22
|
|