KekikStream 0.2.3__py3-none-any.whl → 0.5.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. KekikStream/CLI/__init__.py +1 -1
  2. KekikStream/CLI/pypi_kontrol.py +30 -0
  3. KekikStream/Core/ExtractorBase.py +13 -2
  4. KekikStream/Core/ExtractorLoader.py +31 -10
  5. KekikStream/Core/ExtractorModels.py +2 -0
  6. KekikStream/Core/MediaHandler.py +70 -30
  7. KekikStream/Core/PluginBase.py +6 -5
  8. KekikStream/Core/PluginLoader.py +3 -5
  9. KekikStream/Core/PluginModels.py +6 -16
  10. KekikStream/Extractors/ContentX.py +80 -0
  11. KekikStream/Extractors/FourCX.py +7 -0
  12. KekikStream/Extractors/FourPichive.py +7 -0
  13. KekikStream/Extractors/FourPlayRu.py +7 -0
  14. KekikStream/Extractors/HDStreamAble.py +7 -0
  15. KekikStream/Extractors/Hotlinger.py +7 -0
  16. KekikStream/Extractors/MixPlayHD.py +42 -0
  17. KekikStream/Extractors/Odnoklassniki.py +106 -0
  18. KekikStream/Extractors/OkRuHTTP.py +7 -0
  19. KekikStream/Extractors/OkRuSSL.py +7 -0
  20. KekikStream/Extractors/PeaceMakerst.py +57 -0
  21. KekikStream/Extractors/Pichive.py +7 -0
  22. KekikStream/Extractors/PixelDrain.py +1 -1
  23. KekikStream/Extractors/PlayRu.py +7 -0
  24. KekikStream/Extractors/RapidVid.py +9 -10
  25. KekikStream/Extractors/SibNet.py +1 -1
  26. KekikStream/Extractors/Sobreatsesuyp.py +5 -6
  27. KekikStream/Extractors/TRsTX.py +5 -6
  28. KekikStream/Extractors/TauVideo.py +11 -10
  29. KekikStream/Extractors/TurboImgz.py +9 -12
  30. KekikStream/Extractors/VidMoly.py +25 -33
  31. KekikStream/Extractors/VidMoxy.py +1 -1
  32. KekikStream/Extractors/VideoSeyred.py +47 -0
  33. KekikStream/Managers/MediaManager.py +1 -1
  34. KekikStream/Managers/UIManager.py +6 -2
  35. KekikStream/Plugins/DiziBox.py +138 -0
  36. KekikStream/Plugins/Dizilla.py +95 -0
  37. KekikStream/Plugins/FilmMakinesi.py +8 -8
  38. KekikStream/Plugins/FullHDFilmizlesene.py +5 -4
  39. KekikStream/Plugins/JetFilmizle.py +4 -8
  40. KekikStream/Plugins/RecTV.py +111 -0
  41. KekikStream/Plugins/SineWix.py +4 -1
  42. KekikStream/Plugins/UgurFilm.py +3 -3
  43. KekikStream/__init__.py +177 -158
  44. KekikStream/__main__.py +1 -1
  45. KekikStream/requirements.txt +2 -1
  46. {KekikStream-0.2.3.dist-info → KekikStream-0.5.7.dist-info}/METADATA +4 -3
  47. KekikStream-0.5.7.dist-info/RECORD +58 -0
  48. KekikStream/CLI/check_update.py +0 -33
  49. KekikStream-0.2.3.dist-info/RECORD +0 -41
  50. {KekikStream-0.2.3.dist-info → KekikStream-0.5.7.dist-info}/LICENSE +0 -0
  51. {KekikStream-0.2.3.dist-info → KekikStream-0.5.7.dist-info}/WHEEL +0 -0
  52. {KekikStream-0.2.3.dist-info → KekikStream-0.5.7.dist-info}/entry_points.txt +0 -0
  53. {KekikStream-0.2.3.dist-info → KekikStream-0.5.7.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
3
  from Kekik.cli import konsol, cikis_yap, hata_salla, log_salla, hata_yakala, bellek_temizle, temizle
4
- from .check_update import check_and_update_package
4
+ from .pypi_kontrol import pypi_kontrol_guncelle
@@ -0,0 +1,30 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from . import konsol
4
+ from rich.panel import Panel
5
+ from pkg_resources import get_distribution
6
+ from requests import get
7
+ from subprocess import check_call
8
+ import sys
9
+
10
+ def pypi_kontrol_guncelle(paket_adi: str):
11
+ try:
12
+ konsol.print(f"[bold cyan] {paket_adi} Güncellemesi kontrol ediliyor...[/bold cyan]")
13
+ mevcut_surum = get_distribution(paket_adi).version
14
+ konsol.print(Panel(f"[cyan]Yüklü sürüm:[/cyan] [bold yellow]{mevcut_surum}[/bold yellow]"))
15
+
16
+ istek = get(f"https://pypi.org/pypi/{paket_adi}/json")
17
+ if istek.status_code == 200:
18
+ son_surum = istek.json()["info"]["version"]
19
+ konsol.print(Panel(f"[cyan]En son sürüm:[/cyan] [bold green]{son_surum}[/bold green]"))
20
+
21
+ if mevcut_surum != son_surum:
22
+ konsol.print(f"[bold red]{paket_adi} güncelleniyor...[/bold red]")
23
+ check_call([sys.executable, "-m", "pip", "install", "--upgrade", paket_adi, "--break-system-packages"])
24
+ konsol.print(f"[bold green]{paket_adi} güncellendi![/bold green]")
25
+ else:
26
+ konsol.print(f"[bold green]{paket_adi} zaten güncel.[/bold green]")
27
+ else:
28
+ konsol.print("[bold red]PyPI'ye erişilemiyor. Güncelleme kontrolü atlanıyor.[/bold red]")
29
+ except Exception as hata:
30
+ konsol.print(f"[bold red]Güncelleme kontrolü sırasında hata oluştu: {hata}[/bold red]")
@@ -2,6 +2,7 @@
2
2
 
3
3
  from abc import ABC, abstractmethod
4
4
  from httpx import AsyncClient, Timeout
5
+ from cloudscraper import CloudScraper
5
6
  from typing import Optional
6
7
  from .ExtractorModels import ExtractResult
7
8
 
@@ -15,8 +16,9 @@ class ExtractorBase(ABC):
15
16
  "User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5)",
16
17
  "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
17
18
  },
18
- timeout = Timeout(10.0),
19
+ timeout = Timeout(10.0)
19
20
  )
21
+ self.cloudscraper = CloudScraper()
20
22
 
21
23
  def can_handle_url(self, url: str) -> bool:
22
24
  """URL'nin bu extractor tarafından işlenip işlenemeyeceğini kontrol eder."""
@@ -28,4 +30,13 @@ class ExtractorBase(ABC):
28
30
  pass
29
31
 
30
32
  async def close(self):
31
- await self.oturum.aclose()
33
+ await self.oturum.aclose()
34
+
35
+ def fix_url(self, url: str) -> str:
36
+ if not url:
37
+ return ""
38
+
39
+ if url.startswith("http") or url.startswith("{\""):
40
+ return url
41
+
42
+ return f"https:{url}" if url.startswith("//") else urljoin(self.main_url, url)
@@ -3,41 +3,60 @@
3
3
  from ..CLI import konsol, cikis_yap
4
4
  from .ExtractorBase import ExtractorBase
5
5
  from pathlib import Path
6
- import importlib.util
7
- import os
6
+ import os, importlib.util
8
7
 
9
8
  class ExtractorLoader:
10
9
  def __init__(self, extractors_dir: str):
11
10
  self.local_extractors_dir = Path(extractors_dir)
12
11
  self.global_extractors_dir = Path(__file__).parent.parent / extractors_dir
13
12
  if not self.local_extractors_dir.exists() and not self.global_extractors_dir.exists():
14
- konsol.log(f"[red][!] Extractor dizini bulunamadı: {self.extractors_dir}[/red]")
13
+ konsol.log(f"[red][!] Extractor dizini bulunamadı: {self.global_extractors_dir}[/red]")
15
14
  cikis_yap(False)
16
15
 
17
16
  def load_all(self) -> list[ExtractorBase]:
18
17
  extractors = []
19
18
 
19
+ # Global Extractor'ları yükle
20
20
  if self.global_extractors_dir.exists():
21
21
  konsol.log(f"[green][*] Global Extractor dizininden yükleniyor: {self.global_extractors_dir}[/green]")
22
- extractors.extend(self._load_from_directory(self.global_extractors_dir))
22
+ global_extractors = self._load_from_directory(self.global_extractors_dir)
23
+ konsol.log(f"[green]Global Extractor'lar: {[e.__name__ for e in global_extractors]}[/green]")
24
+ extractors.extend(global_extractors)
23
25
 
26
+ # Yerel Extractor'ları yükle
24
27
  if self.local_extractors_dir.exists():
25
28
  konsol.log(f"[green][*] Yerel Extractor dizininden yükleniyor: {self.local_extractors_dir}[/green]")
26
- extractors.extend(self._load_from_directory(self.local_extractors_dir))
29
+ local_extractors = self._load_from_directory(self.local_extractors_dir)
30
+ konsol.log(f"[green]Yerel Extractor'lar: {[e.__name__ for e in local_extractors]}[/green]")
31
+ extractors.extend(local_extractors)
27
32
 
28
- if not extractors:
29
- konsol.print("[yellow][!] Yüklenecek bir Extractor bulunamadı![/yellow]")
33
+ # Benzersizliği sağlama (modül adı + sınıf adı bazında)
34
+ unique_extractors = []
35
+ seen = set()
36
+ for ext in extractors:
37
+ identifier = f"{ext.__module__}.{ext.__name__}"
38
+ if identifier not in seen:
39
+ unique_extractors.append(ext)
40
+ seen.add(identifier)
30
41
 
31
- return extractors
42
+ konsol.log(f"[blue]Sonuç Extractor'lar: {[e.__name__ for e in unique_extractors]}[/blue]")
43
+
44
+ if not unique_extractors:
45
+ konsol.log("[yellow][!] Yüklenecek bir Extractor bulunamadı![/yellow]")
46
+
47
+ return unique_extractors
32
48
 
33
49
  def _load_from_directory(self, directory: Path) -> list[ExtractorBase]:
34
50
  extractors = []
35
51
  for file in os.listdir(directory):
36
52
  if file.endswith(".py") and not file.startswith("__"):
37
53
  module_name = file[:-3]
54
+ konsol.log(f"[cyan]Modül yükleniyor: {module_name}[/cyan]")
38
55
  if extractor := self._load_extractor(directory, module_name):
56
+ konsol.log(f"[magenta]Extractor bulundu: {extractor.__name__}[/magenta]")
39
57
  extractors.append(extractor)
40
58
 
59
+ konsol.log(f"[yellow]{directory} dizininden yüklenen Extractor'lar: {[e.__name__ for e in extractors]}[/yellow]")
41
60
  return extractors
42
61
 
43
62
  def _load_extractor(self, directory: Path, module_name: str):
@@ -50,12 +69,14 @@ class ExtractorLoader:
50
69
  module = importlib.util.module_from_spec(spec)
51
70
  spec.loader.exec_module(module)
52
71
 
72
+ # Yalnızca doğru modülden gelen ExtractorBase sınıflarını yükle
53
73
  for attr in dir(module):
54
74
  obj = getattr(module, attr)
55
- if isinstance(obj, type) and issubclass(obj, ExtractorBase) and obj is not ExtractorBase:
75
+ if obj.__module__ == module_name and isinstance(obj, type) and issubclass(obj, ExtractorBase) and obj is not ExtractorBase:
76
+ konsol.log(f"[green]Yüklenen sınıf: {module_name}.{obj.__name__} ({obj.__module__}.{obj.__name__})[/green]")
56
77
  return obj
57
78
 
58
79
  except Exception as hata:
59
- konsol.print(f"[red][!] Extractor yüklenirken hata oluştu: {module_name}\nHata: {hata}")
80
+ konsol.log(f"[red][!] Extractor yüklenirken hata oluştu: {module_name}\nHata: {hata}")
60
81
 
61
82
  return None
@@ -3,11 +3,13 @@
3
3
  from pydantic import BaseModel
4
4
  from typing import List, Optional
5
5
 
6
+
6
7
  class Subtitle(BaseModel):
7
8
  """Altyazı modeli."""
8
9
  name : str
9
10
  url : str
10
11
 
12
+
11
13
  class ExtractResult(BaseModel):
12
14
  """Extractor'ın döndürmesi gereken sonuç modeli."""
13
15
  name : str
@@ -2,24 +2,34 @@
2
2
 
3
3
  from ..CLI import konsol
4
4
  from .ExtractorModels import ExtractResult
5
- import subprocess
5
+ import subprocess, os
6
6
 
7
7
  class MediaHandler:
8
- def __init__(self, title: str = "KekikStream", headers: dict = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5)"}):
8
+ def __init__(self, title: str = "KekikStream", headers: dict = None):
9
+ if headers is None:
10
+ headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5)"}
11
+
9
12
  self.headers = headers
10
13
  self.title = title
11
14
 
15
+ def play_media(self, extract_data: ExtractResult):
16
+ if subprocess.check_output(['uname', '-o']).strip() == b'Android':
17
+ return self.play_with_android_mxplayer(extract_data)
18
+
19
+ if "Cookie" in self.headers or extract_data.subtitles:
20
+ return self.play_with_mpv(extract_data)
21
+
22
+ return self.play_with_vlc(extract_data)
23
+
12
24
  def play_with_vlc(self, extract_data: ExtractResult):
13
25
  try:
14
- if "Cookie" in self.headers or extract_data.subtitles:
15
- self.play_with_mpv(extract_data)
16
- return
17
-
18
- vlc_command = ["vlc"]
26
+ vlc_command = ["vlc", "--quiet"]
19
27
 
20
28
  if self.title:
21
- vlc_command.append(f"--meta-title={self.title}")
22
- vlc_command.append(f"--input-title-format={self.title}")
29
+ vlc_command.extend([
30
+ f"--meta-title={self.title}",
31
+ f"--input-title-format={self.title}"
32
+ ])
23
33
 
24
34
  if "User-Agent" in self.headers:
25
35
  vlc_command.append(f"--http-user-agent={self.headers.get('User-Agent')}")
@@ -27,13 +37,16 @@ class MediaHandler:
27
37
  if "Referer" in self.headers:
28
38
  vlc_command.append(f"--http-referrer={self.headers.get('Referer')}")
29
39
 
30
- for subtitle in extract_data.subtitles:
31
- vlc_command.append(f"--sub-file={subtitle.url}")
32
-
40
+ vlc_command.extend(
41
+ f"--sub-file={subtitle.url}" for subtitle in extract_data.subtitles
42
+ )
33
43
  vlc_command.append(extract_data.url)
34
- subprocess.run(vlc_command, check=True)
35
- except subprocess.CalledProcessError as e:
36
- konsol.print(f"[red]VLC oynatma hatası: {e}[/red]")
44
+
45
+ with open(os.devnull, "w") as devnull:
46
+ subprocess.run(vlc_command, stdout=devnull, stderr=devnull, check=True)
47
+
48
+ except subprocess.CalledProcessError as hata:
49
+ konsol.print(f"[red]VLC oynatma hatası: {hata}[/red]")
37
50
  konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
38
51
  except FileNotFoundError:
39
52
  konsol.print("[red]VLC bulunamadı! VLC kurulu olduğundan emin olun.[/red]")
@@ -41,28 +54,55 @@ class MediaHandler:
41
54
 
42
55
  def play_with_mpv(self, extract_data: ExtractResult):
43
56
  try:
44
- mpv_command = ["mpv"]
57
+ mpv_command = ["mpv", "--really-quiet"]
45
58
 
46
59
  if self.title:
47
- mpv_command.append(f"--title={self.title}")
60
+ mpv_command.append(f"--force-media-title={self.title}")
48
61
 
49
- if "User-Agent" in self.headers:
50
- mpv_command.append(f"--http-header-fields=User-Agent: {self.headers.get('User-Agent')}")
62
+ for key, value in self.headers.items():
63
+ mpv_command.append(f"--http-header-fields={key}: {value}")
51
64
 
52
- if "Referer" in self.headers:
53
- mpv_command.append(f"--http-header-fields=Referer: {self.headers.get('Referer')}")
54
-
55
- if "Cookie" in self.headers:
56
- mpv_command.append(f"--http-header-fields=Cookie: {self.headers.get('Cookie')}")
65
+ mpv_command.extend(
66
+ f"--sub-file={subtitle.url}" for subtitle in extract_data.subtitles
67
+ )
68
+ mpv_command.append(extract_data.url)
57
69
 
58
- for subtitle in extract_data.subtitles:
59
- mpv_command.append(f"--sub-file={subtitle.url}")
70
+ with open(os.devnull, "w") as devnull:
71
+ subprocess.run(mpv_command, stdout=devnull, stderr=devnull, check=True)
60
72
 
61
- mpv_command.append(extract_data.url)
62
- subprocess.run(mpv_command, check=True)
63
- except subprocess.CalledProcessError as e:
64
- konsol.print(f"[red]mpv oynatma hatası: {e}[/red]")
73
+ except subprocess.CalledProcessError as hata:
74
+ konsol.print(f"[red]mpv oynatma hatası: {hata}[/red]")
65
75
  konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
66
76
  except FileNotFoundError:
67
77
  konsol.print("[red]mpv bulunamadı! mpv kurulu olduğundan emin olun.[/red]")
68
78
  konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
79
+
80
+ def play_with_android_mxplayer(self, extract_data: ExtractResult):
81
+ paketler = [
82
+ "com.mxtech.videoplayer.ad/.ActivityScreen", # Free sürüm
83
+ "com.mxtech.videoplayer.pro/.ActivityScreen" # Pro sürüm
84
+ ]
85
+
86
+ for paket in paketler:
87
+ try:
88
+ android_command = [
89
+ "am", "start",
90
+ "-a", "android.intent.action.VIEW",
91
+ "-d", extract_data.url,
92
+ "-n", paket
93
+ ]
94
+
95
+ if self.title:
96
+ android_command.extend(["--es", "title", self.title])
97
+
98
+ with open(os.devnull, "w") as devnull:
99
+ subprocess.run(android_command, stdout=devnull, stderr=devnull, check=True)
100
+
101
+ return
102
+
103
+ except subprocess.CalledProcessError as hata:
104
+ konsol.print(f"[red]{paket} oynatma hatası: {hata}[/red]")
105
+ konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
106
+ except FileNotFoundError:
107
+ konsol.print(f"Paket: {paket}, Hata: MX Player kurulu değil")
108
+ konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
@@ -2,6 +2,7 @@
2
2
 
3
3
  from abc import ABC, abstractmethod
4
4
  from httpx import AsyncClient, Timeout
5
+ from cloudscraper import CloudScraper
5
6
  from .PluginModels import SearchResult, MovieInfo
6
7
  from .MediaHandler import MediaHandler
7
8
  from urllib.parse import urljoin
@@ -21,6 +22,9 @@ class PluginBase(ABC):
21
22
  timeout = Timeout(10.0),
22
23
  )
23
24
  self.media_handler = MediaHandler()
25
+ self.cloudscraper = CloudScraper()
26
+ self.oturum.headers.update(self.cloudscraper.headers)
27
+ self.oturum.cookies.update(self.cloudscraper.cookies)
24
28
 
25
29
  @abstractmethod
26
30
  async def search(self, query: str) -> list[SearchResult]:
@@ -43,14 +47,11 @@ class PluginBase(ABC):
43
47
  def fix_url(self, url: str) -> str:
44
48
  if not url:
45
49
  return ""
46
-
50
+
47
51
  if url.startswith("http") or url.startswith("{\""):
48
52
  return url
49
53
 
50
- if url.startswith("//"):
51
- return f"https:{url}"
52
-
53
- return urljoin(self.main_url, url)
54
+ return f"https:{url}" if url.startswith("//") else urljoin(self.main_url, url)
54
55
 
55
56
  @staticmethod
56
57
  def clean_title(title: str) -> str:
@@ -3,9 +3,7 @@
3
3
  from ..CLI import konsol, cikis_yap
4
4
  from .PluginBase import PluginBase
5
5
  from pathlib import Path
6
- import importlib.util
7
- import os
8
- import traceback
6
+ import os, importlib.util, traceback
9
7
 
10
8
  class PluginLoader:
11
9
  def __init__(self, plugins_dir: str):
@@ -20,11 +18,11 @@ class PluginLoader:
20
18
 
21
19
  if self.global_plugins_dir.exists():
22
20
  konsol.log(f"[green][*] Global Plugin dizininden yükleniyor: {self.global_plugins_dir}[/green]")
23
- plugins.update(self._load_from_directory(self.global_plugins_dir))
21
+ plugins |= self._load_from_directory(self.global_plugins_dir)
24
22
 
25
23
  if self.local_plugins_dir.exists():
26
24
  konsol.log(f"[green][*] Yerel Plugin dizininden yükleniyor: {self.local_plugins_dir}[/green]")
27
- plugins.update(self._load_from_directory(self.local_plugins_dir))
25
+ plugins |= self._load_from_directory(self.local_plugins_dir)
28
26
 
29
27
  if not plugins:
30
28
  konsol.print("[yellow][!] Yüklenecek bir Plugin bulunamadı![/yellow]")
@@ -23,17 +23,12 @@ class MovieInfo(BaseModel):
23
23
  actors : Optional[str] = None
24
24
  duration : Optional[int] = None
25
25
 
26
- @field_validator("tags", mode="before")
26
+ @field_validator("tags", "actors", mode="before")
27
27
  @classmethod
28
- def convert_tags(cls, value):
28
+ def convert_lists(cls, value):
29
29
  return ", ".join(value) if isinstance(value, list) else value
30
30
 
31
- @field_validator("actors", mode="before")
32
- @classmethod
33
- def convert_actors(cls, value):
34
- return ", ".join(value) if isinstance(value, list) else value
35
-
36
- @field_validator("rating", mode="before")
31
+ @field_validator("rating", "year", mode="before")
37
32
  @classmethod
38
33
  def ensure_string(cls, value):
39
34
  return str(value) if value is not None else value
@@ -57,17 +52,12 @@ class SeriesInfo(BaseModel):
57
52
  actors : Optional[str] = None
58
53
  episodes : Optional[List[Episode]] = None
59
54
 
60
- @field_validator("tags", mode="before")
61
- @classmethod
62
- def convert_tags(cls, value):
63
- return ", ".join(value) if isinstance(value, list) else value
64
-
65
- @field_validator("actors", mode="before")
55
+ @field_validator("tags", "actors", mode="before")
66
56
  @classmethod
67
- def convert_actors(cls, value):
57
+ def convert_lists(cls, value):
68
58
  return ", ".join(value) if isinstance(value, list) else value
69
59
 
70
- @field_validator("rating", mode="before")
60
+ @field_validator("rating", "year", mode="before")
71
61
  @classmethod
72
62
  def ensure_string(cls, value):
73
63
  return str(value) if value is not None else value
@@ -0,0 +1,80 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
4
+ import re
5
+
6
+ class ContentX(ExtractorBase):
7
+ name = "ContentX"
8
+ main_url = "https://contentx.me"
9
+
10
+ async def extract(self, url, referer=None) -> list[ExtractResult]:
11
+ if referer:
12
+ self.oturum.headers.update({"Referer": referer})
13
+
14
+ istek = await self.oturum.get(url)
15
+ istek.raise_for_status()
16
+ i_source = istek.text
17
+
18
+ i_extract = re.search(r"window\.openPlayer\('([^']+)'", i_source)
19
+ if not i_extract:
20
+ raise ValueError("i_extract is null")
21
+ i_extract_value = i_extract[1]
22
+
23
+ subtitles = []
24
+ sub_urls = set()
25
+ for match in re.finditer(r'"file":"([^"]+)","label":"([^"]+)"', i_source):
26
+ sub_url, sub_lang = match.groups()
27
+
28
+ if sub_url in sub_urls:
29
+ continue
30
+
31
+ sub_urls.add(sub_url)
32
+ subtitles.append(
33
+ Subtitle(
34
+ name = sub_lang.replace("\\u0131", "ı")
35
+ .replace("\\u0130", "İ")
36
+ .replace("\\u00fc", "ü")
37
+ .replace("\\u00e7", "ç"),
38
+ url = self.fix_url(sub_url.replace("\\", ""))
39
+ )
40
+ )
41
+
42
+ vid_source_request = await self.oturum.get(f"{self.main_url}/source2.php?v={i_extract_value}", headers={"Referer": referer or self.main_url})
43
+ vid_source_request.raise_for_status()
44
+
45
+ vid_source = vid_source_request.text
46
+ vid_extract = re.search(r'file":"([^"]+)"', vid_source)
47
+ if not vid_extract:
48
+ raise ValueError("vidExtract is null")
49
+
50
+ m3u_link = vid_extract[1].replace("\\", "")
51
+ results = [
52
+ ExtractResult(
53
+ name = self.name,
54
+ url = m3u_link,
55
+ referer = url,
56
+ subtitles = subtitles
57
+ )
58
+ ]
59
+
60
+ if i_dublaj := re.search(r',\"([^"]+)\",\"Türkçe"', i_source):
61
+ dublaj_value = i_dublaj[1]
62
+ dublaj_source_request = await self.oturum.get(f"{self.main_url}/source2.php?v={dublaj_value}", headers={"Referer": referer or self.main_url})
63
+ dublaj_source_request.raise_for_status()
64
+
65
+ dublaj_source = dublaj_source_request.text
66
+ dublaj_extract = re.search(r'file":"([^"]+)"', dublaj_source)
67
+ if not dublaj_extract:
68
+ raise ValueError("dublajExtract is null")
69
+
70
+ dublaj_link = dublaj_extract[1].replace("\\", "")
71
+ results.append(
72
+ ExtractResult(
73
+ name = f"{self.name} Türkçe Dublaj",
74
+ url = dublaj_link,
75
+ referer = url,
76
+ subtitles = []
77
+ )
78
+ )
79
+
80
+ return results[0] if len(results) == 1 else results
@@ -0,0 +1,7 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Extractors.ContentX import ContentX
4
+
5
+ class FourCX(ContentX):
6
+ name = "FourCX"
7
+ main_url = "https://four.contentx.me"
@@ -0,0 +1,7 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Extractors.ContentX import ContentX
4
+
5
+ class FourPichive(ContentX):
6
+ name = "FourPichive"
7
+ main_url = "https://four.pichive.online"
@@ -0,0 +1,7 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Extractors.ContentX import ContentX
4
+
5
+ class FourPlayRu(ContentX):
6
+ name = "FourPlayRu"
7
+ main_url = "https://four.playru.net"
@@ -0,0 +1,7 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Extractors.PeaceMakerst import PeaceMakerst
4
+
5
+ class HDStreamAble(PeaceMakerst):
6
+ name = "HDStreamAble"
7
+ main_url = "https://hdstreamable.com"
@@ -0,0 +1,7 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Extractors.ContentX import ContentX
4
+
5
+ class Hotlinger(ContentX):
6
+ name = "Hotlinger"
7
+ main_url = "https://hotlinger.com"
@@ -0,0 +1,42 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult
4
+ from Kekik.Sifreleme import AESManager
5
+ import re, json
6
+
7
+ class MixPlayHD(ExtractorBase):
8
+ name = "MixPlayHD"
9
+ main_url = "https://mixplayhd.com"
10
+
11
+ async def extract(self, url, referer=None) -> ExtractResult:
12
+ if referer:
13
+ self.oturum.headers.update({"Referer": referer})
14
+
15
+ istek = await self.oturum.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]
24
+
25
+ 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.")