KekikStream 1.4.4__py3-none-any.whl → 2.0.2__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.
- KekikStream/CLI/pypi_kontrol.py +6 -6
- KekikStream/Core/Extractor/ExtractorBase.py +13 -12
- KekikStream/Core/Extractor/ExtractorLoader.py +25 -17
- KekikStream/Core/Extractor/ExtractorManager.py +53 -9
- KekikStream/Core/Extractor/ExtractorModels.py +5 -7
- KekikStream/Core/Extractor/YTDLPCache.py +35 -0
- KekikStream/Core/Media/MediaHandler.py +52 -31
- KekikStream/Core/Media/MediaManager.py +0 -3
- KekikStream/Core/Plugin/PluginBase.py +47 -21
- KekikStream/Core/Plugin/PluginLoader.py +11 -7
- KekikStream/Core/Plugin/PluginModels.py +25 -25
- KekikStream/Core/__init__.py +1 -0
- KekikStream/Extractors/CloseLoad.py +6 -26
- KekikStream/Extractors/ContentX_.py +40 -0
- KekikStream/Extractors/DzenRu.py +38 -0
- KekikStream/Extractors/ExPlay.py +53 -0
- KekikStream/Extractors/FirePlayer.py +60 -0
- KekikStream/Extractors/HDPlayerSystem.py +41 -0
- KekikStream/Extractors/JetTv.py +45 -0
- KekikStream/Extractors/MailRu.py +2 -4
- KekikStream/Extractors/MixTiger.py +57 -0
- KekikStream/Extractors/MolyStream.py +25 -7
- KekikStream/Extractors/Odnoklassniki.py +16 -11
- KekikStream/Extractors/{OkRuHTTP.py → Odnoklassniki_.py} +5 -1
- KekikStream/Extractors/{HDStreamAble.py → PeaceMakerst_.py} +1 -1
- KekikStream/Extractors/PixelDrain.py +0 -1
- KekikStream/Extractors/PlayerFilmIzle.py +62 -0
- KekikStream/Extractors/RapidVid.py +30 -13
- KekikStream/Extractors/RapidVid_.py +7 -0
- KekikStream/Extractors/SetPlay.py +57 -0
- KekikStream/Extractors/SetPrime.py +45 -0
- KekikStream/Extractors/SibNet.py +0 -1
- KekikStream/Extractors/TurkeyPlayer.py +34 -0
- KekikStream/Extractors/VidHide.py +72 -0
- KekikStream/Extractors/VidMoly.py +20 -19
- KekikStream/Extractors/{VidMolyMe.py → VidMoly_.py} +1 -1
- KekikStream/Extractors/VidMoxy.py +0 -1
- KekikStream/Extractors/VidPapi.py +89 -0
- KekikStream/Extractors/YTDLP.py +177 -0
- KekikStream/Extractors/YildizKisaFilm.py +41 -0
- KekikStream/Plugins/DiziBox.py +28 -16
- KekikStream/Plugins/DiziPal.py +246 -0
- KekikStream/Plugins/DiziYou.py +58 -31
- KekikStream/Plugins/Dizilla.py +97 -68
- KekikStream/Plugins/FilmBip.py +145 -0
- KekikStream/Plugins/FilmMakinesi.py +61 -52
- KekikStream/Plugins/FilmModu.py +138 -0
- KekikStream/Plugins/FullHDFilm.py +164 -0
- KekikStream/Plugins/FullHDFilmizlesene.py +38 -37
- KekikStream/Plugins/HDFilmCehennemi.py +44 -54
- KekikStream/Plugins/JetFilmizle.py +68 -42
- KekikStream/Plugins/KultFilmler.py +219 -0
- KekikStream/Plugins/RecTV.py +41 -37
- KekikStream/Plugins/RoketDizi.py +232 -0
- KekikStream/Plugins/SelcukFlix.py +309 -0
- KekikStream/Plugins/SezonlukDizi.py +16 -14
- KekikStream/Plugins/SineWix.py +39 -30
- KekikStream/Plugins/Sinefy.py +238 -0
- KekikStream/Plugins/SinemaCX.py +157 -0
- KekikStream/Plugins/Sinezy.py +146 -0
- KekikStream/Plugins/SuperFilmGeldi.py +121 -0
- KekikStream/Plugins/UgurFilm.py +10 -10
- KekikStream/__init__.py +296 -319
- KekikStream/requirements.txt +3 -4
- kekikstream-2.0.2.dist-info/METADATA +309 -0
- kekikstream-2.0.2.dist-info/RECORD +82 -0
- {kekikstream-1.4.4.dist-info → kekikstream-2.0.2.dist-info}/WHEEL +1 -1
- KekikStream/Extractors/FourCX.py +0 -7
- KekikStream/Extractors/FourPichive.py +0 -7
- KekikStream/Extractors/FourPlayRu.py +0 -7
- KekikStream/Extractors/Hotlinger.py +0 -7
- KekikStream/Extractors/OkRuSSL.py +0 -7
- KekikStream/Extractors/Pichive.py +0 -7
- KekikStream/Extractors/PlayRu.py +0 -7
- KekikStream/Helpers/Unpack.py +0 -75
- KekikStream/Plugins/Shorten.py +0 -225
- kekikstream-1.4.4.dist-info/METADATA +0 -108
- kekikstream-1.4.4.dist-info/RECORD +0 -63
- {kekikstream-1.4.4.dist-info → kekikstream-2.0.2.dist-info}/entry_points.txt +0 -0
- {kekikstream-1.4.4.dist-info → kekikstream-2.0.2.dist-info/licenses}/LICENSE +0 -0
- {kekikstream-1.4.4.dist-info → kekikstream-2.0.2.dist-info}/top_level.txt +0 -0
KekikStream/__init__.py
CHANGED
|
@@ -2,368 +2,345 @@
|
|
|
2
2
|
|
|
3
3
|
from .CLI import konsol, cikis_yap, hata_yakala, pypi_kontrol_guncelle
|
|
4
4
|
from .Core import PluginManager, ExtractorManager, UIManager, MediaManager, PluginBase, ExtractorBase, SeriesInfo
|
|
5
|
-
from asyncio import run
|
|
5
|
+
from asyncio import run, TaskGroup, Semaphore
|
|
6
6
|
from contextlib import suppress
|
|
7
7
|
|
|
8
8
|
class KekikStream:
|
|
9
9
|
def __init__(self):
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
self.
|
|
14
|
-
|
|
15
|
-
self.
|
|
16
|
-
self.
|
|
17
|
-
self.
|
|
18
|
-
self.
|
|
19
|
-
self.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
10
|
+
self.plugin = PluginManager()
|
|
11
|
+
self.extractor = ExtractorManager()
|
|
12
|
+
self.ui = UIManager()
|
|
13
|
+
self.media = MediaManager()
|
|
14
|
+
|
|
15
|
+
self.current_plugin: PluginBase = None
|
|
16
|
+
self.is_series = False
|
|
17
|
+
self.series_info: SeriesInfo = None
|
|
18
|
+
self.current_episode_index = -1
|
|
19
|
+
self.episode_title = ""
|
|
20
|
+
|
|
21
|
+
async def show_header(self, title: str):
|
|
22
|
+
"""Konsolu temizle ve başlık göster"""
|
|
23
|
+
self.ui.clear_console()
|
|
24
|
+
konsol.rule(title)
|
|
25
|
+
|
|
26
|
+
def update_title(self, new_info: str):
|
|
27
|
+
"""Medya başlığına yeni bilgi ekle"""
|
|
28
|
+
if not new_info:
|
|
29
|
+
return
|
|
30
|
+
current = self.media.get_title()
|
|
31
|
+
if new_info not in current:
|
|
32
|
+
self.media.set_title(f"{current} | {new_info}")
|
|
33
|
+
|
|
34
|
+
async def load_media_info(self, url: str, retries=3):
|
|
35
|
+
"""Medya bilgilerini yükle"""
|
|
36
|
+
for _ in range(retries):
|
|
37
|
+
with suppress(Exception):
|
|
38
|
+
return await self.current_plugin.load_item(url)
|
|
39
|
+
konsol.print("[bold red]Medya bilgileri yüklenemedi![/bold red]")
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
async def start(self):
|
|
43
|
+
"""Uygulamayı başlat"""
|
|
44
|
+
await self.show_header("[bold cyan]KekikStream[/bold cyan]")
|
|
45
|
+
|
|
46
|
+
if not self.plugin.get_plugin_names():
|
|
47
|
+
konsol.print("[bold red]Eklenti bulunamadı![/bold red]")
|
|
48
|
+
return
|
|
37
49
|
|
|
38
50
|
try:
|
|
39
|
-
await self.
|
|
51
|
+
await self.select_plugin()
|
|
40
52
|
finally:
|
|
41
|
-
|
|
42
|
-
await self.eklentiler_yonetici.close_plugins()
|
|
43
|
-
|
|
44
|
-
async def bi_bolum_daha(self):
|
|
45
|
-
await self._temizle_ve_baslik_goster(f"[bold cyan]{self.suanki_eklenti.name} » Bi Bölüm Daha?[/bold cyan]")
|
|
46
|
-
return await self.sonuc_detaylari_goster(self.secilen_sonuc)
|
|
47
|
-
|
|
48
|
-
async def icerik_bitti(self):
|
|
49
|
-
return await self.bi_bolum_daha() if self.dizi else await self.baslat()
|
|
50
|
-
|
|
51
|
-
async def sonuc_bulunamadi(self):
|
|
52
|
-
"""
|
|
53
|
-
Arama sonucunda hiçbir içerik bulunamadığında kullanıcıya seçenekler sunar.
|
|
54
|
-
"""
|
|
55
|
-
secim = await self.arayuz_yonetici.select_from_list(
|
|
56
|
-
message = "Ne yapmak istersiniz?",
|
|
57
|
-
choices = ["Tüm Eklentilerde Ara", "Ana Menü", "Çıkış"]
|
|
58
|
-
)
|
|
53
|
+
await self.plugin.close_plugins()
|
|
59
54
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
case "Çıkış":
|
|
66
|
-
cikis_yap(False)
|
|
67
|
-
|
|
68
|
-
async def eklenti_secimi(self):
|
|
69
|
-
"""
|
|
70
|
-
Kullanıcıdan eklenti seçimi alır ve seçime göre arama işlemini başlatır.
|
|
71
|
-
"""
|
|
72
|
-
eklenti_adi = await self.arayuz_yonetici.select_from_fuzzy(
|
|
73
|
-
message = "Arama yapılacak eklentiyi seçin:",
|
|
74
|
-
choices = ["Tüm Eklentilerde Ara", *self.eklentiler_yonetici.get_plugin_names()]
|
|
55
|
+
async def select_plugin(self):
|
|
56
|
+
"""Eklenti seçimi"""
|
|
57
|
+
plugin_name = await self.ui.select_from_fuzzy(
|
|
58
|
+
message = "Eklenti seçin:",
|
|
59
|
+
choices = ["Tüm Eklentilerde Ara", *self.plugin.get_plugin_names()]
|
|
75
60
|
)
|
|
76
61
|
|
|
77
|
-
if
|
|
78
|
-
await self.
|
|
62
|
+
if plugin_name == "Tüm Eklentilerde Ara":
|
|
63
|
+
await self.search_all_plugins()
|
|
79
64
|
else:
|
|
80
|
-
self.
|
|
81
|
-
await self.
|
|
82
|
-
|
|
83
|
-
async def
|
|
84
|
-
"""
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
await self.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
secilen_sonuc = await self.eklenti_sonuc_secimi(sonuclar)
|
|
98
|
-
if secilen_sonuc:
|
|
99
|
-
await self.sonuc_detaylari_goster({"plugin": self.suanki_eklenti.name, "url": secilen_sonuc})
|
|
100
|
-
|
|
101
|
-
async def eklenti_sonuc_secimi(self, sonuclar: list):
|
|
102
|
-
"""
|
|
103
|
-
Arama sonuçlarından kullanıcıya seçim yaptırır.
|
|
104
|
-
"""
|
|
105
|
-
return await self.arayuz_yonetici.select_from_fuzzy(
|
|
106
|
-
message = "İçerik sonuçlarından birini seçin:",
|
|
107
|
-
choices = [{"name": sonuc.title, "value": sonuc.url} for sonuc in sonuclar]
|
|
65
|
+
self.current_plugin = self.plugin.select_plugin(plugin_name)
|
|
66
|
+
await self.search_in_plugin()
|
|
67
|
+
|
|
68
|
+
async def search_in_plugin(self):
|
|
69
|
+
"""Seçili eklentide ara"""
|
|
70
|
+
await self.show_header(f"[bold cyan]{self.current_plugin.name}[/bold cyan]")
|
|
71
|
+
|
|
72
|
+
query = await self.ui.prompt_text("Arama sorgusu:")
|
|
73
|
+
results = await self.current_plugin.search(query)
|
|
74
|
+
|
|
75
|
+
if not results:
|
|
76
|
+
konsol.print("[bold red]Sonuç bulunamadı![/bold red]")
|
|
77
|
+
return await self.handle_no_results()
|
|
78
|
+
|
|
79
|
+
choice = await self.ui.select_from_fuzzy(
|
|
80
|
+
message = "Sonuç seçin:",
|
|
81
|
+
choices = [{"name": r.title, "value": r.url} for r in results]
|
|
108
82
|
)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
# Eklenti türü kontrolü
|
|
134
|
-
if not isinstance(eklenti, PluginBase):
|
|
135
|
-
konsol.print(f"[yellow][!] {eklenti_adi} geçerli bir PluginBase değil, atlanıyor...[/yellow]")
|
|
136
|
-
continue
|
|
137
|
-
|
|
138
|
-
if eklenti_adi in ["Shorten"]:
|
|
139
|
-
continue
|
|
140
|
-
|
|
141
|
-
konsol.log(f"[yellow][~] {eklenti_adi:<19} aranıyor...[/]")
|
|
142
|
-
try:
|
|
143
|
-
sonuclar = await eklenti.search(sorgu)
|
|
144
|
-
if sonuclar:
|
|
145
|
-
# Sonuçları listeye ekle
|
|
146
|
-
tum_sonuclar.extend(
|
|
147
|
-
[
|
|
148
|
-
{
|
|
149
|
-
"plugin" : eklenti_adi,
|
|
150
|
-
"title" : sonuc.title,
|
|
151
|
-
"url" : sonuc.url,
|
|
152
|
-
"poster" : sonuc.poster
|
|
153
|
-
}
|
|
154
|
-
for sonuc in sonuclar
|
|
83
|
+
|
|
84
|
+
if choice:
|
|
85
|
+
await self.show_media_details({"plugin": self.current_plugin.name, "url": choice})
|
|
86
|
+
|
|
87
|
+
async def search_all_plugins(self):
|
|
88
|
+
"""Tüm eklentilerde ara"""
|
|
89
|
+
await self.show_header("[bold cyan]Tüm Eklentilerde Ara[/bold cyan]")
|
|
90
|
+
|
|
91
|
+
query = await self.ui.prompt_text("Arama sorgusu:")
|
|
92
|
+
all_results = []
|
|
93
|
+
|
|
94
|
+
# Maksimum 5 eşzamanlı arama için semaphore
|
|
95
|
+
semaphore = Semaphore(5)
|
|
96
|
+
|
|
97
|
+
async def search_plugin(name: str, plugin: PluginBase):
|
|
98
|
+
"""Tek bir plugin'de ara (semaphore ile sınırlandırılmış)"""
|
|
99
|
+
async with semaphore:
|
|
100
|
+
konsol.log(f"[yellow][~] {name:<19} aranıyor...[/]")
|
|
101
|
+
try:
|
|
102
|
+
results = await plugin.search(query)
|
|
103
|
+
if results:
|
|
104
|
+
return [
|
|
105
|
+
{"plugin": name, "title": r.title, "url": r.url, "poster": r.poster}
|
|
106
|
+
for r in results
|
|
155
107
|
]
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if not tum_sonuclar:
|
|
161
|
-
konsol.print("[bold red]Hiçbir sonuç bulunamadı![/bold red]")
|
|
162
|
-
await self.sonuc_bulunamadi()
|
|
163
|
-
return tum_sonuclar
|
|
164
|
-
|
|
165
|
-
async def tum_sonuc_secimi(self, sonuclar: list):
|
|
166
|
-
"""
|
|
167
|
-
Tüm arama sonuçlarından kullanıcıya seçim yaptırır.
|
|
168
|
-
"""
|
|
169
|
-
secenekler = [
|
|
170
|
-
{"name": f"[{sonuc['plugin']}]".ljust(21) + f" » {sonuc['title']}", "value": sonuc}
|
|
171
|
-
for sonuc in sonuclar
|
|
172
|
-
]
|
|
108
|
+
except Exception as e:
|
|
109
|
+
konsol.print(f"[bold red]{name} hatası: {e}[/bold red]")
|
|
110
|
+
return []
|
|
173
111
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
112
|
+
# Tüm plugin'leri paralel olarak ara
|
|
113
|
+
async with TaskGroup() as tg:
|
|
114
|
+
tasks = []
|
|
115
|
+
for name, plugin in self.plugin.plugins.items():
|
|
116
|
+
tasks.append(tg.create_task(search_plugin(name, plugin)))
|
|
178
117
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
"""
|
|
183
|
-
for _ in range(deneme):
|
|
184
|
-
with suppress(Exception):
|
|
185
|
-
return await self.suanki_eklenti.load_item(url)
|
|
118
|
+
# Sonuçları topla
|
|
119
|
+
for task in tasks:
|
|
120
|
+
all_results.extend(task.result())
|
|
186
121
|
|
|
187
|
-
|
|
188
|
-
|
|
122
|
+
if not all_results:
|
|
123
|
+
return await self.handle_no_results()
|
|
189
124
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
125
|
+
choice = await self.ui.select_from_fuzzy(
|
|
126
|
+
message = "Sonuç seçin:",
|
|
127
|
+
choices = [
|
|
128
|
+
{"name": f"[{r['plugin']}]".ljust(21) + f" » {r['title']}", "value": r}
|
|
129
|
+
for r in all_results
|
|
130
|
+
]
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
if choice:
|
|
134
|
+
await self.show_media_details(choice)
|
|
200
135
|
|
|
201
|
-
|
|
136
|
+
async def show_media_details(self, choice):
|
|
137
|
+
"""Seçilen medyanın detaylarını göster"""
|
|
138
|
+
try:
|
|
139
|
+
if isinstance(choice, dict) and "plugin" in choice:
|
|
140
|
+
self.current_plugin = self.plugin.select_plugin(choice["plugin"])
|
|
141
|
+
url = choice["url"]
|
|
202
142
|
else:
|
|
203
|
-
url =
|
|
143
|
+
url = choice
|
|
204
144
|
|
|
205
|
-
|
|
206
|
-
if not
|
|
207
|
-
return await self.
|
|
145
|
+
media_info = await self.load_media_info(url)
|
|
146
|
+
if not media_info:
|
|
147
|
+
return await self.handle_no_results()
|
|
208
148
|
|
|
209
|
-
except Exception as
|
|
210
|
-
|
|
211
|
-
return hata_yakala(hata)
|
|
149
|
+
except Exception as e:
|
|
150
|
+
return hata_yakala(e)
|
|
212
151
|
|
|
213
|
-
|
|
214
|
-
self.
|
|
215
|
-
self.arayuz_yonetici.display_media_info(f"{self.suanki_eklenti.name} | {medya_bilgi.title}", medya_bilgi)
|
|
152
|
+
self.media.set_title(f"{self.current_plugin.name} | {media_info.title}")
|
|
153
|
+
self.ui.display_media_info(f"{self.current_plugin.name} | {media_info.title}", media_info)
|
|
216
154
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
self.
|
|
220
|
-
await self.
|
|
155
|
+
if isinstance(media_info, SeriesInfo):
|
|
156
|
+
self.is_series = True
|
|
157
|
+
self.series_info = media_info
|
|
158
|
+
await self.select_episode(media_info)
|
|
221
159
|
else:
|
|
222
|
-
self.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
message = "
|
|
160
|
+
self.reset_series_state()
|
|
161
|
+
links = await self.current_plugin.load_links(media_info.url)
|
|
162
|
+
await self.show_link_options(links)
|
|
163
|
+
|
|
164
|
+
def reset_series_state(self):
|
|
165
|
+
"""Dizi durumunu sıfırla"""
|
|
166
|
+
self.is_series = False
|
|
167
|
+
self.series_info = None
|
|
168
|
+
self.current_episode_index = -1
|
|
169
|
+
self.episode_title = ""
|
|
170
|
+
|
|
171
|
+
async def select_episode(self, series_info: SeriesInfo):
|
|
172
|
+
"""Bölüm seç"""
|
|
173
|
+
selected = await self.ui.select_from_fuzzy(
|
|
174
|
+
message = "Bölüm seçin:",
|
|
237
175
|
choices = [
|
|
238
|
-
{
|
|
239
|
-
|
|
176
|
+
{
|
|
177
|
+
"name" : f"{ep.season}. Sezon {ep.episode}. Bölüm" + (f" - {ep.title}" if ep.title else ""),
|
|
178
|
+
"value" : ep.url
|
|
179
|
+
}
|
|
180
|
+
for ep in series_info.episodes
|
|
240
181
|
]
|
|
241
182
|
)
|
|
242
|
-
if secilen_bolum:
|
|
243
|
-
self.bolum_baslik = bolumler[secilen_bolum]
|
|
244
|
-
|
|
245
|
-
baglantilar = await self.suanki_eklenti.load_links(secilen_bolum)
|
|
246
|
-
await self.baglanti_secenekleri_goster(baglantilar)
|
|
247
|
-
|
|
248
|
-
async def baglanti_secenekleri_goster(self, baglantilar):
|
|
249
|
-
"""
|
|
250
|
-
Bağlantı seçeneklerini kullanıcıya sunar ve seçilen bağlantıya göre oynatma işlemini gerçekleştirir.
|
|
251
|
-
"""
|
|
252
|
-
if not baglantilar:
|
|
253
|
-
konsol.print("[bold red]Hiçbir bağlantı bulunamadı![/bold red]")
|
|
254
|
-
return await self.sonuc_bulunamadi()
|
|
255
|
-
|
|
256
|
-
# Doğrudan oynatma seçeneği
|
|
257
|
-
if hasattr(self.suanki_eklenti, "play") and callable(getattr(self.suanki_eklenti, "play", None)):
|
|
258
|
-
return await self.direkt_oynat(baglantilar)
|
|
259
|
-
|
|
260
|
-
# Bağlantıları çıkarıcılarla eşleştir
|
|
261
|
-
haritalama = self.cikaricilar_yonetici.map_links_to_extractors(baglantilar)
|
|
262
|
-
|
|
263
|
-
# Uygun çıkarıcı kontrolü
|
|
264
|
-
if not haritalama:
|
|
265
|
-
konsol.print("[bold red]Hiçbir Extractor bulunamadı![/bold red]")
|
|
266
|
-
konsol.print(baglantilar)
|
|
267
|
-
return await self.sonuc_bulunamadi()
|
|
268
|
-
|
|
269
|
-
# Kullanıcı seçenekleri
|
|
270
|
-
secim = await self.arayuz_yonetici.select_from_list(
|
|
271
|
-
message = "Ne yapmak istersiniz?",
|
|
272
|
-
choices = ["İzle", "Tüm Eklentilerde Ara", "Ana Menü"]
|
|
273
|
-
)
|
|
274
183
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
184
|
+
if not selected:
|
|
185
|
+
return await self.content_finished()
|
|
186
|
+
|
|
187
|
+
# Bölüm bilgilerini kaydet
|
|
188
|
+
for idx, ep in enumerate(series_info.episodes):
|
|
189
|
+
if ep.url == selected:
|
|
190
|
+
self.current_episode_index = idx
|
|
191
|
+
self.episode_title = (f"{ep.season}. Sezon {ep.episode}. Bölüm" + (f" - {ep.title}" if ep.title else ""))
|
|
192
|
+
break
|
|
193
|
+
|
|
194
|
+
links = await self.current_plugin.load_links(selected)
|
|
195
|
+
await self.show_link_options(links)
|
|
196
|
+
|
|
197
|
+
async def play_next_episode(self):
|
|
198
|
+
"""Sonraki bölümü oynat"""
|
|
199
|
+
self.current_episode_index += 1
|
|
200
|
+
next_ep = self.series_info.episodes[self.current_episode_index]
|
|
201
|
+
self.episode_title = (f"{next_ep.season}. Sezon {next_ep.episode}. Bölüm" + (f" - {next_ep.title}" if next_ep.title else ""))
|
|
202
|
+
links = await self.current_plugin.load_links(next_ep.url)
|
|
203
|
+
await self.show_link_options(links)
|
|
204
|
+
|
|
205
|
+
async def ask_next_episode(self):
|
|
206
|
+
"""Dizi bittikten sonra ne yapılsın?"""
|
|
207
|
+
await self.show_header(f"[bold cyan]{self.current_plugin.name}[/bold cyan]")
|
|
208
|
+
self.ui.display_media_info(f"{self.current_plugin.name} | {self.series_info.title}", self.series_info)
|
|
209
|
+
konsol.print(f"[yellow][+][/yellow] [bold green]{self.episode_title}[/bold green] izlendi!")
|
|
210
|
+
|
|
211
|
+
options = ["Bölüm Seç", "Ana Menü", "Çıkış"]
|
|
212
|
+
if self.current_episode_index + 1 < len(self.series_info.episodes):
|
|
213
|
+
options.insert(0, "Sonraki Bölüm")
|
|
214
|
+
else:
|
|
215
|
+
konsol.print("[bold yellow]Son bölümdü![/bold yellow]")
|
|
283
216
|
|
|
284
|
-
|
|
285
|
-
await self.tum_eklentilerde_arama()
|
|
217
|
+
choice = await self.ui.select_from_list("Ne yapmak istersiniz?", options)
|
|
286
218
|
|
|
287
|
-
|
|
288
|
-
|
|
219
|
+
match choice:
|
|
220
|
+
case "Sonraki Bölüm":
|
|
221
|
+
await self.play_next_episode()
|
|
222
|
+
case "Bölüm Seç":
|
|
223
|
+
await self.select_episode(self.series_info)
|
|
224
|
+
case "Ana Menü":
|
|
225
|
+
await self.start()
|
|
226
|
+
case "Çıkış":
|
|
227
|
+
cikis_yap(False)
|
|
289
228
|
|
|
290
|
-
async def
|
|
291
|
-
"""
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
229
|
+
async def show_link_options(self, links: list[dict]):
|
|
230
|
+
"""Bağlantı seçeneklerini göster"""
|
|
231
|
+
if not links:
|
|
232
|
+
konsol.print("[bold red]Bağlantı bulunamadı![/bold red]")
|
|
233
|
+
return await self.handle_no_results()
|
|
234
|
+
|
|
235
|
+
# Direkt oynatma varsa
|
|
236
|
+
if hasattr(self.current_plugin, "play"):
|
|
237
|
+
return await self.play_direct(links)
|
|
238
|
+
|
|
239
|
+
# Extractor ile oynat
|
|
240
|
+
url_list = [link["url"] for link in links]
|
|
241
|
+
mapping = self.extractor.map_links_to_extractors(url_list)
|
|
242
|
+
|
|
243
|
+
if not mapping:
|
|
244
|
+
konsol.print("[bold red]Extractor bulunamadı![/bold red]")
|
|
245
|
+
return await self.handle_no_results()
|
|
246
|
+
|
|
247
|
+
choice = await self.ui.select_from_list("Ne yapmak istersiniz?", ["İzle", "Tüm Eklentilerde Ara", "Ana Menü"])
|
|
248
|
+
|
|
249
|
+
match choice:
|
|
250
|
+
case "İzle":
|
|
251
|
+
await self.play_with_extractor(links, mapping)
|
|
252
|
+
case "Tüm Eklentilerde Ara":
|
|
253
|
+
await self.search_all_plugins()
|
|
254
|
+
case "Ana Menü":
|
|
255
|
+
await self.start()
|
|
256
|
+
|
|
257
|
+
async def play_direct(self, links: list[dict]):
|
|
258
|
+
"""Plugin'in kendi metoduyla oynat"""
|
|
259
|
+
selected = await self.ui.select_from_list(
|
|
260
|
+
message = "Bağlantı seçin:",
|
|
261
|
+
choices = [{"name": link.get("name", "Bilinmiyor"), "value": link} for link in links]
|
|
300
262
|
)
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
263
|
+
|
|
264
|
+
if not selected:
|
|
265
|
+
return await self.content_finished()
|
|
266
|
+
|
|
267
|
+
self.update_title(self.episode_title)
|
|
268
|
+
self.update_title(selected.get("name"))
|
|
269
|
+
|
|
270
|
+
await self.current_plugin.play(
|
|
271
|
+
name = self.media.get_title(),
|
|
272
|
+
url = selected.get("url"),
|
|
273
|
+
user_agent = selected.get("user_agent"),
|
|
274
|
+
referer = selected.get("referer"),
|
|
275
|
+
subtitles = selected.get("subtitles", [])
|
|
310
276
|
)
|
|
277
|
+
return await self.content_finished()
|
|
311
278
|
|
|
312
|
-
|
|
279
|
+
async def play_with_extractor(self, links: list[dict], mapping: dict):
|
|
280
|
+
"""Extractor ile oynat"""
|
|
281
|
+
options = [
|
|
282
|
+
{"name": link.get("name", mapping[link["url"]]), "value": link}
|
|
283
|
+
for link in links if link["url"] in mapping
|
|
284
|
+
]
|
|
313
285
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
"""
|
|
318
|
-
# Uygun çıkarıcıyı bul
|
|
319
|
-
cikarici: ExtractorBase = self.cikaricilar_yonetici.find_extractor(secilen_link)
|
|
320
|
-
if not cikarici:
|
|
321
|
-
return konsol.print("[bold red]Uygun Extractor bulunamadı.[/bold red]")
|
|
286
|
+
if not options:
|
|
287
|
+
konsol.print("[bold red]İzlenebilir bağlantı yok![/bold red]")
|
|
288
|
+
return await self.content_finished()
|
|
322
289
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
return
|
|
290
|
+
selected = await self.ui.select_from_list("Bağlantı seçin:", options)
|
|
291
|
+
if not selected:
|
|
292
|
+
return await self.content_finished()
|
|
293
|
+
|
|
294
|
+
url = selected.get("url")
|
|
295
|
+
extractor: ExtractorBase = self.extractor.find_extractor(url)
|
|
296
|
+
|
|
297
|
+
if not extractor:
|
|
298
|
+
konsol.print("[bold red]Extractor bulunamadı![/bold red]")
|
|
299
|
+
return await self.handle_no_results()
|
|
333
300
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
301
|
+
try:
|
|
302
|
+
referer = selected.get("referer", self.current_plugin.main_url)
|
|
303
|
+
extract_data = await extractor.extract(url, referer=referer)
|
|
304
|
+
except Exception as e:
|
|
305
|
+
konsol.print(f"[bold red]{extractor.name} hatası: {e}[/bold red]")
|
|
306
|
+
return await self.handle_no_results()
|
|
338
307
|
|
|
339
|
-
|
|
340
|
-
"""
|
|
341
|
-
Birden fazla bağlantı varsa seçim yapar.
|
|
342
|
-
"""
|
|
308
|
+
# Birden fazla link varsa seç
|
|
343
309
|
if isinstance(extract_data, list):
|
|
344
|
-
|
|
345
|
-
message = "
|
|
346
|
-
choices = [{"name":
|
|
310
|
+
extract_data = await self.ui.select_from_list(
|
|
311
|
+
message = "Bağlantı seçin:",
|
|
312
|
+
choices = [{"name": d.name, "value": d} for d in extract_data]
|
|
347
313
|
)
|
|
348
|
-
return extract_data
|
|
349
314
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
self.
|
|
315
|
+
if not extract_data:
|
|
316
|
+
return await self.content_finished()
|
|
317
|
+
|
|
318
|
+
# Başlıkları güncelle ve oynat
|
|
319
|
+
self.update_title(self.episode_title)
|
|
320
|
+
self.update_title(selected.get("name"))
|
|
321
|
+
self.update_title(extract_data.name)
|
|
355
322
|
|
|
356
|
-
|
|
357
|
-
|
|
323
|
+
self.media.play_media(extract_data)
|
|
324
|
+
await self.content_finished()
|
|
358
325
|
|
|
359
|
-
|
|
360
|
-
|
|
326
|
+
async def content_finished(self):
|
|
327
|
+
"""İçerik bittiğinde ne yapsın?"""
|
|
328
|
+
if self.is_series:
|
|
329
|
+
await self.ask_next_episode()
|
|
330
|
+
else:
|
|
331
|
+
await self.start()
|
|
361
332
|
|
|
362
|
-
|
|
363
|
-
|
|
333
|
+
async def handle_no_results(self):
|
|
334
|
+
"""Sonuç bulunamadığında"""
|
|
335
|
+
choice = await self.ui.select_from_list("Ne yapmak istersiniz?", ["Tüm Eklentilerde Ara", "Ana Menü", "Çıkış"])
|
|
336
|
+
match choice:
|
|
337
|
+
case "Tüm Eklentilerde Ara":
|
|
338
|
+
await self.search_all_plugins()
|
|
339
|
+
case "Ana Menü":
|
|
340
|
+
await self.start()
|
|
341
|
+
case "Çıkış":
|
|
342
|
+
cikis_yap(False)
|
|
364
343
|
|
|
365
|
-
if secilen_data.name not in self.medya_yonetici.get_title():
|
|
366
|
-
self.medya_yonetici.set_title(f"{self.medya_yonetici.get_title()} | {secilen_data.name}")
|
|
367
344
|
|
|
368
345
|
def basla():
|
|
369
346
|
try:
|
|
@@ -372,9 +349,9 @@ def basla():
|
|
|
372
349
|
|
|
373
350
|
# Uygulamayı başlat
|
|
374
351
|
app = KekikStream()
|
|
375
|
-
run(app.
|
|
352
|
+
run(app.start())
|
|
376
353
|
cikis_yap(False)
|
|
377
354
|
except KeyboardInterrupt:
|
|
378
355
|
cikis_yap(True)
|
|
379
356
|
except Exception as hata:
|
|
380
|
-
hata_yakala(hata)
|
|
357
|
+
hata_yakala(hata)
|