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/Plugins/DiziYou.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, Subtitle, ExtractResult
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
import re
|
|
6
6
|
|
|
7
7
|
class DiziYou(PluginBase):
|
|
8
8
|
name = "DiziYou"
|
|
9
9
|
language = "tr"
|
|
10
|
-
main_url = "https://www.
|
|
10
|
+
main_url = "https://www.diziyou.one"
|
|
11
11
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
12
12
|
description = "Diziyou en kaliteli Türkçe dublaj ve altyazılı yabancı dizi izleme sitesidir. Güncel ve efsanevi dizileri 1080p Full HD kalitede izlemek için hemen tıkla!"
|
|
13
13
|
|
|
@@ -29,7 +29,6 @@ class DiziYou(PluginBase):
|
|
|
29
29
|
f"{main_url}/dizi-arsivi/page/SAYFA/?tur=Vah%C5%9Fi+Bat%C4%B1" : "Vahşi Batı"
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
@kekik_cache(ttl=60*60)
|
|
33
32
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
34
33
|
istek = await self.httpx.get(f"{url.replace('SAYFA', str(page))}")
|
|
35
34
|
secici = Selector(istek.text)
|
|
@@ -44,7 +43,6 @@ class DiziYou(PluginBase):
|
|
|
44
43
|
for veri in secici.css("div.single-item")
|
|
45
44
|
]
|
|
46
45
|
|
|
47
|
-
@kekik_cache(ttl=60*60)
|
|
48
46
|
async def search(self, query: str) -> list[SearchResult]:
|
|
49
47
|
istek = await self.httpx.get(f"{self.main_url}/?s={query}")
|
|
50
48
|
secici = Selector(istek.text)
|
|
@@ -53,33 +51,53 @@ class DiziYou(PluginBase):
|
|
|
53
51
|
SearchResult(
|
|
54
52
|
title = afis.css("div#categorytitle a::text").get().strip(),
|
|
55
53
|
url = self.fix_url(afis.css("div#categorytitle a::attr(href)").get()),
|
|
56
|
-
poster = self.fix_url(afis.css("img::attr(src)").get())
|
|
54
|
+
poster = self.fix_url(afis.css("img::attr(src)").get() or afis.css("img::attr(data-src)").get())
|
|
57
55
|
)
|
|
58
56
|
for afis in secici.css("div.incontent div#list-series")
|
|
59
57
|
]
|
|
60
58
|
|
|
61
|
-
@kekik_cache(ttl=60*60)
|
|
62
59
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
63
60
|
istek = await self.httpx.get(url)
|
|
64
61
|
secici = Selector(istek.text)
|
|
65
62
|
|
|
66
|
-
title
|
|
67
|
-
|
|
63
|
+
# Title - div.title h1 içinde
|
|
64
|
+
title_raw = secici.css("div.title h1::text").get()
|
|
65
|
+
title = title_raw.strip() if title_raw else ""
|
|
66
|
+
|
|
67
|
+
# Fallback: Eğer title boşsa URL'den çıkar (telif kısıtlaması olan sayfalar için)
|
|
68
|
+
if not title:
|
|
69
|
+
# URL'den slug'ı al: https://www.diziyou.one/jasmine/ -> jasmine -> Jasmine
|
|
70
|
+
slug = url.rstrip('/').split('/')[-1]
|
|
71
|
+
title = slug.replace('-', ' ').title()
|
|
72
|
+
|
|
73
|
+
# Poster
|
|
74
|
+
poster_raw = secici.css("div.category_image img::attr(src)").get()
|
|
75
|
+
poster = self.fix_url(poster_raw) if poster_raw else ""
|
|
68
76
|
year = secici.xpath("//span[contains(., 'Yapım Yılı')]/following-sibling::text()[1]").get()
|
|
69
|
-
description = secici.css("div.diziyou_desc::text").get()
|
|
77
|
+
description = secici.css("div.diziyou_desc::text").get()
|
|
78
|
+
if description:
|
|
79
|
+
description = description.strip()
|
|
70
80
|
tags = secici.css("div.genres a::text").getall()
|
|
71
81
|
rating = secici.xpath("//span[contains(., 'IMDB')]/following-sibling::text()[1]").get()
|
|
72
82
|
_actors = secici.xpath("//span[contains(., 'Oyuncular')]/following-sibling::text()[1]").get()
|
|
73
83
|
actors = [actor.strip() for actor in _actors.split(",")] if _actors else []
|
|
74
84
|
|
|
75
85
|
episodes = []
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
86
|
+
# Episodes - bolumust her bölüm için bir <a> içinde
|
|
87
|
+
# :has() parsel'de çalışmıyor, XPath kullanıyoruz
|
|
88
|
+
for link in secici.xpath('//a[div[@class="bolumust"]]'):
|
|
89
|
+
ep_name_raw = link.css("div.baslik::text").get()
|
|
90
|
+
if not ep_name_raw:
|
|
91
|
+
continue
|
|
92
|
+
ep_name = ep_name_raw.strip()
|
|
93
|
+
|
|
94
|
+
ep_href = self.fix_url(link.css("::attr(href)").get())
|
|
95
|
+
if not ep_href:
|
|
80
96
|
continue
|
|
81
97
|
|
|
82
|
-
|
|
98
|
+
# Bölüm ismi varsa al
|
|
99
|
+
ep_name_raw_clean = link.css("div.bolumismi::text").get()
|
|
100
|
+
ep_name_clean = ep_name_raw_clean.strip().replace("(", "").replace(")", "").strip() if ep_name_raw_clean else ep_name
|
|
83
101
|
|
|
84
102
|
ep_episode = re.search(r"(\d+)\. Bölüm", ep_name)[1]
|
|
85
103
|
ep_season = re.search(r"(\d+)\. Sezon", ep_name)[1]
|
|
@@ -105,14 +123,23 @@ class DiziYou(PluginBase):
|
|
|
105
123
|
actors = actors
|
|
106
124
|
)
|
|
107
125
|
|
|
108
|
-
|
|
109
|
-
async def load_links(self, url: str) -> list[str]:
|
|
126
|
+
async def load_links(self, url: str) -> list[dict]:
|
|
110
127
|
istek = await self.httpx.get(url)
|
|
111
128
|
secici = Selector(istek.text)
|
|
112
129
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
130
|
+
# Title ve episode name - None kontrolü ekle
|
|
131
|
+
item_title_raw = secici.css("div.title h1::text").get()
|
|
132
|
+
item_title = item_title_raw.strip() if item_title_raw else ""
|
|
133
|
+
|
|
134
|
+
ep_name_raw = secici.css("div#bolum-ismi::text").get()
|
|
135
|
+
ep_name = ep_name_raw.strip() if ep_name_raw else ""
|
|
136
|
+
|
|
137
|
+
# Player src'den item_id çıkar
|
|
138
|
+
player_src = secici.css("iframe#diziyouPlayer::attr(src)").get()
|
|
139
|
+
if not player_src:
|
|
140
|
+
return [] # Player bulunamadıysa boş liste döndür
|
|
141
|
+
|
|
142
|
+
item_id = player_src.split("/")[-1].replace(".html", "")
|
|
116
143
|
|
|
117
144
|
subtitles = []
|
|
118
145
|
stream_urls = []
|
|
@@ -128,7 +155,7 @@ class DiziYou(PluginBase):
|
|
|
128
155
|
url = self.fix_url(f"{self.main_url.replace('www', 'storage')}/subtitles/{item_id}/tr.vtt"),
|
|
129
156
|
))
|
|
130
157
|
veri = {
|
|
131
|
-
"dil": "Orjinal Dil",
|
|
158
|
+
"dil": "Orjinal Dil (TR Altyazı)",
|
|
132
159
|
"url": f"{self.main_url.replace('www', 'storage')}/episodes/{item_id}/play.m3u8"
|
|
133
160
|
}
|
|
134
161
|
if veri not in stream_urls:
|
|
@@ -139,31 +166,31 @@ class DiziYou(PluginBase):
|
|
|
139
166
|
url = self.fix_url(f"{self.main_url.replace('www', 'storage')}/subtitles/{item_id}/en.vtt"),
|
|
140
167
|
))
|
|
141
168
|
veri = {
|
|
142
|
-
"dil": "Orjinal Dil",
|
|
169
|
+
"dil": "Orjinal Dil (EN Altyazı)",
|
|
143
170
|
"url": f"{self.main_url.replace('www', 'storage')}/episodes/{item_id}/play.m3u8"
|
|
144
171
|
}
|
|
145
172
|
if veri not in stream_urls:
|
|
146
173
|
stream_urls.append(veri)
|
|
147
174
|
case "turkceDublaj":
|
|
148
175
|
stream_urls.append({
|
|
149
|
-
"dil": "Dublaj",
|
|
176
|
+
"dil": "Türkçe Dublaj",
|
|
150
177
|
"url": f"{self.main_url.replace('www', 'storage')}/episodes/{item_id}_tr/play.m3u8"
|
|
151
178
|
})
|
|
152
179
|
|
|
153
|
-
|
|
180
|
+
results = []
|
|
154
181
|
for stream in stream_urls:
|
|
155
|
-
|
|
156
|
-
"
|
|
157
|
-
"name" : f"{
|
|
182
|
+
results.append({
|
|
183
|
+
"url" : stream.get("url"),
|
|
184
|
+
"name" : f"{stream.get('dil')}",
|
|
158
185
|
"referer" : url,
|
|
159
186
|
"subtitles" : subtitles
|
|
160
|
-
}
|
|
187
|
+
})
|
|
161
188
|
|
|
162
|
-
return
|
|
189
|
+
return results
|
|
163
190
|
|
|
164
|
-
async def play(self,
|
|
165
|
-
extract_result = ExtractResult(
|
|
166
|
-
self.media_handler.title = name
|
|
191
|
+
async def play(self, **kwargs):
|
|
192
|
+
extract_result = ExtractResult(**kwargs)
|
|
193
|
+
self.media_handler.title = kwargs.get("name")
|
|
167
194
|
if self.name not in self.media_handler.title:
|
|
168
195
|
self.media_handler.title = f"{self.name} | {self.media_handler.title}"
|
|
169
196
|
|
KekikStream/Plugins/Dizilla.py
CHANGED
|
@@ -1,58 +1,71 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
from json import loads
|
|
6
6
|
from urllib.parse import urlparse, urlunparse
|
|
7
|
+
from Crypto.Cipher import AES
|
|
8
|
+
from base64 import b64decode
|
|
7
9
|
|
|
8
10
|
class Dizilla(PluginBase):
|
|
9
11
|
name = "Dizilla"
|
|
10
12
|
language = "tr"
|
|
11
|
-
main_url = "https://
|
|
13
|
+
main_url = "https://dizilla40.com"
|
|
12
14
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
13
|
-
description = "
|
|
15
|
+
description = "1080p yabancı dizi izle. Türkçe altyazılı veya dublaj seçenekleriyle 1080p çözünürlükte yabancı dizilere anında ulaş. Popüler dizileri kesintisiz izle."
|
|
14
16
|
|
|
15
17
|
main_page = {
|
|
16
|
-
f"{main_url}/tum-bolumler"
|
|
17
|
-
f"{main_url}/
|
|
18
|
-
f"{main_url}/
|
|
19
|
-
f"{main_url}/
|
|
20
|
-
f"{main_url}/
|
|
21
|
-
f"{main_url}/
|
|
22
|
-
f"{main_url}/
|
|
18
|
+
f"{main_url}/tum-bolumler" : "Altyazılı Bölümler",
|
|
19
|
+
f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=15&countryIdsComma=&orderType=date_desc&languageId=-1¤tPage=SAYFA¤tPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Aile",
|
|
20
|
+
f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=9&countryIdsComma=&orderType=date_desc&languageId=-1¤tPage=SAYFA¤tPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Aksiyon",
|
|
21
|
+
f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=17&countryIdsComma=&orderType=date_desc&languageId=-1¤tPage=SAYFA¤tPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Animasyon",
|
|
22
|
+
f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=5&countryIdsComma=&orderType=date_desc&languageId=-1¤tPage=SAYFA¤tPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Bilim Kurgu",
|
|
23
|
+
f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=2&countryIdsComma=&orderType=date_desc&languageId=-1¤tPage=SAYFA¤tPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Dram",
|
|
24
|
+
f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=12&countryIdsComma=&orderType=date_desc&languageId=-1¤tPage=SAYFA¤tPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Fantastik",
|
|
25
|
+
f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=18&countryIdsComma=&orderType=date_desc&languageId=-1¤tPage=SAYFA¤tPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Gerilim",
|
|
26
|
+
f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=3&countryIdsComma=&orderType=date_desc&languageId=-1¤tPage=SAYFA¤tPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Gizem",
|
|
27
|
+
f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=4&countryIdsComma=&orderType=date_desc&languageId=-1¤tPage=SAYFA¤tPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Komedi",
|
|
28
|
+
f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=8&countryIdsComma=&orderType=date_desc&languageId=-1¤tPage=SAYFA¤tPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Korku",
|
|
29
|
+
f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=24&countryIdsComma=&orderType=date_desc&languageId=-1¤tPage=SAYFA¤tPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Macera",
|
|
30
|
+
f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=7&countryIdsComma=&orderType=date_desc&languageId=-1¤tPage=SAYFA¤tPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Romantik",
|
|
31
|
+
f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=26&countryIdsComma=&orderType=date_desc&languageId=-1¤tPage=SAYFA¤tPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Savaş",
|
|
32
|
+
f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=1&countryIdsComma=&orderType=date_desc&languageId=-1¤tPage=SAYFA¤tPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Suç",
|
|
33
|
+
f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=11&countryIdsComma=&orderType=date_desc&languageId=-1¤tPage=SAYFA¤tPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Western",
|
|
23
34
|
}
|
|
24
35
|
|
|
25
|
-
@kekik_cache(ttl=60*60)
|
|
26
36
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
27
|
-
istek = await self.httpx.get(url)
|
|
28
|
-
secici = Selector(istek.text)
|
|
29
|
-
|
|
30
37
|
ana_sayfa = []
|
|
31
38
|
|
|
32
|
-
if "
|
|
39
|
+
if "api/bg" in url:
|
|
40
|
+
istek = await self.httpx.post(url.replace("SAYFA", str(page)))
|
|
41
|
+
decrypted = await self.decrypt_response(istek.json().get("response"))
|
|
42
|
+
veriler = decrypted.get("result", [])
|
|
33
43
|
ana_sayfa.extend([
|
|
34
44
|
MainPageResult(
|
|
35
45
|
category = category,
|
|
36
|
-
title = veri.
|
|
37
|
-
url = self.fix_url(veri.
|
|
38
|
-
poster = self.fix_url(veri.
|
|
46
|
+
title = veri.get("original_title"),
|
|
47
|
+
url = self.fix_url(f"{self.main_url}/{veri.get('used_slug')}"),
|
|
48
|
+
poster = self.fix_url(veri.get("object_poster_url")),
|
|
39
49
|
)
|
|
40
|
-
for veri in
|
|
50
|
+
for veri in veriler
|
|
41
51
|
])
|
|
42
52
|
else:
|
|
43
|
-
|
|
53
|
+
istek = await self.httpx.get(url.replace("SAYFA", str(page)))
|
|
54
|
+
secici = Selector(istek.text)
|
|
55
|
+
|
|
56
|
+
for veri in secici.css("div.tab-content > div.grid a"):
|
|
44
57
|
name = veri.css("h2::text").get()
|
|
45
|
-
ep_name = veri.
|
|
58
|
+
ep_name = veri.xpath("normalize-space(//div[contains(@class, 'opacity-80')])").get()
|
|
46
59
|
if not ep_name:
|
|
47
60
|
continue
|
|
48
61
|
|
|
49
62
|
ep_name = ep_name.replace(". Sezon", "x").replace(". Bölüm", "").replace("x ", "x")
|
|
50
63
|
title = f"{name} - {ep_name}"
|
|
51
64
|
|
|
52
|
-
ep_req = await self.httpx.get(veri.css("::attr(href)").get())
|
|
65
|
+
ep_req = await self.httpx.get(self.fix_url(veri.css("::attr(href)").get()))
|
|
53
66
|
ep_secici = Selector(ep_req.text)
|
|
54
|
-
href = self.fix_url(ep_secici.css("a
|
|
55
|
-
poster = self.fix_url(ep_secici.css("img.imgt::attr(
|
|
67
|
+
href = self.fix_url(ep_secici.css("nav li:nth-of-type(3) a::attr(href)").get())
|
|
68
|
+
poster = self.fix_url(ep_secici.css("img.imgt::attr(src)").get())
|
|
56
69
|
|
|
57
70
|
ana_sayfa.append(
|
|
58
71
|
MainPageResult(
|
|
@@ -65,32 +78,31 @@ class Dizilla(PluginBase):
|
|
|
65
78
|
|
|
66
79
|
return ana_sayfa
|
|
67
80
|
|
|
68
|
-
|
|
81
|
+
async def decrypt_response(self, response: str) -> dict:
|
|
82
|
+
# 32 bytes key
|
|
83
|
+
key = "9bYMCNQiWsXIYFWYAu7EkdsSbmGBTyUI".encode("utf-8")
|
|
84
|
+
|
|
85
|
+
# IV = 16 bytes of zero
|
|
86
|
+
iv = bytes([0] * 16)
|
|
87
|
+
|
|
88
|
+
# Base64 decode
|
|
89
|
+
encrypted_bytes = b64decode(response)
|
|
90
|
+
|
|
91
|
+
# AES/CBC/PKCS5Padding
|
|
92
|
+
cipher = AES.new(key, AES.MODE_CBC, iv)
|
|
93
|
+
decrypted = cipher.decrypt(encrypted_bytes)
|
|
94
|
+
|
|
95
|
+
# PKCS5/PKCS7 padding remove
|
|
96
|
+
pad_len = decrypted[-1]
|
|
97
|
+
decrypted = decrypted[:-pad_len]
|
|
98
|
+
|
|
99
|
+
# JSON decode
|
|
100
|
+
return loads(decrypted.decode("utf-8"))
|
|
101
|
+
|
|
69
102
|
async def search(self, query: str) -> list[SearchResult]:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
cValue = ilk_secici.css("input[name='cValue']::attr(value)").get()
|
|
74
|
-
|
|
75
|
-
self.httpx.headers.update({
|
|
76
|
-
"Accept" : "application/json, text/javascript, */*; q=0.01",
|
|
77
|
-
"X-Requested-With" : "XMLHttpRequest",
|
|
78
|
-
"Referer" : f"{self.main_url}/"
|
|
79
|
-
})
|
|
80
|
-
self.httpx.cookies.update({
|
|
81
|
-
"showAllDaFull" : "true",
|
|
82
|
-
"PHPSESSID" : ilk_istek.cookies.get("PHPSESSID"),
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
arama_istek = await self.httpx.post(
|
|
86
|
-
url = f"{self.main_url}/bg/searchcontent",
|
|
87
|
-
data = {
|
|
88
|
-
"cKey" : cKey,
|
|
89
|
-
"cValue" : cValue,
|
|
90
|
-
"searchterm" : query
|
|
91
|
-
}
|
|
92
|
-
)
|
|
93
|
-
arama_veri = arama_istek.json().get("data", {}).get("result", [])
|
|
103
|
+
arama_istek = await self.httpx.post(f"{self.main_url}/api/bg/searchcontent?searchterm={query}")
|
|
104
|
+
decrypted = await self.decrypt_response(arama_istek.json().get("response"))
|
|
105
|
+
arama_veri = decrypted.get("result", [])
|
|
94
106
|
|
|
95
107
|
return [
|
|
96
108
|
SearchResult(
|
|
@@ -101,7 +113,6 @@ class Dizilla(PluginBase):
|
|
|
101
113
|
for veri in arama_veri
|
|
102
114
|
]
|
|
103
115
|
|
|
104
|
-
@kekik_cache(ttl=60*60)
|
|
105
116
|
async def url_base_degis(self, eski_url:str, yeni_base:str) -> str:
|
|
106
117
|
parsed_url = urlparse(eski_url)
|
|
107
118
|
parsed_yeni_base = urlparse(yeni_base)
|
|
@@ -112,27 +123,34 @@ class Dizilla(PluginBase):
|
|
|
112
123
|
|
|
113
124
|
return urlunparse(yeni_url)
|
|
114
125
|
|
|
115
|
-
@kekik_cache(ttl=60*60)
|
|
116
126
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
117
127
|
istek = await self.httpx.get(url)
|
|
118
128
|
secici = Selector(istek.text)
|
|
119
129
|
veri = loads(secici.xpath("//script[@type='application/ld+json']/text()").getall()[-1])
|
|
120
130
|
|
|
121
|
-
title
|
|
131
|
+
title = veri.get("name")
|
|
122
132
|
if alt_title := veri.get("alternateName"):
|
|
123
133
|
title += f" - ({alt_title})"
|
|
124
134
|
|
|
125
135
|
poster = self.fix_url(veri.get("image"))
|
|
126
136
|
description = veri.get("description")
|
|
127
137
|
year = veri.get("datePublished").split("-")[0]
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
138
|
+
|
|
139
|
+
# Tags extraction from page content (h3 tag)
|
|
140
|
+
tags_raw = secici.css("div.poster.poster h3::text").get()
|
|
141
|
+
tags = [t.strip() for t in tags_raw.split(",")] if tags_raw else []
|
|
142
|
+
|
|
143
|
+
rating = veri.get("aggregateRating", {}).get("ratingValue")
|
|
144
|
+
actors = [actor.get("name") for actor in veri.get("actor", []) if actor.get("name")]
|
|
131
145
|
|
|
132
146
|
bolumler = []
|
|
133
147
|
sezonlar = veri.get("containsSeason") if isinstance(veri.get("containsSeason"), list) else [veri.get("containsSeason")]
|
|
134
148
|
for sezon in sezonlar:
|
|
135
|
-
|
|
149
|
+
episodes = sezon.get("episode")
|
|
150
|
+
if isinstance(episodes, dict):
|
|
151
|
+
episodes = [episodes]
|
|
152
|
+
|
|
153
|
+
for bolum in episodes:
|
|
136
154
|
bolumler.append(Episode(
|
|
137
155
|
season = sezon.get("seasonNumber"),
|
|
138
156
|
episode = bolum.get("episodeNumber"),
|
|
@@ -152,15 +170,26 @@ class Dizilla(PluginBase):
|
|
|
152
170
|
actors = actors
|
|
153
171
|
)
|
|
154
172
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
173
|
+
async def load_links(self, url: str) -> list[dict]:
|
|
174
|
+
istek = await self.httpx.get(url)
|
|
175
|
+
secici = Selector(istek.text)
|
|
176
|
+
|
|
177
|
+
next_data = loads(secici.css("script#__NEXT_DATA__::text").get())
|
|
178
|
+
secure_data = next_data.get("props", {}).get("pageProps", {}).get("secureData", {})
|
|
179
|
+
decrypted = await self.decrypt_response(secure_data)
|
|
180
|
+
results = decrypted.get("RelatedResults", {}).get("getEpisodeSources", {}).get("result", [])
|
|
181
|
+
|
|
182
|
+
links = []
|
|
183
|
+
for result in results:
|
|
184
|
+
iframe_src = Selector(result.get("source_content")).css("iframe::attr(src)").get()
|
|
185
|
+
iframe_url = self.fix_url(iframe_src)
|
|
186
|
+
if not iframe_url:
|
|
187
|
+
continue
|
|
188
|
+
|
|
189
|
+
extractor = self.ex_manager.find_extractor(iframe_url)
|
|
190
|
+
links.append({
|
|
191
|
+
"url" : iframe_url,
|
|
192
|
+
"name" : f"{extractor.name if extractor else 'Main Player'} | {result.get('language_name')}",
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
return links
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo
|
|
4
|
+
from parsel import Selector
|
|
5
|
+
|
|
6
|
+
class FilmBip(PluginBase):
|
|
7
|
+
name = "FilmBip"
|
|
8
|
+
language = "tr"
|
|
9
|
+
main_url = "https://filmbip.com"
|
|
10
|
+
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
11
|
+
description = "FilmBip adlı film sitemizde Full HD film izle. Yerli ve yabancı filmleri Türkçe dublaj veya altyazılı şekilde 1080p yüksek kalite film izle"
|
|
12
|
+
|
|
13
|
+
main_page = {
|
|
14
|
+
f"{main_url}/filmler/SAYFA" : "Yeni Filmler",
|
|
15
|
+
f"{main_url}/film/tur/aile/SAYFA" : "Aile",
|
|
16
|
+
f"{main_url}/film/tur/aksiyon/SAYFA" : "Aksiyon",
|
|
17
|
+
f"{main_url}/film/tur/belgesel/SAYFA" : "Belgesel",
|
|
18
|
+
f"{main_url}/film/tur/bilim-kurgu/SAYFA" : "Bilim Kurgu",
|
|
19
|
+
f"{main_url}/film/tur/dram/SAYFA" : "Dram",
|
|
20
|
+
f"{main_url}/film/tur/fantastik/SAYFA" : "Fantastik",
|
|
21
|
+
f"{main_url}/film/tur/gerilim/SAYFA" : "Gerilim",
|
|
22
|
+
f"{main_url}/film/tur/gizem/SAYFA" : "Gizem",
|
|
23
|
+
f"{main_url}/film/tur/komedi/SAYFA" : "Komedi",
|
|
24
|
+
f"{main_url}/film/tur/korku/SAYFA" : "Korku",
|
|
25
|
+
f"{main_url}/film/tur/macera/SAYFA" : "Macera",
|
|
26
|
+
f"{main_url}/film/tur/muzik/SAYFA" : "Müzik",
|
|
27
|
+
f"{main_url}/film/tur/romantik/SAYFA" : "Romantik",
|
|
28
|
+
f"{main_url}/film/tur/savas/SAYFA" : "Savaş",
|
|
29
|
+
f"{main_url}/film/tur/suc/SAYFA" : "Suç",
|
|
30
|
+
f"{main_url}/film/tur/tarih/SAYFA" : "Tarih",
|
|
31
|
+
f"{main_url}/film/tur/vahsi-bati/SAYFA" : "Western",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
35
|
+
page_url = url.replace("SAYFA", "") if page == 1 else url.replace("SAYFA", str(page))
|
|
36
|
+
page_url = page_url.rstrip("/")
|
|
37
|
+
|
|
38
|
+
istek = await self.httpx.get(page_url)
|
|
39
|
+
secici = Selector(istek.text)
|
|
40
|
+
|
|
41
|
+
results = []
|
|
42
|
+
for veri in secici.css("div.poster-long"):
|
|
43
|
+
img = veri.css("a.block img.lazy")
|
|
44
|
+
title = img.css("::attr(alt)").get()
|
|
45
|
+
href = self.fix_url(veri.css("a.block::attr(href)").get())
|
|
46
|
+
poster = self.fix_url(img.css("::attr(data-src)").get() or img.css("::attr(src)").get())
|
|
47
|
+
|
|
48
|
+
if title and href:
|
|
49
|
+
results.append(MainPageResult(
|
|
50
|
+
category = category,
|
|
51
|
+
title = title,
|
|
52
|
+
url = href,
|
|
53
|
+
poster = poster,
|
|
54
|
+
))
|
|
55
|
+
|
|
56
|
+
return results
|
|
57
|
+
|
|
58
|
+
async def search(self, query: str) -> list[SearchResult]:
|
|
59
|
+
istek = await self.httpx.post(
|
|
60
|
+
url = f"{self.main_url}/search",
|
|
61
|
+
headers = {
|
|
62
|
+
"Accept" : "application/json, text/javascript, */*; q=0.01",
|
|
63
|
+
"X-Requested-With" : "XMLHttpRequest",
|
|
64
|
+
"Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
|
|
65
|
+
"Origin" : self.main_url,
|
|
66
|
+
"Referer" : f"{self.main_url}/"
|
|
67
|
+
},
|
|
68
|
+
data = {"query": query}
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
json_data = istek.json()
|
|
73
|
+
if not json_data.get("success"):
|
|
74
|
+
return []
|
|
75
|
+
|
|
76
|
+
html_content = json_data.get("theme", "")
|
|
77
|
+
except Exception:
|
|
78
|
+
return []
|
|
79
|
+
|
|
80
|
+
secici = Selector(text=html_content)
|
|
81
|
+
|
|
82
|
+
results = []
|
|
83
|
+
for veri in secici.css("li"):
|
|
84
|
+
title = veri.css("a.block.truncate::text").get()
|
|
85
|
+
href = self.fix_url(veri.css("a::attr(href)").get())
|
|
86
|
+
poster = self.fix_url(veri.css("img.lazy::attr(data-src)").get())
|
|
87
|
+
|
|
88
|
+
if title and href:
|
|
89
|
+
results.append(SearchResult(
|
|
90
|
+
title = title.strip(),
|
|
91
|
+
url = href,
|
|
92
|
+
poster = poster,
|
|
93
|
+
))
|
|
94
|
+
|
|
95
|
+
return results
|
|
96
|
+
|
|
97
|
+
async def load_item(self, url: str) -> MovieInfo:
|
|
98
|
+
istek = await self.httpx.get(url)
|
|
99
|
+
secici = Selector(istek.text)
|
|
100
|
+
|
|
101
|
+
title = secici.css("div.page-title h1::text").get()
|
|
102
|
+
poster = self.fix_url(secici.css("meta[property='og:image']::attr(content)").get())
|
|
103
|
+
trailer = secici.css("div.series-profile-trailer::attr(data-yt)").get()
|
|
104
|
+
description = secici.css("div.series-profile-infos-in.article p::text").get() or \
|
|
105
|
+
secici.css("div.series-profile-summary p::text").get()
|
|
106
|
+
|
|
107
|
+
tags = secici.css("div.series-profile-type.tv-show-profile-type a::text").getall()
|
|
108
|
+
|
|
109
|
+
# XPath ile yıl, süre ve puan
|
|
110
|
+
year = secici.xpath("//li[span[contains(text(), 'Yapım yılı')]]/p/text()").re_first(r"(\d{4})")
|
|
111
|
+
duration = secici.xpath("//li[span[contains(text(), 'Süre')]]/p/text()").re_first(r"(\d+)")
|
|
112
|
+
rating = secici.xpath("//li[span[contains(text(), 'IMDB Puanı')]]/p/span/text()").get()
|
|
113
|
+
|
|
114
|
+
actors = secici.css("div.series-profile-cast ul li a img::attr(alt)").getall()
|
|
115
|
+
|
|
116
|
+
return MovieInfo(
|
|
117
|
+
url = url,
|
|
118
|
+
poster = poster,
|
|
119
|
+
title = self.clean_title(title) if title else "",
|
|
120
|
+
description = description.strip() if description else None,
|
|
121
|
+
tags = tags,
|
|
122
|
+
year = year,
|
|
123
|
+
rating = rating,
|
|
124
|
+
duration = int(duration) if duration else None,
|
|
125
|
+
actors = actors,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
async def load_links(self, url: str) -> list[dict]:
|
|
129
|
+
istek = await self.httpx.get(url)
|
|
130
|
+
secici = Selector(istek.text)
|
|
131
|
+
|
|
132
|
+
results = []
|
|
133
|
+
|
|
134
|
+
for player in secici.css("div#tv-spoox2"):
|
|
135
|
+
iframe = self.fix_url(player.css("iframe::attr(src)").get())
|
|
136
|
+
|
|
137
|
+
if iframe:
|
|
138
|
+
extractor = self.ex_manager.find_extractor(iframe)
|
|
139
|
+
results.append({
|
|
140
|
+
"name" : extractor.name if extractor else "Player",
|
|
141
|
+
"url" : iframe,
|
|
142
|
+
"referer" : f"{self.main_url}/"
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
return results
|