KekikStream 0.8.1__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/Extractor/ExtractorBase.py +8 -2
- KekikStream/Core/Extractor/ExtractorLoader.py +16 -9
- KekikStream/Core/Extractor/ExtractorManager.py +5 -2
- KekikStream/Core/Media/MediaHandler.py +4 -0
- KekikStream/Core/Plugin/PluginLoader.py +20 -6
- KekikStream/Core/Plugin/PluginManager.py +4 -0
- KekikStream/__init__.py +32 -0
- {KekikStream-0.8.1.dist-info → KekikStream-0.8.2.dist-info}/METADATA +1 -1
- {KekikStream-0.8.1.dist-info → KekikStream-0.8.2.dist-info}/RECORD +13 -13
- {KekikStream-0.8.1.dist-info → KekikStream-0.8.2.dist-info}/LICENSE +0 -0
- {KekikStream-0.8.1.dist-info → KekikStream-0.8.2.dist-info}/WHEEL +0 -0
- {KekikStream-0.8.1.dist-info → KekikStream-0.8.2.dist-info}/entry_points.txt +0 -0
- {KekikStream-0.8.1.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
|
|
@@ -7,8 +7,11 @@ 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
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:
|
@@ -5,10 +5,12 @@ from .ExtractorBase import ExtractorBase
|
|
5
5
|
|
6
6
|
class ExtractorManager:
|
7
7
|
def __init__(self, extractor_dir="Extractors"):
|
8
|
+
# Çıkarıcı yükleyiciyi başlat ve tüm çıkarıcıları yükle
|
8
9
|
self.extractor_loader = ExtractorLoader(extractor_dir)
|
9
10
|
self.extractors = self.extractor_loader.load_all()
|
10
11
|
|
11
|
-
def find_extractor(self, link):
|
12
|
+
def find_extractor(self, link) -> ExtractorBase:
|
13
|
+
# Verilen bağlantıyı işleyebilecek çıkarıcıyı bul
|
12
14
|
for extractor_cls in self.extractors:
|
13
15
|
extractor:ExtractorBase = extractor_cls()
|
14
16
|
if extractor.can_handle_url(link):
|
@@ -16,7 +18,8 @@ class ExtractorManager:
|
|
16
18
|
|
17
19
|
return None
|
18
20
|
|
19
|
-
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
|
20
23
|
mapping = {}
|
21
24
|
for link in links:
|
22
25
|
for extractor_cls in self.extractors:
|
@@ -6,6 +6,7 @@ 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
|
|
@@ -7,55 +7,69 @@ 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
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
|
@@ -5,16 +5,20 @@ from .PluginBase import PluginBase
|
|
5
5
|
|
6
6
|
class PluginManager:
|
7
7
|
def __init__(self, plugin_dir="Plugins"):
|
8
|
+
# Eklenti yükleyiciyi başlat ve tüm eklentileri yükle
|
8
9
|
self.plugin_loader = PluginLoader(plugin_dir)
|
9
10
|
self.plugins = self.plugin_loader.load_all()
|
10
11
|
|
11
12
|
def get_plugin_names(self):
|
13
|
+
# Dizindeki tüm eklenti adlarını listeler ve sıralar
|
12
14
|
return sorted(list(self.plugins.keys()))
|
13
15
|
|
14
16
|
def select_plugin(self, plugin_name):
|
17
|
+
# Verilen eklenti adını kullanarak eklentiyi seç
|
15
18
|
return self.plugins.get(plugin_name)
|
16
19
|
|
17
20
|
async def close_plugins(self):
|
21
|
+
# Tüm eklentileri kapat
|
18
22
|
for plugin in self.plugins.values():
|
19
23
|
if isinstance(plugin, PluginBase):
|
20
24
|
await plugin.close()
|
KekikStream/__init__.py
CHANGED
@@ -7,6 +7,7 @@ from contextlib import suppress
|
|
7
7
|
|
8
8
|
class KekikStream:
|
9
9
|
def __init__(self):
|
10
|
+
# Yönetici sınıflarını başlat
|
10
11
|
self.eklentiler_yonetici = PluginManager()
|
11
12
|
self.cikaricilar_yonetici = ExtractorManager()
|
12
13
|
self.arayuz_yonetici = UIManager()
|
@@ -14,17 +15,22 @@ class KekikStream:
|
|
14
15
|
self.suanki_eklenti: PluginBase = None
|
15
16
|
|
16
17
|
async def baslat(self):
|
18
|
+
# Konsolu temizle ve başlık göster
|
17
19
|
self.arayuz_yonetici.clear_console()
|
18
20
|
konsol.rule("[bold cyan]KekikStream Başlatılıyor[/bold cyan]")
|
21
|
+
|
22
|
+
# Eklenti kontrolü
|
19
23
|
if not self.eklentiler_yonetici.get_plugin_names():
|
20
24
|
return konsol.print("[bold red]Hiçbir eklenti bulunamadı![/bold red]")
|
21
25
|
|
22
26
|
try:
|
23
27
|
await self.eklenti_secimi()
|
24
28
|
finally:
|
29
|
+
# Program kapanırken tüm eklentileri kapat
|
25
30
|
await self.eklentiler_yonetici.close_plugins()
|
26
31
|
|
27
32
|
async def sonuc_bulunamadi(self):
|
33
|
+
# Sonuç bulunamadığında kullanıcıya seçenekler sun
|
28
34
|
secim = await self.arayuz_yonetici.select_from_list(
|
29
35
|
message = "Ne yapmak istersiniz?",
|
30
36
|
choices = ["Tüm Eklentilerde Ara", "Ana Menü", "Çıkış"]
|
@@ -39,6 +45,7 @@ class KekikStream:
|
|
39
45
|
cikis_yap(False)
|
40
46
|
|
41
47
|
async def eklenti_secimi(self):
|
48
|
+
# Fuzzy ile eklenti seçimi yap
|
42
49
|
eklenti_adi = await self.arayuz_yonetici.select_from_fuzzy(
|
43
50
|
message = "Arama yapılacak eklentiyi seçin:",
|
44
51
|
choices = ["Tüm Eklentilerde Ara", *self.eklentiler_yonetici.get_plugin_names()]
|
@@ -51,9 +58,11 @@ class KekikStream:
|
|
51
58
|
await self.eklenti_ile_arama()
|
52
59
|
|
53
60
|
async def eklenti_ile_arama(self):
|
61
|
+
# Seçilen eklentide arama yap
|
54
62
|
self.arayuz_yonetici.clear_console()
|
55
63
|
konsol.rule(f"[bold cyan]{self.suanki_eklenti.name} Eklentisinde Arama Yapın[/bold cyan]")
|
56
64
|
|
65
|
+
# Kullanıcıdan sorgu al ve ara
|
57
66
|
sorgu = await self.arayuz_yonetici.prompt_text("Arama sorgusu girin:")
|
58
67
|
sonuclar = await self.suanki_eklenti.search(sorgu)
|
59
68
|
|
@@ -65,12 +74,14 @@ class KekikStream:
|
|
65
74
|
await self.sonuc_detaylari_goster({"plugin": self.suanki_eklenti.name, "url": secilen_sonuc})
|
66
75
|
|
67
76
|
async def eklenti_sonuc_secimi(self, sonuclar):
|
77
|
+
# Arama sonuçlarından birini seç
|
68
78
|
return await self.arayuz_yonetici.select_from_fuzzy(
|
69
79
|
message = "İçerik sonuçlarından birini seçin:",
|
70
80
|
choices = [{"name": sonuc.title, "value": sonuc.url} for sonuc in sonuclar]
|
71
81
|
)
|
72
82
|
|
73
83
|
async def tum_eklentilerde_arama(self):
|
84
|
+
# Tüm eklentilerde arama yap
|
74
85
|
self.arayuz_yonetici.clear_console()
|
75
86
|
konsol.rule("[bold cyan]Tüm Eklentilerde Arama Yapın[/bold cyan]")
|
76
87
|
|
@@ -88,7 +99,9 @@ class KekikStream:
|
|
88
99
|
async def tum_eklentilerde_arama_sorgula(self, sorgu: str) -> list:
|
89
100
|
tum_sonuclar = []
|
90
101
|
|
102
|
+
# Her eklentide arama yap
|
91
103
|
for eklenti_adi, eklenti in self.eklentiler_yonetici.plugins.items():
|
104
|
+
# Eklenti türü kontrolü
|
92
105
|
if not isinstance(eklenti, PluginBase):
|
93
106
|
konsol.print(f"[yellow][!] {eklenti_adi} geçerli bir PluginBase değil, atlanıyor...[/yellow]")
|
94
107
|
continue
|
@@ -97,6 +110,7 @@ class KekikStream:
|
|
97
110
|
try:
|
98
111
|
sonuclar = await eklenti.search(sorgu)
|
99
112
|
if sonuclar:
|
113
|
+
# Sonuçları listeye ekle
|
100
114
|
tum_sonuclar.extend(
|
101
115
|
[{"plugin": eklenti_adi, "title": sonuc.title, "url": sonuc.url, "poster": sonuc.poster} for sonuc in sonuclar]
|
102
116
|
)
|
@@ -111,6 +125,7 @@ class KekikStream:
|
|
111
125
|
return tum_sonuclar
|
112
126
|
|
113
127
|
async def tum_sonuc_secimi(self, sonuclar):
|
128
|
+
# Tüm sonuçlardan birini seç
|
114
129
|
secenekler = [
|
115
130
|
{"name": f"[{sonuc['plugin']}]".ljust(21) + f" » {sonuc['title']}", "value": sonuc}
|
116
131
|
for sonuc in sonuclar
|
@@ -123,6 +138,7 @@ class KekikStream:
|
|
123
138
|
|
124
139
|
async def sonuc_detaylari_goster(self, secilen_sonuc):
|
125
140
|
try:
|
141
|
+
# Seçilen sonucun detaylarını al
|
126
142
|
if isinstance(secilen_sonuc, dict) and "plugin" in secilen_sonuc:
|
127
143
|
eklenti_adi = secilen_sonuc["plugin"]
|
128
144
|
url = secilen_sonuc["url"]
|
@@ -131,6 +147,7 @@ class KekikStream:
|
|
131
147
|
else:
|
132
148
|
url = secilen_sonuc
|
133
149
|
|
150
|
+
# Medya bilgilerini yükle (3 deneme hakkı)
|
134
151
|
medya_bilgi = None
|
135
152
|
for _ in range(3):
|
136
153
|
with suppress(Exception):
|
@@ -144,9 +161,11 @@ class KekikStream:
|
|
144
161
|
konsol.log(secilen_sonuc)
|
145
162
|
return hata_yakala(hata)
|
146
163
|
|
164
|
+
# Medya başlığını ayarla ve bilgileri göster
|
147
165
|
self.medya_yonetici.set_title(f"{self.suanki_eklenti.name} | {medya_bilgi.title}")
|
148
166
|
self.arayuz_yonetici.display_media_info(f"{self.suanki_eklenti.name} | {medya_bilgi.title}", medya_bilgi)
|
149
167
|
|
168
|
+
# Dizi ise bölüm seçimi yap
|
150
169
|
if isinstance(medya_bilgi, SeriesInfo):
|
151
170
|
secilen_bolum = await self.arayuz_yonetici.select_from_fuzzy(
|
152
171
|
message = "İzlemek istediğiniz bölümü seçin:",
|
@@ -167,15 +186,19 @@ class KekikStream:
|
|
167
186
|
konsol.print("[bold red]Hiçbir bağlantı bulunamadı![/bold red]")
|
168
187
|
return await self.sonuc_bulunamadi()
|
169
188
|
|
189
|
+
# Bağlantıları çıkarıcılarla eşleştir
|
170
190
|
haritalama = self.cikaricilar_yonetici.map_links_to_extractors(baglantilar)
|
171
191
|
play_fonksiyonu_var = hasattr(self.suanki_eklenti, "play") and callable(getattr(self.suanki_eklenti, "play", None))
|
172
192
|
# ! DEBUG
|
173
193
|
# konsol.print(baglantilar)
|
194
|
+
|
195
|
+
# Uygun çıkarıcı kontrolü
|
174
196
|
if not haritalama and not play_fonksiyonu_var:
|
175
197
|
konsol.print("[bold red]Hiçbir Extractor bulunamadı![/bold red]")
|
176
198
|
konsol.print(baglantilar)
|
177
199
|
return await self.sonuc_bulunamadi()
|
178
200
|
|
201
|
+
# Doğrudan oynatma seçeneği
|
179
202
|
if not haritalama:
|
180
203
|
secilen_link = await self.arayuz_yonetici.select_from_list(
|
181
204
|
message = "Doğrudan oynatmak için bir bağlantı seçin:",
|
@@ -185,6 +208,7 @@ class KekikStream:
|
|
185
208
|
await self.medya_oynat(secilen_link)
|
186
209
|
return
|
187
210
|
|
211
|
+
# Kullanıcı seçenekleri
|
188
212
|
secim = await self.arayuz_yonetici.select_from_list(
|
189
213
|
message = "Ne yapmak istersiniz?",
|
190
214
|
choices = ["İzle", "Tüm Eklentilerde Ara", "Ana Menü"]
|
@@ -206,6 +230,7 @@ class KekikStream:
|
|
206
230
|
await self.baslat()
|
207
231
|
|
208
232
|
async def medya_oynat(self, secilen_link):
|
233
|
+
# Eklentinin kendi oynatıcısı varsa onu kullan
|
209
234
|
if hasattr(self.suanki_eklenti, "play") and callable(self.suanki_eklenti.play):
|
210
235
|
konsol.log(f"[yellow][»] Oynatılıyor : {secilen_link}")
|
211
236
|
return await self.suanki_eklenti.play(
|
@@ -215,16 +240,19 @@ class KekikStream:
|
|
215
240
|
subtitles = self.suanki_eklenti._data[secilen_link]["subtitles"]
|
216
241
|
)
|
217
242
|
|
243
|
+
# Uygun çıkarıcıyı bul
|
218
244
|
cikarici: ExtractorBase = self.cikaricilar_yonetici.find_extractor(secilen_link)
|
219
245
|
if not cikarici:
|
220
246
|
return konsol.print("[bold red]Uygun Extractor bulunamadı.[/bold red]")
|
221
247
|
|
222
248
|
try:
|
249
|
+
# Medya bilgilerini çıkar
|
223
250
|
extract_data = await cikarici.extract(secilen_link, referer=self.suanki_eklenti.main_url)
|
224
251
|
except Exception as hata:
|
225
252
|
konsol.print(f"[bold red]{cikarici.name} » hata oluştu: {hata}[/bold red]")
|
226
253
|
return await self.sonuc_bulunamadi()
|
227
254
|
|
255
|
+
# Birden fazla bağlantı varsa seçim yap
|
228
256
|
if isinstance(extract_data, list):
|
229
257
|
secilen_data = await self.arayuz_yonetici.select_from_list(
|
230
258
|
message = "Birden fazla bağlantı bulundu, lütfen birini seçin:",
|
@@ -233,9 +261,11 @@ class KekikStream:
|
|
233
261
|
else:
|
234
262
|
secilen_data = extract_data
|
235
263
|
|
264
|
+
# Cookie varsa ayarla
|
236
265
|
if secilen_data.headers.get("Cookie"):
|
237
266
|
self.medya_yonetici.set_headers({"Cookie": secilen_data.headers.get("Cookie")})
|
238
267
|
|
268
|
+
# Başlık ve referrer ayarla
|
239
269
|
self.medya_yonetici.set_title(f"{self.medya_yonetici.get_title()} | {secilen_data.name}")
|
240
270
|
self.medya_yonetici.set_headers({"Referer": secilen_data.referer})
|
241
271
|
konsol.log(f"[yellow][»] Oynatılıyor : {secilen_data.url}")
|
@@ -243,8 +273,10 @@ class KekikStream:
|
|
243
273
|
|
244
274
|
def basla():
|
245
275
|
try:
|
276
|
+
# PyPI güncellemelerini kontrol et
|
246
277
|
pypi_kontrol_guncelle("KekikStream")
|
247
278
|
|
279
|
+
# Uygulamayı başlat
|
248
280
|
app = KekikStream()
|
249
281
|
run(app.baslat())
|
250
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,18 +1,18 @@
|
|
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
6
|
KekikStream/Core/__init__.py,sha256=2N0VFP4QsyDWn4pV77JX_5_XachD5qKzhuDor3klj58,657
|
7
|
-
KekikStream/Core/Extractor/ExtractorBase.py,sha256=
|
8
|
-
KekikStream/Core/Extractor/ExtractorLoader.py,sha256=
|
9
|
-
KekikStream/Core/Extractor/ExtractorManager.py,sha256=
|
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
10
|
KekikStream/Core/Extractor/ExtractorModels.py,sha256=huIcPQ5VIRfMx0LcL5SS1u4dldZbHjzHKEdSEtOPlc0,456
|
11
|
-
KekikStream/Core/Media/MediaHandler.py,sha256
|
11
|
+
KekikStream/Core/Media/MediaHandler.py,sha256=-yVOnI5pNKWgvrRgJ8DVKjvTWuHTwUC7JSKlKa06lSw,6179
|
12
12
|
KekikStream/Core/Media/MediaManager.py,sha256=9ItiUguOkk3wg3YY5uf3mrjfwLPCvggnP8QviX0uiuE,526
|
13
13
|
KekikStream/Core/Plugin/PluginBase.py,sha256=KuR89bkrChPAct4-PMjxbK4i6busXMMFeZjv-x4F1CQ,2521
|
14
|
-
KekikStream/Core/Plugin/PluginLoader.py,sha256=
|
15
|
-
KekikStream/Core/Plugin/PluginManager.py,sha256=
|
14
|
+
KekikStream/Core/Plugin/PluginLoader.py,sha256=2UM3gNcEgd7k-FxG-JB5nTIS0K_clzvFtzGjMA_Sx7Q,3379
|
15
|
+
KekikStream/Core/Plugin/PluginManager.py,sha256=CZVg1eegi8vfMfccx0DRV0Box8kXz-aoULTQLgbPbvM,893
|
16
16
|
KekikStream/Core/Plugin/PluginModels.py,sha256=q8tjkt_-uiJ7uNxOThYR0FgTQLZglVAOAaM0Kske-28,2063
|
17
17
|
KekikStream/Core/UI/UIManager.py,sha256=T4V_kdTTWa-UDamgLSKa__dWJuzcvRK9NuwBlzU9Bzc,1693
|
18
18
|
KekikStream/Extractors/CloseLoad.py,sha256=YmDB3YvuDaCUbQ0T_tmhnkEsC5mSdEN6GNoAR662fl8,990
|
@@ -50,9 +50,9 @@ KekikStream/Plugins/RecTV.py,sha256=Pt2IQ2jLsQp7Mo85uM_ml3nxOR0uirX7vXOnE10CPm0,
|
|
50
50
|
KekikStream/Plugins/SezonlukDizi.py,sha256=5BZVzQ2eQtymHxO0bzjA2ho4FFNahPFQly4hoHuH8lo,4441
|
51
51
|
KekikStream/Plugins/SineWix.py,sha256=VvFeAS2-Y-KJ1Od16yZjUJLiESwsBBGb2GNG3BLLupU,4806
|
52
52
|
KekikStream/Plugins/UgurFilm.py,sha256=yYXee5uxwNnPqFJZ6s6cRkmUyqS3Vv8x-iesPalc4j4,2930
|
53
|
-
KekikStream-0.8.
|
54
|
-
KekikStream-0.8.
|
55
|
-
KekikStream-0.8.
|
56
|
-
KekikStream-0.8.
|
57
|
-
KekikStream-0.8.
|
58
|
-
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,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|