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.
Files changed (53) hide show
  1. KekikStream/CLI/__init__.py +1 -1
  2. KekikStream/CLI/pypi_kontrol.py +30 -0
  3. KekikStream/Core/ExtractorBase.py +13 -2
  4. KekikStream/Core/ExtractorLoader.py +31 -10
  5. KekikStream/Core/ExtractorModels.py +2 -0
  6. KekikStream/Core/MediaHandler.py +70 -30
  7. KekikStream/Core/PluginBase.py +6 -5
  8. KekikStream/Core/PluginLoader.py +3 -5
  9. KekikStream/Core/PluginModels.py +6 -16
  10. KekikStream/Extractors/ContentX.py +80 -0
  11. KekikStream/Extractors/FourCX.py +7 -0
  12. KekikStream/Extractors/FourPichive.py +7 -0
  13. KekikStream/Extractors/FourPlayRu.py +7 -0
  14. KekikStream/Extractors/HDStreamAble.py +7 -0
  15. KekikStream/Extractors/Hotlinger.py +7 -0
  16. KekikStream/Extractors/MixPlayHD.py +42 -0
  17. KekikStream/Extractors/Odnoklassniki.py +106 -0
  18. KekikStream/Extractors/OkRuHTTP.py +7 -0
  19. KekikStream/Extractors/OkRuSSL.py +7 -0
  20. KekikStream/Extractors/PeaceMakerst.py +57 -0
  21. KekikStream/Extractors/Pichive.py +7 -0
  22. KekikStream/Extractors/PixelDrain.py +1 -1
  23. KekikStream/Extractors/PlayRu.py +7 -0
  24. KekikStream/Extractors/RapidVid.py +9 -10
  25. KekikStream/Extractors/SibNet.py +1 -1
  26. KekikStream/Extractors/Sobreatsesuyp.py +5 -6
  27. KekikStream/Extractors/TRsTX.py +5 -6
  28. KekikStream/Extractors/TauVideo.py +11 -10
  29. KekikStream/Extractors/TurboImgz.py +9 -12
  30. KekikStream/Extractors/VidMoly.py +25 -33
  31. KekikStream/Extractors/VidMoxy.py +1 -1
  32. KekikStream/Extractors/VideoSeyred.py +47 -0
  33. KekikStream/Managers/MediaManager.py +1 -1
  34. KekikStream/Managers/UIManager.py +6 -2
  35. KekikStream/Plugins/DiziBox.py +138 -0
  36. KekikStream/Plugins/Dizilla.py +95 -0
  37. KekikStream/Plugins/FilmMakinesi.py +8 -8
  38. KekikStream/Plugins/FullHDFilmizlesene.py +5 -4
  39. KekikStream/Plugins/JetFilmizle.py +4 -8
  40. KekikStream/Plugins/RecTV.py +111 -0
  41. KekikStream/Plugins/SineWix.py +4 -1
  42. KekikStream/Plugins/UgurFilm.py +3 -3
  43. KekikStream/__init__.py +177 -158
  44. KekikStream/__main__.py +1 -1
  45. KekikStream/requirements.txt +2 -1
  46. {KekikStream-0.2.3.dist-info → KekikStream-0.5.7.dist-info}/METADATA +4 -3
  47. KekikStream-0.5.7.dist-info/RECORD +58 -0
  48. KekikStream/CLI/check_update.py +0 -33
  49. KekikStream-0.2.3.dist-info/RECORD +0 -41
  50. {KekikStream-0.2.3.dist-info → KekikStream-0.5.7.dist-info}/LICENSE +0 -0
  51. {KekikStream-0.2.3.dist-info → KekikStream-0.5.7.dist-info}/WHEEL +0 -0
  52. {KekikStream-0.2.3.dist-info → KekikStream-0.5.7.dist-info}/entry_points.txt +0 -0
  53. {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,7 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Extractors.Odnoklassniki import Odnoklassniki
4
+
5
+ class OkRuHTTP(Odnoklassniki):
6
+ name = "OkRuHTTP"
7
+ main_url = "http://ok.ru"
@@ -0,0 +1,7 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Extractors.Odnoklassniki import Odnoklassniki
4
+
5
+ class OkRuSSL(Odnoklassniki):
6
+ name = "OkRuSSL"
7
+ main_url = "https://ok.ru"
@@ -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
+ )
@@ -0,0 +1,7 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Extractors.ContentX import ContentX
4
+
5
+ class Pichive(ContentX):
6
+ name = "Pichive"
7
+ main_url = "https://pichive.online"
@@ -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.group(1)
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
 
@@ -0,0 +1,7 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Extractors.ContentX import ContentX
4
+
5
+ class PlayRu(ContentX):
6
+ name = "PlayRu"
7
+ main_url = "https://playru.net"
@@ -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 = re.search(r'file": "(.*)",', istek.text)
37
- if extracted_value:
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.group(1)))
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.group(1).replace("\\\\x", "")
48
+
49
+ escaped_hex = extracted_value[1].replace("\\\\x", "")
51
50
  decoded_url = bytes.fromhex(escaped_hex).decode("utf-8")
52
- except Exception as e:
53
- raise RuntimeError(f"Extraction failed: {e}")
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(
@@ -18,7 +18,7 @@ class SibNet(ExtractorBase):
18
18
  if not match:
19
19
  raise ValueError("m3u bağlantısı bulunamadı.")
20
20
 
21
- m3u_link = f"{self.main_url}{match.group(1)}"
21
+ m3u_link = f"{self.main_url}{match[1]}"
22
22
 
23
23
  await self.close()
24
24
  return ExtractResult(
@@ -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.group(1).replace("\\", "")
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
@@ -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.group(1).replace("\\", "")
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
- for video in api_data["urls"]:
26
- results.append(ExtractResult(
27
- name = f"{self.name} - {video['label']}",
28
- url = video["url"],
29
- referer = referer or self.main_url,
30
- subtitles = []
31
- ))
32
-
33
- return results
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 = re.search(r'file: "(.*)",', istek.text)
18
- if not video_match:
19
- raise ValueError("File not found in response.")
20
-
21
- video_link = video_match.group(1)
22
-
23
- return ExtractResult(
24
- name = self.name,
25
- url = video_link,
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 = 0
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, headers=headers)
28
+ response = await self.oturum.get(embed_url)
33
29
  response.raise_for_status()
34
- script_match = re.search(r"sources:\s*\[(.*?)\],", response.text, re.DOTALL)
35
- script_content = script_match.group(1) if script_match else None
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 = re.search(r"tracks:\s*\[(.*?)\]", response.text, re.DOTALL)
52
- if subtitle_match:
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
- try:
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
- for sub in subtitle_sources
65
- if sub.get("kind") == "captions"
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 = source.get("file")
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.")
@@ -16,4 +16,4 @@ class MediaManager:
16
16
  self.media_handler.headers.update(headers)
17
17
 
18
18
  def play_media(self, extract_data):
19
- self.media_handler.play_with_vlc(extract_data)
19
+ self.media_handler.play_media(extract_data)
@@ -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="60%").execute_async()
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 = "60%"
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))