KekikStream 1.8.9__tar.gz → 1.9.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kekikstream-1.9.3/KekikStream/Core/Extractor/ExtractorManager.py +52 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Core/Media/MediaHandler.py +5 -58
- kekikstream-1.9.3/KekikStream/Extractors/YTDLP.py +172 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream.egg-info/PKG-INFO +13 -20
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream.egg-info/SOURCES.txt +1 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/PKG-INFO +13 -20
- {kekikstream-1.8.9 → kekikstream-1.9.3}/README.md +12 -19
- {kekikstream-1.8.9 → kekikstream-1.9.3}/setup.py +1 -1
- kekikstream-1.8.9/KekikStream/Core/Extractor/ExtractorManager.py +0 -31
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/CLI/__init__.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/CLI/pypi_kontrol.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Core/Extractor/ExtractorBase.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Core/Extractor/ExtractorLoader.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Core/Extractor/ExtractorModels.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Core/Media/MediaManager.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Core/Plugin/PluginBase.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Core/Plugin/PluginLoader.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Core/Plugin/PluginManager.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Core/Plugin/PluginModels.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Core/UI/UIManager.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Core/__init__.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/CloseLoad.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/ContentX.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/DzenRu.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/ExPlay.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/FirePlayer.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/FourCX.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/FourPichive.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/FourPlayRu.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/HDPlayerSystem.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/HDStreamAble.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/Hotlinger.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/JetTv.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/MailRu.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/MixPlayHD.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/MixTiger.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/MolyStream.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/Odnoklassniki.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/OkRuHTTP.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/OkRuSSL.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/PeaceMakerst.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/Pichive.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/PixelDrain.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/PlayRu.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/PlayerFilmIzle.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/RapidVid.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/SetPlay.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/SetPrime.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/SibNet.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/Sobreatsesuyp.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/TRsTX.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/TauVideo.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/TurboImgz.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/TurkeyPlayer.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/VidHide.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/VidMoly.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/VidMolyMe.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/VidMoxy.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/VidPapi.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/VideoSeyred.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Extractors/YildizKisaFilm.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/DiziBox.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/DiziPal.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/DiziYou.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/Dizilla.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/FilmBip.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/FilmMakinesi.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/FilmModu.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/FullHDFilm.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/FullHDFilmizlesene.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/HDFilmCehennemi.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/JetFilmizle.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/KultFilmler.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/RecTV.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/RoketDizi.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/SelcukFlix.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/SezonlukDizi.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/SineWix.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/Sinefy.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/SinemaCX.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/Sinezy.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/SuperFilmGeldi.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/Plugins/UgurFilm.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/__init__.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/__main__.py +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream/requirements.txt +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream.egg-info/dependency_links.txt +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream.egg-info/entry_points.txt +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream.egg-info/requires.txt +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/KekikStream.egg-info/top_level.txt +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/LICENSE +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/MANIFEST.in +0 -0
- {kekikstream-1.8.9 → kekikstream-1.9.3}/setup.cfg +0 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from .ExtractorLoader import ExtractorLoader
|
|
4
|
+
from .ExtractorBase import ExtractorBase
|
|
5
|
+
|
|
6
|
+
class ExtractorManager:
|
|
7
|
+
def __init__(self, extractor_dir="Extractors"):
|
|
8
|
+
# Çıkarıcı yükleyiciyi başlat ve tüm çıkarıcıları yükle
|
|
9
|
+
self.extractor_loader = ExtractorLoader(extractor_dir)
|
|
10
|
+
self.extractors = self.extractor_loader.load_all()
|
|
11
|
+
|
|
12
|
+
# Extractor instance'larını cache'le
|
|
13
|
+
self._extractor_instances = []
|
|
14
|
+
self._ytdlp_extractor = None
|
|
15
|
+
|
|
16
|
+
for extractor_cls in self.extractors:
|
|
17
|
+
instance = extractor_cls()
|
|
18
|
+
|
|
19
|
+
# YTDLP'yi ayrı tut
|
|
20
|
+
if instance.name == "yt-dlp":
|
|
21
|
+
self._ytdlp_extractor = instance
|
|
22
|
+
else:
|
|
23
|
+
self._extractor_instances.append(instance)
|
|
24
|
+
|
|
25
|
+
# YTDLP'yi EN BAŞA ekle
|
|
26
|
+
if self._ytdlp_extractor:
|
|
27
|
+
self._extractor_instances.insert(0, self._ytdlp_extractor)
|
|
28
|
+
|
|
29
|
+
def find_extractor(self, link) -> ExtractorBase:
|
|
30
|
+
"""
|
|
31
|
+
Verilen bağlantıyı işleyebilecek çıkarıcıyı bul
|
|
32
|
+
"""
|
|
33
|
+
# Cached instance'ları kullan
|
|
34
|
+
for extractor in self._extractor_instances:
|
|
35
|
+
if extractor.can_handle_url(link):
|
|
36
|
+
return extractor
|
|
37
|
+
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
def map_links_to_extractors(self, links) -> dict:
|
|
41
|
+
"""
|
|
42
|
+
Bağlantıları uygun çıkarıcılarla eşleştir
|
|
43
|
+
"""
|
|
44
|
+
mapping = {}
|
|
45
|
+
for link in links:
|
|
46
|
+
# Cached instance'ları kullan
|
|
47
|
+
for extractor in self._extractor_instances:
|
|
48
|
+
if extractor.can_handle_url(link):
|
|
49
|
+
mapping[link] = f"{extractor.name:<30} » {link.replace(extractor.main_url, '')}"
|
|
50
|
+
break # İlk eşleşmede dur
|
|
51
|
+
|
|
52
|
+
return mapping
|
|
@@ -2,62 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
from ...CLI import konsol
|
|
4
4
|
from ..Extractor.ExtractorModels import ExtractResult
|
|
5
|
-
import subprocess, os
|
|
5
|
+
import subprocess, os
|
|
6
6
|
|
|
7
7
|
class MediaHandler:
|
|
8
8
|
def __init__(self, title: str = "KekikStream"):
|
|
9
9
|
self.title = title
|
|
10
10
|
self.headers = {}
|
|
11
11
|
|
|
12
|
-
def should_use_ytdlp(self, url: str, user_agent: str) -> bool:
|
|
13
|
-
"""
|
|
14
|
-
yt-dlp gereken durumları profesyonel şekilde tespit et
|
|
15
|
-
|
|
16
|
-
yt-dlp'nin native Python API'sini simulate mode ile kullanarak
|
|
17
|
-
güvenilir ve performanslı tespit yapar.
|
|
18
|
-
|
|
19
|
-
Args:
|
|
20
|
-
url: Video URL'si
|
|
21
|
-
user_agent: User-Agent string'i
|
|
22
|
-
|
|
23
|
-
Returns:
|
|
24
|
-
bool: yt-dlp kullanılması gerekiyorsa True
|
|
25
|
-
"""
|
|
26
|
-
# 1. User-Agent bazlı kontrol (mevcut davranışı koru - RecTV, MolyStream için)
|
|
27
|
-
ytdlp_user_agents = [
|
|
28
|
-
"googleusercontent",
|
|
29
|
-
"Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0"
|
|
30
|
-
]
|
|
31
|
-
|
|
32
|
-
if user_agent in ytdlp_user_agents:
|
|
33
|
-
konsol.log("[cyan][ℹ] User-Agent bazlı yt-dlp tespiti[/cyan]")
|
|
34
|
-
return True
|
|
35
|
-
|
|
36
|
-
# 2. yt-dlp'nin native Python API'sini kullan (simulate mode)
|
|
37
|
-
try:
|
|
38
|
-
ydl_opts = {
|
|
39
|
-
"simulate" : True, # Download yok, sadece tespit
|
|
40
|
-
"quiet" : True, # Log kirliliği yok
|
|
41
|
-
"no_warnings" : True, # Uyarı mesajları yok
|
|
42
|
-
"extract_flat" : True # Minimal işlem
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
|
46
|
-
# URL'yi işleyebiliyor mu kontrol et
|
|
47
|
-
info = ydl.extract_info(url, download=False, process=False)
|
|
48
|
-
|
|
49
|
-
# Generic extractor ise atla
|
|
50
|
-
if info and info.get("extractor_key") != "Generic":
|
|
51
|
-
konsol.log(f"[cyan][ℹ] yt-dlp extractor: {info.get('extractor_key', 'Unknown')}[/cyan]")
|
|
52
|
-
return True
|
|
53
|
-
|
|
54
|
-
return False
|
|
55
|
-
|
|
56
|
-
except Exception as e:
|
|
57
|
-
# yt-dlp işleyemezse False döndür
|
|
58
|
-
konsol.log(f"[yellow][⚠] yt-dlp kontrol hatası: {e}[/yellow]")
|
|
59
|
-
return False
|
|
60
|
-
|
|
61
12
|
def play_media(self, extract_data: ExtractResult):
|
|
62
13
|
# user-agent ekle (varsayılan veya extract_data'dan)
|
|
63
14
|
user_agent = extract_data.user_agent or "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5)"
|
|
@@ -67,18 +18,14 @@ class MediaHandler:
|
|
|
67
18
|
if extract_data.referer:
|
|
68
19
|
self.headers["referer"] = extract_data.referer
|
|
69
20
|
|
|
21
|
+
# Özel Durumlar (RecTV vs. Googleusercontent)
|
|
22
|
+
if user_agent in ["googleusercontent", "Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0"]:
|
|
23
|
+
return self.play_with_ytdlp(extract_data)
|
|
24
|
+
|
|
70
25
|
# İşletim sistemine göre oynatıcı seç (Android durumu)
|
|
71
26
|
if subprocess.check_output(['uname', '-o']).strip() == b'Android':
|
|
72
27
|
return self.play_with_android_mxplayer(extract_data)
|
|
73
28
|
|
|
74
|
-
# Akıllı yt-dlp tespiti
|
|
75
|
-
if self.should_use_ytdlp(extract_data.url, user_agent):
|
|
76
|
-
konsol.log("[green][✓] yt-dlp kullanılacak[/green]")
|
|
77
|
-
success = self.play_with_ytdlp(extract_data)
|
|
78
|
-
if success:
|
|
79
|
-
return True
|
|
80
|
-
konsol.log("[yellow][⚠] yt-dlp başarısız, standart oynatıcılar deneniyor...[/yellow]")
|
|
81
|
-
|
|
82
29
|
# Oynatıcı öncelik sırası (fallback zincirleme)
|
|
83
30
|
players = [
|
|
84
31
|
("MPV", self.play_with_mpv),
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
|
|
4
|
+
from urllib.parse import urlparse
|
|
5
|
+
from yt_dlp.extractor import gen_extractors
|
|
6
|
+
import yt_dlp, re, sys, os
|
|
7
|
+
|
|
8
|
+
class YTDLP(ExtractorBase):
|
|
9
|
+
name = "yt-dlp"
|
|
10
|
+
main_url = "" # Universal - tüm siteleri destekler
|
|
11
|
+
|
|
12
|
+
_FAST_DOMAIN_RE = None # compiled mega-regex (host üstünden)
|
|
13
|
+
|
|
14
|
+
@classmethod
|
|
15
|
+
def _init_fast_domain_regex(cls):
|
|
16
|
+
if cls._FAST_DOMAIN_RE is not None:
|
|
17
|
+
return
|
|
18
|
+
|
|
19
|
+
domains = set()
|
|
20
|
+
|
|
21
|
+
# yt-dlp extractor'larının _VALID_URL regex'lerinden domain yakala
|
|
22
|
+
# Regex metinlerinde domainler genelde "\." şeklinde geçer.
|
|
23
|
+
domain_pat = re.compile(r"(?:[a-z0-9-]+\\\.)+[a-z]{2,}", re.IGNORECASE)
|
|
24
|
+
|
|
25
|
+
for ie in gen_extractors():
|
|
26
|
+
# Generic'i fast-path'e dahil etmiyoruz
|
|
27
|
+
if getattr(ie, "IE_NAME", "").lower() == "generic":
|
|
28
|
+
continue
|
|
29
|
+
|
|
30
|
+
valid = getattr(ie, "_VALID_URL", None)
|
|
31
|
+
if not valid or not isinstance(valid, str):
|
|
32
|
+
continue
|
|
33
|
+
|
|
34
|
+
for m in domain_pat.findall(valid):
|
|
35
|
+
d = m.replace(r"\.", ".").lower()
|
|
36
|
+
|
|
37
|
+
# Çok agresif/şüpheli şeyleri elemek istersen burada filtre koyabilirsin
|
|
38
|
+
# (genelde gerek kalmıyor)
|
|
39
|
+
domains.add(d)
|
|
40
|
+
|
|
41
|
+
# Hiç domain çıkmazsa (çok uç durum) fallback: boş regex
|
|
42
|
+
if not domains:
|
|
43
|
+
cls._FAST_DOMAIN_RE = re.compile(r"$^") # hiçbir şeye match etmez
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
# Host eşleştirmesi: subdomain destekli (m.youtube.com, player.vimeo.com vs.)
|
|
47
|
+
# (?:^|.*\.) (domain1|domain2|...) $
|
|
48
|
+
joined = "|".join(sorted(re.escape(d) for d in domains))
|
|
49
|
+
pattern = rf"(?:^|.*\.)(?:{joined})$"
|
|
50
|
+
cls._FAST_DOMAIN_RE = re.compile(pattern, re.IGNORECASE)
|
|
51
|
+
|
|
52
|
+
def __init__(self):
|
|
53
|
+
self.__class__._init_fast_domain_regex()
|
|
54
|
+
|
|
55
|
+
def can_handle_url(self, url: str) -> bool:
|
|
56
|
+
"""
|
|
57
|
+
Fast-path: URL host'unu tek mega-regex ile kontrol et (loop yok)
|
|
58
|
+
Slow-path: gerekirse mevcut extract_info tabanlı kontrolün
|
|
59
|
+
"""
|
|
60
|
+
# URL parse + host al
|
|
61
|
+
try:
|
|
62
|
+
parsed = urlparse(url)
|
|
63
|
+
host = (parsed.hostname or "").lower()
|
|
64
|
+
except Exception:
|
|
65
|
+
host = ""
|
|
66
|
+
|
|
67
|
+
# Şemasız URL desteği: "youtube.com/..." gibi
|
|
68
|
+
if not host and "://" not in url:
|
|
69
|
+
try:
|
|
70
|
+
parsed = urlparse("https://" + url)
|
|
71
|
+
host = (parsed.hostname or "").lower()
|
|
72
|
+
except Exception:
|
|
73
|
+
host = ""
|
|
74
|
+
|
|
75
|
+
# Fast-path
|
|
76
|
+
if host and self.__class__._FAST_DOMAIN_RE.search(host):
|
|
77
|
+
return True
|
|
78
|
+
|
|
79
|
+
# SLOW PATH: Diğer siteler için yt-dlp'nin native kontrolü
|
|
80
|
+
try:
|
|
81
|
+
# stderr'ı geçici olarak kapat (hata mesajlarını gizle)
|
|
82
|
+
old_stderr = sys.stderr
|
|
83
|
+
sys.stderr = open(os.devnull, "w")
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
ydl_opts = {
|
|
87
|
+
"simulate" : True, # Download yok, sadece tespit
|
|
88
|
+
"quiet" : True, # Log kirliliği yok
|
|
89
|
+
"no_warnings" : True, # Uyarı mesajları yok
|
|
90
|
+
"extract_flat" : True, # Minimal işlem
|
|
91
|
+
"no_check_certificates" : True,
|
|
92
|
+
"ignoreerrors" : True # Hataları yoksay
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
|
96
|
+
# URL'yi işleyebiliyor mu kontrol et
|
|
97
|
+
info = ydl.extract_info(url, download=False, process=False)
|
|
98
|
+
|
|
99
|
+
# Generic extractor ise atla
|
|
100
|
+
if info and info.get("extractor_key") != "Generic":
|
|
101
|
+
return True
|
|
102
|
+
|
|
103
|
+
return False
|
|
104
|
+
finally:
|
|
105
|
+
# stderr'ı geri yükle
|
|
106
|
+
sys.stderr.close()
|
|
107
|
+
sys.stderr = old_stderr
|
|
108
|
+
|
|
109
|
+
except Exception:
|
|
110
|
+
# yt-dlp işleyemezse False döndür
|
|
111
|
+
return False
|
|
112
|
+
|
|
113
|
+
async def extract(self, url: str, referer: str | None = None) -> ExtractResult:
|
|
114
|
+
ydl_opts = {
|
|
115
|
+
"quiet" : True,
|
|
116
|
+
"no_warnings" : True,
|
|
117
|
+
"extract_flat" : False, # Tam bilgi al
|
|
118
|
+
"format" : "best", # En iyi kalite
|
|
119
|
+
"no_check_certificates" : True
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# Referer varsa header olarak ekle
|
|
123
|
+
if referer:
|
|
124
|
+
ydl_opts["http_headers"] = {"Referer": referer}
|
|
125
|
+
|
|
126
|
+
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
|
127
|
+
info = ydl.extract_info(url, download=False)
|
|
128
|
+
|
|
129
|
+
if not info:
|
|
130
|
+
raise ValueError("yt-dlp video bilgisi döndürmedi")
|
|
131
|
+
|
|
132
|
+
# Video URL'sini al
|
|
133
|
+
video_url = info.get("url")
|
|
134
|
+
if not video_url:
|
|
135
|
+
# Bazen formatlar listesinde olabilir
|
|
136
|
+
formats = info.get("formats", [])
|
|
137
|
+
if formats:
|
|
138
|
+
video_url = formats[-1].get("url") # Son format (genellikle en iyi)
|
|
139
|
+
|
|
140
|
+
if not video_url:
|
|
141
|
+
raise ValueError("Video URL bulunamadı")
|
|
142
|
+
|
|
143
|
+
# Altyazıları çıkar
|
|
144
|
+
subtitles = []
|
|
145
|
+
if subtitle_data := info.get("subtitles"):
|
|
146
|
+
for lang, subs in subtitle_data.items():
|
|
147
|
+
for sub in subs:
|
|
148
|
+
if sub_url := sub.get("url"):
|
|
149
|
+
subtitles.append(
|
|
150
|
+
Subtitle(
|
|
151
|
+
name=f"{lang} ({sub.get('ext', 'unknown')})",
|
|
152
|
+
url=sub_url
|
|
153
|
+
)
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# User-Agent al
|
|
157
|
+
user_agent = None
|
|
158
|
+
http_headers = info.get("http_headers", {})
|
|
159
|
+
if http_headers:
|
|
160
|
+
user_agent = http_headers.get("User-Agent")
|
|
161
|
+
|
|
162
|
+
return ExtractResult(
|
|
163
|
+
name = self.name,
|
|
164
|
+
url = video_url,
|
|
165
|
+
referer = referer or info.get("webpage_url"),
|
|
166
|
+
user_agent = user_agent,
|
|
167
|
+
subtitles = subtitles
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
async def close(self):
|
|
171
|
+
"""yt-dlp için cleanup gerekmez"""
|
|
172
|
+
pass
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: KekikStream
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.9.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
|
|
@@ -92,13 +92,6 @@ pip install -U KekikStream
|
|
|
92
92
|
KekikStream
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
-
**Kütüphane (örnek arama):**
|
|
96
|
-
```python
|
|
97
|
-
from KekikStream import Manager
|
|
98
|
-
results = Manager().search("vikings")
|
|
99
|
-
print(results[0].title)
|
|
100
|
-
```
|
|
101
|
-
|
|
102
95
|
---
|
|
103
96
|
|
|
104
97
|
## ✨ Özellikler
|
|
@@ -139,11 +132,11 @@ class MyPlugin(PluginBase):
|
|
|
139
132
|
|
|
140
133
|
### 🎬 Oynatıcı Desteği
|
|
141
134
|
|
|
142
|
-
| Oynatıcı
|
|
143
|
-
|
|
144
|
-
| **
|
|
145
|
-
| **
|
|
146
|
-
| **MX Player** | Android
|
|
135
|
+
| Oynatıcı | Platform | Özellikler |
|
|
136
|
+
|---------------|----------|---------------------------|
|
|
137
|
+
| **MPV** | Desktop | Custom headers, subtitles |
|
|
138
|
+
| **VLC** | Desktop | Custom headers, subtitles |
|
|
139
|
+
| **MX Player** | Android | ADB üzerinden |
|
|
147
140
|
|
|
148
141
|
> Özel durumlar için (Google Drive vb.) arka planda otomatik olarak yt-dlp devreye girer.
|
|
149
142
|
|
|
@@ -175,8 +168,8 @@ graph TB
|
|
|
175
168
|
end
|
|
176
169
|
|
|
177
170
|
subgraph Players
|
|
178
|
-
VLC[🎥 VLC]
|
|
179
171
|
MPV[🎥 MPV]
|
|
172
|
+
VLC[🎥 VLC]
|
|
180
173
|
MX[🎥 MX Player]
|
|
181
174
|
end
|
|
182
175
|
|
|
@@ -246,13 +239,13 @@ KekikStream/
|
|
|
246
239
|
|
|
247
240
|
## 📊 Performans
|
|
248
241
|
|
|
249
|
-
| Metrik
|
|
250
|
-
|
|
251
|
-
| Plugin Sayısı
|
|
252
|
-
| Extractor Sayısı
|
|
242
|
+
| Metrik | Değer |
|
|
243
|
+
|----------------------|------------------|
|
|
244
|
+
| Plugin Sayısı | 20+ |
|
|
245
|
+
| Extractor Sayısı | 40+ |
|
|
253
246
|
| Desteklenen Platform | Desktop, Android |
|
|
254
|
-
| Async Arama
|
|
255
|
-
| Cache Desteği
|
|
247
|
+
| Async Arama | ✅ |
|
|
248
|
+
| Cache Desteği | ✅ |
|
|
256
249
|
|
|
257
250
|
---
|
|
258
251
|
|
|
@@ -64,6 +64,7 @@ KekikStream/Extractors/VidMolyMe.py
|
|
|
64
64
|
KekikStream/Extractors/VidMoxy.py
|
|
65
65
|
KekikStream/Extractors/VidPapi.py
|
|
66
66
|
KekikStream/Extractors/VideoSeyred.py
|
|
67
|
+
KekikStream/Extractors/YTDLP.py
|
|
67
68
|
KekikStream/Extractors/YildizKisaFilm.py
|
|
68
69
|
KekikStream/Plugins/DiziBox.py
|
|
69
70
|
KekikStream/Plugins/DiziPal.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: KekikStream
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.9.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
|
|
@@ -92,13 +92,6 @@ pip install -U KekikStream
|
|
|
92
92
|
KekikStream
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
-
**Kütüphane (örnek arama):**
|
|
96
|
-
```python
|
|
97
|
-
from KekikStream import Manager
|
|
98
|
-
results = Manager().search("vikings")
|
|
99
|
-
print(results[0].title)
|
|
100
|
-
```
|
|
101
|
-
|
|
102
95
|
---
|
|
103
96
|
|
|
104
97
|
## ✨ Özellikler
|
|
@@ -139,11 +132,11 @@ class MyPlugin(PluginBase):
|
|
|
139
132
|
|
|
140
133
|
### 🎬 Oynatıcı Desteği
|
|
141
134
|
|
|
142
|
-
| Oynatıcı
|
|
143
|
-
|
|
144
|
-
| **
|
|
145
|
-
| **
|
|
146
|
-
| **MX Player** | Android
|
|
135
|
+
| Oynatıcı | Platform | Özellikler |
|
|
136
|
+
|---------------|----------|---------------------------|
|
|
137
|
+
| **MPV** | Desktop | Custom headers, subtitles |
|
|
138
|
+
| **VLC** | Desktop | Custom headers, subtitles |
|
|
139
|
+
| **MX Player** | Android | ADB üzerinden |
|
|
147
140
|
|
|
148
141
|
> Özel durumlar için (Google Drive vb.) arka planda otomatik olarak yt-dlp devreye girer.
|
|
149
142
|
|
|
@@ -175,8 +168,8 @@ graph TB
|
|
|
175
168
|
end
|
|
176
169
|
|
|
177
170
|
subgraph Players
|
|
178
|
-
VLC[🎥 VLC]
|
|
179
171
|
MPV[🎥 MPV]
|
|
172
|
+
VLC[🎥 VLC]
|
|
180
173
|
MX[🎥 MX Player]
|
|
181
174
|
end
|
|
182
175
|
|
|
@@ -246,13 +239,13 @@ KekikStream/
|
|
|
246
239
|
|
|
247
240
|
## 📊 Performans
|
|
248
241
|
|
|
249
|
-
| Metrik
|
|
250
|
-
|
|
251
|
-
| Plugin Sayısı
|
|
252
|
-
| Extractor Sayısı
|
|
242
|
+
| Metrik | Değer |
|
|
243
|
+
|----------------------|------------------|
|
|
244
|
+
| Plugin Sayısı | 20+ |
|
|
245
|
+
| Extractor Sayısı | 40+ |
|
|
253
246
|
| Desteklenen Platform | Desktop, Android |
|
|
254
|
-
| Async Arama
|
|
255
|
-
| Cache Desteği
|
|
247
|
+
| Async Arama | ✅ |
|
|
248
|
+
| Cache Desteği | ✅ |
|
|
256
249
|
|
|
257
250
|
---
|
|
258
251
|
|
|
@@ -55,13 +55,6 @@ pip install -U KekikStream
|
|
|
55
55
|
KekikStream
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
**Kütüphane (örnek arama):**
|
|
59
|
-
```python
|
|
60
|
-
from KekikStream import Manager
|
|
61
|
-
results = Manager().search("vikings")
|
|
62
|
-
print(results[0].title)
|
|
63
|
-
```
|
|
64
|
-
|
|
65
58
|
---
|
|
66
59
|
|
|
67
60
|
## ✨ Özellikler
|
|
@@ -102,11 +95,11 @@ class MyPlugin(PluginBase):
|
|
|
102
95
|
|
|
103
96
|
### 🎬 Oynatıcı Desteği
|
|
104
97
|
|
|
105
|
-
| Oynatıcı
|
|
106
|
-
|
|
107
|
-
| **
|
|
108
|
-
| **
|
|
109
|
-
| **MX Player** | Android
|
|
98
|
+
| Oynatıcı | Platform | Özellikler |
|
|
99
|
+
|---------------|----------|---------------------------|
|
|
100
|
+
| **MPV** | Desktop | Custom headers, subtitles |
|
|
101
|
+
| **VLC** | Desktop | Custom headers, subtitles |
|
|
102
|
+
| **MX Player** | Android | ADB üzerinden |
|
|
110
103
|
|
|
111
104
|
> Özel durumlar için (Google Drive vb.) arka planda otomatik olarak yt-dlp devreye girer.
|
|
112
105
|
|
|
@@ -138,8 +131,8 @@ graph TB
|
|
|
138
131
|
end
|
|
139
132
|
|
|
140
133
|
subgraph Players
|
|
141
|
-
VLC[🎥 VLC]
|
|
142
134
|
MPV[🎥 MPV]
|
|
135
|
+
VLC[🎥 VLC]
|
|
143
136
|
MX[🎥 MX Player]
|
|
144
137
|
end
|
|
145
138
|
|
|
@@ -209,13 +202,13 @@ KekikStream/
|
|
|
209
202
|
|
|
210
203
|
## 📊 Performans
|
|
211
204
|
|
|
212
|
-
| Metrik
|
|
213
|
-
|
|
214
|
-
| Plugin Sayısı
|
|
215
|
-
| Extractor Sayısı
|
|
205
|
+
| Metrik | Değer |
|
|
206
|
+
|----------------------|------------------|
|
|
207
|
+
| Plugin Sayısı | 20+ |
|
|
208
|
+
| Extractor Sayısı | 40+ |
|
|
216
209
|
| Desteklenen Platform | Desktop, Android |
|
|
217
|
-
| Async Arama
|
|
218
|
-
| Cache Desteği
|
|
210
|
+
| Async Arama | ✅ |
|
|
211
|
+
| Cache Desteği | ✅ |
|
|
219
212
|
|
|
220
213
|
---
|
|
221
214
|
|
|
@@ -6,7 +6,7 @@ from io import open
|
|
|
6
6
|
setup(
|
|
7
7
|
# ? Genel Bilgiler
|
|
8
8
|
name = "KekikStream",
|
|
9
|
-
version = "1.
|
|
9
|
+
version = "1.9.3",
|
|
10
10
|
url = "https://github.com/keyiflerolsun/KekikStream",
|
|
11
11
|
description = "terminal üzerinden medya içeriği aramanızı ve VLC/MPV gibi popüler medya oynatıcılar aracılığıyla doğrudan izlemenizi sağlayan modüler ve genişletilebilir bir bıdı bıdı",
|
|
12
12
|
keywords = ["KekikStream", "KekikAkademi", "keyiflerolsun"],
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
-
|
|
3
|
-
from .ExtractorLoader import ExtractorLoader
|
|
4
|
-
from .ExtractorBase import ExtractorBase
|
|
5
|
-
|
|
6
|
-
class ExtractorManager:
|
|
7
|
-
def __init__(self, extractor_dir="Extractors"):
|
|
8
|
-
# Çıkarıcı yükleyiciyi başlat ve tüm çıkarıcıları yükle
|
|
9
|
-
self.extractor_loader = ExtractorLoader(extractor_dir)
|
|
10
|
-
self.extractors = self.extractor_loader.load_all()
|
|
11
|
-
|
|
12
|
-
def find_extractor(self, link) -> ExtractorBase:
|
|
13
|
-
# Verilen bağlantıyı işleyebilecek çıkarıcıyı bul
|
|
14
|
-
for extractor_cls in self.extractors:
|
|
15
|
-
extractor:ExtractorBase = extractor_cls()
|
|
16
|
-
if extractor.can_handle_url(link):
|
|
17
|
-
return extractor
|
|
18
|
-
|
|
19
|
-
return None
|
|
20
|
-
|
|
21
|
-
def map_links_to_extractors(self, links) -> dict:
|
|
22
|
-
# Bağlantıları uygun çıkarıcılarla eşleştir
|
|
23
|
-
mapping = {}
|
|
24
|
-
for link in links:
|
|
25
|
-
for extractor_cls in self.extractors:
|
|
26
|
-
extractor:ExtractorBase = extractor_cls()
|
|
27
|
-
if extractor.can_handle_url(link):
|
|
28
|
-
mapping[link] = f"{extractor.name:<30} » {link.replace(extractor.main_url, '')}"
|
|
29
|
-
break
|
|
30
|
-
|
|
31
|
-
return mapping
|
|
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
|
|
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
|