KekikStream 2.4.2__py3-none-any.whl → 2.4.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. KekikStream/Core/Extractor/ExtractorBase.py +3 -2
  2. KekikStream/Core/HTMLHelper.py +134 -40
  3. KekikStream/Core/Plugin/PluginBase.py +3 -2
  4. KekikStream/Extractors/CloseLoad.py +30 -54
  5. KekikStream/Extractors/ContentX.py +27 -72
  6. KekikStream/Extractors/DonilasPlay.py +33 -77
  7. KekikStream/Extractors/DzenRu.py +10 -24
  8. KekikStream/Extractors/ExPlay.py +20 -38
  9. KekikStream/Extractors/Filemoon.py +19 -45
  10. KekikStream/Extractors/HDMomPlayer.py +24 -56
  11. KekikStream/Extractors/HDPlayerSystem.py +13 -31
  12. KekikStream/Extractors/HotStream.py +14 -32
  13. KekikStream/Extractors/JFVid.py +3 -24
  14. KekikStream/Extractors/JetTv.py +21 -34
  15. KekikStream/Extractors/MailRu.py +11 -29
  16. KekikStream/Extractors/MixPlayHD.py +15 -28
  17. KekikStream/Extractors/MixTiger.py +17 -40
  18. KekikStream/Extractors/MolyStream.py +17 -21
  19. KekikStream/Extractors/Odnoklassniki.py +28 -104
  20. KekikStream/Extractors/PeaceMakerst.py +18 -45
  21. KekikStream/Extractors/PixelDrain.py +8 -16
  22. KekikStream/Extractors/PlayerFilmIzle.py +22 -41
  23. KekikStream/Extractors/RapidVid.py +21 -35
  24. KekikStream/Extractors/SetPlay.py +18 -43
  25. KekikStream/Extractors/SibNet.py +7 -17
  26. KekikStream/Extractors/Sobreatsesuyp.py +23 -45
  27. KekikStream/Extractors/TRsTX.py +23 -53
  28. KekikStream/Extractors/TurboImgz.py +7 -14
  29. KekikStream/Extractors/VCTPlay.py +10 -28
  30. KekikStream/Extractors/VidHide.py +10 -31
  31. KekikStream/Extractors/VidMoly.py +65 -99
  32. KekikStream/Extractors/VidMoxy.py +16 -27
  33. KekikStream/Extractors/VidPapi.py +24 -54
  34. KekikStream/Extractors/VideoSeyred.py +19 -40
  35. KekikStream/Extractors/Videostr.py +42 -99
  36. KekikStream/Extractors/Vidoza.py +8 -15
  37. KekikStream/Extractors/YildizKisaFilm.py +13 -31
  38. KekikStream/Plugins/BelgeselX.py +63 -69
  39. KekikStream/Plugins/DiziBox.py +16 -36
  40. KekikStream/Plugins/DiziMom.py +37 -129
  41. KekikStream/Plugins/DiziPal.py +71 -164
  42. KekikStream/Plugins/DiziYou.py +44 -152
  43. KekikStream/Plugins/Dizilla.py +18 -44
  44. KekikStream/Plugins/FilmBip.py +10 -24
  45. KekikStream/Plugins/FilmEkseni.py +12 -32
  46. KekikStream/Plugins/FilmMakinesi.py +24 -77
  47. KekikStream/Plugins/FilmModu.py +11 -18
  48. KekikStream/Plugins/Filmatek.py +13 -39
  49. KekikStream/Plugins/Full4kizle.py +33 -133
  50. KekikStream/Plugins/FullHDFilm.py +23 -93
  51. KekikStream/Plugins/FullHDFilmizlesene.py +10 -29
  52. KekikStream/Plugins/HDFilmCehennemi.py +27 -66
  53. KekikStream/Plugins/JetFilmizle.py +19 -20
  54. KekikStream/Plugins/KultFilmler.py +16 -50
  55. KekikStream/Plugins/RecTV.py +47 -85
  56. KekikStream/Plugins/SelcukFlix.py +29 -47
  57. KekikStream/Plugins/SetFilmIzle.py +28 -84
  58. KekikStream/Plugins/SezonlukDizi.py +27 -59
  59. KekikStream/Plugins/Sinefy.py +37 -100
  60. KekikStream/Plugins/SinemaCX.py +12 -18
  61. KekikStream/Plugins/Sinezy.py +11 -12
  62. KekikStream/Plugins/SuperFilmGeldi.py +8 -13
  63. KekikStream/Plugins/UgurFilm.py +14 -14
  64. KekikStream/Plugins/Watch32.py +42 -74
  65. KekikStream/Plugins/YabanciDizi.py +33 -87
  66. {kekikstream-2.4.2.dist-info → kekikstream-2.4.4.dist-info}/METADATA +1 -1
  67. kekikstream-2.4.4.dist-info/RECORD +93 -0
  68. kekikstream-2.4.2.dist-info/RECORD +0 -93
  69. {kekikstream-2.4.2.dist-info → kekikstream-2.4.4.dist-info}/WHEEL +0 -0
  70. {kekikstream-2.4.2.dist-info → kekikstream-2.4.4.dist-info}/entry_points.txt +0 -0
  71. {kekikstream-2.4.2.dist-info → kekikstream-2.4.4.dist-info}/licenses/LICENSE +0 -0
  72. {kekikstream-2.4.2.dist-info → kekikstream-2.4.4.dist-info}/top_level.txt +0 -0
@@ -6,22 +6,12 @@ class SibNet(ExtractorBase):
6
6
  name = "SibNet"
7
7
  main_url = "https://video.sibnet.ru"
8
8
 
9
- async def extract(self, url, referer=None) -> ExtractResult:
10
- if referer:
11
- self.httpx.headers.update({"Referer": referer})
9
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
10
+ self.httpx.headers.update({"Referer": referer or url})
12
11
 
13
- response = await self.httpx.get(url)
14
- response.raise_for_status()
12
+ resp = await self.httpx.get(url)
13
+ path = HTMLHelper(resp.text).regex_first(r'player\.src\(\[\{src: "([^\"]+)"')
14
+ if not path:
15
+ raise ValueError(f"SibNet: Video yolu bulunamadı. {url}")
15
16
 
16
- m3u_suffix = HTMLHelper(response.text).regex_first(r'player\.src\(\[\{src: "([^\"]+)"')
17
- if not m3u_suffix:
18
- raise ValueError("m3u bağlantısı bulunamadı.")
19
-
20
- m3u_link = f"{self.main_url}{m3u_suffix}"
21
-
22
- return ExtractResult(
23
- name = self.name,
24
- url = m3u_link,
25
- referer = url,
26
- subtitles = []
27
- )
17
+ return ExtractResult(name=self.name, url=f"{self.main_url}{path}", referer=url)
@@ -7,53 +7,31 @@ class Sobreatsesuyp(ExtractorBase):
7
7
  name = "Sobreatsesuyp"
8
8
  main_url = "https://sobreatsesuyp.com"
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
+ ref = referer or self.main_url
12
+ self.httpx.headers.update({"Referer": ref})
13
13
 
14
- istek = await self.httpx.get(url)
15
- istek.raise_for_status()
14
+ resp = await self.httpx.get(url)
15
+ path = HTMLHelper(resp.text).regex_first(r'file":"([^\"]+)')
16
+ if not path:
17
+ raise ValueError(f"Sobreatsesuyp: File path bulunamadı. {url}")
16
18
 
17
- file_path = HTMLHelper(istek.text).regex_first(r'file":"([^\"]+)')
18
- if not file_path:
19
- raise ValueError("File not found in response.")
19
+ post_resp = await self.httpx.post(f"{self.main_url}/{path.replace('\\', '')}")
20
+ data_list = post_resp.json()[1:] if isinstance(post_resp.json(), list) else []
20
21
 
21
- file_path = file_path.replace("\\", "")
22
- post_link = f"{self.main_url}/{file_path}"
23
-
24
- post_istek = await self.httpx.post(post_link)
25
- post_istek.raise_for_status()
26
-
27
- try:
28
- post_json = json.loads(post_istek.text)
29
- except json.JSONDecodeError as hata:
30
- raise ValueError("Failed to parse JSON response.") from hata
31
-
32
- video_data_list = post_json[1:] if isinstance(post_json, list) else []
33
-
34
- all_results = []
35
-
36
- for item in video_data_list:
22
+ results = []
23
+ for item in data_list:
37
24
  title = item.get("title")
38
25
  file = item.get("file")
39
-
40
- if not title or not file:
41
- continue
42
-
43
- playlist_url = f"{self.main_url}/playlist/{file.lstrip('/')}.txt"
44
- playlist_request = await self.httpx.post(playlist_url, headers={"Referer": referer or self.main_url})
45
- playlist_request.raise_for_status()
46
-
47
- all_results.append(
48
- ExtractResult(
49
- name = f"{self.name} - {title}",
50
- url = playlist_request.text,
51
- referer = self.main_url,
52
- subtitles = []
53
- )
54
- )
55
-
56
- if not all_results:
57
- raise ValueError("No videos found in response.")
58
-
59
- return all_results[0] if len(all_results) == 1 else all_results
26
+ if title and file:
27
+ playlist_resp = await self.httpx.post(f"{self.main_url}/playlist/{file.lstrip('/')}.txt")
28
+ results.append(ExtractResult(
29
+ name = f"{self.name} - {title}",
30
+ url = playlist_resp.text,
31
+ referer = self.main_url
32
+ ))
33
+
34
+ if not results:
35
+ raise ValueError(f"Sobreatsesuyp: Video bulunamadı. {url}")
36
+
37
+ return results[0] if len(results) == 1 else results
@@ -7,61 +7,31 @@ class TRsTX(ExtractorBase):
7
7
  name = "TRsTX"
8
8
  main_url = "https://trstx.org"
9
9
 
10
- async def extract(self, url, referer=None) -> list[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
+ ref = referer or self.main_url
12
+ self.httpx.headers.update({"Referer": ref})
13
13
 
14
- istek = await self.httpx.get(url)
15
- istek.raise_for_status()
14
+ resp = await self.httpx.get(url)
15
+ path = HTMLHelper(resp.text).regex_first(r'file":"([^\"]+)')
16
+ if not path:
17
+ raise ValueError(f"TRsTX: File path bulunamadı. {url}")
16
18
 
17
- file_path = HTMLHelper(istek.text).regex_first(r'file":"([^\"]+)')
18
- if not file_path:
19
- raise ValueError("File not found in response.")
19
+ post_resp = await self.httpx.post(f"{self.main_url}/{path.replace('\\', '')}")
20
+ data_list = post_resp.json()[1:] if isinstance(post_resp.json(), list) else []
20
21
 
21
- file_path = file_path.replace("\\", "")
22
- post_link = f"{self.main_url}/{file_path}"
23
-
24
- post_istek = await self.httpx.post(post_link)
25
- post_istek.raise_for_status()
26
-
27
- try:
28
- post_json = json.loads(post_istek.text)
29
- except json.JSONDecodeError as hata:
30
- raise ValueError("Failed to parse JSON response.") from hata
31
-
32
- video_data_list = post_json[1:] if isinstance(post_json, list) else []
33
-
34
- video_links = set()
35
- all_results = []
36
-
37
- for item in video_data_list:
22
+ results = []
23
+ for item in data_list:
38
24
  title = item.get("title")
39
25
  file = item.get("file")
40
-
41
- if not title or not file:
42
- continue
43
-
44
- playlist_url = f"{self.main_url}/playlist/{file.lstrip('/')}.txt"
45
- playlist_request = await self.httpx.post(playlist_url, headers={"Referer": referer or self.main_url})
46
- playlist_request.raise_for_status()
47
-
48
- video_data = playlist_request.text
49
-
50
- if video_data in video_links:
51
- continue
52
-
53
- video_links.add(video_data)
54
-
55
- all_results.append(
56
- ExtractResult(
57
- name = f"{self.name} - {title}",
58
- url = video_data,
59
- referer = self.main_url,
60
- subtitles = []
61
- )
62
- )
63
-
64
- if not all_results:
65
- raise ValueError("No videos found in response.")
66
-
67
- return all_results[0] if len(all_results) == 1 else all_results
26
+ if title and file:
27
+ playlist_resp = await self.httpx.post(f"{self.main_url}/playlist/{file.lstrip('/')}.txt")
28
+ results.append(ExtractResult(
29
+ name = f"{self.name} - {title}",
30
+ url = playlist_resp.text,
31
+ referer = self.main_url
32
+ ))
33
+
34
+ if not results:
35
+ raise ValueError(f"TRsTX: Video bulunamadı. {url}")
36
+
37
+ return results[0] if len(results) == 1 else results
@@ -6,19 +6,12 @@ class TurboImgz(ExtractorBase):
6
6
  name = "TurboImgz"
7
7
  main_url = "https://turbo.imgz.me"
8
8
 
9
- async def extract(self, url, referer=None) -> ExtractResult:
10
- if referer:
11
- self.httpx.headers.update({"Referer": referer})
9
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
10
+ self.httpx.headers.update({"Referer": referer or url})
12
11
 
13
- istek = await self.httpx.get(url)
14
- istek.raise_for_status()
12
+ resp = await self.httpx.get(url)
13
+ v_url = HTMLHelper(resp.text).regex_first(r'file: "(.*)",')
14
+ if not v_url:
15
+ raise ValueError(f"TurboImgz: Video bulunamadı. {url}")
15
16
 
16
- if video := HTMLHelper(istek.text).regex_first(r'file: "(.*)",'):
17
- return ExtractResult(
18
- name = self.name,
19
- url = video,
20
- referer = referer or self.main_url,
21
- subtitles = []
22
- )
23
- else:
24
- raise ValueError("File not found in response.")
17
+ return ExtractResult(name=self.name, url=v_url, referer=referer or self.main_url)
@@ -7,35 +7,17 @@ class VCTPlay(ExtractorBase):
7
7
  name = "VCTPlay"
8
8
  main_url = "https://vctplay.site"
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) -> ExtractResult:
11
+ v_id = url.split("/")[-1].split("?")[0]
12
+ params = parse_qs(urlparse(url).query)
13
+ part_key = params.get("partKey", [""])[0].lower()
13
14
 
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
15
+ suffix = ""
16
+ if "turkcedublaj" in part_key: suffix = "Dublaj"
17
+ elif "turkcealtyazi" in part_key: suffix = "Altyazı"
35
18
 
36
19
  return ExtractResult(
37
- name = display_name,
38
- url = master_url,
39
- referer = f"{self.main_url}/",
40
- subtitles = []
20
+ name = f"{self.name} - {suffix}" if suffix else self.name,
21
+ url = f"{self.main_url}/manifests/{v_id}/master.txt",
22
+ referer = f"{self.main_url}/"
41
23
  )
@@ -25,46 +25,26 @@ class VidHide(ExtractorBase):
25
25
  return url.replace("/f/", "/v/")
26
26
 
27
27
  async def extract(self, url: str, referer: str = None) -> ExtractResult:
28
- # Dinamik base URL kullan
29
28
  base_url = self.get_base_url(url)
30
-
31
- if referer:
32
- self.httpx.headers.update({"Referer": referer})
33
-
34
29
  self.httpx.headers.update({
35
- "Sec-Fetch-Dest" : "empty",
36
- "Sec-Fetch-Mode" : "cors",
37
- "Sec-Fetch-Site" : "cross-site",
38
- "Origin" : base_url,
30
+ "Referer" : referer or base_url,
31
+ "Origin" : base_url,
39
32
  })
40
33
 
41
34
  embed_url = self.get_embed_url(url)
42
35
  istek = await self.httpx.get(embed_url)
43
- response = istek.text
36
+ sel = HTMLHelper(istek.text)
44
37
 
45
- script = None
46
- if "eval(function" in response:
38
+ unpacked = ""
39
+ if "eval(function" in istek.text:
47
40
  try:
48
- unpacked = Packer.unpack(response)
49
- if "var links" in unpacked:
50
- script = unpacked.split("var links")[1]
51
- else:
52
- script = unpacked
53
- except Exception:
41
+ unpacked = Packer.unpack(istek.text)
42
+ except:
54
43
  pass
55
44
 
56
- if not script:
57
- script = HTMLHelper(response).regex_first(r'(?s)sources:\s*(\[.*?\])')
58
-
59
- m3u8_url = None
60
- if script:
61
- # m3u8 urls could be prefixed by 'file:', 'hls2:' or 'hls4:', so we just match ':'
62
- m3u8_url = HTMLHelper(script).regex_first(r':\s*"([^\"]*?m3u8[^\"]*?)"')
45
+ content = unpacked or istek.text
46
+ m3u8_url = HTMLHelper(content).regex_first(r'[:"]\s*["\']([^"\']+\.m3u8[^"\']*)["\']')
63
47
 
64
- if not m3u8_url:
65
- # Fallback direct search in response if unpacking failed or structure changed
66
- m3u8_url = HTMLHelper(response).regex_first(r'file:"(.*?\.m3u8.*?)"')
67
-
68
48
  if not m3u8_url:
69
49
  raise ValueError(f"VidHide: Video URL bulunamadı. {url}")
70
50
 
@@ -72,6 +52,5 @@ class VidHide(ExtractorBase):
72
52
  name = self.name,
73
53
  url = self.fix_url(m3u8_url),
74
54
  referer = f"{base_url}/",
75
- user_agent = self.httpx.headers.get("User-Agent", ""),
76
- subtitles = []
55
+ user_agent = self.httpx.headers.get("User-Agent", "")
77
56
  )
@@ -9,7 +9,7 @@ class VidMoly(ExtractorBase):
9
9
  main_url = "https://vidmoly.to"
10
10
 
11
11
  # Birden fazla domain destekle
12
- supported_domains = ["vidmoly.to", "vidmoly.me", "vidmoly.net"]
12
+ supported_domains = ["vidmoly.to", "vidmoly.me", "vidmoly.net", "vidmoly.biz"]
13
13
 
14
14
  def can_handle_url(self, url: str) -> bool:
15
15
  return any(domain in url for domain in self.supported_domains)
@@ -18,112 +18,78 @@ class VidMoly(ExtractorBase):
18
18
  if referer:
19
19
  self.httpx.headers.update({"Referer": referer})
20
20
 
21
- self.httpx.headers.update({
22
- "Sec-Fetch-Dest" : "iframe",
23
- })
24
-
25
- if ".me" in url:
26
- url = url.replace(".me", ".net")
27
- if ".to" in url:
28
- url = url.replace(".to", ".net")
29
-
30
- # VidMoly bazen redirect ediyor, takip et
31
- response = await self.httpx.get(url, follow_redirects=True)
32
- if "Select number" in response.text:
33
- secici = HTMLHelper(response.text)
34
-
35
- op_val = secici.select_attr("input[name='op']", "value")
36
- file_code_val = secici.select_attr("input[name='file_code']", "value")
37
- answer_val = secici.select_text("div.vhint b")
38
- ts_val = secici.select_attr("input[name='ts']", "value")
39
- nonce_val = secici.select_attr("input[name='nonce']", "value")
40
- ctok_val = secici.select_attr("input[name='ctok']", "value")
41
-
42
- response = await self.httpx.post(
43
- url = url,
44
- data = {
45
- "op" : op_val,
46
- "file_code" : file_code_val,
47
- "answer" : answer_val,
48
- "ts" : ts_val,
49
- "nonce" : nonce_val,
50
- "ctok" : ctok_val
51
- },
52
- follow_redirects=True
53
- )
54
-
21
+ self.httpx.headers.update({"Sec-Fetch-Dest" : "iframe"})
22
+
23
+ # Domain normalleştirme
24
+ url = url.replace(".me", ".net").replace(".to", ".net")
25
+
26
+ resp = await self.httpx.get(url, follow_redirects=True)
27
+ sel = HTMLHelper(resp.text)
28
+
29
+ # "Select number" kontrolü (Bot koruması)
30
+ if "Select number" in resp.text:
31
+ op_val = sel.select_attr("input[name='op']", "value")
32
+ file_code_val = sel.select_attr("input[name='file_code']", "value")
33
+ answer_val = sel.select_text("div.vhint b")
34
+ ts_val = sel.select_attr("input[name='ts']", "value")
35
+ nonce_val = sel.select_attr("input[name='nonce']", "value")
36
+ ctok_val = sel.select_attr("input[name='ctok']", "value")
37
+
38
+ resp = await self.httpx.post(url, data={
39
+ "op" : op_val,
40
+ "file_code" : file_code_val,
41
+ "answer" : answer_val,
42
+ "ts" : ts_val,
43
+ "nonce" : nonce_val,
44
+ "ctok" : ctok_val
45
+ }, follow_redirects=True)
46
+ sel = HTMLHelper(resp.text)
55
47
 
56
48
  # Altyazı kaynaklarını ayrıştır
57
49
  subtitles = []
58
- resp_sec = HTMLHelper(response.text)
59
- if subtitle_str := resp_sec.regex_first(r"tracks:\s*\[(.*?)\]", flags= re.DOTALL):
60
- subtitle_data = self._add_marks(subtitle_str, "file")
61
- subtitle_data = self._add_marks(subtitle_data, "label")
62
- subtitle_data = self._add_marks(subtitle_data, "kind")
50
+ if sub_str := sel.regex_first(r"tracks:\s*\[(.*?)\]", flags=re.DOTALL):
51
+ sub_data = self._add_marks(sub_str, "file")
52
+ sub_data = self._add_marks(sub_data, "label")
53
+ sub_data = self._add_marks(sub_data, "kind")
63
54
 
64
55
  with contextlib.suppress(json.JSONDecodeError):
65
- subtitle_sources = json.loads(f"[{subtitle_data}]")
56
+ sub_sources = json.loads(f"[{sub_data}]")
66
57
  subtitles = [
67
- Subtitle(
68
- name = sub.get("label"),
69
- url = self.fix_url(sub.get("file")),
70
- )
71
- for sub in subtitle_sources
72
- if sub.get("kind") == "captions"
58
+ Subtitle(name=sub.get("label"), url=self.fix_url(sub.get("file")))
59
+ for sub in sub_sources if sub.get("kind") == "captions"
73
60
  ]
74
61
 
75
- if "#EXTM3U" in response.text:
76
- for line in response.text.splitlines():
77
- line = line.strip().replace('"', '').replace("'", "")
78
- if line.startswith("http"):
79
- return ExtractResult(
80
- name = self.name,
81
- url = line,
82
- referer = self.main_url,
83
- subtitles = subtitles
84
- )
85
-
86
- if script_str := resp_sec.regex_first(r"sources:\s*\[(.*?)\],", flags= re.DOTALL):
87
- script_content = script_str
88
- # Video kaynaklarını ayrıştır
89
- video_data = self._add_marks(script_content, "file")
90
- try:
91
- video_sources = json.loads(f"[{video_data}]")
92
- # İlk video kaynağını al
93
- for source in video_sources:
94
- if file_url := source.get("file"):
95
- return ExtractResult(
96
- name = self.name,
97
- url = file_url,
98
- referer = self.main_url,
99
- subtitles = subtitles
100
- )
101
- except json.JSONDecodeError:
102
- pass
103
-
104
- # Fallback: Doğrudan file regex ile ara (Kotlin mantığı)
105
- # file:"..." veya file: "..."
106
- if file_match := resp_sec.regex_first(r'file\s*:\s*["\']([^"\']+\.m3u8[^"\']*)["\']'):
107
- return ExtractResult(
108
- name = self.name,
109
- url = file_match,
110
- referer = self.main_url,
111
- subtitles = subtitles
112
- )
113
-
114
- # Fallback 2: Herhangi bir file (m3u8 olma şartı olmadan ama tercihen)
115
- if file_match := resp_sec.regex_first(r'file\s*:\s*["\']([^"\']+)["\']'):
116
- url_candidate = file_match
117
- # Resim dosyalarını hariç tut
118
- if not url_candidate.endswith(('.jpg', '.png', '.jpeg')):
119
- return ExtractResult(
120
- name = self.name,
121
- url = url_candidate,
122
- referer = self.main_url,
123
- subtitles = subtitles
124
- )
125
-
126
- raise ValueError("Video URL bulunamadı.")
62
+ # Video URL Bulma
63
+ video_url = None
64
+ if "#EXTM3U" in resp.text:
65
+ for line in resp.text.splitlines():
66
+ if line.strip().startswith("http"):
67
+ video_url = line.strip().replace('"', '').replace("'", "")
68
+ break
69
+
70
+ if not video_url:
71
+ if src_str := sel.regex_first(r"sources:\s*\[(.*?)\],", flags=re.DOTALL):
72
+ vid_data = self._add_marks(src_str, "file")
73
+ with contextlib.suppress(json.JSONDecodeError):
74
+ vid_sources = json.loads(f"[{vid_data}]")
75
+ for source in vid_sources:
76
+ if source.get("file"):
77
+ video_url = source.get("file")
78
+ break
79
+
80
+ if not video_url:
81
+ video_url = sel.regex_first(r'file\s*:\s*["\']([^"\']+\.m3u8[^"\']*)["\']') or \
82
+ sel.regex_first(r'file\s*:\s*["\']([^"\']+\.mp4[^"\']*)["\']')
83
+
84
+ if not video_url:
85
+ raise ValueError(f"VidMoly: Video URL bulunamadı. {url}")
86
+
87
+ return ExtractResult(
88
+ name = self.name,
89
+ url = video_url,
90
+ referer = f"{self.get_base_url(url)}/",
91
+ subtitles = subtitles
92
+ )
127
93
 
128
94
  def _add_marks(self, text: str, field: str) -> str:
129
95
  """
@@ -7,42 +7,31 @@ class VidMoxy(ExtractorBase):
7
7
  name = "VidMoxy"
8
8
  main_url = "https://vidmoxy.com"
9
9
 
10
- async def extract(self, url, referer=None) -> ExtractResult:
10
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
11
11
  if referer:
12
12
  self.httpx.headers.update({"Referer": referer})
13
13
 
14
- istek = await self.httpx.get(url)
15
- istek.raise_for_status()
14
+ resp = await self.httpx.get(url)
15
+ sel = HTMLHelper(resp.text)
16
16
 
17
- subtitles = []
18
- subtitle_matches = HTMLHelper(istek.text).regex_all(r'captions","file":"([^\"]+)","label":"([^\"]+)"')
19
- seen_subtitles = set()
17
+ subtitles = []
18
+ for s_url, s_lang in sel.regex_all(r'captions","file":"([^\"]+)","label":"([^\"]+)"'):
19
+ decoded_lang = s_lang.encode().decode('unicode_escape')
20
+ subtitles.append(Subtitle(name=decoded_lang, url=s_url.replace("\\", "")))
20
21
 
21
- for sub_url, sub_lang in subtitle_matches:
22
- if sub_url in seen_subtitles:
23
- continue
22
+ hex_data = sel.regex_first(r'file": "(.*)",')
23
+ if not hex_data:
24
+ eval_data = sel.regex_first(r'\};\s*(eval\(function[\s\S]*?)var played = \d+;')
25
+ if eval_data:
26
+ unpacked = Packer.unpack(Packer.unpack(eval_data))
27
+ hex_data = HTMLHelper(unpacked).regex_first(r'file":"(.*)","label')
24
28
 
25
- seen_subtitles.add(sub_url)
26
- decoded_lang = (
27
- sub_lang.replace("\\u0131", "ı")
28
- .replace("\\u0130", "İ")
29
- .replace("\\u00fc", "ü")
30
- .replace("\\u00e7", "ç")
31
- )
32
- subtitles.append(Subtitle(name=decoded_lang, url=sub_url.replace("\\", "")))
33
-
34
- escaped_hex = HTMLHelper(istek.text).regex_first(r'file": "(.*)",')
35
- if not escaped_hex:
36
- eval_jwsetup = HTMLHelper(istek.text).regex_first(r'\};\s*(eval\(function[\s\S]*?)var played = \d+;')
37
- jwsetup = Packer.unpack(Packer.unpack(eval_jwsetup)) if eval_jwsetup else None
38
- if jwsetup:
39
- escaped_hex = HTMLHelper(jwsetup).regex_first(r'file":"(.*)","label')
40
-
41
- m3u_link = HexCodec.decode(escaped_hex)
29
+ if not hex_data:
30
+ raise ValueError(f"VidMoxy: Hex data bulunamadı. {url}")
42
31
 
43
32
  return ExtractResult(
44
33
  name = self.name,
45
- url = m3u_link,
34
+ url = HexCodec.decode(hex_data),
46
35
  referer = self.main_url,
47
36
  subtitles = subtitles
48
37
  )