KekikStream 0.8.0__tar.gz → 0.8.2__tar.gz
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-0.8.0/KekikStream/Core → kekikstream-0.8.2/KekikStream/Core/Extractor}/ExtractorBase.py +8 -2
- {kekikstream-0.8.0/KekikStream/Core → kekikstream-0.8.2/KekikStream/Core/Extractor}/ExtractorLoader.py +18 -11
- {kekikstream-0.8.0/KekikStream/Managers → kekikstream-0.8.2/KekikStream/Core/Extractor}/ExtractorManager.py +7 -3
- {kekikstream-0.8.0/KekikStream/Core → kekikstream-0.8.2/KekikStream/Core/Media}/MediaHandler.py +6 -2
- {kekikstream-0.8.0/KekikStream/Managers → kekikstream-0.8.2/KekikStream/Core/Media}/MediaManager.py +1 -1
- {kekikstream-0.8.0/KekikStream/Core → kekikstream-0.8.2/KekikStream/Core/Plugin}/PluginBase.py +6 -6
- {kekikstream-0.8.0/KekikStream/Core → kekikstream-0.8.2/KekikStream/Core/Plugin}/PluginLoader.py +22 -8
- {kekikstream-0.8.0/KekikStream/Managers → kekikstream-0.8.2/KekikStream/Core/Plugin}/PluginManager.py +6 -1
- {kekikstream-0.8.0/KekikStream/Managers → kekikstream-0.8.2/KekikStream/Core/UI}/UIManager.py +1 -1
- kekikstream-0.8.2/KekikStream/Core/__init__.py +16 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Plugins/RecTV.py +4 -5
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Plugins/SineWix.py +1 -2
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/__init__.py +33 -2
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream.egg-info/PKG-INFO +1 -1
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream.egg-info/SOURCES.txt +11 -12
- {kekikstream-0.8.0 → kekikstream-0.8.2}/PKG-INFO +1 -1
- {kekikstream-0.8.0 → kekikstream-0.8.2}/setup.py +1 -1
- kekikstream-0.8.0/KekikStream/Core/__init__.py +0 -9
- kekikstream-0.8.0/KekikStream/Managers/__init__.py +0 -6
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/CLI/__init__.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/CLI/pypi_kontrol.py +0 -0
- {kekikstream-0.8.0/KekikStream/Core → kekikstream-0.8.2/KekikStream/Core/Extractor}/ExtractorModels.py +0 -0
- {kekikstream-0.8.0/KekikStream/Core → kekikstream-0.8.2/KekikStream/Core/Plugin}/PluginModels.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/CloseLoad.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/ContentX.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/FourCX.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/FourPichive.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/FourPlayRu.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/HDStreamAble.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/Hotlinger.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/MailRu.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/MixPlayHD.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/Odnoklassniki.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/OkRuHTTP.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/OkRuSSL.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/PeaceMakerst.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/Pichive.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/PixelDrain.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/PlayRu.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/RapidVid.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/SibNet.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/Sobreatsesuyp.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/TRsTX.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/TauVideo.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/TurboImgz.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/VidMoly.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/VidMoxy.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Extractors/VideoSeyred.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Plugins/DiziBox.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Plugins/DiziYou.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Plugins/Dizilla.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Plugins/FilmMakinesi.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Plugins/FullHDFilmizlesene.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Plugins/JetFilmizle.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Plugins/SezonlukDizi.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/Plugins/UgurFilm.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/__main__.py +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream/requirements.txt +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream.egg-info/dependency_links.txt +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream.egg-info/entry_points.txt +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream.egg-info/requires.txt +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/KekikStream.egg-info/top_level.txt +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/LICENSE +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/MANIFEST.in +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/README.md +0 -0
- {kekikstream-0.8.0 → kekikstream-0.8.2}/setup.cfg +0 -0
{kekikstream-0.8.0/KekikStream/Core → kekikstream-0.8.2/KekikStream/Core/Extractor}/ExtractorBase.py
RENAMED
@@ -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:
|
{kekikstream-0.8.0/KekikStream/Core → kekikstream-0.8.2/KekikStream/Core/Media}/MediaHandler.py
RENAMED
@@ -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
|
|
{kekikstream-0.8.0/KekikStream/Core → kekikstream-0.8.2/KekikStream/Core/Plugin}/PluginBase.py
RENAMED
@@ -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):
|
{kekikstream-0.8.0/KekikStream/Core → kekikstream-0.8.2/KekikStream/Core/Plugin}/PluginLoader.py
RENAMED
@@ -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()
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
|
+
|
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
|
@@ -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
|
|
@@ -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"
|
@@ -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
|
@@ -13,14 +13,18 @@ KekikStream.egg-info/requires.txt
|
|
13
13
|
KekikStream.egg-info/top_level.txt
|
14
14
|
KekikStream/CLI/__init__.py
|
15
15
|
KekikStream/CLI/pypi_kontrol.py
|
16
|
-
KekikStream/Core/ExtractorBase.py
|
17
|
-
KekikStream/Core/ExtractorLoader.py
|
18
|
-
KekikStream/Core/ExtractorModels.py
|
19
|
-
KekikStream/Core/MediaHandler.py
|
20
|
-
KekikStream/Core/PluginBase.py
|
21
|
-
KekikStream/Core/PluginLoader.py
|
22
|
-
KekikStream/Core/PluginModels.py
|
23
16
|
KekikStream/Core/__init__.py
|
17
|
+
KekikStream/Core/Extractor/ExtractorBase.py
|
18
|
+
KekikStream/Core/Extractor/ExtractorLoader.py
|
19
|
+
KekikStream/Core/Extractor/ExtractorManager.py
|
20
|
+
KekikStream/Core/Extractor/ExtractorModels.py
|
21
|
+
KekikStream/Core/Media/MediaHandler.py
|
22
|
+
KekikStream/Core/Media/MediaManager.py
|
23
|
+
KekikStream/Core/Plugin/PluginBase.py
|
24
|
+
KekikStream/Core/Plugin/PluginLoader.py
|
25
|
+
KekikStream/Core/Plugin/PluginManager.py
|
26
|
+
KekikStream/Core/Plugin/PluginModels.py
|
27
|
+
KekikStream/Core/UI/UIManager.py
|
24
28
|
KekikStream/Extractors/CloseLoad.py
|
25
29
|
KekikStream/Extractors/ContentX.py
|
26
30
|
KekikStream/Extractors/FourCX.py
|
@@ -46,11 +50,6 @@ KekikStream/Extractors/TurboImgz.py
|
|
46
50
|
KekikStream/Extractors/VidMoly.py
|
47
51
|
KekikStream/Extractors/VidMoxy.py
|
48
52
|
KekikStream/Extractors/VideoSeyred.py
|
49
|
-
KekikStream/Managers/ExtractorManager.py
|
50
|
-
KekikStream/Managers/MediaManager.py
|
51
|
-
KekikStream/Managers/PluginManager.py
|
52
|
-
KekikStream/Managers/UIManager.py
|
53
|
-
KekikStream/Managers/__init__.py
|
54
53
|
KekikStream/Plugins/DiziBox.py
|
55
54
|
KekikStream/Plugins/DiziYou.py
|
56
55
|
KekikStream/Plugins/Dizilla.py
|
@@ -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
|
@@ -6,7 +6,7 @@ from io import open
|
|
6
6
|
setup(
|
7
7
|
# ? Genel Bilgiler
|
8
8
|
name = "KekikStream",
|
9
|
-
version = "0.8.
|
9
|
+
version = "0.8.2",
|
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,9 +0,0 @@
|
|
1
|
-
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
2
|
-
|
3
|
-
from .PluginBase import PluginBase
|
4
|
-
from .PluginLoader import PluginLoader
|
5
|
-
from .PluginModels import SearchResult, MovieInfo, Episode, SeriesInfo
|
6
|
-
from .ExtractorBase import ExtractorBase
|
7
|
-
from .ExtractorLoader import ExtractorLoader
|
8
|
-
from .ExtractorModels import ExtractResult, Subtitle
|
9
|
-
from .MediaHandler import MediaHandler
|
File without changes
|
File without changes
|
File without changes
|
{kekikstream-0.8.0/KekikStream/Core → kekikstream-0.8.2/KekikStream/Core/Plugin}/PluginModels.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|