KekikStream 1.5.6__py3-none-any.whl → 1.5.7__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.
@@ -1,16 +1,16 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from . import konsol
4
- from rich.panel import Panel
5
- from pkg_resources import get_distribution
6
- from requests import get
7
- from subprocess import check_call
3
+ from . import konsol
4
+ from rich.panel import Panel
5
+ from importlib import metadata
6
+ from requests import get
7
+ from subprocess import check_call
8
8
  import sys
9
9
 
10
10
  def pypi_kontrol_guncelle(paket_adi: str):
11
11
  try:
12
12
  konsol.print(f"[bold cyan] {paket_adi} Güncellemesi kontrol ediliyor...[/bold cyan]")
13
- mevcut_surum = get_distribution(paket_adi).version
13
+ mevcut_surum = metadata.version(paket_adi)
14
14
  konsol.print(Panel(f"[cyan]Yüklü sürüm:[/cyan] [bold yellow]{mevcut_surum}[/bold yellow]"))
15
15
 
16
16
  istek = get(f"https://pypi.org/pypi/{paket_adi}/json")
@@ -34,11 +34,11 @@ class MediaHandler:
34
34
  if "Cookie" in self.headers or extract_data.subtitles:
35
35
  return self.play_with_mpv(extract_data)
36
36
 
37
- return self.play_with_vlc(extract_data)
37
+ return self.play_with_vlc(extract_data) or self.play_with_mpv(extract_data)
38
38
 
39
39
  def play_with_vlc(self, extract_data: ExtractResult):
40
40
  konsol.log(f"[yellow][»] VLC ile Oynatılıyor : {extract_data.url}")
41
- konsol.print(self.headers)
41
+ # konsol.print(self.headers)
42
42
  try:
43
43
  vlc_command = ["vlc", "--quiet"]
44
44
 
@@ -62,16 +62,19 @@ class MediaHandler:
62
62
  with open(os.devnull, "w") as devnull:
63
63
  subprocess.run(vlc_command, stdout=devnull, stderr=devnull, check=True)
64
64
 
65
+ return True
65
66
  except subprocess.CalledProcessError as hata:
66
67
  konsol.print(f"[red]VLC oynatma hatası: {hata}[/red]")
67
68
  konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
69
+ return False
68
70
  except FileNotFoundError:
69
71
  konsol.print("[red]VLC bulunamadı! VLC kurulu olduğundan emin olun.[/red]")
70
- konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
72
+ # konsol.print({"title": self.title, "url": extract_data.url, "headers": self.headers})
73
+ return False
71
74
 
72
75
  def play_with_mpv(self, extract_data: ExtractResult):
73
76
  konsol.log(f"[yellow][»] MPV ile Oynatılıyor : {extract_data.url}")
74
- konsol.print(self.headers)
77
+ # konsol.print(self.headers)
75
78
  try:
76
79
  mpv_command = ["mpv"]
77
80
 
@@ -98,7 +101,7 @@ class MediaHandler:
98
101
 
99
102
  def play_with_ytdlp(self, extract_data: ExtractResult):
100
103
  konsol.log(f"[yellow][»] yt-dlp ile Oynatılıyor : {extract_data.url}")
101
- konsol.print(self.headers)
104
+ # konsol.print(self.headers)
102
105
  try:
103
106
  ytdlp_command = ["yt-dlp", "--quiet", "--no-warnings"]
104
107
 
@@ -131,7 +134,7 @@ class MediaHandler:
131
134
 
132
135
  def play_with_android_mxplayer(self, extract_data: ExtractResult):
133
136
  konsol.log(f"[yellow][»] MxPlayer ile Oynatılıyor : {extract_data.url}")
134
- konsol.print(self.headers)
137
+ # konsol.print(self.headers)
135
138
  paketler = [
136
139
  "com.mxtech.videoplayer.ad/.ActivityScreen", # Free sürüm
137
140
  "com.mxtech.videoplayer.pro/.ActivityScreen" # Pro sürüm
@@ -1,11 +1,12 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from abc import ABC, abstractmethod
4
- from httpx import AsyncClient, Timeout
5
- from cloudscraper import CloudScraper
6
- from .PluginModels import MainPageResult, SearchResult, MovieInfo
7
- from ..Media.MediaHandler import MediaHandler
8
- from urllib.parse import urljoin
3
+ from abc import ABC, abstractmethod
4
+ from httpx import AsyncClient, Timeout
5
+ from cloudscraper import CloudScraper
6
+ from .PluginModels import MainPageResult, SearchResult, MovieInfo
7
+ from ..Media.MediaHandler import MediaHandler
8
+ from ..Extractor.ExtractorManager import ExtractorManager
9
+ from urllib.parse import urljoin
9
10
  import re
10
11
 
11
12
  class PluginBase(ABC):
@@ -34,6 +35,7 @@ class PluginBase(ABC):
34
35
  )
35
36
  self.media_handler = MediaHandler()
36
37
  self.cloudscraper = CloudScraper()
38
+ self.ex_manager = ExtractorManager()
37
39
  self.httpx.headers.update(self.cloudscraper.headers)
38
40
  self.httpx.cookies.update(self.cloudscraper.cookies)
39
41
 
@@ -53,8 +55,28 @@ class PluginBase(ABC):
53
55
  pass
54
56
 
55
57
  @abstractmethod
56
- async def load_links(self, url: str) -> list[str]:
57
- """Bir medya öğesi için oynatma bağlantılarını döndürür."""
58
+ async def load_links(self, url: str) -> list[dict]:
59
+ """
60
+ Bir medya öğesi için oynatma bağlantılarını döndürür.
61
+
62
+ Args:
63
+ url: Medya URL'si
64
+
65
+ Returns:
66
+ Dictionary listesi, her biri şu alanları içerir:
67
+ - url (str, zorunlu): Video URL'si
68
+ - name (str, zorunlu): Gösterim adı (tüm bilgileri içerir)
69
+ - referer (str, opsiyonel): Referer header
70
+ - subtitles (list, opsiyonel): Altyazı listesi
71
+
72
+ Example:
73
+ [
74
+ {
75
+ "url": "https://example.com/video.m3u8",
76
+ "name": "HDFilmCehennemi | 1080p TR Dublaj"
77
+ }
78
+ ]
79
+ """
58
80
  pass
59
81
 
60
82
  async def close(self):
@@ -20,9 +20,9 @@ class PluginLoader:
20
20
  plugins = {}
21
21
 
22
22
  # Global eklentileri yükle
23
- # if self.global_plugins_dir.exists():
23
+ if self.global_plugins_dir.exists():
24
24
  # konsol.log(f"[green][*] Global Eklenti dizininden yükleniyor: {self.global_plugins_dir}[/green]")
25
- # plugins |= self._load_from_directory(self.global_plugins_dir)
25
+ plugins |= self._load_from_directory(self.global_plugins_dir)
26
26
 
27
27
  # Yerel eklentileri yükle
28
28
  if self.local_plugins_dir.exists():
@@ -1,31 +1,12 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
3
  from KekikStream.Core import ExtractorBase, ExtractResult
4
- from Kekik.Sifreleme import Packer
5
- import re, base64
6
-
7
- def get_m3u_link(data: str) -> str:
8
- first = base64.b64decode(data)
9
- first_reversed = first[::-1]
10
-
11
- second = base64.b64decode(first_reversed)
12
-
13
- parts = second.decode('utf-8').split("|")
14
- if len(parts) < 2:
15
- raise ValueError("Decoded data has an unexpected format.")
16
-
17
- return parts[1]
18
-
19
- def extract_data(raw_script: str) -> str:
20
- pattern = re.compile(r'return result\}var .*?=.*?\("(.*?)"\)')
21
- if match := pattern.search(raw_script):
22
- return match[1]
23
- else:
24
- raise Exception("data not found")
4
+ from Kekik.Sifreleme import Packer, StreamDecoder
5
+ import re
25
6
 
26
7
  class CloseLoadExtractor(ExtractorBase):
27
8
  name = "CloseLoad"
28
- main_url = "https://closeload.filmmakinesi.de"
9
+ main_url = "https://closeload.filmmakinesi.sh"
29
10
 
30
11
  async def extract(self, url, referer=None) -> ExtractResult:
31
12
  if referer:
@@ -35,7 +16,7 @@ class CloseLoadExtractor(ExtractorBase):
35
16
  istek.raise_for_status()
36
17
 
37
18
  eval_func = re.compile(r'\s*(eval\(function[\s\S].*)\s*').findall(istek.text)[0]
38
- m3u_link = get_m3u_link(extract_data(Packer.unpack(eval_func)))
19
+ m3u_link = StreamDecoder.extract_stream_url(Packer.unpack(eval_func))
39
20
 
40
21
  await self.close()
41
22
  return ExtractResult(
@@ -18,24 +18,13 @@ class VidMoly(ExtractorBase):
18
18
  })
19
19
 
20
20
  if self.main_url.endswith(".me"):
21
- self.main_url = self.main_url.replace(".me", ".to")
22
- url = url.replace(".me", ".to")
21
+ self.main_url = self.main_url.replace(".me", ".net")
22
+ url = url.replace(".me", ".net")
23
23
 
24
- # Embed URL oluştur
25
- embed_url = url.replace("/w/", "/embed-") + "-920x360.html" if "/w/" in url else url
26
- script_content = None
27
- attempts = 0
24
+ response = await self.httpx.get(url)
28
25
 
29
- # Script verisini almak için deneme yap
30
- while attempts < 10 and not script_content:
31
- attempts += 1
32
- response = await self.httpx.get(embed_url)
33
- response.raise_for_status()
34
-
35
- script_match = re.search(r"sources:\s*\[(.*?)\],", response.text, re.DOTALL)
36
- script_content = script_match[1] if script_match else None
37
- if not script_content:
38
- await asyncio.sleep(0.5)
26
+ script_match = re.search(r"sources:\s*\[(.*?)\],", response.text, re.DOTALL)
27
+ script_content = script_match[1] if script_match else None
39
28
 
40
29
  if not script_content:
41
30
  raise ValueError("Gerekli script bulunamadı.")
@@ -40,7 +40,7 @@ class DiziBox(PluginBase):
40
40
  f"{main_url}/dizi-arsivi/page/SAYFA/?tur[0]=yarisma&yil&imdb" : "Yarışma"
41
41
  }
42
42
 
43
- @kekik_cache(ttl=60*60)
43
+ #@kekik_cache(ttl=60*60)
44
44
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
45
45
  istek = await self.httpx.get(
46
46
  url = f"{url.replace('SAYFA', str(page))}",
@@ -58,7 +58,7 @@ class DiziBox(PluginBase):
58
58
  for veri in secici.css("article.detailed-article")
59
59
  ]
60
60
 
61
- @kekik_cache(ttl=60*60)
61
+ #@kekik_cache(ttl=60*60)
62
62
  async def search(self, query: str) -> list[SearchResult]:
63
63
  self.httpx.cookies.update({
64
64
  "LockUser" : "true",
@@ -77,7 +77,7 @@ class DiziBox(PluginBase):
77
77
  for item in secici.css("article.detailed-article")
78
78
  ]
79
79
 
80
- @kekik_cache(ttl=60*60)
80
+ #@kekik_cache(ttl=60*60)
81
81
  async def load_item(self, url: str) -> SeriesInfo:
82
82
  istek = await self.httpx.get(url)
83
83
  secici = Selector(istek.text)
@@ -124,13 +124,19 @@ class DiziBox(PluginBase):
124
124
  actors = actors,
125
125
  )
126
126
 
127
- @kekik_cache(ttl=60*60)
127
+ #@kekik_cache(ttl=60*60)
128
128
  async def _iframe_decode(self, name:str, iframe_link:str, referer:str) -> list[str]:
129
129
  results = []
130
130
 
131
+ self.httpx.headers.update({"Referer": referer})
132
+ self.httpx.cookies.update({
133
+ "LockUser" : "true",
134
+ "isTrustedUser" : "true",
135
+ "dbxu" : "1722403730363"
136
+ })
137
+
131
138
  if "/player/king/king.php" in iframe_link:
132
139
  iframe_link = iframe_link.replace("king.php?v=", "king.php?wmode=opaque&v=")
133
- self.httpx.headers.update({"Referer": referer})
134
140
 
135
141
  istek = await self.httpx.get(iframe_link)
136
142
  secici = Selector(istek.text)
@@ -150,7 +156,6 @@ class DiziBox(PluginBase):
150
156
 
151
157
  elif "/player/moly/moly.php" in iframe_link:
152
158
  iframe_link = iframe_link.replace("moly.php?h=", "moly.php?wmode=opaque&h=")
153
- self.httpx.headers.update({"Referer": referer})
154
159
  while True:
155
160
  await asyncio.sleep(.3)
156
161
  with contextlib.suppress(Exception):
@@ -171,15 +176,20 @@ class DiziBox(PluginBase):
171
176
 
172
177
  return results
173
178
 
174
- @kekik_cache(ttl=15*60)
175
- async def load_links(self, url: str) -> list[str]:
179
+ #@kekik_cache(ttl=15*60)
180
+ async def load_links(self, url: str) -> list[dict]:
176
181
  istek = await self.httpx.get(url)
177
182
  secici = Selector(istek.text)
178
183
 
179
- iframes = []
184
+ results = []
180
185
  if main_iframe := secici.css("div#video-area iframe::attr(src)").get():
181
186
  if decoded := await self._iframe_decode(self.name, main_iframe, url):
182
- iframes.extend(decoded)
187
+ for iframe in decoded:
188
+ extractor = self.ex_manager.find_extractor(iframe)
189
+ results.append({
190
+ "url" : iframe,
191
+ "name" : f"{extractor.name if extractor else 'Main Player'}"
192
+ })
183
193
 
184
194
  for alternatif in secici.css("div.video-toolbar option[value]"):
185
195
  alt_name = alternatif.css("::text").get()
@@ -195,6 +205,11 @@ class DiziBox(PluginBase):
195
205
  alt_secici = Selector(alt_istek.text)
196
206
  if alt_iframe := alt_secici.css("div#video-area iframe::attr(src)").get():
197
207
  if decoded := await self._iframe_decode(alt_name, alt_iframe, url):
198
- iframes.extend(decoded)
199
-
200
- return iframes
208
+ for iframe in decoded:
209
+ extractor = self.ex_manager.find_extractor(iframe)
210
+ results.append({
211
+ "url" : iframe,
212
+ "name" : f"{extractor.name if extractor else alt_name}"
213
+ })
214
+
215
+ return results
@@ -7,7 +7,7 @@ import re
7
7
  class DiziYou(PluginBase):
8
8
  name = "DiziYou"
9
9
  language = "tr"
10
- main_url = "https://www.diziyou3.com"
10
+ main_url = "https://www.diziyou.mx"
11
11
  favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
12
12
  description = "Diziyou en kaliteli Türkçe dublaj ve altyazılı yabancı dizi izleme sitesidir. Güncel ve efsanevi dizileri 1080p Full HD kalitede izlemek için hemen tıkla!"
13
13
 
@@ -31,7 +31,7 @@ class DiziYou(PluginBase):
31
31
 
32
32
  _data = {}
33
33
 
34
- @kekik_cache(ttl=60*60)
34
+ #@kekik_cache(ttl=60*60)
35
35
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
36
36
  istek = await self.httpx.get(f"{url.replace('SAYFA', str(page))}")
37
37
  secici = Selector(istek.text)
@@ -46,7 +46,7 @@ class DiziYou(PluginBase):
46
46
  for veri in secici.css("div.single-item")
47
47
  ]
48
48
 
49
- @kekik_cache(ttl=60*60)
49
+ #@kekik_cache(ttl=60*60)
50
50
  async def search(self, query: str) -> list[SearchResult]:
51
51
  istek = await self.httpx.get(f"{self.main_url}/?s={query}")
52
52
  secici = Selector(istek.text)
@@ -60,7 +60,7 @@ class DiziYou(PluginBase):
60
60
  for afis in secici.css("div.incontent div#list-series")
61
61
  ]
62
62
 
63
- @kekik_cache(ttl=60*60)
63
+ #@kekik_cache(ttl=60*60)
64
64
  async def load_item(self, url: str) -> SeriesInfo:
65
65
  istek = await self.httpx.get(url)
66
66
  secici = Selector(istek.text)
@@ -107,8 +107,8 @@ class DiziYou(PluginBase):
107
107
  actors = actors
108
108
  )
109
109
 
110
- @kekik_cache(ttl=15*60)
111
- async def load_links(self, url: str) -> list[str]:
110
+ #@kekik_cache(ttl=15*60)
111
+ async def load_links(self, url: str) -> list[dict]:
112
112
  istek = await self.httpx.get(url)
113
113
  secici = Selector(istek.text)
114
114
 
@@ -130,7 +130,7 @@ class DiziYou(PluginBase):
130
130
  url = self.fix_url(f"{self.main_url.replace('www', 'storage')}/subtitles/{item_id}/tr.vtt"),
131
131
  ))
132
132
  veri = {
133
- "dil": "Orjinal Dil",
133
+ "dil": "Orjinal Dil (TR Altyazı)",
134
134
  "url": f"{self.main_url.replace('www', 'storage')}/episodes/{item_id}/play.m3u8"
135
135
  }
136
136
  if veri not in stream_urls:
@@ -141,28 +141,27 @@ class DiziYou(PluginBase):
141
141
  url = self.fix_url(f"{self.main_url.replace('www', 'storage')}/subtitles/{item_id}/en.vtt"),
142
142
  ))
143
143
  veri = {
144
- "dil": "Orjinal Dil",
144
+ "dil": "Orjinal Dil (EN Altyazı)",
145
145
  "url": f"{self.main_url.replace('www', 'storage')}/episodes/{item_id}/play.m3u8"
146
146
  }
147
147
  if veri not in stream_urls:
148
148
  stream_urls.append(veri)
149
149
  case "turkceDublaj":
150
150
  stream_urls.append({
151
- "dil": "Dublaj",
151
+ "dil": "Türkçe Dublaj",
152
152
  "url": f"{self.main_url.replace('www', 'storage')}/episodes/{item_id}_tr/play.m3u8"
153
153
  })
154
154
 
155
-
155
+ results = []
156
156
  for stream in stream_urls:
157
- self._data[stream.get("url")] = {
158
- "ext_name" : f"{self.name} | {stream.get('dil')}",
159
- "name" : f"{self.name} | {stream.get('dil')} | {item_title} - {ep_name}",
157
+ results.append({
158
+ "url" : stream.get("url"),
159
+ "name" : f"{stream.get('dil')}",
160
160
  "referer" : url,
161
- "headers" : self.media_handler.headers,
162
161
  "subtitles" : subtitles
163
- }
162
+ })
164
163
 
165
- return [stream.get("url") for stream in stream_urls]
164
+ return results
166
165
 
167
166
  async def play(self, name: str, url: str, referer: str, subtitles: list[Subtitle]):
168
167
  extract_result = ExtractResult(name=name, url=url, referer=referer, subtitles=subtitles)
@@ -4,11 +4,13 @@ from KekikStream.Core import kekik_cache, PluginBase, MainPageResult, SearchResu
4
4
  from parsel import Selector
5
5
  from json import loads
6
6
  from urllib.parse import urlparse, urlunparse
7
+ from Crypto.Cipher import AES
8
+ from base64 import b64decode
7
9
 
8
10
  class Dizilla(PluginBase):
9
11
  name = "Dizilla"
10
12
  language = "tr"
11
- main_url = "https://dizilla.nl"
13
+ main_url = "https://dizilla40.com"
12
14
  favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
13
15
  description = "Dizilla tüm yabancı dizileri ücretsiz olarak Türkçe Dublaj ve altyazılı seçenekleri ile 1080P kalite izleyebileceğiniz yeni nesil yabancı dizi izleme siteniz."
14
16
 
@@ -22,7 +24,7 @@ class Dizilla(PluginBase):
22
24
  f"{main_url}/dizi-turu/komedi" : "Komedi"
23
25
  }
24
26
 
25
- @kekik_cache(ttl=60*60)
27
+ #@kekik_cache(ttl=60*60)
26
28
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
27
29
  istek = await self.httpx.get(url)
28
30
  secici = Selector(istek.text)
@@ -65,32 +67,32 @@ class Dizilla(PluginBase):
65
67
 
66
68
  return ana_sayfa
67
69
 
68
- @kekik_cache(ttl=60*60)
70
+ async def decrypt_response(self, response: str) -> dict:
71
+ # 32 bytes key
72
+ key = "9bYMCNQiWsXIYFWYAu7EkdsSbmGBTyUI".encode("utf-8")
73
+
74
+ # IV = 16 bytes of zero
75
+ iv = bytes([0] * 16)
76
+
77
+ # Base64 decode
78
+ encrypted_bytes = b64decode(response)
79
+
80
+ # AES/CBC/PKCS5Padding
81
+ cipher = AES.new(key, AES.MODE_CBC, iv)
82
+ decrypted = cipher.decrypt(encrypted_bytes)
83
+
84
+ # PKCS5/PKCS7 padding remove
85
+ pad_len = decrypted[-1]
86
+ decrypted = decrypted[:-pad_len]
87
+
88
+ # JSON decode
89
+ return loads(decrypted.decode("utf-8"))
90
+
91
+ #@kekik_cache(ttl=60*60)
69
92
  async def search(self, query: str) -> list[SearchResult]:
70
- ilk_istek = await self.httpx.get(self.main_url)
71
- ilk_secici = Selector(ilk_istek.text)
72
- cKey = ilk_secici.css("input[name='cKey']::attr(value)").get()
73
- cValue = ilk_secici.css("input[name='cValue']::attr(value)").get()
74
-
75
- self.httpx.headers.update({
76
- "Accept" : "application/json, text/javascript, */*; q=0.01",
77
- "X-Requested-With" : "XMLHttpRequest",
78
- "Referer" : f"{self.main_url}/"
79
- })
80
- self.httpx.cookies.update({
81
- "showAllDaFull" : "true",
82
- "PHPSESSID" : ilk_istek.cookies.get("PHPSESSID"),
83
- })
84
-
85
- arama_istek = await self.httpx.post(
86
- url = f"{self.main_url}/bg/searchcontent",
87
- data = {
88
- "cKey" : cKey,
89
- "cValue" : cValue,
90
- "searchterm" : query
91
- }
92
- )
93
- arama_veri = arama_istek.json().get("data", {}).get("result", [])
93
+ arama_istek = await self.httpx.post(f"{self.main_url}/api/bg/searchcontent?searchterm={query}")
94
+ decrypted = await self.decrypt_response(arama_istek.json().get("response"))
95
+ arama_veri = decrypted.get("result", [])
94
96
 
95
97
  return [
96
98
  SearchResult(
@@ -101,7 +103,7 @@ class Dizilla(PluginBase):
101
103
  for veri in arama_veri
102
104
  ]
103
105
 
104
- @kekik_cache(ttl=60*60)
106
+ #@kekik_cache(ttl=60*60)
105
107
  async def url_base_degis(self, eski_url:str, yeni_base:str) -> str:
106
108
  parsed_url = urlparse(eski_url)
107
109
  parsed_yeni_base = urlparse(yeni_base)
@@ -112,7 +114,7 @@ class Dizilla(PluginBase):
112
114
 
113
115
  return urlunparse(yeni_url)
114
116
 
115
- @kekik_cache(ttl=60*60)
117
+ #@kekik_cache(ttl=60*60)
116
118
  async def load_item(self, url: str) -> SeriesInfo:
117
119
  istek = await self.httpx.get(url)
118
120
  secici = Selector(istek.text)
@@ -152,15 +154,27 @@ class Dizilla(PluginBase):
152
154
  actors = actors
153
155
  )
154
156
 
155
- @kekik_cache(ttl=15*60)
156
- async def load_links(self, url: str) -> list[str]:
157
- istek = await self.httpx.get(url)
158
- secici = Selector(istek.text)
159
-
160
- iframes = [self.fix_url(secici.css("div#playerLsDizilla iframe::attr(src)").get())]
161
- for alternatif in secici.css("a[href*='player']"):
162
- alt_istek = await self.httpx.get(self.fix_url(alternatif.css("::attr(href)").get()))
163
- alt_secici = Selector(alt_istek.text)
164
- iframes.append(self.fix_url(alt_secici.css("div#playerLsDizilla iframe::attr(src)").get()))
165
-
166
- return iframes
157
+ #@kekik_cache(ttl=15*60)
158
+ async def load_links(self, url: str) -> list[dict]:
159
+ istek = await self.httpx.get(url)
160
+ secici = Selector(istek.text)
161
+
162
+ next_data = loads(secici.css("script#__NEXT_DATA__::text").get())
163
+ secure_data = next_data.get("props", {}).get("pageProps", {}).get("secureData", {})
164
+ decrypted = await self.decrypt_response(secure_data)
165
+ results = decrypted.get("RelatedResults", {}).get("getEpisodeSources", {}).get("result", [])
166
+
167
+ links = []
168
+ for result in results:
169
+ iframe_src = Selector(result.get("source_content")).css("iframe::attr(src)").get()
170
+ iframe_url = self.fix_url(iframe_src)
171
+ if not iframe_url:
172
+ continue
173
+
174
+ extractor = self.ex_manager.find_extractor(iframe_url)
175
+ links.append({
176
+ "url" : iframe_url,
177
+ "name" : f"{extractor.name if extractor else 'Main Player'} | {result.get('language_name')}",
178
+ })
179
+
180
+ return links
@@ -6,7 +6,7 @@ from parsel import Selector
6
6
  class FilmMakinesi(PluginBase):
7
7
  name = "FilmMakinesi"
8
8
  language = "tr"
9
- main_url = "https://filmmakinesi.de"
9
+ main_url = "https://filmmakinesi.sh"
10
10
  favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
11
11
  description = "Film Makinesi, en yeni ve en güncel filmleri sitemizde full HD kalite farkı ile izleyebilirsiniz. HD film izle denildiğinde akla gelen en kaliteli film izleme sitesi."
12
12
 
@@ -34,7 +34,7 @@ class FilmMakinesi(PluginBase):
34
34
  f"{main_url}/film-izle/spor/page/" : "Spor"
35
35
  }
36
36
 
37
- @kekik_cache(ttl=60*60)
37
+ #@kekik_cache(ttl=60*60)
38
38
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
39
39
  istek = self.cloudscraper.get(f"{url}{page}")
40
40
  secici = Selector(istek.text)
@@ -51,15 +51,15 @@ class FilmMakinesi(PluginBase):
51
51
  for veri in veriler
52
52
  ]
53
53
 
54
- @kekik_cache(ttl=60*60)
54
+ #@kekik_cache(ttl=60*60)
55
55
  async def search(self, query: str) -> list[SearchResult]:
56
- istek = await self.httpx.get(f"{self.main_url}/?s={query}")
56
+ istek = await self.httpx.get(f"{self.main_url}/arama/?s={query}")
57
57
  secici = Selector(istek.text)
58
58
 
59
59
  results = []
60
- for article in secici.css("section#film_posts article"):
61
- title = article.css("h6 a::text").get()
62
- href = article.css("h6 a::attr(href)").get()
60
+ for article in secici.css("div.item-relative"):
61
+ title = article.css("div.title::text").get()
62
+ href = article.css("a::attr(href)").get()
63
63
  poster = article.css("img::attr(data-src)").get() or article.css("img::attr(src)").get()
64
64
 
65
65
  if title and href:
@@ -73,40 +73,47 @@ class FilmMakinesi(PluginBase):
73
73
 
74
74
  return results
75
75
 
76
- @kekik_cache(ttl=60*60)
76
+ #@kekik_cache(ttl=60*60)
77
77
  async def load_item(self, url: str) -> MovieInfo:
78
78
  istek = await self.httpx.get(url)
79
79
  secici = Selector(istek.text)
80
80
 
81
- title = secici.css("h1.single_h1 a::text").get().strip()
82
- poster = secici.css("[property='og:image']::attr(content)").get().strip()
83
- description = secici.css("section#film_single article p:last-of-type::text").get().strip()
84
- tags = secici.css("dt:contains('Tür:') + dd a::text").get().strip()
85
- rating = secici.css("dt:contains('IMDB Puanı:') + dd::text").get().strip()
86
- year = secici.css("dt:contains('Yapım Yılı:') + dd a::text").get().strip()
87
- actors = secici.css("dt:contains('Oyuncular:') + dd::text").get().strip()
88
- duration = secici.css("dt:contains('Film Süresi:') + dd time::attr(datetime)").get().strip()
89
-
90
- duration_minutes = 0
91
- if duration and duration.startswith("PT") and duration.endswith("M"):
92
- duration_minutes = int(duration[2:-1])
81
+ title = secici.css("h1.title::text").get().strip()
82
+ poster = secici.css("img.cover-img::attr(src)").get().strip()
83
+ description = secici.css("div.info-description p::text").get().strip()
84
+ rating = secici.css("div.score::text").get().strip()
85
+ year = secici.css("span.date a::text").get().strip()
86
+ actors = secici.css("div.cast-name::text").getall()
87
+ duration = secici.css("div.time::text").get().split()[1].strip()
93
88
 
94
89
  return MovieInfo(
95
90
  url = url,
96
91
  poster = self.fix_url(poster),
97
- title = title,
92
+ title = self.clean_title(title),
98
93
  description = description,
99
- tags = tags,
100
94
  rating = rating,
101
95
  year = year,
102
96
  actors = actors,
103
- duration = duration_minutes
97
+ duration = duration
104
98
  )
105
99
 
106
- @kekik_cache(ttl=15*60)
107
- async def load_links(self, url: str) -> list[str]:
100
+ #@kekik_cache(ttl=15*60)
101
+ async def load_links(self, url: str) -> list[dict]:
108
102
  istek = await self.httpx.get(url)
109
103
  secici = Selector(istek.text)
110
104
 
111
- iframe_src = secici.css("div.player-div iframe::attr(src)").get() or secici.css("div.player-div iframe::attr(data-src)").get()
112
- return [self.fix_url(iframe_src)] if iframe_src else []
105
+ iframe_src = secici.css("iframe::attr(data-src)").get()
106
+
107
+ all_links = [iframe_src] if iframe_src else []
108
+ for link in secici.css("div.video-parts a[data-video_url]"):
109
+ all_links.append(link.attrib.get("data-video_url"))
110
+
111
+ response = []
112
+ for idx, link in enumerate(all_links):
113
+ extractor = self.ex_manager.find_extractor(link)
114
+ response.append({
115
+ "url" : link,
116
+ "name" : f"{extractor.name if extractor else f'Player {idx + 1}'}",
117
+ })
118
+
119
+ return response