KekikStream 2.2.9__py3-none-any.whl → 2.5.3__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 (88) hide show
  1. KekikStream/Core/Extractor/ExtractorBase.py +3 -2
  2. KekikStream/Core/Extractor/ExtractorLoader.py +8 -14
  3. KekikStream/Core/HTMLHelper.py +205 -0
  4. KekikStream/Core/Plugin/PluginBase.py +48 -12
  5. KekikStream/Core/Plugin/PluginLoader.py +13 -14
  6. KekikStream/Core/Plugin/PluginManager.py +2 -2
  7. KekikStream/Core/Plugin/PluginModels.py +0 -3
  8. KekikStream/Core/__init__.py +2 -0
  9. KekikStream/Extractors/Abstream.py +27 -0
  10. KekikStream/Extractors/CloseLoad.py +31 -56
  11. KekikStream/Extractors/ContentX.py +28 -71
  12. KekikStream/Extractors/DonilasPlay.py +34 -78
  13. KekikStream/Extractors/DzenRu.py +11 -25
  14. KekikStream/Extractors/ExPlay.py +20 -38
  15. KekikStream/Extractors/Filemoon.py +23 -53
  16. KekikStream/Extractors/HDMomPlayer.py +30 -0
  17. KekikStream/Extractors/HDPlayerSystem.py +13 -31
  18. KekikStream/Extractors/HotStream.py +27 -0
  19. KekikStream/Extractors/JFVid.py +3 -24
  20. KekikStream/Extractors/JetTv.py +21 -34
  21. KekikStream/Extractors/JetV.py +55 -0
  22. KekikStream/Extractors/MailRu.py +11 -29
  23. KekikStream/Extractors/MixPlayHD.py +17 -31
  24. KekikStream/Extractors/MixTiger.py +17 -40
  25. KekikStream/Extractors/MolyStream.py +25 -22
  26. KekikStream/Extractors/Odnoklassniki.py +41 -105
  27. KekikStream/Extractors/PeaceMakerst.py +20 -47
  28. KekikStream/Extractors/PixelDrain.py +9 -16
  29. KekikStream/Extractors/PlayerFilmIzle.py +23 -46
  30. KekikStream/Extractors/RapidVid.py +23 -36
  31. KekikStream/Extractors/SetPlay.py +19 -44
  32. KekikStream/Extractors/SetPrime.py +3 -6
  33. KekikStream/Extractors/SibNet.py +8 -19
  34. KekikStream/Extractors/Sobreatsesuyp.py +25 -47
  35. KekikStream/Extractors/TRsTX.py +25 -55
  36. KekikStream/Extractors/TurboImgz.py +8 -16
  37. KekikStream/Extractors/TurkeyPlayer.py +5 -5
  38. KekikStream/Extractors/VCTPlay.py +10 -28
  39. KekikStream/Extractors/Veev.py +145 -0
  40. KekikStream/Extractors/VidBiz.py +62 -0
  41. KekikStream/Extractors/VidHide.py +59 -34
  42. KekikStream/Extractors/VidMoly.py +67 -89
  43. KekikStream/Extractors/VidMoxy.py +17 -29
  44. KekikStream/Extractors/VidPapi.py +26 -58
  45. KekikStream/Extractors/VideoSeyred.py +21 -42
  46. KekikStream/Extractors/Videostr.py +58 -0
  47. KekikStream/Extractors/Vidoza.py +18 -0
  48. KekikStream/Extractors/Vtbe.py +38 -0
  49. KekikStream/Extractors/YTDLP.py +2 -2
  50. KekikStream/Extractors/YildizKisaFilm.py +13 -31
  51. KekikStream/Extractors/Zeus.py +61 -0
  52. KekikStream/Plugins/BelgeselX.py +108 -99
  53. KekikStream/Plugins/DiziBox.py +61 -106
  54. KekikStream/Plugins/DiziMom.py +179 -0
  55. KekikStream/Plugins/DiziPal.py +104 -192
  56. KekikStream/Plugins/DiziYou.py +66 -149
  57. KekikStream/Plugins/Dizilla.py +93 -126
  58. KekikStream/Plugins/FilmBip.py +102 -72
  59. KekikStream/Plugins/FilmEkseni.py +199 -0
  60. KekikStream/Plugins/FilmMakinesi.py +101 -64
  61. KekikStream/Plugins/FilmModu.py +35 -59
  62. KekikStream/Plugins/Filmatek.py +184 -0
  63. KekikStream/Plugins/FilmciBaba.py +155 -0
  64. KekikStream/Plugins/FullHDFilmizlesene.py +32 -78
  65. KekikStream/Plugins/HDFilm.py +243 -0
  66. KekikStream/Plugins/HDFilmCehennemi.py +261 -222
  67. KekikStream/Plugins/JetFilmizle.py +117 -98
  68. KekikStream/Plugins/KultFilmler.py +153 -143
  69. KekikStream/Plugins/RecTV.py +53 -49
  70. KekikStream/Plugins/RoketDizi.py +92 -123
  71. KekikStream/Plugins/SelcukFlix.py +86 -95
  72. KekikStream/Plugins/SetFilmIzle.py +105 -143
  73. KekikStream/Plugins/SezonlukDizi.py +106 -128
  74. KekikStream/Plugins/Sinefy.py +194 -166
  75. KekikStream/Plugins/SinemaCX.py +159 -113
  76. KekikStream/Plugins/Sinezy.py +44 -73
  77. KekikStream/Plugins/SuperFilmGeldi.py +28 -52
  78. KekikStream/Plugins/UgurFilm.py +94 -72
  79. KekikStream/Plugins/Watch32.py +160 -0
  80. KekikStream/Plugins/YabanciDizi.py +250 -0
  81. {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/METADATA +1 -1
  82. kekikstream-2.5.3.dist-info/RECORD +99 -0
  83. {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/WHEEL +1 -1
  84. KekikStream/Plugins/FullHDFilm.py +0 -254
  85. kekikstream-2.2.9.dist-info/RECORD +0 -82
  86. {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/entry_points.txt +0 -0
  87. {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/licenses/LICENSE +0 -0
  88. {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/top_level.txt +0 -0
@@ -1,89 +1,57 @@
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
4
+
5
5
 
6
6
  class VidPapi(ExtractorBase):
7
- name = "VidApi"
7
+ name = "VidPapi"
8
8
  main_url = "https://vidpapi.xyz"
9
9
 
10
- async def extract(self, url, referer=None) -> ExtractResult:
11
- ext_ref = referer or ""
10
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
11
+ ref = referer or self.main_url
12
12
 
13
- # URL parsing
13
+ # ID tespiti
14
14
  if "video/" in url:
15
15
  vid_id = url.split("video/")[-1]
16
16
  else:
17
17
  vid_id = url.split("?data=")[-1]
18
18
 
19
- # 1. Altyazıları çek
20
- sub_url = f"{self.main_url}/player/index.php?data={vid_id}"
21
- sub_headers = {
19
+ headers = {
22
20
  "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
23
21
  "X-Requested-With" : "XMLHttpRequest",
24
- "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0",
25
- "Referer" : ext_ref or "https://kultfilmler.pro/"
22
+ "Referer" : ref
26
23
  }
27
24
 
25
+ # 1. Altyazıları çek
28
26
  subtitles = []
29
27
  try:
30
- sub_istek = await self.httpx.post(
31
- url = sub_url,
32
- headers = sub_headers,
33
- data = {"hash": vid_id, "r": "https://kultfilmler.pro/"}
28
+ sub_resp = await self.httpx.post(
29
+ f"{self.main_url}/player/index.php?data={vid_id}",
30
+ headers = headers,
31
+ data = {"hash": vid_id, "r": ref}
34
32
  )
35
-
36
- subtitle_match = re.search(r'var playerjsSubtitle = "([^"]*)"', sub_istek.text, re.IGNORECASE)
37
- if subtitle_match and subtitle_match.group(1):
38
- raw_subs = subtitle_match.group(1)
39
-
40
- found_subs = re.findall(r'\[(.*?)\](.*?)(?:,|$)', raw_subs)
41
- for lang, sub_link in found_subs:
42
- lang = lang.strip()
43
- if "Türkçe" in lang:
44
- lang_code = "tr"
45
- lang_name = "Turkish"
46
- elif "İngilizce" in lang:
47
- lang_code = "en"
48
- lang_name = "English"
49
- else:
50
- lang_code = lang[:2].lower()
51
- lang_name = lang
52
-
53
- subtitles.append(Subtitle(
54
- name = lang_name,
55
- url = sub_link.strip()
56
- ))
57
-
58
- except Exception as e:
33
+ sel = HTMLHelper(sub_resp.text)
34
+ if raw_subs := sel.regex_first(r'var playerjsSubtitle\s*=\s*"([^"]*)"'):
35
+ for lang, link in HTMLHelper(raw_subs).regex_all(r'\[(.*?)\](https?://[^\s\",]+)'):
36
+ subtitles.append(Subtitle(name=lang.strip(), url=link.strip()))
37
+ except:
59
38
  pass
60
39
 
61
40
  # 2. Videoyu çek
62
- video_url = f"{self.main_url}/player/index.php?data={vid_id}&do=getVideo"
63
- video_headers = sub_headers.copy()
64
-
65
- response = await self.httpx.post(
66
- url = video_url,
67
- headers = video_headers,
68
- data = {"hash": vid_id, "r": "https://kultfilmler.pro/"}
41
+ resp = await self.httpx.post(
42
+ f"{self.main_url}/player/index.php?data={vid_id}&do=getVideo",
43
+ headers = headers,
44
+ data = {"hash": vid_id, "r": ref}
69
45
  )
70
- response.raise_for_status()
71
-
72
- try:
73
- video_data = response.json()
74
- except Exception:
75
- return None
46
+ data = resp.json()
76
47
 
77
- stream_url = video_data.get("securedLink")
78
- if not stream_url or not stream_url.strip():
79
- stream_url = video_data.get("videoSource")
80
-
48
+ stream_url = data.get("securedLink") or data.get("videoSource")
81
49
  if not stream_url:
82
- raise ValueError("No video link found in VidPapi response")
50
+ raise ValueError(f"VidPapi: Video URL bulunamadı. {url}")
83
51
 
84
52
  return ExtractResult(
85
53
  name = self.name,
86
54
  url = stream_url,
87
- referer = ext_ref or self.main_url,
55
+ referer = ref,
88
56
  subtitles = subtitles
89
57
  )
@@ -1,53 +1,32 @@
1
- # ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
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 json, re
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle, HTMLHelper
4
+ import json
5
5
 
6
6
  class VideoSeyred(ExtractorBase):
7
7
  name = "VideoSeyred"
8
8
  main_url = "https://videoseyred.in"
9
9
 
10
- async def extract(self, url, referer=None) -> ExtractResult:
11
- if referer:
12
- self.httpx.headers.update({"Referer": referer})
10
+ async def extract(self, url: str, referer: str = None) -> list[ExtractResult] | ExtractResult:
11
+ v_id = url.split("embed/")[1].split("?")[0]
12
+ if len(v_id) > 10:
13
+ resp = await self.httpx.get(url)
14
+ v_id = HTMLHelper(resp.text).regex_first(r"playlist\/(.*)\.json")
13
15
 
14
- video_id = url.split("embed/")[1].split("?")[0]
15
- if len(video_id) > 10:
16
- kontrol = await self.httpx.get(url)
17
- kontrol.raise_for_status()
18
-
19
- video_id = re.search(r"playlist\/(.*)\.json", kontrol.text)[1]
20
-
21
- video_url = f"{self.main_url}/playlist/{video_id}.json"
22
-
23
- response = await self.httpx.get(video_url)
24
- response.raise_for_status()
25
-
26
- try:
27
- if response_list := json.loads(response.text):
28
- response_data = response_list[0]
29
- else:
30
- raise ValueError("Empty response from VideoSeyred.")
31
-
32
- except (json.JSONDecodeError, IndexError) as hata:
33
- raise RuntimeError(f"Failed to parse response: {hata}") from hata
16
+ json_resp = await self.httpx.get(f"{self.main_url}/playlist/{v_id}.json")
17
+ data = json_resp.json()[0]
34
18
 
35
19
  subtitles = [
36
- Subtitle(name=track["label"], url=self.fix_url(track["file"]))
37
- for track in response_data.get("tracks", [])
38
- if track.get("kind") == "captions" and track.get("label")
20
+ Subtitle(name=t["label"], url=self.fix_url(t["file"]))
21
+ for t in data.get("tracks", []) if t.get("kind") == "captions"
22
+ ]
23
+
24
+ results = [
25
+ ExtractResult(name=self.name, url=self.fix_url(s["file"]), referer=self.main_url, subtitles=subtitles)
26
+ for s in data.get("sources", [])
39
27
  ]
40
28
 
41
- if video_links := [
42
- ExtractResult(
43
- name = self.name,
44
- url = self.fix_url(source["file"]),
45
- referer = self.main_url,
46
- subtitles = subtitles,
47
- )
48
- for source in response_data.get("sources", [])
49
- ]:
50
- # En yüksek kaliteli videoyu döndür (varsayılan olarak ilk video)
51
- return video_links[0] if len(video_links) == 1 else video_links
52
- else:
53
- raise ValueError("No video links found in the response.")
29
+ if not results:
30
+ raise ValueError(f"VideoSeyred: Video bulunamadı. {url}")
31
+
32
+ return results[0] if len(results) == 1 else results
@@ -0,0 +1,58 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper, Subtitle
4
+ from urllib.parse import quote
5
+ import re
6
+
7
+ class Videostr(ExtractorBase):
8
+ name = "Videostr"
9
+ main_url = "https://videostr.net"
10
+
11
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
12
+ v_id = url.split("?")[0].split("/")[-1]
13
+ headers = {"Referer": self.main_url, "X-Requested-With": "XMLHttpRequest"}
14
+
15
+ resp = await self.httpx.get(url, headers=headers)
16
+ sel = HTMLHelper(resp.text)
17
+
18
+ # Nonce Bulma
19
+ nonce = sel.regex_first(r"\b[a-zA-Z0-9]{48}\b")
20
+ if not nonce:
21
+ m = re.search(r"\b([a-zA-Z0-9]{16})\b.*?\b([a-zA-Z0-9]{16})\b.*?\b([a-zA-Z0-9]{16})\b", resp.text, re.DOTALL)
22
+ if m: nonce = m.group(1) + m.group(2) + m.group(3)
23
+
24
+ if not nonce:
25
+ raise ValueError(f"Videostr: Nonce bulunamadı. {url}")
26
+
27
+ # Kaynakları Çek
28
+ api_resp = await self.httpx.get(f"{self.main_url}/embed-1/v3/e-1/getSources?id={v_id}&_k={nonce}", headers=headers)
29
+ data = api_resp.json()
30
+
31
+ enc_file = data.get("sources", [{}])[0].get("file")
32
+ if not enc_file:
33
+ raise ValueError("Videostr: Kaynak bulunamadı.")
34
+
35
+ m3u8_url = None
36
+ if ".m3u8" in enc_file:
37
+ m3u8_url = enc_file
38
+ else:
39
+ # Decryption Flow (External Keys)
40
+ with contextlib.suppress(Exception):
41
+ key_resp = await self.httpx.get("https://raw.githubusercontent.com/yogesh-hacker/MegacloudKeys/refs/heads/main/keys.json")
42
+ v_key = key_resp.json().get("vidstr")
43
+ if v_key:
44
+ decode_api = "https://script.google.com/macros/s/AKfycbxHbYHbrGMXYD2-bC-C43D3njIbU-wGiYQuJL61H4vyy6YVXkybMNNEPJNPPuZrD1gRVA/exec"
45
+ dec_resp = await self.httpx.get(f"{decode_api}?encrypted_data={quote(enc_file)}&nonce={quote(nonce)}&secret={quote(v_key)}")
46
+ m3u8_url = re.search(r'"file":"(.*?)"', dec_resp.text).group(1).replace("\\/", "/")
47
+
48
+ if not m3u8_url:
49
+ raise ValueError(f"Videostr: Video URL bulunamadı. {url}")
50
+
51
+ subtitles = [
52
+ Subtitle(name=t.get("label", "Altyazı"), url=t.get("file"))
53
+ for t in data.get("tracks", []) if t.get("kind") in ["captions", "subtitles"]
54
+ ]
55
+
56
+ return ExtractResult(name=self.name, url=m3u8_url, referer=f"{self.main_url}/", subtitles=subtitles)
57
+
58
+ import contextlib
@@ -0,0 +1,18 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
4
+
5
+ class Vidoza(ExtractorBase):
6
+ name = "Vidoza"
7
+ main_url = "https://vidoza.net"
8
+
9
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
10
+ self.httpx.headers.update({"Referer": referer or url})
11
+
12
+ resp = await self.httpx.get(url)
13
+ v_url = HTMLHelper(resp.text).select_attr("source", "src")
14
+
15
+ if not v_url:
16
+ raise ValueError(f"Vidoza: Video bulunamadı. {url}")
17
+
18
+ return ExtractResult(name=self.name, url=v_url, referer=url)
@@ -0,0 +1,38 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
4
+ from Kekik.Sifreleme import Packer
5
+
6
+ class Vtbe(ExtractorBase):
7
+ name = "Vtbe"
8
+ main_url = "https://vtbe.to"
9
+
10
+ async def extract(self, url: str, referer: str = None) -> list[ExtractResult]:
11
+ # Iframe ise embed url'i düzeltmek gerekebilir ama genelde embed-xxxx.html formatı
12
+ istek = await self.httpx.get(url, headers={"Referer": referer or self.main_url})
13
+ text = istek.text
14
+
15
+ # Packed script bul: function(p,a,c,k,e,d)
16
+ packed = HTMLHelper(text).regex_first(r'(eval\s*\(\s*function[\s\S]+?)<\/script>')
17
+
18
+ if not packed:
19
+ raise ValueError(f"Vtbe: Packed script bulunamadı. {url}")
20
+
21
+ unpacked = ""
22
+ try:
23
+ unpacked = Packer.unpack(packed)
24
+ except:
25
+ raise ValueError("Vtbe: Unpack hatası")
26
+
27
+ # sources:[{file:"..."
28
+ file_url = HTMLHelper(unpacked).regex_first(r'sources:\s*\[\s*\{\s*file:\s*"([^"]+)"')
29
+
30
+ if not file_url:
31
+ raise ValueError("Vtbe: Video URL (file) bulunamadı")
32
+
33
+ return ExtractResult(
34
+ name = self.name,
35
+ url = self.fix_url(file_url),
36
+ referer = url,
37
+ user_agent = self.httpx.headers.get("User-Agent", "")
38
+ )
@@ -151,8 +151,8 @@ class YTDLP(ExtractorBase):
151
151
  ydl_opts = {
152
152
  "quiet" : True,
153
153
  "no_warnings" : True,
154
- "extract_flat" : False, # Tam bilgi al
155
- "format" : "best", # En iyi kalite
154
+ "extract_flat" : False, # Tam bilgi al
155
+ "format" : "best/all", # En iyi kalite, yoksa herhangi biri
156
156
  "no_check_certificates" : True,
157
157
  "socket_timeout" : 3,
158
158
  "retries" : 1
@@ -6,36 +6,18 @@ class YildizKisaFilm(ExtractorBase):
6
6
  name = "YildizKisaFilm"
7
7
  main_url = "https://yildizkisafilm.org"
8
8
 
9
- async def extract(self, url, referer=None) -> ExtractResult:
10
- ext_ref = referer or ""
11
-
12
- if "video/" in url:
13
- vid_id = url.split("video/")[-1]
14
- else:
15
- vid_id = url.split("?data=")[-1]
16
-
17
- post_url = f"{self.main_url}/player/index.php?data={vid_id}&do=getVideo"
18
-
19
- response = await self.httpx.post(
20
- url = post_url,
21
- data = {"hash": vid_id, "r": ext_ref},
22
- headers = {
23
- "Referer" : ext_ref,
24
- "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
25
- "X-Requested-With" : "XMLHttpRequest"
26
- }
9
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
10
+ ref = referer or self.main_url
11
+ v_id = url.split("video/")[-1] if "video/" in url else url.split("?data=")[-1]
12
+
13
+ resp = await self.httpx.post(
14
+ f"{self.main_url}/player/index.php?data={v_id}&do=getVideo",
15
+ data = {"hash": v_id, "r": ref},
16
+ headers = {"Referer": ref, "X-Requested-With": "XMLHttpRequest"}
27
17
  )
28
- response.raise_for_status()
18
+
19
+ m3u8_url = resp.json().get("securedLink")
20
+ if not m3u8_url:
21
+ raise ValueError(f"YildizKisaFilm: Video URL bulunamadı. {url}")
29
22
 
30
- video_data = response.json()
31
- m3u_link = video_data.get("securedLink")
32
-
33
- if not m3u_link:
34
- raise ValueError("securedLink not found in response")
35
-
36
- return ExtractResult(
37
- name = self.name,
38
- url = m3u_link,
39
- referer = ext_ref,
40
- subtitles = []
41
- )
23
+ return ExtractResult(name=self.name, url=m3u8_url, referer=ref)
@@ -0,0 +1,61 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
4
+
5
+ class Zeus(ExtractorBase):
6
+ name = "Zeus"
7
+ main_url = "https://d2rs.com"
8
+
9
+ async def extract(self, url: str, referer: str = None) -> list[ExtractResult]:
10
+ # Iframe içeriğini al
11
+ istek = await self.httpx.get(url, headers={"Referer": referer} if referer else None)
12
+ text = istek.text
13
+
14
+ # 'q' parametresini bul
15
+ # form.append("q", "...")
16
+ q_param = HTMLHelper(text).regex_first(r'form\.append\("q",\s*"([^"]+)"\)')
17
+
18
+ if not q_param:
19
+ raise ValueError(f"Zeus: 'q' parametresi bulunamadı. {url}")
20
+
21
+ # API'ye POST at
22
+ resp = await self.httpx.post(
23
+ url = "https://d2rs.com/zeus/api.php",
24
+ data = {"q": q_param},
25
+ headers = {"Referer": url}
26
+ )
27
+
28
+ try:
29
+ sources = resp.json()
30
+ except:
31
+ raise ValueError("Zeus: API yanıtı geçersiz JSON")
32
+
33
+ results = []
34
+ # [{"file": "...", "label": "Full HD", "type": "video/mp4"}, ...]
35
+ for i, source in enumerate(sources, 1):
36
+ file_path = source.get("file")
37
+ label = source.get("label") or ""
38
+ type_ = source.get("type", "")
39
+
40
+ if not file_path:
41
+ continue
42
+
43
+ full_url = f"https://d2rs.com/zeus/{file_path}"
44
+
45
+ # İsimlendirme
46
+ if label:
47
+ source_name = f"{self.name} | {label}"
48
+ else:
49
+ source_name = f"{self.name} | Kaynak {i}"
50
+
51
+ results.append(ExtractResult(
52
+ name = source_name,
53
+ url = self.fix_url(full_url),
54
+ referer = url,
55
+ user_agent = self.httpx.headers.get("User-Agent", "")
56
+ ))
57
+
58
+ if not results:
59
+ raise ValueError("Zeus: Kaynak bulunamadı")
60
+
61
+ return results