KekikStream 1.9.0__py3-none-any.whl → 1.9.4__py3-none-any.whl

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.
@@ -7,25 +7,64 @@ class ExtractorManager:
7
7
  def __init__(self, extractor_dir="Extractors"):
8
8
  # Çıkarıcı yükleyiciyi başlat ve tüm çıkarıcıları yükle
9
9
  self.extractor_loader = ExtractorLoader(extractor_dir)
10
- self.extractors = self.extractor_loader.load_all()
10
+ self.extractors = self.extractor_loader.load_all() # Sadece class'lar
11
11
 
12
- def find_extractor(self, link) -> ExtractorBase:
13
- # Verilen bağlantıyı işleyebilecek çıkarıcıyı bul
12
+ # Lazy loading: Instance'lar ilk kullanımda oluşturulacak
13
+ self._extractor_instances = None # None = henüz oluşturulmadı
14
+ self._ytdlp_extractor = None
15
+ self._initialized = False
16
+
17
+ def _ensure_initialized(self):
18
+ """
19
+ Lazy initialization: İlk kullanımda TÜM extractorları initialize et
20
+
21
+ Startup'ta sadece class'ları yükledik (hızlı).
22
+ Şimdi instance'ları oluştur ve cache'le (bir kere).
23
+ """
24
+ if self._initialized:
25
+ return
26
+
27
+ # Instance listesi oluştur
28
+ self._extractor_instances = []
29
+
30
+ # TÜM extractorları instance'la
14
31
  for extractor_cls in self.extractors:
15
- extractor:ExtractorBase = extractor_cls()
32
+ instance = extractor_cls()
33
+
34
+ # YTDLP'yi ayrı tut
35
+ if instance.name == "yt-dlp":
36
+ self._ytdlp_extractor = instance
37
+ else:
38
+ self._extractor_instances.append(instance)
39
+
40
+ # YTDLP'yi EN BAŞA ekle
41
+ if self._ytdlp_extractor:
42
+ self._extractor_instances.insert(0, self._ytdlp_extractor)
43
+
44
+ self._initialized = True
45
+
46
+ def find_extractor(self, link) -> ExtractorBase:
47
+ """
48
+ Verilen bağlantıyı işleyebilecek çıkarıcıyı bul
49
+ """
50
+ self._ensure_initialized()
51
+ # Cached instance'ları kullan
52
+ for extractor in self._extractor_instances:
16
53
  if extractor.can_handle_url(link):
17
54
  return extractor
18
55
 
19
56
  return None
20
57
 
21
58
  def map_links_to_extractors(self, links) -> dict:
22
- # Bağlantıları uygun çıkarıcılarla eşleştir
59
+ """
60
+ Bağlantıları uygun çıkarıcılarla eşleştir
61
+ """
23
62
  mapping = {}
24
63
  for link in links:
25
- for extractor_cls in self.extractors:
26
- extractor:ExtractorBase = extractor_cls()
64
+ # Cached instance'ları kullan
65
+ for extractor in self._extractor_instances:
27
66
  if extractor.can_handle_url(link):
28
67
  mapping[link] = f"{extractor.name:<30} » {link.replace(extractor.main_url, '')}"
29
- break
68
+ break # İlk eşleşmede dur
30
69
 
31
- return mapping
70
+ return mapping
@@ -1,19 +1,82 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
3
  from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
4
- import yt_dlp, sys, os
4
+ from urllib.parse import urlparse
5
+ from yt_dlp.extractor import gen_extractors
6
+ import yt_dlp, re, sys, os
5
7
 
6
8
  class YTDLP(ExtractorBase):
7
9
  name = "yt-dlp"
8
10
  main_url = "" # Universal - tüm siteleri destekler
9
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
+
10
52
  def __init__(self):
11
- pass
53
+ self.__class__._init_fast_domain_regex()
12
54
 
13
55
  def can_handle_url(self, url: str) -> bool:
14
56
  """
15
- yt-dlp'nin bu URL'yi işleyip işleyemeyeceğini kontrol et
57
+ Fast-path: URL host'unu tek mega-regex ile kontrol et (loop yok)
58
+ Slow-path: gerekirse mevcut extract_info tabanlı kontrolün
16
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ü
17
80
  try:
18
81
  # stderr'ı geçici olarak kapat (hata mesajlarını gizle)
19
82
  old_stderr = sys.stderr
@@ -51,7 +114,7 @@ class YTDLP(ExtractorBase):
51
114
  ydl_opts = {
52
115
  "quiet" : True,
53
116
  "no_warnings" : True,
54
- "extract_flat" : False, # Tam bilgi al
117
+ "extract_flat" : False, # Tam bilgi al
55
118
  "format" : "best", # En iyi kalite
56
119
  "no_check_certificates" : True
57
120
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: KekikStream
3
- Version: 1.9.0
3
+ Version: 1.9.4
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ı | Platform | Özellikler |
143
- |----------|----------|------------|
144
- | **VLC** | Desktop | Custom headers, subtitles, varsayılan |
145
- | **MPV** | Desktop | Custom headers, subtitles |
146
- | **MX Player** | Android | ADB üzerinden |
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 | Değer |
250
- |--------|-------|
251
- | Plugin Sayısı | 20+ |
252
- | Extractor Sayısı | 40+ |
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
 
@@ -6,7 +6,7 @@ KekikStream/CLI/pypi_kontrol.py,sha256=q6fNs6EKJDc5VuUFig9DBzLzNPp_kMD1vOVgLElci
6
6
  KekikStream/Core/__init__.py,sha256=ar2MZQF83ryfLfydEXcfjdwNe4Too_HT6bP-D_4TopA,710
7
7
  KekikStream/Core/Extractor/ExtractorBase.py,sha256=Yj7CGvm2ZKxlvuUkZu0X1Pl0JMH250W7hyqv09duTmE,1637
8
8
  KekikStream/Core/Extractor/ExtractorLoader.py,sha256=7uxUXTAuF65KKkmbI6iRiCiUhx-IqrronB7ixhchcTU,4289
9
- KekikStream/Core/Extractor/ExtractorManager.py,sha256=4L1H3jiTnf0kTq4W6uS7n95bBYHlKJ8_hh0og8z4erQ,1244
9
+ KekikStream/Core/Extractor/ExtractorManager.py,sha256=MTgZJe2YJhr7fY1fAGgNI_MWLPVyLlWEkXblEz-zD6E,2467
10
10
  KekikStream/Core/Extractor/ExtractorModels.py,sha256=Qj_gbIeGRewaZXNfYkTi4FFRRq6XBOc0HS0tXGDwajI,445
11
11
  KekikStream/Core/Media/MediaHandler.py,sha256=MEn3spPAThVloN3WcoCwWhpoyMA7tAZvcwYjmjJsX3U,7678
12
12
  KekikStream/Core/Media/MediaManager.py,sha256=AaUq2D7JSJIphjoAj2fjLOJjswm7Qf5hjYCbBdrbnDU,438
@@ -54,7 +54,7 @@ KekikStream/Extractors/VidMolyMe.py,sha256=ogLiFUJVqFbhtzQrZ1gSB9me85DiHvntjWtSv
54
54
  KekikStream/Extractors/VidMoxy.py,sha256=LT7wTKBtuuagXwfGjWZwQF2NQGuChurZJ-I6gM0Jcek,1771
55
55
  KekikStream/Extractors/VidPapi.py,sha256=g9ohdL9VJrxy4N7xerbIRz3ZxjsXFHlJWy0NaZ31hFY,3259
56
56
  KekikStream/Extractors/VideoSeyred.py,sha256=M6QPZ_isX9vM_7LPo-2I_8Cf1vB9awHw8vvzBODtoiQ,1977
57
- KekikStream/Extractors/YTDLP.py,sha256=Ifaex6DTEaLPWjTmhLReilsFHEJRCH0Ghs-rFSvwiQk,3965
57
+ KekikStream/Extractors/YTDLP.py,sha256=O7JkwKMVhCd3RK0yfR5_-mCW5OMOUf3AXpWjOlYJPss,6327
58
58
  KekikStream/Extractors/YildizKisaFilm.py,sha256=R_JlrOVeMiDlXYcuTdItnKvidyx8_u3B14fSrxew2aE,1316
59
59
  KekikStream/Plugins/DiziBox.py,sha256=sxM7ckKeKwMrMkRNUAvh5wE9wdOuVda6Ag_zAdwSvi8,9935
60
60
  KekikStream/Plugins/DiziPal.py,sha256=MBONjermWBm3sN-8ZSILnfXI2F_V2kH65gpTNOuL9dI,10198
@@ -78,9 +78,9 @@ KekikStream/Plugins/SinemaCX.py,sha256=DUvYa7J4a2D5ivLO_sQiaStoV5FDxmz8onJyFwAid
78
78
  KekikStream/Plugins/Sinezy.py,sha256=EttAZogKoKMP8RP_X1fSfi8vVxA2RWizwgnLkmnhERQ,5675
79
79
  KekikStream/Plugins/SuperFilmGeldi.py,sha256=Ohm21BPsJH_S1tx5i2APEgAOD25k2NiwRP7rSgAKvRs,5289
80
80
  KekikStream/Plugins/UgurFilm.py,sha256=eKGzmSi8k_QbXnYPWXZRdmCxxc32zZh4rynmdxCbm1o,4832
81
- kekikstream-1.9.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
82
- kekikstream-1.9.0.dist-info/METADATA,sha256=Mgtks2nTdNgWNefPpw8g_8wihlF26PfcNXucneXAmh0,9035
83
- kekikstream-1.9.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
84
- kekikstream-1.9.0.dist-info/entry_points.txt,sha256=dFwdiTx8djyehI0Gsz-rZwjAfZzUzoBSrmzRu9ubjJc,50
85
- kekikstream-1.9.0.dist-info/top_level.txt,sha256=DNmGJDXl27Drdfobrak8KYLmocW_uznVYFJOzcjUgmY,12
86
- kekikstream-1.9.0.dist-info/RECORD,,
81
+ kekikstream-1.9.4.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
82
+ kekikstream-1.9.4.dist-info/METADATA,sha256=RvKMeLPHAc7LHybDrg88zz4KhxZN1on4gh2ysJVv5fs,9079
83
+ kekikstream-1.9.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
84
+ kekikstream-1.9.4.dist-info/entry_points.txt,sha256=dFwdiTx8djyehI0Gsz-rZwjAfZzUzoBSrmzRu9ubjJc,50
85
+ kekikstream-1.9.4.dist-info/top_level.txt,sha256=DNmGJDXl27Drdfobrak8KYLmocW_uznVYFJOzcjUgmY,12
86
+ kekikstream-1.9.4.dist-info/RECORD,,