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.

Potentially problematic release.


This version of KekikStream might be problematic. Click here for more details.

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,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
4
- import re, 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
- if match := re.search(r"file: '([^']*)'", document, re.IGNORECASE):
35
- master_url = match.group(1)
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)
@@ -1,42 +1,28 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from KekikStream.Core import ExtractorBase, ExtractResult
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
4
4
  from Kekik.Sifreleme import AESManager
5
- import re, json
5
+ import json
6
6
 
7
7
  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
- be_player_match = re.search(r"bePlayer\('([^']+)',\s*'(\{[^\}]+\})'\);", istek.text)
19
- if not be_player_match:
20
- raise ValueError("bePlayer not found in the response.")
21
-
22
- be_player_pass = be_player_match[1]
23
- be_player_data = be_player_match[2]
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
- if video_url_match := re.search(
32
- pattern = r'"video_location":"([^"]+)"',
33
- string = decrypted_json.get("schedule", {}).get("client", ""),
34
- ):
35
- return ExtractResult(
36
- name = self.name,
37
- url = video_url_match[1],
38
- referer = self.main_url,
39
- subtitles = []
40
- )
41
- else:
42
- 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,35 +1,38 @@
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
- from selectolax.parser import HTMLParser
5
- import re
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle, HTMLHelper
6
4
 
7
5
  class MolyStream(ExtractorBase):
8
6
  name = "MolyStream"
9
7
  main_url = "https://dbx.molystream.org"
10
8
 
11
- async def extract(self, url, referer=None) -> ExtractResult:
12
- if "doctype html" in url:
13
- secici = HTMLParser(url)
14
- video_el = secici.css_first("video#sheplayer source")
15
- video = video_el.attrs.get("src") if video_el else None
16
- else:
17
- video = url
9
+ # Birden fazla domain destekle
10
+ supported_domains = [
11
+ "dbx.molystream.org", "ydx.molystream.org",
12
+ "yd.sheila.stream", "ydf.popcornvakti.net",
13
+ ]
18
14
 
19
- matches = re.findall(
20
- pattern = r"addSrtFile\(['\"]([^'\"]+\.srt)['\"]\s*,\s*['\"][a-z]{2}['\"]\s*,\s*['\"]([^'\"]+)['\"]",
21
- string = url
22
- )
15
+ def can_handle_url(self, url: str) -> bool:
16
+ return any(domain in url for domain in self.supported_domains)
17
+
18
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
19
+ self.httpx.headers.update({"Referer": referer or self.main_url})
20
+
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
23
27
 
24
- subtitles = [
25
- Subtitle(name = name, url = self.fix_url(url))
26
- for url, name in matches
27
- ]
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)))
28
31
 
29
32
  return ExtractResult(
30
- name = self.name,
31
- url = video,
32
- 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,
33
36
  user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0",
34
- subtitles = subtitles
37
+ subtitles = subtitles
35
38
  )
@@ -1,117 +1,53 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from KekikStream.Core import ExtractorBase, ExtractResult
4
- import re, json
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
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_match = re.search(r'"videos":(\[.*?\])', response_text)
49
- if not videos_match:
50
- raise ValueError("No video data found in the response.")
51
-
52
- try:
53
- videos = json.loads(videos_match[1])
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)
@@ -1,63 +1,36 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from KekikStream.Core import ExtractorBase, ExtractResult
4
- import re, json
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
4
+ import json
5
5
 
6
6
  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 = re.search(r"teve2\.com\.tr\\\/embed\\\/(\d+)", response_text)[1]
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)
@@ -1,27 +1,20 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from KekikStream.Core import ExtractorBase, ExtractResult
4
- import re
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
5
4
 
6
5
  class PixelDrain(ExtractorBase):
7
6
  name = "PixelDrain"
8
7
  main_url = "https://pixeldrain.com"
9
8
 
10
- async def extract(self, url, referer=None) -> ExtractResult:
11
- if referer:
12
- 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})
13
11
 
14
- pixel_id_match = re.search(r"/u/([^/?]+)|([^\/]+)(?=\?download)", url)
15
- if not pixel_id_match:
16
- raise ValueError("PixelDrain bağlantısından ID çıkarılamadı.")
17
-
18
- pixel_id = pixel_id_match[1]
19
- download_link = f"{self.main_url}/api/file/{pixel_id}?download"
20
- 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}")
21
15
 
22
16
  return ExtractResult(
23
- name = f"{self.name} - {pixel_id}",
24
- url = download_link,
25
- referer = referer_link,
26
- 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"
27
20
  )