Skip to content

Commit d2b7610

Browse files
committed
feat: Add LuciferPlays extractor and improve SuperFilmIzle plugin's multi-part video handling and actor parsing.
1 parent f51bd58 commit d2b7610

File tree

3 files changed

+138
-14
lines changed

3 files changed

+138
-14
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2+
3+
from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle, HTMLHelper
4+
from Kekik.Sifreleme import AESManager
5+
import json, contextlib
6+
7+
class LuciferPlays(ExtractorBase):
8+
name = "LuciferPlays"
9+
main_url = "https://luciferplays.com"
10+
11+
async def extract(self, url: str, referer: str = None) -> ExtractResult:
12+
# LuciferPlays genelde referer olarak kendi ana dizinini veya gömüldüğü sayfayı bekler
13+
self.httpx.headers.update({"Referer": referer or url})
14+
15+
resp = await self.httpx.get(url)
16+
sel = HTMLHelper(resp.text)
17+
18+
m3u8_url = None
19+
subtitles = []
20+
21+
# 1. bePlayer (AES Decryption)
22+
# patern: bePlayer('pass', '{"ct":"...", "iv":"...", "s":"..."}');
23+
if match := sel.regex_first(r"bePlayer\('([^']+)',\s*'(\{[^}]+\})'\);", group=None):
24+
pass_val, data_val = match
25+
with contextlib.suppress(Exception):
26+
decrypted = AESManager.decrypt(data_val, pass_val)
27+
28+
# Çözülen içerik genelde JSON formatındadır
29+
try:
30+
data = json.loads(decrypted)
31+
32+
# Video Lokasyonu (Donilas/HDMom Style)
33+
m3u8_url = data.get("video_location")
34+
35+
# Altyazılar
36+
for sub in data.get("strSubtitles", []):
37+
sub_url = self.fix_url(sub.get("file"))
38+
if sub_url and "Forced" not in sub.get("label", ""):
39+
subtitles.append(Subtitle(
40+
name = sub.get("label", "TR").upper(),
41+
url = sub_url
42+
))
43+
44+
# Eğer video_location bulunamadıysa MixPlay style kontrol et
45+
if not m3u8_url:
46+
client_data = data.get("schedule", {}).get("client", "")
47+
m3u8_url = HTMLHelper(client_data).regex_first(r'"video_location":"([^"]+)"')
48+
49+
except json.JSONDecodeError:
50+
# JSON değilse düz metin içinde ara
51+
m3u8_url = HTMLHelper(decrypted).regex_first(r'"video_location":"([^"]+)"')
52+
53+
# 2. Fallback (Düz JS içinde file ara)
54+
if not m3u8_url:
55+
m3u8_url = sel.regex_first(r'file\s*:\s*"([^"]+)"')
56+
57+
if not m3u8_url:
58+
raise ValueError(f"LuciferPlays: Video linki bulunamadı. {url}")
59+
60+
return ExtractResult(
61+
name = self.name,
62+
url = self.fix_url(m3u8_url),
63+
referer = url,
64+
subtitles = subtitles
65+
)

KekikStream/Plugins/SuperFilmIzle.py

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
22

33
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult, HTMLHelper
4+
import asyncio
45

56
class SuperFilmIzle(PluginBase):
67
name = "SuperFilmIzle"
@@ -91,7 +92,7 @@ async def load_item(self, url: str) -> MovieInfo:
9192
tags = secici.select_texts("ul.post-categories li a")
9293
rating = secici.select_text("div.imdb-count")
9394
rating = rating.replace("IMDB Puanı", "") if rating else None
94-
actors = secici.select_texts("div.actors a")
95+
actors = secici.select_texts("div.actors a") or secici.select_texts("div.cast a")
9596

9697
return MovieInfo(
9798
url = url,
@@ -105,15 +106,73 @@ async def load_item(self, url: str) -> MovieInfo:
105106
)
106107

107108
async def load_links(self, url: str) -> list[ExtractResult]:
108-
istek = await self.httpx.get(url)
109-
secici = HTMLHelper(istek.text)
110-
111-
iframe = secici.select_attr("div.video-content iframe", "src")
112-
iframe = self.fix_url(iframe) if iframe else None
113-
114-
if not iframe:
115-
return []
116-
117-
results = []
118-
119-
return results
109+
istek = await self.httpx.get(url)
110+
main_text = istek.text
111+
secici = HTMLHelper(main_text)
112+
113+
# 1. Alternatifleri / Parçaları Belirle
114+
# (url, name, needs_fetch)
115+
sources = []
116+
117+
# Keremiya / Movifox Alternatif Yapısı (li.part)
118+
part_items = secici.select("div#action-parts li.part")
119+
if part_items:
120+
for li in part_items:
121+
name = secici.select_text("div.part-name", li) or "Alternatif"
122+
123+
# Aktif olan parça (Mevcut sayfada)
124+
if "active" in li.attrs.get("class", []):
125+
sources.append((None, name, False))
126+
127+
# Pasif olanlar (Link verilmişse)
128+
elif a_tag := secici.select_first("a.post-page-numbers", li):
129+
href = a_tag.attrs.get("href")
130+
if href:
131+
sources.append((self.fix_url(href), name, True))
132+
else:
133+
# Alternatif menüsü yoksa tek parça olarak işle
134+
sources.append((None, "", False))
135+
136+
# 2. İşleme Görevlerini Hazırla
137+
extract_tasks = []
138+
139+
async def process_task(source_data):
140+
src_url, src_name, needs_fetch = source_data
141+
142+
# Iframe'i bulacağımız HTML kaynağını belirle
143+
html_to_parse = main_text
144+
if needs_fetch:
145+
try:
146+
resp = await self.httpx.get(src_url)
147+
html_to_parse = resp.text
148+
except:
149+
return []
150+
151+
# HTML içindeki iframeleri topla
152+
temp_secici = HTMLHelper(html_to_parse)
153+
iframes = []
154+
for ifr in temp_secici.select("div.video-content iframe"):
155+
if src := ifr.attrs.get("src") or ifr.attrs.get("data-src"):
156+
iframes.append(self.fix_url(src))
157+
158+
# Bulunan iframeleri extract et (prefix olarak parça adını ekle)
159+
results = []
160+
for ifr_url in iframes:
161+
if extracted := await self.extract(ifr_url, prefix=src_name or None):
162+
if isinstance(extracted, list):
163+
results.extend(extracted)
164+
else:
165+
results.append(extracted)
166+
return results
167+
168+
for src in sources:
169+
extract_tasks.append(process_task(src))
170+
171+
# 3. Tüm Görevleri Paralel Çalıştır ve Sonuçları Topla
172+
results_groups = await asyncio.gather(*extract_tasks)
173+
174+
final_results = []
175+
for group in results_groups:
176+
final_results.extend(group)
177+
178+
return final_results

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
setup(
77
# ? Genel Bilgiler
88
name = "KekikStream",
9-
version = "2.5.6",
9+
version = "2.5.7",
1010
url = "https://github.com/keyiflerolsun/KekikStream",
1111
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ı",
1212
keywords = ["KekikStream", "KekikAkademi", "keyiflerolsun"],

0 commit comments

Comments
 (0)