KekikStream 2.1.3__tar.gz → 2.1.5__tar.gz
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-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/CloseLoad.py +17 -2
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/FilmMakinesi.py +9 -5
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/FullHDFilm.py +68 -17
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/HDFilmCehennemi.py +61 -21
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/SelcukFlix.py +66 -42
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream.egg-info/PKG-INFO +3 -1
- {kekikstream-2.1.3 → kekikstream-2.1.5}/PKG-INFO +3 -1
- {kekikstream-2.1.3 → kekikstream-2.1.5}/README.md +2 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/setup.py +1 -1
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/CLI/__init__.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/CLI/pypi_kontrol.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Extractor/ExtractorBase.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Extractor/ExtractorLoader.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Extractor/ExtractorManager.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Extractor/ExtractorModels.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Extractor/YTDLPCache.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Media/MediaHandler.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Media/MediaManager.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Plugin/PluginBase.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Plugin/PluginLoader.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Plugin/PluginManager.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Plugin/PluginModels.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/UI/UIManager.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/__init__.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/ContentX.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/DonilasPlay.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/DzenRu.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/ExPlay.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/HDPlayerSystem.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/JetTv.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/MailRu.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/MixPlayHD.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/MixTiger.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/MolyStream.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/Odnoklassniki.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/PeaceMakerst.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/PixelDrain.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/PlayerFilmIzle.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/RapidVid.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/SetPlay.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/SetPrime.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/SibNet.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/Sobreatsesuyp.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/TRsTX.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/TauVideo.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/TurboImgz.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/TurkeyPlayer.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/VCTPlay.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/VidHide.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/VidMoly.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/VidMoxy.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/VidPapi.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/VideoSeyred.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/YTDLP.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/YildizKisaFilm.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/BelgeselX.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/DiziBox.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/DiziPal.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/DiziYou.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/Dizilla.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/FilmBip.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/FilmModu.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/FullHDFilmizlesene.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/JetFilmizle.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/KultFilmler.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/RecTV.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/RoketDizi.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/SetFilmIzle.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/SezonlukDizi.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/SineWix.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/Sinefy.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/SinemaCX.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/Sinezy.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/SuperFilmGeldi.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/UgurFilm.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/__init__.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/__main__.py +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/requirements.txt +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream.egg-info/SOURCES.txt +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream.egg-info/dependency_links.txt +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream.egg-info/entry_points.txt +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream.egg-info/requires.txt +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream.egg-info/top_level.txt +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/LICENSE +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/MANIFEST.in +0 -0
- {kekikstream-2.1.3 → kekikstream-2.1.5}/setup.cfg +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
2
|
|
|
3
|
-
from KekikStream.Core import ExtractorBase, ExtractResult
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
|
|
4
4
|
from Kekik.Sifreleme import Packer, StreamDecoder
|
|
5
|
+
from parsel import Selector
|
|
5
6
|
import re
|
|
6
7
|
|
|
7
8
|
class CloseLoadExtractor(ExtractorBase):
|
|
@@ -15,12 +16,26 @@ class CloseLoadExtractor(ExtractorBase):
|
|
|
15
16
|
istek = await self.httpx.get(url)
|
|
16
17
|
istek.raise_for_status()
|
|
17
18
|
|
|
19
|
+
# Video URL'sini çıkar
|
|
18
20
|
eval_func = re.compile(r'\s*(eval\(function[\s\S].*)\s*').findall(istek.text)[0]
|
|
19
21
|
m3u_link = StreamDecoder.extract_stream_url(Packer.unpack(eval_func))
|
|
20
22
|
|
|
23
|
+
# Subtitle'ları parse et (Kotlin referansı: track elementleri)
|
|
24
|
+
subtitles = []
|
|
25
|
+
secici = Selector(istek.text)
|
|
26
|
+
for track in secici.css("track"):
|
|
27
|
+
raw_src = track.css("::attr(src)").get() or ""
|
|
28
|
+
raw_src = raw_src.strip()
|
|
29
|
+
label = track.css("::attr(label)").get() or track.css("::attr(srclang)").get() or "Altyazı"
|
|
30
|
+
|
|
31
|
+
if raw_src:
|
|
32
|
+
full_url = raw_src if raw_src.startswith("http") else f"{self.main_url}{raw_src}"
|
|
33
|
+
subtitles.append(Subtitle(name=label, url=full_url))
|
|
34
|
+
|
|
21
35
|
return ExtractResult(
|
|
22
36
|
name = self.name,
|
|
23
37
|
url = m3u_link,
|
|
24
38
|
referer = self.main_url,
|
|
25
|
-
subtitles =
|
|
39
|
+
subtitles = subtitles
|
|
26
40
|
)
|
|
41
|
+
|
|
@@ -75,18 +75,22 @@ class FilmMakinesi(PluginBase):
|
|
|
75
75
|
istek = await self.httpx.get(url)
|
|
76
76
|
secici = Selector(istek.text)
|
|
77
77
|
|
|
78
|
-
title = secici.css("h1.title::text").get()
|
|
79
|
-
|
|
80
|
-
|
|
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 ""
|
|
81
84
|
rating = secici.css("div.score::text").get()
|
|
82
85
|
if rating:
|
|
83
86
|
rating = rating.strip().split()[0]
|
|
84
|
-
year = secici.css("span.date a::text").get()
|
|
87
|
+
year = secici.css("span.date a::text").get()
|
|
88
|
+
year = year.strip() if year else ""
|
|
85
89
|
actors = secici.css("div.cast-name::text").getall()
|
|
86
90
|
tags = secici.css("div.genre a::text").getall()
|
|
87
91
|
duration = secici.css("div.time::text").get()
|
|
88
92
|
if duration:
|
|
89
|
-
duration = duration.split()[1].strip()
|
|
93
|
+
duration = duration.split()[1].strip() if len(duration.split()) > 1 else ""
|
|
90
94
|
|
|
91
95
|
return MovieInfo(
|
|
92
96
|
url = url,
|
|
@@ -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, ExtractResult, Subtitle
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult, Subtitle
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
import re, base64
|
|
6
6
|
|
|
@@ -69,14 +69,13 @@ class FullHDFilm(PluginBase):
|
|
|
69
69
|
if veri.css("img::attr(alt)").get()
|
|
70
70
|
]
|
|
71
71
|
|
|
72
|
-
async def load_item(self, url: str) -> MovieInfo:
|
|
72
|
+
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
73
73
|
istek = await self.httpx.get(url)
|
|
74
74
|
secici = Selector(istek.text)
|
|
75
75
|
|
|
76
|
-
title = secici.css("h1::text").get()
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
secici.css("div#details div::text").get()
|
|
76
|
+
title = secici.css("h1::text").get() or ""
|
|
77
|
+
title = title.strip() if title else ""
|
|
78
|
+
poster = self.fix_url(secici.css("div.poster img::attr(src)").get() or "")
|
|
80
79
|
|
|
81
80
|
actors_text = secici.css("div.oyuncular.info::text").get()
|
|
82
81
|
if actors_text:
|
|
@@ -89,20 +88,72 @@ class FullHDFilm(PluginBase):
|
|
|
89
88
|
tags = secici.css("div.tur.info a::text").getall()
|
|
90
89
|
rating = secici.css("div.imdb::text").re_first(r"IMDb\s*([\d\.]+)")
|
|
91
90
|
|
|
92
|
-
#
|
|
91
|
+
# Description
|
|
93
92
|
description = secici.xpath("//div[contains(@class, 'others')]/preceding-sibling::div[1]//text()").getall()
|
|
94
93
|
description = "".join(description).strip() if description else None
|
|
95
94
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
95
|
+
# Kotlin referansı: URL'de -dizi kontrolü veya tags içinde "dizi" kontrolü
|
|
96
|
+
is_series = "-dizi" in url.lower() or any("dizi" in tag.lower() for tag in tags)
|
|
97
|
+
|
|
98
|
+
if is_series:
|
|
99
|
+
episodes = []
|
|
100
|
+
part_elements = secici.css("li.psec")
|
|
101
|
+
part_names = secici.css("li.psec a::text").getall()
|
|
102
|
+
|
|
103
|
+
# pdata değerlerini çıkar
|
|
104
|
+
pdata_matches = re.findall(r"pdata\['([^']+)'\]\s*=\s*'([^']+)'", istek.text)
|
|
105
|
+
|
|
106
|
+
for idx, (part_id, part_name) in enumerate(zip([el.css("::attr(id)").get() for el in part_elements], part_names)):
|
|
107
|
+
if not part_name:
|
|
108
|
+
continue
|
|
109
|
+
|
|
110
|
+
part_name = part_name.strip()
|
|
111
|
+
|
|
112
|
+
# Fragman'ları atla
|
|
113
|
+
if "fragman" in part_name.lower() or (part_id and "fragman" in part_id.lower()):
|
|
114
|
+
continue
|
|
115
|
+
|
|
116
|
+
# Sezon ve bölüm numarası çıkar
|
|
117
|
+
sz_match = re.search(r'(\d+)\s*sezon', part_id.lower() if part_id else "")
|
|
118
|
+
ep_match = re.search(r'^(\d+)\.', part_name)
|
|
119
|
+
|
|
120
|
+
sz_num = int(sz_match.group(1)) if sz_match else 1
|
|
121
|
+
ep_num = int(ep_match.group(1)) if ep_match else idx + 1
|
|
122
|
+
|
|
123
|
+
# pdata'dan video URL'si çık (varsa)
|
|
124
|
+
video_url = url # Varsayılan olarak ana URL kullan
|
|
125
|
+
if idx < len(pdata_matches):
|
|
126
|
+
video_url = pdata_matches[idx][1] if pdata_matches[idx][1] else url
|
|
127
|
+
|
|
128
|
+
episodes.append(Episode(
|
|
129
|
+
season = sz_num,
|
|
130
|
+
episode = ep_num,
|
|
131
|
+
title = f"{sz_num}. Sezon {ep_num}. Bölüm",
|
|
132
|
+
url = url # Bölüm URL'leri load_links'te işlenecek
|
|
133
|
+
))
|
|
134
|
+
|
|
135
|
+
return SeriesInfo(
|
|
136
|
+
url = url,
|
|
137
|
+
poster = poster,
|
|
138
|
+
title = self.clean_title(title) if title else "",
|
|
139
|
+
description = description,
|
|
140
|
+
tags = tags,
|
|
141
|
+
year = year,
|
|
142
|
+
actors = actors,
|
|
143
|
+
rating = rating.strip() if rating else None,
|
|
144
|
+
episodes = episodes
|
|
145
|
+
)
|
|
146
|
+
else:
|
|
147
|
+
return MovieInfo(
|
|
148
|
+
url = url,
|
|
149
|
+
poster = poster,
|
|
150
|
+
title = self.clean_title(title) if title else "",
|
|
151
|
+
description = description,
|
|
152
|
+
tags = tags,
|
|
153
|
+
year = year,
|
|
154
|
+
actors = actors,
|
|
155
|
+
rating = rating.strip() if rating else None,
|
|
156
|
+
)
|
|
106
157
|
|
|
107
158
|
def _get_iframe(self, source_code: str) -> str:
|
|
108
159
|
"""Base64 kodlu iframe'i çözümle"""
|
|
@@ -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, Subtitle
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, Subtitle
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
from Kekik.Sifreleme import Packer, StreamDecoder
|
|
6
6
|
import random, string, re
|
|
@@ -71,36 +71,76 @@ class HDFilmCehennemi(PluginBase):
|
|
|
71
71
|
|
|
72
72
|
return results
|
|
73
73
|
|
|
74
|
-
async def load_item(self, url: str) -> MovieInfo:
|
|
74
|
+
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
75
75
|
istek = await self.httpx.get(url, headers = {"Referer": f"{self.main_url}/"})
|
|
76
76
|
secici = Selector(istek.text)
|
|
77
77
|
|
|
78
|
-
title = secici.css("h1.section-title::text").get()
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
title = secici.css("h1.section-title::text").get()
|
|
79
|
+
title = title.strip() if title else ""
|
|
80
|
+
poster = secici.css("aside.post-info-poster img.lazyload::attr(data-src)").get() or ""
|
|
81
|
+
poster = poster.strip() if poster else ""
|
|
82
|
+
description = secici.css("article.post-info-content > p::text").get() or ""
|
|
83
|
+
description = description.strip() if description else ""
|
|
81
84
|
tags = secici.css("div.post-info-genres a::text").getall()
|
|
82
|
-
rating = secici.css("div.post-info-imdb-rating span::text").get()
|
|
83
|
-
|
|
85
|
+
rating = secici.css("div.post-info-imdb-rating span::text").get() or ""
|
|
86
|
+
rating = rating.strip() if rating else ""
|
|
87
|
+
year = secici.css("div.post-info-year-country a::text").get() or ""
|
|
88
|
+
year = year.strip() if year else ""
|
|
84
89
|
actors = secici.css("div.post-info-cast a > strong::text").getall()
|
|
85
|
-
duration = secici.css("div.post-info-duration::text").get()
|
|
90
|
+
duration = secici.css("div.post-info-duration::text").get() or "0"
|
|
91
|
+
duration = duration.replace("dakika", "").strip()
|
|
86
92
|
|
|
87
|
-
|
|
88
93
|
try:
|
|
89
|
-
duration_minutes = int(duration
|
|
94
|
+
duration_minutes = int(re.search(r'\d+', duration).group()) if re.search(r'\d+', duration) else 0
|
|
90
95
|
except Exception:
|
|
91
96
|
duration_minutes = 0
|
|
92
97
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
# Dizi mi film mi kontrol et (Kotlin referansı: div.seasons kontrolü)
|
|
99
|
+
is_series = len(secici.css("div.seasons").getall()) > 0
|
|
100
|
+
|
|
101
|
+
if is_series:
|
|
102
|
+
episodes = []
|
|
103
|
+
for ep in secici.css("div.seasons-tab-content a"):
|
|
104
|
+
ep_name = ep.css("h4::text").get()
|
|
105
|
+
ep_href = ep.css("::attr(href)").get()
|
|
106
|
+
if ep_name and ep_href:
|
|
107
|
+
ep_name = ep_name.strip()
|
|
108
|
+
# Regex ile sezon ve bölüm numarası çıkar
|
|
109
|
+
ep_match = re.search(r'(\d+)\.\s*Bölüm', ep_name)
|
|
110
|
+
sz_match = re.search(r'(\d+)\.\s*Sezon', ep_name)
|
|
111
|
+
ep_num = int(ep_match.group(1)) if ep_match else 1
|
|
112
|
+
sz_num = int(sz_match.group(1)) if sz_match else 1
|
|
113
|
+
|
|
114
|
+
episodes.append(Episode(
|
|
115
|
+
season = sz_num,
|
|
116
|
+
episode = ep_num,
|
|
117
|
+
title = ep_name,
|
|
118
|
+
url = self.fix_url(ep_href)
|
|
119
|
+
))
|
|
120
|
+
|
|
121
|
+
return SeriesInfo(
|
|
122
|
+
url = url,
|
|
123
|
+
poster = self.fix_url(poster),
|
|
124
|
+
title = self.clean_title(title),
|
|
125
|
+
description = description,
|
|
126
|
+
tags = tags,
|
|
127
|
+
rating = rating,
|
|
128
|
+
year = year,
|
|
129
|
+
actors = actors,
|
|
130
|
+
episodes = episodes
|
|
131
|
+
)
|
|
132
|
+
else:
|
|
133
|
+
return MovieInfo(
|
|
134
|
+
url = url,
|
|
135
|
+
poster = self.fix_url(poster),
|
|
136
|
+
title = self.clean_title(title),
|
|
137
|
+
description = description,
|
|
138
|
+
tags = tags,
|
|
139
|
+
rating = rating,
|
|
140
|
+
year = year,
|
|
141
|
+
actors = actors,
|
|
142
|
+
duration = duration_minutes
|
|
143
|
+
)
|
|
104
144
|
|
|
105
145
|
def generate_random_cookie(self):
|
|
106
146
|
return "".join(random.choices(string.ascii_letters + string.digits, k=16))
|
|
@@ -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, SeriesInfo, Episode
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode
|
|
4
4
|
from parsel import Selector
|
|
5
5
|
import re, base64, json, urllib.parse
|
|
6
6
|
|
|
@@ -137,8 +137,13 @@ class SelcukFlix(PluginBase):
|
|
|
137
137
|
search_url = f"{self.main_url}/api/bg/searchcontent?searchterm={query}"
|
|
138
138
|
|
|
139
139
|
headers = {
|
|
140
|
+
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0",
|
|
140
141
|
"Accept" : "application/json, text/plain, */*",
|
|
142
|
+
"Accept-Language" : "en-US,en;q=0.5",
|
|
141
143
|
"X-Requested-With" : "XMLHttpRequest",
|
|
144
|
+
"Sec-Fetch-Site" : "same-origin",
|
|
145
|
+
"Sec-Fetch-Mode" : "cors",
|
|
146
|
+
"Sec-Fetch-Dest" : "empty",
|
|
142
147
|
"Referer" : f"{self.main_url}/"
|
|
143
148
|
}
|
|
144
149
|
|
|
@@ -151,15 +156,16 @@ class SelcukFlix(PluginBase):
|
|
|
151
156
|
try:
|
|
152
157
|
decoded_str = raw_data.decode('utf-8')
|
|
153
158
|
except UnicodeDecodeError:
|
|
154
|
-
decoded_str = raw_data.decode('iso-8859-1')
|
|
159
|
+
decoded_str = raw_data.decode('iso-8859-1')
|
|
155
160
|
|
|
156
161
|
search_data = json.loads(decoded_str)
|
|
157
162
|
|
|
158
163
|
results = []
|
|
159
164
|
for item in search_data.get("result", []):
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
165
|
+
# API field isimleri: object_name, used_slug, object_poster_url
|
|
166
|
+
title = item.get("object_name") or item.get("title")
|
|
167
|
+
slug = item.get("used_slug") or item.get("slug")
|
|
168
|
+
poster = item.get("object_poster_url") or item.get("poster")
|
|
163
169
|
|
|
164
170
|
if poster:
|
|
165
171
|
poster = self.clean_image_url(poster)
|
|
@@ -176,7 +182,7 @@ class SelcukFlix(PluginBase):
|
|
|
176
182
|
except Exception:
|
|
177
183
|
return []
|
|
178
184
|
|
|
179
|
-
async def load_item(self, url: str) -> SeriesInfo:
|
|
185
|
+
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
180
186
|
resp = await self.httpx.get(url)
|
|
181
187
|
sel = Selector(resp.text)
|
|
182
188
|
|
|
@@ -190,15 +196,17 @@ class SelcukFlix(PluginBase):
|
|
|
190
196
|
try:
|
|
191
197
|
decoded_str = raw_data.decode('utf-8')
|
|
192
198
|
except UnicodeDecodeError:
|
|
193
|
-
decoded_str = raw_data.decode('iso-8859-1')
|
|
199
|
+
decoded_str = raw_data.decode('iso-8859-1')
|
|
194
200
|
|
|
195
201
|
content_details = json.loads(decoded_str)
|
|
196
202
|
item = content_details.get("contentItem", {})
|
|
197
203
|
|
|
198
|
-
title = item.get("original_title") or item.get("originalTitle")
|
|
204
|
+
title = item.get("original_title") or item.get("originalTitle") or ""
|
|
199
205
|
poster = self.clean_image_url(item.get("poster_url") or item.get("posterUrl"))
|
|
200
206
|
description = item.get("description") or item.get("used_description")
|
|
201
207
|
rating = str(item.get("imdb_point") or item.get("imdbPoint", ""))
|
|
208
|
+
year = item.get("release_year") or item.get("releaseYear")
|
|
209
|
+
duration = item.get("total_minutes") or item.get("totalMinutes")
|
|
202
210
|
|
|
203
211
|
series_data = content_details.get("relatedData", {}).get("seriesData")
|
|
204
212
|
if not series_data and "RelatedResults" in content_details:
|
|
@@ -206,17 +214,18 @@ class SelcukFlix(PluginBase):
|
|
|
206
214
|
if series_data and isinstance(series_data, list):
|
|
207
215
|
pass
|
|
208
216
|
|
|
209
|
-
|
|
217
|
+
# Dizi mi film mi kontrol et (Kotlin referansı)
|
|
210
218
|
if series_data:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
219
|
+
episodes = []
|
|
220
|
+
seasons_list = []
|
|
221
|
+
if isinstance(series_data, dict):
|
|
222
|
+
seasons_list = series_data.get("seasons", [])
|
|
223
|
+
elif isinstance(series_data, list):
|
|
224
|
+
seasons_list = series_data
|
|
225
|
+
|
|
226
|
+
for season in seasons_list:
|
|
218
227
|
if not isinstance(season, dict): continue
|
|
219
|
-
s_no = season.get("season_no") or season.get("seasonNo")
|
|
228
|
+
s_no = season.get("season_no") or season.get("seasonNo")
|
|
220
229
|
ep_list = season.get("episodes", [])
|
|
221
230
|
for ep in ep_list:
|
|
222
231
|
episodes.append(Episode(
|
|
@@ -225,15 +234,27 @@ class SelcukFlix(PluginBase):
|
|
|
225
234
|
title = ep.get("ep_text") or ep.get("epText"),
|
|
226
235
|
url = self.fix_url(ep.get("used_slug") or ep.get("usedSlug"))
|
|
227
236
|
))
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
+
|
|
238
|
+
return SeriesInfo(
|
|
239
|
+
title = title,
|
|
240
|
+
url = url,
|
|
241
|
+
poster = poster,
|
|
242
|
+
description = description,
|
|
243
|
+
rating = rating,
|
|
244
|
+
year = year,
|
|
245
|
+
episodes = episodes
|
|
246
|
+
)
|
|
247
|
+
else:
|
|
248
|
+
# Film ise MovieInfo döndür
|
|
249
|
+
return MovieInfo(
|
|
250
|
+
title = title,
|
|
251
|
+
url = url,
|
|
252
|
+
poster = poster,
|
|
253
|
+
description = description,
|
|
254
|
+
rating = rating,
|
|
255
|
+
year = year,
|
|
256
|
+
duration = duration
|
|
257
|
+
)
|
|
237
258
|
|
|
238
259
|
async def load_links(self, url: str) -> list[dict]:
|
|
239
260
|
resp = await self.httpx.get(url)
|
|
@@ -248,42 +269,45 @@ class SelcukFlix(PluginBase):
|
|
|
248
269
|
secure_data = data["props"]["pageProps"]["secureData"]
|
|
249
270
|
raw_data = base64.b64decode(secure_data.replace('"', ''))
|
|
250
271
|
|
|
251
|
-
# Try UTF-8 first, fallback to ISO-8859-1 (matching Kotlin)
|
|
252
272
|
try:
|
|
253
273
|
decoded_str = raw_data.decode('utf-8')
|
|
254
274
|
except UnicodeDecodeError:
|
|
255
275
|
decoded_str = raw_data.decode('iso-8859-1')
|
|
256
276
|
|
|
257
277
|
content_details = json.loads(decoded_str)
|
|
258
|
-
|
|
278
|
+
related_results = content_details.get("RelatedResults", {})
|
|
259
279
|
|
|
260
280
|
source_content = None
|
|
261
281
|
|
|
262
|
-
#
|
|
282
|
+
# Dizi (bölüm) için
|
|
263
283
|
if "/dizi/" in url:
|
|
264
|
-
|
|
265
|
-
|
|
284
|
+
episode_sources = related_results.get("getEpisodeSources", {})
|
|
285
|
+
if episode_sources.get("state"):
|
|
286
|
+
res = episode_sources.get("result", [])
|
|
266
287
|
if res:
|
|
267
|
-
source_content = res[0].get("sourceContent")
|
|
288
|
+
source_content = res[0].get("source_content") or res[0].get("sourceContent")
|
|
268
289
|
else:
|
|
269
|
-
#
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
rr = content_details.get("RelatedResults", {})
|
|
290
|
+
# Film için
|
|
291
|
+
movie_parts = related_results.get("getMoviePartsById", {})
|
|
292
|
+
if movie_parts.get("state"):
|
|
293
|
+
parts = movie_parts.get("result", [])
|
|
294
|
+
if parts:
|
|
295
|
+
first_part_id = parts[0].get("id")
|
|
276
296
|
key = f"getMoviePartSourcesById_{first_part_id}"
|
|
277
|
-
if key in
|
|
278
|
-
res =
|
|
297
|
+
if key in related_results:
|
|
298
|
+
res = related_results[key].get("result", [])
|
|
279
299
|
if res:
|
|
280
|
-
source_content = res[0].get("source_content")
|
|
300
|
+
source_content = res[0].get("source_content") or res[0].get("sourceContent")
|
|
281
301
|
|
|
282
302
|
if source_content:
|
|
283
303
|
iframe_sel = Selector(source_content)
|
|
284
304
|
iframe_src = iframe_sel.css("iframe::attr(src)").get()
|
|
285
305
|
if iframe_src:
|
|
286
306
|
iframe_src = self.fix_url(iframe_src)
|
|
307
|
+
# Hotlinger domain değişimi (Kotlin referansı)
|
|
308
|
+
if "sn.dplayer74.site" in iframe_src:
|
|
309
|
+
iframe_src = iframe_src.replace("sn.dplayer74.site", "sn.hotlinger.com")
|
|
310
|
+
|
|
287
311
|
data = await self.extract(iframe_src)
|
|
288
312
|
if data:
|
|
289
313
|
return [data]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: KekikStream
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.5
|
|
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
|
|
@@ -292,6 +292,8 @@ Projeyi geliştirmek için katkılarınızı bekliyoruz!
|
|
|
292
292
|
|
|
293
293
|
- [keyiflerolsun/Kekik-cloudstream](https://github.com/keyiflerolsun/Kekik-cloudstream)
|
|
294
294
|
- [keyiflerolsun/seyirTurk-Parser](https://github.com/keyiflerolsun/seyirTurk-Parser)
|
|
295
|
+
- [feroxx/Kekik-cloudstream](https://github.com/feroxx/Kekik-cloudstream)
|
|
296
|
+
- [kerimmkirac/cs-kerim](https://github.com/kerimmkirac/cs-kerim)
|
|
295
297
|
|
|
296
298
|
## 🌐 Telif Hakkı ve Lisans
|
|
297
299
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: KekikStream
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.5
|
|
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
|
|
@@ -292,6 +292,8 @@ Projeyi geliştirmek için katkılarınızı bekliyoruz!
|
|
|
292
292
|
|
|
293
293
|
- [keyiflerolsun/Kekik-cloudstream](https://github.com/keyiflerolsun/Kekik-cloudstream)
|
|
294
294
|
- [keyiflerolsun/seyirTurk-Parser](https://github.com/keyiflerolsun/seyirTurk-Parser)
|
|
295
|
+
- [feroxx/Kekik-cloudstream](https://github.com/feroxx/Kekik-cloudstream)
|
|
296
|
+
- [kerimmkirac/cs-kerim](https://github.com/kerimmkirac/cs-kerim)
|
|
295
297
|
|
|
296
298
|
## 🌐 Telif Hakkı ve Lisans
|
|
297
299
|
|
|
@@ -255,6 +255,8 @@ Projeyi geliştirmek için katkılarınızı bekliyoruz!
|
|
|
255
255
|
|
|
256
256
|
- [keyiflerolsun/Kekik-cloudstream](https://github.com/keyiflerolsun/Kekik-cloudstream)
|
|
257
257
|
- [keyiflerolsun/seyirTurk-Parser](https://github.com/keyiflerolsun/seyirTurk-Parser)
|
|
258
|
+
- [feroxx/Kekik-cloudstream](https://github.com/feroxx/Kekik-cloudstream)
|
|
259
|
+
- [kerimmkirac/cs-kerim](https://github.com/kerimmkirac/cs-kerim)
|
|
258
260
|
|
|
259
261
|
## 🌐 Telif Hakkı ve Lisans
|
|
260
262
|
|
|
@@ -6,7 +6,7 @@ from io import open
|
|
|
6
6
|
setup(
|
|
7
7
|
# ? Genel Bilgiler
|
|
8
8
|
name = "KekikStream",
|
|
9
|
-
version = "2.1.
|
|
9
|
+
version = "2.1.5",
|
|
10
10
|
url = "https://github.com/keyiflerolsun/KekikStream",
|
|
11
11
|
description = "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ı",
|
|
12
12
|
keywords = ["KekikStream", "KekikAkademi", "keyiflerolsun"],
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|