KekikStream 1.7.2__py3-none-any.whl → 1.7.3__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.
Files changed (31) hide show
  1. KekikStream/Extractors/DzenRu.py +39 -0
  2. KekikStream/Extractors/ExPlay.py +54 -0
  3. KekikStream/Extractors/FirePlayer.py +61 -0
  4. KekikStream/Extractors/HDPlayerSystem.py +42 -0
  5. KekikStream/Extractors/JetTv.py +47 -0
  6. KekikStream/Extractors/MixTiger.py +61 -0
  7. KekikStream/Extractors/PlayerFilmIzle.py +63 -0
  8. KekikStream/Extractors/SetPlay.py +58 -0
  9. KekikStream/Extractors/SetPrime.py +46 -0
  10. KekikStream/Extractors/TurkeyPlayer.py +35 -0
  11. KekikStream/Extractors/VidHide.py +73 -0
  12. KekikStream/Extractors/VidPapi.py +90 -0
  13. KekikStream/Extractors/VidStack.py +75 -0
  14. KekikStream/Extractors/YildizKisaFilm.py +42 -0
  15. KekikStream/Plugins/Dizilla.py +5 -1
  16. KekikStream/Plugins/FilmBip.py +145 -0
  17. KekikStream/Plugins/FullHDFilm.py +164 -0
  18. KekikStream/Plugins/JetFilmizle.py +10 -3
  19. KekikStream/Plugins/KultFilmler.py +219 -0
  20. KekikStream/Plugins/RoketDizi.py +204 -0
  21. KekikStream/Plugins/SelcukFlix.py +216 -0
  22. KekikStream/Plugins/SezonlukDizi.py +3 -0
  23. KekikStream/Plugins/Sinefy.py +214 -0
  24. KekikStream/Plugins/Sinezy.py +99 -0
  25. KekikStream/Plugins/SuperFilmGeldi.py +121 -0
  26. {kekikstream-1.7.2.dist-info → kekikstream-1.7.3.dist-info}/METADATA +1 -1
  27. {kekikstream-1.7.2.dist-info → kekikstream-1.7.3.dist-info}/RECORD +31 -9
  28. {kekikstream-1.7.2.dist-info → kekikstream-1.7.3.dist-info}/WHEEL +0 -0
  29. {kekikstream-1.7.2.dist-info → kekikstream-1.7.3.dist-info}/entry_points.txt +0 -0
  30. {kekikstream-1.7.2.dist-info → kekikstream-1.7.3.dist-info}/licenses/LICENSE +0 -0
  31. {kekikstream-1.7.2.dist-info → kekikstream-1.7.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,75 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
4
+ from Crypto.Cipher import AES
5
+ from urllib.parse import urlparse
6
+ import re, binascii
7
+
8
+ class VidStack(ExtractorBase):
9
+ name = "VidStack"
10
+ main_url = "https://vidstack.io"
11
+ requires_referer = True
12
+
13
+ def get_base_url(self, url: str) -> str:
14
+ try:
15
+ parsed = urlparse(url)
16
+ return f"{parsed.scheme}://{parsed.netloc}"
17
+ except Exception:
18
+ return self.main_url
19
+
20
+ def decrypt_aes(self, encrypted_hex: str, key: str, iv: str) -> str:
21
+ try:
22
+ key_bytes = key.encode('utf-8')
23
+ iv_bytes = iv.encode('utf-8')
24
+ cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
25
+
26
+ encrypted_bytes = binascii.unhexlify(encrypted_hex)
27
+ decrypted_bytes = cipher.decrypt(encrypted_bytes)
28
+
29
+ # Remove PKCS5 padding
30
+ padding_len = decrypted_bytes[-1]
31
+ return decrypted_bytes[:-padding_len].decode('utf-8')
32
+ except Exception:
33
+ return None
34
+
35
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
36
+ self.cffi.headers.update({
37
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0"
38
+ })
39
+
40
+ if referer:
41
+ self.cffi.headers.update({"Referer": referer})
42
+
43
+ video_hash = url.split("#")[-1].split("/")[-1]
44
+ base_url = self.get_base_url(url)
45
+
46
+ api_url = f"{base_url}/api/v1/video?id={video_hash}"
47
+ istek = await self.cffi.get(api_url)
48
+ encoded = istek.text.strip()
49
+
50
+ key = "kiemtienmua911ca"
51
+ iv_list = ["1234567890oiuytr", "0123456789abcdef"]
52
+
53
+ decrypted_text = None
54
+ for iv in iv_list:
55
+ if result := self.decrypt_aes(encoded, key, iv):
56
+ decrypted_text = result
57
+ break
58
+
59
+ if not decrypted_text:
60
+ raise ValueError(f"VidStack: Şifre çözülemedi. {url}")
61
+
62
+ m3u8_url = ""
63
+ if match := re.search(r'"source":"(.*?)"', decrypted_text):
64
+ m3u8_url = match.group(1).replace("\\/", "/")
65
+
66
+ if not m3u8_url:
67
+ raise ValueError(f"VidStack: Source bulunamadı. {url}")
68
+
69
+ return ExtractResult(
70
+ name = self.name,
71
+ url = m3u8_url,
72
+ referer = url,
73
+ headers = {},
74
+ subtitles = []
75
+ )
@@ -0,0 +1,42 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult
4
+
5
+ class YildizKisaFilm(ExtractorBase):
6
+ name = "YildizKisaFilm"
7
+ main_url = "https://yildizkisafilm.org"
8
+
9
+ async def extract(self, url, referer=None) -> ExtractResult:
10
+ ext_ref = referer or ""
11
+
12
+ if "video/" in url:
13
+ vid_id = url.split("video/")[-1]
14
+ else:
15
+ vid_id = url.split("?data=")[-1]
16
+
17
+ post_url = f"{self.main_url}/player/index.php?data={vid_id}&do=getVideo"
18
+
19
+ response = await self.cffi.post(
20
+ url = post_url,
21
+ data = {"hash": vid_id, "r": ext_ref},
22
+ headers = {
23
+ "Referer" : ext_ref,
24
+ "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
25
+ "X-Requested-With" : "XMLHttpRequest"
26
+ }
27
+ )
28
+ response.raise_for_status()
29
+
30
+ video_data = response.json()
31
+ m3u_link = video_data.get("securedLink")
32
+
33
+ if not m3u_link:
34
+ raise ValueError("securedLink not found in response")
35
+
36
+ return ExtractResult(
37
+ name = self.name,
38
+ url = m3u_link,
39
+ referer = ext_ref,
40
+ headers = {},
41
+ subtitles = []
42
+ )
@@ -134,7 +134,11 @@ class Dizilla(PluginBase):
134
134
  bolumler = []
135
135
  sezonlar = veri.get("containsSeason") if isinstance(veri.get("containsSeason"), list) else [veri.get("containsSeason")]
136
136
  for sezon in sezonlar:
137
- for bolum in sezon.get("episode"):
137
+ episodes = sezon.get("episode")
138
+ if isinstance(episodes, dict):
139
+ episodes = [episodes]
140
+
141
+ for bolum in episodes:
138
142
  bolumler.append(Episode(
139
143
  season = sezon.get("seasonNumber"),
140
144
  episode = bolum.get("episodeNumber"),
@@ -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 = "Film izleme sitesi."
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.cffi.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.cffi.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.cffi.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.cffi.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
@@ -0,0 +1,164 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult, Subtitle
4
+ from parsel import Selector
5
+ import re, base64
6
+
7
+ class FullHDFilm(PluginBase):
8
+ name = "FullHDFilm"
9
+ language = "tr"
10
+ main_url = "https://hdfilm.us"
11
+ favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
12
+ description = "Full HD Film izle, Türkçe Dublaj ve Altyazılı filmler."
13
+
14
+ main_page = {
15
+ f"{main_url}/tur/turkce-altyazili-film-izle" : "Altyazılı Filmler",
16
+ f"{main_url}/tur/netflix-filmleri-izle" : "Netflix",
17
+ f"{main_url}/category/aile-filmleri-izle" : "Aile",
18
+ f"{main_url}/category/aksiyon-filmleri-izle" : "Aksiyon",
19
+ f"{main_url}/category/animasyon-filmleri-izle" : "Animasyon",
20
+ f"{main_url}/category/belgesel-filmleri-izle" : "Belgesel",
21
+ f"{main_url}/category/bilim-kurgu-filmleri-izle" : "Bilim-Kurgu",
22
+ f"{main_url}/category/biyografi-filmleri-izle" : "Biyografi",
23
+ f"{main_url}/category/dram-filmleri-izle" : "Dram",
24
+ f"{main_url}/category/fantastik-filmler-izle" : "Fantastik",
25
+ f"{main_url}/category/gerilim-filmleri-izle" : "Gerilim",
26
+ f"{main_url}/category/gizem-filmleri-izle" : "Gizem",
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/romantik-filmler-izle" : "Romantik",
31
+ f"{main_url}/category/savas-filmleri-izle" : "Savaş",
32
+ f"{main_url}/category/suc-filmleri-izle" : "Suç",
33
+ f"{main_url}/tur/yerli-film-izle" : "Yerli Film",
34
+ }
35
+
36
+ async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
37
+ page_url = url if page == 1 else f"{url}/page/{page}"
38
+
39
+ self.cffi.headers.update({
40
+ "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
41
+ "Referer" : f"{self.main_url}/"
42
+ })
43
+
44
+ istek = await self.cffi.get(page_url)
45
+ secici = Selector(istek.text)
46
+
47
+ return [
48
+ MainPageResult(
49
+ category = category,
50
+ title = veri.css("img::attr(alt)").get(),
51
+ url = self.fix_url(veri.css("a::attr(href)").get()),
52
+ poster = self.fix_url(veri.css("img::attr(src)").get()),
53
+ )
54
+ for veri in secici.css("div.movie-poster")
55
+ if veri.css("img::attr(alt)").get()
56
+ ]
57
+
58
+ async def search(self, query: str) -> list[SearchResult]:
59
+ istek = await self.cffi.get(f"{self.main_url}/?s={query}")
60
+ secici = Selector(istek.text)
61
+
62
+ return [
63
+ SearchResult(
64
+ title = veri.css("img::attr(alt)").get(),
65
+ url = self.fix_url(veri.css("a::attr(href)").get()),
66
+ poster = self.fix_url(veri.css("img::attr(src)").get()),
67
+ )
68
+ for veri in secici.css("div.movie-poster")
69
+ if veri.css("img::attr(alt)").get()
70
+ ]
71
+
72
+ async def load_item(self, url: str) -> MovieInfo:
73
+ istek = await self.cffi.get(url)
74
+ secici = Selector(istek.text)
75
+
76
+ title = secici.css("h1::text").get()
77
+ poster = self.fix_url(secici.css("div.poster img::attr(src)").get())
78
+ description = secici.css("div#details div.text::text").get() or \
79
+ secici.css("div#details div::text").get()
80
+
81
+ actors_text = secici.css("div.oyuncular.info::text").get()
82
+ if actors_text:
83
+ actors_text = actors_text.replace("Oyuncular:", "").strip()
84
+ actors = [a.strip() for a in actors_text.split(",")]
85
+ else:
86
+ actors = []
87
+
88
+ year = secici.css("div.yayin-tarihi.info::text").re_first(r"(\d{4})")
89
+ tags = secici.css("div.tur.info a::text").getall()
90
+ rating = secici.css("div.imdb::text").re_first(r"IMDb\s*([\d\.]+)")
91
+
92
+ # Açıklama usually above .others
93
+ description = secici.xpath("//div[contains(@class, 'others')]/preceding-sibling::div[1]//text()").getall()
94
+ description = "".join(description).strip() if description else None
95
+
96
+ return MovieInfo(
97
+ url = url,
98
+ poster = poster,
99
+ title = self.clean_title(title) if title else "",
100
+ description = description,
101
+ tags = tags,
102
+ year = year,
103
+ actors = actors,
104
+ rating = rating.strip() if rating else None,
105
+ )
106
+
107
+ def _get_iframe(self, source_code: str) -> str:
108
+ """Base64 kodlu iframe'i çözümle"""
109
+ match = re.search(r'<script[^>]*>(PCEtLWJhc2xpazp[^<]*)</script>', source_code)
110
+ if not match:
111
+ return ""
112
+
113
+ try:
114
+ decoded_html = base64.b64decode(match[1]).decode("utf-8")
115
+ iframe_match = re.search(r'<iframe[^>]+src=["\']([^"\']+)["\']', decoded_html)
116
+ return self.fix_url(iframe_match[1]) if iframe_match else ""
117
+ except Exception:
118
+ return ""
119
+
120
+ def _extract_subtitle_url(self, source_code: str) -> str | None:
121
+ """playerjsSubtitle değişkeninden .srt URL çıkar"""
122
+ patterns = [
123
+ r'var playerjsSubtitle = "\[Türkçe\](https?://[^\s"]+?\.srt)";',
124
+ r'var playerjsSubtitle = "(https?://[^\s"]+?\.srt)";',
125
+ r'subtitle:\s*"(https?://[^\s"]+?\.srt)"',
126
+ ]
127
+
128
+ for pattern in patterns:
129
+ if match := re.search(pattern, source_code):
130
+ return match[1]
131
+
132
+ return None
133
+
134
+ async def load_links(self, url: str) -> list[dict]:
135
+ self.cffi.headers.update({
136
+ "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
137
+ "Referer" : self.main_url
138
+ })
139
+
140
+ istek = await self.cffi.get(url)
141
+ source_code = istek.text
142
+
143
+ # Ana sayfadan altyazı URL'sini çek
144
+ subtitle_url = self._extract_subtitle_url(source_code)
145
+
146
+ # Iframe'den altyazı URL'sini çek
147
+ iframe_src = self._get_iframe(source_code)
148
+
149
+ if not subtitle_url and iframe_src:
150
+ iframe_istek = await self.cffi.get(iframe_src)
151
+ subtitle_url = self._extract_subtitle_url(iframe_istek.text)
152
+
153
+ results = []
154
+
155
+ if iframe_src:
156
+ extractor = self.ex_manager.find_extractor(iframe_src)
157
+ results.append({
158
+ "name" : extractor.name if extractor else "FullHDFilm Player",
159
+ "url" : iframe_src,
160
+ "referer" : self.main_url,
161
+ "subtitles" : [Subtitle(name="Türkçe", url=subtitle_url)] if subtitle_url else []
162
+ })
163
+
164
+ return results
@@ -66,10 +66,17 @@ class JetFilmizle(PluginBase):
66
66
  secici = Selector(istek.text)
67
67
 
68
68
  title = self.clean_title(secici.css("div.movie-exp-title::text").get())
69
- poster = secici.css("section.movie-exp img::attr(data-src), section.movie-exp img::attr(src)").get().strip()
70
- description = secici.css("section.movie-exp p.aciklama::text").get().strip()
69
+ poster_raw = secici.css("section.movie-exp img::attr(data-src), section.movie-exp img::attr(src)").get()
70
+ poster = poster_raw.strip() if poster_raw else None
71
+
72
+ desc_raw = secici.css("section.movie-exp p.aciklama::text").get()
73
+ description = desc_raw.strip() if desc_raw else None
74
+
71
75
  tags = secici.css("section.movie-exp div.catss a::text").getall()
72
- rating = secici.css("section.movie-exp div.imdb_puan span::text").get().strip()
76
+
77
+ rating_raw = secici.css("section.movie-exp div.imdb_puan span::text").get()
78
+ rating = rating_raw.strip() if rating_raw else None
79
+
73
80
  year = secici.xpath("//div[@class='yap' and (contains(., 'Vizyon') or contains(., 'Yapım'))]/text()").get()
74
81
  year = year.strip() if year else None
75
82
  actors = secici.css("div[itemprop='actor'] a span::text").getall()