KekikStream 1.8.0__py3-none-any.whl → 1.8.2__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/Media/MediaHandler.py +32 -34
- KekikStream/Plugins/DiziPal.py +2 -2
- KekikStream/Plugins/DiziYou.py +40 -11
- KekikStream/Plugins/Dizilla.py +8 -5
- KekikStream/Plugins/FilmBip.py +1 -1
- KekikStream/Plugins/RoketDizi.py +102 -89
- KekikStream/Plugins/SinemaCX.py +1 -1
- {kekikstream-1.8.0.dist-info → kekikstream-1.8.2.dist-info}/METADATA +1 -1
- {kekikstream-1.8.0.dist-info → kekikstream-1.8.2.dist-info}/RECORD +13 -13
- {kekikstream-1.8.0.dist-info → kekikstream-1.8.2.dist-info}/WHEEL +0 -0
- {kekikstream-1.8.0.dist-info → kekikstream-1.8.2.dist-info}/entry_points.txt +0 -0
- {kekikstream-1.8.0.dist-info → kekikstream-1.8.2.dist-info}/licenses/LICENSE +0 -0
- {kekikstream-1.8.0.dist-info → kekikstream-1.8.2.dist-info}/top_level.txt +0 -0
|
@@ -6,37 +6,35 @@ import subprocess, os
|
|
|
6
6
|
|
|
7
7
|
class MediaHandler:
|
|
8
8
|
def __init__(self, title: str = "KekikStream"):
|
|
9
|
-
self.title
|
|
9
|
+
self.title = title
|
|
10
|
+
self.headers = {}
|
|
10
11
|
|
|
11
12
|
def play_media(self, extract_data: ExtractResult):
|
|
12
|
-
# Headers dict'ini user_agent ve referer'dan oluştur
|
|
13
|
-
headers = {}
|
|
14
|
-
|
|
15
13
|
# user-agent ekle (varsayılan veya extract_data'dan)
|
|
16
14
|
user_agent = extract_data.user_agent or "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5)"
|
|
17
|
-
headers["user-agent"] = user_agent
|
|
18
|
-
|
|
15
|
+
self.headers["user-agent"] = user_agent
|
|
16
|
+
|
|
19
17
|
# referer ekle
|
|
20
18
|
if extract_data.referer:
|
|
21
|
-
headers["referer"] = extract_data.referer
|
|
22
|
-
|
|
19
|
+
self.headers["referer"] = extract_data.referer
|
|
20
|
+
|
|
23
21
|
# Google Drive gibi özel durumlar için yt-dlp kullan
|
|
24
22
|
if user_agent in ["googleusercontent", "Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0"]:
|
|
25
|
-
return self.play_with_ytdlp(extract_data
|
|
23
|
+
return self.play_with_ytdlp(extract_data)
|
|
26
24
|
|
|
27
25
|
# İşletim sistemine göre oynatıcı seç
|
|
28
26
|
if subprocess.check_output(['uname', '-o']).strip() == b'Android':
|
|
29
|
-
return self.play_with_android_mxplayer(extract_data
|
|
27
|
+
return self.play_with_android_mxplayer(extract_data)
|
|
30
28
|
|
|
31
29
|
# Alt yazılar varsa mpv kullan
|
|
32
30
|
if extract_data.subtitles:
|
|
33
|
-
return self.play_with_mpv(extract_data
|
|
31
|
+
return self.play_with_mpv(extract_data)
|
|
34
32
|
|
|
35
|
-
return self.play_with_vlc(extract_data
|
|
33
|
+
return self.play_with_vlc(extract_data) or self.play_with_mpv(extract_data)
|
|
36
34
|
|
|
37
|
-
def play_with_vlc(self, extract_data: ExtractResult
|
|
35
|
+
def play_with_vlc(self, extract_data: ExtractResult):
|
|
38
36
|
konsol.log(f"[yellow][»] VLC ile Oynatılıyor : {extract_data.url}")
|
|
39
|
-
# konsol.print(headers)
|
|
37
|
+
# konsol.print(self.headers)
|
|
40
38
|
try:
|
|
41
39
|
vlc_command = ["vlc", "--quiet"]
|
|
42
40
|
|
|
@@ -46,11 +44,11 @@ class MediaHandler:
|
|
|
46
44
|
f"--input-title-format={self.title}"
|
|
47
45
|
])
|
|
48
46
|
|
|
49
|
-
if "user-agent" in headers:
|
|
50
|
-
vlc_command.append(f"--http-user-agent={headers.get('user-agent')}")
|
|
47
|
+
if "user-agent" in self.headers:
|
|
48
|
+
vlc_command.append(f"--http-user-agent={self.headers.get('user-agent')}")
|
|
51
49
|
|
|
52
|
-
if "referer" in headers:
|
|
53
|
-
vlc_command.append(f"--http-referrer={headers.get('referer')}")
|
|
50
|
+
if "referer" in self.headers:
|
|
51
|
+
vlc_command.append(f"--http-referrer={self.headers.get('referer')}")
|
|
54
52
|
|
|
55
53
|
vlc_command.extend(
|
|
56
54
|
f"--sub-file={subtitle.url}" for subtitle in extract_data.subtitles
|
|
@@ -63,23 +61,23 @@ class MediaHandler:
|
|
|
63
61
|
return True
|
|
64
62
|
except subprocess.CalledProcessError as hata:
|
|
65
63
|
konsol.print(f"[red]VLC oynatma hatası: {hata}[/red]")
|
|
66
|
-
konsol.print({"title": self.title, "url": extract_data.url, "headers": headers})
|
|
64
|
+
konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
|
|
67
65
|
return False
|
|
68
66
|
except FileNotFoundError:
|
|
69
67
|
konsol.print("[red]VLC bulunamadı! VLC kurulu olduğundan emin olun.[/red]")
|
|
70
|
-
# konsol.print({"title": self.title, "url": extract_data.url, "headers": headers})
|
|
68
|
+
# konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
|
|
71
69
|
return False
|
|
72
70
|
|
|
73
|
-
def play_with_mpv(self, extract_data: ExtractResult
|
|
71
|
+
def play_with_mpv(self, extract_data: ExtractResult):
|
|
74
72
|
konsol.log(f"[yellow][»] MPV ile Oynatılıyor : {extract_data.url}")
|
|
75
|
-
# konsol.print(headers)
|
|
73
|
+
# konsol.print(self.headers)
|
|
76
74
|
try:
|
|
77
75
|
mpv_command = ["mpv"]
|
|
78
76
|
|
|
79
77
|
if self.title:
|
|
80
78
|
mpv_command.append(f"--force-media-title={self.title}")
|
|
81
79
|
|
|
82
|
-
for key, value in headers.items():
|
|
80
|
+
for key, value in self.headers.items():
|
|
83
81
|
mpv_command.append(f"--http-header-fields={key}: {value}")
|
|
84
82
|
|
|
85
83
|
mpv_command.extend(
|
|
@@ -92,18 +90,18 @@ class MediaHandler:
|
|
|
92
90
|
|
|
93
91
|
except subprocess.CalledProcessError as hata:
|
|
94
92
|
konsol.print(f"[red]mpv oynatma hatası: {hata}[/red]")
|
|
95
|
-
konsol.print({"title": self.title, "url": extract_data.url, "headers": headers})
|
|
93
|
+
konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
|
|
96
94
|
except FileNotFoundError:
|
|
97
95
|
konsol.print("[red]mpv bulunamadı! mpv kurulu olduğundan emin olun.[/red]")
|
|
98
|
-
konsol.print({"title": self.title, "url": extract_data.url, "headers": headers})
|
|
96
|
+
konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
|
|
99
97
|
|
|
100
|
-
def play_with_ytdlp(self, extract_data: ExtractResult
|
|
98
|
+
def play_with_ytdlp(self, extract_data: ExtractResult):
|
|
101
99
|
konsol.log(f"[yellow][»] yt-dlp ile Oynatılıyor : {extract_data.url}")
|
|
102
|
-
# konsol.print(headers)
|
|
100
|
+
# konsol.print(self.headers)
|
|
103
101
|
try:
|
|
104
102
|
ytdlp_command = ["yt-dlp", "--quiet", "--no-warnings"]
|
|
105
103
|
|
|
106
|
-
for key, value in headers.items():
|
|
104
|
+
for key, value in self.headers.items():
|
|
107
105
|
ytdlp_command.extend(["--add-header", f"{key}: {value}"])
|
|
108
106
|
|
|
109
107
|
ytdlp_command.extend([
|
|
@@ -125,14 +123,14 @@ class MediaHandler:
|
|
|
125
123
|
|
|
126
124
|
except subprocess.CalledProcessError as hata:
|
|
127
125
|
konsol.print(f"[red]Oynatma hatası: {hata}[/red]")
|
|
128
|
-
konsol.print({"title": self.title, "url": extract_data.url, "headers": headers})
|
|
126
|
+
konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
|
|
129
127
|
except FileNotFoundError:
|
|
130
128
|
konsol.print("[red]yt-dlp veya mpv bulunamadı! Kurulumlarından emin olun.[/red]")
|
|
131
|
-
konsol.print({"title": self.title, "url": extract_data.url, "headers": headers})
|
|
129
|
+
konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
|
|
132
130
|
|
|
133
|
-
def play_with_android_mxplayer(self, extract_data: ExtractResult
|
|
131
|
+
def play_with_android_mxplayer(self, extract_data: ExtractResult):
|
|
134
132
|
konsol.log(f"[yellow][»] MxPlayer ile Oynatılıyor : {extract_data.url}")
|
|
135
|
-
# konsol.print(headers)
|
|
133
|
+
# konsol.print(self.headers)
|
|
136
134
|
paketler = [
|
|
137
135
|
"com.mxtech.videoplayer.ad/.ActivityScreen", # Free sürüm
|
|
138
136
|
"com.mxtech.videoplayer.pro/.ActivityScreen" # Pro sürüm
|
|
@@ -157,7 +155,7 @@ class MediaHandler:
|
|
|
157
155
|
|
|
158
156
|
except subprocess.CalledProcessError as hata:
|
|
159
157
|
konsol.print(f"[red]{paket} oynatma hatası: {hata}[/red]")
|
|
160
|
-
konsol.print({"title": self.title, "url": extract_data.url, "headers": headers})
|
|
158
|
+
konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
|
|
161
159
|
except FileNotFoundError:
|
|
162
160
|
konsol.print(f"Paket: {paket}, Hata: MX Player kurulu değil")
|
|
163
|
-
konsol.print({"title": self.title, "url": extract_data.url, "headers": headers})
|
|
161
|
+
konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
|
KekikStream/Plugins/DiziPal.py
CHANGED
|
@@ -7,9 +7,9 @@ import re
|
|
|
7
7
|
class DiziPal(PluginBase):
|
|
8
8
|
name = "DiziPal"
|
|
9
9
|
language = "tr"
|
|
10
|
-
main_url = "https://
|
|
10
|
+
main_url = "https://dizipal1223.com"
|
|
11
11
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
12
|
-
description = "
|
|
12
|
+
description = "dizipal güncel, dizipal yeni ve gerçek adresi. dizipal en yeni dizi ve filmleri güvenli ve hızlı şekilde sunar."
|
|
13
13
|
|
|
14
14
|
main_page = {
|
|
15
15
|
f"{main_url}/diziler/son-bolumler" : "Son Bölümler",
|
KekikStream/Plugins/DiziYou.py
CHANGED
|
@@ -53,7 +53,7 @@ class DiziYou(PluginBase):
|
|
|
53
53
|
SearchResult(
|
|
54
54
|
title = afis.css("div#categorytitle a::text").get().strip(),
|
|
55
55
|
url = self.fix_url(afis.css("div#categorytitle a::attr(href)").get()),
|
|
56
|
-
poster = self.fix_url(afis.css("img::attr(src)").get())
|
|
56
|
+
poster = self.fix_url(afis.css("img::attr(src)").get() or afis.css("img::attr(data-src)").get())
|
|
57
57
|
)
|
|
58
58
|
for afis in secici.css("div.incontent div#list-series")
|
|
59
59
|
]
|
|
@@ -63,8 +63,19 @@ class DiziYou(PluginBase):
|
|
|
63
63
|
istek = await self.httpx.get(url)
|
|
64
64
|
secici = Selector(istek.text)
|
|
65
65
|
|
|
66
|
-
title
|
|
67
|
-
|
|
66
|
+
# Title - div.title h1 içinde
|
|
67
|
+
title_raw = secici.css("div.title h1::text").get()
|
|
68
|
+
title = title_raw.strip() if title_raw else ""
|
|
69
|
+
|
|
70
|
+
# Fallback: Eğer title boşsa URL'den çıkar (telif kısıtlaması olan sayfalar için)
|
|
71
|
+
if not title:
|
|
72
|
+
# URL'den slug'ı al: https://www.diziyou.one/jasmine/ -> jasmine -> Jasmine
|
|
73
|
+
slug = url.rstrip('/').split('/')[-1]
|
|
74
|
+
title = slug.replace('-', ' ').title()
|
|
75
|
+
|
|
76
|
+
# Poster
|
|
77
|
+
poster_raw = secici.css("div.category_image img::attr(src)").get()
|
|
78
|
+
poster = self.fix_url(poster_raw) if poster_raw else ""
|
|
68
79
|
year = secici.xpath("//span[contains(., 'Yapım Yılı')]/following-sibling::text()[1]").get()
|
|
69
80
|
description = secici.css("div.diziyou_desc::text").get()
|
|
70
81
|
if description:
|
|
@@ -75,13 +86,21 @@ class DiziYou(PluginBase):
|
|
|
75
86
|
actors = [actor.strip() for actor in _actors.split(",")] if _actors else []
|
|
76
87
|
|
|
77
88
|
episodes = []
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
89
|
+
# Episodes - bolumust her bölüm için bir <a> içinde
|
|
90
|
+
# :has() parsel'de çalışmıyor, XPath kullanıyoruz
|
|
91
|
+
for link in secici.xpath('//a[div[@class="bolumust"]]'):
|
|
92
|
+
ep_name_raw = link.css("div.baslik::text").get()
|
|
93
|
+
if not ep_name_raw:
|
|
94
|
+
continue
|
|
95
|
+
ep_name = ep_name_raw.strip()
|
|
96
|
+
|
|
97
|
+
ep_href = self.fix_url(link.css("::attr(href)").get())
|
|
98
|
+
if not ep_href:
|
|
82
99
|
continue
|
|
83
100
|
|
|
84
|
-
|
|
101
|
+
# Bölüm ismi varsa al
|
|
102
|
+
ep_name_raw_clean = link.css("div.bolumismi::text").get()
|
|
103
|
+
ep_name_clean = ep_name_raw_clean.strip().replace("(", "").replace(")", "").strip() if ep_name_raw_clean else ep_name
|
|
85
104
|
|
|
86
105
|
ep_episode = re.search(r"(\d+)\. Bölüm", ep_name)[1]
|
|
87
106
|
ep_season = re.search(r"(\d+)\. Sezon", ep_name)[1]
|
|
@@ -112,9 +131,19 @@ class DiziYou(PluginBase):
|
|
|
112
131
|
istek = await self.httpx.get(url)
|
|
113
132
|
secici = Selector(istek.text)
|
|
114
133
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
134
|
+
# Title ve episode name - None kontrolü ekle
|
|
135
|
+
item_title_raw = secici.css("div.title h1::text").get()
|
|
136
|
+
item_title = item_title_raw.strip() if item_title_raw else ""
|
|
137
|
+
|
|
138
|
+
ep_name_raw = secici.css("div#bolum-ismi::text").get()
|
|
139
|
+
ep_name = ep_name_raw.strip() if ep_name_raw else ""
|
|
140
|
+
|
|
141
|
+
# Player src'den item_id çıkar
|
|
142
|
+
player_src = secici.css("iframe#diziyouPlayer::attr(src)").get()
|
|
143
|
+
if not player_src:
|
|
144
|
+
return [] # Player bulunamadıysa boş liste döndür
|
|
145
|
+
|
|
146
|
+
item_id = player_src.split("/")[-1].replace(".html", "")
|
|
118
147
|
|
|
119
148
|
subtitles = []
|
|
120
149
|
stream_urls = []
|
KekikStream/Plugins/Dizilla.py
CHANGED
|
@@ -16,7 +16,6 @@ class Dizilla(PluginBase):
|
|
|
16
16
|
|
|
17
17
|
main_page = {
|
|
18
18
|
f"{main_url}/tum-bolumler" : "Altyazılı Bölümler",
|
|
19
|
-
f"{main_url}/dublaj-bolumler" : "Dublaj Bölümler",
|
|
20
19
|
f"{main_url}/dizi-turu/aile" : "Aile",
|
|
21
20
|
f"{main_url}/dizi-turu/aksiyon" : "Aksiyon",
|
|
22
21
|
f"{main_url}/dizi-turu/bilim-kurgu" : "Bilim Kurgu",
|
|
@@ -35,11 +34,11 @@ class Dizilla(PluginBase):
|
|
|
35
34
|
ana_sayfa.extend([
|
|
36
35
|
MainPageResult(
|
|
37
36
|
category = category,
|
|
38
|
-
title = veri.css("
|
|
39
|
-
url = self.fix_url(veri.css("::attr(href)").get()),
|
|
37
|
+
title = veri.css("span.font-normal::text").get(),
|
|
38
|
+
url = self.fix_url(veri.css("a::attr(href)").get()),
|
|
40
39
|
poster = self.fix_url(veri.css("img::attr(src)").get() or veri.css("img::attr(data-src)").get())
|
|
41
40
|
)
|
|
42
|
-
for veri in secici.css("
|
|
41
|
+
for veri in secici.css("span.watchlistitem-")
|
|
43
42
|
])
|
|
44
43
|
else:
|
|
45
44
|
for veri in secici.css("div.tab-content > div.grid a"):
|
|
@@ -127,7 +126,11 @@ class Dizilla(PluginBase):
|
|
|
127
126
|
poster = self.fix_url(veri.get("image"))
|
|
128
127
|
description = veri.get("description")
|
|
129
128
|
year = veri.get("datePublished").split("-")[0]
|
|
130
|
-
|
|
129
|
+
|
|
130
|
+
# Tags extraction from page content (h3 tag)
|
|
131
|
+
tags_raw = secici.css("h3.text-white.opacity-60::text").get()
|
|
132
|
+
tags = [t.strip() for t in tags_raw.split(",")] if tags_raw else []
|
|
133
|
+
|
|
131
134
|
rating = veri.get("aggregateRating", {}).get("ratingValue")
|
|
132
135
|
actors = [actor.get("name") for actor in veri.get("actor", []) if actor.get("name")]
|
|
133
136
|
|
KekikStream/Plugins/FilmBip.py
CHANGED
|
@@ -8,7 +8,7 @@ class FilmBip(PluginBase):
|
|
|
8
8
|
language = "tr"
|
|
9
9
|
main_url = "https://filmbip.com"
|
|
10
10
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
11
|
-
description = "
|
|
11
|
+
description = "FilmBip adlı film sitemizde Full HD film izle. Yerli ve yabancı filmleri Türkçe dublaj veya altyazılı şekilde 1080p yüksek kalite film izle"
|
|
12
12
|
|
|
13
13
|
main_page = {
|
|
14
14
|
f"{main_url}/filmler/SAYFA" : "Yeni Filmler",
|
KekikStream/Plugins/RoketDizi.py
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, MovieInfo
|
|
4
4
|
from parsel import Selector
|
|
5
|
-
import re, base64, json
|
|
5
|
+
import re, base64, json
|
|
6
6
|
|
|
7
7
|
class RoketDizi(PluginBase):
|
|
8
8
|
name = "RoketDizi"
|
|
9
9
|
lang = "tr"
|
|
10
|
-
main_url = "https://
|
|
10
|
+
main_url = "https://roketdizi.to"
|
|
11
|
+
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
12
|
+
description = "Türkiye'nin en tatlış yabancı dizi izleme sitesi. Türkçe dublaj, altyazılı, eski ve yeni yabancı dizilerin yanı sıra kore (asya) dizileri izleyebilirsiniz."
|
|
11
13
|
|
|
12
14
|
# Domain doğrulama ve anti-bot mekanizmaları var
|
|
13
15
|
requires_cffi = True
|
|
@@ -25,81 +27,70 @@ class RoketDizi(PluginBase):
|
|
|
25
27
|
|
|
26
28
|
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
27
29
|
full_url = f"{self.main_url}/{url}?&page={page}"
|
|
28
|
-
resp
|
|
29
|
-
sel
|
|
30
|
+
resp = await self.cffi.get(full_url)
|
|
31
|
+
sel = Selector(resp.text)
|
|
30
32
|
|
|
31
33
|
results = []
|
|
32
34
|
|
|
33
35
|
for item in sel.css("div.w-full.p-4 span.bg-\\[\\#232323\\]"):
|
|
34
|
-
title
|
|
35
|
-
href
|
|
36
|
-
poster= item.css("img::attr(src)").get()
|
|
36
|
+
title = item.css("span.font-normal.line-clamp-1::text").get()
|
|
37
|
+
href = item.css("a::attr(href)").get()
|
|
38
|
+
poster = item.css("img::attr(src)").get()
|
|
37
39
|
|
|
38
40
|
if title and href:
|
|
39
41
|
results.append(MainPageResult(
|
|
40
|
-
category=category,
|
|
41
|
-
title=title,
|
|
42
|
-
url=self.fix_url(href),
|
|
43
|
-
poster=self.fix_url(poster)
|
|
42
|
+
category = category,
|
|
43
|
+
title = title,
|
|
44
|
+
url = self.fix_url(href),
|
|
45
|
+
poster = self.fix_url(poster)
|
|
44
46
|
))
|
|
45
47
|
return results
|
|
46
48
|
|
|
47
|
-
async def get_domain(self):
|
|
48
|
-
try:
|
|
49
|
-
domain_list = await self.cffi.get("https://raw.githubusercontent.com/Kraptor123/domainListesi/refs/heads/main/eklenti_domainleri.txt")
|
|
50
|
-
if domain_list.status_code == 200:
|
|
51
|
-
for line in domain_list.text.split("|"):
|
|
52
|
-
if line.strip().startswith("RoketDizi"):
|
|
53
|
-
domain = line.split(":")[-1].strip()
|
|
54
|
-
if "http" not in domain:
|
|
55
|
-
domain = f"https://{domain}"
|
|
56
|
-
return domain
|
|
57
|
-
except Exception:
|
|
58
|
-
pass
|
|
59
|
-
return self.main_url
|
|
60
|
-
|
|
61
49
|
async def search(self, query: str) -> list[SearchResult]:
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
# Get Cookies and Keys
|
|
65
|
-
main_req = await self.cffi.get(current_domain)
|
|
66
|
-
sel = Selector(main_req.text)
|
|
67
|
-
|
|
68
|
-
c_key = sel.css("input[name='cKey']::attr(value)").get()
|
|
69
|
-
c_value = sel.css("input[name='cValue']::attr(value)").get()
|
|
70
|
-
|
|
71
|
-
post_url = f"{current_domain}/api/bg/searchContent?searchterm={query}"
|
|
50
|
+
post_url = f"{self.main_url}/api/bg/searchContent?searchterm={query}"
|
|
72
51
|
|
|
73
52
|
headers = {
|
|
74
|
-
"Accept": "application/json, text/javascript, */*; q=0.01",
|
|
75
|
-
"X-Requested-With": "XMLHttpRequest",
|
|
76
|
-
"Referer": f"{
|
|
77
|
-
"CNT": "vakTR"
|
|
53
|
+
"Accept" : "application/json, text/javascript, */*; q=0.01",
|
|
54
|
+
"X-Requested-With" : "XMLHttpRequest",
|
|
55
|
+
"Referer" : f"{self.main_url}/",
|
|
78
56
|
}
|
|
79
|
-
|
|
80
|
-
data = {}
|
|
81
|
-
if c_key and c_value:
|
|
82
|
-
data = {"cKey": c_key, "cValue": c_value}
|
|
83
57
|
|
|
84
|
-
search_req = await self.cffi.post(post_url,
|
|
58
|
+
search_req = await self.cffi.post(post_url, headers=headers)
|
|
85
59
|
|
|
86
60
|
try:
|
|
87
61
|
resp_json = search_req.json()
|
|
88
|
-
|
|
62
|
+
|
|
63
|
+
# Response is base64 encoded!
|
|
64
|
+
if not resp_json.get("success"):
|
|
65
|
+
return []
|
|
66
|
+
|
|
67
|
+
encoded_response = resp_json.get("response", "")
|
|
68
|
+
if not encoded_response:
|
|
69
|
+
return []
|
|
70
|
+
|
|
71
|
+
# Decode base64
|
|
72
|
+
decoded = base64.b64decode(encoded_response).decode('utf-8')
|
|
73
|
+
data = json.loads(decoded)
|
|
74
|
+
|
|
75
|
+
if not data.get("state"):
|
|
89
76
|
return []
|
|
90
77
|
|
|
91
|
-
html_content = resp_json.get("html", "").strip()
|
|
92
|
-
sel_results = Selector(html_content)
|
|
93
|
-
|
|
94
78
|
results = []
|
|
95
|
-
|
|
79
|
+
result_items = data.get("result", [])
|
|
96
80
|
|
|
97
|
-
for
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
81
|
+
for item in result_items:
|
|
82
|
+
title = item.get("object_name", "")
|
|
83
|
+
slug = item.get("used_slug", "")
|
|
84
|
+
poster = item.get("object_poster_url", "")
|
|
85
|
+
|
|
86
|
+
if title and slug:
|
|
87
|
+
# Construct full URL from slug
|
|
88
|
+
full_url = f"{self.main_url}/{slug}"
|
|
89
|
+
results.append(SearchResult(
|
|
90
|
+
title = title.strip(),
|
|
91
|
+
url = full_url,
|
|
92
|
+
poster = self.fix_url(poster) if poster else None
|
|
93
|
+
))
|
|
103
94
|
|
|
104
95
|
return results
|
|
105
96
|
|
|
@@ -115,14 +106,41 @@ class RoketDizi(PluginBase):
|
|
|
115
106
|
poster = sel.css("div.w-full.page-top img::attr(src)").get()
|
|
116
107
|
description = sel.css("div.mt-2.text-sm::text").get()
|
|
117
108
|
|
|
118
|
-
|
|
109
|
+
# Tags - genre bilgileri (Detaylar bölümünde)
|
|
110
|
+
tags = []
|
|
111
|
+
genre_text = sel.css("h3.text-white.opacity-90::text").get()
|
|
112
|
+
if genre_text:
|
|
113
|
+
tags = [t.strip() for t in genre_text.split(",")]
|
|
119
114
|
|
|
120
|
-
|
|
121
|
-
if tags:
|
|
122
|
-
tags = [t.strip() for t in tags.split(",")]
|
|
123
|
-
|
|
115
|
+
# Rating
|
|
124
116
|
rating = sel.css("div.flex.items-center span.text-white.text-sm::text").get()
|
|
125
|
-
|
|
117
|
+
|
|
118
|
+
# Year ve Actors - Detaylar (Details) bölümünden
|
|
119
|
+
year = None
|
|
120
|
+
actors = []
|
|
121
|
+
|
|
122
|
+
# Detaylar bölümündeki tüm flex-col div'leri al
|
|
123
|
+
detail_items = sel.css("div.flex.flex-col")
|
|
124
|
+
for item in detail_items:
|
|
125
|
+
# Label ve value yapısı: span.text-base ve span.text-sm.opacity-90
|
|
126
|
+
label = item.css("span.text-base::text").get()
|
|
127
|
+
value = item.css("span.text-sm.opacity-90::text").get()
|
|
128
|
+
|
|
129
|
+
if label and value:
|
|
130
|
+
label = label.strip()
|
|
131
|
+
value = value.strip()
|
|
132
|
+
|
|
133
|
+
# Yayın tarihi (yıl)
|
|
134
|
+
if label == "Yayın tarihi":
|
|
135
|
+
# "16 Ekim 2018" formatından yılı çıkar
|
|
136
|
+
year_match = re.search(r'\d{4}', value)
|
|
137
|
+
if year_match:
|
|
138
|
+
year = year_match.group()
|
|
139
|
+
|
|
140
|
+
# Yaratıcılar veya Oyuncular
|
|
141
|
+
elif label in ["Yaratıcılar", "Oyuncular"]:
|
|
142
|
+
if value:
|
|
143
|
+
actors.append(value)
|
|
126
144
|
|
|
127
145
|
# Check urls for episodes
|
|
128
146
|
all_urls = re.findall(r'"url":"([^"]*)"', resp.text)
|
|
@@ -130,33 +148,38 @@ class RoketDizi(PluginBase):
|
|
|
130
148
|
|
|
131
149
|
episodes = []
|
|
132
150
|
if is_series:
|
|
133
|
-
|
|
151
|
+
# Dict kullanarak duplicate'leri önle ama sıralı tut
|
|
152
|
+
episodes_dict = {}
|
|
134
153
|
for u in all_urls:
|
|
135
|
-
if "bolum" in u and u not in
|
|
136
|
-
seen_eps.add(u)
|
|
154
|
+
if "bolum" in u and u not in episodes_dict:
|
|
137
155
|
season_match = re.search(r'/sezon-(\d+)', u)
|
|
138
156
|
ep_match = re.search(r'/bolum-(\d+)', u)
|
|
139
157
|
|
|
140
158
|
season = int(season_match.group(1)) if season_match else 1
|
|
141
159
|
episode_num = int(ep_match.group(1)) if ep_match else 1
|
|
142
160
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
161
|
+
# Key olarak (season, episode) tuple kullan
|
|
162
|
+
key = (season, episode_num)
|
|
163
|
+
episodes_dict[key] = Episode(
|
|
164
|
+
season = season,
|
|
165
|
+
episode = episode_num,
|
|
166
|
+
title = f"{season}. Sezon {episode_num}. Bölüm",
|
|
167
|
+
url = self.fix_url(u)
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
# Sıralı liste oluştur
|
|
171
|
+
episodes = [episodes_dict[key] for key in sorted(episodes_dict.keys())]
|
|
149
172
|
|
|
150
173
|
return SeriesInfo(
|
|
151
|
-
title=title,
|
|
152
|
-
url=url,
|
|
153
|
-
poster=self.fix_url(poster),
|
|
154
|
-
description=description,
|
|
155
|
-
tags=tags,
|
|
156
|
-
rating=rating,
|
|
157
|
-
actors=actors,
|
|
158
|
-
episodes=episodes,
|
|
159
|
-
year=year
|
|
174
|
+
title = title,
|
|
175
|
+
url = url,
|
|
176
|
+
poster = self.fix_url(poster),
|
|
177
|
+
description = description,
|
|
178
|
+
tags = tags,
|
|
179
|
+
rating = rating,
|
|
180
|
+
actors = actors,
|
|
181
|
+
episodes = episodes,
|
|
182
|
+
year = year
|
|
160
183
|
)
|
|
161
184
|
|
|
162
185
|
async def load_links(self, url: str) -> list[dict]:
|
|
@@ -195,13 +218,3 @@ class RoketDizi(PluginBase):
|
|
|
195
218
|
|
|
196
219
|
except Exception:
|
|
197
220
|
return []
|
|
198
|
-
|
|
199
|
-
def fix_url(self, url: str, domain:str=None) -> str:
|
|
200
|
-
if not url: return ""
|
|
201
|
-
if url.startswith("http"): return url
|
|
202
|
-
base = domain or self.main_url
|
|
203
|
-
return f"https:{url}" if url.startswith("//") else urllib.parse.urljoin(base, url)
|
|
204
|
-
|
|
205
|
-
def get_domain_sync(self, url:str):
|
|
206
|
-
parsed = urllib.parse.urlparse(url)
|
|
207
|
-
return f"{parsed.scheme}://{parsed.netloc}"
|
KekikStream/Plugins/SinemaCX.py
CHANGED
|
@@ -7,7 +7,7 @@ import re
|
|
|
7
7
|
class SinemaCX(PluginBase):
|
|
8
8
|
name = "SinemaCX"
|
|
9
9
|
language = "tr"
|
|
10
|
-
main_url = "https://www.sinema.
|
|
10
|
+
main_url = "https://www.sinema.onl"
|
|
11
11
|
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
12
12
|
description = "HD Film izle, Türkçe Dublaj ve Altyazılı filmler."
|
|
13
13
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: KekikStream
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.2
|
|
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
|
|
@@ -8,7 +8,7 @@ KekikStream/Core/Extractor/ExtractorBase.py,sha256=0GO8u5YzsboYMLk6kmSJmzqLZAbX_
|
|
|
8
8
|
KekikStream/Core/Extractor/ExtractorLoader.py,sha256=7uxUXTAuF65KKkmbI6iRiCiUhx-IqrronB7ixhchcTU,4289
|
|
9
9
|
KekikStream/Core/Extractor/ExtractorManager.py,sha256=4L1H3jiTnf0kTq4W6uS7n95bBYHlKJ8_hh0og8z4erQ,1244
|
|
10
10
|
KekikStream/Core/Extractor/ExtractorModels.py,sha256=Qj_gbIeGRewaZXNfYkTi4FFRRq6XBOc0HS0tXGDwajI,445
|
|
11
|
-
KekikStream/Core/Media/MediaHandler.py,sha256=
|
|
11
|
+
KekikStream/Core/Media/MediaHandler.py,sha256=taLA3rXsN_VfNn7nIc_OZKaaif8kuEZznhH_EaOiQQk,6874
|
|
12
12
|
KekikStream/Core/Media/MediaManager.py,sha256=AaUq2D7JSJIphjoAj2fjLOJjswm7Qf5hjYCbBdrbnDU,438
|
|
13
13
|
KekikStream/Core/Plugin/PluginBase.py,sha256=hlvErfJd_11wuhpIzI0Bfa0y3R4g5xM4VakSQJ-54mY,4425
|
|
14
14
|
KekikStream/Core/Plugin/PluginLoader.py,sha256=yZxMug-OcJ5RBm4fQkoquKrZxcBU7Pvt4IcY-d0WU8g,3393
|
|
@@ -56,10 +56,10 @@ KekikStream/Extractors/VidPapi.py,sha256=g9ohdL9VJrxy4N7xerbIRz3ZxjsXFHlJWy0NaZ3
|
|
|
56
56
|
KekikStream/Extractors/VideoSeyred.py,sha256=M6QPZ_isX9vM_7LPo-2I_8Cf1vB9awHw8vvzBODtoiQ,1977
|
|
57
57
|
KekikStream/Extractors/YildizKisaFilm.py,sha256=R_JlrOVeMiDlXYcuTdItnKvidyx8_u3B14fSrxew2aE,1316
|
|
58
58
|
KekikStream/Plugins/DiziBox.py,sha256=x7lChsXwaKbWeIPs9uN-jU1ZlVG73a7_1H5_emoPlUQ,10092
|
|
59
|
-
KekikStream/Plugins/DiziPal.py,sha256=
|
|
60
|
-
KekikStream/Plugins/DiziYou.py,sha256=
|
|
61
|
-
KekikStream/Plugins/Dizilla.py,sha256=
|
|
62
|
-
KekikStream/Plugins/FilmBip.py,sha256=
|
|
59
|
+
KekikStream/Plugins/DiziPal.py,sha256=MBONjermWBm3sN-8ZSILnfXI2F_V2kH65gpTNOuL9dI,10198
|
|
60
|
+
KekikStream/Plugins/DiziYou.py,sha256=Gj4PKMKHLO7yOfGt-W9XjXjGpYwnhiJGdzt0-mqMMiM,9145
|
|
61
|
+
KekikStream/Plugins/Dizilla.py,sha256=VrpX875q5zp27w0zWgN4NE-ImpuIGAFWxzVhVITbAl0,7588
|
|
62
|
+
KekikStream/Plugins/FilmBip.py,sha256=Tfx2dUc1Qs7ZQoJtsBtjOJXCKmTe56m74lNhuUYYU14,6182
|
|
63
63
|
KekikStream/Plugins/FilmMakinesi.py,sha256=CdV4k44dw0Q4rO3x4GobSDT1KGrkgit0OfTPxZfmfJ8,5314
|
|
64
64
|
KekikStream/Plugins/FilmModu.py,sha256=b27hchMoYZwG3I-kM1sveW7rHKOF5OuepdjPgKIehEM,6706
|
|
65
65
|
KekikStream/Plugins/FullHDFilm.py,sha256=kkb-JtWf23uiEzP9f_uds0tROYiKOyxcX0D-jNtQFi0,7005
|
|
@@ -68,18 +68,18 @@ KekikStream/Plugins/HDFilmCehennemi.py,sha256=cI8pQEPF0xo9vVI2fCPktjvCuH8N8f5lI0
|
|
|
68
68
|
KekikStream/Plugins/JetFilmizle.py,sha256=0UgHnBTkd4mMXKSLjYxAixFMGXrVa0qOLqYiLb6RKZQ,6092
|
|
69
69
|
KekikStream/Plugins/KultFilmler.py,sha256=VZET3RUoOVYKE-C2YbkMW8oNcxz6zE2pR7a3z-B4nD4,8987
|
|
70
70
|
KekikStream/Plugins/RecTV.py,sha256=dJBHc0Um-hizxj__lz3To0mA7An86YpoN3hZPX4xJic,7673
|
|
71
|
-
KekikStream/Plugins/RoketDizi.py,sha256=
|
|
71
|
+
KekikStream/Plugins/RoketDizi.py,sha256=C6ID2sfEwf0Tw8_tO-pc1nx8TB0Ii_rCVRzlHA7E-oA,8547
|
|
72
72
|
KekikStream/Plugins/SelcukFlix.py,sha256=F3Rv2TRpfM-SZUAqjTPsQChS_Ejoh5q1Mo5fBFlsLy0,9013
|
|
73
73
|
KekikStream/Plugins/SezonlukDizi.py,sha256=IomeNsVlji1TCimv8JwdMquKLcxZwwJQOZYzJ5v0OdE,6455
|
|
74
74
|
KekikStream/Plugins/SineWix.py,sha256=dPFUlHece9zo57Xjttdp_w-K9J_d1_8C-U6u1twWLh8,7493
|
|
75
75
|
KekikStream/Plugins/Sinefy.py,sha256=mRwtQYiH7I_1k4EZS0g4MhnRDEx0NXwY8sa5tI33dog,8368
|
|
76
|
-
KekikStream/Plugins/SinemaCX.py,sha256=
|
|
76
|
+
KekikStream/Plugins/SinemaCX.py,sha256=DUvYa7J4a2D5ivLO_sQiaStoV5FDxmz8onJyFwAidvY,7177
|
|
77
77
|
KekikStream/Plugins/Sinezy.py,sha256=t7InHEtKdIVyBQj8HJWwWcHhRP9AXKKXYE0O3YD8MYg,3647
|
|
78
78
|
KekikStream/Plugins/SuperFilmGeldi.py,sha256=Ohm21BPsJH_S1tx5i2APEgAOD25k2NiwRP7rSgAKvRs,5289
|
|
79
79
|
KekikStream/Plugins/UgurFilm.py,sha256=BUoDQOQF6tsj2tZj06OL9ga7j_oj116p3C2GQsnMXTU,4961
|
|
80
|
-
kekikstream-1.8.
|
|
81
|
-
kekikstream-1.8.
|
|
82
|
-
kekikstream-1.8.
|
|
83
|
-
kekikstream-1.8.
|
|
84
|
-
kekikstream-1.8.
|
|
85
|
-
kekikstream-1.8.
|
|
80
|
+
kekikstream-1.8.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
81
|
+
kekikstream-1.8.2.dist-info/METADATA,sha256=nXpNw-DQqIKw6ni5DSDAtdPUR913PoRoS5h-Hi4En7I,4983
|
|
82
|
+
kekikstream-1.8.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
83
|
+
kekikstream-1.8.2.dist-info/entry_points.txt,sha256=dFwdiTx8djyehI0Gsz-rZwjAfZzUzoBSrmzRu9ubjJc,50
|
|
84
|
+
kekikstream-1.8.2.dist-info/top_level.txt,sha256=DNmGJDXl27Drdfobrak8KYLmocW_uznVYFJOzcjUgmY,12
|
|
85
|
+
kekikstream-1.8.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|