KekikStream 2.5.7__py3-none-any.whl → 2.5.9__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.
Potentially problematic release.
This version of KekikStream might be problematic. Click here for more details.
- KekikStream/CLI/__pycache__/pypi_kontrol.cpython-314.pyc +0 -0
- KekikStream/Core/Extractor/__pycache__/ExtractorBase.cpython-314.pyc +0 -0
- KekikStream/Core/Extractor/__pycache__/ExtractorLoader.cpython-314.pyc +0 -0
- KekikStream/Core/Extractor/__pycache__/ExtractorManager.cpython-314.pyc +0 -0
- KekikStream/Core/Extractor/__pycache__/ExtractorModels.cpython-314.pyc +0 -0
- KekikStream/Core/Extractor/__pycache__/YTDLPCache.cpython-314.pyc +0 -0
- KekikStream/Core/Media/__pycache__/MediaHandler.cpython-314.pyc +0 -0
- KekikStream/Core/Media/__pycache__/MediaManager.cpython-314.pyc +0 -0
- KekikStream/Core/Plugin/__pycache__/PluginBase.cpython-314.pyc +0 -0
- KekikStream/Core/Plugin/__pycache__/PluginLoader.cpython-314.pyc +0 -0
- KekikStream/Core/Plugin/__pycache__/PluginManager.cpython-314.pyc +0 -0
- KekikStream/Core/Plugin/__pycache__/PluginModels.cpython-314.pyc +0 -0
- KekikStream/Core/UI/__pycache__/UIManager.cpython-314.pyc +0 -0
- KekikStream/Core/__pycache__/HTMLHelper.cpython-314.pyc +0 -0
- KekikStream/Core/__pycache__/__init__.cpython-314.pyc +0 -0
- KekikStream/Extractors/HotStream.py +7 -2
- KekikStream/Extractors/StreamWish.py +80 -0
- KekikStream/Extractors/VidHide.py +46 -44
- KekikStream/Extractors/VidStack.py +88 -0
- KekikStream/Extractors/__pycache__/Abstream.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/CloseLoad.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/ContentX.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/DonilasPlay.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/DzenRu.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/ExPlay.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/Filemoon.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/HDMomPlayer.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/HDPlayerSystem.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/HotStream.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/JFVid.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/JetTv.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/JetV.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/LuciferPlays.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/MailRu.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/MixPlayHD.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/MixTiger.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/MolyStream.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/Odnoklassniki.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/PeaceMakerst.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/PixelDrain.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/PlayerFilmIzle.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/RapidVid.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/SetPlay.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/SetPrime.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/SibNet.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/Sobreatsesuyp.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/StreamWish.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/TRsTX.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/TauVideo.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/TurboImgz.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/TurkeyPlayer.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/VCTPlay.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/Veev.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/VidBiz.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/VidHide.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/VidMoly.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/VidMoxy.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/VidPapi.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/VidStack.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/VideoSeyred.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/Videostr.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/Vidoza.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/Vtbe.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/YTDLP.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/YildizKisaFilm.cpython-314.pyc +0 -0
- KekikStream/Extractors/__pycache__/Zeus.cpython-314.pyc +0 -0
- KekikStream/Plugins/DDizi.py +176 -0
- KekikStream/Plugins/RealFilmIzle.py +94 -0
- KekikStream/Plugins/ShowFlix.py +211 -0
- KekikStream/Plugins/__pycache__/BelgeselX.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/DDizi.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/DiziBox.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/DiziMom.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/DiziPal.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/DiziYou.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/Dizilla.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/FilmBip.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/FilmEkseni.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/FilmMakinesi.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/FilmModu.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/Filmatek.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/FilmciBaba.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/FullHDFilmizlesene.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/HDFilm.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/HDFilmCehennemi.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/JetFilmizle.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/KultFilmler.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/RealFilmIzle.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/RecTV.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/RoketDizi.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/SelcukFlix.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/SetFilmIzle.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/SezonlukDizi.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/ShowFlix.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/SineWix.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/Sinefy.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/SinemaCX.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/Sinezy.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/SuperFilmIzle.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/UgurFilm.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/Watch32.cpython-314.pyc +0 -0
- KekikStream/Plugins/__pycache__/YabanciDizi.cpython-314.pyc +0 -0
- {kekikstream-2.5.7.dist-info → kekikstream-2.5.9.dist-info}/METADATA +1 -1
- kekikstream-2.5.9.dist-info/RECORD +200 -0
- kekikstream-2.5.7.dist-info/RECORD +0 -100
- {kekikstream-2.5.7.dist-info → kekikstream-2.5.9.dist-info}/WHEEL +0 -0
- {kekikstream-2.5.7.dist-info → kekikstream-2.5.9.dist-info}/entry_points.txt +0 -0
- {kekikstream-2.5.7.dist-info → kekikstream-2.5.9.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-2.5.7.dist-info → kekikstream-2.5.9.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
|
|
4
|
+
from contextlib import suppress
|
|
5
|
+
|
|
6
|
+
class DDizi(PluginBase):
|
|
7
|
+
name = "DDizi"
|
|
8
|
+
language = "tr"
|
|
9
|
+
main_url = "https://www.ddizi.im"
|
|
10
|
+
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
11
|
+
description = "Ddizi, dizi izle, dizi seyret, yerli dizi izle, canlı dizi, türk dizi izle, dizi izle full, diziizle, eski diziler"
|
|
12
|
+
|
|
13
|
+
main_page = {
|
|
14
|
+
f"{main_url}/yeni-eklenenler7" : "Son Eklenen Bölümler",
|
|
15
|
+
f"{main_url}/yabanci-dizi-izle" : "Yabancı Diziler",
|
|
16
|
+
f"{main_url}/eski.diziler" : "Eski Diziler",
|
|
17
|
+
f"{main_url}/yerli-diziler" : "Yerli Diziler"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async def get_articles(self, secici: HTMLHelper) -> list[dict]:
|
|
21
|
+
articles = []
|
|
22
|
+
for veri in secici.select("div.dizi-boxpost-cat, div.dizi-boxpost"):
|
|
23
|
+
title = secici.select_text("a", veri)
|
|
24
|
+
href = secici.select_attr("a", "href", veri)
|
|
25
|
+
img = secici.select_first("img.img-back, img.img-back-cat", veri)
|
|
26
|
+
poster = img.attrs.get("data-src") or img.attrs.get("src") if img else None
|
|
27
|
+
|
|
28
|
+
if title and href:
|
|
29
|
+
articles.append({
|
|
30
|
+
"title" : self.clean_title(title),
|
|
31
|
+
"url" : self.fix_url(href),
|
|
32
|
+
"poster": self.fix_url(poster),
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
return articles
|
|
36
|
+
|
|
37
|
+
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
38
|
+
# DDizi'de sayfalama /sayfa-X formatında (0'dan başlıyor)
|
|
39
|
+
if page > 1:
|
|
40
|
+
target_url = f"{url}/sayfa-{page-1}"
|
|
41
|
+
else:
|
|
42
|
+
target_url = url
|
|
43
|
+
|
|
44
|
+
istek = await self.httpx.get(target_url, follow_redirects=True)
|
|
45
|
+
secici = HTMLHelper(istek.text)
|
|
46
|
+
veriler = await self.get_articles(secici)
|
|
47
|
+
|
|
48
|
+
return [MainPageResult(**veri, category=category) for veri in veriler if veri]
|
|
49
|
+
|
|
50
|
+
async def search(self, query: str) -> list[SearchResult]:
|
|
51
|
+
istek = await self.httpx.post(
|
|
52
|
+
url = f"{self.main_url}/arama/",
|
|
53
|
+
headers = {"Referer": f"{self.main_url}/"},
|
|
54
|
+
data = {"arama": query}
|
|
55
|
+
)
|
|
56
|
+
secici = HTMLHelper(istek.text)
|
|
57
|
+
veriler = await self.get_articles(secici)
|
|
58
|
+
|
|
59
|
+
return [SearchResult(**veri) for veri in veriler if veri]
|
|
60
|
+
|
|
61
|
+
async def load_item(self, url: str) -> SeriesInfo:
|
|
62
|
+
istek = await self.httpx.get(url)
|
|
63
|
+
secici = HTMLHelper(istek.text)
|
|
64
|
+
|
|
65
|
+
title = self.clean_title(secici.select_text("h1, h2, div.dizi-boxpost-cat a"))
|
|
66
|
+
poster = secici.select_poster("div.afis img, img.afis, img.img-back, img.img-back-cat")
|
|
67
|
+
description = secici.select_text("div.dizi-aciklama, div.aciklama, p")
|
|
68
|
+
rating = secici.select_text("span.comments-ss")
|
|
69
|
+
|
|
70
|
+
# Meta verileri (DDizi'de pek yok ama deniyoruz)
|
|
71
|
+
# Year için sadece açıklama kısmına bakalım ki URL'deki ID'yi almasın
|
|
72
|
+
year = HTMLHelper(description).regex_first(r"(\d{4})") if description else None
|
|
73
|
+
actors = secici.select_texts("div.oyuncular a, ul.bilgi li a")
|
|
74
|
+
|
|
75
|
+
episodes = []
|
|
76
|
+
current_page = 1
|
|
77
|
+
has_next = True
|
|
78
|
+
|
|
79
|
+
while has_next:
|
|
80
|
+
page_url = f"{url}/sayfa-{current_page}" if current_page > 1 else url
|
|
81
|
+
if current_page > 1:
|
|
82
|
+
istek = await self.httpx.get(page_url)
|
|
83
|
+
secici = HTMLHelper(istek.text)
|
|
84
|
+
|
|
85
|
+
page_eps = secici.select("div.bolumler a, div.sezonlar a, div.dizi-arsiv a, div.dizi-boxpost-cat a")
|
|
86
|
+
if not page_eps:
|
|
87
|
+
break
|
|
88
|
+
|
|
89
|
+
for ep in page_eps:
|
|
90
|
+
name = ep.text().strip()
|
|
91
|
+
href = ep.attrs.get("href")
|
|
92
|
+
if name and href:
|
|
93
|
+
# 'Bölüm Final' gibi durumları temizleyelim
|
|
94
|
+
clean_name = name.replace("Final", "").strip()
|
|
95
|
+
s, e = secici.extract_season_episode(clean_name)
|
|
96
|
+
episodes.append(Episode(
|
|
97
|
+
season = s or 1,
|
|
98
|
+
episode = e or 1,
|
|
99
|
+
title = name,
|
|
100
|
+
url = self.fix_url(href)
|
|
101
|
+
))
|
|
102
|
+
|
|
103
|
+
# Sonraki sayfa kontrolü
|
|
104
|
+
has_next = any("Sonraki" in a.text() for a in secici.select(".pagination a"))
|
|
105
|
+
current_page += 1
|
|
106
|
+
if current_page > 10: break # Emniyet kilidi
|
|
107
|
+
|
|
108
|
+
if not episodes:
|
|
109
|
+
s, e = secici.extract_season_episode(title)
|
|
110
|
+
episodes.append(Episode(
|
|
111
|
+
season = s or 1,
|
|
112
|
+
episode = e or 1,
|
|
113
|
+
title = title,
|
|
114
|
+
url = url
|
|
115
|
+
))
|
|
116
|
+
|
|
117
|
+
return SeriesInfo(
|
|
118
|
+
url = url,
|
|
119
|
+
poster = self.fix_url(poster),
|
|
120
|
+
title = title,
|
|
121
|
+
description = description,
|
|
122
|
+
rating = rating.strip() if rating else None,
|
|
123
|
+
year = year,
|
|
124
|
+
actors = actors,
|
|
125
|
+
episodes = episodes
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
129
|
+
istek = await self.httpx.get(url)
|
|
130
|
+
secici = HTMLHelper(istek.text)
|
|
131
|
+
|
|
132
|
+
results = []
|
|
133
|
+
# og:video ve JWPlayer kontrolü
|
|
134
|
+
og_video = secici.select_attr("meta[property='og:video']", "content")
|
|
135
|
+
if og_video:
|
|
136
|
+
og_video = self.fix_url(og_video)
|
|
137
|
+
with suppress(Exception):
|
|
138
|
+
player_istek = await self.httpx.get(og_video, headers={"Referer": url})
|
|
139
|
+
player_secici = HTMLHelper(player_istek.text)
|
|
140
|
+
|
|
141
|
+
# file: '...' logic
|
|
142
|
+
sources = player_secici.regex_all(r'file:\s*["\']([^"\']+)["\']')
|
|
143
|
+
for src in sources:
|
|
144
|
+
src = self.fix_url(src)
|
|
145
|
+
# Direkt link kontrolü - Extractor gerektirmeyenler
|
|
146
|
+
is_direct = any(x in src.lower() for x in ["google", "twimg", "mncdn", "akamai", "streambox", ".m3u8", ".mp4", "master.txt"])
|
|
147
|
+
|
|
148
|
+
if is_direct:
|
|
149
|
+
results.append(ExtractResult(
|
|
150
|
+
url = src,
|
|
151
|
+
name = "Video",
|
|
152
|
+
user_agent = "googleusercontent",
|
|
153
|
+
referer = "https://twitter.com/"
|
|
154
|
+
))
|
|
155
|
+
else:
|
|
156
|
+
res = await self.extract(src, referer=og_video)
|
|
157
|
+
if res:
|
|
158
|
+
if isinstance(res, list): results.extend(res)
|
|
159
|
+
else: results.append(res)
|
|
160
|
+
|
|
161
|
+
# Fallback to direct extraction if nothing found but we have og_video
|
|
162
|
+
if not results:
|
|
163
|
+
if any(x in og_video.lower() for x in ["google", "twimg", "mncdn", "akamai", "streambox", ".m3u8", ".mp4", "master.txt"]):
|
|
164
|
+
results.append(ExtractResult(
|
|
165
|
+
url = og_video,
|
|
166
|
+
name = "Video",
|
|
167
|
+
user_agent = "googleusercontent",
|
|
168
|
+
referer = "https://twitter.com/"
|
|
169
|
+
))
|
|
170
|
+
else:
|
|
171
|
+
res = await self.extract(og_video)
|
|
172
|
+
if res:
|
|
173
|
+
if isinstance(res, list): results.extend(res)
|
|
174
|
+
else: results.append(res)
|
|
175
|
+
|
|
176
|
+
return results
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult, HTMLHelper
|
|
4
|
+
|
|
5
|
+
class RealFilmIzle(PluginBase):
|
|
6
|
+
name = "RealFilmIzle"
|
|
7
|
+
language = "tr"
|
|
8
|
+
main_url = "https://realfilmizle.com"
|
|
9
|
+
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
10
|
+
description = "realfilmizle.com, sinemayı seven kullanıcılar için hazırlanmış, zengin içerik yapısına sahip bir online film izleme sitesidir."
|
|
11
|
+
|
|
12
|
+
main_page = {
|
|
13
|
+
f"{main_url}/dizi/aile-filmleri/page" : "Aile",
|
|
14
|
+
f"{main_url}/dizi/aksiyon-filmleri/page" : "Aksiyon",
|
|
15
|
+
f"{main_url}/dizi/animasyon-filmleri/page" : "Animasyon",
|
|
16
|
+
f"{main_url}/dizi/anime-filmleri/page" : "Anime",
|
|
17
|
+
f"{main_url}/dizi/belgeseler-filmleri/page" : "Belgeseler",
|
|
18
|
+
f"{main_url}/dizi/bilim-kurgu-filmleri/page" : "Bilim-Kurgu",
|
|
19
|
+
f"{main_url}/dizi/biyografi-filmleri/page" : "Biyoğrafi",
|
|
20
|
+
f"{main_url}/dizi/dram-filmleri/page" : "Dram",
|
|
21
|
+
f"{main_url}/dizi/erotik-filmleri/page" : "Erotik",
|
|
22
|
+
f"{main_url}/dizi/fantastik-filmleri/page" : "Fantastik",
|
|
23
|
+
f"{main_url}/dizi/gerilim-filmleri/page" : "Gerilim",
|
|
24
|
+
f"{main_url}/dizi/gizem-filmleri/page" : "Gizem",
|
|
25
|
+
f"{main_url}/dizi/hint-filmleri/page" : "Hint",
|
|
26
|
+
f"{main_url}/dizi/komedi-filmleri/page" : "Komedi",
|
|
27
|
+
f"{main_url}/dizi/korku-filmleri/page" : "Korku",
|
|
28
|
+
f"{main_url}/dizi/macera-filmleri/page" : "Macera",
|
|
29
|
+
f"{main_url}/dizi/muzikal-filmleri/page" : "Müzikal",
|
|
30
|
+
f"{main_url}/dizi/netflix-filmleri/page" : "Netflix",
|
|
31
|
+
f"{main_url}/dizi/romantik-filmleri/page" : "Romantik",
|
|
32
|
+
f"{main_url}/dizi/savas-filmleri/page" : "Savaş",
|
|
33
|
+
f"{main_url}/dizi/spor-filmleri/page" : "Spor",
|
|
34
|
+
f"{main_url}/dizi/suc-filmleri/page" : "Suç",
|
|
35
|
+
f"{main_url}/dizi/tarihi-filmleri/page" : "Tarihi",
|
|
36
|
+
f"{main_url}/dizi/western-filmleri/page" : "Western",
|
|
37
|
+
f"{main_url}/dizi/yerli-filmleri/page" : "Yerli",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async def get_articles(self, secici: HTMLHelper) -> list[dict]:
|
|
41
|
+
articles = []
|
|
42
|
+
for veri in secici.select("article.movie-box"):
|
|
43
|
+
title = secici.select_text("div.name a", veri)
|
|
44
|
+
href = secici.select_attr("div.name a", "href", veri)
|
|
45
|
+
poster = secici.select_poster("img", veri)
|
|
46
|
+
|
|
47
|
+
articles.append({
|
|
48
|
+
"title" : self.clean_title(title),
|
|
49
|
+
"url" : self.fix_url(href),
|
|
50
|
+
"poster": self.fix_url(poster),
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
return articles
|
|
54
|
+
|
|
55
|
+
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
56
|
+
istek = await self.httpx.get(f"{url}/{page}")
|
|
57
|
+
secici = HTMLHelper(istek.text)
|
|
58
|
+
veriler = await self.get_articles(secici)
|
|
59
|
+
|
|
60
|
+
return [MainPageResult(**veri, category=category) for veri in veriler if veri]
|
|
61
|
+
|
|
62
|
+
async def search(self, query: str) -> list[SearchResult]:
|
|
63
|
+
istek = await self.httpx.get(f"{self.main_url}/?s={query}")
|
|
64
|
+
secici = HTMLHelper(istek.text)
|
|
65
|
+
veriler = await self.get_articles(secici)
|
|
66
|
+
|
|
67
|
+
return [SearchResult(**veri) for veri in veriler if veri]
|
|
68
|
+
|
|
69
|
+
async def load_item(self, url: str) -> MovieInfo:
|
|
70
|
+
istek = await self.httpx.get(url)
|
|
71
|
+
secici = HTMLHelper(istek.text)
|
|
72
|
+
|
|
73
|
+
title = self.clean_title(secici.select_text("div.film h1"))
|
|
74
|
+
poster = secici.select_poster("div.poster img")
|
|
75
|
+
description = secici.select_direct_text("div.description")
|
|
76
|
+
tags = secici.select_texts("ol.scheme-breadcrumbs li a")
|
|
77
|
+
tags = [tag.replace("✅ ", "").replace(" Filmleri", "") for tag in tags if tag != "Film izle"]
|
|
78
|
+
|
|
79
|
+
return MovieInfo(
|
|
80
|
+
url = url,
|
|
81
|
+
poster = self.fix_url(poster),
|
|
82
|
+
title = self.clean_title(title),
|
|
83
|
+
description = description,
|
|
84
|
+
tags = tags
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
88
|
+
istek = await self.httpx.get(url)
|
|
89
|
+
secici = HTMLHelper(istek.text)
|
|
90
|
+
|
|
91
|
+
iframe = secici.select_attr("div.video-content iframe", "src")
|
|
92
|
+
result = await self.extract(iframe)
|
|
93
|
+
|
|
94
|
+
return [result] if result else []
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult, HTMLHelper
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
class ShowFlix(PluginBase):
|
|
7
|
+
name = "ShowFlix"
|
|
8
|
+
language = "en"
|
|
9
|
+
main_url = "https://showflix.store"
|
|
10
|
+
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
11
|
+
description = "Showflix - Watch and Download Latest Movies and TV Shows for Free. Stream in HD with No Ads!"
|
|
12
|
+
|
|
13
|
+
# Kotlin'den gelen API endpoint'leri
|
|
14
|
+
movie_api = "https://parse.showflix.sbs/parse/classes/moviesv2"
|
|
15
|
+
tv_api = "https://parse.showflix.sbs/parse/classes/seriesv2"
|
|
16
|
+
|
|
17
|
+
# Parse API ayarları (Kotlin'den uyarlandı) - Bu placeholder'lar çalışıyor!
|
|
18
|
+
app_id = "SHOWFLIXAPPID"
|
|
19
|
+
js_key = "SHOWFLIXMASTERKEY"
|
|
20
|
+
|
|
21
|
+
def get_payload(self, extra: dict) -> dict:
|
|
22
|
+
base = {
|
|
23
|
+
"_method": "GET",
|
|
24
|
+
"_ApplicationId": self.app_id,
|
|
25
|
+
"_JavaScriptKey": self.js_key,
|
|
26
|
+
"_ClientVersion": "js3.4.1",
|
|
27
|
+
"_InstallationId": "60f6b1a7-8860-4edf-b255-6bc465b6c704"
|
|
28
|
+
}
|
|
29
|
+
base.update(extra)
|
|
30
|
+
return base
|
|
31
|
+
|
|
32
|
+
main_page = {
|
|
33
|
+
"movie" : "Movies",
|
|
34
|
+
"tv" : "TV Shows"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
38
|
+
api_url = self.movie_api if url == "movie" else self.tv_api
|
|
39
|
+
skip = (page - 1) * 20
|
|
40
|
+
|
|
41
|
+
payload = self.get_payload({
|
|
42
|
+
"limit": 20,
|
|
43
|
+
"skip": skip,
|
|
44
|
+
"order": "-updatedAt"
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
istek = await self.httpx.post(api_url, json=payload)
|
|
48
|
+
data = istek.json().get("results", [])
|
|
49
|
+
|
|
50
|
+
results = []
|
|
51
|
+
for item in data:
|
|
52
|
+
title = item.get("name")
|
|
53
|
+
poster = item.get("posterURL") or item.get("image")
|
|
54
|
+
# Detay sayfasına gitmek için ID'yi kullanacağız, ancak Plugin yapısına uygun bir URL uydurmalıyız
|
|
55
|
+
# load_item içinde bu URL'den ID'yi geri alacağız
|
|
56
|
+
item_type = "movie" if url == "movie" else "tv"
|
|
57
|
+
href = f"{self.main_url}/detail/{item_type}/{item.get('objectId')}"
|
|
58
|
+
|
|
59
|
+
if title:
|
|
60
|
+
results.append(MainPageResult(
|
|
61
|
+
category = category,
|
|
62
|
+
title = self.clean_title(title),
|
|
63
|
+
url = href,
|
|
64
|
+
poster = self.fix_url(poster)
|
|
65
|
+
))
|
|
66
|
+
|
|
67
|
+
return results
|
|
68
|
+
|
|
69
|
+
async def search(self, query: str) -> list[SearchResult]:
|
|
70
|
+
results = []
|
|
71
|
+
for api_url, item_type in [(self.movie_api, "movie"), (self.tv_api, "tv")]:
|
|
72
|
+
payload = self.get_payload({
|
|
73
|
+
"where": {"name": {"$regex": query, "$options": "i"}},
|
|
74
|
+
"limit": 10
|
|
75
|
+
})
|
|
76
|
+
istek = await self.httpx.post(api_url, json=payload)
|
|
77
|
+
data = istek.json().get("results", [])
|
|
78
|
+
|
|
79
|
+
for item in data:
|
|
80
|
+
results.append(SearchResult(
|
|
81
|
+
title = self.clean_title(item.get("name")),
|
|
82
|
+
url = f"{self.main_url}/detail/{item_type}/{item.get('objectId')}",
|
|
83
|
+
poster = self.fix_url(item.get("posterURL") or item.get("image"))
|
|
84
|
+
))
|
|
85
|
+
|
|
86
|
+
return results
|
|
87
|
+
|
|
88
|
+
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
89
|
+
# URL formatımız: .../detail/{type}/{id}
|
|
90
|
+
parts = url.split("/")
|
|
91
|
+
item_type = parts[-2]
|
|
92
|
+
obj_id = parts[-1]
|
|
93
|
+
|
|
94
|
+
api_url = self.movie_api if item_type == "movie" else self.tv_api
|
|
95
|
+
payload = self.get_payload({})
|
|
96
|
+
|
|
97
|
+
istek = await self.httpx.post(f"{api_url}/{obj_id}", json=payload)
|
|
98
|
+
item = istek.json()
|
|
99
|
+
|
|
100
|
+
title = item.get("name")
|
|
101
|
+
poster = self.fix_url(item.get("posterURL") or item.get("image"))
|
|
102
|
+
description = item.get("storyline") or item.get("description")
|
|
103
|
+
year = item.get("releaseYear") or item.get("year")
|
|
104
|
+
rating = item.get("rating")
|
|
105
|
+
|
|
106
|
+
if item_type == "movie":
|
|
107
|
+
return MovieInfo(
|
|
108
|
+
url = url,
|
|
109
|
+
poster = poster,
|
|
110
|
+
title = title,
|
|
111
|
+
description = description,
|
|
112
|
+
year = str(year) if year else None,
|
|
113
|
+
rating = str(rating) if rating else None
|
|
114
|
+
)
|
|
115
|
+
else:
|
|
116
|
+
# Sezon ve bölümleri ayrı API çağrılarıyla alıyoruz
|
|
117
|
+
episodes = await self.get_seasons_with_episodes(obj_id)
|
|
118
|
+
|
|
119
|
+
return SeriesInfo(
|
|
120
|
+
url = url,
|
|
121
|
+
poster = poster,
|
|
122
|
+
title = title,
|
|
123
|
+
description = description,
|
|
124
|
+
year = str(year) if year else None,
|
|
125
|
+
rating = str(rating) if rating else None,
|
|
126
|
+
episodes = episodes
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
async def get_seasons_with_episodes(self, series_id: str) -> list[Episode]:
|
|
130
|
+
# Sezonları al
|
|
131
|
+
season_url = "https://parse.showflix.sbs/parse/classes/seasonv2"
|
|
132
|
+
payload = self.get_payload({"where": {"seriesId": series_id}})
|
|
133
|
+
istek = await self.httpx.post(season_url, json=payload)
|
|
134
|
+
seasons = istek.json().get("results", [])
|
|
135
|
+
|
|
136
|
+
all_episodes = []
|
|
137
|
+
for season in seasons:
|
|
138
|
+
season_id = season.get("objectId")
|
|
139
|
+
season_num = int("".join(filter(str.isdigit, season.get("name", "1"))) or "1")
|
|
140
|
+
|
|
141
|
+
# Bölümleri al
|
|
142
|
+
episode_url = "https://parse.showflix.sbs/parse/classes/episodev2"
|
|
143
|
+
ep_payload = self.get_payload({"where": {"seasonId": season_id}})
|
|
144
|
+
ep_istek = await self.httpx.post(episode_url, json=ep_payload)
|
|
145
|
+
eps = ep_istek.json().get("results", [])
|
|
146
|
+
|
|
147
|
+
for ep in eps:
|
|
148
|
+
# Gömülü linkleri 'data' alanında saklayabiliriz
|
|
149
|
+
embeds = ep.get("embedLinks", {})
|
|
150
|
+
data = {
|
|
151
|
+
"streamwish": embeds.get("streamwish"),
|
|
152
|
+
"streamruby": embeds.get("streamruby"),
|
|
153
|
+
"upnshare": embeds.get("upnshare"),
|
|
154
|
+
"vihide": embeds.get("vihide")
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
all_episodes.append(Episode(
|
|
158
|
+
season = season_num,
|
|
159
|
+
episode = ep.get("episodeNumber", 1),
|
|
160
|
+
title = ep.get("name"),
|
|
161
|
+
url = f"showflix://{json.dumps(data)}" # Custom protocol for load_links
|
|
162
|
+
))
|
|
163
|
+
|
|
164
|
+
return sorted(all_episodes, key=lambda x: (x.season, x.episode))
|
|
165
|
+
|
|
166
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
167
|
+
if url.startswith("showflix://"):
|
|
168
|
+
data = json.loads(url.replace("showflix://", ""))
|
|
169
|
+
results = []
|
|
170
|
+
|
|
171
|
+
mapping = {
|
|
172
|
+
"streamwish": "https://embedwish.com/e/{}",
|
|
173
|
+
"streamruby": "https://rubyvidhub.com/embed-{}.html",
|
|
174
|
+
"upnshare": "https://showflix.upns.one/#{}",
|
|
175
|
+
"vihide": "https://smoothpre.com/v/{}.html"
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
for key, template in mapping.items():
|
|
179
|
+
if val := data.get(key):
|
|
180
|
+
res = await self.extract(template.format(val))
|
|
181
|
+
if res:
|
|
182
|
+
if isinstance(res, list):
|
|
183
|
+
results.extend(res)
|
|
184
|
+
else:
|
|
185
|
+
results.append(res)
|
|
186
|
+
return results
|
|
187
|
+
|
|
188
|
+
# Movie Fallback
|
|
189
|
+
parts = url.split("/")
|
|
190
|
+
obj_id = parts[-1]
|
|
191
|
+
payload = self.get_payload({})
|
|
192
|
+
istek = await self.httpx.post(f"{self.movie_api}/{obj_id}", json=payload)
|
|
193
|
+
item = istek.json()
|
|
194
|
+
embeds = item.get("embedLinks", {})
|
|
195
|
+
|
|
196
|
+
results = []
|
|
197
|
+
mapping = {
|
|
198
|
+
"streamwish": "https://embedwish.com/e/{}",
|
|
199
|
+
"streamruby": "https://rubyvidhub.com/embed-{}.html",
|
|
200
|
+
"upnshare": "https://showflix.upns.one/#{}",
|
|
201
|
+
"vihide": "https://smoothpre.com/v/{}.html"
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
for key, template in mapping.items():
|
|
205
|
+
if val := embeds.get(key):
|
|
206
|
+
res = await self.extract(template.format(val))
|
|
207
|
+
if res:
|
|
208
|
+
if isinstance(res, list): results.extend(res)
|
|
209
|
+
else: results.append(res)
|
|
210
|
+
|
|
211
|
+
return results
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: KekikStream
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.9
|
|
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
|