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
|
@@ -1,14 +1,15 @@
|
|
|
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
|
+
import re
|
|
5
6
|
|
|
6
7
|
class JetFilmizle(PluginBase):
|
|
7
8
|
name = "JetFilmizle"
|
|
8
9
|
language = "tr"
|
|
9
10
|
main_url = "https://jetfilmizle.website"
|
|
10
11
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
11
|
-
description = "
|
|
12
|
+
description = "Film izle, Yerli, Yabancı film izle, Türkçe dublaj, alt yazılı seçenekleriyle ödül almış filmleri Full HD kalitesiyle ve jetfilmizle hızıyla donmadan ücretsizce izleyebilirsiniz."
|
|
12
13
|
|
|
13
14
|
main_page = {
|
|
14
15
|
f"{main_url}/page/" : "Son Filmler",
|
|
@@ -16,12 +17,29 @@ class JetFilmizle(PluginBase):
|
|
|
16
17
|
f"{main_url}/editorun-secimi/page/" : "Editörün Seçimi",
|
|
17
18
|
f"{main_url}/turk-film-izle/page/" : "Türk Filmleri",
|
|
18
19
|
f"{main_url}/cizgi-filmler-izle/page/" : "Çizgi Filmler",
|
|
19
|
-
f"{main_url}/kategoriler/yesilcam-filmleri-izlee/page/" : "Yeşilçam Filmleri"
|
|
20
|
+
f"{main_url}/kategoriler/yesilcam-filmleri-izlee/page/" : "Yeşilçam Filmleri",
|
|
21
|
+
f"{main_url}/film-turu/aile-filmleri-izle/page/" : "Aile Filmleri",
|
|
22
|
+
f"{main_url}/film-turu/aksiyon-filmleri/page/" : "Aksiyon Filmleri",
|
|
23
|
+
f"{main_url}/film-turu/animasyon-filmler-izle/page/" : "Animasyon Filmleri",
|
|
24
|
+
f"{main_url}/film-turu/bilim-kurgu-filmler/page/" : "Bilim Kurgu Filmleri",
|
|
25
|
+
f"{main_url}/film-turu/dram-filmleri-izle/page/" : "Dram Filmleri",
|
|
26
|
+
f"{main_url}/film-turu/fantastik-filmleri-izle/page/" : "Fantastik Filmler",
|
|
27
|
+
f"{main_url}/film-turu/gerilim-filmleri/page/" : "Gerilim Filmleri",
|
|
28
|
+
f"{main_url}/film-turu/gizem-filmleri/page/" : "Gizem Filmleri",
|
|
29
|
+
f"{main_url}/film-turu/komedi-film-full-izle/page/" : "Komedi Filmleri",
|
|
30
|
+
f"{main_url}/film-turu/korku-filmleri-izle/page/" : "Korku Filmleri",
|
|
31
|
+
f"{main_url}/film-turu/macera-filmleri/page/" : "Macera Filmleri",
|
|
32
|
+
f"{main_url}/film-turu/muzikal/page/" : "Müzikal Filmler",
|
|
33
|
+
f"{main_url}/film-turu/polisiye/page/" : "Polisiye Filmler",
|
|
34
|
+
f"{main_url}/film-turu/romantik-film-izle/page/" : "Romantik Filmler",
|
|
35
|
+
f"{main_url}/film-turu/savas-filmi-izle/page/" : "Savaş Filmleri",
|
|
36
|
+
f"{main_url}/film-turu/spor/page/" : "Spor Filmleri",
|
|
37
|
+
f"{main_url}/film-turu/suc-filmleri/page/" : "Suç Filmleri",
|
|
38
|
+
f"{main_url}/film-turu/tarihi-filmler/page/" : "Tarihi Filmleri",
|
|
20
39
|
}
|
|
21
40
|
|
|
22
|
-
#@kekik_cache(ttl=60*60)
|
|
23
41
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
24
|
-
istek = await self.
|
|
42
|
+
istek = await self.httpx.get(f"{url}{page}", follow_redirects=True)
|
|
25
43
|
secici = Selector(istek.text)
|
|
26
44
|
|
|
27
45
|
return [
|
|
@@ -34,9 +52,8 @@ class JetFilmizle(PluginBase):
|
|
|
34
52
|
for veri in secici.css("article.movie") if veri.css("h2 a::text, h3 a::text, h4 a::text, h5 a::text, h6 a::text").get()
|
|
35
53
|
]
|
|
36
54
|
|
|
37
|
-
#@kekik_cache(ttl=60*60)
|
|
38
55
|
async def search(self, query: str) -> list[SearchResult]:
|
|
39
|
-
istek = await self.
|
|
56
|
+
istek = await self.httpx.post(
|
|
40
57
|
url = f"{self.main_url}/filmara.php",
|
|
41
58
|
data = {"s": query},
|
|
42
59
|
headers = {"Referer": f"{self.main_url}/"}
|
|
@@ -60,18 +77,31 @@ class JetFilmizle(PluginBase):
|
|
|
60
77
|
|
|
61
78
|
return results
|
|
62
79
|
|
|
63
|
-
#@kekik_cache(ttl=60*60)
|
|
64
80
|
async def load_item(self, url: str) -> MovieInfo:
|
|
65
|
-
istek = await self.
|
|
81
|
+
istek = await self.httpx.get(url)
|
|
66
82
|
secici = Selector(istek.text)
|
|
67
83
|
|
|
68
84
|
title = self.clean_title(secici.css("div.movie-exp-title::text").get())
|
|
69
|
-
|
|
70
|
-
|
|
85
|
+
poster_raw = secici.css("section.movie-exp img::attr(data-src), section.movie-exp img::attr(src)").get()
|
|
86
|
+
poster = poster_raw.strip() if poster_raw else None
|
|
87
|
+
|
|
88
|
+
desc_raw = secici.css("section.movie-exp p.aciklama::text").get()
|
|
89
|
+
description = desc_raw.strip() if desc_raw else None
|
|
90
|
+
|
|
71
91
|
tags = secici.css("section.movie-exp div.catss a::text").getall()
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
92
|
+
|
|
93
|
+
rating_raw = secici.css("section.movie-exp div.imdb_puan span::text").get()
|
|
94
|
+
rating = rating_raw.strip() if rating_raw else None
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# Year - div.yap içinde 4 haneli sayı ara
|
|
98
|
+
year_div = secici.xpath("//div[@class='yap' and (contains(., 'Vizyon') or contains(., 'Yapım'))]/text()").get()
|
|
99
|
+
year = None
|
|
100
|
+
if year_div:
|
|
101
|
+
year_match = re.search(r'(\d{4})', year_div.strip())
|
|
102
|
+
if year_match:
|
|
103
|
+
year = year_match.group(1)
|
|
104
|
+
|
|
75
105
|
actors = secici.css("div[itemprop='actor'] a span::text").getall()
|
|
76
106
|
|
|
77
107
|
return MovieInfo(
|
|
@@ -85,47 +115,50 @@ class JetFilmizle(PluginBase):
|
|
|
85
115
|
actors = actors
|
|
86
116
|
)
|
|
87
117
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
istek = await self.cffi.get(url)
|
|
118
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
119
|
+
istek = await self.httpx.get(url)
|
|
91
120
|
secici = Selector(istek.text)
|
|
92
121
|
|
|
93
|
-
|
|
94
|
-
if main_iframe := secici.css("div#movie iframe::attr(data-src), div#movie iframe::attr(data), div#movie iframe::attr(src)").get():
|
|
95
|
-
iframes.append(self.fix_url(main_iframe))
|
|
122
|
+
results = []
|
|
96
123
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
124
|
+
# 1) Ana iframe'leri kontrol et
|
|
125
|
+
for iframe in secici.css("iframe"):
|
|
126
|
+
src = (iframe.css("::attr(src)").get() or
|
|
127
|
+
iframe.css("::attr(data-src)").get() or
|
|
128
|
+
iframe.css("::attr(data-lazy-src)").get())
|
|
129
|
+
|
|
130
|
+
if src and src != "about:blank":
|
|
131
|
+
iframe_url = self.fix_url(src)
|
|
132
|
+
data = await self.extract(iframe_url)
|
|
133
|
+
if data:
|
|
134
|
+
results.append(data)
|
|
135
|
+
|
|
136
|
+
# 2) Sayfa numaralarından linkleri topla (Fragman hariç)
|
|
137
|
+
page_links = []
|
|
138
|
+
for link in secici.css("a.post-page-numbers"):
|
|
139
|
+
isim = link.css("span::text").get() or ""
|
|
140
|
+
if isim != "Fragman":
|
|
141
|
+
href = link.css("::attr(href)").get()
|
|
142
|
+
if href:
|
|
143
|
+
page_links.append((self.fix_url(href), isim))
|
|
144
|
+
|
|
145
|
+
# 3) Her sayfa linkindeki iframe'leri bul
|
|
146
|
+
for page_url, isim in page_links:
|
|
147
|
+
try:
|
|
148
|
+
page_resp = await self.httpx.get(page_url)
|
|
149
|
+
page_sel = Selector(page_resp.text)
|
|
150
|
+
|
|
151
|
+
for iframe in page_sel.css("div#movie iframe"):
|
|
152
|
+
src = (iframe.css("::attr(src)").get() or
|
|
153
|
+
iframe.css("::attr(data-src)").get() or
|
|
154
|
+
iframe.css("::attr(data-lazy-src)").get())
|
|
155
|
+
|
|
156
|
+
if src and src != "about:blank":
|
|
157
|
+
iframe_url = self.fix_url(src)
|
|
158
|
+
data = await self.extract(iframe_url, prefix=isim)
|
|
159
|
+
if data:
|
|
160
|
+
results.append(data)
|
|
161
|
+
except Exception:
|
|
100
162
|
continue
|
|
101
163
|
|
|
102
|
-
part_istek = await self.cffi.get(part_href)
|
|
103
|
-
part_secici = Selector(part_istek.text)
|
|
104
|
-
|
|
105
|
-
if iframe := part_secici.css("div#movie iframe::attr(data-src), div#movie iframe::attr(data), div#movie iframe::attr(src)").get():
|
|
106
|
-
iframes.append(self.fix_url(iframe))
|
|
107
|
-
else:
|
|
108
|
-
for link in part_secici.css("div#movie p a"):
|
|
109
|
-
if download_link := link.attrib.get("href"):
|
|
110
|
-
iframes.append(self.fix_url(download_link))
|
|
111
|
-
|
|
112
|
-
processed_iframes = []
|
|
113
|
-
for iframe in iframes:
|
|
114
|
-
if "jetv.xyz" in iframe:
|
|
115
|
-
jetv_istek = await self.cffi.get(iframe)
|
|
116
|
-
jetv_secici = Selector(jetv_istek.text)
|
|
117
|
-
|
|
118
|
-
if jetv_iframe := jetv_secici.css("iframe::attr(src)").get():
|
|
119
|
-
processed_iframes.append(self.fix_url(jetv_iframe))
|
|
120
|
-
else:
|
|
121
|
-
processed_iframes.append(iframe)
|
|
122
|
-
|
|
123
|
-
results = []
|
|
124
|
-
for idx, iframe in enumerate(processed_iframes):
|
|
125
|
-
extractor = self.ex_manager.find_extractor(iframe)
|
|
126
|
-
results.append({
|
|
127
|
-
"url" : iframe,
|
|
128
|
-
"name" : f"{extractor.name if extractor else f'Player {idx + 1}'}"
|
|
129
|
-
})
|
|
130
|
-
|
|
131
164
|
return results
|
|
@@ -0,0 +1,217 @@
|
|
|
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, Subtitle
|
|
4
|
+
from parsel import Selector
|
|
5
|
+
import re, base64
|
|
6
|
+
|
|
7
|
+
class KultFilmler(PluginBase):
|
|
8
|
+
name = "KultFilmler"
|
|
9
|
+
language = "tr"
|
|
10
|
+
main_url = "https://kultfilmler.net"
|
|
11
|
+
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
12
|
+
description = "Kült Filmler özenle en iyi filmleri derler ve iyi bir altyazılı film izleme deneyimi sunmayı amaçlar. Reklamsız 1080P Altyazılı Film izle..."
|
|
13
|
+
|
|
14
|
+
main_page = {
|
|
15
|
+
f"{main_url}/category/aile-filmleri-izle" : "Aile",
|
|
16
|
+
f"{main_url}/category/aksiyon-filmleri-izle" : "Aksiyon",
|
|
17
|
+
f"{main_url}/category/animasyon-filmleri-izle" : "Animasyon",
|
|
18
|
+
f"{main_url}/category/belgesel-izle" : "Belgesel",
|
|
19
|
+
f"{main_url}/category/bilim-kurgu-filmleri-izle": "Bilim Kurgu",
|
|
20
|
+
f"{main_url}/category/biyografi-filmleri-izle" : "Biyografi",
|
|
21
|
+
f"{main_url}/category/dram-filmleri-izle" : "Dram",
|
|
22
|
+
f"{main_url}/category/fantastik-filmleri-izle" : "Fantastik",
|
|
23
|
+
f"{main_url}/category/gerilim-filmleri-izle" : "Gerilim",
|
|
24
|
+
f"{main_url}/category/gizem-filmleri-izle" : "Gizem",
|
|
25
|
+
f"{main_url}/category/kara-filmleri-izle" : "Kara Film",
|
|
26
|
+
f"{main_url}/category/kisa-film-izle" : "Kısa Metraj",
|
|
27
|
+
f"{main_url}/category/komedi-filmleri-izle" : "Komedi",
|
|
28
|
+
f"{main_url}/category/korku-filmleri-izle" : "Korku",
|
|
29
|
+
f"{main_url}/category/macera-filmleri-izle" : "Macera",
|
|
30
|
+
f"{main_url}/category/muzik-filmleri-izle" : "Müzik",
|
|
31
|
+
f"{main_url}/category/polisiye-filmleri-izle" : "Polisiye",
|
|
32
|
+
f"{main_url}/category/romantik-filmleri-izle" : "Romantik",
|
|
33
|
+
f"{main_url}/category/savas-filmleri-izle" : "Savaş",
|
|
34
|
+
f"{main_url}/category/suc-filmleri-izle" : "Suç",
|
|
35
|
+
f"{main_url}/category/tarih-filmleri-izle" : "Tarih",
|
|
36
|
+
f"{main_url}/category/yerli-filmleri-izle" : "Yerli",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
40
|
+
istek = await self.httpx.get(url)
|
|
41
|
+
secici = Selector(istek.text)
|
|
42
|
+
|
|
43
|
+
results = []
|
|
44
|
+
for veri in secici.css("div.col-md-12 div.movie-box"):
|
|
45
|
+
title = veri.css("div.img img::attr(alt)").get()
|
|
46
|
+
href = self.fix_url(veri.css("a::attr(href)").get())
|
|
47
|
+
poster = self.fix_url(veri.css("div.img img::attr(src)").get())
|
|
48
|
+
|
|
49
|
+
if title and href:
|
|
50
|
+
results.append(MainPageResult(
|
|
51
|
+
category = category,
|
|
52
|
+
title = title,
|
|
53
|
+
url = href,
|
|
54
|
+
poster = poster,
|
|
55
|
+
))
|
|
56
|
+
|
|
57
|
+
return results
|
|
58
|
+
|
|
59
|
+
async def search(self, query: str) -> list[SearchResult]:
|
|
60
|
+
istek = await self.httpx.get(f"{self.main_url}?s={query}")
|
|
61
|
+
secici = Selector(istek.text)
|
|
62
|
+
|
|
63
|
+
results = []
|
|
64
|
+
for veri in secici.css("div.movie-box"):
|
|
65
|
+
title = veri.css("div.img img::attr(alt)").get()
|
|
66
|
+
href = self.fix_url(veri.css("a::attr(href)").get())
|
|
67
|
+
poster = self.fix_url(veri.css("div.img img::attr(src)").get())
|
|
68
|
+
|
|
69
|
+
if title and href:
|
|
70
|
+
results.append(SearchResult(
|
|
71
|
+
title = title,
|
|
72
|
+
url = href,
|
|
73
|
+
poster = poster,
|
|
74
|
+
))
|
|
75
|
+
|
|
76
|
+
return results
|
|
77
|
+
|
|
78
|
+
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
79
|
+
istek = await self.httpx.get(url)
|
|
80
|
+
secici = Selector(istek.text)
|
|
81
|
+
|
|
82
|
+
title = secici.css("div.film-bilgileri img::attr(alt)").get() or secici.css("[property='og:title']::attr(content)").get()
|
|
83
|
+
poster = self.fix_url(secici.css("[property='og:image']::attr(content)").get())
|
|
84
|
+
description = secici.css("div.description::text").get()
|
|
85
|
+
tags = secici.css("ul.post-categories a::text").getall()
|
|
86
|
+
# HTML analizine göre güncellenen alanlar
|
|
87
|
+
year = secici.css("li.release span a::text").get()
|
|
88
|
+
duration = secici.css("li.time span::text").re_first(r"(\d+)")
|
|
89
|
+
rating = secici.css("div.imdb-count::text").get()
|
|
90
|
+
actors = secici.css("div.actors a::text").getall()
|
|
91
|
+
if rating:
|
|
92
|
+
rating = rating.strip()
|
|
93
|
+
|
|
94
|
+
# Dizi mi kontrol et
|
|
95
|
+
if "/dizi/" in url:
|
|
96
|
+
episodes = []
|
|
97
|
+
for bolum in secici.css("div.episode-box"):
|
|
98
|
+
ep_href = self.fix_url(bolum.css("div.name a::attr(href)").get())
|
|
99
|
+
ssn_detail = bolum.css("span.episodetitle::text").get() or ""
|
|
100
|
+
ep_detail = bolum.css("span.episodetitle b::text").get() or ""
|
|
101
|
+
ep_name = f"{ssn_detail} - {ep_detail}"
|
|
102
|
+
|
|
103
|
+
if ep_href:
|
|
104
|
+
ep_season = re.search(r"(\d+)\.", ssn_detail)
|
|
105
|
+
ep_episode = re.search(r"(\d+)\.", ep_detail)
|
|
106
|
+
|
|
107
|
+
episodes.append(Episode(
|
|
108
|
+
season = int(ep_season[1]) if ep_season else 1,
|
|
109
|
+
episode = int(ep_episode[1]) if ep_episode else 1,
|
|
110
|
+
title = ep_name.strip(" -"),
|
|
111
|
+
url = ep_href,
|
|
112
|
+
))
|
|
113
|
+
|
|
114
|
+
return SeriesInfo(
|
|
115
|
+
url = url,
|
|
116
|
+
poster = poster,
|
|
117
|
+
title = self.clean_title(title) if title else "",
|
|
118
|
+
description = description,
|
|
119
|
+
tags = tags,
|
|
120
|
+
year = year,
|
|
121
|
+
actors = actors,
|
|
122
|
+
rating = rating,
|
|
123
|
+
episodes = episodes,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
return MovieInfo(
|
|
127
|
+
url = url,
|
|
128
|
+
poster = poster,
|
|
129
|
+
title = self.clean_title(title) if title else "",
|
|
130
|
+
description = description,
|
|
131
|
+
tags = tags,
|
|
132
|
+
year = year,
|
|
133
|
+
rating = rating,
|
|
134
|
+
actors = actors,
|
|
135
|
+
duration = int(duration) if duration else None,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
def _get_iframe(self, source_code: str) -> str:
|
|
139
|
+
"""Base64 kodlu iframe'i çözümle"""
|
|
140
|
+
atob_match = re.search(r"PHA\+[0-9a-zA-Z+/=]*", source_code)
|
|
141
|
+
if not atob_match:
|
|
142
|
+
return ""
|
|
143
|
+
|
|
144
|
+
atob = atob_match.group()
|
|
145
|
+
|
|
146
|
+
# Padding düzelt
|
|
147
|
+
padding = 4 - len(atob) % 4
|
|
148
|
+
if padding < 4:
|
|
149
|
+
atob = atob + "=" * padding
|
|
150
|
+
|
|
151
|
+
try:
|
|
152
|
+
decoded = base64.b64decode(atob).decode("utf-8")
|
|
153
|
+
secici = Selector(text=decoded)
|
|
154
|
+
return self.fix_url(secici.css("iframe::attr(src)").get()) or ""
|
|
155
|
+
except Exception:
|
|
156
|
+
return ""
|
|
157
|
+
|
|
158
|
+
def _extract_subtitle_url(self, source_code: str) -> str | None:
|
|
159
|
+
"""Altyazı URL'sini çıkar"""
|
|
160
|
+
match = re.search(r"(https?://[^\s\"]+\.srt)", source_code)
|
|
161
|
+
return match[1] if match else None
|
|
162
|
+
|
|
163
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
164
|
+
istek = await self.httpx.get(url)
|
|
165
|
+
secici = Selector(istek.text)
|
|
166
|
+
|
|
167
|
+
iframes = set()
|
|
168
|
+
|
|
169
|
+
# Ana iframe
|
|
170
|
+
main_frame = self._get_iframe(istek.text)
|
|
171
|
+
if main_frame:
|
|
172
|
+
iframes.add(main_frame)
|
|
173
|
+
|
|
174
|
+
# Alternatif player'lar
|
|
175
|
+
for player in secici.css("div.container#player"):
|
|
176
|
+
alt_iframe = self.fix_url(player.css("iframe::attr(src)").get())
|
|
177
|
+
if alt_iframe:
|
|
178
|
+
alt_istek = await self.httpx.get(alt_iframe)
|
|
179
|
+
alt_frame = self._get_iframe(alt_istek.text)
|
|
180
|
+
if alt_frame:
|
|
181
|
+
iframes.add(alt_frame)
|
|
182
|
+
|
|
183
|
+
results = []
|
|
184
|
+
|
|
185
|
+
for iframe in iframes:
|
|
186
|
+
subtitles = []
|
|
187
|
+
|
|
188
|
+
# VidMoly özel işleme
|
|
189
|
+
if "vidmoly" in iframe:
|
|
190
|
+
headers = {
|
|
191
|
+
"User-Agent" : "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36",
|
|
192
|
+
"Sec-Fetch-Dest" : "iframe"
|
|
193
|
+
}
|
|
194
|
+
iframe_istek = await self.httpx.get(iframe, headers=headers)
|
|
195
|
+
m3u_match = re.search(r'file:"([^"]+)"', iframe_istek.text)
|
|
196
|
+
|
|
197
|
+
if m3u_match:
|
|
198
|
+
results.append(ExtractResult(
|
|
199
|
+
name = "VidMoly",
|
|
200
|
+
url = m3u_match[1],
|
|
201
|
+
referer = self.main_url,
|
|
202
|
+
subtitles = []
|
|
203
|
+
))
|
|
204
|
+
continue
|
|
205
|
+
|
|
206
|
+
# Altyazı çıkar
|
|
207
|
+
subtitle_url = self._extract_subtitle_url(url)
|
|
208
|
+
if subtitle_url:
|
|
209
|
+
subtitles.append(Subtitle(name="Türkçe", url=subtitle_url))
|
|
210
|
+
|
|
211
|
+
data = await self.extract(iframe)
|
|
212
|
+
if data:
|
|
213
|
+
# ExtractResult objesi immutable, yeni bir kopya oluştur
|
|
214
|
+
updated_data = data.model_copy(update={"subtitles": subtitles}) if subtitles else data
|
|
215
|
+
results.append(updated_data)
|
|
216
|
+
|
|
217
|
+
return results
|
KekikStream/Plugins/RecTV.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, MovieInfo, Episode, SeriesInfo, ExtractResult
|
|
4
4
|
from json import dumps, loads
|
|
5
5
|
import re
|
|
6
6
|
|
|
@@ -30,10 +30,9 @@ class RecTV(PluginBase):
|
|
|
30
30
|
f"{main_url}/api/movie/by/filtres/5/created/SAYFA/{sw_key}/" : "Romantik"
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
#@kekik_cache(ttl=60*60)
|
|
34
33
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
35
|
-
self.
|
|
36
|
-
istek = await self.
|
|
34
|
+
self.httpx.headers.update({"user-agent": "okhttp/4.12.0"})
|
|
35
|
+
istek = await self.httpx.get(f"{url.replace('SAYFA', str(int(page) - 1))}")
|
|
37
36
|
veriler = istek.json()
|
|
38
37
|
|
|
39
38
|
return [
|
|
@@ -46,10 +45,9 @@ class RecTV(PluginBase):
|
|
|
46
45
|
for veri in veriler
|
|
47
46
|
]
|
|
48
47
|
|
|
49
|
-
#@kekik_cache(ttl=60*60)
|
|
50
48
|
async def search(self, query: str) -> list[SearchResult]:
|
|
51
|
-
self.
|
|
52
|
-
istek = await self.
|
|
49
|
+
self.httpx.headers.update({"user-agent": "okhttp/4.12.0"})
|
|
50
|
+
istek = await self.httpx.get(f"{self.main_url}/api/search/{query}/{self.sw_key}/")
|
|
53
51
|
|
|
54
52
|
kanallar = istek.json().get("channels")
|
|
55
53
|
icerikler = istek.json().get("posters")
|
|
@@ -67,14 +65,13 @@ class RecTV(PluginBase):
|
|
|
67
65
|
for veri in tum_veri
|
|
68
66
|
]
|
|
69
67
|
|
|
70
|
-
#@kekik_cache(ttl=60*60)
|
|
71
68
|
async def load_item(self, url: str) -> MovieInfo:
|
|
72
|
-
self.
|
|
69
|
+
self.httpx.headers.update({"user-agent": "okhttp/4.12.0"})
|
|
73
70
|
veri = loads(url)
|
|
74
71
|
|
|
75
72
|
match veri.get("type"):
|
|
76
73
|
case "serie":
|
|
77
|
-
dizi_istek = await self.
|
|
74
|
+
dizi_istek = await self.httpx.get(f"{self.main_url}/api/season/by/serie/{veri.get('id')}/{self.sw_key}/")
|
|
78
75
|
dizi_veri = dizi_istek.json()
|
|
79
76
|
|
|
80
77
|
episodes = []
|
|
@@ -119,23 +116,21 @@ class RecTV(PluginBase):
|
|
|
119
116
|
actors = []
|
|
120
117
|
)
|
|
121
118
|
|
|
122
|
-
|
|
123
|
-
async def load_links(self, url: str) -> list[dict]:
|
|
124
|
-
self.media_handler.headers.update({"User-Agent": "googleusercontent"})
|
|
125
|
-
|
|
119
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
126
120
|
try:
|
|
127
121
|
veri = loads(url)
|
|
128
122
|
except Exception:
|
|
129
123
|
# JSON değilse düz URL'dir (eski yapı veya hata)
|
|
130
|
-
return [
|
|
124
|
+
return [ExtractResult(url=url, name="Video")]
|
|
131
125
|
|
|
132
126
|
# Eğer dizi bölümü ise (bizim oluşturduğumuz yapı)
|
|
133
127
|
if veri.get("is_episode"):
|
|
134
|
-
return [
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
128
|
+
return [ExtractResult(
|
|
129
|
+
url = veri.get("url"),
|
|
130
|
+
name = veri.get("title", "Bölüm"),
|
|
131
|
+
user_agent = "googleusercontent",
|
|
132
|
+
referer = "https://twitter.com/"
|
|
133
|
+
)]
|
|
139
134
|
|
|
140
135
|
# Film ise (RecTV API yapısı)
|
|
141
136
|
results = []
|
|
@@ -145,18 +140,11 @@ class RecTV(PluginBase):
|
|
|
145
140
|
if "otolinkaff" in video_link:
|
|
146
141
|
continue
|
|
147
142
|
|
|
148
|
-
results.append(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return results
|
|
155
|
-
|
|
156
|
-
async def play(self, name: str, url: str, referer: str, subtitles: list[Subtitle]):
|
|
157
|
-
extract_result = ExtractResult(name=name, url=url, referer=referer, subtitles=subtitles)
|
|
158
|
-
self.media_handler.title = name
|
|
159
|
-
if self.name not in self.media_handler.title:
|
|
160
|
-
self.media_handler.title = f"{self.name} | {self.media_handler.title}"
|
|
143
|
+
results.append(ExtractResult(
|
|
144
|
+
url = video_link,
|
|
145
|
+
name = f"{veri.get('title')} - {kaynak.get('title')}",
|
|
146
|
+
user_agent = "googleusercontent",
|
|
147
|
+
referer = "https://twitter.com/"
|
|
148
|
+
))
|
|
161
149
|
|
|
162
|
-
|
|
150
|
+
return results
|