KekikStream 1.6.8__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.
- KekikStream/Core/Plugin/PluginModels.py +1 -0
- KekikStream/Extractors/DzenRu.py +39 -0
- KekikStream/Extractors/ExPlay.py +54 -0
- KekikStream/Extractors/FirePlayer.py +61 -0
- KekikStream/Extractors/HDPlayerSystem.py +42 -0
- KekikStream/Extractors/JetTv.py +47 -0
- KekikStream/Extractors/MixTiger.py +61 -0
- KekikStream/Extractors/PlayerFilmIzle.py +63 -0
- KekikStream/Extractors/SetPlay.py +58 -0
- KekikStream/Extractors/SetPrime.py +46 -0
- KekikStream/Extractors/TurkeyPlayer.py +35 -0
- KekikStream/Extractors/VidHide.py +73 -0
- KekikStream/Extractors/VidPapi.py +90 -0
- KekikStream/Extractors/VidStack.py +75 -0
- KekikStream/Extractors/YildizKisaFilm.py +42 -0
- KekikStream/Plugins/DiziPal.py +246 -0
- KekikStream/Plugins/Dizilla.py +5 -1
- KekikStream/Plugins/FilmBip.py +145 -0
- KekikStream/Plugins/FilmModu.py +138 -0
- KekikStream/Plugins/FullHDFilm.py +164 -0
- KekikStream/Plugins/JetFilmizle.py +10 -3
- KekikStream/Plugins/KultFilmler.py +219 -0
- KekikStream/Plugins/RecTV.py +1 -1
- KekikStream/Plugins/RoketDizi.py +204 -0
- KekikStream/Plugins/SelcukFlix.py +216 -0
- KekikStream/Plugins/SezonlukDizi.py +3 -0
- KekikStream/Plugins/Sinefy.py +214 -0
- KekikStream/Plugins/SinemaCX.py +157 -0
- KekikStream/Plugins/Sinezy.py +99 -0
- KekikStream/Plugins/SuperFilmGeldi.py +121 -0
- {kekikstream-1.6.8.dist-info → kekikstream-1.7.3.dist-info}/METADATA +1 -1
- {kekikstream-1.6.8.dist-info → kekikstream-1.7.3.dist-info}/RECORD +36 -11
- {kekikstream-1.6.8.dist-info → kekikstream-1.7.3.dist-info}/WHEEL +0 -0
- {kekikstream-1.6.8.dist-info → kekikstream-1.7.3.dist-info}/entry_points.txt +0 -0
- {kekikstream-1.6.8.dist-info → kekikstream-1.7.3.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-1.6.8.dist-info → kekikstream-1.7.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
class VidPapi(ExtractorBase):
|
|
7
|
+
name = "VidApi"
|
|
8
|
+
main_url = "https://vidpapi.xyz"
|
|
9
|
+
|
|
10
|
+
async def extract(self, url, referer=None) -> ExtractResult:
|
|
11
|
+
ext_ref = referer or ""
|
|
12
|
+
|
|
13
|
+
# URL parsing
|
|
14
|
+
if "video/" in url:
|
|
15
|
+
vid_id = url.split("video/")[-1]
|
|
16
|
+
else:
|
|
17
|
+
vid_id = url.split("?data=")[-1]
|
|
18
|
+
|
|
19
|
+
# 1. Altyazıları çek
|
|
20
|
+
sub_url = f"{self.main_url}/player/index.php?data={vid_id}"
|
|
21
|
+
sub_headers = {
|
|
22
|
+
"Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
|
|
23
|
+
"X-Requested-With" : "XMLHttpRequest",
|
|
24
|
+
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0",
|
|
25
|
+
"Referer" : ext_ref or "https://kultfilmler.pro/"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
subtitles = []
|
|
29
|
+
try:
|
|
30
|
+
sub_istek = await self.cffi.post(
|
|
31
|
+
url = sub_url,
|
|
32
|
+
headers = sub_headers,
|
|
33
|
+
data = {"hash": vid_id, "r": "https://kultfilmler.pro/"}
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
subtitle_match = re.search(r'var playerjsSubtitle = "([^"]*)"', sub_istek.text, re.IGNORECASE)
|
|
37
|
+
if subtitle_match and subtitle_match.group(1):
|
|
38
|
+
raw_subs = subtitle_match.group(1)
|
|
39
|
+
|
|
40
|
+
found_subs = re.findall(r'\[(.*?)\](.*?)(?:,|$)', raw_subs)
|
|
41
|
+
for lang, sub_link in found_subs:
|
|
42
|
+
lang = lang.strip()
|
|
43
|
+
if "Türkçe" in lang:
|
|
44
|
+
lang_code = "tr"
|
|
45
|
+
lang_name = "Turkish"
|
|
46
|
+
elif "İngilizce" in lang:
|
|
47
|
+
lang_code = "en"
|
|
48
|
+
lang_name = "English"
|
|
49
|
+
else:
|
|
50
|
+
lang_code = lang[:2].lower()
|
|
51
|
+
lang_name = lang
|
|
52
|
+
|
|
53
|
+
subtitles.append(Subtitle(
|
|
54
|
+
name = lang_name,
|
|
55
|
+
url = sub_link.strip()
|
|
56
|
+
))
|
|
57
|
+
|
|
58
|
+
except Exception as e:
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
# 2. Videoyu çek
|
|
62
|
+
video_url = f"{self.main_url}/player/index.php?data={vid_id}&do=getVideo"
|
|
63
|
+
video_headers = sub_headers.copy()
|
|
64
|
+
|
|
65
|
+
response = await self.cffi.post(
|
|
66
|
+
url = video_url,
|
|
67
|
+
headers = video_headers,
|
|
68
|
+
data = {"hash": vid_id, "r": "https://kultfilmler.pro/"}
|
|
69
|
+
)
|
|
70
|
+
response.raise_for_status()
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
video_data = response.json()
|
|
74
|
+
except Exception:
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
stream_url = video_data.get("securedLink")
|
|
78
|
+
if not stream_url or not stream_url.strip():
|
|
79
|
+
stream_url = video_data.get("videoSource")
|
|
80
|
+
|
|
81
|
+
if not stream_url:
|
|
82
|
+
raise ValueError("No video link found in VidPapi response")
|
|
83
|
+
|
|
84
|
+
return ExtractResult(
|
|
85
|
+
name = self.name,
|
|
86
|
+
url = stream_url,
|
|
87
|
+
referer = ext_ref or self.main_url,
|
|
88
|
+
headers = {},
|
|
89
|
+
subtitles = subtitles
|
|
90
|
+
)
|
|
@@ -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
|
+
)
|
|
@@ -0,0 +1,246 @@
|
|
|
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
|
|
6
|
+
|
|
7
|
+
class DiziPal(PluginBase):
|
|
8
|
+
name = "DiziPal"
|
|
9
|
+
language = "tr"
|
|
10
|
+
main_url = "https://dizipal1222.com"
|
|
11
|
+
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
12
|
+
description = "Yabancı Dizi ve Film izle."
|
|
13
|
+
|
|
14
|
+
main_page = {
|
|
15
|
+
f"{main_url}/diziler/son-bolumler" : "Son Bölümler",
|
|
16
|
+
f"{main_url}/diziler" : "Yeni Diziler",
|
|
17
|
+
f"{main_url}/filmler" : "Yeni Filmler",
|
|
18
|
+
f"{main_url}/koleksiyon/netflix" : "Netflix",
|
|
19
|
+
f"{main_url}/koleksiyon/exxen" : "Exxen",
|
|
20
|
+
f"{main_url}/koleksiyon/blutv" : "BluTV",
|
|
21
|
+
f"{main_url}/koleksiyon/disney" : "Disney+",
|
|
22
|
+
f"{main_url}/koleksiyon/amazon-prime" : "Amazon Prime",
|
|
23
|
+
f"{main_url}/koleksiyon/tod-bein" : "TOD (beIN)",
|
|
24
|
+
f"{main_url}/koleksiyon/gain" : "Gain",
|
|
25
|
+
f"{main_url}/tur/mubi" : "Mubi",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
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
|
+
results = []
|
|
33
|
+
|
|
34
|
+
if "/son-bolumler" in url:
|
|
35
|
+
for veri in secici.css("div.episode-item"):
|
|
36
|
+
name = veri.css("div.name::text").get()
|
|
37
|
+
episode = veri.css("div.episode::text").get()
|
|
38
|
+
href = veri.css("a::attr(href)").get()
|
|
39
|
+
poster = veri.css("img::attr(src)").get()
|
|
40
|
+
|
|
41
|
+
if name and href:
|
|
42
|
+
ep_text = episode.strip().replace(". Sezon ", "x").replace(". Bölüm", "") if episode else ""
|
|
43
|
+
title = f"{name} {ep_text}"
|
|
44
|
+
# Son bölümler linkini dizi sayfasına çevir
|
|
45
|
+
dizi_url = href.split("/sezon")[0] if "/sezon" in href else href
|
|
46
|
+
|
|
47
|
+
results.append(MainPageResult(
|
|
48
|
+
category = category,
|
|
49
|
+
title = title,
|
|
50
|
+
url = self.fix_url(dizi_url),
|
|
51
|
+
poster = self.fix_url(poster) if poster else None,
|
|
52
|
+
))
|
|
53
|
+
else:
|
|
54
|
+
for veri in secici.css("article.type2 ul li"):
|
|
55
|
+
title = veri.css("span.title::text").get()
|
|
56
|
+
href = veri.css("a::attr(href)").get()
|
|
57
|
+
poster = veri.css("img::attr(src)").get()
|
|
58
|
+
|
|
59
|
+
if title and href:
|
|
60
|
+
results.append(MainPageResult(
|
|
61
|
+
category = category,
|
|
62
|
+
title = title,
|
|
63
|
+
url = self.fix_url(href),
|
|
64
|
+
poster = self.fix_url(poster) if poster else None,
|
|
65
|
+
))
|
|
66
|
+
|
|
67
|
+
return results
|
|
68
|
+
|
|
69
|
+
async def search(self, query: str) -> list[SearchResult]:
|
|
70
|
+
self.cffi.headers.update({
|
|
71
|
+
"Accept" : "application/json, text/javascript, */*; q=0.01",
|
|
72
|
+
"X-Requested-With" : "XMLHttpRequest"
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
istek = await self.cffi.post(
|
|
76
|
+
url = f"{self.main_url}/api/search-autocomplete",
|
|
77
|
+
data = {"query": query}
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
data = istek.json()
|
|
82
|
+
except Exception:
|
|
83
|
+
return []
|
|
84
|
+
|
|
85
|
+
results = []
|
|
86
|
+
|
|
87
|
+
# API bazen dict, bazen list döner
|
|
88
|
+
items = data.values() if isinstance(data, dict) else data
|
|
89
|
+
|
|
90
|
+
for item in items:
|
|
91
|
+
if not isinstance(item, dict):
|
|
92
|
+
continue
|
|
93
|
+
|
|
94
|
+
title = item.get("title")
|
|
95
|
+
url = item.get("url")
|
|
96
|
+
poster = item.get("poster")
|
|
97
|
+
|
|
98
|
+
if title and url:
|
|
99
|
+
results.append(SearchResult(
|
|
100
|
+
title = title,
|
|
101
|
+
url = f"{self.main_url}{url}",
|
|
102
|
+
poster = self.fix_url(poster) if poster else None,
|
|
103
|
+
))
|
|
104
|
+
|
|
105
|
+
return results
|
|
106
|
+
|
|
107
|
+
async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
|
|
108
|
+
# Reset headers to get HTML response
|
|
109
|
+
self.cffi.headers.update({
|
|
110
|
+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
|
111
|
+
})
|
|
112
|
+
self.cffi.headers.pop("X-Requested-With", None)
|
|
113
|
+
|
|
114
|
+
istek = await self.cffi.get(url)
|
|
115
|
+
secici = Selector(text=istek.text, type="html")
|
|
116
|
+
|
|
117
|
+
poster = self.fix_url(secici.css("meta[property='og:image']::attr(content)").get())
|
|
118
|
+
year = secici.xpath("//div[text()='Yapım Yılı']//following-sibling::div/text()").get()
|
|
119
|
+
description = secici.css("div.summary p::text").get()
|
|
120
|
+
rating = secici.xpath("//div[text()='IMDB Puanı']//following-sibling::div/text()").get()
|
|
121
|
+
tags_raw = secici.xpath("//div[text()='Türler']//following-sibling::div/text()").get()
|
|
122
|
+
tags = [t.strip() for t in tags_raw.split() if t.strip()] if tags_raw else None
|
|
123
|
+
|
|
124
|
+
dur_text = secici.xpath("//div[text()='Ortalama Süre']//following-sibling::div/text()").get()
|
|
125
|
+
dur_match = re.search(r"(\d+)", dur_text or "")
|
|
126
|
+
duration = int(dur_match[1]) if dur_match else None
|
|
127
|
+
|
|
128
|
+
if "/dizi/" in url:
|
|
129
|
+
title = secici.css("div.cover h5::text").get()
|
|
130
|
+
|
|
131
|
+
episodes = []
|
|
132
|
+
for ep in secici.css("div.episode-item"):
|
|
133
|
+
ep_name = ep.css("div.name::text").get()
|
|
134
|
+
ep_href = ep.css("a::attr(href)").get()
|
|
135
|
+
ep_text = ep.css("div.episode::text").get() or ""
|
|
136
|
+
ep_parts = ep_text.strip().split(" ")
|
|
137
|
+
|
|
138
|
+
ep_season = None
|
|
139
|
+
ep_episode = None
|
|
140
|
+
if len(ep_parts) >= 4:
|
|
141
|
+
try:
|
|
142
|
+
ep_season = int(ep_parts[0].replace(".", ""))
|
|
143
|
+
ep_episode = int(ep_parts[2].replace(".", ""))
|
|
144
|
+
except ValueError:
|
|
145
|
+
pass
|
|
146
|
+
|
|
147
|
+
if ep_name and ep_href:
|
|
148
|
+
episodes.append(Episode(
|
|
149
|
+
season = ep_season,
|
|
150
|
+
episode = ep_episode,
|
|
151
|
+
title = ep_name.strip(),
|
|
152
|
+
url = self.fix_url(ep_href),
|
|
153
|
+
))
|
|
154
|
+
|
|
155
|
+
return SeriesInfo(
|
|
156
|
+
url = url,
|
|
157
|
+
poster = poster,
|
|
158
|
+
title = title,
|
|
159
|
+
description = description.strip() if description else None,
|
|
160
|
+
tags = tags,
|
|
161
|
+
rating = rating.strip() if rating else None,
|
|
162
|
+
year = year.strip() if year else None,
|
|
163
|
+
duration = duration,
|
|
164
|
+
episodes = episodes if episodes else None,
|
|
165
|
+
)
|
|
166
|
+
else:
|
|
167
|
+
title = secici.xpath("//div[@class='g-title'][2]/div/text()").get()
|
|
168
|
+
|
|
169
|
+
return MovieInfo(
|
|
170
|
+
url = url,
|
|
171
|
+
poster = poster,
|
|
172
|
+
title = title.strip() if title else None,
|
|
173
|
+
description = description.strip() if description else None,
|
|
174
|
+
tags = tags,
|
|
175
|
+
rating = rating.strip() if rating else None,
|
|
176
|
+
year = year.strip() if year else None,
|
|
177
|
+
duration = duration,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
async def load_links(self, url: str) -> list[dict]:
|
|
181
|
+
# Reset headers to get HTML response
|
|
182
|
+
self.cffi.headers.update({
|
|
183
|
+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
|
184
|
+
})
|
|
185
|
+
self.cffi.headers.pop("X-Requested-With", None)
|
|
186
|
+
|
|
187
|
+
istek = await self.cffi.get(url)
|
|
188
|
+
secici = Selector(istek.text)
|
|
189
|
+
|
|
190
|
+
iframe = secici.css(".series-player-container iframe::attr(src)").get()
|
|
191
|
+
if not iframe:
|
|
192
|
+
iframe = secici.css("div#vast_new iframe::attr(src)").get()
|
|
193
|
+
|
|
194
|
+
if not iframe:
|
|
195
|
+
return []
|
|
196
|
+
|
|
197
|
+
results = []
|
|
198
|
+
|
|
199
|
+
self.cffi.headers.update({"Referer": f"{self.main_url}/"})
|
|
200
|
+
i_istek = await self.cffi.get(iframe)
|
|
201
|
+
i_text = i_istek.text
|
|
202
|
+
|
|
203
|
+
# m3u link çıkar
|
|
204
|
+
m3u_match = re.search(r'file:"([^"]+)"', i_text)
|
|
205
|
+
if m3u_match:
|
|
206
|
+
m3u_link = m3u_match[1]
|
|
207
|
+
|
|
208
|
+
# Altyazıları çıkar
|
|
209
|
+
subtitles = []
|
|
210
|
+
sub_match = re.search(r'"subtitle":"([^"]+)"', i_text)
|
|
211
|
+
if sub_match:
|
|
212
|
+
sub_text = sub_match[1]
|
|
213
|
+
if "," in sub_text:
|
|
214
|
+
for sub in sub_text.split(","):
|
|
215
|
+
lang = sub.split("[")[1].split("]")[0] if "[" in sub else "Türkçe"
|
|
216
|
+
sub_url = sub.replace(f"[{lang}]", "")
|
|
217
|
+
subtitles.append(Subtitle(name=lang, url=self.fix_url(sub_url)))
|
|
218
|
+
else:
|
|
219
|
+
lang = sub_text.split("[")[1].split("]")[0] if "[" in sub_text else "Türkçe"
|
|
220
|
+
sub_url = sub_text.replace(f"[{lang}]", "")
|
|
221
|
+
subtitles.append(Subtitle(name=lang, url=self.fix_url(sub_url)))
|
|
222
|
+
|
|
223
|
+
results.append({
|
|
224
|
+
"name" : self.name,
|
|
225
|
+
"url" : m3u_link,
|
|
226
|
+
"referer" : f"{self.main_url}/",
|
|
227
|
+
"subtitles" : subtitles
|
|
228
|
+
})
|
|
229
|
+
else:
|
|
230
|
+
# Extractor'a yönlendir
|
|
231
|
+
extractor = self.ex_manager.find_extractor(iframe)
|
|
232
|
+
results.append({
|
|
233
|
+
"name" : f"{extractor.name if extractor else self.name}",
|
|
234
|
+
"url" : iframe,
|
|
235
|
+
"referer" : f"{self.main_url}/",
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
return results
|
|
239
|
+
|
|
240
|
+
async def play(self, name: str, url: str, referer: str, subtitles: list[Subtitle]):
|
|
241
|
+
extract_result = ExtractResult(name=name, url=url, referer=referer, subtitles=subtitles)
|
|
242
|
+
self.media_handler.title = name
|
|
243
|
+
if self.name not in self.media_handler.title:
|
|
244
|
+
self.media_handler.title = f"{self.name} | {self.media_handler.title}"
|
|
245
|
+
|
|
246
|
+
self.media_handler.play_media(extract_result)
|
KekikStream/Plugins/Dizilla.py
CHANGED
|
@@ -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
|
-
|
|
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
|