KekikStream 0.2.3__py3-none-any.whl → 0.5.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.
- KekikStream/CLI/__init__.py +1 -1
- KekikStream/CLI/pypi_kontrol.py +30 -0
- KekikStream/Core/ExtractorBase.py +13 -2
- KekikStream/Core/ExtractorLoader.py +31 -10
- KekikStream/Core/ExtractorModels.py +2 -0
- KekikStream/Core/MediaHandler.py +70 -30
- KekikStream/Core/PluginBase.py +6 -5
- KekikStream/Core/PluginLoader.py +3 -5
- KekikStream/Core/PluginModels.py +6 -16
- KekikStream/Extractors/ContentX.py +80 -0
- KekikStream/Extractors/FourCX.py +7 -0
- KekikStream/Extractors/FourPichive.py +7 -0
- KekikStream/Extractors/FourPlayRu.py +7 -0
- KekikStream/Extractors/HDStreamAble.py +7 -0
- KekikStream/Extractors/Hotlinger.py +7 -0
- KekikStream/Extractors/MixPlayHD.py +42 -0
- KekikStream/Extractors/Odnoklassniki.py +106 -0
- KekikStream/Extractors/OkRuHTTP.py +7 -0
- KekikStream/Extractors/OkRuSSL.py +7 -0
- KekikStream/Extractors/PeaceMakerst.py +57 -0
- KekikStream/Extractors/Pichive.py +7 -0
- KekikStream/Extractors/PixelDrain.py +1 -1
- KekikStream/Extractors/PlayRu.py +7 -0
- KekikStream/Extractors/RapidVid.py +9 -10
- KekikStream/Extractors/SibNet.py +1 -1
- KekikStream/Extractors/Sobreatsesuyp.py +5 -6
- KekikStream/Extractors/TRsTX.py +5 -6
- KekikStream/Extractors/TauVideo.py +11 -10
- KekikStream/Extractors/TurboImgz.py +9 -12
- KekikStream/Extractors/VidMoly.py +25 -33
- KekikStream/Extractors/VidMoxy.py +1 -1
- KekikStream/Extractors/VideoSeyred.py +47 -0
- KekikStream/Managers/MediaManager.py +1 -1
- KekikStream/Managers/UIManager.py +6 -2
- KekikStream/Plugins/DiziBox.py +138 -0
- KekikStream/Plugins/Dizilla.py +95 -0
- KekikStream/Plugins/FilmMakinesi.py +8 -8
- KekikStream/Plugins/FullHDFilmizlesene.py +5 -4
- KekikStream/Plugins/JetFilmizle.py +4 -8
- KekikStream/Plugins/RecTV.py +111 -0
- KekikStream/Plugins/SineWix.py +4 -1
- KekikStream/Plugins/UgurFilm.py +3 -3
- KekikStream/__init__.py +177 -158
- KekikStream/__main__.py +1 -1
- KekikStream/requirements.txt +2 -1
- {KekikStream-0.2.3.dist-info → KekikStream-0.5.7.dist-info}/METADATA +4 -3
- KekikStream-0.5.7.dist-info/RECORD +58 -0
- KekikStream/CLI/check_update.py +0 -33
- KekikStream-0.2.3.dist-info/RECORD +0 -41
- {KekikStream-0.2.3.dist-info → KekikStream-0.5.7.dist-info}/LICENSE +0 -0
- {KekikStream-0.2.3.dist-info → KekikStream-0.5.7.dist-info}/WHEEL +0 -0
- {KekikStream-0.2.3.dist-info → KekikStream-0.5.7.dist-info}/entry_points.txt +0 -0
- {KekikStream-0.2.3.dist-info → KekikStream-0.5.7.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
|
+
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult
|
4
|
+
import re, json
|
5
|
+
|
6
|
+
class Odnoklassniki(ExtractorBase):
|
7
|
+
name = "Odnoklassniki"
|
8
|
+
main_url = "https://odnoklassniki.ru"
|
9
|
+
|
10
|
+
async def extract(self, url, referer=None) -> ExtractResult:
|
11
|
+
if referer:
|
12
|
+
self.oturum.headers.update({"Referer": referer})
|
13
|
+
|
14
|
+
self.oturum.headers.update({
|
15
|
+
"User-Agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36"
|
16
|
+
})
|
17
|
+
|
18
|
+
if "/video/" in url:
|
19
|
+
url = url.replace("/video/", "/videoembed/")
|
20
|
+
|
21
|
+
try:
|
22
|
+
istek = await self.fetch_with_redirects(url)
|
23
|
+
istek.raise_for_status()
|
24
|
+
except Exception as hata:
|
25
|
+
raise RuntimeError(f"Failed to fetch the URL: {url}, Error: {hata}") from hata
|
26
|
+
|
27
|
+
response_text = (
|
28
|
+
istek.text.replace("\\"", "\"")
|
29
|
+
.replace("\\\\", "\\")
|
30
|
+
.replace(r"\\u", "\\u")
|
31
|
+
)
|
32
|
+
response_text = re.sub(
|
33
|
+
r"\\u([0-9A-Fa-f]{4})",
|
34
|
+
lambda match: chr(int(match[1], 16)),
|
35
|
+
response_text
|
36
|
+
)
|
37
|
+
|
38
|
+
videos_match = re.search(r'"videos":(\[.*?\])', response_text)
|
39
|
+
if not videos_match:
|
40
|
+
raise ValueError("No video data found in the response.")
|
41
|
+
|
42
|
+
try:
|
43
|
+
videos = json.loads(videos_match[1])
|
44
|
+
except json.JSONDecodeError as hata:
|
45
|
+
raise ValueError("Failed to parse video data.") from hata
|
46
|
+
|
47
|
+
quality_order = {
|
48
|
+
"ULTRA": 6, # 4K veya daha yüksek
|
49
|
+
"QUAD": 5, # 1440p
|
50
|
+
"FULL": 4, # 1080p
|
51
|
+
"HD": 3, # 720p
|
52
|
+
"SD": 2, # 480p
|
53
|
+
"LOW": 1, # 360p
|
54
|
+
"MOBILE": 0 # 144p
|
55
|
+
}
|
56
|
+
|
57
|
+
# Kaliteye göre en iyi videoyu seçme
|
58
|
+
best_video = None
|
59
|
+
best_quality_score = -1
|
60
|
+
|
61
|
+
for video in videos:
|
62
|
+
video_url = video.get("url")
|
63
|
+
quality_name = video.get("name", "").upper()
|
64
|
+
|
65
|
+
if not video_url or not quality_name:
|
66
|
+
continue
|
67
|
+
|
68
|
+
# Kalite sıralamasına göre puanla
|
69
|
+
quality_score = quality_order.get(quality_name, -1)
|
70
|
+
if quality_score > best_quality_score:
|
71
|
+
best_quality_score = quality_score
|
72
|
+
best_video = video_url
|
73
|
+
|
74
|
+
if not best_video:
|
75
|
+
raise ValueError("No valid video URLs found.")
|
76
|
+
|
77
|
+
if best_video.startswith("//"):
|
78
|
+
best_video = f"https:{best_video}"
|
79
|
+
|
80
|
+
return ExtractResult(
|
81
|
+
name = self.name,
|
82
|
+
url = best_video,
|
83
|
+
referer = self.main_url,
|
84
|
+
subtitles = []
|
85
|
+
)
|
86
|
+
|
87
|
+
async def fetch_with_redirects(self, url, max_redirects=5):
|
88
|
+
"""Yönlendirmeleri takip eden bir fonksiyon"""
|
89
|
+
redirects = 0
|
90
|
+
while redirects < max_redirects:
|
91
|
+
istek = await self.oturum.get(url, follow_redirects=False)
|
92
|
+
|
93
|
+
if istek.status_code not in [301, 302]:
|
94
|
+
break # Yönlendirme yoksa çık
|
95
|
+
|
96
|
+
redirected_url = istek.headers.get("Location")
|
97
|
+
if not redirected_url:
|
98
|
+
raise ValueError("Redirect location not found.")
|
99
|
+
|
100
|
+
url = redirected_url if redirected_url.startswith("http") else f"https://{redirected_url}"
|
101
|
+
redirects += 1
|
102
|
+
|
103
|
+
if redirects == max_redirects:
|
104
|
+
raise RuntimeError(f"Max redirects ({max_redirects}) reached.")
|
105
|
+
|
106
|
+
return istek
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
|
+
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult
|
4
|
+
import re, json
|
5
|
+
|
6
|
+
class PeaceMakerst(ExtractorBase):
|
7
|
+
name = "PeaceMakerst"
|
8
|
+
main_url = "https://peacemakerst.com"
|
9
|
+
|
10
|
+
async def extract(self, url, referer=None) -> ExtractResult:
|
11
|
+
if referer:
|
12
|
+
self.oturum.headers.update({"Referer": referer})
|
13
|
+
|
14
|
+
self.oturum.headers.update({
|
15
|
+
"Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
|
16
|
+
"X-Requested-With" : "XMLHttpRequest"
|
17
|
+
})
|
18
|
+
|
19
|
+
response = await self.oturum.post(
|
20
|
+
url = f"{url}?do=getVideo",
|
21
|
+
data = {
|
22
|
+
"hash" : url.split("video/")[-1],
|
23
|
+
"r" : referer or "",
|
24
|
+
"s" : ""
|
25
|
+
}
|
26
|
+
)
|
27
|
+
response.raise_for_status()
|
28
|
+
|
29
|
+
response_text = response.text
|
30
|
+
m3u_link = None
|
31
|
+
|
32
|
+
if "teve2.com.tr\\/embed\\/" in response_text:
|
33
|
+
teve2_id = re.search(r"teve2\.com\.tr\\\/embed\\\/(\d+)", response_text)[1]
|
34
|
+
teve2_url = f"https://www.teve2.com.tr/action/media/{teve2_id}"
|
35
|
+
|
36
|
+
teve2_response = await self.oturum.get(teve2_url, headers={"Referer": f"https://www.teve2.com.tr/embed/{teve2_id}"})
|
37
|
+
teve2_response.raise_for_status()
|
38
|
+
teve2_json = teve2_response.json()
|
39
|
+
|
40
|
+
m3u_link = f"{teve2_json['Media']['Link']['ServiceUrl']}//{teve2_json['Media']['Link']['SecurePath']}"
|
41
|
+
else:
|
42
|
+
try:
|
43
|
+
video_response = response.json()
|
44
|
+
if video_sources := video_response.get("videoSources", []):
|
45
|
+
m3u_link = video_sources[-1]["file"]
|
46
|
+
except (json.JSONDecodeError, KeyError) as hata:
|
47
|
+
raise ValueError("Peace response is invalid or null.") from hata
|
48
|
+
|
49
|
+
if not m3u_link:
|
50
|
+
raise ValueError("m3u link not found.")
|
51
|
+
|
52
|
+
return ExtractResult(
|
53
|
+
name = self.name,
|
54
|
+
url = m3u_link,
|
55
|
+
referer = url,
|
56
|
+
subtitles = []
|
57
|
+
)
|
@@ -15,7 +15,7 @@ class PixelDrain(ExtractorBase):
|
|
15
15
|
if not pixel_id_match:
|
16
16
|
raise ValueError("PixelDrain bağlantısından ID çıkarılamadı.")
|
17
17
|
|
18
|
-
pixel_id = pixel_id_match
|
18
|
+
pixel_id = pixel_id_match[1]
|
19
19
|
download_link = f"{self.main_url}/api/file/{pixel_id}?download"
|
20
20
|
referer_link = f"{self.main_url}/u/{pixel_id}?download"
|
21
21
|
|
@@ -22,8 +22,8 @@ class RapidVid(ExtractorBase):
|
|
22
22
|
for sub_url, sub_lang in subtitle_matches:
|
23
23
|
if sub_url in seen_subtitles:
|
24
24
|
continue
|
25
|
-
seen_subtitles.add(sub_url)
|
26
25
|
|
26
|
+
seen_subtitles.add(sub_url)
|
27
27
|
decoded_lang = (
|
28
28
|
sub_lang.replace("\\u0131", "ı")
|
29
29
|
.replace("\\u0130", "İ")
|
@@ -33,24 +33,23 @@ class RapidVid(ExtractorBase):
|
|
33
33
|
subtitles.append(Subtitle(name=decoded_lang, url=sub_url.replace("\\", "")))
|
34
34
|
|
35
35
|
try:
|
36
|
-
extracted_value
|
37
|
-
|
38
|
-
escaped_hex = extracted_value.group(1)
|
36
|
+
if extracted_value := re.search(r'file": "(.*)",', istek.text):
|
37
|
+
escaped_hex = extracted_value[1]
|
39
38
|
decoded_url = HexCodec.decode(escaped_hex)
|
40
39
|
else:
|
41
40
|
eval_jwsetup = re.search(r'\};\s*(eval\(function[\s\S]*?)var played = \d+;', istek.text)
|
42
41
|
if not eval_jwsetup:
|
43
42
|
raise ValueError("JWPlayer setup not found.")
|
44
|
-
|
45
|
-
unpacked_jwsetup = Packer.unpack(Packer.unpack(eval_jwsetup
|
43
|
+
|
44
|
+
unpacked_jwsetup = Packer.unpack(Packer.unpack(eval_jwsetup[1]))
|
46
45
|
extracted_value = re.search(r'file":"(.*)","label', unpacked_jwsetup)
|
47
46
|
if not extracted_value:
|
48
47
|
raise ValueError("File URL not found in unpacked JWPlayer setup.")
|
49
|
-
|
50
|
-
escaped_hex = extracted_value
|
48
|
+
|
49
|
+
escaped_hex = extracted_value[1].replace("\\\\x", "")
|
51
50
|
decoded_url = bytes.fromhex(escaped_hex).decode("utf-8")
|
52
|
-
except Exception as
|
53
|
-
raise RuntimeError(f"Extraction failed: {
|
51
|
+
except Exception as hata:
|
52
|
+
raise RuntimeError(f"Extraction failed: {hata}") from hata
|
54
53
|
|
55
54
|
await self.close()
|
56
55
|
return ExtractResult(
|
KekikStream/Extractors/SibNet.py
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
2
|
|
3
3
|
from KekikStream.Core import ExtractorBase, ExtractResult
|
4
|
-
import re
|
5
|
-
import json
|
4
|
+
import re, json
|
6
5
|
|
7
6
|
class Sobreatsesuyp(ExtractorBase):
|
8
7
|
name = "Sobreatsesuyp"
|
@@ -19,7 +18,7 @@ class Sobreatsesuyp(ExtractorBase):
|
|
19
18
|
if not file_match:
|
20
19
|
raise ValueError("File not found in response.")
|
21
20
|
|
22
|
-
file_path = file_match
|
21
|
+
file_path = file_match[1].replace("\\", "")
|
23
22
|
post_link = f"{self.main_url}/{file_path}"
|
24
23
|
|
25
24
|
post_istek = await self.oturum.post(post_link)
|
@@ -27,8 +26,8 @@ class Sobreatsesuyp(ExtractorBase):
|
|
27
26
|
|
28
27
|
try:
|
29
28
|
post_json = json.loads(post_istek.text)
|
30
|
-
except json.JSONDecodeError:
|
31
|
-
raise ValueError("Failed to parse JSON response.")
|
29
|
+
except json.JSONDecodeError as hata:
|
30
|
+
raise ValueError("Failed to parse JSON response.") from hata
|
32
31
|
|
33
32
|
video_data_list = post_json[1:] if isinstance(post_json, list) else []
|
34
33
|
|
@@ -57,4 +56,4 @@ class Sobreatsesuyp(ExtractorBase):
|
|
57
56
|
if not all_results:
|
58
57
|
raise ValueError("No videos found in response.")
|
59
58
|
|
60
|
-
return all_results
|
59
|
+
return all_results[0] if len(all_results) == 1 else all_results
|
KekikStream/Extractors/TRsTX.py
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
2
|
|
3
3
|
from KekikStream.Core import ExtractorBase, ExtractResult
|
4
|
-
import re
|
5
|
-
import json
|
4
|
+
import re, json
|
6
5
|
|
7
6
|
class TRsTX(ExtractorBase):
|
8
7
|
name = "TRsTX"
|
@@ -19,7 +18,7 @@ class TRsTX(ExtractorBase):
|
|
19
18
|
if not file_match:
|
20
19
|
raise ValueError("File not found in response.")
|
21
20
|
|
22
|
-
file_path = file_match
|
21
|
+
file_path = file_match[1].replace("\\", "")
|
23
22
|
post_link = f"{self.main_url}/{file_path}"
|
24
23
|
|
25
24
|
post_istek = await self.oturum.post(post_link)
|
@@ -27,8 +26,8 @@ class TRsTX(ExtractorBase):
|
|
27
26
|
|
28
27
|
try:
|
29
28
|
post_json = json.loads(post_istek.text)
|
30
|
-
except json.JSONDecodeError:
|
31
|
-
raise ValueError("Failed to parse JSON response.")
|
29
|
+
except json.JSONDecodeError as hata:
|
30
|
+
raise ValueError("Failed to parse JSON response.") from hata
|
32
31
|
|
33
32
|
video_data_list = post_json[1:] if isinstance(post_json, list) else []
|
34
33
|
|
@@ -65,4 +64,4 @@ class TRsTX(ExtractorBase):
|
|
65
64
|
if not all_results:
|
66
65
|
raise ValueError("No videos found in response.")
|
67
66
|
|
68
|
-
return all_results
|
67
|
+
return all_results[0] if len(all_results) == 1 else all_results
|
@@ -21,13 +21,14 @@ class TauVideo(ExtractorBase):
|
|
21
21
|
if "urls" not in api_data:
|
22
22
|
raise ValueError("API yanıtında 'urls' bulunamadı.")
|
23
23
|
|
24
|
-
results = [
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
24
|
+
results = [
|
25
|
+
ExtractResult(
|
26
|
+
name = f"{self.name} - {video['label']}",
|
27
|
+
url = video["url"],
|
28
|
+
referer = referer or self.main_url,
|
29
|
+
subtitles = []
|
30
|
+
)
|
31
|
+
for video in api_data["urls"]
|
32
|
+
]
|
33
|
+
|
34
|
+
return results[0] if len(results) == 1 else results
|
@@ -14,15 +14,12 @@ class TurboImgz(ExtractorBase):
|
|
14
14
|
istek = await self.oturum.get(url)
|
15
15
|
istek.raise_for_status()
|
16
16
|
|
17
|
-
video_match
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
referer = referer or self.main_url,
|
27
|
-
subtitles = []
|
28
|
-
)
|
17
|
+
if video_match := re.search(r'file: "(.*)",', istek.text):
|
18
|
+
return ExtractResult(
|
19
|
+
name = self.name,
|
20
|
+
url = video_match[1],
|
21
|
+
referer = referer or self.main_url,
|
22
|
+
subtitles = []
|
23
|
+
)
|
24
|
+
else:
|
25
|
+
raise ValueError("File not found in response.")
|
@@ -2,9 +2,7 @@
|
|
2
2
|
# ! https://github.com/recloudstream/cloudstream/blob/master/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vidmoly.kt
|
3
3
|
|
4
4
|
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
|
5
|
-
import re
|
6
|
-
import asyncio
|
7
|
-
import json
|
5
|
+
import re, asyncio, contextlib, json
|
8
6
|
|
9
7
|
class VidMoly(ExtractorBase):
|
10
8
|
name = "VidMoly"
|
@@ -14,25 +12,24 @@ class VidMoly(ExtractorBase):
|
|
14
12
|
if referer:
|
15
13
|
self.oturum.headers.update({"Referer": referer})
|
16
14
|
|
17
|
-
headers
|
18
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
|
19
|
-
"Sec-Fetch-Dest": "iframe",
|
20
|
-
}
|
15
|
+
self.oturum.headers.update({
|
16
|
+
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
|
17
|
+
"Sec-Fetch-Dest" : "iframe",
|
18
|
+
})
|
21
19
|
|
22
20
|
# Embed URL oluştur
|
23
|
-
embed_url
|
24
|
-
url.replace("/w/", "/embed-") + "-920x360.html" if "/w/" in url else url
|
25
|
-
)
|
21
|
+
embed_url = url.replace("/w/", "/embed-") + "-920x360.html" if "/w/" in url else url
|
26
22
|
script_content = None
|
27
|
-
attempts
|
23
|
+
attempts = 0
|
28
24
|
|
29
25
|
# Script verisini almak için deneme yap
|
30
26
|
while attempts < 10 and not script_content:
|
31
27
|
attempts += 1
|
32
|
-
response = await self.oturum.get(embed_url
|
28
|
+
response = await self.oturum.get(embed_url)
|
33
29
|
response.raise_for_status()
|
34
|
-
|
35
|
-
|
30
|
+
|
31
|
+
script_match = re.search(r"sources:\s*\[(.*?)\],", response.text, re.DOTALL)
|
32
|
+
script_content = script_match[1] if script_match else None
|
36
33
|
if not script_content:
|
37
34
|
await asyncio.sleep(0.5)
|
38
35
|
|
@@ -43,35 +40,30 @@ class VidMoly(ExtractorBase):
|
|
43
40
|
video_data = self._add_marks(script_content, "file")
|
44
41
|
try:
|
45
42
|
video_sources = json.loads(f"[{video_data}]")
|
46
|
-
except json.JSONDecodeError:
|
47
|
-
raise ValueError("Video kaynakları ayrıştırılamadı.")
|
43
|
+
except json.JSONDecodeError as hata:
|
44
|
+
raise ValueError("Video kaynakları ayrıştırılamadı.") from hata
|
48
45
|
|
49
46
|
# Altyazı kaynaklarını ayrıştır
|
50
47
|
subtitles = []
|
51
|
-
subtitle_match
|
52
|
-
|
53
|
-
subtitle_data = self._add_marks(subtitle_match.group(1), "file")
|
48
|
+
if subtitle_match := re.search(r"tracks:\s*\[(.*?)\]", response.text, re.DOTALL):
|
49
|
+
subtitle_data = self._add_marks(subtitle_match[1], "file")
|
54
50
|
subtitle_data = self._add_marks(subtitle_data, "label")
|
55
51
|
subtitle_data = self._add_marks(subtitle_data, "kind")
|
56
52
|
|
57
|
-
|
53
|
+
with contextlib.suppress(json.JSONDecodeError):
|
58
54
|
subtitle_sources = json.loads(f"[{subtitle_data}]")
|
59
55
|
subtitles = [
|
60
56
|
Subtitle(
|
61
|
-
name=sub.get("label"),
|
62
|
-
url=self.fix_url(sub.get("file")),
|
57
|
+
name = sub.get("label"),
|
58
|
+
url = self.fix_url(sub.get("file")),
|
63
59
|
)
|
64
|
-
|
65
|
-
|
60
|
+
for sub in subtitle_sources
|
61
|
+
if sub.get("kind") == "captions"
|
66
62
|
]
|
67
|
-
except json.JSONDecodeError:
|
68
|
-
pass
|
69
|
-
|
70
63
|
# İlk video kaynağını al
|
71
64
|
video_url = None
|
72
65
|
for source in video_sources:
|
73
|
-
file_url
|
74
|
-
if file_url:
|
66
|
+
if file_url := source.get("file"):
|
75
67
|
video_url = file_url
|
76
68
|
break
|
77
69
|
|
@@ -80,10 +72,10 @@ class VidMoly(ExtractorBase):
|
|
80
72
|
|
81
73
|
await self.close()
|
82
74
|
return ExtractResult(
|
83
|
-
name=self.name,
|
84
|
-
url=video_url,
|
85
|
-
referer=self.main_url,
|
86
|
-
subtitles=subtitles
|
75
|
+
name = self.name,
|
76
|
+
url = video_url,
|
77
|
+
referer = self.main_url,
|
78
|
+
subtitles = subtitles
|
87
79
|
)
|
88
80
|
|
89
81
|
def _add_marks(self, text: str, field: str) -> str:
|
@@ -22,8 +22,8 @@ class VidMoxy(ExtractorBase):
|
|
22
22
|
for sub_url, sub_lang in subtitle_matches:
|
23
23
|
if sub_url in seen_subtitles:
|
24
24
|
continue
|
25
|
-
seen_subtitles.add(sub_url)
|
26
25
|
|
26
|
+
seen_subtitles.add(sub_url)
|
27
27
|
decoded_lang = (
|
28
28
|
sub_lang.replace("\\u0131", "ı")
|
29
29
|
.replace("\\u0130", "İ")
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
|
+
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
|
4
|
+
import json
|
5
|
+
|
6
|
+
class VideoSeyred(ExtractorBase):
|
7
|
+
name = "VideoSeyred"
|
8
|
+
main_url = "https://videoseyred.in"
|
9
|
+
|
10
|
+
async def extract(self, url, referer=None) -> ExtractResult:
|
11
|
+
if referer:
|
12
|
+
self.oturum.headers.update({"Referer": referer})
|
13
|
+
|
14
|
+
video_id = url.split("embed/")[1].split("?")[0]
|
15
|
+
video_url = f"{self.main_url}/playlist/{video_id}.json"
|
16
|
+
|
17
|
+
response = await self.oturum.get(video_url)
|
18
|
+
response.raise_for_status()
|
19
|
+
|
20
|
+
try:
|
21
|
+
if response_list := json.loads(response.text):
|
22
|
+
response_data = response_list[0]
|
23
|
+
else:
|
24
|
+
raise ValueError("Empty response from VideoSeyred.")
|
25
|
+
|
26
|
+
except (json.JSONDecodeError, IndexError) as hata:
|
27
|
+
raise RuntimeError(f"Failed to parse response: {hata}") from hata
|
28
|
+
|
29
|
+
subtitles = [
|
30
|
+
Subtitle(name=track["label"], url=self.fix_url(track["file"]))
|
31
|
+
for track in response_data.get("tracks", [])
|
32
|
+
if track.get("kind") == "captions" and track.get("label")
|
33
|
+
]
|
34
|
+
|
35
|
+
if video_links := [
|
36
|
+
ExtractResult(
|
37
|
+
name = self.name,
|
38
|
+
url = self.fix_url(source["file"]),
|
39
|
+
referer = self.main_url,
|
40
|
+
subtitles = subtitles,
|
41
|
+
)
|
42
|
+
for source in response_data.get("sources", [])
|
43
|
+
]:
|
44
|
+
# En yüksek kaliteli videoyu döndür (varsayılan olarak ilk video)
|
45
|
+
return video_links[0] if len(video_links) == 1 else video_links
|
46
|
+
else:
|
47
|
+
raise ValueError("No video links found in the response.")
|
@@ -9,11 +9,12 @@ import os
|
|
9
9
|
class UIManager:
|
10
10
|
@staticmethod
|
11
11
|
def clear_console():
|
12
|
+
# return True
|
12
13
|
os.system("cls" if os.name == "nt" else "clear")
|
13
14
|
|
14
15
|
@staticmethod
|
15
16
|
async def select_from_list(message, choices):
|
16
|
-
return await inquirer.select(message=message, choices=choices, max_height="
|
17
|
+
return await inquirer.select(message=message, choices=choices, max_height="75%").execute_async()
|
17
18
|
|
18
19
|
@staticmethod
|
19
20
|
async def select_from_fuzzy(message, choices):
|
@@ -22,7 +23,7 @@ class UIManager:
|
|
22
23
|
choices = choices,
|
23
24
|
validate = lambda result: result in [choice if isinstance(choice, str) else choice["value"] for choice in choices],
|
24
25
|
filter = lambda result: result,
|
25
|
-
max_height = "
|
26
|
+
max_height = "75%"
|
26
27
|
).execute_async()
|
27
28
|
|
28
29
|
@staticmethod
|
@@ -40,6 +41,9 @@ class UIManager:
|
|
40
41
|
continue
|
41
42
|
|
42
43
|
if value:
|
44
|
+
if '",' in value:
|
45
|
+
continue
|
46
|
+
|
43
47
|
table.add_row(f"[bold cyan]{key.capitalize()}[/bold cyan]", str(value))
|
44
48
|
|
45
49
|
konsol.print(Panel(table, title=f"[bold green]{plugin_name}[/bold green]", expand=False))
|