KekikStream 2.3.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 (85) hide show
  1. KekikStream/Core/Extractor/ExtractorBase.py +3 -2
  2. KekikStream/Core/Extractor/ExtractorLoader.py +8 -14
  3. KekikStream/Core/HTMLHelper.py +120 -49
  4. KekikStream/Core/Plugin/PluginBase.py +30 -12
  5. KekikStream/Core/Plugin/PluginLoader.py +12 -14
  6. KekikStream/Core/Plugin/PluginManager.py +2 -2
  7. KekikStream/Core/Plugin/PluginModels.py +0 -3
  8. KekikStream/Extractors/Abstream.py +27 -0
  9. KekikStream/Extractors/CloseLoad.py +30 -54
  10. KekikStream/Extractors/ContentX.py +27 -72
  11. KekikStream/Extractors/DonilasPlay.py +33 -77
  12. KekikStream/Extractors/DzenRu.py +10 -24
  13. KekikStream/Extractors/ExPlay.py +20 -38
  14. KekikStream/Extractors/Filemoon.py +21 -46
  15. KekikStream/Extractors/HDMomPlayer.py +30 -0
  16. KekikStream/Extractors/HDPlayerSystem.py +13 -31
  17. KekikStream/Extractors/HotStream.py +27 -0
  18. KekikStream/Extractors/JFVid.py +3 -24
  19. KekikStream/Extractors/JetTv.py +21 -34
  20. KekikStream/Extractors/JetV.py +55 -0
  21. KekikStream/Extractors/MailRu.py +11 -29
  22. KekikStream/Extractors/MixPlayHD.py +15 -28
  23. KekikStream/Extractors/MixTiger.py +17 -40
  24. KekikStream/Extractors/MolyStream.py +17 -21
  25. KekikStream/Extractors/Odnoklassniki.py +40 -104
  26. KekikStream/Extractors/PeaceMakerst.py +18 -45
  27. KekikStream/Extractors/PixelDrain.py +8 -16
  28. KekikStream/Extractors/PlayerFilmIzle.py +22 -41
  29. KekikStream/Extractors/RapidVid.py +21 -35
  30. KekikStream/Extractors/SetPlay.py +18 -43
  31. KekikStream/Extractors/SibNet.py +7 -17
  32. KekikStream/Extractors/Sobreatsesuyp.py +23 -45
  33. KekikStream/Extractors/TRsTX.py +23 -53
  34. KekikStream/Extractors/TurboImgz.py +7 -14
  35. KekikStream/Extractors/VCTPlay.py +10 -28
  36. KekikStream/Extractors/Veev.py +145 -0
  37. KekikStream/Extractors/VidBiz.py +62 -0
  38. KekikStream/Extractors/VidHide.py +58 -30
  39. KekikStream/Extractors/VidMoly.py +65 -99
  40. KekikStream/Extractors/VidMoxy.py +16 -27
  41. KekikStream/Extractors/VidPapi.py +24 -54
  42. KekikStream/Extractors/VideoSeyred.py +19 -40
  43. KekikStream/Extractors/Videostr.py +58 -0
  44. KekikStream/Extractors/Vidoza.py +18 -0
  45. KekikStream/Extractors/Vtbe.py +38 -0
  46. KekikStream/Extractors/YTDLP.py +2 -2
  47. KekikStream/Extractors/YildizKisaFilm.py +13 -31
  48. KekikStream/Extractors/Zeus.py +61 -0
  49. KekikStream/Plugins/BelgeselX.py +97 -77
  50. KekikStream/Plugins/DiziBox.py +28 -45
  51. KekikStream/Plugins/DiziMom.py +179 -0
  52. KekikStream/Plugins/DiziPal.py +95 -161
  53. KekikStream/Plugins/DiziYou.py +51 -147
  54. KekikStream/Plugins/Dizilla.py +40 -61
  55. KekikStream/Plugins/FilmBip.py +90 -39
  56. KekikStream/Plugins/FilmEkseni.py +199 -0
  57. KekikStream/Plugins/FilmMakinesi.py +72 -73
  58. KekikStream/Plugins/FilmModu.py +25 -35
  59. KekikStream/Plugins/Filmatek.py +184 -0
  60. KekikStream/Plugins/FilmciBaba.py +155 -0
  61. KekikStream/Plugins/FullHDFilmizlesene.py +16 -37
  62. KekikStream/Plugins/HDFilm.py +243 -0
  63. KekikStream/Plugins/HDFilmCehennemi.py +242 -189
  64. KekikStream/Plugins/JetFilmizle.py +101 -69
  65. KekikStream/Plugins/KultFilmler.py +138 -104
  66. KekikStream/Plugins/RecTV.py +52 -73
  67. KekikStream/Plugins/RoketDizi.py +18 -27
  68. KekikStream/Plugins/SelcukFlix.py +30 -48
  69. KekikStream/Plugins/SetFilmIzle.py +76 -104
  70. KekikStream/Plugins/SezonlukDizi.py +90 -94
  71. KekikStream/Plugins/Sinefy.py +195 -167
  72. KekikStream/Plugins/SinemaCX.py +148 -78
  73. KekikStream/Plugins/Sinezy.py +29 -31
  74. KekikStream/Plugins/SuperFilmGeldi.py +12 -17
  75. KekikStream/Plugins/UgurFilm.py +85 -38
  76. KekikStream/Plugins/Watch32.py +160 -0
  77. KekikStream/Plugins/YabanciDizi.py +176 -211
  78. {kekikstream-2.3.9.dist-info → kekikstream-2.5.3.dist-info}/METADATA +1 -1
  79. kekikstream-2.5.3.dist-info/RECORD +99 -0
  80. {kekikstream-2.3.9.dist-info → kekikstream-2.5.3.dist-info}/WHEEL +1 -1
  81. KekikStream/Plugins/FullHDFilm.py +0 -249
  82. kekikstream-2.3.9.dist-info/RECORD +0 -84
  83. {kekikstream-2.3.9.dist-info → kekikstream-2.5.3.dist-info}/entry_points.txt +0 -0
  84. {kekikstream-2.3.9.dist-info → kekikstream-2.5.3.dist-info}/licenses/LICENSE +0 -0
  85. {kekikstream-2.3.9.dist-info → kekikstream-2.5.3.dist-info}/top_level.txt +0 -0
@@ -1,45 +1,32 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle, HTMLHelper
4
- import json
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
4
+ import contextlib
5
5
 
6
6
  class JetTv(ExtractorBase):
7
7
  name = "JetTv"
8
8
  main_url = "https://jetv.xyz"
9
9
 
10
10
  async def extract(self, url: str, referer: str = None) -> ExtractResult:
11
- istek = await self.httpx.get(url)
12
- document = istek.text
11
+ resp = await self.httpx.get(url)
12
+ sel = HTMLHelper(resp.text)
13
13
 
14
- # 1. Yöntem: API üzerinden alma
15
- master_url = ""
16
- final_ref = f"{self.main_url}/"
14
+ m3u8_url = None
15
+ final_ref = self.main_url
17
16
 
18
17
  if "id=" in url:
19
- vid_id = url.split("id=")[-1]
20
- api_url = f"https://jetv.xyz/apollo/get_video.php?id={vid_id}"
21
- try:
22
- # Referer olarak video sayfasının kendisi gönderilmeli
23
- api_resp = await self.httpx.get(api_url, headers={"Referer": url})
24
- api_json = api_resp.json()
25
-
26
- if api_json.get("success"):
27
- master_url = api_json.get("masterUrl", "")
28
- final_ref = api_json.get("referrerUrl") or final_ref
29
- except Exception:
30
- pass
31
-
32
- # 2. Yöntem: Regex Fallback
33
- if not master_url:
34
- hp = HTMLHelper(document)
35
- master_url = hp.regex_first(r"(?i)file: '([^']*)'") or master_url
36
-
37
- if not master_url:
38
- raise ValueError(f"JetTv: Video kaynağı bulunamadı. {url}")
39
-
40
- return ExtractResult(
41
- name = self.name,
42
- url = master_url,
43
- referer = final_ref,
44
- subtitles = []
45
- )
18
+ v_id = url.split("id=")[-1]
19
+ with contextlib.suppress(Exception):
20
+ api_resp = await self.httpx.get(f"{self.main_url}/apollo/get_video.php?id={v_id}", headers={"Referer": url})
21
+ data = api_resp.json()
22
+ if data.get("success"):
23
+ m3u8_url = data.get("masterUrl")
24
+ final_ref = data.get("referrerUrl") or final_ref
25
+
26
+ if not m3u8_url:
27
+ m3u8_url = sel.regex_first(r"(?i)file: '([^']*)'")
28
+
29
+ if not m3u8_url:
30
+ raise ValueError(f"JetTv: Video URL bulunamadı. {url}")
31
+
32
+ return ExtractResult(name=self.name, url=m3u8_url, referer=final_ref)
@@ -0,0 +1,55 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
4
+ import json, re
5
+
6
+ class JetV(ExtractorBase):
7
+ name = "JetV"
8
+ main_url = "https://jetv.xyz"
9
+
10
+ async def extract(self, url: str, referer: str = None) -> list[ExtractResult]:
11
+ istek = await self.httpx.get(url, headers={"Referer": referer} if referer else None)
12
+ text = istek.text
13
+
14
+ # Script içindeki sources kısmını bul
15
+ # "sources": [ ... ]
16
+ sources_str = HTMLHelper(text).regex_first(r'"sources":\s*(\[.*?\])')
17
+ if not sources_str:
18
+ # Altenatif: sources: [ ... ] (tırnaksız sources)
19
+ sources_str = HTMLHelper(text).regex_first(r'sources:\s*(\[.*?\])')
20
+
21
+ if not sources_str:
22
+ raise ValueError(f"JetV: Sources bulunamadı. {url}")
23
+
24
+ # file: -> "file":
25
+ clean_json = re.sub(r'(\w+):', r'"\1":', sources_str)
26
+ # ' -> "
27
+ clean_json = clean_json.replace("'", '"')
28
+
29
+ try:
30
+ sources = json.loads(clean_json)
31
+ except:
32
+ # Basit parser yetmediyse, manuel parse deneyelim (tek kaynak varsa)
33
+ file_url = HTMLHelper(sources_str).regex_first(r'file["\']?:\s*["\']([^"\']+)["\']')
34
+ label = HTMLHelper(sources_str).regex_first(r'label["\']?:\s*["\']([^"\']+)["\']')
35
+ if file_url:
36
+ sources = [{"file": file_url, "label": label or "Unknown"}]
37
+ else:
38
+ raise ValueError("JetV: JSON parse hatası")
39
+
40
+ results = []
41
+ for source in sources:
42
+ file_path = source.get("file")
43
+ label = source.get("label", "Unknown")
44
+
45
+ if not file_path:
46
+ continue
47
+
48
+ results.append(ExtractResult(
49
+ name = f"{self.name} | {label}",
50
+ url = self.fix_url(file_path),
51
+ referer = url,
52
+ user_agent = self.httpx.headers.get("User-Agent", "")
53
+ ))
54
+
55
+ return results
@@ -2,37 +2,19 @@
2
2
 
3
3
  from KekikStream.Core import ExtractorBase, ExtractResult
4
4
 
5
- class MailRuExtractor(ExtractorBase):
5
+ class MailRu(ExtractorBase):
6
6
  name = "MailRu"
7
7
  main_url = "https://my.mail.ru"
8
8
 
9
- async def extract(self, url, referer=None) -> ExtractResult:
10
- vid_id = url.split("video/embed/")[-1].strip()
11
- video_meta_url = f"{self.main_url}/+/video/meta/{vid_id}"
9
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
10
+ v_id = url.split("video/embed/")[-1].strip()
11
+ if referer: self.httpx.headers.update({"Referer": referer})
12
12
 
13
- if referer:
14
- self.httpx.headers.update({"Referer": referer})
13
+ resp = await self.httpx.get(f"{self.main_url}/+/video/meta/{v_id}")
14
+ data = resp.json()
15
+
16
+ v_url = data.get("videos", [{}])[0].get("url")
17
+ if not v_url:
18
+ raise ValueError(f"MailRu: Video URL bulunamadı. {url}")
15
19
 
16
- istek = await self.httpx.get(video_meta_url)
17
- istek.raise_for_status()
18
-
19
- video_key = istek.cookies.get("video_key")
20
- if not video_key:
21
- raise ValueError("Video key bulunamadı.")
22
-
23
- video_data = istek.json()
24
- videos = video_data.get("videos", [])
25
- if not videos:
26
- raise ValueError("Videolar bulunamadı.")
27
-
28
- video = videos[0]
29
- video_url = video["url"]
30
- if video_url.startswith("//"):
31
- video_url = f"https:{video_url}"
32
-
33
- return ExtractResult(
34
- name = self.name,
35
- url = video_url,
36
- referer = self.main_url,
37
- subtitles = []
38
- )
20
+ return ExtractResult(name=self.name, url=self.fix_url(v_url), referer=self.main_url)
@@ -8,34 +8,21 @@ class MixPlayHD(ExtractorBase):
8
8
  name = "MixPlayHD"
9
9
  main_url = "https://mixplayhd.com"
10
10
 
11
- async def extract(self, url, referer=None) -> ExtractResult:
12
- if referer:
13
- self.httpx.headers.update({"Referer": referer})
11
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
12
+ self.httpx.headers.update({"Referer": referer or self.main_url})
14
13
 
15
- istek = await self.httpx.get(url)
16
- istek.raise_for_status()
17
-
18
- hp = HTMLHelper(istek.text)
19
- be_player_matches = hp.regex_all(r"bePlayer\('([^']+)',\s*'(\{[^\}]+\})'\);")
20
- if not be_player_matches:
21
- raise ValueError("bePlayer not found in the response.")
22
-
23
- be_player_pass, be_player_data = be_player_matches[0]
14
+ resp = await self.httpx.get(url)
15
+ match = HTMLHelper(resp.text).regex_first(r"bePlayer\('([^']+)',\s*'(\{[^\}]+\})'\);", group=None)
16
+ if not match:
17
+ raise ValueError(f"MixPlayHD: bePlayer bulunamadı. {url}")
24
18
 
19
+ pass_val, data_val = match
25
20
  try:
26
- decrypted_data = AESManager.decrypt(be_player_data, be_player_pass).replace("\\", "")
27
- decrypted_json = json.loads(decrypted_data)
28
- except Exception as hata:
29
- raise RuntimeError(f"Decryption failed: {hata}") from hata
30
-
31
- client_str = decrypted_json.get("schedule", {}).get("client", "")
32
- video_url = HTMLHelper(client_str).regex_first(r'"video_location":"([^"]+)"')
33
- if video_url:
34
- return ExtractResult(
35
- name = self.name,
36
- url = video_url,
37
- referer = self.main_url,
38
- subtitles = []
39
- )
40
- else:
41
- raise ValueError("M3U8 video URL not found in the decrypted data.")
21
+ data = json.loads(AESManager.decrypt(data_val, pass_val))
22
+ v_url = HTMLHelper(data.get("schedule", {}).get("client", "")).regex_first(r'"video_location":"([^"]+)"')
23
+ if v_url:
24
+ return ExtractResult(name=self.name, url=v_url, referer=self.main_url)
25
+ except Exception as e:
26
+ raise ValueError(f"MixPlayHD: Decryption failed. {e}")
27
+
28
+ raise ValueError(f"MixPlayHD: Video URL bulunamadı. {url}")
@@ -6,52 +6,29 @@ class MixTiger(ExtractorBase):
6
6
  name = "MixTiger"
7
7
  main_url = "https://www.mixtiger.com"
8
8
 
9
- async def extract(self, url, referer=None) -> ExtractResult:
10
- ext_ref = referer or ""
11
- post_url = f"{url}?do=getVideo"
12
- vid_id = url.split("video/")[-1] if "video/" in url else ""
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 ""
13
12
 
14
- response = await self.httpx.post(
15
- url = post_url,
16
- data = {"hash": vid_id, "r": ext_ref, "s": ""},
13
+ resp = await self.httpx.post(
14
+ f"{url}?do=getVideo",
15
+ data = {"hash": v_id, "r": ref, "s": ""},
17
16
  headers = {
18
- "Referer" : ext_ref,
19
- "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
20
- "X-Requested-With" : "XMLHttpRequest"
17
+ "Referer": ref,
18
+ "X-Requested-With": "XMLHttpRequest"
21
19
  }
22
20
  )
23
- response.raise_for_status()
21
+ data = resp.json()
24
22
 
25
- video_data = response.json()
23
+ m3u8_url = data.get("videoSrc")
24
+ if not m3u8_url and data.get("videoSources"):
25
+ m3u8_url = data["videoSources"][-1].get("file")
26
26
 
27
- # videoSrc varsa doğrudan kullan
28
- if video_data.get("videoSrc"):
29
- m3u_link = video_data["videoSrc"]
30
- # videoSources listesi varsa son elemanı al
31
- elif video_data.get("videoSources"):
32
- sources = video_data["videoSources"]
33
- m3u_link = sources[-1].get("file") if sources else None
34
- else:
35
- m3u_link = None
36
-
37
- if not m3u_link:
38
- raise ValueError("Video URL not found in response")
39
-
40
- # Recursive extraction check - başka extractor kullanılabilir mi?
41
- try:
42
- from KekikStream.Core.Extractor.ExtractorManager import ExtractorManager
43
- manager = ExtractorManager()
44
- if nested_extractor := manager.find_extractor(m3u_link):
45
- # Nested extractor ile çıkar
46
- return await nested_extractor.extract(m3u_link, referer=ext_ref)
47
- except Exception:
48
- # Recursive extraction başarısız olursa standart sonucu döndür
49
- pass
27
+ if not m3u8_url:
28
+ raise ValueError(f"MixTiger: Video linki bulunamadı. {url}")
50
29
 
51
30
  return ExtractResult(
52
- name = self.name,
53
- url = m3u_link,
54
- referer = None if "disk.yandex" in m3u_link else ext_ref,
55
- subtitles = []
31
+ name = self.name,
32
+ url = m3u8_url,
33
+ referer = None if "disk.yandex" in m3u8_url else ref
56
34
  )
57
-
@@ -1,7 +1,6 @@
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, HTMLHelper
4
- import re
5
4
 
6
5
  class MolyStream(ExtractorBase):
7
6
  name = "MolyStream"
@@ -9,34 +8,31 @@ class MolyStream(ExtractorBase):
9
8
 
10
9
  # Birden fazla domain destekle
11
10
  supported_domains = [
12
- "dbx.molystream.org",
13
- "ydx.molystream.org",
14
- "yd.sheila.stream",
15
- "ydf.popcornvakti.net",
11
+ "dbx.molystream.org", "ydx.molystream.org",
12
+ "yd.sheila.stream", "ydf.popcornvakti.net",
16
13
  ]
17
14
 
18
15
  def can_handle_url(self, url: str) -> bool:
19
16
  return any(domain in url for domain in self.supported_domains)
20
17
 
21
- async def extract(self, url, referer=None) -> ExtractResult:
22
- if "doctype html" in url:
23
- secici = HTMLHelper(url)
24
- video = secici.select_attr("video#sheplayer source", "src")
25
- else:
26
- video = url
18
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
19
+ self.httpx.headers.update({"Referer": referer or self.main_url})
27
20
 
28
- resp_sec = HTMLHelper(url)
29
- matches = resp_sec.regex_all(r"addSrtFile\(['\"]([^'\"]+\.srt)['\"]\s*,\s*['\"][a-z]{2}['\"]\s*,\s*['\"]([^'\"]+)['\"]")
21
+ # Eğer url zaten bir HTML kaynağıysa (doctype html içeriyorsa)
22
+ if "doctype html" in url.lower():
23
+ sel = HTMLHelper(url)
24
+ v_url = sel.select_attr("video#sheplayer source", "src")
25
+ else:
26
+ v_url = url
30
27
 
31
- subtitles = [
32
- Subtitle(name = name, url = self.fix_url(url))
33
- for url, name in matches
34
- ]
28
+ subtitles = []
29
+ for s_url, s_name in HTMLHelper(url).regex_all(r"addSrtFile\(['\"]([^'\"]+\.srt)['\"]\s*,\s*['\"][a-z]{2}['\"]\s*,\s*['\"]([^'\"]+)['\"]"):
30
+ subtitles.append(Subtitle(name=s_name, url=self.fix_url(s_url)))
35
31
 
36
32
  return ExtractResult(
37
- name = self.name,
38
- url = video,
39
- referer = video.replace("/sheila", "") if video else None,
33
+ name = self.name,
34
+ url = v_url,
35
+ referer = v_url.replace("/sheila", "") if v_url else None,
40
36
  user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0",
41
- subtitles = subtitles
37
+ subtitles = subtitles
42
38
  )
@@ -1,117 +1,53 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
3
  from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
4
- import re, json
4
+ import json, html
5
5
 
6
6
  class Odnoklassniki(ExtractorBase):
7
7
  name = "Odnoklassniki"
8
8
  main_url = "https://odnoklassniki.ru"
9
9
 
10
- # Birden fazla domain destekle
11
10
  supported_domains = ["odnoklassniki.ru", "ok.ru"]
12
11
 
13
12
  def can_handle_url(self, url: str) -> bool:
14
13
  return any(domain in url for domain in self.supported_domains)
15
14
 
16
- async def extract(self, url, referer=None) -> ExtractResult:
17
- if "/video/" in url:
18
- url = url.replace("/video/", "/videoembed/")
19
-
20
- headers = {
21
- "Accept" : "*/*",
22
- "Connection" : "keep-alive",
23
- "Sec-Fetch-Dest" : "empty",
24
- "Sec-Fetch-Mode" : "cors",
25
- "Sec-Fetch-Site" : "cross-site",
26
- "Origin" : self.main_url,
27
- "User-Agent" : "Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0",
28
- }
29
- self.httpx.headers.update(headers)
30
-
31
- try:
32
- istek = await self.fetch_with_redirects(url)
33
- istek.raise_for_status()
34
- except Exception as hata:
35
- raise RuntimeError(f"Failed to fetch the URL: {url}, Error: {hata}") from hata
36
-
37
- response_text = (
38
- istek.text.replace("\\"", "\"")
39
- .replace("\\\\", "\\")
40
- .replace(r"\\u", "\\u")
41
- )
42
- response_text = re.sub(
43
- r"\\u([0-9A-Fa-f]{4})",
44
- lambda match: chr(int(match[1], 16)),
45
- response_text
46
- )
47
-
48
- videos_json = HTMLHelper(response_text).regex_first(r'"videos":(\[.*?\])')
49
- if not videos_json:
50
- raise ValueError("No video data found in the response.")
51
-
52
- try:
53
- videos = json.loads(videos_json)
54
- except json.JSONDecodeError as hata:
55
- raise ValueError("Failed to parse video data.") from hata
56
-
57
- quality_order = {
58
- "ULTRA": 6, # 4K veya daha yüksek
59
- "QUAD": 5, # 1440p
60
- "FULL": 4, # 1080p
61
- "HD": 3, # 720p
62
- "SD": 2, # 480p
63
- "LOW": 1, # 360p
64
- "MOBILE": 0 # 144p
65
- }
66
-
67
- # Kaliteye göre en iyi videoyu seçme
68
- best_video = None
69
- best_quality_score = -1
70
-
71
- for video in videos:
72
- video_url = video.get("url")
73
- quality_name = video.get("name", "").upper()
74
-
75
- if not video_url or not quality_name:
76
- continue
77
-
78
- # Kalite sıralamasına göre puanla
79
- quality_score = quality_order.get(quality_name, -1)
80
- if quality_score > best_quality_score:
81
- best_quality_score = quality_score
82
- best_video = video_url
83
-
84
- if not best_video:
85
- raise ValueError("No valid video URLs found.")
86
-
87
- if best_video.startswith("//"):
88
- best_video = f"https:{best_video}"
89
-
90
- return ExtractResult(
91
- name = self.name,
92
- url = best_video,
93
- referer = referer,
94
- user_agent = headers.get("User-Agent", None),
95
- subtitles = []
96
- )
97
-
98
- async def fetch_with_redirects(self, url, max_redirects=5):
99
- """Yönlendirmeleri takip eden bir fonksiyon"""
100
- redirects = 0
101
- while redirects < max_redirects:
102
- istek = await self.httpx.get(url, follow_redirects=False)
103
-
104
- if istek.status_code not in [301, 302]:
105
- break # Yönlendirme yoksa çık
106
-
107
- redirected_url = istek.headers.get("Location")
108
- if not redirected_url:
109
- raise ValueError("Redirect location not found.")
110
-
111
- url = redirected_url if redirected_url.startswith("http") else f"https://{redirected_url}"
112
- redirects += 1
113
-
114
- if redirects == max_redirects:
115
- raise RuntimeError(f"Max redirects ({max_redirects}) reached.")
116
-
117
- return istek
15
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
16
+ if "/video/" in url: url = url.replace("/video/", "/videoembed/")
17
+ self.httpx.headers.update({"Origin": self.main_url})
18
+
19
+ resp = await self.httpx.get(url, follow_redirects=True)
20
+ sel = HTMLHelper(resp.text)
21
+
22
+ # Metadata içinden videos array'ini al (esnek regex)
23
+ v_data = sel.regex_first(r'videos[^:]+:(\[.*?\])')
24
+ if not v_data:
25
+ if "Видео заблокировано" in resp.text or "copyrightsRestricted" in resp.text:
26
+ raise ValueError("Odnoklassniki: Video telif nedeniyle silinmiş/erişilemiyor.")
27
+ raise ValueError(f"Odnoklassniki: Video verisi bulunamadı. {url}")
28
+
29
+ # Kalite sıralaması (En yüksekten düşüğe)
30
+ order = ["ULTRA", "QUAD", "FULL", "HD", "SD", "LOW", "MOBILE"]
31
+ # Escaped string'i temizle
32
+ v_data = html.unescape(v_data)
33
+ v_data = v_data.replace('\\"', '"').replace('\\/', '/')
34
+ videos = json.loads(v_data)
35
+
36
+ best_url = None
37
+ for q in order:
38
+ best_url = next((v.get("url") for v in videos if v.get("name", "").upper() == q), None)
39
+ if best_url: break
40
+
41
+ if not best_url:
42
+ best_url = videos[0].get("url") if videos else None
43
+
44
+ if not best_url:
45
+ raise ValueError("Odnoklassniki: Geçerli video URL'si bulunamadı.")
46
+
47
+ # URL temizliği (u0026 -> & ve olası unicode kaçışları)
48
+ best_url = best_url.replace("u0026", "&").replace("\\u0026", "&")
49
+ # Eğer hala \uXXXX formatında unicode kaçışları varsa çöz
50
+ if "\\u" in best_url:
51
+ best_url = best_url.encode().decode('unicode-escape')
52
+
53
+ return ExtractResult(name=self.name, url=self.fix_url(best_url), referer=referer)
@@ -7,57 +7,30 @@ class PeaceMakerst(ExtractorBase):
7
7
  name = "PeaceMakerst"
8
8
  main_url = "https://peacemakerst.com"
9
9
 
10
- # Birden fazla domain destekle
11
10
  supported_domains = ["peacemakerst.com", "hdstreamable.com"]
12
11
 
13
12
  def can_handle_url(self, url: str) -> bool:
14
13
  return any(domain in url for domain in self.supported_domains)
15
14
 
16
- async def extract(self, url, referer=None) -> ExtractResult:
17
- if referer:
18
- self.httpx.headers.update({"Referer": referer})
19
-
15
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
20
16
  self.httpx.headers.update({
21
- "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
17
+ "Referer" : referer or url,
22
18
  "X-Requested-With" : "XMLHttpRequest"
23
19
  })
24
20
 
25
- response = await self.httpx.post(
26
- url = f"{url}?do=getVideo",
27
- data = {
28
- "hash" : url.split("video/")[-1],
29
- "r" : referer or "",
30
- "s" : ""
31
- }
32
- )
33
- response.raise_for_status()
34
-
35
- response_text = response.text
36
- m3u_link = None
37
-
38
- if "teve2.com.tr\\/embed\\/" in response_text:
39
- teve2_id = HTMLHelper(response_text).regex_first(r"teve2\.com\.tr\\\/embed\\\/(\d+)")
40
- teve2_url = f"https://www.teve2.com.tr/action/media/{teve2_id}"
41
-
42
- teve2_response = await self.httpx.get(teve2_url, headers={"Referer": f"https://www.teve2.com.tr/embed/{teve2_id}"})
43
- teve2_response.raise_for_status()
44
- teve2_json = teve2_response.json()
45
-
46
- m3u_link = f"{teve2_json['Media']['Link']['ServiceUrl']}//{teve2_json['Media']['Link']['SecurePath']}"
47
- else:
48
- try:
49
- video_response = response.json()
50
- if video_sources := video_response.get("videoSources", []):
51
- m3u_link = video_sources[-1]["file"]
52
- except (json.JSONDecodeError, KeyError) as hata:
53
- raise ValueError("Peace response is invalid or null.") from hata
54
-
55
- if not m3u_link:
56
- raise ValueError("m3u link not found.")
57
-
58
- return ExtractResult(
59
- name = self.name,
60
- url = m3u_link,
61
- referer = url,
62
- subtitles = []
63
- )
21
+ resp = await self.httpx.post(f"{url}?do=getVideo", data={"hash": url.split("video/")[-1], "r": referer or "", "s": ""})
22
+ data = resp.json()
23
+
24
+ m3u8_url = None
25
+ if "teve2.com.tr" in resp.text:
26
+ v_id = HTMLHelper(resp.text).regex_first(r"teve2\.com\.tr\\\/embed\\\/(\d+)")
27
+ t_resp = await self.httpx.get(f"https://www.teve2.com.tr/action/media/{v_id}")
28
+ t_data = t_resp.json()
29
+ m3u8_url = f"{t_data['Media']['Link']['ServiceUrl']}//{t_data['Media']['Link']['SecurePath']}"
30
+ elif sources := data.get("videoSources"):
31
+ m3u8_url = sources[-1]["file"]
32
+
33
+ if not m3u8_url:
34
+ raise ValueError(f"PeaceMakerst: Video linki bulunamadı. {url}")
35
+
36
+ return ExtractResult(name=self.name, url=m3u8_url, referer=url)
@@ -6,23 +6,15 @@ class PixelDrain(ExtractorBase):
6
6
  name = "PixelDrain"
7
7
  main_url = "https://pixeldrain.com"
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
+ if referer: self.httpx.headers.update({"Referer": referer})
12
11
 
13
- hp = HTMLHelper(url)
14
- matches = hp.regex_all(r"/u/([^/?]+)|([^\/]+)(?=\?download)")
15
- if not matches:
16
- raise ValueError("PixelDrain bağlantısından ID çıkarılamadı.")
17
-
18
- m = matches[0]
19
- pixel_id = next((g for g in m if g), None)
20
- download_link = f"{self.main_url}/api/file/{pixel_id}?download"
21
- referer_link = f"{self.main_url}/u/{pixel_id}?download"
12
+ p_id = HTMLHelper(url).regex_first(r"/u/([^/?]+)|([^\/]+)(?=\?download)")
13
+ if not p_id:
14
+ raise ValueError(f"PixelDrain: ID bulunamadı. {url}")
22
15
 
23
16
  return ExtractResult(
24
- name = f"{self.name} - {pixel_id}",
25
- url = download_link,
26
- referer = referer_link,
27
- subtitles = []
17
+ name = f"{self.name} - {p_id}",
18
+ url = f"{self.main_url}/api/file/{p_id}?download",
19
+ referer = f"{self.main_url}/u/{p_id}?download"
28
20
  )