KekikStream 1.7.1__py3-none-any.whl → 2.2.0__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/Core/Extractor/ExtractorBase.py +20 -9
- 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 +44 -26
- KekikStream/Core/Media/MediaManager.py +0 -3
- KekikStream/Core/Plugin/PluginBase.py +82 -22
- KekikStream/Core/Plugin/PluginLoader.py +11 -7
- KekikStream/Core/Plugin/PluginModels.py +25 -26
- KekikStream/Core/__init__.py +1 -0
- KekikStream/Extractors/CloseLoad.py +21 -7
- KekikStream/Extractors/ContentX.py +21 -6
- KekikStream/Extractors/DonilasPlay.py +86 -0
- KekikStream/Extractors/DzenRu.py +38 -0
- KekikStream/Extractors/ExPlay.py +53 -0
- KekikStream/Extractors/Filemoon.py +78 -0
- KekikStream/Extractors/HDPlayerSystem.py +41 -0
- KekikStream/Extractors/JetTv.py +45 -0
- KekikStream/Extractors/MailRu.py +3 -4
- KekikStream/Extractors/MixPlayHD.py +2 -3
- KekikStream/Extractors/MixTiger.py +57 -0
- KekikStream/Extractors/MolyStream.py +5 -5
- KekikStream/Extractors/Odnoklassniki.py +13 -7
- KekikStream/Extractors/PeaceMakerst.py +10 -5
- KekikStream/Extractors/PixelDrain.py +1 -2
- KekikStream/Extractors/PlayerFilmIzle.py +65 -0
- KekikStream/Extractors/RapidVid.py +23 -8
- KekikStream/Extractors/SetPlay.py +66 -0
- KekikStream/Extractors/SetPrime.py +45 -0
- KekikStream/Extractors/SibNet.py +2 -3
- KekikStream/Extractors/Sobreatsesuyp.py +4 -5
- KekikStream/Extractors/TRsTX.py +4 -5
- KekikStream/Extractors/TauVideo.py +2 -3
- KekikStream/Extractors/TurboImgz.py +2 -3
- KekikStream/Extractors/TurkeyPlayer.py +34 -0
- KekikStream/Extractors/VCTPlay.py +41 -0
- KekikStream/Extractors/VidHide.py +81 -0
- KekikStream/Extractors/VidMoly.py +55 -34
- KekikStream/Extractors/VidMoxy.py +2 -3
- KekikStream/Extractors/VidPapi.py +89 -0
- KekikStream/Extractors/VideoSeyred.py +3 -4
- KekikStream/Extractors/YTDLP.py +211 -0
- KekikStream/Extractors/YildizKisaFilm.py +41 -0
- KekikStream/Plugins/BelgeselX.py +196 -0
- KekikStream/Plugins/DiziBox.py +25 -34
- KekikStream/Plugins/DiziPal.py +24 -35
- KekikStream/Plugins/DiziYou.py +54 -37
- KekikStream/Plugins/Dizilla.py +66 -46
- KekikStream/Plugins/FilmBip.py +142 -0
- KekikStream/Plugins/FilmMakinesi.py +36 -28
- KekikStream/Plugins/FilmModu.py +20 -24
- KekikStream/Plugins/FullHDFilm.py +220 -0
- KekikStream/Plugins/FullHDFilmizlesene.py +9 -15
- KekikStream/Plugins/HDFilmCehennemi.py +141 -69
- KekikStream/Plugins/JetFilmizle.py +85 -52
- KekikStream/Plugins/KultFilmler.py +217 -0
- KekikStream/Plugins/RecTV.py +22 -34
- KekikStream/Plugins/RoketDizi.py +222 -0
- KekikStream/Plugins/SelcukFlix.py +328 -0
- KekikStream/Plugins/SetFilmIzle.py +252 -0
- KekikStream/Plugins/SezonlukDizi.py +54 -21
- KekikStream/Plugins/SineWix.py +17 -29
- KekikStream/Plugins/Sinefy.py +241 -0
- KekikStream/Plugins/SinemaCX.py +154 -0
- KekikStream/Plugins/Sinezy.py +143 -0
- KekikStream/Plugins/SuperFilmGeldi.py +130 -0
- KekikStream/Plugins/UgurFilm.py +13 -19
- KekikStream/__init__.py +47 -56
- KekikStream/requirements.txt +3 -4
- kekikstream-2.2.0.dist-info/METADATA +312 -0
- kekikstream-2.2.0.dist-info/RECORD +81 -0
- KekikStream/Extractors/FourCX.py +0 -7
- KekikStream/Extractors/FourPichive.py +0 -7
- KekikStream/Extractors/FourPlayRu.py +0 -7
- KekikStream/Extractors/HDStreamAble.py +0 -7
- KekikStream/Extractors/Hotlinger.py +0 -7
- KekikStream/Extractors/OkRuHTTP.py +0 -7
- KekikStream/Extractors/OkRuSSL.py +0 -7
- KekikStream/Extractors/Pichive.py +0 -7
- KekikStream/Extractors/PlayRu.py +0 -7
- KekikStream/Extractors/VidMolyMe.py +0 -7
- kekikstream-1.7.1.dist-info/METADATA +0 -109
- kekikstream-1.7.1.dist-info/RECORD +0 -63
- {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.dist-info}/WHEEL +0 -0
- {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.dist-info}/entry_points.txt +0 -0
- {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.dist-info}/top_level.txt +0 -0
KekikStream/Plugins/Dizilla.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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, ExtractResult
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
from json import loads
|
|
6
6
|
from urllib.parse import urlparse, urlunparse
|
|
@@ -12,36 +12,47 @@ class Dizilla(PluginBase):
|
|
|
12
12
|
language = "tr"
|
|
13
13
|
main_url = "https://dizilla40.com"
|
|
14
14
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
15
|
-
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."
|
|
16
16
|
|
|
17
17
|
main_page = {
|
|
18
|
-
f"{main_url}/tum-bolumler"
|
|
19
|
-
f"{main_url}/
|
|
20
|
-
f"{main_url}/
|
|
21
|
-
f"{main_url}/
|
|
22
|
-
f"{main_url}/
|
|
23
|
-
f"{main_url}/
|
|
24
|
-
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",
|
|
25
34
|
}
|
|
26
35
|
|
|
27
|
-
#@kekik_cache(ttl=60*60)
|
|
28
36
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
29
|
-
istek = await self.cffi.get(url)
|
|
30
|
-
secici = Selector(istek.text)
|
|
31
|
-
|
|
32
37
|
ana_sayfa = []
|
|
33
38
|
|
|
34
|
-
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", [])
|
|
35
43
|
ana_sayfa.extend([
|
|
36
44
|
MainPageResult(
|
|
37
45
|
category = category,
|
|
38
|
-
title = veri.
|
|
39
|
-
url = self.fix_url(veri.
|
|
40
|
-
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")),
|
|
41
49
|
)
|
|
42
|
-
for veri in
|
|
50
|
+
for veri in veriler
|
|
43
51
|
])
|
|
44
52
|
else:
|
|
53
|
+
istek = await self.httpx.get(url.replace("SAYFA", str(page)))
|
|
54
|
+
secici = Selector(istek.text)
|
|
55
|
+
|
|
45
56
|
for veri in secici.css("div.tab-content > div.grid a"):
|
|
46
57
|
name = veri.css("h2::text").get()
|
|
47
58
|
ep_name = veri.xpath("normalize-space(//div[contains(@class, 'opacity-80')])").get()
|
|
@@ -51,7 +62,7 @@ class Dizilla(PluginBase):
|
|
|
51
62
|
ep_name = ep_name.replace(". Sezon", "x").replace(". Bölüm", "").replace("x ", "x")
|
|
52
63
|
title = f"{name} - {ep_name}"
|
|
53
64
|
|
|
54
|
-
ep_req = await self.
|
|
65
|
+
ep_req = await self.httpx.get(self.fix_url(veri.css("::attr(href)").get()))
|
|
55
66
|
ep_secici = Selector(ep_req.text)
|
|
56
67
|
href = self.fix_url(ep_secici.css("nav li:nth-of-type(3) a::attr(href)").get())
|
|
57
68
|
poster = self.fix_url(ep_secici.css("img.imgt::attr(src)").get())
|
|
@@ -88,9 +99,8 @@ class Dizilla(PluginBase):
|
|
|
88
99
|
# JSON decode
|
|
89
100
|
return loads(decrypted.decode("utf-8"))
|
|
90
101
|
|
|
91
|
-
#@kekik_cache(ttl=60*60)
|
|
92
102
|
async def search(self, query: str) -> list[SearchResult]:
|
|
93
|
-
arama_istek = await self.
|
|
103
|
+
arama_istek = await self.httpx.post(f"{self.main_url}/api/bg/searchcontent?searchterm={query}")
|
|
94
104
|
decrypted = await self.decrypt_response(arama_istek.json().get("response"))
|
|
95
105
|
arama_veri = decrypted.get("result", [])
|
|
96
106
|
|
|
@@ -103,7 +113,6 @@ class Dizilla(PluginBase):
|
|
|
103
113
|
for veri in arama_veri
|
|
104
114
|
]
|
|
105
115
|
|
|
106
|
-
#@kekik_cache(ttl=60*60)
|
|
107
116
|
async def url_base_degis(self, eski_url:str, yeni_base:str) -> str:
|
|
108
117
|
parsed_url = urlparse(eski_url)
|
|
109
118
|
parsed_yeni_base = urlparse(yeni_base)
|
|
@@ -114,27 +123,34 @@ class Dizilla(PluginBase):
|
|
|
114
123
|
|
|
115
124
|
return urlunparse(yeni_url)
|
|
116
125
|
|
|
117
|
-
#@kekik_cache(ttl=60*60)
|
|
118
126
|
async def load_item(self, url: str) -> SeriesInfo:
|
|
119
|
-
istek = await self.
|
|
127
|
+
istek = await self.httpx.get(url)
|
|
120
128
|
secici = Selector(istek.text)
|
|
121
129
|
veri = loads(secici.xpath("//script[@type='application/ld+json']/text()").getall()[-1])
|
|
122
130
|
|
|
123
|
-
title
|
|
131
|
+
title = veri.get("name")
|
|
124
132
|
if alt_title := veri.get("alternateName"):
|
|
125
133
|
title += f" - ({alt_title})"
|
|
126
134
|
|
|
127
135
|
poster = self.fix_url(veri.get("image"))
|
|
128
136
|
description = veri.get("description")
|
|
129
137
|
year = veri.get("datePublished").split("-")[0]
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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")]
|
|
133
145
|
|
|
134
146
|
bolumler = []
|
|
135
147
|
sezonlar = veri.get("containsSeason") if isinstance(veri.get("containsSeason"), list) else [veri.get("containsSeason")]
|
|
136
148
|
for sezon in sezonlar:
|
|
137
|
-
|
|
149
|
+
episodes = sezon.get("episode")
|
|
150
|
+
if isinstance(episodes, dict):
|
|
151
|
+
episodes = [episodes]
|
|
152
|
+
|
|
153
|
+
for bolum in episodes:
|
|
138
154
|
bolumler.append(Episode(
|
|
139
155
|
season = sezon.get("seasonNumber"),
|
|
140
156
|
episode = bolum.get("episodeNumber"),
|
|
@@ -154,9 +170,8 @@ class Dizilla(PluginBase):
|
|
|
154
170
|
actors = actors
|
|
155
171
|
)
|
|
156
172
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
istek = await self.cffi.get(url)
|
|
173
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
174
|
+
istek = await self.httpx.get(url)
|
|
160
175
|
secici = Selector(istek.text)
|
|
161
176
|
|
|
162
177
|
next_data = loads(secici.css("script#__NEXT_DATA__::text").get())
|
|
@@ -164,17 +179,22 @@ class Dizilla(PluginBase):
|
|
|
164
179
|
decrypted = await self.decrypt_response(secure_data)
|
|
165
180
|
results = decrypted.get("RelatedResults", {}).get("getEpisodeSources", {}).get("result", [])
|
|
166
181
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
182
|
+
if not results:
|
|
183
|
+
return []
|
|
184
|
+
|
|
185
|
+
# Get first source (matching Kotlin)
|
|
186
|
+
first_result = results[0]
|
|
187
|
+
source_content = first_result.get("source_content", "")
|
|
188
|
+
|
|
189
|
+
# Clean the source_content string (matching Kotlin: .replace("\"", "").replace("\\", ""))
|
|
190
|
+
cleaned_source = source_content.replace('"', '').replace('\\', '')
|
|
191
|
+
|
|
192
|
+
# Parse cleaned HTML
|
|
193
|
+
iframe_src = Selector(cleaned_source).css("iframe::attr(src)").get()
|
|
194
|
+
iframe_url = self.fix_url(iframe_src)
|
|
195
|
+
|
|
196
|
+
if not iframe_url:
|
|
197
|
+
return []
|
|
198
|
+
|
|
199
|
+
data = await self.extract(iframe_url, prefix=first_result.get('language_name', 'Unknown'))
|
|
200
|
+
return [data] if data else []
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult
|
|
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[ExtractResult]:
|
|
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
|
+
data = await self.extract(iframe)
|
|
139
|
+
if data:
|
|
140
|
+
results.append(data)
|
|
141
|
+
|
|
142
|
+
return results
|
|
@@ -1,6 +1,6 @@
|
|
|
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, MovieInfo, ExtractResult
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
|
|
6
6
|
class FilmMakinesi(PluginBase):
|
|
@@ -8,7 +8,7 @@ class FilmMakinesi(PluginBase):
|
|
|
8
8
|
language = "tr"
|
|
9
9
|
main_url = "https://filmmakinesi.to"
|
|
10
10
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
11
|
-
description = "Film Makinesi
|
|
11
|
+
description = "Film Makinesi ile en yeni ve güncel filmleri Full HD kalite farkı ile izleyebilirsiniz. Film izle denildiğinde akla gelen en kaliteli film sitesi."
|
|
12
12
|
|
|
13
13
|
main_page = {
|
|
14
14
|
f"{main_url}/filmler-1/" : "Son Filmler",
|
|
@@ -34,7 +34,6 @@ class FilmMakinesi(PluginBase):
|
|
|
34
34
|
f"{main_url}/tur/western-fm1/film/" : "Western"
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
#@kekik_cache(ttl=60*60)
|
|
38
37
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
39
38
|
istek = self.cloudscraper.get(f"{url}{'' if page == 1 else f'page/{page}/'}")
|
|
40
39
|
secici = Selector(istek.text)
|
|
@@ -51,9 +50,8 @@ class FilmMakinesi(PluginBase):
|
|
|
51
50
|
for veri in veriler
|
|
52
51
|
]
|
|
53
52
|
|
|
54
|
-
#@kekik_cache(ttl=60*60)
|
|
55
53
|
async def search(self, query: str) -> list[SearchResult]:
|
|
56
|
-
istek = await self.
|
|
54
|
+
istek = await self.httpx.get(f"{self.main_url}/arama/?s={query}")
|
|
57
55
|
secici = Selector(istek.text)
|
|
58
56
|
|
|
59
57
|
results = []
|
|
@@ -73,51 +71,61 @@ class FilmMakinesi(PluginBase):
|
|
|
73
71
|
|
|
74
72
|
return results
|
|
75
73
|
|
|
76
|
-
#@kekik_cache(ttl=60*60)
|
|
77
74
|
async def load_item(self, url: str) -> MovieInfo:
|
|
78
|
-
istek = await self.
|
|
75
|
+
istek = await self.httpx.get(url)
|
|
79
76
|
secici = Selector(istek.text)
|
|
80
77
|
|
|
81
|
-
title = secici.css("h1.title::text").get()
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
title = secici.css("h1.title::text").get()
|
|
79
|
+
title = title.strip() if title else ""
|
|
80
|
+
poster = secici.css("img.cover-img::attr(src)").get()
|
|
81
|
+
poster = poster.strip() if poster else ""
|
|
82
|
+
description = secici.css("div.info-description p::text").get()
|
|
83
|
+
description = description.strip() if description else ""
|
|
84
84
|
rating = secici.css("div.score::text").get()
|
|
85
85
|
if rating:
|
|
86
86
|
rating = rating.strip().split()[0]
|
|
87
|
-
year = secici.css("span.date a::text").get()
|
|
87
|
+
year = secici.css("span.date a::text").get()
|
|
88
|
+
year = year.strip() if year else ""
|
|
88
89
|
actors = secici.css("div.cast-name::text").getall()
|
|
90
|
+
tags = secici.css("div.genre a::text").getall()
|
|
89
91
|
duration = secici.css("div.time::text").get()
|
|
90
92
|
if duration:
|
|
91
|
-
duration = duration.split()[1].strip()
|
|
93
|
+
duration = duration.split()[1].strip() if len(duration.split()) > 1 else ""
|
|
92
94
|
|
|
93
95
|
return MovieInfo(
|
|
94
96
|
url = url,
|
|
95
97
|
poster = self.fix_url(poster),
|
|
96
98
|
title = self.clean_title(title),
|
|
97
99
|
description = description,
|
|
100
|
+
tags = tags,
|
|
98
101
|
rating = rating,
|
|
99
102
|
year = year,
|
|
100
103
|
actors = actors,
|
|
101
104
|
duration = duration
|
|
102
105
|
)
|
|
103
106
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
istek = await self.cffi.get(url)
|
|
107
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
108
|
+
istek = await self.httpx.get(url)
|
|
107
109
|
secici = Selector(istek.text)
|
|
108
110
|
|
|
109
|
-
|
|
111
|
+
response = []
|
|
110
112
|
|
|
111
|
-
|
|
113
|
+
# Video parts linklerini ve etiketlerini al
|
|
112
114
|
for link in secici.css("div.video-parts a[data-video_url]"):
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
115
|
+
video_url = link.attrib.get("data-video_url")
|
|
116
|
+
label = link.css("::text").get() or ""
|
|
117
|
+
label = label.strip()
|
|
118
|
+
|
|
119
|
+
data = await self.extract(video_url, prefix=label.split()[0] if label else None)
|
|
120
|
+
if data:
|
|
121
|
+
response.append(data)
|
|
122
|
+
|
|
123
|
+
# Eğer video-parts yoksa iframe kullan
|
|
124
|
+
if not response:
|
|
125
|
+
iframe_src = secici.css("iframe::attr(data-src)").get()
|
|
126
|
+
if iframe_src:
|
|
127
|
+
data = await self.extract(iframe_src)
|
|
128
|
+
if data:
|
|
129
|
+
response.append(data)
|
|
130
|
+
|
|
131
|
+
return response
|
KekikStream/Plugins/FilmModu.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo,
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, Subtitle, ExtractResult
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
import re
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ class FilmModu(PluginBase):
|
|
|
9
9
|
language = "tr"
|
|
10
10
|
main_url = "https://www.filmmodu.ws"
|
|
11
11
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
12
|
-
description = "
|
|
12
|
+
description = "Film modun geldiyse yüksek kalitede yeni filmleri izle, 1080p izleyebileceğiniz reklamsız tek film sitesi."
|
|
13
13
|
|
|
14
14
|
main_page = {
|
|
15
15
|
f"{main_url}/hd-film-kategori/4k-film-izle?page=SAYFA" : "4K",
|
|
@@ -41,7 +41,7 @@ class FilmModu(PluginBase):
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
44
|
-
istek = await self.
|
|
44
|
+
istek = await self.httpx.get(url.replace("SAYFA", str(page)))
|
|
45
45
|
secici = Selector(istek.text)
|
|
46
46
|
|
|
47
47
|
return [
|
|
@@ -56,7 +56,7 @@ class FilmModu(PluginBase):
|
|
|
56
56
|
]
|
|
57
57
|
|
|
58
58
|
async def search(self, query: str) -> list[SearchResult]:
|
|
59
|
-
istek = await self.
|
|
59
|
+
istek = await self.httpx.get(f"{self.main_url}/film-ara?term={query}")
|
|
60
60
|
secici = Selector(istek.text)
|
|
61
61
|
|
|
62
62
|
return [
|
|
@@ -70,7 +70,7 @@ class FilmModu(PluginBase):
|
|
|
70
70
|
]
|
|
71
71
|
|
|
72
72
|
async def load_item(self, url: str) -> MovieInfo:
|
|
73
|
-
istek = await self.
|
|
73
|
+
istek = await self.httpx.get(url)
|
|
74
74
|
secici = Selector(istek.text)
|
|
75
75
|
|
|
76
76
|
org_title = secici.css("div.titles h1::text").get()
|
|
@@ -87,20 +87,24 @@ class FilmModu(PluginBase):
|
|
|
87
87
|
actors = [a.css("span::text").get() for a in secici.css("a[itemprop='actor']")],
|
|
88
88
|
)
|
|
89
89
|
|
|
90
|
-
async def load_links(self, url: str) -> list[
|
|
91
|
-
istek = await self.
|
|
90
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
91
|
+
istek = await self.httpx.get(url)
|
|
92
92
|
secici = Selector(istek.text)
|
|
93
93
|
|
|
94
|
+
alternates = secici.css("div.alternates a")
|
|
95
|
+
if not alternates:
|
|
96
|
+
return [] # No alternates available
|
|
97
|
+
|
|
94
98
|
results = []
|
|
95
99
|
|
|
96
|
-
for alternatif in
|
|
100
|
+
for alternatif in alternates:
|
|
97
101
|
alt_link = self.fix_url(alternatif.css("::attr(href)").get())
|
|
98
102
|
alt_name = alternatif.css("::text").get()
|
|
99
103
|
|
|
100
104
|
if alt_name == "Fragman" or not alt_link:
|
|
101
105
|
continue
|
|
102
106
|
|
|
103
|
-
alt_istek = await self.
|
|
107
|
+
alt_istek = await self.httpx.get(alt_link)
|
|
104
108
|
alt_text = alt_istek.text
|
|
105
109
|
|
|
106
110
|
vid_id = re.search(r"var videoId = '(.*)'", alt_text)
|
|
@@ -109,7 +113,7 @@ class FilmModu(PluginBase):
|
|
|
109
113
|
if not vid_id or not vid_type:
|
|
110
114
|
continue
|
|
111
115
|
|
|
112
|
-
source_istek = await self.
|
|
116
|
+
source_istek = await self.httpx.get(
|
|
113
117
|
f"{self.main_url}/get-source?movie_id={vid_id[1]}&type={vid_type[1]}"
|
|
114
118
|
)
|
|
115
119
|
source_data = source_istek.json()
|
|
@@ -120,19 +124,11 @@ class FilmModu(PluginBase):
|
|
|
120
124
|
subtitle_url = None
|
|
121
125
|
|
|
122
126
|
for source in source_data.get("sources", []):
|
|
123
|
-
results.append(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
results.append(ExtractResult(
|
|
128
|
+
name = f"{self.name} | {alt_name} | {source.get('label', 'Bilinmiyor')}",
|
|
129
|
+
url = self.fix_url(source["src"]),
|
|
130
|
+
referer = f"{self.main_url}/",
|
|
131
|
+
subtitles = [Subtitle(name="Türkçe", url=subtitle_url)] if subtitle_url else []
|
|
132
|
+
))
|
|
129
133
|
|
|
130
134
|
return results
|
|
131
|
-
|
|
132
|
-
async def play(self, name: str, url: str, referer: str, subtitles: list[Subtitle]):
|
|
133
|
-
extract_result = ExtractResult(name=name, url=url, referer=referer, subtitles=subtitles)
|
|
134
|
-
self.media_handler.title = name
|
|
135
|
-
if self.name not in self.media_handler.title:
|
|
136
|
-
self.media_handler.title = f"{self.name} | {self.media_handler.title}"
|
|
137
|
-
|
|
138
|
-
self.media_handler.play_media(extract_result)
|