KekikStream 0.8.1__py3-none-any.whl → 0.8.3__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of KekikStream might be problematic. Click here for more details.
- 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/Plugins/JetFilmizle.py +1 -1
- KekikStream/__init__.py +32 -0
- {KekikStream-0.8.1.dist-info → KekikStream-0.8.3.dist-info}/METADATA +1 -1
- {KekikStream-0.8.1.dist-info → KekikStream-0.8.3.dist-info}/RECORD +14 -14
- {KekikStream-0.8.1.dist-info → KekikStream-0.8.3.dist-info}/LICENSE +0 -0
- {KekikStream-0.8.1.dist-info → KekikStream-0.8.3.dist-info}/WHEEL +0 -0
- {KekikStream-0.8.1.dist-info → KekikStream-0.8.3.dist-info}/entry_points.txt +0 -0
- {KekikStream-0.8.1.dist-info → KekikStream-0.8.3.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.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
|
@@ -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
|
@@ -45,14 +45,14 @@ KekikStream/Plugins/DiziYou.py,sha256=kpRY3U6lqaZKgn9ED2TprwU7qfLxuC2ZZmrRemegry
|
|
45
45
|
KekikStream/Plugins/Dizilla.py,sha256=evWYvETw1c4RY0GB5P20cB_I_U7ZxzzvnG7RLNGJRPs,4258
|
46
46
|
KekikStream/Plugins/FilmMakinesi.py,sha256=rz8TQeL41PJbeEmksgPHIhp6J-4vbSCBTeEH0ukExz4,2822
|
47
47
|
KekikStream/Plugins/FullHDFilmizlesene.py,sha256=Fa0gRP_NoMfPC8HIKRxERjQVOv8Fyb-ayMJ2EooZ7BE,3080
|
48
|
-
KekikStream/Plugins/JetFilmizle.py,sha256=
|
48
|
+
KekikStream/Plugins/JetFilmizle.py,sha256=Gu4Ums-88x7jNKAtKkdSXyMaOyLv0_Kb6jnomhAWhM0,3916
|
49
49
|
KekikStream/Plugins/RecTV.py,sha256=Pt2IQ2jLsQp7Mo85uM_ml3nxOR0uirX7vXOnE10CPm0,4886
|
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.3.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
54
|
+
KekikStream-0.8.3.dist-info/METADATA,sha256=CxKT0vhQw9uT534rpw-W2LZPZ1ElsWAFyDIv0rrMcHE,4226
|
55
|
+
KekikStream-0.8.3.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
56
|
+
KekikStream-0.8.3.dist-info/entry_points.txt,sha256=dFwdiTx8djyehI0Gsz-rZwjAfZzUzoBSrmzRu9ubjJc,50
|
57
|
+
KekikStream-0.8.3.dist-info/top_level.txt,sha256=DNmGJDXl27Drdfobrak8KYLmocW_uznVYFJOzcjUgmY,12
|
58
|
+
KekikStream-0.8.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|