KekikStream 0.8.0__py3-none-any.whl → 0.8.2__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- KekikStream/Core/{ExtractorBase.py → Extractor/ExtractorBase.py} +8 -2
- KekikStream/Core/{ExtractorLoader.py → Extractor/ExtractorLoader.py} +18 -11
- KekikStream/{Managers → Core/Extractor}/ExtractorManager.py +7 -3
- KekikStream/Core/{MediaHandler.py → Media/MediaHandler.py} +6 -2
- KekikStream/{Managers → Core/Media}/MediaManager.py +1 -1
- KekikStream/Core/{PluginBase.py → Plugin/PluginBase.py} +6 -6
- KekikStream/Core/{PluginLoader.py → Plugin/PluginLoader.py} +22 -8
- KekikStream/{Managers → Core/Plugin}/PluginManager.py +6 -1
- KekikStream/{Managers → Core/UI}/UIManager.py +1 -1
- KekikStream/Core/__init__.py +14 -7
- KekikStream/Plugins/RecTV.py +4 -5
- KekikStream/Plugins/SineWix.py +1 -2
- KekikStream/__init__.py +33 -2
- {KekikStream-0.8.0.dist-info → KekikStream-0.8.2.dist-info}/METADATA +1 -1
- {KekikStream-0.8.0.dist-info → KekikStream-0.8.2.dist-info}/RECORD +21 -22
- KekikStream/Managers/__init__.py +0 -6
- /KekikStream/Core/{ExtractorModels.py → Extractor/ExtractorModels.py} +0 -0
- /KekikStream/Core/{PluginModels.py → Plugin/PluginModels.py} +0 -0
- {KekikStream-0.8.0.dist-info → KekikStream-0.8.2.dist-info}/LICENSE +0 -0
- {KekikStream-0.8.0.dist-info → KekikStream-0.8.2.dist-info}/WHEEL +0 -0
- {KekikStream-0.8.0.dist-info → KekikStream-0.8.2.dist-info}/entry_points.txt +0 -0
- {KekikStream-0.8.0.dist-info → KekikStream-0.8.2.dist-info}/top_level.txt +0 -0
@@ -5,12 +5,15 @@ from httpx import AsyncClient, Timeout
|
|
5
5
|
from cloudscraper import CloudScraper
|
6
6
|
from typing import Optional
|
7
7
|
from .ExtractorModels import ExtractResult
|
8
|
+
from urllib.parse import urljoin
|
8
9
|
|
9
10
|
class ExtractorBase(ABC):
|
11
|
+
# Çıkarıcının temel özellikleri
|
10
12
|
name = "Extractor"
|
11
13
|
main_url = ""
|
12
14
|
|
13
15
|
def __init__(self):
|
16
|
+
# HTTP istekleri için oturum oluştur
|
14
17
|
self.oturum = AsyncClient(
|
15
18
|
headers = {
|
16
19
|
"User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5)",
|
@@ -18,21 +21,24 @@ class ExtractorBase(ABC):
|
|
18
21
|
},
|
19
22
|
timeout = Timeout(10.0)
|
20
23
|
)
|
24
|
+
# CloudFlare korumalı siteler için scraper ayarla
|
21
25
|
self.cloudscraper = CloudScraper()
|
22
26
|
|
23
27
|
def can_handle_url(self, url: str) -> bool:
|
24
|
-
|
28
|
+
# URL'nin bu çıkarıcı tarafından işlenip işlenemeyeceğini kontrol et
|
25
29
|
return self.main_url in url
|
26
30
|
|
27
31
|
@abstractmethod
|
28
32
|
async def extract(self, url: str, referer: Optional[str] = None) -> ExtractResult:
|
29
|
-
|
33
|
+
# Alt sınıflar tarafından uygulanacak medya çıkarma fonksiyonu
|
30
34
|
pass
|
31
35
|
|
32
36
|
async def close(self):
|
37
|
+
# HTTP oturumunu güvenli bir şekilde kapat
|
33
38
|
await self.oturum.aclose()
|
34
39
|
|
35
40
|
def fix_url(self, url: str) -> str:
|
41
|
+
# Eksik URL'leri düzelt ve tam URL formatına çevir
|
36
42
|
if not url:
|
37
43
|
return ""
|
38
44
|
|
@@ -1,14 +1,17 @@
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
2
|
|
3
|
-
from
|
3
|
+
from ...CLI import konsol, cikis_yap
|
4
4
|
from .ExtractorBase import ExtractorBase
|
5
5
|
from pathlib import Path
|
6
6
|
import os, importlib.util
|
7
7
|
|
8
8
|
class ExtractorLoader:
|
9
9
|
def __init__(self, extractors_dir: str):
|
10
|
+
# Yerel ve global çıkarıcı dizinlerini ayarla
|
10
11
|
self.local_extractors_dir = Path(extractors_dir)
|
11
|
-
self.global_extractors_dir = Path(__file__).parent.parent / extractors_dir
|
12
|
+
self.global_extractors_dir = Path(__file__).parent.parent.parent / extractors_dir
|
13
|
+
|
14
|
+
# Dizin kontrolü
|
12
15
|
if not self.local_extractors_dir.exists() and not self.global_extractors_dir.exists():
|
13
16
|
konsol.log(f"[red][!] Extractor dizini bulunamadı: {self.global_extractors_dir}[/red]")
|
14
17
|
cikis_yap(False)
|
@@ -16,14 +19,14 @@ class ExtractorLoader:
|
|
16
19
|
def load_all(self) -> list[ExtractorBase]:
|
17
20
|
extractors = []
|
18
21
|
|
19
|
-
# Global
|
22
|
+
# Global çıkarıcıları yükle
|
20
23
|
if self.global_extractors_dir.exists():
|
21
24
|
konsol.log(f"[green][*] Global Extractor dizininden yükleniyor: {self.global_extractors_dir}[/green]")
|
22
25
|
global_extractors = self._load_from_directory(self.global_extractors_dir)
|
23
26
|
konsol.log(f"[green]Global Extractor'lar: {[e.__name__ for e in global_extractors]}[/green]")
|
24
27
|
extractors.extend(global_extractors)
|
25
28
|
|
26
|
-
# Yerel
|
29
|
+
# Yerel çıkarıcıları yükle
|
27
30
|
if self.local_extractors_dir.exists():
|
28
31
|
konsol.log(f"[green][*] Yerel Extractor dizininden yükleniyor: {self.local_extractors_dir}[/green]")
|
29
32
|
local_extractors = self._load_from_directory(self.local_extractors_dir)
|
@@ -32,12 +35,12 @@ class ExtractorLoader:
|
|
32
35
|
|
33
36
|
# Benzersizliği sağlama (modül adı + sınıf adı bazında)
|
34
37
|
unique_extractors = []
|
35
|
-
|
38
|
+
seen_names = set()
|
36
39
|
for ext in extractors:
|
37
40
|
identifier = f"{ext.__module__}.{ext.__name__}"
|
38
|
-
if identifier not in
|
41
|
+
if identifier not in seen_names:
|
39
42
|
unique_extractors.append(ext)
|
40
|
-
|
43
|
+
seen_names.add(identifier)
|
41
44
|
|
42
45
|
konsol.log(f"[blue]Sonuç Extractor'lar: {[e.__name__ for e in unique_extractors]}[/blue]")
|
43
46
|
|
@@ -48,12 +51,14 @@ class ExtractorLoader:
|
|
48
51
|
|
49
52
|
def _load_from_directory(self, directory: Path) -> list[ExtractorBase]:
|
50
53
|
extractors = []
|
54
|
+
|
55
|
+
# Dizindeki tüm .py dosyalarını tara
|
51
56
|
for file in os.listdir(directory):
|
52
57
|
if file.endswith(".py") and not file.startswith("__"):
|
53
|
-
module_name = file[:-3]
|
54
|
-
konsol.log(f"[cyan]
|
58
|
+
module_name = file[:-3] # .py uzantısını kaldır
|
59
|
+
konsol.log(f"[cyan]Okunan Dosya\t\t: {module_name}[/cyan]")
|
55
60
|
if extractor := self._load_extractor(directory, module_name):
|
56
|
-
konsol.log(f"[magenta]Extractor
|
61
|
+
konsol.log(f"[magenta]Extractor Yüklendi\t: {extractor.__name__}[/magenta]")
|
57
62
|
extractors.append(extractor)
|
58
63
|
|
59
64
|
konsol.log(f"[yellow]{directory} dizininden yüklenen Extractor'lar: {[e.__name__ for e in extractors]}[/yellow]")
|
@@ -61,11 +66,13 @@ class ExtractorLoader:
|
|
61
66
|
|
62
67
|
def _load_extractor(self, directory: Path, module_name: str):
|
63
68
|
try:
|
69
|
+
# Modül dosyasını bul ve yükle
|
64
70
|
path = directory / f"{module_name}.py"
|
65
71
|
spec = importlib.util.spec_from_file_location(module_name, path)
|
66
72
|
if not spec or not spec.loader:
|
67
73
|
return None
|
68
74
|
|
75
|
+
# Modülü içe aktar
|
69
76
|
module = importlib.util.module_from_spec(spec)
|
70
77
|
spec.loader.exec_module(module)
|
71
78
|
|
@@ -73,7 +80,7 @@ class ExtractorLoader:
|
|
73
80
|
for attr in dir(module):
|
74
81
|
obj = getattr(module, attr)
|
75
82
|
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]")
|
83
|
+
konsol.log(f"[green]Yüklenen sınıf\t\t: {module_name}.{obj.__name__} ({obj.__module__}.{obj.__name__})[/green]")
|
77
84
|
return obj
|
78
85
|
|
79
86
|
except Exception as hata:
|
@@ -1,13 +1,16 @@
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
2
|
|
3
|
-
from
|
3
|
+
from .ExtractorLoader import ExtractorLoader
|
4
|
+
from .ExtractorBase import ExtractorBase
|
4
5
|
|
5
6
|
class ExtractorManager:
|
6
7
|
def __init__(self, extractor_dir="Extractors"):
|
8
|
+
# Çıkarıcı yükleyiciyi başlat ve tüm çıkarıcıları yükle
|
7
9
|
self.extractor_loader = ExtractorLoader(extractor_dir)
|
8
10
|
self.extractors = self.extractor_loader.load_all()
|
9
11
|
|
10
|
-
def find_extractor(self, link):
|
12
|
+
def find_extractor(self, link) -> ExtractorBase:
|
13
|
+
# Verilen bağlantıyı işleyebilecek çıkarıcıyı bul
|
11
14
|
for extractor_cls in self.extractors:
|
12
15
|
extractor:ExtractorBase = extractor_cls()
|
13
16
|
if extractor.can_handle_url(link):
|
@@ -15,7 +18,8 @@ class ExtractorManager:
|
|
15
18
|
|
16
19
|
return None
|
17
20
|
|
18
|
-
def map_links_to_extractors(self, links):
|
21
|
+
def map_links_to_extractors(self, links) -> dict:
|
22
|
+
# Bağlantıları uygun çıkarıcılarla eşleştir
|
19
23
|
mapping = {}
|
20
24
|
for link in links:
|
21
25
|
for extractor_cls in self.extractors:
|
@@ -1,11 +1,12 @@
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
2
|
|
3
|
-
from
|
4
|
-
from .ExtractorModels import ExtractResult
|
3
|
+
from ...CLI import konsol
|
4
|
+
from ..Extractor.ExtractorModels import ExtractResult
|
5
5
|
import subprocess, os
|
6
6
|
|
7
7
|
class MediaHandler:
|
8
8
|
def __init__(self, title: str = "KekikStream", headers: dict = None):
|
9
|
+
# Varsayılan HTTP başlıklarını ayarla
|
9
10
|
if headers is None:
|
10
11
|
headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5)"}
|
11
12
|
|
@@ -13,12 +14,15 @@ class MediaHandler:
|
|
13
14
|
self.title = title
|
14
15
|
|
15
16
|
def play_media(self, extract_data: ExtractResult):
|
17
|
+
# Google Drive gibi özel durumlar için yt-dlp kullan
|
16
18
|
if self.headers.get("User-Agent") == "googleusercontent":
|
17
19
|
return self.play_with_ytdlp(extract_data)
|
18
20
|
|
21
|
+
# İşletim sistemine göre oynatıcı seç
|
19
22
|
if subprocess.check_output(['uname', '-o']).strip() == b'Android':
|
20
23
|
return self.play_with_android_mxplayer(extract_data)
|
21
24
|
|
25
|
+
# Cookie veya alt yazılar varsa mpv kullan
|
22
26
|
if "Cookie" in self.headers or extract_data.subtitles:
|
23
27
|
return self.play_with_mpv(extract_data)
|
24
28
|
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
2
|
|
3
|
-
from abc
|
4
|
-
from httpx
|
5
|
-
from cloudscraper
|
6
|
-
from .PluginModels
|
7
|
-
from .MediaHandler import MediaHandler
|
8
|
-
from urllib.parse
|
3
|
+
from abc import ABC, abstractmethod
|
4
|
+
from httpx import AsyncClient, Timeout
|
5
|
+
from cloudscraper import CloudScraper
|
6
|
+
from .PluginModels import SearchResult, MovieInfo
|
7
|
+
from ..Media.MediaHandler import MediaHandler
|
8
|
+
from urllib.parse import urljoin
|
9
9
|
import re
|
10
10
|
|
11
11
|
class PluginBase(ABC):
|
@@ -1,61 +1,75 @@
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
2
|
|
3
|
-
from
|
3
|
+
from ...CLI import konsol, cikis_yap
|
4
4
|
from .PluginBase import PluginBase
|
5
5
|
from pathlib import Path
|
6
6
|
import os, importlib.util, traceback
|
7
7
|
|
8
8
|
class PluginLoader:
|
9
9
|
def __init__(self, plugins_dir: str):
|
10
|
+
# Yerel ve global eklenti dizinlerini ayarla
|
10
11
|
self.local_plugins_dir = Path(plugins_dir).resolve()
|
11
|
-
self.global_plugins_dir = Path(__file__).parent.parent / plugins_dir
|
12
|
+
self.global_plugins_dir = Path(__file__).parent.parent.parent / plugins_dir
|
13
|
+
|
14
|
+
# Dizin kontrolü
|
12
15
|
if not self.local_plugins_dir.exists() and not self.global_plugins_dir.exists():
|
13
|
-
konsol.log(f"[red][!]
|
16
|
+
konsol.log(f"[red][!] Eklenti dizini bulunamadı: {plugins_dir}[/red]")
|
14
17
|
cikis_yap(False)
|
15
18
|
|
16
19
|
def load_all(self) -> dict[str, PluginBase]:
|
17
20
|
plugins = {}
|
18
21
|
|
22
|
+
# Global eklentileri yükle
|
19
23
|
if self.global_plugins_dir.exists():
|
20
|
-
konsol.log(f"[green][*] Global
|
24
|
+
konsol.log(f"[green][*] Global Eklenti dizininden yükleniyor: {self.global_plugins_dir}[/green]")
|
21
25
|
plugins |= self._load_from_directory(self.global_plugins_dir)
|
22
26
|
|
27
|
+
# Yerel eklentileri yükle
|
23
28
|
if self.local_plugins_dir.exists():
|
24
|
-
konsol.log(f"[green][*] Yerel
|
29
|
+
konsol.log(f"[green][*] Yerel Eklenti dizininden yükleniyor: {self.local_plugins_dir}[/green]")
|
25
30
|
plugins |= self._load_from_directory(self.local_plugins_dir)
|
26
31
|
|
27
32
|
if not plugins:
|
28
|
-
konsol.print("[yellow][!] Yüklenecek bir
|
33
|
+
konsol.print("[yellow][!] Yüklenecek bir Eklenti bulunamadı![/yellow]")
|
29
34
|
|
30
35
|
return dict(sorted(plugins.items()))
|
31
36
|
|
32
37
|
def _load_from_directory(self, directory: Path) -> dict[str, PluginBase]:
|
33
38
|
plugins = {}
|
39
|
+
|
40
|
+
# Dizindeki tüm .py dosyalarını tara
|
34
41
|
for file in os.listdir(directory):
|
35
42
|
if file.endswith(".py") and not file.startswith("__"):
|
36
|
-
module_name = file[:-3]
|
43
|
+
module_name = file[:-3] # .py uzantısını kaldır
|
44
|
+
konsol.log(f"[cyan]Okunan Dosya\t\t: {module_name}[/cyan]")
|
37
45
|
if plugin := self._load_plugin(directory, module_name):
|
46
|
+
konsol.log(f"[magenta]Eklenti Yüklendi\t: {plugin.name}[/magenta]")
|
38
47
|
plugins[module_name] = plugin
|
39
48
|
|
49
|
+
konsol.log(f"[yellow]{directory} dizininden yüklenen Eklentiler: {list(plugins.keys())}[/yellow]")
|
40
50
|
return plugins
|
41
51
|
|
42
52
|
def _load_plugin(self, directory: Path, module_name: str):
|
43
53
|
try:
|
54
|
+
# Modül dosyasını bul ve yükle
|
44
55
|
path = directory / f"{module_name}.py"
|
45
56
|
spec = importlib.util.spec_from_file_location(module_name, path)
|
46
57
|
if not spec or not spec.loader:
|
47
58
|
raise ImportError(f"Spec oluşturulamadı: {module_name}")
|
48
59
|
|
60
|
+
# Modülü içe aktar
|
49
61
|
module = importlib.util.module_from_spec(spec)
|
50
62
|
spec.loader.exec_module(module)
|
51
63
|
|
64
|
+
# Yalnızca doğru modülden gelen PluginBase sınıflarını yükle
|
52
65
|
for attr in dir(module):
|
53
66
|
obj = getattr(module, attr)
|
54
67
|
if isinstance(obj, type) and issubclass(obj, PluginBase) and obj is not PluginBase:
|
68
|
+
konsol.log(f"[yellow]Yüklenen sınıf\t\t: {module_name}.{obj.__name__} ({obj.__module__}.{obj.__name__})[/yellow]")
|
55
69
|
return obj()
|
56
70
|
|
57
71
|
except Exception as hata:
|
58
|
-
konsol.print(f"[red][!]
|
72
|
+
konsol.print(f"[red][!] Eklenti yüklenirken hata oluştu: {module_name}\nHata: {hata}")
|
59
73
|
konsol.print(f"[dim]{traceback.format_exc()}[/dim]")
|
60
74
|
|
61
75
|
return None
|
@@ -1,19 +1,24 @@
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
2
|
|
3
|
-
from
|
3
|
+
from .PluginLoader import PluginLoader
|
4
|
+
from .PluginBase import PluginBase
|
4
5
|
|
5
6
|
class PluginManager:
|
6
7
|
def __init__(self, plugin_dir="Plugins"):
|
8
|
+
# Eklenti yükleyiciyi başlat ve tüm eklentileri yükle
|
7
9
|
self.plugin_loader = PluginLoader(plugin_dir)
|
8
10
|
self.plugins = self.plugin_loader.load_all()
|
9
11
|
|
10
12
|
def get_plugin_names(self):
|
13
|
+
# Dizindeki tüm eklenti adlarını listeler ve sıralar
|
11
14
|
return sorted(list(self.plugins.keys()))
|
12
15
|
|
13
16
|
def select_plugin(self, plugin_name):
|
17
|
+
# Verilen eklenti adını kullanarak eklentiyi seç
|
14
18
|
return self.plugins.get(plugin_name)
|
15
19
|
|
16
20
|
async def close_plugins(self):
|
21
|
+
# Tüm eklentileri kapat
|
17
22
|
for plugin in self.plugins.values():
|
18
23
|
if isinstance(plugin, PluginBase):
|
19
24
|
await plugin.close()
|
KekikStream/Core/__init__.py
CHANGED
@@ -1,9 +1,16 @@
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
2
|
|
3
|
-
from .
|
4
|
-
|
5
|
-
from .
|
6
|
-
from .
|
7
|
-
from .
|
8
|
-
from .
|
9
|
-
|
3
|
+
from .UI.UIManager import UIManager
|
4
|
+
|
5
|
+
from .Plugin.PluginManager import PluginManager
|
6
|
+
from .Plugin.PluginBase import PluginBase
|
7
|
+
from .Plugin.PluginLoader import PluginLoader
|
8
|
+
from .Plugin.PluginModels import SearchResult, MovieInfo, Episode, SeriesInfo
|
9
|
+
|
10
|
+
from .Extractor.ExtractorManager import ExtractorManager
|
11
|
+
from .Extractor.ExtractorBase import ExtractorBase
|
12
|
+
from .Extractor.ExtractorLoader import ExtractorLoader
|
13
|
+
from .Extractor.ExtractorModels import ExtractResult, Subtitle
|
14
|
+
|
15
|
+
from .Media.MediaManager import MediaManager
|
16
|
+
from .Media.MediaHandler import MediaHandler
|
KekikStream/Plugins/RecTV.py
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
2
|
|
3
|
-
from KekikStream.CLI
|
4
|
-
from KekikStream.Core
|
5
|
-
from
|
6
|
-
from
|
7
|
-
from json import dumps, loads
|
3
|
+
from KekikStream.CLI import konsol
|
4
|
+
from KekikStream.Core import PluginBase, SearchResult, MovieInfo, Episode, SeriesInfo, ExtractResult, Subtitle
|
5
|
+
from httpx import AsyncClient
|
6
|
+
from json import dumps, loads
|
8
7
|
import re
|
9
8
|
|
10
9
|
|
KekikStream/Plugins/SineWix.py
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
2
|
|
3
|
-
from KekikStream.Core
|
4
|
-
from KekikStream.Core.ExtractorModels import ExtractResult, Subtitle
|
3
|
+
from KekikStream.Core import PluginBase, SearchResult, MovieInfo, Episode, SeriesInfo, ExtractResult, Subtitle
|
5
4
|
|
6
5
|
class SineWix(PluginBase):
|
7
6
|
name = "SineWix"
|
KekikStream/__init__.py
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
2
|
|
3
3
|
from .CLI import konsol, cikis_yap, hata_yakala, pypi_kontrol_guncelle
|
4
|
-
from .
|
5
|
-
from .Core import PluginBase, ExtractorBase, SeriesInfo
|
4
|
+
from .Core import PluginManager, ExtractorManager, UIManager, MediaManager, PluginBase, ExtractorBase, SeriesInfo
|
6
5
|
from asyncio import run
|
7
6
|
from contextlib import suppress
|
8
7
|
|
9
8
|
class KekikStream:
|
10
9
|
def __init__(self):
|
10
|
+
# Yönetici sınıflarını başlat
|
11
11
|
self.eklentiler_yonetici = PluginManager()
|
12
12
|
self.cikaricilar_yonetici = ExtractorManager()
|
13
13
|
self.arayuz_yonetici = UIManager()
|
@@ -15,17 +15,22 @@ class KekikStream:
|
|
15
15
|
self.suanki_eklenti: PluginBase = None
|
16
16
|
|
17
17
|
async def baslat(self):
|
18
|
+
# Konsolu temizle ve başlık göster
|
18
19
|
self.arayuz_yonetici.clear_console()
|
19
20
|
konsol.rule("[bold cyan]KekikStream Başlatılıyor[/bold cyan]")
|
21
|
+
|
22
|
+
# Eklenti kontrolü
|
20
23
|
if not self.eklentiler_yonetici.get_plugin_names():
|
21
24
|
return konsol.print("[bold red]Hiçbir eklenti bulunamadı![/bold red]")
|
22
25
|
|
23
26
|
try:
|
24
27
|
await self.eklenti_secimi()
|
25
28
|
finally:
|
29
|
+
# Program kapanırken tüm eklentileri kapat
|
26
30
|
await self.eklentiler_yonetici.close_plugins()
|
27
31
|
|
28
32
|
async def sonuc_bulunamadi(self):
|
33
|
+
# Sonuç bulunamadığında kullanıcıya seçenekler sun
|
29
34
|
secim = await self.arayuz_yonetici.select_from_list(
|
30
35
|
message = "Ne yapmak istersiniz?",
|
31
36
|
choices = ["Tüm Eklentilerde Ara", "Ana Menü", "Çıkış"]
|
@@ -40,6 +45,7 @@ class KekikStream:
|
|
40
45
|
cikis_yap(False)
|
41
46
|
|
42
47
|
async def eklenti_secimi(self):
|
48
|
+
# Fuzzy ile eklenti seçimi yap
|
43
49
|
eklenti_adi = await self.arayuz_yonetici.select_from_fuzzy(
|
44
50
|
message = "Arama yapılacak eklentiyi seçin:",
|
45
51
|
choices = ["Tüm Eklentilerde Ara", *self.eklentiler_yonetici.get_plugin_names()]
|
@@ -52,9 +58,11 @@ class KekikStream:
|
|
52
58
|
await self.eklenti_ile_arama()
|
53
59
|
|
54
60
|
async def eklenti_ile_arama(self):
|
61
|
+
# Seçilen eklentide arama yap
|
55
62
|
self.arayuz_yonetici.clear_console()
|
56
63
|
konsol.rule(f"[bold cyan]{self.suanki_eklenti.name} Eklentisinde Arama Yapın[/bold cyan]")
|
57
64
|
|
65
|
+
# Kullanıcıdan sorgu al ve ara
|
58
66
|
sorgu = await self.arayuz_yonetici.prompt_text("Arama sorgusu girin:")
|
59
67
|
sonuclar = await self.suanki_eklenti.search(sorgu)
|
60
68
|
|
@@ -66,12 +74,14 @@ class KekikStream:
|
|
66
74
|
await self.sonuc_detaylari_goster({"plugin": self.suanki_eklenti.name, "url": secilen_sonuc})
|
67
75
|
|
68
76
|
async def eklenti_sonuc_secimi(self, sonuclar):
|
77
|
+
# Arama sonuçlarından birini seç
|
69
78
|
return await self.arayuz_yonetici.select_from_fuzzy(
|
70
79
|
message = "İçerik sonuçlarından birini seçin:",
|
71
80
|
choices = [{"name": sonuc.title, "value": sonuc.url} for sonuc in sonuclar]
|
72
81
|
)
|
73
82
|
|
74
83
|
async def tum_eklentilerde_arama(self):
|
84
|
+
# Tüm eklentilerde arama yap
|
75
85
|
self.arayuz_yonetici.clear_console()
|
76
86
|
konsol.rule("[bold cyan]Tüm Eklentilerde Arama Yapın[/bold cyan]")
|
77
87
|
|
@@ -89,7 +99,9 @@ class KekikStream:
|
|
89
99
|
async def tum_eklentilerde_arama_sorgula(self, sorgu: str) -> list:
|
90
100
|
tum_sonuclar = []
|
91
101
|
|
102
|
+
# Her eklentide arama yap
|
92
103
|
for eklenti_adi, eklenti in self.eklentiler_yonetici.plugins.items():
|
104
|
+
# Eklenti türü kontrolü
|
93
105
|
if not isinstance(eklenti, PluginBase):
|
94
106
|
konsol.print(f"[yellow][!] {eklenti_adi} geçerli bir PluginBase değil, atlanıyor...[/yellow]")
|
95
107
|
continue
|
@@ -98,6 +110,7 @@ class KekikStream:
|
|
98
110
|
try:
|
99
111
|
sonuclar = await eklenti.search(sorgu)
|
100
112
|
if sonuclar:
|
113
|
+
# Sonuçları listeye ekle
|
101
114
|
tum_sonuclar.extend(
|
102
115
|
[{"plugin": eklenti_adi, "title": sonuc.title, "url": sonuc.url, "poster": sonuc.poster} for sonuc in sonuclar]
|
103
116
|
)
|
@@ -112,6 +125,7 @@ class KekikStream:
|
|
112
125
|
return tum_sonuclar
|
113
126
|
|
114
127
|
async def tum_sonuc_secimi(self, sonuclar):
|
128
|
+
# Tüm sonuçlardan birini seç
|
115
129
|
secenekler = [
|
116
130
|
{"name": f"[{sonuc['plugin']}]".ljust(21) + f" » {sonuc['title']}", "value": sonuc}
|
117
131
|
for sonuc in sonuclar
|
@@ -124,6 +138,7 @@ class KekikStream:
|
|
124
138
|
|
125
139
|
async def sonuc_detaylari_goster(self, secilen_sonuc):
|
126
140
|
try:
|
141
|
+
# Seçilen sonucun detaylarını al
|
127
142
|
if isinstance(secilen_sonuc, dict) and "plugin" in secilen_sonuc:
|
128
143
|
eklenti_adi = secilen_sonuc["plugin"]
|
129
144
|
url = secilen_sonuc["url"]
|
@@ -132,6 +147,7 @@ class KekikStream:
|
|
132
147
|
else:
|
133
148
|
url = secilen_sonuc
|
134
149
|
|
150
|
+
# Medya bilgilerini yükle (3 deneme hakkı)
|
135
151
|
medya_bilgi = None
|
136
152
|
for _ in range(3):
|
137
153
|
with suppress(Exception):
|
@@ -145,9 +161,11 @@ class KekikStream:
|
|
145
161
|
konsol.log(secilen_sonuc)
|
146
162
|
return hata_yakala(hata)
|
147
163
|
|
164
|
+
# Medya başlığını ayarla ve bilgileri göster
|
148
165
|
self.medya_yonetici.set_title(f"{self.suanki_eklenti.name} | {medya_bilgi.title}")
|
149
166
|
self.arayuz_yonetici.display_media_info(f"{self.suanki_eklenti.name} | {medya_bilgi.title}", medya_bilgi)
|
150
167
|
|
168
|
+
# Dizi ise bölüm seçimi yap
|
151
169
|
if isinstance(medya_bilgi, SeriesInfo):
|
152
170
|
secilen_bolum = await self.arayuz_yonetici.select_from_fuzzy(
|
153
171
|
message = "İzlemek istediğiniz bölümü seçin:",
|
@@ -168,15 +186,19 @@ class KekikStream:
|
|
168
186
|
konsol.print("[bold red]Hiçbir bağlantı bulunamadı![/bold red]")
|
169
187
|
return await self.sonuc_bulunamadi()
|
170
188
|
|
189
|
+
# Bağlantıları çıkarıcılarla eşleştir
|
171
190
|
haritalama = self.cikaricilar_yonetici.map_links_to_extractors(baglantilar)
|
172
191
|
play_fonksiyonu_var = hasattr(self.suanki_eklenti, "play") and callable(getattr(self.suanki_eklenti, "play", None))
|
173
192
|
# ! DEBUG
|
174
193
|
# konsol.print(baglantilar)
|
194
|
+
|
195
|
+
# Uygun çıkarıcı kontrolü
|
175
196
|
if not haritalama and not play_fonksiyonu_var:
|
176
197
|
konsol.print("[bold red]Hiçbir Extractor bulunamadı![/bold red]")
|
177
198
|
konsol.print(baglantilar)
|
178
199
|
return await self.sonuc_bulunamadi()
|
179
200
|
|
201
|
+
# Doğrudan oynatma seçeneği
|
180
202
|
if not haritalama:
|
181
203
|
secilen_link = await self.arayuz_yonetici.select_from_list(
|
182
204
|
message = "Doğrudan oynatmak için bir bağlantı seçin:",
|
@@ -186,6 +208,7 @@ class KekikStream:
|
|
186
208
|
await self.medya_oynat(secilen_link)
|
187
209
|
return
|
188
210
|
|
211
|
+
# Kullanıcı seçenekleri
|
189
212
|
secim = await self.arayuz_yonetici.select_from_list(
|
190
213
|
message = "Ne yapmak istersiniz?",
|
191
214
|
choices = ["İzle", "Tüm Eklentilerde Ara", "Ana Menü"]
|
@@ -207,6 +230,7 @@ class KekikStream:
|
|
207
230
|
await self.baslat()
|
208
231
|
|
209
232
|
async def medya_oynat(self, secilen_link):
|
233
|
+
# Eklentinin kendi oynatıcısı varsa onu kullan
|
210
234
|
if hasattr(self.suanki_eklenti, "play") and callable(self.suanki_eklenti.play):
|
211
235
|
konsol.log(f"[yellow][»] Oynatılıyor : {secilen_link}")
|
212
236
|
return await self.suanki_eklenti.play(
|
@@ -216,16 +240,19 @@ class KekikStream:
|
|
216
240
|
subtitles = self.suanki_eklenti._data[secilen_link]["subtitles"]
|
217
241
|
)
|
218
242
|
|
243
|
+
# Uygun çıkarıcıyı bul
|
219
244
|
cikarici: ExtractorBase = self.cikaricilar_yonetici.find_extractor(secilen_link)
|
220
245
|
if not cikarici:
|
221
246
|
return konsol.print("[bold red]Uygun Extractor bulunamadı.[/bold red]")
|
222
247
|
|
223
248
|
try:
|
249
|
+
# Medya bilgilerini çıkar
|
224
250
|
extract_data = await cikarici.extract(secilen_link, referer=self.suanki_eklenti.main_url)
|
225
251
|
except Exception as hata:
|
226
252
|
konsol.print(f"[bold red]{cikarici.name} » hata oluştu: {hata}[/bold red]")
|
227
253
|
return await self.sonuc_bulunamadi()
|
228
254
|
|
255
|
+
# Birden fazla bağlantı varsa seçim yap
|
229
256
|
if isinstance(extract_data, list):
|
230
257
|
secilen_data = await self.arayuz_yonetici.select_from_list(
|
231
258
|
message = "Birden fazla bağlantı bulundu, lütfen birini seçin:",
|
@@ -234,9 +261,11 @@ class KekikStream:
|
|
234
261
|
else:
|
235
262
|
secilen_data = extract_data
|
236
263
|
|
264
|
+
# Cookie varsa ayarla
|
237
265
|
if secilen_data.headers.get("Cookie"):
|
238
266
|
self.medya_yonetici.set_headers({"Cookie": secilen_data.headers.get("Cookie")})
|
239
267
|
|
268
|
+
# Başlık ve referrer ayarla
|
240
269
|
self.medya_yonetici.set_title(f"{self.medya_yonetici.get_title()} | {secilen_data.name}")
|
241
270
|
self.medya_yonetici.set_headers({"Referer": secilen_data.referer})
|
242
271
|
konsol.log(f"[yellow][»] Oynatılıyor : {secilen_data.url}")
|
@@ -244,8 +273,10 @@ class KekikStream:
|
|
244
273
|
|
245
274
|
def basla():
|
246
275
|
try:
|
276
|
+
# PyPI güncellemelerini kontrol et
|
247
277
|
pypi_kontrol_guncelle("KekikStream")
|
248
278
|
|
279
|
+
# Uygulamayı başlat
|
249
280
|
app = KekikStream()
|
250
281
|
run(app.baslat())
|
251
282
|
cikis_yap(False)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: KekikStream
|
3
|
-
Version: 0.8.
|
3
|
+
Version: 0.8.2
|
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
|
@@ -1,16 +1,20 @@
|
|
1
|
-
KekikStream/__init__.py,sha256=
|
1
|
+
KekikStream/__init__.py,sha256=2ocXWKQcb05mHfRPHKxHt7nHufvPOzKESmTrIVfy70k,12174
|
2
2
|
KekikStream/__main__.py,sha256=B81dQoeGEb-T5Sycs3eNAmW7unvx0Mef0syCjs4nPds,137
|
3
3
|
KekikStream/requirements.txt,sha256=QWCXrrmKodIm7mGtIz9cWr9sks-lmL_TilKMrruWJn0,77
|
4
4
|
KekikStream/CLI/__init__.py,sha256=U6oLq_O7u5y2eHhBnmfhZNns_EqHHJXJmzl8jvZFUNY,230
|
5
5
|
KekikStream/CLI/pypi_kontrol.py,sha256=MchatOwCWCpFBtgt09yag9Rjal9XFyh2W_oVs2p7SNg,1518
|
6
|
-
KekikStream/Core/
|
7
|
-
KekikStream/Core/
|
8
|
-
KekikStream/Core/
|
9
|
-
KekikStream/Core/
|
10
|
-
KekikStream/Core/
|
11
|
-
KekikStream/Core/
|
12
|
-
KekikStream/Core/
|
13
|
-
KekikStream/Core/
|
6
|
+
KekikStream/Core/__init__.py,sha256=2N0VFP4QsyDWn4pV77JX_5_XachD5qKzhuDor3klj58,657
|
7
|
+
KekikStream/Core/Extractor/ExtractorBase.py,sha256=ZyasO5m7iAsnh-mwhtlp-VXkZ4pIuWuHvCIskBX7FUg,1726
|
8
|
+
KekikStream/Core/Extractor/ExtractorLoader.py,sha256=ecrfz9mYizlENCjbyfjdfnOrQorxQTF4ZFGhPpU6JHk,4193
|
9
|
+
KekikStream/Core/Extractor/ExtractorManager.py,sha256=4L1H3jiTnf0kTq4W6uS7n95bBYHlKJ8_hh0og8z4erQ,1244
|
10
|
+
KekikStream/Core/Extractor/ExtractorModels.py,sha256=huIcPQ5VIRfMx0LcL5SS1u4dldZbHjzHKEdSEtOPlc0,456
|
11
|
+
KekikStream/Core/Media/MediaHandler.py,sha256=-yVOnI5pNKWgvrRgJ8DVKjvTWuHTwUC7JSKlKa06lSw,6179
|
12
|
+
KekikStream/Core/Media/MediaManager.py,sha256=9ItiUguOkk3wg3YY5uf3mrjfwLPCvggnP8QviX0uiuE,526
|
13
|
+
KekikStream/Core/Plugin/PluginBase.py,sha256=KuR89bkrChPAct4-PMjxbK4i6busXMMFeZjv-x4F1CQ,2521
|
14
|
+
KekikStream/Core/Plugin/PluginLoader.py,sha256=2UM3gNcEgd7k-FxG-JB5nTIS0K_clzvFtzGjMA_Sx7Q,3379
|
15
|
+
KekikStream/Core/Plugin/PluginManager.py,sha256=CZVg1eegi8vfMfccx0DRV0Box8kXz-aoULTQLgbPbvM,893
|
16
|
+
KekikStream/Core/Plugin/PluginModels.py,sha256=q8tjkt_-uiJ7uNxOThYR0FgTQLZglVAOAaM0Kske-28,2063
|
17
|
+
KekikStream/Core/UI/UIManager.py,sha256=T4V_kdTTWa-UDamgLSKa__dWJuzcvRK9NuwBlzU9Bzc,1693
|
14
18
|
KekikStream/Extractors/CloseLoad.py,sha256=YmDB3YvuDaCUbQ0T_tmhnkEsC5mSdEN6GNoAR662fl8,990
|
15
19
|
KekikStream/Extractors/ContentX.py,sha256=XPoAuA95LOTgCUGyioXxOFWR0nNKWWOHLkYMlzguIIE,2980
|
16
20
|
KekikStream/Extractors/FourCX.py,sha256=4FrMj1IZBBpN_g1P6S3A-8eUu7QFwlt4fJXzJ7vfe0Q,221
|
@@ -36,24 +40,19 @@ KekikStream/Extractors/TurboImgz.py,sha256=VXx9vZZRTdQiVNER0LcXm2nsv2OaXnxuPpslG
|
|
36
40
|
KekikStream/Extractors/VidMoly.py,sha256=BKJgk60GomFYiLFsRQSR2sOYP105Aix5y5XLazBNWmw,3368
|
37
41
|
KekikStream/Extractors/VidMoxy.py,sha256=_K6BA7Uo59DA3ty_tsayCUZjXmRoDBTghekVNXiuZ7g,1800
|
38
42
|
KekikStream/Extractors/VideoSeyred.py,sha256=otyGi1zdY_JPrXJjoZjesCQDiOkxFdaWiXQ9mOmrygA,1780
|
39
|
-
KekikStream/Managers/ExtractorManager.py,sha256=9rGlUsnedJ7fwIeObN5Vsm8H5VLal0ODO7F93dDRx8w,976
|
40
|
-
KekikStream/Managers/MediaManager.py,sha256=SPO85LchT7bJKSecmXd1FzCjg0rUT8s3B1wulPa4SMw,519
|
41
|
-
KekikStream/Managers/PluginManager.py,sha256=YDBLHB_Fh79A3Pei0ny2KLVY4VSihdNiKBh_w5tBl-0,637
|
42
|
-
KekikStream/Managers/UIManager.py,sha256=e89u_QgmxL85zGAYyYsQp6b3E5y7fHGteLt2OYHHbD8,1693
|
43
|
-
KekikStream/Managers/__init__.py,sha256=3085I_9Sa2L_Vq6Z-QvYUYn1BapkN4sQqBo8ITZoD_4,251
|
44
43
|
KekikStream/Plugins/DiziBox.py,sha256=i_73VNXk2eM7xTg-6a0Xk2Yts2c9grWbRVVHhxFgoic,5935
|
45
44
|
KekikStream/Plugins/DiziYou.py,sha256=kpRY3U6lqaZKgn9ED2TprwU7qfLxuC2ZZmrRemegryo,5382
|
46
45
|
KekikStream/Plugins/Dizilla.py,sha256=evWYvETw1c4RY0GB5P20cB_I_U7ZxzzvnG7RLNGJRPs,4258
|
47
46
|
KekikStream/Plugins/FilmMakinesi.py,sha256=rz8TQeL41PJbeEmksgPHIhp6J-4vbSCBTeEH0ukExz4,2822
|
48
47
|
KekikStream/Plugins/FullHDFilmizlesene.py,sha256=Fa0gRP_NoMfPC8HIKRxERjQVOv8Fyb-ayMJ2EooZ7BE,3080
|
49
48
|
KekikStream/Plugins/JetFilmizle.py,sha256=FXkMSQtjYoxwIonjRENFa91rC42L_8SYRhjhuSgsu60,3919
|
50
|
-
KekikStream/Plugins/RecTV.py,sha256=
|
49
|
+
KekikStream/Plugins/RecTV.py,sha256=Pt2IQ2jLsQp7Mo85uM_ml3nxOR0uirX7vXOnE10CPm0,4886
|
51
50
|
KekikStream/Plugins/SezonlukDizi.py,sha256=5BZVzQ2eQtymHxO0bzjA2ho4FFNahPFQly4hoHuH8lo,4441
|
52
|
-
KekikStream/Plugins/SineWix.py,sha256=
|
51
|
+
KekikStream/Plugins/SineWix.py,sha256=VvFeAS2-Y-KJ1Od16yZjUJLiESwsBBGb2GNG3BLLupU,4806
|
53
52
|
KekikStream/Plugins/UgurFilm.py,sha256=yYXee5uxwNnPqFJZ6s6cRkmUyqS3Vv8x-iesPalc4j4,2930
|
54
|
-
KekikStream-0.8.
|
55
|
-
KekikStream-0.8.
|
56
|
-
KekikStream-0.8.
|
57
|
-
KekikStream-0.8.
|
58
|
-
KekikStream-0.8.
|
59
|
-
KekikStream-0.8.
|
53
|
+
KekikStream-0.8.2.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
54
|
+
KekikStream-0.8.2.dist-info/METADATA,sha256=qGDsp7unyH1NgrlDfx5g7dpx59o_e03zkKbSBAQTGs0,4226
|
55
|
+
KekikStream-0.8.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
56
|
+
KekikStream-0.8.2.dist-info/entry_points.txt,sha256=dFwdiTx8djyehI0Gsz-rZwjAfZzUzoBSrmzRu9ubjJc,50
|
57
|
+
KekikStream-0.8.2.dist-info/top_level.txt,sha256=DNmGJDXl27Drdfobrak8KYLmocW_uznVYFJOzcjUgmY,12
|
58
|
+
KekikStream-0.8.2.dist-info/RECORD,,
|
KekikStream/Managers/__init__.py
DELETED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|