KekikStream 1.9.6__tar.gz → 2.0.3__tar.gz

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 (95) hide show
  1. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Core/Extractor/ExtractorBase.py +5 -4
  2. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Core/Extractor/ExtractorLoader.py +25 -17
  3. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Core/Extractor/ExtractorManager.py +1 -1
  4. kekikstream-2.0.3/KekikStream/Core/Extractor/YTDLPCache.py +35 -0
  5. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Core/Plugin/PluginBase.py +4 -0
  6. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Core/Plugin/PluginLoader.py +11 -7
  7. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Core/__init__.py +1 -0
  8. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/CloseLoad.py +1 -1
  9. kekikstream-2.0.3/KekikStream/Extractors/ContentX_.py +40 -0
  10. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/JetTv.py +1 -1
  11. kekikstream-1.9.6/KekikStream/Extractors/OkRuHTTP.py → kekikstream-2.0.3/KekikStream/Extractors/Odnoklassniki_.py +5 -1
  12. kekikstream-1.9.6/KekikStream/Extractors/HDStreamAble.py → kekikstream-2.0.3/KekikStream/Extractors/PeaceMakerst_.py +1 -1
  13. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/PlayerFilmIzle.py +3 -3
  14. kekikstream-2.0.3/KekikStream/Extractors/RapidVid_.py +7 -0
  15. kekikstream-1.9.6/KekikStream/Extractors/VidMolyMe.py → kekikstream-2.0.3/KekikStream/Extractors/VidMoly_.py +1 -1
  16. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/YTDLP.py +44 -39
  17. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/Dizilla.py +1 -1
  18. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/FilmMakinesi.py +2 -0
  19. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/JetFilmizle.py +52 -37
  20. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/RoketDizi.py +7 -2
  21. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/Sinefy.py +4 -1
  22. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/SinemaCX.py +1 -1
  23. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/Sinezy.py +16 -1
  24. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream.egg-info/PKG-INFO +27 -1
  25. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream.egg-info/SOURCES.txt +6 -10
  26. {kekikstream-1.9.6 → kekikstream-2.0.3}/PKG-INFO +27 -1
  27. {kekikstream-1.9.6 → kekikstream-2.0.3}/README.md +26 -0
  28. {kekikstream-1.9.6 → kekikstream-2.0.3}/setup.py +1 -1
  29. kekikstream-1.9.6/KekikStream/Extractors/FourCX.py +0 -7
  30. kekikstream-1.9.6/KekikStream/Extractors/FourPichive.py +0 -7
  31. kekikstream-1.9.6/KekikStream/Extractors/FourPlayRu.py +0 -7
  32. kekikstream-1.9.6/KekikStream/Extractors/Hotlinger.py +0 -7
  33. kekikstream-1.9.6/KekikStream/Extractors/OkRuSSL.py +0 -7
  34. kekikstream-1.9.6/KekikStream/Extractors/Pichive.py +0 -7
  35. kekikstream-1.9.6/KekikStream/Extractors/PlayRu.py +0 -7
  36. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/CLI/__init__.py +0 -0
  37. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/CLI/pypi_kontrol.py +0 -0
  38. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Core/Extractor/ExtractorModels.py +0 -0
  39. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Core/Media/MediaHandler.py +0 -0
  40. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Core/Media/MediaManager.py +0 -0
  41. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Core/Plugin/PluginManager.py +0 -0
  42. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Core/Plugin/PluginModels.py +0 -0
  43. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Core/UI/UIManager.py +0 -0
  44. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/ContentX.py +0 -0
  45. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/DzenRu.py +0 -0
  46. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/ExPlay.py +0 -0
  47. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/FirePlayer.py +0 -0
  48. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/HDPlayerSystem.py +0 -0
  49. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/MailRu.py +0 -0
  50. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/MixPlayHD.py +0 -0
  51. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/MixTiger.py +0 -0
  52. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/MolyStream.py +0 -0
  53. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/Odnoklassniki.py +0 -0
  54. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/PeaceMakerst.py +0 -0
  55. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/PixelDrain.py +0 -0
  56. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/RapidVid.py +0 -0
  57. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/SetPlay.py +0 -0
  58. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/SetPrime.py +0 -0
  59. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/SibNet.py +0 -0
  60. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/Sobreatsesuyp.py +0 -0
  61. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/TRsTX.py +0 -0
  62. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/TauVideo.py +0 -0
  63. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/TurboImgz.py +0 -0
  64. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/TurkeyPlayer.py +0 -0
  65. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/VidHide.py +0 -0
  66. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/VidMoly.py +0 -0
  67. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/VidMoxy.py +0 -0
  68. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/VidPapi.py +0 -0
  69. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/VideoSeyred.py +0 -0
  70. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Extractors/YildizKisaFilm.py +0 -0
  71. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/DiziBox.py +0 -0
  72. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/DiziPal.py +0 -0
  73. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/DiziYou.py +0 -0
  74. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/FilmBip.py +0 -0
  75. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/FilmModu.py +0 -0
  76. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/FullHDFilm.py +0 -0
  77. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/FullHDFilmizlesene.py +0 -0
  78. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/HDFilmCehennemi.py +0 -0
  79. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/KultFilmler.py +0 -0
  80. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/RecTV.py +0 -0
  81. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/SelcukFlix.py +0 -0
  82. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/SezonlukDizi.py +0 -0
  83. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/SineWix.py +0 -0
  84. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/SuperFilmGeldi.py +0 -0
  85. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/Plugins/UgurFilm.py +0 -0
  86. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/__init__.py +0 -0
  87. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/__main__.py +0 -0
  88. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream/requirements.txt +0 -0
  89. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream.egg-info/dependency_links.txt +0 -0
  90. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream.egg-info/entry_points.txt +0 -0
  91. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream.egg-info/requires.txt +0 -0
  92. {kekikstream-1.9.6 → kekikstream-2.0.3}/KekikStream.egg-info/top_level.txt +0 -0
  93. {kekikstream-1.9.6 → kekikstream-2.0.3}/LICENSE +0 -0
  94. {kekikstream-1.9.6 → kekikstream-2.0.3}/MANIFEST.in +0 -0
  95. {kekikstream-1.9.6 → kekikstream-2.0.3}/setup.cfg +0 -0
@@ -17,12 +17,13 @@ class ExtractorBase(ABC):
17
17
  self.cloudscraper = CloudScraper()
18
18
 
19
19
  # httpx - lightweight and safe for most HTTP requests
20
- self.httpx = AsyncClient(
21
- timeout = 3,
22
- follow_redirects = True
23
- )
20
+ self.httpx = AsyncClient(timeout = 10)
24
21
  self.httpx.headers.update(self.cloudscraper.headers)
25
22
  self.httpx.cookies.update(self.cloudscraper.cookies)
23
+ self.httpx.headers.update({
24
+ "User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 15.7; rv:135.0) Gecko/20100101 Firefox/135.0",
25
+ "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
26
+ })
26
27
 
27
28
  def can_handle_url(self, url: str) -> bool:
28
29
  # URL'nin bu çıkarıcı tarafından işlenip işlenemeyeceğini kontrol et
@@ -19,19 +19,22 @@ class ExtractorLoader:
19
19
  def load_all(self) -> list[ExtractorBase]:
20
20
  extractors = []
21
21
 
22
- # Global çıkarıcıları yükle
23
- if self.global_extractors_dir.exists():
24
- # konsol.log(f"[green][*] Global Extractor dizininden yükleniyor: {self.global_extractors_dir}[/green]")
25
- global_extractors = self._load_from_directory(self.global_extractors_dir)
26
- # konsol.log(f"[green]Global Extractor'lar: {[e.__name__ for e in global_extractors]}[/green]")
27
- extractors.extend(global_extractors)
28
-
29
- # Yerel çıkarıcıları yükle
22
+ # Eğer yerel dizinde Extractor varsa, sadece onları yükle (eklenti geliştirme modu)
30
23
  if self.local_extractors_dir.exists():
31
24
  # konsol.log(f"[green][*] Yerel Extractor dizininden yükleniyor: {self.local_extractors_dir}[/green]")
32
25
  local_extractors = self._load_from_directory(self.local_extractors_dir)
33
26
  # konsol.log(f"[green]Yerel Extractor'lar: {[e.__name__ for e in local_extractors]}[/green]")
34
- extractors.extend(local_extractors)
27
+
28
+ if local_extractors:
29
+ # konsol.log("[cyan][*] Yerel Extractor bulundu, global Extractor'lar atlanıyor (eklenti geliştirme modu)[/cyan]")
30
+ extractors.extend(local_extractors)
31
+
32
+ # Yerel dizinde Extractor yoksa, global'leri yükle
33
+ if not extractors and self.global_extractors_dir.exists():
34
+ # konsol.log(f"[green][*] Global Extractor dizininden yükleniyor: {self.global_extractors_dir}[/green]")
35
+ global_extractors = self._load_from_directory(self.global_extractors_dir)
36
+ # konsol.log(f"[green]Global Extractor'lar: {[e.__name__ for e in global_extractors]}[/green]")
37
+ extractors.extend(global_extractors)
35
38
 
36
39
  # Benzersizliği sağlama (modül adı + sınıf adı bazında)
37
40
  unique_extractors = []
@@ -57,9 +60,10 @@ class ExtractorLoader:
57
60
  if file.endswith(".py") and not file.startswith("__"):
58
61
  module_name = file[:-3] # .py uzantısını kaldır
59
62
  # konsol.log(f"[cyan]Okunan Dosya\t\t: {module_name}[/cyan]")
60
- if extractor := self._load_extractor(directory, module_name):
61
- # konsol.log(f"[magenta]Extractor Yüklendi\t: {extractor.__name__}[/magenta]")
62
- extractors.append(extractor)
63
+ module_extractors = self._load_extractor(directory, module_name)
64
+ if module_extractors:
65
+ # konsol.log(f"[magenta]Extractor Yüklendi\t: {[e.__name__ for e in module_extractors]}[/magenta]")
66
+ extractors.extend(module_extractors)
63
67
 
64
68
  # konsol.log(f"[yellow]{directory} dizininden yüklenen Extractor'lar: {[e.__name__ for e in extractors]}[/yellow]")
65
69
  return extractors
@@ -70,21 +74,25 @@ class ExtractorLoader:
70
74
  path = directory / f"{module_name}.py"
71
75
  spec = importlib.util.spec_from_file_location(module_name, path)
72
76
  if not spec or not spec.loader:
73
- return None
77
+ return []
74
78
 
75
79
  # Modülü içe aktar
76
80
  module = importlib.util.module_from_spec(spec)
77
81
  spec.loader.exec_module(module)
78
82
 
79
- # Yalnızca doğru modülden gelen ExtractorBase sınıflarını yükle
83
+ # Yalnızca doğru modülden gelen ExtractorBase sınıflarını yükle (TÜM CLASS'LAR)
84
+ extractors = []
80
85
  for attr in dir(module):
81
86
  obj = getattr(module, attr)
82
- if obj.__module__ == module_name and isinstance(obj, type) and issubclass(obj, ExtractorBase) and obj is not ExtractorBase:
87
+ # isinstance kontrolünü __module__ kontrolünden ÖNCE yap
88
+ if isinstance(obj, type) and issubclass(obj, ExtractorBase) and obj is not ExtractorBase and obj.__module__ == module_name:
83
89
  # konsol.log(f"[green]Yüklenen sınıf\t\t: {module_name}.{obj.__name__} ({obj.__module__}.{obj.__name__})[/green]")
84
- return obj
90
+ extractors.append(obj)
91
+
92
+ return extractors
85
93
 
86
94
  except Exception as hata:
87
95
  konsol.log(f"[red][!] Extractor yüklenirken hata oluştu: {module_name}\nHata: {hata}")
88
96
  konsol.print(f"[dim]{traceback.format_exc()}[/dim]")
89
97
 
90
- return None
98
+ return []
@@ -63,7 +63,7 @@ class ExtractorManager:
63
63
  """
64
64
  # Lazy loading: İlk kullanımda extractorları initialize et
65
65
  self._ensure_initialized()
66
-
66
+
67
67
  mapping = {}
68
68
  for link in links:
69
69
  # Cached instance'ları kullan
@@ -0,0 +1,35 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from Kekik.cli import konsol
4
+ from yt_dlp.extractor import gen_extractors
5
+
6
+ # Global cache (module-level singleton)
7
+ _YTDLP_EXTRACTORS_CACHE = None
8
+ _CACHE_INITIALIZED = False
9
+
10
+ def get_ytdlp_extractors() -> list:
11
+ """
12
+ yt-dlp extractorlarını cache'le ve döndür
13
+
14
+ Returns:
15
+ list: yt-dlp extractor sınıfları
16
+ """
17
+ global _YTDLP_EXTRACTORS_CACHE, _CACHE_INITIALIZED
18
+
19
+ if _CACHE_INITIALIZED:
20
+ return _YTDLP_EXTRACTORS_CACHE
21
+
22
+ try:
23
+ extractors = list(gen_extractors())
24
+ extractors = [ie for ie in extractors if ie.ie_key() != 'Generic']
25
+
26
+ _YTDLP_EXTRACTORS_CACHE = extractors
27
+ _CACHE_INITIALIZED = True
28
+
29
+ return extractors
30
+
31
+ except Exception as e:
32
+ konsol.log(f"[red][⚠] yt-dlp extractor cache hatası: {e}[/red]")
33
+ _YTDLP_EXTRACTORS_CACHE = []
34
+ _CACHE_INITIALIZED = True
35
+ return []
@@ -34,6 +34,10 @@ class PluginBase(ABC):
34
34
  )
35
35
  self.httpx.headers.update(self.cloudscraper.headers)
36
36
  self.httpx.cookies.update(self.cloudscraper.cookies)
37
+ self.httpx.headers.update({
38
+ "User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 15.7; rv:135.0) Gecko/20100101 Firefox/135.0",
39
+ "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
40
+ })
37
41
 
38
42
  self.media_handler = MediaHandler()
39
43
  self.ex_manager = ExtractorManager()
@@ -19,15 +19,19 @@ class PluginLoader:
19
19
  def load_all(self) -> dict[str, PluginBase]:
20
20
  plugins = {}
21
21
 
22
- # Global eklentileri yükle
23
- if self.global_plugins_dir.exists():
24
- # konsol.log(f"[green][*] Global Eklenti dizininden yükleniyor: {self.global_plugins_dir}[/green]")
25
- plugins |= self._load_from_directory(self.global_plugins_dir)
26
-
27
- # Yerel eklentileri yükle
22
+ # Eğer yerel dizinde Plugin varsa, sadece onları yükle (eklenti geliştirme modu)
28
23
  if self.local_plugins_dir.exists():
29
24
  # konsol.log(f"[green][*] Yerel Eklenti dizininden yükleniyor: {self.local_plugins_dir}[/green]")
30
- plugins |= self._load_from_directory(self.local_plugins_dir)
25
+ local_plugins = self._load_from_directory(self.local_plugins_dir)
26
+
27
+ if local_plugins:
28
+ # konsol.log("[cyan][*] Yerel Plugin bulundu, global Plugin'ler atlanıyor (eklenti geliştirme modu)[/cyan]")
29
+ plugins |= local_plugins
30
+
31
+ # Yerel dizinde Plugin yoksa, global'leri yükle
32
+ if not plugins and self.global_plugins_dir.exists():
33
+ # konsol.log(f"[green][*] Global Eklenti dizininden yükleniyor: {self.global_plugins_dir}[/green]")
34
+ plugins |= self._load_from_directory(self.global_plugins_dir)
31
35
 
32
36
  if not plugins:
33
37
  konsol.print("[yellow][!] Yüklenecek bir Eklenti bulunamadı![/yellow]")
@@ -13,6 +13,7 @@ from .Extractor.ExtractorManager import ExtractorManager
13
13
  from .Extractor.ExtractorBase import ExtractorBase
14
14
  from .Extractor.ExtractorLoader import ExtractorLoader
15
15
  from .Extractor.ExtractorModels import ExtractResult, Subtitle
16
+ from .Extractor.YTDLPCache import get_ytdlp_extractors
16
17
 
17
18
  from .Media.MediaManager import MediaManager
18
19
  from .Media.MediaHandler import MediaHandler
@@ -6,7 +6,7 @@ import re
6
6
 
7
7
  class CloseLoadExtractor(ExtractorBase):
8
8
  name = "CloseLoad"
9
- main_url = "https://closeload.filmmakinesi.sh"
9
+ main_url = "https://closeload.filmmakinesi.to"
10
10
 
11
11
  async def extract(self, url, referer=None) -> ExtractResult:
12
12
  if referer:
@@ -0,0 +1,40 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Extractors.ContentX import ContentX
4
+
5
+ # DPlayer82 Family - https://dplayer82.site subdomains
6
+ class SNDPlayer(ContentX):
7
+ name = "SNDPlayer"
8
+ main_url = "https://sn.dplayer82.site"
9
+
10
+ class FourDPlayer(ContentX):
11
+ name = "FourDPlayer"
12
+ main_url = "https://four.dplayer82.site"
13
+
14
+ class ORGDPlayer(ContentX):
15
+ name = "ORGDPlayer"
16
+ main_url = "https://org.dplayer82.site"
17
+
18
+ # Hotlinger
19
+ class Hotlinger(ContentX):
20
+ name = "Hotlinger"
21
+ main_url = "https://hotlinger.com"
22
+
23
+ # Pichive Family
24
+ class Pichive(ContentX):
25
+ name = "Pichive"
26
+ main_url = "https://pichive.me"
27
+
28
+ class FourPichive(ContentX):
29
+ name = "FourPichive"
30
+ main_url = "https://four.pichive.me"
31
+
32
+ # PlayRu Family
33
+ class FourPlayRu(ContentX):
34
+ name = "FourPlayRu"
35
+ main_url = "https://four.playru.net"
36
+
37
+ # CX Family
38
+ class FourCX(ContentX):
39
+ name = "FourCX"
40
+ main_url = "https://four.contentx.me"
@@ -31,7 +31,7 @@ class JetTv(ExtractorBase):
31
31
 
32
32
  # 2. Yöntem: Regex Fallback
33
33
  if not master_url:
34
- if match := re.search(r"file: '([^']*)'", document, re.IGNORE_CASE):
34
+ if match := re.search(r"file: '([^']*)'", document, re.IGNORECASE):
35
35
  master_url = match.group(1)
36
36
 
37
37
  if not master_url:
@@ -4,4 +4,8 @@ from KekikStream.Extractors.Odnoklassniki import Odnoklassniki
4
4
 
5
5
  class OkRuHTTP(Odnoklassniki):
6
6
  name = "OkRuHTTP"
7
- main_url = "http://ok.ru"
7
+ main_url = "http://ok.ru"
8
+
9
+ class OkRuSSL(Odnoklassniki):
10
+ name = "OkRuSSL"
11
+ main_url = "https://ok.ru"
@@ -4,4 +4,4 @@ from KekikStream.Extractors.PeaceMakerst import PeaceMakerst
4
4
 
5
5
  class HDStreamAble(PeaceMakerst):
6
6
  name = "HDStreamAble"
7
- main_url = "https://hdstreamable.com"
7
+ main_url = "https://hdstreamable.com"
@@ -16,7 +16,7 @@ class PlayerFilmIzle(ExtractorBase):
16
16
  video_req = istek.text
17
17
 
18
18
  subtitles = []
19
- if sub_match := re.search(r'playerjsSubtitle = "([^"]*)"', video_req, re.IGNORE_CASE):
19
+ if sub_match := re.search(r'playerjsSubtitle = "([^"]*)"', video_req, re.IGNORECASE):
20
20
  sub_yakala = sub_match.group(1)
21
21
  # Format örneği: [dil]url
22
22
  # Kotlin kodunda: subYakala.substringAfter("]") -> url
@@ -27,7 +27,7 @@ class PlayerFilmIzle(ExtractorBase):
27
27
  subtitles.append(Subtitle(name=sub_lang, url=sub_url))
28
28
 
29
29
  # Data yakalama: FirePlayer|DATA|...
30
- data_match = re.search(r'FirePlayer\|([^|]+)\|', video_req, re.IGNORE_CASE)
30
+ data_match = re.search(r'FirePlayer\|([^|]+)\|', video_req, re.IGNORECASE)
31
31
  data_val = data_match.group(1) if data_match else None
32
32
 
33
33
  if not data_val:
@@ -47,7 +47,7 @@ class PlayerFilmIzle(ExtractorBase):
47
47
  get_url = response.text.replace("\\", "")
48
48
 
49
49
  m3u8_url = ""
50
- if url_yakala := re.search(r'"securedLink":"([^"]*)"', get_url, re.IGNORE_CASE):
50
+ if url_yakala := re.search(r'"securedLink":"([^"]*)"', get_url, re.IGNORECASE):
51
51
  m3u8_url = url_yakala.group(1)
52
52
 
53
53
  if not m3u8_url:
@@ -0,0 +1,7 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Extractors.RapidVid import RapidVid
4
+
5
+ class RapidFilm(RapidVid):
6
+ name = "RapidFilm"
7
+ main_url = "https://rapid.filmmakinesi.to"
@@ -4,4 +4,4 @@ from KekikStream.Extractors.VidMoly import VidMoly
4
4
 
5
5
  class VidMolyMe(VidMoly):
6
6
  name = "VidMolyMe"
7
- main_url = "https://vidmoly.me"
7
+ main_url = "https://vidmoly.me"
@@ -1,8 +1,7 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle, get_ytdlp_extractors
4
4
  from urllib.parse import urlparse
5
- from yt_dlp.extractor import gen_extractors
6
5
  import yt_dlp, re, sys, os
7
6
 
8
7
  class YTDLP(ExtractorBase):
@@ -13,20 +12,22 @@ class YTDLP(ExtractorBase):
13
12
 
14
13
  @classmethod
15
14
  def _init_fast_domain_regex(cls):
15
+ """
16
+ Fast domain regex'i initialize et
17
+ """
16
18
  if cls._FAST_DOMAIN_RE is not None:
17
19
  return
18
20
 
19
21
  domains = set()
20
22
 
23
+ # Merkezi cache'den extractorları al
24
+ extractors = get_ytdlp_extractors()
25
+
21
26
  # yt-dlp extractor'larının _VALID_URL regex'lerinden domain yakala
22
27
  # Regex metinlerinde domainler genelde "\." şeklinde geçer.
23
28
  domain_pat = re.compile(r"(?:[a-z0-9-]+\\\.)+[a-z]{2,}", re.IGNORECASE)
24
29
 
25
- for ie in gen_extractors():
26
- # Generic'i fast-path'e dahil etmiyoruz
27
- if getattr(ie, "IE_NAME", "").lower() == "generic":
28
- continue
29
-
30
+ for ie in extractors:
30
31
  valid = getattr(ie, "_VALID_URL", None)
31
32
  if not valid or not isinstance(valid, str):
32
33
  continue
@@ -77,38 +78,40 @@ class YTDLP(ExtractorBase):
77
78
  return True
78
79
 
79
80
  # SLOW PATH: Diğer siteler için yt-dlp'nin native kontrolü
80
- try:
81
- # stderr'ı geçici olarak kapat (hata mesajlarını gizle)
82
- old_stderr = sys.stderr
83
- sys.stderr = open(os.devnull, "w")
84
-
85
- try:
86
- ydl_opts = {
87
- "simulate" : True, # Download yok, sadece tespit
88
- "quiet" : True, # Log kirliliği yok
89
- "no_warnings" : True, # Uyarı mesajları yok
90
- "extract_flat" : True, # Minimal işlem
91
- "no_check_certificates" : True,
92
- "ignoreerrors" : True # Hataları yoksay
93
- }
94
-
95
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
96
- # URL'yi işleyebiliyor mu kontrol et
97
- info = ydl.extract_info(url, download=False, process=False)
98
-
99
- # Generic extractor ise atla
100
- if info and info.get("extractor_key") != "Generic":
101
- return True
102
-
103
- return False
104
- finally:
105
- # stderr'ı geri yükle
106
- sys.stderr.close()
107
- sys.stderr = old_stderr
108
-
109
- except Exception:
81
+ # try:
82
+ # # stderr'ı geçici olarak kapat (hata mesajlarını gizle)
83
+ # old_stderr = sys.stderr
84
+ # sys.stderr = open(os.devnull, "w")
85
+
86
+ # try:
87
+ # ydl_opts = {
88
+ # "simulate" : True, # Download yok, sadece tespit
89
+ # "quiet" : True, # Log kirliliği yok
90
+ # "no_warnings" : True, # Uyarı mesajları yok
91
+ # "extract_flat" : True, # Minimal işlem
92
+ # "no_check_certificates" : True,
93
+ # "ignoreerrors" : True, # Hataları yoksay
94
+ # "socket_timeout" : 3,
95
+ # "retries" : 1
96
+ # }
97
+
98
+ # with yt_dlp.YoutubeDL(ydl_opts) as ydl:
99
+ # # URL'yi işleyebiliyor mu kontrol et
100
+ # info = ydl.extract_info(url, download=False, process=False)
101
+
102
+ # # Generic extractor ise atla
103
+ # if info and info.get("extractor_key") != "Generic":
104
+ # return True
105
+
106
+ # return False
107
+ # finally:
108
+ # # stderr geri yükle
109
+ # sys.stderr.close()
110
+ # sys.stderr = old_stderr
111
+
112
+ # except Exception:
110
113
  # yt-dlp işleyemezse False döndür
111
- return False
114
+ return False
112
115
 
113
116
  async def extract(self, url: str, referer: str | None = None) -> ExtractResult:
114
117
  ydl_opts = {
@@ -116,7 +119,9 @@ class YTDLP(ExtractorBase):
116
119
  "no_warnings" : True,
117
120
  "extract_flat" : False, # Tam bilgi al
118
121
  "format" : "best", # En iyi kalite
119
- "no_check_certificates" : True
122
+ "no_check_certificates" : True,
123
+ "socket_timeout" : 3,
124
+ "retries" : 1
120
125
  }
121
126
 
122
127
  # Referer varsa header olarak ekle
@@ -137,7 +137,7 @@ class Dizilla(PluginBase):
137
137
  year = veri.get("datePublished").split("-")[0]
138
138
 
139
139
  # Tags extraction from page content (h3 tag)
140
- tags_raw = secici.css("h3.text-white.opacity-60::text").get()
140
+ tags_raw = secici.css("div.poster.poster h3::text").get()
141
141
  tags = [t.strip() for t in tags_raw.split(",")] if tags_raw else []
142
142
 
143
143
  rating = veri.get("aggregateRating", {}).get("ratingValue")
@@ -83,6 +83,7 @@ class FilmMakinesi(PluginBase):
83
83
  rating = rating.strip().split()[0]
84
84
  year = secici.css("span.date a::text").get().strip()
85
85
  actors = secici.css("div.cast-name::text").getall()
86
+ tags = secici.css("div.genre a::text").getall()
86
87
  duration = secici.css("div.time::text").get()
87
88
  if duration:
88
89
  duration = duration.split()[1].strip()
@@ -92,6 +93,7 @@ class FilmMakinesi(PluginBase):
92
93
  poster = self.fix_url(poster),
93
94
  title = self.clean_title(title),
94
95
  description = description,
96
+ tags = tags,
95
97
  rating = rating,
96
98
  year = year,
97
99
  actors = actors,
@@ -74,8 +74,15 @@ class JetFilmizle(PluginBase):
74
74
  rating_raw = secici.css("section.movie-exp div.imdb_puan span::text").get()
75
75
  rating = rating_raw.strip() if rating_raw else None
76
76
 
77
- year = secici.xpath("//div[@class='yap' and (contains(., 'Vizyon') or contains(., 'Yapım'))]/text()").get()
78
- year = year.strip() if year else None
77
+
78
+ # Year - div.yap içinde 4 haneli sayı ara
79
+ year_div = secici.xpath("//div[@class='yap' and (contains(., 'Vizyon') or contains(., 'Yapım'))]/text()").get()
80
+ year = None
81
+ if year_div:
82
+ year_match = re.search(r'(\d{4})', year_div.strip())
83
+ if year_match:
84
+ year = year_match.group(1)
85
+
79
86
  actors = secici.css("div[itemprop='actor'] a span::text").getall()
80
87
 
81
88
  return MovieInfo(
@@ -93,42 +100,50 @@ class JetFilmizle(PluginBase):
93
100
  istek = await self.httpx.get(url)
94
101
  secici = Selector(istek.text)
95
102
 
96
- iframes = []
97
- if main_iframe := secici.css("div#movie iframe::attr(data-src), div#movie iframe::attr(data), div#movie iframe::attr(src)").get():
98
- iframes.append(self.fix_url(main_iframe))
103
+ results = []
99
104
 
100
- for part in secici.css("div.film_part a"):
101
- part_href = part.attrib.get("href")
102
- if not part_href:
105
+ # 1) Ana iframe'leri kontrol et
106
+ for iframe in secici.css("iframe"):
107
+ src = (iframe.css("::attr(src)").get() or
108
+ iframe.css("::attr(data-src)").get() or
109
+ iframe.css("::attr(data-lazy-src)").get())
110
+
111
+ if src and src != "about:blank":
112
+ iframe_url = self.fix_url(src)
113
+ extractor = self.ex_manager.find_extractor(iframe_url)
114
+ results.append({
115
+ "url": iframe_url,
116
+ "name": extractor.name if extractor else "Ana Player"
117
+ })
118
+
119
+ # 2) Sayfa numaralarından linkleri topla (Fragman hariç)
120
+ page_links = []
121
+ for link in secici.css("a.post-page-numbers"):
122
+ isim = link.css("span::text").get() or ""
123
+ if isim != "Fragman":
124
+ href = link.css("::attr(href)").get()
125
+ if href:
126
+ page_links.append((self.fix_url(href), isim))
127
+
128
+ # 3) Her sayfa linkindeki iframe'leri bul
129
+ for page_url, isim in page_links:
130
+ try:
131
+ page_resp = await self.httpx.get(page_url)
132
+ page_sel = Selector(page_resp.text)
133
+
134
+ for iframe in page_sel.css("div#movie iframe"):
135
+ src = (iframe.css("::attr(src)").get() or
136
+ iframe.css("::attr(data-src)").get() or
137
+ iframe.css("::attr(data-lazy-src)").get())
138
+
139
+ if src and src != "about:blank":
140
+ iframe_url = self.fix_url(src)
141
+ extractor = self.ex_manager.find_extractor(iframe_url)
142
+ results.append({
143
+ "url": iframe_url,
144
+ "name": f"{extractor.name if extractor else 'Player'} | {isim}"
145
+ })
146
+ except Exception:
103
147
  continue
104
148
 
105
- part_istek = await self.httpx.get(part_href)
106
- part_secici = Selector(part_istek.text)
107
-
108
- if iframe := part_secici.css("div#movie iframe::attr(data-src), div#movie iframe::attr(data), div#movie iframe::attr(src)").get():
109
- iframes.append(self.fix_url(iframe))
110
- else:
111
- for link in part_secici.css("div#movie p a"):
112
- if download_link := link.attrib.get("href"):
113
- iframes.append(self.fix_url(download_link))
114
-
115
- processed_iframes = []
116
- for iframe in iframes:
117
- if "jetv.xyz" in iframe:
118
- jetv_istek = await self.httpx.get(iframe)
119
- jetv_secici = Selector(jetv_istek.text)
120
-
121
- if jetv_iframe := jetv_secici.css("iframe::attr(src)").get():
122
- processed_iframes.append(self.fix_url(jetv_iframe))
123
- else:
124
- processed_iframes.append(iframe)
125
-
126
- results = []
127
- for idx, iframe in enumerate(processed_iframes):
128
- extractor = self.ex_manager.find_extractor(iframe)
129
- results.append({
130
- "url" : iframe,
131
- "name" : f"{extractor.name if extractor else f'Player {idx + 1}'}"
132
- })
133
-
134
149
  return results
@@ -203,14 +203,19 @@ class RoketDizi(PluginBase):
203
203
 
204
204
  # Check extractor
205
205
  extractor = self.ex_manager.find_extractor(iframe_url)
206
+ ext_name = extractor.name if extractor else ""
206
207
 
207
208
  # Metadata'dan bilgileri al
208
- source_name = source.get("source_name", extractor.name if extractor else "Iframe")
209
+ source_name = source.get("source_name", "")
209
210
  language_name = source.get("language_name", "")
210
211
  quality_name = source.get("quality_name", "")
211
212
 
212
213
  # İsmi oluştur
213
- name_parts = [source_name]
214
+ name_parts = []
215
+ if source_name:
216
+ name_parts.append(source_name)
217
+ if ext_name:
218
+ name_parts.append(ext_name)
214
219
  if language_name:
215
220
  name_parts.append(language_name)
216
221
  if quality_name:
@@ -153,6 +153,7 @@ class Sinefy(PluginBase):
153
153
  tags = sel.css("div.item.categories a::text").getall()
154
154
  rating = sel.css("span.color-imdb::text").get()
155
155
  actors = sel.css("div.content h5::text").getall()
156
+ year = sel.css("span.item.year::text").get() # Year bilgisi eklendi
156
157
 
157
158
  episodes = []
158
159
  season_elements = sel.css("section.episodes-box")
@@ -207,6 +208,7 @@ class Sinefy(PluginBase):
207
208
  rating = rating,
208
209
  tags = tags,
209
210
  actors = actors,
211
+ year = year,
210
212
  episodes = episodes
211
213
  )
212
214
  else:
@@ -217,7 +219,8 @@ class Sinefy(PluginBase):
217
219
  description = description,
218
220
  rating = rating,
219
221
  tags = tags,
220
- actors = actors
222
+ actors = actors,
223
+ year = year
221
224
  )
222
225
 
223
226
  async def load_links(self, url: str) -> list[dict]:
@@ -7,7 +7,7 @@ import re
7
7
  class SinemaCX(PluginBase):
8
8
  name = "SinemaCX"
9
9
  language = "tr"
10
- main_url = "https://www.sinema.onl"
10
+ main_url = "https://www.sinema.fit"
11
11
  favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
12
12
  description = "HD Film izle, Türkçe Dublaj ve Altyazılı filmler."
13
13
 
@@ -94,6 +94,20 @@ class Sinezy(PluginBase):
94
94
 
95
95
  tags = sel.css("div.detail span a::text").getall()
96
96
  actors = sel.css("span.oyn p::text").getall() # Might need splitting logic
97
+
98
+ year = None
99
+ info_text = sel.css("span.info::text").get()
100
+ if info_text:
101
+ year_match = re.search(r'\b(19\d{2}|20\d{2})\b', info_text)
102
+ if year_match:
103
+ year = year_match.group(1)
104
+
105
+ # Bulunamadıysa tüm sayfada ara
106
+ if not year:
107
+ all_text = " ".join(sel.css("::text").getall())
108
+ year_match = re.search(r'\b(19\d{2}|20\d{2})\b', all_text)
109
+ if year_match:
110
+ year = year_match.group(1)
97
111
 
98
112
  return MovieInfo(
99
113
  title = title,
@@ -102,7 +116,8 @@ class Sinezy(PluginBase):
102
116
  description = description,
103
117
  tags = tags,
104
118
  rating = rating,
105
- actors = actors
119
+ actors = actors,
120
+ year = year
106
121
  )
107
122
 
108
123
  async def load_links(self, url: str) -> list[dict]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: KekikStream
3
- Version: 1.9.6
3
+ Version: 2.0.3
4
4
  Summary: terminal üzerinden medya içeriği aramanızı ve VLC/MPV gibi popüler medya oynatıcılar aracılığıyla doğrudan izlemenizi sağlayan modüler ve genişletilebilir bir bıdı bıdı
5
5
  Home-page: https://github.com/keyiflerolsun/KekikStream
6
6
  Author: keyiflerolsun
@@ -235,6 +235,32 @@ KekikStream/
235
235
  3. `get_main_page`, `search`, `load_item`, `load_links` metodlarını implemente edin.
236
236
  4. Plugin'i test edin (örnek: `Tests/Single.py`).
237
237
 
238
+ ### 🔧 Geliştirme Modu
239
+
240
+ KekikStream, eklenti geliştiricileri için otomatik bir **geliştirme modu** sunar:
241
+
242
+ **Plugin Geliştirme:**
243
+ - Çalışma dizininde `Plugins/` klasörü oluşturup içine plugin dosyası eklerseniz, **sadece bu local plugin'ler** yüklenir
244
+ - Global plugin'ler (sisteme kurulu olanlar) otomatik olarak atlanır
245
+ - Bu sayede test sırasında diğer plugin'lerle karışma olmaz
246
+
247
+ **Extractor Geliştirme:**
248
+ - Çalışma dizininde `Extractors/` klasörü oluşturup içine extractor dosyası eklerseniz, **sadece bu local extractor'lar** yüklenir
249
+ - Global extractor'lar otomatik olarak atlanır
250
+ - Kendi extractor'ınızı izole bir ortamda test edebilirsiniz
251
+
252
+ **Örnek:**
253
+ ```bash
254
+ # Çalışma dizininizde
255
+ mkdir Plugins
256
+ touch Plugins/MyTestPlugin.py # Plugin'inizi yazın
257
+
258
+ # KekikStream'i çalıştırın - sadece MyTestPlugin yüklenecek
259
+ KekikStream
260
+ ```
261
+
262
+ > 💡 **Not:** Yerel dizinde herhangi bir Plugin/Extractor dosyası bulunmazsa, sistem normal şekilde global olanları yükler.
263
+
238
264
  ---
239
265
 
240
266
  ## 📊 Performans
@@ -18,6 +18,7 @@ KekikStream/Core/Extractor/ExtractorBase.py
18
18
  KekikStream/Core/Extractor/ExtractorLoader.py
19
19
  KekikStream/Core/Extractor/ExtractorManager.py
20
20
  KekikStream/Core/Extractor/ExtractorModels.py
21
+ KekikStream/Core/Extractor/YTDLPCache.py
21
22
  KekikStream/Core/Media/MediaHandler.py
22
23
  KekikStream/Core/Media/MediaManager.py
23
24
  KekikStream/Core/Plugin/PluginBase.py
@@ -27,29 +28,24 @@ KekikStream/Core/Plugin/PluginModels.py
27
28
  KekikStream/Core/UI/UIManager.py
28
29
  KekikStream/Extractors/CloseLoad.py
29
30
  KekikStream/Extractors/ContentX.py
31
+ KekikStream/Extractors/ContentX_.py
30
32
  KekikStream/Extractors/DzenRu.py
31
33
  KekikStream/Extractors/ExPlay.py
32
34
  KekikStream/Extractors/FirePlayer.py
33
- KekikStream/Extractors/FourCX.py
34
- KekikStream/Extractors/FourPichive.py
35
- KekikStream/Extractors/FourPlayRu.py
36
35
  KekikStream/Extractors/HDPlayerSystem.py
37
- KekikStream/Extractors/HDStreamAble.py
38
- KekikStream/Extractors/Hotlinger.py
39
36
  KekikStream/Extractors/JetTv.py
40
37
  KekikStream/Extractors/MailRu.py
41
38
  KekikStream/Extractors/MixPlayHD.py
42
39
  KekikStream/Extractors/MixTiger.py
43
40
  KekikStream/Extractors/MolyStream.py
44
41
  KekikStream/Extractors/Odnoklassniki.py
45
- KekikStream/Extractors/OkRuHTTP.py
46
- KekikStream/Extractors/OkRuSSL.py
42
+ KekikStream/Extractors/Odnoklassniki_.py
47
43
  KekikStream/Extractors/PeaceMakerst.py
48
- KekikStream/Extractors/Pichive.py
44
+ KekikStream/Extractors/PeaceMakerst_.py
49
45
  KekikStream/Extractors/PixelDrain.py
50
- KekikStream/Extractors/PlayRu.py
51
46
  KekikStream/Extractors/PlayerFilmIzle.py
52
47
  KekikStream/Extractors/RapidVid.py
48
+ KekikStream/Extractors/RapidVid_.py
53
49
  KekikStream/Extractors/SetPlay.py
54
50
  KekikStream/Extractors/SetPrime.py
55
51
  KekikStream/Extractors/SibNet.py
@@ -60,7 +56,7 @@ KekikStream/Extractors/TurboImgz.py
60
56
  KekikStream/Extractors/TurkeyPlayer.py
61
57
  KekikStream/Extractors/VidHide.py
62
58
  KekikStream/Extractors/VidMoly.py
63
- KekikStream/Extractors/VidMolyMe.py
59
+ KekikStream/Extractors/VidMoly_.py
64
60
  KekikStream/Extractors/VidMoxy.py
65
61
  KekikStream/Extractors/VidPapi.py
66
62
  KekikStream/Extractors/VideoSeyred.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: KekikStream
3
- Version: 1.9.6
3
+ Version: 2.0.3
4
4
  Summary: terminal üzerinden medya içeriği aramanızı ve VLC/MPV gibi popüler medya oynatıcılar aracılığıyla doğrudan izlemenizi sağlayan modüler ve genişletilebilir bir bıdı bıdı
5
5
  Home-page: https://github.com/keyiflerolsun/KekikStream
6
6
  Author: keyiflerolsun
@@ -235,6 +235,32 @@ KekikStream/
235
235
  3. `get_main_page`, `search`, `load_item`, `load_links` metodlarını implemente edin.
236
236
  4. Plugin'i test edin (örnek: `Tests/Single.py`).
237
237
 
238
+ ### 🔧 Geliştirme Modu
239
+
240
+ KekikStream, eklenti geliştiricileri için otomatik bir **geliştirme modu** sunar:
241
+
242
+ **Plugin Geliştirme:**
243
+ - Çalışma dizininde `Plugins/` klasörü oluşturup içine plugin dosyası eklerseniz, **sadece bu local plugin'ler** yüklenir
244
+ - Global plugin'ler (sisteme kurulu olanlar) otomatik olarak atlanır
245
+ - Bu sayede test sırasında diğer plugin'lerle karışma olmaz
246
+
247
+ **Extractor Geliştirme:**
248
+ - Çalışma dizininde `Extractors/` klasörü oluşturup içine extractor dosyası eklerseniz, **sadece bu local extractor'lar** yüklenir
249
+ - Global extractor'lar otomatik olarak atlanır
250
+ - Kendi extractor'ınızı izole bir ortamda test edebilirsiniz
251
+
252
+ **Örnek:**
253
+ ```bash
254
+ # Çalışma dizininizde
255
+ mkdir Plugins
256
+ touch Plugins/MyTestPlugin.py # Plugin'inizi yazın
257
+
258
+ # KekikStream'i çalıştırın - sadece MyTestPlugin yüklenecek
259
+ KekikStream
260
+ ```
261
+
262
+ > 💡 **Not:** Yerel dizinde herhangi bir Plugin/Extractor dosyası bulunmazsa, sistem normal şekilde global olanları yükler.
263
+
238
264
  ---
239
265
 
240
266
  ## 📊 Performans
@@ -198,6 +198,32 @@ KekikStream/
198
198
  3. `get_main_page`, `search`, `load_item`, `load_links` metodlarını implemente edin.
199
199
  4. Plugin'i test edin (örnek: `Tests/Single.py`).
200
200
 
201
+ ### 🔧 Geliştirme Modu
202
+
203
+ KekikStream, eklenti geliştiricileri için otomatik bir **geliştirme modu** sunar:
204
+
205
+ **Plugin Geliştirme:**
206
+ - Çalışma dizininde `Plugins/` klasörü oluşturup içine plugin dosyası eklerseniz, **sadece bu local plugin'ler** yüklenir
207
+ - Global plugin'ler (sisteme kurulu olanlar) otomatik olarak atlanır
208
+ - Bu sayede test sırasında diğer plugin'lerle karışma olmaz
209
+
210
+ **Extractor Geliştirme:**
211
+ - Çalışma dizininde `Extractors/` klasörü oluşturup içine extractor dosyası eklerseniz, **sadece bu local extractor'lar** yüklenir
212
+ - Global extractor'lar otomatik olarak atlanır
213
+ - Kendi extractor'ınızı izole bir ortamda test edebilirsiniz
214
+
215
+ **Örnek:**
216
+ ```bash
217
+ # Çalışma dizininizde
218
+ mkdir Plugins
219
+ touch Plugins/MyTestPlugin.py # Plugin'inizi yazın
220
+
221
+ # KekikStream'i çalıştırın - sadece MyTestPlugin yüklenecek
222
+ KekikStream
223
+ ```
224
+
225
+ > 💡 **Not:** Yerel dizinde herhangi bir Plugin/Extractor dosyası bulunmazsa, sistem normal şekilde global olanları yükler.
226
+
201
227
  ---
202
228
 
203
229
  ## 📊 Performans
@@ -6,7 +6,7 @@ from io import open
6
6
  setup(
7
7
  # ? Genel Bilgiler
8
8
  name = "KekikStream",
9
- version = "1.9.6",
9
+ version = "2.0.3",
10
10
  url = "https://github.com/keyiflerolsun/KekikStream",
11
11
  description = "terminal üzerinden medya içeriği aramanızı ve VLC/MPV gibi popüler medya oynatıcılar aracılığıyla doğrudan izlemenizi sağlayan modüler ve genişletilebilir bir bıdı bıdı",
12
12
  keywords = ["KekikStream", "KekikAkademi", "keyiflerolsun"],
@@ -1,7 +0,0 @@
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"
@@ -1,7 +0,0 @@
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"
@@ -1,7 +0,0 @@
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"
@@ -1,7 +0,0 @@
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"
@@ -1,7 +0,0 @@
1
- # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
-
3
- from KekikStream.Extractors.Odnoklassniki import Odnoklassniki
4
-
5
- class OkRuSSL(Odnoklassniki):
6
- name = "OkRuSSL"
7
- main_url = "https://ok.ru"
@@ -1,7 +0,0 @@
1
- # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
-
3
- from KekikStream.Extractors.ContentX import ContentX
4
-
5
- class Pichive(ContentX):
6
- name = "Pichive"
7
- main_url = "https://pichive.online"
@@ -1,7 +0,0 @@
1
- # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
-
3
- from KekikStream.Extractors.ContentX import ContentX
4
-
5
- class PlayRu(ContentX):
6
- name = "PlayRu"
7
- main_url = "https://playru.net"
File without changes
File without changes
File without changes