KekikStream 1.5.2__py3-none-any.whl → 1.6.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.
Files changed (42) hide show
  1. KekikStream/CLI/pypi_kontrol.py +6 -6
  2. KekikStream/Core/Extractor/ExtractorBase.py +6 -11
  3. KekikStream/Core/Media/MediaHandler.py +9 -6
  4. KekikStream/Core/Plugin/PluginBase.py +35 -21
  5. KekikStream/Extractors/CloseLoad.py +6 -26
  6. KekikStream/Extractors/ContentX.py +4 -4
  7. KekikStream/Extractors/MailRu.py +2 -3
  8. KekikStream/Extractors/MixPlayHD.py +2 -2
  9. KekikStream/Extractors/MolyStream.py +23 -5
  10. KekikStream/Extractors/Odnoklassniki.py +14 -10
  11. KekikStream/Extractors/PeaceMakerst.py +4 -4
  12. KekikStream/Extractors/PixelDrain.py +1 -2
  13. KekikStream/Extractors/RapidVid.py +32 -15
  14. KekikStream/Extractors/SibNet.py +2 -3
  15. KekikStream/Extractors/Sobreatsesuyp.py +4 -4
  16. KekikStream/Extractors/TRsTX.py +4 -4
  17. KekikStream/Extractors/TauVideo.py +2 -2
  18. KekikStream/Extractors/TurboImgz.py +2 -2
  19. KekikStream/Extractors/VidMoly.py +22 -21
  20. KekikStream/Extractors/VidMoxy.py +2 -3
  21. KekikStream/Extractors/VideoSeyred.py +3 -3
  22. KekikStream/Plugins/DiziBox.py +46 -29
  23. KekikStream/Plugins/DiziYou.py +22 -23
  24. KekikStream/Plugins/Dizilla.py +62 -48
  25. KekikStream/Plugins/FilmMakinesi.py +65 -54
  26. KekikStream/Plugins/FullHDFilmizlesene.py +44 -39
  27. KekikStream/Plugins/HDFilmCehennemi.py +51 -61
  28. KekikStream/Plugins/JetFilmizle.py +21 -13
  29. KekikStream/Plugins/RecTV.py +40 -36
  30. KekikStream/Plugins/SezonlukDizi.py +23 -20
  31. KekikStream/Plugins/SineWix.py +42 -33
  32. KekikStream/Plugins/UgurFilm.py +19 -15
  33. KekikStream/__init__.py +285 -318
  34. KekikStream/requirements.txt +1 -1
  35. {kekikstream-1.5.2.dist-info → kekikstream-1.6.7.dist-info}/METADATA +5 -4
  36. kekikstream-1.6.7.dist-info/RECORD +61 -0
  37. {kekikstream-1.5.2.dist-info → kekikstream-1.6.7.dist-info}/WHEEL +1 -1
  38. KekikStream/Plugins/Shorten.py +0 -226
  39. kekikstream-1.5.2.dist-info/RECORD +0 -62
  40. {kekikstream-1.5.2.dist-info → kekikstream-1.6.7.dist-info}/entry_points.txt +0 -0
  41. {kekikstream-1.5.2.dist-info → kekikstream-1.6.7.dist-info/licenses}/LICENSE +0 -0
  42. {kekikstream-1.5.2.dist-info → kekikstream-1.6.7.dist-info}/top_level.txt +0 -0
@@ -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")
@@ -1,7 +1,7 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
3
  from abc import ABC, abstractmethod
4
- from httpx import AsyncClient, Timeout
4
+ from curl_cffi import AsyncSession
5
5
  from cloudscraper import CloudScraper
6
6
  from typing import Optional
7
7
  from .ExtractorModels import ExtractResult
@@ -14,15 +14,10 @@ class ExtractorBase(ABC):
14
14
 
15
15
  def __init__(self):
16
16
  # HTTP istekleri için oturum oluştur
17
- self.httpx = AsyncClient(
18
- headers = {
19
- "User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5)",
20
- "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
21
- },
22
- timeout = Timeout(10.0)
23
- )
24
- # CloudFlare korumalı siteler için scraper ayarla
25
- self.cloudscraper = CloudScraper()
17
+ self.cffi = AsyncSession(impersonate="firefox135")
18
+ self.cloudscraper = CloudScraper()
19
+ self.cffi.cookies.update(self.cloudscraper.cookies)
20
+ self.cffi.headers.update({"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 15.7; rv:135.0) Gecko/20100101 Firefox/135.0"})
26
21
 
27
22
  def can_handle_url(self, url: str) -> bool:
28
23
  # URL'nin bu çıkarıcı tarafından işlenip işlenemeyeceğini kontrol et
@@ -35,7 +30,7 @@ class ExtractorBase(ABC):
35
30
 
36
31
  async def close(self):
37
32
  # HTTP oturumunu güvenli bir şekilde kapat
38
- await self.httpx.aclose()
33
+ await self.cffi.close()
39
34
 
40
35
  def fix_url(self, url: str) -> str:
41
36
  # Eksik URL'leri düzelt ve tam URL formatına çevir
@@ -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 curl_cffi import AsyncSession
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):
@@ -17,25 +18,18 @@ class PluginBase(ABC):
17
18
 
18
19
  main_page = {}
19
20
 
20
- _data = {}
21
-
22
21
  async def url_update(self, new_url: str):
23
22
  self.favicon = self.favicon.replace(self.main_url, new_url)
24
23
  self.main_page = {url.replace(self.main_url, new_url): category for url, category in self.main_page.items()}
25
24
  self.main_url = new_url
26
25
 
27
26
  def __init__(self):
28
- self.httpx = AsyncClient(
29
- headers = {
30
- "User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5)",
31
- "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
32
- },
33
- timeout = Timeout(10.0),
34
- )
27
+ self.cffi = AsyncSession(impersonate="firefox135")
28
+ self.cloudscraper = CloudScraper()
29
+ self.cffi.cookies.update(self.cloudscraper.cookies)
30
+ self.cffi.headers.update({"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 15.7; rv:135.0) Gecko/20100101 Firefox/135.0"})
35
31
  self.media_handler = MediaHandler()
36
- self.cloudscraper = CloudScraper()
37
- self.httpx.headers.update(self.cloudscraper.headers)
38
- self.httpx.cookies.update(self.cloudscraper.cookies)
32
+ self.ex_manager = ExtractorManager()
39
33
 
40
34
  # @abstractmethod
41
35
  # async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
@@ -53,12 +47,32 @@ class PluginBase(ABC):
53
47
  pass
54
48
 
55
49
  @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."""
50
+ async def load_links(self, url: str) -> list[dict]:
51
+ """
52
+ Bir medya öğesi için oynatma bağlantılarını döndürür.
53
+
54
+ Args:
55
+ url: Medya URL'si
56
+
57
+ Returns:
58
+ Dictionary listesi, her biri şu alanları içerir:
59
+ - url (str, zorunlu): Video URL'si
60
+ - name (str, zorunlu): Gösterim adı (tüm bilgileri içerir)
61
+ - referer (str, opsiyonel): Referer header
62
+ - subtitles (list, opsiyonel): Altyazı listesi
63
+
64
+ Example:
65
+ [
66
+ {
67
+ "url": "https://example.com/video.m3u8",
68
+ "name": "HDFilmCehennemi | 1080p TR Dublaj"
69
+ }
70
+ ]
71
+ """
58
72
  pass
59
73
 
60
74
  async def close(self):
61
- await self.httpx.aclose()
75
+ await self.cffi.close()
62
76
 
63
77
  def fix_url(self, url: str) -> str:
64
78
  if not url:
@@ -1,43 +1,23 @@
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:
32
- self.httpx.headers.update({"Referer": referer})
13
+ self.cffi.headers.update({"Referer": referer})
33
14
 
34
- istek = await self.httpx.get(url)
15
+ istek = await self.cffi.get(url)
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
- await self.close()
41
21
  return ExtractResult(
42
22
  name = self.name,
43
23
  url = m3u_link,
@@ -9,9 +9,9 @@ class ContentX(ExtractorBase):
9
9
 
10
10
  async def extract(self, url, referer=None) -> list[ExtractResult]:
11
11
  if referer:
12
- self.httpx.headers.update({"Referer": referer})
12
+ self.cffi.headers.update({"Referer": referer})
13
13
 
14
- istek = await self.httpx.get(url)
14
+ istek = await self.cffi.get(url)
15
15
  istek.raise_for_status()
16
16
  i_source = istek.text
17
17
 
@@ -39,7 +39,7 @@ class ContentX(ExtractorBase):
39
39
  )
40
40
  )
41
41
 
42
- vid_source_request = await self.httpx.get(f"{self.main_url}/source2.php?v={i_extract_value}", headers={"Referer": referer or self.main_url})
42
+ vid_source_request = await self.cffi.get(f"{self.main_url}/source2.php?v={i_extract_value}", headers={"Referer": referer or self.main_url})
43
43
  vid_source_request.raise_for_status()
44
44
 
45
45
  vid_source = vid_source_request.text
@@ -60,7 +60,7 @@ class ContentX(ExtractorBase):
60
60
 
61
61
  if i_dublaj := re.search(r',\"([^"]+)\",\"Türkçe"', i_source):
62
62
  dublaj_value = i_dublaj[1]
63
- dublaj_source_request = await self.httpx.get(f"{self.main_url}/source2.php?v={dublaj_value}", headers={"Referer": referer or self.main_url})
63
+ dublaj_source_request = await self.cffi.get(f"{self.main_url}/source2.php?v={dublaj_value}", headers={"Referer": referer or self.main_url})
64
64
  dublaj_source_request.raise_for_status()
65
65
 
66
66
  dublaj_source = dublaj_source_request.text
@@ -11,9 +11,9 @@ class MailRuExtractor(ExtractorBase):
11
11
  video_meta_url = f"{self.main_url}/+/video/meta/{vid_id}"
12
12
 
13
13
  if referer:
14
- self.httpx.headers.update({"Referer": referer})
14
+ self.cffi.headers.update({"Referer": referer})
15
15
 
16
- istek = await self.httpx.get(video_meta_url)
16
+ istek = await self.cffi.get(video_meta_url)
17
17
  istek.raise_for_status()
18
18
 
19
19
  video_key = istek.cookies.get("video_key")
@@ -30,7 +30,6 @@ class MailRuExtractor(ExtractorBase):
30
30
  if video_url.startswith("//"):
31
31
  video_url = f"https:{video_url}"
32
32
 
33
- await self.close()
34
33
  return ExtractResult(
35
34
  name = self.name,
36
35
  url = video_url,
@@ -10,9 +10,9 @@ class MixPlayHD(ExtractorBase):
10
10
 
11
11
  async def extract(self, url, referer=None) -> ExtractResult:
12
12
  if referer:
13
- self.httpx.headers.update({"Referer": referer})
13
+ self.cffi.headers.update({"Referer": referer})
14
14
 
15
- istek = await self.httpx.get(url)
15
+ istek = await self.cffi.get(url)
16
16
  istek.raise_for_status()
17
17
 
18
18
  be_player_match = re.search(r"bePlayer\('([^']+)',\s*'(\{[^\}]+\})'\);", istek.text)
@@ -1,16 +1,34 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from KekikStream.Core import ExtractorBase, ExtractResult
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
4
+ from parsel import Selector
5
+ import re
4
6
 
5
7
  class MolyStream(ExtractorBase):
6
8
  name = "MolyStream"
7
9
  main_url = "https://dbx.molystream.org"
8
10
 
9
11
  async def extract(self, url, referer=None) -> ExtractResult:
12
+ if "doctype html" in url:
13
+ secici = Selector(url)
14
+ video = secici.css("video#sheplayer source::attr(src)").get()
15
+ else:
16
+ video = url
17
+
18
+ matches = re.findall(
19
+ pattern = r"addSrtFile\(['\"]([^'\"]+\.srt)['\"]\s*,\s*['\"][a-z]{2}['\"]\s*,\s*['\"]([^'\"]+)['\"]",
20
+ string = url
21
+ )
22
+
23
+ subtitles = [
24
+ Subtitle(name = name, url = self.fix_url(url))
25
+ for url, name in matches
26
+ ]
27
+
10
28
  return ExtractResult(
11
29
  name = self.name,
12
- url = url,
13
- referer = url.replace("/sheila", ""),
30
+ url = video,
31
+ referer = video.replace("/sheila", ""),
14
32
  headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0"},
15
- subtitles = []
16
- )
33
+ subtitles = subtitles
34
+ )
@@ -8,16 +8,20 @@ class Odnoklassniki(ExtractorBase):
8
8
  main_url = "https://odnoklassniki.ru"
9
9
 
10
10
  async def extract(self, url, referer=None) -> ExtractResult:
11
- if referer:
12
- self.httpx.headers.update({"Referer": referer})
13
-
14
- self.httpx.headers.update({
15
- "User-Agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36"
16
- })
17
-
18
11
  if "/video/" in url:
19
12
  url = url.replace("/video/", "/videoembed/")
20
13
 
14
+ headers = {
15
+ "Accept" : "*/*",
16
+ "Connection" : "keep-alive",
17
+ "Sec-Fetch-Dest" : "empty",
18
+ "Sec-Fetch-Mode" : "cors",
19
+ "Sec-Fetch-Site" : "cross-site",
20
+ "Origin" : self.main_url,
21
+ "User-Agent" : "Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0",
22
+ }
23
+ self.cffi.headers.update(headers)
24
+
21
25
  try:
22
26
  istek = await self.fetch_with_redirects(url)
23
27
  istek.raise_for_status()
@@ -80,8 +84,8 @@ class Odnoklassniki(ExtractorBase):
80
84
  return ExtractResult(
81
85
  name = self.name,
82
86
  url = best_video,
83
- referer = self.main_url,
84
- headers = {},
87
+ referer = referer,
88
+ headers = headers,
85
89
  subtitles = []
86
90
  )
87
91
 
@@ -89,7 +93,7 @@ class Odnoklassniki(ExtractorBase):
89
93
  """Yönlendirmeleri takip eden bir fonksiyon"""
90
94
  redirects = 0
91
95
  while redirects < max_redirects:
92
- istek = await self.httpx.get(url, follow_redirects=False)
96
+ istek = await self.cffi.get(url, allow_redirects=False)
93
97
 
94
98
  if istek.status_code not in [301, 302]:
95
99
  break # Yönlendirme yoksa çık
@@ -9,14 +9,14 @@ class PeaceMakerst(ExtractorBase):
9
9
 
10
10
  async def extract(self, url, referer=None) -> ExtractResult:
11
11
  if referer:
12
- self.httpx.headers.update({"Referer": referer})
12
+ self.cffi.headers.update({"Referer": referer})
13
13
 
14
- self.httpx.headers.update({
14
+ self.cffi.headers.update({
15
15
  "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
16
16
  "X-Requested-With" : "XMLHttpRequest"
17
17
  })
18
18
 
19
- response = await self.httpx.post(
19
+ response = await self.cffi.post(
20
20
  url = f"{url}?do=getVideo",
21
21
  data = {
22
22
  "hash" : url.split("video/")[-1],
@@ -33,7 +33,7 @@ class PeaceMakerst(ExtractorBase):
33
33
  teve2_id = re.search(r"teve2\.com\.tr\\\/embed\\\/(\d+)", response_text)[1]
34
34
  teve2_url = f"https://www.teve2.com.tr/action/media/{teve2_id}"
35
35
 
36
- teve2_response = await self.httpx.get(teve2_url, headers={"Referer": f"https://www.teve2.com.tr/embed/{teve2_id}"})
36
+ teve2_response = await self.cffi.get(teve2_url, headers={"Referer": f"https://www.teve2.com.tr/embed/{teve2_id}"})
37
37
  teve2_response.raise_for_status()
38
38
  teve2_json = teve2_response.json()
39
39
 
@@ -9,7 +9,7 @@ class PixelDrain(ExtractorBase):
9
9
 
10
10
  async def extract(self, url, referer=None) -> ExtractResult:
11
11
  if referer:
12
- self.httpx.headers.update({"Referer": referer})
12
+ self.cffi.headers.update({"Referer": referer})
13
13
 
14
14
  pixel_id_match = re.search(r"/u/([^/?]+)|([^\/]+)(?=\?download)", url)
15
15
  if not pixel_id_match:
@@ -19,7 +19,6 @@ class PixelDrain(ExtractorBase):
19
19
  download_link = f"{self.main_url}/api/file/{pixel_id}?download"
20
20
  referer_link = f"{self.main_url}/u/{pixel_id}?download"
21
21
 
22
- await self.close()
23
22
  return ExtractResult(
24
23
  name = f"{self.name} - {pixel_id}",
25
24
  url = download_link,
@@ -2,7 +2,7 @@
2
2
 
3
3
  from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
4
4
  from Kekik.Sifreleme import Packer, HexCodec
5
- import re
5
+ import re, base64
6
6
 
7
7
  class RapidVid(ExtractorBase):
8
8
  name = "RapidVid"
@@ -10,9 +10,9 @@ class RapidVid(ExtractorBase):
10
10
 
11
11
  async def extract(self, url, referer=None) -> ExtractResult:
12
12
  if referer:
13
- self.httpx.headers.update({"Referer": referer})
13
+ self.cffi.headers.update({"Referer": referer})
14
14
 
15
- istek = await self.httpx.get(url)
15
+ istek = await self.cffi.get(url)
16
16
  istek.raise_for_status()
17
17
 
18
18
  subtitles = []
@@ -37,25 +37,42 @@ class RapidVid(ExtractorBase):
37
37
  escaped_hex = extracted_value[1]
38
38
  decoded_url = HexCodec.decode(escaped_hex)
39
39
  else:
40
- eval_jwsetup = re.search(r'\};\s*(eval\(function[\s\S]*?)var played = \d+;', istek.text)
41
- if not eval_jwsetup:
42
- raise ValueError("JWPlayer setup not found.")
40
+ av_encoded = re.search(r"av\('([^']+)'\)", istek.text)
41
+ if not av_encoded:
42
+ raise ValueError("AV encoding not found.")
43
43
 
44
- unpacked_jwsetup = Packer.unpack(Packer.unpack(eval_jwsetup[1]))
45
- extracted_value = re.search(r'file":"(.*)","label', unpacked_jwsetup)
46
- if not extracted_value:
47
- raise ValueError("File URL not found in unpacked JWPlayer setup.")
48
-
49
- escaped_hex = extracted_value[1].replace("\\\\x", "")
50
- decoded_url = bytes.fromhex(escaped_hex).decode("utf-8")
44
+ decoded_url = self.decode_secret(av_encoded[1])
51
45
  except Exception as hata:
52
46
  raise RuntimeError(f"Extraction failed: {hata}") from hata
53
47
 
54
- await self.close()
55
48
  return ExtractResult(
56
49
  name = self.name,
57
50
  url = decoded_url,
58
51
  referer = self.main_url,
59
52
  headers = {},
60
53
  subtitles = subtitles
61
- )
54
+ )
55
+
56
+ def decode_secret(self, encoded_string: str) -> str:
57
+ # 1. Base64 ile şifrelenmiş string ters çevrilmiş, önce geri çeviriyoruz
58
+ reversed_input = encoded_string[::-1]
59
+
60
+ # 2. İlk base64 çözme işlemi
61
+ decoded_once = base64.b64decode(reversed_input).decode("utf-8")
62
+
63
+ decrypted_chars = []
64
+ key = "K9L"
65
+
66
+ # 3. Key'e göre karakter kaydırma geri alınıyor
67
+ for index, encoded_char in enumerate(decoded_once):
68
+ key_char = key[index % len(key)]
69
+ offset = (ord(key_char) % 5) + 1 # Her karakter için dinamik offset
70
+
71
+ original_char_code = ord(encoded_char) - offset
72
+ decrypted_chars.append(chr(original_char_code))
73
+
74
+ # 4. Karakterleri birleştirip ikinci base64 çözme işlemini yapıyoruz
75
+ intermediate_string = "".join(decrypted_chars)
76
+ final_decoded_bytes = base64.b64decode(intermediate_string)
77
+
78
+ return final_decoded_bytes.decode("utf-8")
@@ -9,9 +9,9 @@ class SibNet(ExtractorBase):
9
9
 
10
10
  async def extract(self, url, referer=None) -> ExtractResult:
11
11
  if referer:
12
- self.httpx.headers.update({"Referer": referer})
12
+ self.cffi.headers.update({"Referer": referer})
13
13
 
14
- response = await self.httpx.get(url)
14
+ response = await self.cffi.get(url)
15
15
  response.raise_for_status()
16
16
 
17
17
  match = re.search(r'player\.src\(\[\{src: \"([^\"]+)\"', response.text)
@@ -20,7 +20,6 @@ class SibNet(ExtractorBase):
20
20
 
21
21
  m3u_link = f"{self.main_url}{match[1]}"
22
22
 
23
- await self.close()
24
23
  return ExtractResult(
25
24
  name = self.name,
26
25
  url = m3u_link,
@@ -9,9 +9,9 @@ class Sobreatsesuyp(ExtractorBase):
9
9
 
10
10
  async def extract(self, url, referer=None) -> ExtractResult:
11
11
  if referer:
12
- self.httpx.headers.update({"Referer": referer})
12
+ self.cffi.headers.update({"Referer": referer})
13
13
 
14
- istek = await self.httpx.get(url)
14
+ istek = await self.cffi.get(url)
15
15
  istek.raise_for_status()
16
16
 
17
17
  file_match = re.search(r'file\":\"([^\"]+)', istek.text)
@@ -21,7 +21,7 @@ class Sobreatsesuyp(ExtractorBase):
21
21
  file_path = file_match[1].replace("\\", "")
22
22
  post_link = f"{self.main_url}/{file_path}"
23
23
 
24
- post_istek = await self.httpx.post(post_link)
24
+ post_istek = await self.cffi.post(post_link)
25
25
  post_istek.raise_for_status()
26
26
 
27
27
  try:
@@ -41,7 +41,7 @@ class Sobreatsesuyp(ExtractorBase):
41
41
  continue
42
42
 
43
43
  playlist_url = f"{self.main_url}/playlist/{file.lstrip('/')}.txt"
44
- playlist_request = await self.httpx.post(playlist_url, headers={"Referer": referer or self.main_url})
44
+ playlist_request = await self.cffi.post(playlist_url, headers={"Referer": referer or self.main_url})
45
45
  playlist_request.raise_for_status()
46
46
 
47
47
  all_results.append(
@@ -9,9 +9,9 @@ class TRsTX(ExtractorBase):
9
9
 
10
10
  async def extract(self, url, referer=None) -> list[ExtractResult]:
11
11
  if referer:
12
- self.httpx.headers.update({"Referer": referer})
12
+ self.cffi.headers.update({"Referer": referer})
13
13
 
14
- istek = await self.httpx.get(url)
14
+ istek = await self.cffi.get(url)
15
15
  istek.raise_for_status()
16
16
 
17
17
  file_match = re.search(r'file\":\"([^\"]+)', istek.text)
@@ -21,7 +21,7 @@ class TRsTX(ExtractorBase):
21
21
  file_path = file_match[1].replace("\\", "")
22
22
  post_link = f"{self.main_url}/{file_path}"
23
23
 
24
- post_istek = await self.httpx.post(post_link)
24
+ post_istek = await self.cffi.post(post_link)
25
25
  post_istek.raise_for_status()
26
26
 
27
27
  try:
@@ -42,7 +42,7 @@ class TRsTX(ExtractorBase):
42
42
  continue
43
43
 
44
44
  playlist_url = f"{self.main_url}/playlist/{file.lstrip('/')}.txt"
45
- playlist_request = await self.httpx.post(playlist_url, headers={"Referer": referer or self.main_url})
45
+ playlist_request = await self.cffi.post(playlist_url, headers={"Referer": referer or self.main_url})
46
46
  playlist_request.raise_for_status()
47
47
 
48
48
  video_data = playlist_request.text
@@ -8,12 +8,12 @@ class TauVideo(ExtractorBase):
8
8
 
9
9
  async def extract(self, url, referer=None) -> list[ExtractResult]:
10
10
  if referer:
11
- self.httpx.headers.update({"Referer": referer})
11
+ self.cffi.headers.update({"Referer": referer})
12
12
 
13
13
  video_key = url.split("/")[-1]
14
14
  api_url = f"{self.main_url}/api/video/{video_key}"
15
15
 
16
- response = await self.httpx.get(api_url)
16
+ response = await self.cffi.get(api_url)
17
17
  response.raise_for_status()
18
18
 
19
19
  api_data = response.json()
@@ -9,9 +9,9 @@ class TurboImgz(ExtractorBase):
9
9
 
10
10
  async def extract(self, url, referer=None) -> ExtractResult:
11
11
  if referer:
12
- self.httpx.headers.update({"Referer": referer})
12
+ self.cffi.headers.update({"Referer": referer})
13
13
 
14
- istek = await self.httpx.get(url)
14
+ istek = await self.cffi.get(url)
15
15
  istek.raise_for_status()
16
16
 
17
17
  if video_match := re.search(r'file: "(.*)",', istek.text):