KekikStream 1.7.1__py3-none-any.whl → 2.2.0__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/Extractor/ExtractorBase.py +20 -9
- KekikStream/Core/Extractor/ExtractorLoader.py +25 -17
- KekikStream/Core/Extractor/ExtractorManager.py +53 -9
- KekikStream/Core/Extractor/ExtractorModels.py +5 -7
- KekikStream/Core/Extractor/YTDLPCache.py +35 -0
- KekikStream/Core/Media/MediaHandler.py +44 -26
- KekikStream/Core/Media/MediaManager.py +0 -3
- KekikStream/Core/Plugin/PluginBase.py +82 -22
- KekikStream/Core/Plugin/PluginLoader.py +11 -7
- KekikStream/Core/Plugin/PluginModels.py +25 -26
- KekikStream/Core/__init__.py +1 -0
- KekikStream/Extractors/CloseLoad.py +21 -7
- KekikStream/Extractors/ContentX.py +21 -6
- KekikStream/Extractors/DonilasPlay.py +86 -0
- KekikStream/Extractors/DzenRu.py +38 -0
- KekikStream/Extractors/ExPlay.py +53 -0
- KekikStream/Extractors/Filemoon.py +78 -0
- KekikStream/Extractors/HDPlayerSystem.py +41 -0
- KekikStream/Extractors/JetTv.py +45 -0
- KekikStream/Extractors/MailRu.py +3 -4
- KekikStream/Extractors/MixPlayHD.py +2 -3
- KekikStream/Extractors/MixTiger.py +57 -0
- KekikStream/Extractors/MolyStream.py +5 -5
- KekikStream/Extractors/Odnoklassniki.py +13 -7
- KekikStream/Extractors/PeaceMakerst.py +10 -5
- KekikStream/Extractors/PixelDrain.py +1 -2
- KekikStream/Extractors/PlayerFilmIzle.py +65 -0
- KekikStream/Extractors/RapidVid.py +23 -8
- KekikStream/Extractors/SetPlay.py +66 -0
- KekikStream/Extractors/SetPrime.py +45 -0
- KekikStream/Extractors/SibNet.py +2 -3
- KekikStream/Extractors/Sobreatsesuyp.py +4 -5
- KekikStream/Extractors/TRsTX.py +4 -5
- KekikStream/Extractors/TauVideo.py +2 -3
- KekikStream/Extractors/TurboImgz.py +2 -3
- KekikStream/Extractors/TurkeyPlayer.py +34 -0
- KekikStream/Extractors/VCTPlay.py +41 -0
- KekikStream/Extractors/VidHide.py +81 -0
- KekikStream/Extractors/VidMoly.py +55 -34
- KekikStream/Extractors/VidMoxy.py +2 -3
- KekikStream/Extractors/VidPapi.py +89 -0
- KekikStream/Extractors/VideoSeyred.py +3 -4
- KekikStream/Extractors/YTDLP.py +211 -0
- KekikStream/Extractors/YildizKisaFilm.py +41 -0
- KekikStream/Plugins/BelgeselX.py +196 -0
- KekikStream/Plugins/DiziBox.py +25 -34
- KekikStream/Plugins/DiziPal.py +24 -35
- KekikStream/Plugins/DiziYou.py +54 -37
- KekikStream/Plugins/Dizilla.py +66 -46
- KekikStream/Plugins/FilmBip.py +142 -0
- KekikStream/Plugins/FilmMakinesi.py +36 -28
- KekikStream/Plugins/FilmModu.py +20 -24
- KekikStream/Plugins/FullHDFilm.py +220 -0
- KekikStream/Plugins/FullHDFilmizlesene.py +9 -15
- KekikStream/Plugins/HDFilmCehennemi.py +141 -69
- KekikStream/Plugins/JetFilmizle.py +85 -52
- KekikStream/Plugins/KultFilmler.py +217 -0
- KekikStream/Plugins/RecTV.py +22 -34
- KekikStream/Plugins/RoketDizi.py +222 -0
- KekikStream/Plugins/SelcukFlix.py +328 -0
- KekikStream/Plugins/SetFilmIzle.py +252 -0
- KekikStream/Plugins/SezonlukDizi.py +54 -21
- KekikStream/Plugins/SineWix.py +17 -29
- KekikStream/Plugins/Sinefy.py +241 -0
- KekikStream/Plugins/SinemaCX.py +154 -0
- KekikStream/Plugins/Sinezy.py +143 -0
- KekikStream/Plugins/SuperFilmGeldi.py +130 -0
- KekikStream/Plugins/UgurFilm.py +13 -19
- KekikStream/__init__.py +47 -56
- KekikStream/requirements.txt +3 -4
- kekikstream-2.2.0.dist-info/METADATA +312 -0
- kekikstream-2.2.0.dist-info/RECORD +81 -0
- KekikStream/Extractors/FourCX.py +0 -7
- KekikStream/Extractors/FourPichive.py +0 -7
- KekikStream/Extractors/FourPlayRu.py +0 -7
- KekikStream/Extractors/HDStreamAble.py +0 -7
- KekikStream/Extractors/Hotlinger.py +0 -7
- KekikStream/Extractors/OkRuHTTP.py +0 -7
- KekikStream/Extractors/OkRuSSL.py +0 -7
- KekikStream/Extractors/Pichive.py +0 -7
- KekikStream/Extractors/PlayRu.py +0 -7
- KekikStream/Extractors/VidMolyMe.py +0 -7
- kekikstream-1.7.1.dist-info/METADATA +0 -109
- kekikstream-1.7.1.dist-info/RECORD +0 -63
- {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.dist-info}/WHEEL +0 -0
- {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.dist-info}/entry_points.txt +0 -0
- {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.dist-info}/top_level.txt +0 -0
|
@@ -7,6 +7,12 @@ class Odnoklassniki(ExtractorBase):
|
|
|
7
7
|
name = "Odnoklassniki"
|
|
8
8
|
main_url = "https://odnoklassniki.ru"
|
|
9
9
|
|
|
10
|
+
# Birden fazla domain destekle
|
|
11
|
+
supported_domains = ["odnoklassniki.ru", "ok.ru"]
|
|
12
|
+
|
|
13
|
+
def can_handle_url(self, url: str) -> bool:
|
|
14
|
+
return any(domain in url for domain in self.supported_domains)
|
|
15
|
+
|
|
10
16
|
async def extract(self, url, referer=None) -> ExtractResult:
|
|
11
17
|
if "/video/" in url:
|
|
12
18
|
url = url.replace("/video/", "/videoembed/")
|
|
@@ -20,7 +26,7 @@ class Odnoklassniki(ExtractorBase):
|
|
|
20
26
|
"Origin" : self.main_url,
|
|
21
27
|
"User-Agent" : "Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0",
|
|
22
28
|
}
|
|
23
|
-
self.
|
|
29
|
+
self.httpx.headers.update(headers)
|
|
24
30
|
|
|
25
31
|
try:
|
|
26
32
|
istek = await self.fetch_with_redirects(url)
|
|
@@ -82,18 +88,18 @@ class Odnoklassniki(ExtractorBase):
|
|
|
82
88
|
best_video = f"https:{best_video}"
|
|
83
89
|
|
|
84
90
|
return ExtractResult(
|
|
85
|
-
name
|
|
86
|
-
url
|
|
87
|
-
referer
|
|
88
|
-
|
|
89
|
-
subtitles
|
|
91
|
+
name = self.name,
|
|
92
|
+
url = best_video,
|
|
93
|
+
referer = referer,
|
|
94
|
+
user_agent = headers.get("User-Agent", None),
|
|
95
|
+
subtitles = []
|
|
90
96
|
)
|
|
91
97
|
|
|
92
98
|
async def fetch_with_redirects(self, url, max_redirects=5):
|
|
93
99
|
"""Yönlendirmeleri takip eden bir fonksiyon"""
|
|
94
100
|
redirects = 0
|
|
95
101
|
while redirects < max_redirects:
|
|
96
|
-
istek = await self.
|
|
102
|
+
istek = await self.httpx.get(url, follow_redirects=False)
|
|
97
103
|
|
|
98
104
|
if istek.status_code not in [301, 302]:
|
|
99
105
|
break # Yönlendirme yoksa çık
|
|
@@ -7,16 +7,22 @@ class PeaceMakerst(ExtractorBase):
|
|
|
7
7
|
name = "PeaceMakerst"
|
|
8
8
|
main_url = "https://peacemakerst.com"
|
|
9
9
|
|
|
10
|
+
# Birden fazla domain destekle
|
|
11
|
+
supported_domains = ["peacemakerst.com", "hdstreamable.com"]
|
|
12
|
+
|
|
13
|
+
def can_handle_url(self, url: str) -> bool:
|
|
14
|
+
return any(domain in url for domain in self.supported_domains)
|
|
15
|
+
|
|
10
16
|
async def extract(self, url, referer=None) -> ExtractResult:
|
|
11
17
|
if referer:
|
|
12
|
-
self.
|
|
18
|
+
self.httpx.headers.update({"Referer": referer})
|
|
13
19
|
|
|
14
|
-
self.
|
|
20
|
+
self.httpx.headers.update({
|
|
15
21
|
"Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
|
|
16
22
|
"X-Requested-With" : "XMLHttpRequest"
|
|
17
23
|
})
|
|
18
24
|
|
|
19
|
-
response = await self.
|
|
25
|
+
response = await self.httpx.post(
|
|
20
26
|
url = f"{url}?do=getVideo",
|
|
21
27
|
data = {
|
|
22
28
|
"hash" : url.split("video/")[-1],
|
|
@@ -33,7 +39,7 @@ class PeaceMakerst(ExtractorBase):
|
|
|
33
39
|
teve2_id = re.search(r"teve2\.com\.tr\\\/embed\\\/(\d+)", response_text)[1]
|
|
34
40
|
teve2_url = f"https://www.teve2.com.tr/action/media/{teve2_id}"
|
|
35
41
|
|
|
36
|
-
teve2_response = await self.
|
|
42
|
+
teve2_response = await self.httpx.get(teve2_url, headers={"Referer": f"https://www.teve2.com.tr/embed/{teve2_id}"})
|
|
37
43
|
teve2_response.raise_for_status()
|
|
38
44
|
teve2_json = teve2_response.json()
|
|
39
45
|
|
|
@@ -53,6 +59,5 @@ class PeaceMakerst(ExtractorBase):
|
|
|
53
59
|
name = self.name,
|
|
54
60
|
url = m3u_link,
|
|
55
61
|
referer = url,
|
|
56
|
-
headers = {},
|
|
57
62
|
subtitles = []
|
|
58
63
|
)
|
|
@@ -9,7 +9,7 @@ class PixelDrain(ExtractorBase):
|
|
|
9
9
|
|
|
10
10
|
async def extract(self, url, referer=None) -> ExtractResult:
|
|
11
11
|
if referer:
|
|
12
|
-
self.
|
|
12
|
+
self.httpx.headers.update({"Referer": referer})
|
|
13
13
|
|
|
14
14
|
pixel_id_match = re.search(r"/u/([^/?]+)|([^\/]+)(?=\?download)", url)
|
|
15
15
|
if not pixel_id_match:
|
|
@@ -23,6 +23,5 @@ class PixelDrain(ExtractorBase):
|
|
|
23
23
|
name = f"{self.name} - {pixel_id}",
|
|
24
24
|
url = download_link,
|
|
25
25
|
referer = referer_link,
|
|
26
|
-
headers = {},
|
|
27
26
|
subtitles = []
|
|
28
27
|
)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
class PlayerFilmIzle(ExtractorBase):
|
|
7
|
+
name = "PlayerFilmIzle"
|
|
8
|
+
main_url = "https://player.filmizle.in"
|
|
9
|
+
|
|
10
|
+
def can_handle_url(self, url: str) -> bool:
|
|
11
|
+
return "filmizle.in" in url or "fireplayer" in url.lower()
|
|
12
|
+
|
|
13
|
+
async def extract(self, url: str, referer: str = None) -> ExtractResult:
|
|
14
|
+
# Kotlin tarafında referer mainUrl olarak zorlanmış
|
|
15
|
+
ext_ref = self.main_url
|
|
16
|
+
self.httpx.headers.update({"Referer": ext_ref})
|
|
17
|
+
|
|
18
|
+
istek = await self.httpx.get(url)
|
|
19
|
+
video_req = istek.text
|
|
20
|
+
|
|
21
|
+
subtitles = []
|
|
22
|
+
if sub_match := re.search(r'playerjsSubtitle = "([^"]*)"', video_req, re.IGNORECASE):
|
|
23
|
+
sub_yakala = sub_match.group(1)
|
|
24
|
+
# Format örneği: [dil]url
|
|
25
|
+
# Kotlin kodunda: subYakala.substringAfter("]") -> url
|
|
26
|
+
# subYakala.substringBefore("]").removePrefix("[") -> lang
|
|
27
|
+
if "]" in sub_yakala:
|
|
28
|
+
sub_lang_raw, sub_url = sub_yakala.split("]", 1)
|
|
29
|
+
sub_lang = sub_lang_raw.replace("[", "")
|
|
30
|
+
subtitles.append(Subtitle(name=sub_lang, url=sub_url))
|
|
31
|
+
|
|
32
|
+
# Data yakalama: FirePlayer|DATA|...
|
|
33
|
+
data_match = re.search(r'FirePlayer\|([^|]+)\|', video_req, re.IGNORECASE)
|
|
34
|
+
data_val = data_match.group(1) if data_match else None
|
|
35
|
+
|
|
36
|
+
if not data_val:
|
|
37
|
+
raise ValueError("PlayerFilmIzle: Data bulunamadı")
|
|
38
|
+
|
|
39
|
+
url_post = f"{self.main_url}/player/index.php?data={data_val}&do=getVideo"
|
|
40
|
+
|
|
41
|
+
post_headers = {
|
|
42
|
+
"Referer": ext_ref,
|
|
43
|
+
"X-Requested-With": "XMLHttpRequest"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# Kotlin'de post data: "hash" -> data, "r" -> ""
|
|
47
|
+
post_data = {"hash": data_val, "r": ""}
|
|
48
|
+
|
|
49
|
+
response = await self.httpx.post(url_post, data=post_data, headers=post_headers)
|
|
50
|
+
get_url = response.text.replace("\\", "")
|
|
51
|
+
|
|
52
|
+
m3u8_url = ""
|
|
53
|
+
if url_yakala := re.search(r'"securedLink":"([^"]*)"', get_url, re.IGNORECASE):
|
|
54
|
+
m3u8_url = url_yakala.group(1)
|
|
55
|
+
|
|
56
|
+
if not m3u8_url:
|
|
57
|
+
raise ValueError("PlayerFilmIzle: M3U8 linki bulunamadı")
|
|
58
|
+
|
|
59
|
+
return ExtractResult(
|
|
60
|
+
name = self.name,
|
|
61
|
+
url = m3u8_url,
|
|
62
|
+
referer = ext_ref,
|
|
63
|
+
user_agent = self.httpx.headers.get("User-Agent", None),
|
|
64
|
+
subtitles = subtitles
|
|
65
|
+
)
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
3
|
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
|
|
4
|
-
from Kekik.Sifreleme import Packer, HexCodec
|
|
4
|
+
from Kekik.Sifreleme import Packer, HexCodec, StreamDecoder
|
|
5
5
|
import re, base64
|
|
6
6
|
|
|
7
7
|
class RapidVid(ExtractorBase):
|
|
8
8
|
name = "RapidVid"
|
|
9
9
|
main_url = "https://rapidvid.net"
|
|
10
10
|
|
|
11
|
+
# Birden fazla domain destekle
|
|
12
|
+
supported_domains = ["rapidvid.net", "rapid.filmmakinesi.to"]
|
|
13
|
+
|
|
14
|
+
def can_handle_url(self, url: str) -> bool:
|
|
15
|
+
return any(domain in url for domain in self.supported_domains)
|
|
16
|
+
|
|
11
17
|
async def extract(self, url, referer=None) -> ExtractResult:
|
|
12
18
|
if referer:
|
|
13
|
-
self.
|
|
19
|
+
self.httpx.headers.update({"Referer": referer})
|
|
14
20
|
|
|
15
|
-
istek = await self.
|
|
21
|
+
istek = await self.httpx.get(url)
|
|
16
22
|
istek.raise_for_status()
|
|
17
23
|
|
|
18
24
|
subtitles = []
|
|
@@ -33,15 +39,25 @@ class RapidVid(ExtractorBase):
|
|
|
33
39
|
subtitles.append(Subtitle(name=decoded_lang, url=sub_url.replace("\\", "")))
|
|
34
40
|
|
|
35
41
|
try:
|
|
42
|
+
decoded_url = None
|
|
43
|
+
|
|
44
|
+
# Method 1: file": "..." pattern (HexCodec)
|
|
36
45
|
if extracted_value := re.search(r'file": "(.*)",', istek.text):
|
|
37
46
|
escaped_hex = extracted_value[1]
|
|
38
47
|
decoded_url = HexCodec.decode(escaped_hex)
|
|
39
|
-
else:
|
|
40
|
-
av_encoded = re.search(r"av\('([^']+)'\)", istek.text)
|
|
41
|
-
if not av_encoded:
|
|
42
|
-
raise ValueError("AV encoding not found.")
|
|
43
48
|
|
|
49
|
+
# Method 2: av('...') pattern
|
|
50
|
+
elif av_encoded := re.search(r"av\('([^']+)'\)", istek.text):
|
|
44
51
|
decoded_url = self.decode_secret(av_encoded[1])
|
|
52
|
+
|
|
53
|
+
# Method 3: Packed script with dc_* function (StreamDecoder)
|
|
54
|
+
elif Packer.detect_packed(istek.text):
|
|
55
|
+
unpacked = Packer.unpack(istek.text)
|
|
56
|
+
decoded_url = StreamDecoder.extract_stream_url(unpacked)
|
|
57
|
+
|
|
58
|
+
if not decoded_url:
|
|
59
|
+
raise ValueError("No valid video URL pattern found.")
|
|
60
|
+
|
|
45
61
|
except Exception as hata:
|
|
46
62
|
raise RuntimeError(f"Extraction failed: {hata}") from hata
|
|
47
63
|
|
|
@@ -49,7 +65,6 @@ class RapidVid(ExtractorBase):
|
|
|
49
65
|
name = self.name,
|
|
50
66
|
url = decoded_url,
|
|
51
67
|
referer = self.main_url,
|
|
52
|
-
headers = {},
|
|
53
68
|
subtitles = subtitles
|
|
54
69
|
)
|
|
55
70
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult
|
|
4
|
+
from urllib.parse import urlparse, parse_qs
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
class SetPlay(ExtractorBase):
|
|
8
|
+
name = "SetPlay"
|
|
9
|
+
main_url = "https://setplay.shop"
|
|
10
|
+
|
|
11
|
+
# Birden fazla domain destekle
|
|
12
|
+
supported_domains = ["setplay.cfd", "setplay.shop", "setplay.site"]
|
|
13
|
+
|
|
14
|
+
def can_handle_url(self, url: str) -> bool:
|
|
15
|
+
return any(domain in url for domain in self.supported_domains)
|
|
16
|
+
|
|
17
|
+
async def extract(self, url, referer=None) -> ExtractResult:
|
|
18
|
+
ext_ref = referer or ""
|
|
19
|
+
|
|
20
|
+
if referer:
|
|
21
|
+
self.httpx.headers.update({"Referer": referer})
|
|
22
|
+
|
|
23
|
+
# Dinamik base URL kullan
|
|
24
|
+
base_url = self.get_base_url(url)
|
|
25
|
+
|
|
26
|
+
istek = await self.httpx.get(url)
|
|
27
|
+
istek.raise_for_status()
|
|
28
|
+
|
|
29
|
+
# videoUrl çıkar
|
|
30
|
+
video_url_match = re.search(r'videoUrl":"([^",]+)"', istek.text)
|
|
31
|
+
if not video_url_match:
|
|
32
|
+
raise ValueError("videoUrl not found")
|
|
33
|
+
video_url = video_url_match[1].replace("\\", "")
|
|
34
|
+
|
|
35
|
+
# videoServer çıkar
|
|
36
|
+
video_server_match = re.search(r'videoServer":"([^",]+)"', istek.text)
|
|
37
|
+
if not video_server_match:
|
|
38
|
+
raise ValueError("videoServer not found")
|
|
39
|
+
video_server = video_server_match[1]
|
|
40
|
+
|
|
41
|
+
# title çıkar (opsiyonel)
|
|
42
|
+
title_match = re.search(r'title":"([^",]+)"', istek.text)
|
|
43
|
+
title_base = title_match[1].split(".")[-1] if title_match else "Unknown"
|
|
44
|
+
|
|
45
|
+
# partKey logic
|
|
46
|
+
parsed = urlparse(url)
|
|
47
|
+
params = parse_qs(parsed.query)
|
|
48
|
+
part_key = params.get("partKey", [""])[0]
|
|
49
|
+
|
|
50
|
+
name_suffix = ""
|
|
51
|
+
if "turkcedublaj" in part_key.lower():
|
|
52
|
+
name_suffix = "Dublaj"
|
|
53
|
+
elif "turkcealtyazi" in part_key.lower():
|
|
54
|
+
name_suffix = "Altyazı"
|
|
55
|
+
else:
|
|
56
|
+
name_suffix = title_base
|
|
57
|
+
|
|
58
|
+
# M3U8 link oluştur - base_url kullan (main_url yerine)
|
|
59
|
+
m3u_link = f"{base_url}{video_url}?s={video_server}"
|
|
60
|
+
|
|
61
|
+
return ExtractResult(
|
|
62
|
+
name = f"{self.name} - {name_suffix}",
|
|
63
|
+
url = m3u_link,
|
|
64
|
+
referer = url,
|
|
65
|
+
subtitles = []
|
|
66
|
+
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult
|
|
4
|
+
from urllib.parse import urlparse, parse_qs
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
class SetPrime(ExtractorBase):
|
|
8
|
+
name = "SetPrime"
|
|
9
|
+
main_url = "https://setplay.site"
|
|
10
|
+
|
|
11
|
+
async def extract(self, url, referer=None) -> ExtractResult:
|
|
12
|
+
# URL parsing
|
|
13
|
+
parsed = urlparse(url)
|
|
14
|
+
params = parse_qs(parsed.query)
|
|
15
|
+
part_key = params.get("partKey", [""])[0].upper()
|
|
16
|
+
clean_url = url.split("?partKey=")[0]
|
|
17
|
+
|
|
18
|
+
# POST URL: embed?i= -> embed/get?i=
|
|
19
|
+
post_url = clean_url.replace("embed?i=", "embed/get?i=")
|
|
20
|
+
|
|
21
|
+
response = await self.httpx.post(
|
|
22
|
+
url = post_url,
|
|
23
|
+
headers = {"Referer": clean_url}
|
|
24
|
+
)
|
|
25
|
+
response.raise_for_status()
|
|
26
|
+
|
|
27
|
+
# Links parse
|
|
28
|
+
links_match = re.search(r'Links":\["([^"\]]+)"', response.text)
|
|
29
|
+
if not links_match:
|
|
30
|
+
raise ValueError("Links not found in SetPrime response")
|
|
31
|
+
|
|
32
|
+
link_suffix = links_match.group(1)
|
|
33
|
+
if not link_suffix.startswith("/"):
|
|
34
|
+
raise ValueError("Links not valid (must start with /)")
|
|
35
|
+
|
|
36
|
+
m3u_link = f"{self.main_url}{link_suffix}"
|
|
37
|
+
|
|
38
|
+
display_name = f"{self.name} - {part_key}" if part_key else self.name
|
|
39
|
+
|
|
40
|
+
return ExtractResult(
|
|
41
|
+
name = display_name,
|
|
42
|
+
url = m3u_link,
|
|
43
|
+
referer = clean_url,
|
|
44
|
+
subtitles = []
|
|
45
|
+
)
|
KekikStream/Extractors/SibNet.py
CHANGED
|
@@ -9,9 +9,9 @@ class SibNet(ExtractorBase):
|
|
|
9
9
|
|
|
10
10
|
async def extract(self, url, referer=None) -> ExtractResult:
|
|
11
11
|
if referer:
|
|
12
|
-
self.
|
|
12
|
+
self.httpx.headers.update({"Referer": referer})
|
|
13
13
|
|
|
14
|
-
response = await self.
|
|
14
|
+
response = await self.httpx.get(url)
|
|
15
15
|
response.raise_for_status()
|
|
16
16
|
|
|
17
17
|
match = re.search(r'player\.src\(\[\{src: \"([^\"]+)\"', response.text)
|
|
@@ -24,6 +24,5 @@ class SibNet(ExtractorBase):
|
|
|
24
24
|
name = self.name,
|
|
25
25
|
url = m3u_link,
|
|
26
26
|
referer = url,
|
|
27
|
-
headers = {},
|
|
28
27
|
subtitles = []
|
|
29
28
|
)
|
|
@@ -9,9 +9,9 @@ class Sobreatsesuyp(ExtractorBase):
|
|
|
9
9
|
|
|
10
10
|
async def extract(self, url, referer=None) -> ExtractResult:
|
|
11
11
|
if referer:
|
|
12
|
-
self.
|
|
12
|
+
self.httpx.headers.update({"Referer": referer})
|
|
13
13
|
|
|
14
|
-
istek = await self.
|
|
14
|
+
istek = await self.httpx.get(url)
|
|
15
15
|
istek.raise_for_status()
|
|
16
16
|
|
|
17
17
|
file_match = re.search(r'file\":\"([^\"]+)', istek.text)
|
|
@@ -21,7 +21,7 @@ class Sobreatsesuyp(ExtractorBase):
|
|
|
21
21
|
file_path = file_match[1].replace("\\", "")
|
|
22
22
|
post_link = f"{self.main_url}/{file_path}"
|
|
23
23
|
|
|
24
|
-
post_istek = await self.
|
|
24
|
+
post_istek = await self.httpx.post(post_link)
|
|
25
25
|
post_istek.raise_for_status()
|
|
26
26
|
|
|
27
27
|
try:
|
|
@@ -41,7 +41,7 @@ class Sobreatsesuyp(ExtractorBase):
|
|
|
41
41
|
continue
|
|
42
42
|
|
|
43
43
|
playlist_url = f"{self.main_url}/playlist/{file.lstrip('/')}.txt"
|
|
44
|
-
playlist_request = await self.
|
|
44
|
+
playlist_request = await self.httpx.post(playlist_url, headers={"Referer": referer or self.main_url})
|
|
45
45
|
playlist_request.raise_for_status()
|
|
46
46
|
|
|
47
47
|
all_results.append(
|
|
@@ -49,7 +49,6 @@ class Sobreatsesuyp(ExtractorBase):
|
|
|
49
49
|
name = f"{self.name} - {title}",
|
|
50
50
|
url = playlist_request.text,
|
|
51
51
|
referer = self.main_url,
|
|
52
|
-
headers = {},
|
|
53
52
|
subtitles = []
|
|
54
53
|
)
|
|
55
54
|
)
|
KekikStream/Extractors/TRsTX.py
CHANGED
|
@@ -9,9 +9,9 @@ class TRsTX(ExtractorBase):
|
|
|
9
9
|
|
|
10
10
|
async def extract(self, url, referer=None) -> list[ExtractResult]:
|
|
11
11
|
if referer:
|
|
12
|
-
self.
|
|
12
|
+
self.httpx.headers.update({"Referer": referer})
|
|
13
13
|
|
|
14
|
-
istek = await self.
|
|
14
|
+
istek = await self.httpx.get(url)
|
|
15
15
|
istek.raise_for_status()
|
|
16
16
|
|
|
17
17
|
file_match = re.search(r'file\":\"([^\"]+)', istek.text)
|
|
@@ -21,7 +21,7 @@ class TRsTX(ExtractorBase):
|
|
|
21
21
|
file_path = file_match[1].replace("\\", "")
|
|
22
22
|
post_link = f"{self.main_url}/{file_path}"
|
|
23
23
|
|
|
24
|
-
post_istek = await self.
|
|
24
|
+
post_istek = await self.httpx.post(post_link)
|
|
25
25
|
post_istek.raise_for_status()
|
|
26
26
|
|
|
27
27
|
try:
|
|
@@ -42,7 +42,7 @@ class TRsTX(ExtractorBase):
|
|
|
42
42
|
continue
|
|
43
43
|
|
|
44
44
|
playlist_url = f"{self.main_url}/playlist/{file.lstrip('/')}.txt"
|
|
45
|
-
playlist_request = await self.
|
|
45
|
+
playlist_request = await self.httpx.post(playlist_url, headers={"Referer": referer or self.main_url})
|
|
46
46
|
playlist_request.raise_for_status()
|
|
47
47
|
|
|
48
48
|
video_data = playlist_request.text
|
|
@@ -57,7 +57,6 @@ class TRsTX(ExtractorBase):
|
|
|
57
57
|
name = f"{self.name} - {title}",
|
|
58
58
|
url = video_data,
|
|
59
59
|
referer = self.main_url,
|
|
60
|
-
headers = {},
|
|
61
60
|
subtitles = []
|
|
62
61
|
)
|
|
63
62
|
)
|
|
@@ -8,12 +8,12 @@ class TauVideo(ExtractorBase):
|
|
|
8
8
|
|
|
9
9
|
async def extract(self, url, referer=None) -> list[ExtractResult]:
|
|
10
10
|
if referer:
|
|
11
|
-
self.
|
|
11
|
+
self.httpx.headers.update({"Referer": referer})
|
|
12
12
|
|
|
13
13
|
video_key = url.split("/")[-1]
|
|
14
14
|
api_url = f"{self.main_url}/api/video/{video_key}"
|
|
15
15
|
|
|
16
|
-
response = await self.
|
|
16
|
+
response = await self.httpx.get(api_url)
|
|
17
17
|
response.raise_for_status()
|
|
18
18
|
|
|
19
19
|
api_data = response.json()
|
|
@@ -26,7 +26,6 @@ class TauVideo(ExtractorBase):
|
|
|
26
26
|
name = f"{self.name} - {video['label']}",
|
|
27
27
|
url = video["url"],
|
|
28
28
|
referer = referer or self.main_url,
|
|
29
|
-
headers = {},
|
|
30
29
|
subtitles = []
|
|
31
30
|
)
|
|
32
31
|
for video in api_data["urls"]
|
|
@@ -9,9 +9,9 @@ class TurboImgz(ExtractorBase):
|
|
|
9
9
|
|
|
10
10
|
async def extract(self, url, referer=None) -> ExtractResult:
|
|
11
11
|
if referer:
|
|
12
|
-
self.
|
|
12
|
+
self.httpx.headers.update({"Referer": referer})
|
|
13
13
|
|
|
14
|
-
istek = await self.
|
|
14
|
+
istek = await self.httpx.get(url)
|
|
15
15
|
istek.raise_for_status()
|
|
16
16
|
|
|
17
17
|
if video_match := re.search(r'file: "(.*)",', istek.text):
|
|
@@ -19,7 +19,6 @@ class TurboImgz(ExtractorBase):
|
|
|
19
19
|
name = self.name,
|
|
20
20
|
url = video_match[1],
|
|
21
21
|
referer = referer or self.main_url,
|
|
22
|
-
headers = {},
|
|
23
22
|
subtitles = []
|
|
24
23
|
)
|
|
25
24
|
else:
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
|
|
4
|
+
import re, json
|
|
5
|
+
|
|
6
|
+
class TurkeyPlayer(ExtractorBase):
|
|
7
|
+
name = "TurkeyPlayer"
|
|
8
|
+
main_url = "https://watch.turkeyplayer.com/"
|
|
9
|
+
|
|
10
|
+
async def extract(self, url: str, referer: str = None) -> ExtractResult:
|
|
11
|
+
if referer:
|
|
12
|
+
self.httpx.headers.update({"Referer": referer})
|
|
13
|
+
|
|
14
|
+
istek = await self.httpx.get(url)
|
|
15
|
+
page_content = istek.text
|
|
16
|
+
|
|
17
|
+
video_json_match = re.search(r'var\s+video\s*=\s*(\{.*?\});', page_content, re.DOTALL)
|
|
18
|
+
if not video_json_match:
|
|
19
|
+
raise ValueError("TurkeyPlayer: Video JSON bulunamadı")
|
|
20
|
+
|
|
21
|
+
video_data = json.loads(video_json_match.group(1))
|
|
22
|
+
|
|
23
|
+
video_id = video_data.get("id")
|
|
24
|
+
video_md5 = video_data.get("md5")
|
|
25
|
+
|
|
26
|
+
master_url = f"https://watch.turkeyplayer.com/m3u8/8/{video_md5}/master.txt?s=1&id={video_id}&cache=1"
|
|
27
|
+
|
|
28
|
+
return ExtractResult(
|
|
29
|
+
name = self.name,
|
|
30
|
+
url = master_url,
|
|
31
|
+
referer = referer or url,
|
|
32
|
+
user_agent = self.httpx.headers.get("User-Agent", ""),
|
|
33
|
+
subtitles = []
|
|
34
|
+
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult
|
|
4
|
+
from urllib.parse import urlparse, parse_qs
|
|
5
|
+
|
|
6
|
+
class VCTPlay(ExtractorBase):
|
|
7
|
+
name = "VCTPlay"
|
|
8
|
+
main_url = "https://vctplay.site"
|
|
9
|
+
|
|
10
|
+
async def extract(self, url, referer=None) -> ExtractResult:
|
|
11
|
+
if referer:
|
|
12
|
+
self.httpx.headers.update({"Referer": referer})
|
|
13
|
+
|
|
14
|
+
# URL'den video ID'sini çıkar
|
|
15
|
+
# https://vctplay.site/video/2hjDGco5exdv -> 2hjDGco5exdv
|
|
16
|
+
video_id = url.split("/")[-1]
|
|
17
|
+
if "?" in video_id:
|
|
18
|
+
video_id = video_id.split("?")[0]
|
|
19
|
+
|
|
20
|
+
# Manifests URL oluştur
|
|
21
|
+
master_url = f"{self.main_url}/manifests/{video_id}/master.txt"
|
|
22
|
+
|
|
23
|
+
# partKey'den isim belirle
|
|
24
|
+
parsed = urlparse(url)
|
|
25
|
+
params = parse_qs(parsed.query)
|
|
26
|
+
part_key = params.get("partKey", [""])[0]
|
|
27
|
+
|
|
28
|
+
name_suffix = ""
|
|
29
|
+
if "turkcedublaj" in part_key.lower():
|
|
30
|
+
name_suffix = "Dublaj"
|
|
31
|
+
elif "turkcealtyazi" in part_key.lower():
|
|
32
|
+
name_suffix = "Altyazı"
|
|
33
|
+
|
|
34
|
+
display_name = f"{self.name} - {name_suffix}" if name_suffix else self.name
|
|
35
|
+
|
|
36
|
+
return ExtractResult(
|
|
37
|
+
name = display_name,
|
|
38
|
+
url = master_url,
|
|
39
|
+
referer = f"{self.main_url}/",
|
|
40
|
+
subtitles = []
|
|
41
|
+
)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
|
|
4
|
+
from Kekik.Sifreleme import Packer
|
|
5
|
+
from parsel import Selector
|
|
6
|
+
import re
|
|
7
|
+
|
|
8
|
+
class VidHide(ExtractorBase):
|
|
9
|
+
name = "VidHide"
|
|
10
|
+
main_url = "https://vidhidepro.com"
|
|
11
|
+
|
|
12
|
+
# Birden fazla domain destekle
|
|
13
|
+
supported_domains = ["vidhidepro.com", "vidhide.com", "rubyvidhub.com"]
|
|
14
|
+
|
|
15
|
+
def can_handle_url(self, url: str) -> bool:
|
|
16
|
+
return any(domain in url for domain in self.supported_domains)
|
|
17
|
+
|
|
18
|
+
def get_embed_url(self, url: str) -> str:
|
|
19
|
+
if "/d/" in url:
|
|
20
|
+
return url.replace("/d/", "/v/")
|
|
21
|
+
elif "/download/" in url:
|
|
22
|
+
return url.replace("/download/", "/v/")
|
|
23
|
+
elif "/file/" in url:
|
|
24
|
+
return url.replace("/file/", "/v/")
|
|
25
|
+
else:
|
|
26
|
+
return url.replace("/f/", "/v/")
|
|
27
|
+
|
|
28
|
+
async def extract(self, url: str, referer: str = None) -> ExtractResult:
|
|
29
|
+
# Dinamik base URL kullan
|
|
30
|
+
base_url = self.get_base_url(url)
|
|
31
|
+
|
|
32
|
+
if referer:
|
|
33
|
+
self.httpx.headers.update({"Referer": referer})
|
|
34
|
+
|
|
35
|
+
self.httpx.headers.update({
|
|
36
|
+
"Sec-Fetch-Dest" : "empty",
|
|
37
|
+
"Sec-Fetch-Mode" : "cors",
|
|
38
|
+
"Sec-Fetch-Site" : "cross-site",
|
|
39
|
+
"Origin" : base_url,
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
embed_url = self.get_embed_url(url)
|
|
43
|
+
istek = await self.httpx.get(embed_url)
|
|
44
|
+
response = istek.text
|
|
45
|
+
|
|
46
|
+
script = None
|
|
47
|
+
if "eval(function" in response:
|
|
48
|
+
try:
|
|
49
|
+
unpacked = Packer.unpack(response)
|
|
50
|
+
if "var links" in unpacked:
|
|
51
|
+
script = unpacked.split("var links")[1]
|
|
52
|
+
else:
|
|
53
|
+
script = unpacked
|
|
54
|
+
except Exception:
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
if not script:
|
|
58
|
+
if matches := re.search(r'sources:\s*(\[.*?\])', response, re.DOTALL):
|
|
59
|
+
script = matches.group(1)
|
|
60
|
+
|
|
61
|
+
m3u8_url = None
|
|
62
|
+
if script:
|
|
63
|
+
# m3u8 urls could be prefixed by 'file:', 'hls2:' or 'hls4:', so we just match ':'
|
|
64
|
+
if match := re.search(r':\s*"([^"]*?m3u8[^"]*?)"', script):
|
|
65
|
+
m3u8_url = match.group(1)
|
|
66
|
+
|
|
67
|
+
if not m3u8_url:
|
|
68
|
+
# Fallback direct search in response if unpacking failed or structure changed
|
|
69
|
+
if match := re.search(r'file:"(.*?\.m3u8.*?)"', response):
|
|
70
|
+
m3u8_url = match.group(1)
|
|
71
|
+
|
|
72
|
+
if not m3u8_url:
|
|
73
|
+
raise ValueError(f"VidHide: Video URL bulunamadı. {url}")
|
|
74
|
+
|
|
75
|
+
return ExtractResult(
|
|
76
|
+
name = self.name,
|
|
77
|
+
url = self.fix_url(m3u8_url),
|
|
78
|
+
referer = f"{base_url}/",
|
|
79
|
+
user_agent = self.httpx.headers.get("User-Agent", ""),
|
|
80
|
+
subtitles = []
|
|
81
|
+
)
|