KekikStream 1.4.4__py3-none-any.whl → 2.0.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.
Files changed (81) hide show
  1. KekikStream/CLI/pypi_kontrol.py +6 -6
  2. KekikStream/Core/Extractor/ExtractorBase.py +13 -12
  3. KekikStream/Core/Extractor/ExtractorLoader.py +25 -17
  4. KekikStream/Core/Extractor/ExtractorManager.py +53 -9
  5. KekikStream/Core/Extractor/ExtractorModels.py +5 -7
  6. KekikStream/Core/Extractor/YTDLPCache.py +35 -0
  7. KekikStream/Core/Media/MediaHandler.py +52 -31
  8. KekikStream/Core/Media/MediaManager.py +0 -3
  9. KekikStream/Core/Plugin/PluginBase.py +47 -21
  10. KekikStream/Core/Plugin/PluginLoader.py +11 -7
  11. KekikStream/Core/Plugin/PluginModels.py +25 -25
  12. KekikStream/Core/__init__.py +1 -0
  13. KekikStream/Extractors/CloseLoad.py +6 -26
  14. KekikStream/Extractors/ContentX_.py +40 -0
  15. KekikStream/Extractors/DzenRu.py +38 -0
  16. KekikStream/Extractors/ExPlay.py +53 -0
  17. KekikStream/Extractors/FirePlayer.py +60 -0
  18. KekikStream/Extractors/HDPlayerSystem.py +41 -0
  19. KekikStream/Extractors/JetTv.py +45 -0
  20. KekikStream/Extractors/MailRu.py +2 -4
  21. KekikStream/Extractors/MixTiger.py +57 -0
  22. KekikStream/Extractors/MolyStream.py +25 -7
  23. KekikStream/Extractors/Odnoklassniki.py +16 -11
  24. KekikStream/Extractors/{OkRuHTTP.py → Odnoklassniki_.py} +5 -1
  25. KekikStream/Extractors/{HDStreamAble.py → PeaceMakerst_.py} +1 -1
  26. KekikStream/Extractors/PixelDrain.py +0 -1
  27. KekikStream/Extractors/PlayerFilmIzle.py +62 -0
  28. KekikStream/Extractors/RapidVid.py +30 -13
  29. KekikStream/Extractors/RapidVid_.py +7 -0
  30. KekikStream/Extractors/SetPlay.py +57 -0
  31. KekikStream/Extractors/SetPrime.py +45 -0
  32. KekikStream/Extractors/SibNet.py +0 -1
  33. KekikStream/Extractors/TurkeyPlayer.py +34 -0
  34. KekikStream/Extractors/VidHide.py +72 -0
  35. KekikStream/Extractors/VidMoly.py +20 -19
  36. KekikStream/Extractors/{VidMolyMe.py → VidMoly_.py} +1 -1
  37. KekikStream/Extractors/VidMoxy.py +0 -1
  38. KekikStream/Extractors/VidPapi.py +89 -0
  39. KekikStream/Extractors/YTDLP.py +177 -0
  40. KekikStream/Extractors/YildizKisaFilm.py +41 -0
  41. KekikStream/Plugins/DiziBox.py +28 -16
  42. KekikStream/Plugins/DiziPal.py +246 -0
  43. KekikStream/Plugins/DiziYou.py +58 -31
  44. KekikStream/Plugins/Dizilla.py +97 -68
  45. KekikStream/Plugins/FilmBip.py +145 -0
  46. KekikStream/Plugins/FilmMakinesi.py +61 -52
  47. KekikStream/Plugins/FilmModu.py +138 -0
  48. KekikStream/Plugins/FullHDFilm.py +164 -0
  49. KekikStream/Plugins/FullHDFilmizlesene.py +38 -37
  50. KekikStream/Plugins/HDFilmCehennemi.py +44 -54
  51. KekikStream/Plugins/JetFilmizle.py +68 -42
  52. KekikStream/Plugins/KultFilmler.py +219 -0
  53. KekikStream/Plugins/RecTV.py +41 -37
  54. KekikStream/Plugins/RoketDizi.py +232 -0
  55. KekikStream/Plugins/SelcukFlix.py +309 -0
  56. KekikStream/Plugins/SezonlukDizi.py +16 -14
  57. KekikStream/Plugins/SineWix.py +39 -30
  58. KekikStream/Plugins/Sinefy.py +238 -0
  59. KekikStream/Plugins/SinemaCX.py +157 -0
  60. KekikStream/Plugins/Sinezy.py +146 -0
  61. KekikStream/Plugins/SuperFilmGeldi.py +121 -0
  62. KekikStream/Plugins/UgurFilm.py +10 -10
  63. KekikStream/__init__.py +296 -319
  64. KekikStream/requirements.txt +3 -4
  65. kekikstream-2.0.2.dist-info/METADATA +309 -0
  66. kekikstream-2.0.2.dist-info/RECORD +82 -0
  67. {kekikstream-1.4.4.dist-info → kekikstream-2.0.2.dist-info}/WHEEL +1 -1
  68. KekikStream/Extractors/FourCX.py +0 -7
  69. KekikStream/Extractors/FourPichive.py +0 -7
  70. KekikStream/Extractors/FourPlayRu.py +0 -7
  71. KekikStream/Extractors/Hotlinger.py +0 -7
  72. KekikStream/Extractors/OkRuSSL.py +0 -7
  73. KekikStream/Extractors/Pichive.py +0 -7
  74. KekikStream/Extractors/PlayRu.py +0 -7
  75. KekikStream/Helpers/Unpack.py +0 -75
  76. KekikStream/Plugins/Shorten.py +0 -225
  77. kekikstream-1.4.4.dist-info/METADATA +0 -108
  78. kekikstream-1.4.4.dist-info/RECORD +0 -63
  79. {kekikstream-1.4.4.dist-info → kekikstream-2.0.2.dist-info}/entry_points.txt +0 -0
  80. {kekikstream-1.4.4.dist-info → kekikstream-2.0.2.dist-info/licenses}/LICENSE +0 -0
  81. {kekikstream-1.4.4.dist-info → kekikstream-2.0.2.dist-info}/top_level.txt +0 -0
@@ -1,34 +1,33 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
3
  from pydantic import BaseModel, field_validator, model_validator
4
- from typing import List, Optional
5
4
 
6
5
  class MainPageResult(BaseModel):
7
6
  """Ana sayfa sonucunda dönecek veri modeli."""
8
7
  category : str
9
8
  title : str
10
9
  url : str
11
- poster : Optional[str] = None
10
+ poster : str | None = None
12
11
 
13
12
 
14
13
  class SearchResult(BaseModel):
15
14
  """Arama sonucunda dönecek veri modeli."""
16
15
  title : str
17
16
  url : str
18
- poster : Optional[str] = None
17
+ poster : str | None = None
19
18
 
20
19
 
21
20
  class MovieInfo(BaseModel):
22
21
  """Bir medya öğesinin bilgilerini tutan model."""
23
22
  url : str
24
- poster : Optional[str] = None
25
- title : Optional[str] = None
26
- description : Optional[str] = None
27
- tags : Optional[str] = None
28
- rating : Optional[str] = None
29
- year : Optional[str] = None
30
- actors : Optional[str] = None
31
- duration : Optional[int] = None
23
+ poster : str | None = None
24
+ title : str | None = None
25
+ description : str | None = None
26
+ tags : str | None = None
27
+ rating : str | None = None
28
+ year : str | None = None
29
+ actors : str | None = None
30
+ duration : int | None = None
32
31
 
33
32
  @field_validator("tags", "actors", mode="before")
34
33
  @classmethod
@@ -42,10 +41,10 @@ class MovieInfo(BaseModel):
42
41
 
43
42
 
44
43
  class Episode(BaseModel):
45
- season : Optional[int] = None
46
- episode : Optional[int] = None
47
- title : Optional[str] = None
48
- url : Optional[str] = None
44
+ season : int | None = None
45
+ episode : int | None = None
46
+ title : str | None = None
47
+ url : str | None = None
49
48
 
50
49
  @model_validator(mode="after")
51
50
  def check_title(self) -> "Episode":
@@ -58,15 +57,16 @@ class Episode(BaseModel):
58
57
  return self
59
58
 
60
59
  class SeriesInfo(BaseModel):
61
- url : Optional[str] = None
62
- poster : Optional[str] = None
63
- title : Optional[str] = None
64
- description : Optional[str] = None
65
- tags : Optional[str] = None
66
- rating : Optional[str] = None
67
- year : Optional[str] = None
68
- actors : Optional[str] = None
69
- episodes : Optional[List[Episode]] = None
60
+ url : str | None = None
61
+ poster : str | None = None
62
+ title : str | None = None
63
+ description : str | None = None
64
+ tags : str | None = None
65
+ rating : str | None = None
66
+ year : str | None = None
67
+ actors : str | None = None
68
+ duration : int | None = None
69
+ episodes : list[Episode] | None = None
70
70
 
71
71
  @field_validator("tags", "actors", mode="before")
72
72
  @classmethod
@@ -76,4 +76,4 @@ class SeriesInfo(BaseModel):
76
76
  @field_validator("rating", "year", mode="before")
77
77
  @classmethod
78
78
  def ensure_string(cls, value):
79
- return str(value) if value is not None else value
79
+ return str(value) if value is not None else value
@@ -13,6 +13,7 @@ from .Extractor.ExtractorManager import ExtractorManager
13
13
  from .Extractor.ExtractorBase import ExtractorBase
14
14
  from .Extractor.ExtractorLoader import ExtractorLoader
15
15
  from .Extractor.ExtractorModels import ExtractResult, Subtitle
16
+ from .Extractor.YTDLPCache import get_ytdlp_extractors
16
17
 
17
18
  from .Media.MediaManager import MediaManager
18
19
  from .Media.MediaHandler import MediaHandler
@@ -1,31 +1,12 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from KekikStream.Core import ExtractorBase, ExtractResult
4
- from KekikStream.Helpers.Unpack import unpack
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")
3
+ from KekikStream.Core import ExtractorBase, ExtractResult
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.to"
29
10
 
30
11
  async def extract(self, url, referer=None) -> ExtractResult:
31
12
  if referer:
@@ -35,12 +16,11 @@ 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(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,
44
24
  referer = self.main_url,
45
25
  subtitles = []
46
- )
26
+ )
@@ -0,0 +1,40 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Extractors.ContentX import ContentX
4
+
5
+ # DPlayer82 Family - https://dplayer82.site subdomains
6
+ class SNDPlayer(ContentX):
7
+ name = "SNDPlayer"
8
+ main_url = "https://sn.dplayer82.site"
9
+
10
+ class FourDPlayer(ContentX):
11
+ name = "FourDPlayer"
12
+ main_url = "https://four.dplayer82.site"
13
+
14
+ class ORGDPlayer(ContentX):
15
+ name = "ORGDPlayer"
16
+ main_url = "https://org.dplayer82.site"
17
+
18
+ # Hotlinger
19
+ class Hotlinger(ContentX):
20
+ name = "Hotlinger"
21
+ main_url = "https://hotlinger.com"
22
+
23
+ # Pichive Family
24
+ class Pichive(ContentX):
25
+ name = "Pichive"
26
+ main_url = "https://pichive.me"
27
+
28
+ class FourPichive(ContentX):
29
+ name = "FourPichive"
30
+ main_url = "https://four.pichive.me"
31
+
32
+ # PlayRu Family
33
+ class FourPlayRu(ContentX):
34
+ name = "FourPlayRu"
35
+ main_url = "https://four.playru.net"
36
+
37
+ # CX Family
38
+ class FourCX(ContentX):
39
+ name = "FourCX"
40
+ main_url = "https://four.contentx.me"
@@ -0,0 +1,38 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult
4
+ import re
5
+
6
+ class DzenRu(ExtractorBase):
7
+ name = "DzenRu"
8
+ main_url = "https://dzen.ru"
9
+
10
+ async def extract(self, url, referer=None) -> ExtractResult:
11
+ video_key = url.split("/")[-1]
12
+ video_url = f"{self.main_url}/embed/{video_key}"
13
+
14
+ if referer:
15
+ self.httpx.headers.update({"Referer": referer})
16
+
17
+ istek = await self.httpx.get(video_url)
18
+ istek.raise_for_status()
19
+
20
+ # okcdn.ru linklerini bul
21
+ matches = re.findall(r'https://vd\d+\.okcdn\.ru/\?[^"\'\\\s]+', istek.text)
22
+
23
+ if not matches:
24
+ raise ValueError("DzenRu video link not found")
25
+
26
+ # Benzersiz linkleri al, son kaliteyi kullan
27
+ unique_links = list(set(matches))
28
+ best_link = unique_links[-1] if unique_links else None
29
+
30
+ if not best_link:
31
+ raise ValueError("No valid video URL found")
32
+
33
+ return ExtractResult(
34
+ name = self.name,
35
+ url = best_link,
36
+ referer = self.main_url,
37
+ subtitles = []
38
+ )
@@ -0,0 +1,53 @@
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
+ from urllib.parse import urlparse, parse_qs
6
+
7
+ class ExPlay(ExtractorBase):
8
+ name = "ExPlay"
9
+ main_url = "https://explay.store"
10
+
11
+ async def extract(self, url, referer=None) -> ExtractResult:
12
+ ext_ref = referer or ""
13
+
14
+ # URL parsing for partKey
15
+ parsed = urlparse(url)
16
+ params = parse_qs(parsed.query)
17
+ part_key = params.get("partKey", [""])[0]
18
+ clean_url = url.split("?partKey=")[0]
19
+
20
+ if referer:
21
+ self.httpx.headers.update({"Referer": referer})
22
+
23
+ istek = await self.httpx.get(clean_url)
24
+ istek.raise_for_status()
25
+
26
+ # videoUrl çıkar
27
+ video_url_match = re.search(r'videoUrl":"([^",]+)"', istek.text)
28
+ if not video_url_match:
29
+ raise ValueError("videoUrl not found")
30
+ video_url = video_url_match[1].replace("\\", "")
31
+
32
+ # videoServer çıkar
33
+ video_server_match = re.search(r'videoServer":"([^",]+)"', istek.text)
34
+ if not video_server_match:
35
+ raise ValueError("videoServer not found")
36
+ video_server = video_server_match[1]
37
+
38
+ # title çıkar
39
+ title_match = re.search(r'title":"([^",]+)"', istek.text)
40
+ title = title_match[1].split(".")[-1] if title_match else "Unknown"
41
+
42
+ if part_key and "turkce" in part_key.lower():
43
+ title = part_key # Or nicer formatting like SetPlay
44
+
45
+ # M3U8 link oluştur
46
+ m3u_link = f"{self.main_url}{video_url}?s={video_server}"
47
+
48
+ return ExtractResult(
49
+ name = f"{self.name} - {title}",
50
+ url = m3u_link,
51
+ referer = clean_url,
52
+ subtitles = []
53
+ )
@@ -0,0 +1,60 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult
4
+ from Kekik.Sifreleme import Packer
5
+ import re
6
+
7
+ class FirePlayer(ExtractorBase):
8
+ name = "FirePlayer"
9
+ main_url = "https://Player.filmizle.in"
10
+
11
+ def can_handle_url(self, url: str) -> bool:
12
+ return "filmizle.in" in url or "fireplayer" in url.lower()
13
+
14
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
15
+ if not referer:
16
+ referer = "https://sinezy.site/"
17
+
18
+ headers = {
19
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
20
+ "Referer": referer
21
+ }
22
+
23
+ istek = await self.httpx.get(url, headers=headers)
24
+
25
+ # Unpack usage similar to VidMoxy / suggestion
26
+ # Find the packed code block
27
+ match = re.search(r'(eval\(function\(p,a,c,k,e,d\)[\s\S]+?)\s*</script>', istek.text)
28
+ if match:
29
+ packed_code = match.group(1)
30
+ unpacked = Packer.unpack(packed_code)
31
+ else:
32
+ unpacked = istek.text
33
+
34
+ # Normalize escaped slashes
35
+ unpacked = unpacked.replace(r"\/", "/")
36
+
37
+ video_url = None
38
+
39
+ # Look for .mp4 or .m3u8 urls directly first
40
+ url_match = re.search(r'(https?://[^"\'\s]+\.(?:mp4|m3u8))', unpacked)
41
+ if url_match:
42
+ video_url = url_match.group(1)
43
+
44
+ if not video_url:
45
+ # Fallback: find all 'file': '...' and pick best
46
+ files = re.findall(r'file\s*:\s*["\']([^"\']+)["\']', unpacked)
47
+ for f in files:
48
+ if f.strip() and not f.endswith(".jpg") and not f.endswith(".png") and not f.endswith(".vtt"):
49
+ video_url = f
50
+ break
51
+
52
+ if not video_url:
53
+ raise ValueError("Could not find video URL in unpacked content")
54
+
55
+ return ExtractResult(
56
+ name = self.name,
57
+ url = video_url,
58
+ referer = url,
59
+ user_agent = headers.get("User-Agent", "")
60
+ )
@@ -0,0 +1,41 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult
4
+
5
+ class HDPlayerSystem(ExtractorBase):
6
+ name = "HDPlayerSystem"
7
+ main_url = "https://hdplayersystem.com"
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.httpx.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 = url,
40
+ subtitles = []
41
+ )
@@ -0,0 +1,45 @@
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, json
5
+
6
+ class JetTv(ExtractorBase):
7
+ name = "JetTv"
8
+ main_url = "https://jetv.xyz"
9
+
10
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
11
+ istek = await self.httpx.get(url)
12
+ document = istek.text
13
+
14
+ # 1. Yöntem: API üzerinden alma
15
+ master_url = ""
16
+ final_ref = f"{self.main_url}/"
17
+
18
+ if "id=" in url:
19
+ vid_id = url.split("id=")[-1]
20
+ api_url = f"https://jetv.xyz/apollo/get_video.php?id={vid_id}"
21
+ try:
22
+ # Referer olarak video sayfasının kendisi gönderilmeli
23
+ api_resp = await self.httpx.get(api_url, headers={"Referer": url})
24
+ api_json = api_resp.json()
25
+
26
+ if api_json.get("success"):
27
+ master_url = api_json.get("masterUrl", "")
28
+ final_ref = api_json.get("referrerUrl") or final_ref
29
+ except Exception:
30
+ pass
31
+
32
+ # 2. Yöntem: Regex Fallback
33
+ if not master_url:
34
+ if match := re.search(r"file: '([^']*)'", document, re.IGNORECASE):
35
+ master_url = match.group(1)
36
+
37
+ if not master_url:
38
+ raise ValueError(f"JetTv: Video kaynağı bulunamadı. {url}")
39
+
40
+ return ExtractResult(
41
+ name = self.name,
42
+ url = master_url,
43
+ referer = final_ref,
44
+ subtitles = []
45
+ )
@@ -30,11 +30,9 @@ 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,
37
36
  referer = self.main_url,
38
- subtitles = [],
39
- headers = {"Cookie": f"video_key={video_key}"}
40
- )
37
+ subtitles = []
38
+ )
@@ -0,0 +1,57 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult
4
+
5
+ class MixTiger(ExtractorBase):
6
+ name = "MixTiger"
7
+ main_url = "https://www.mixtiger.com"
8
+
9
+ async def extract(self, url, referer=None) -> ExtractResult:
10
+ ext_ref = referer or ""
11
+ post_url = f"{url}?do=getVideo"
12
+ vid_id = url.split("video/")[-1] if "video/" in url else ""
13
+
14
+ response = await self.httpx.post(
15
+ url = post_url,
16
+ data = {"hash": vid_id, "r": ext_ref, "s": ""},
17
+ headers = {
18
+ "Referer" : ext_ref,
19
+ "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
20
+ "X-Requested-With" : "XMLHttpRequest"
21
+ }
22
+ )
23
+ response.raise_for_status()
24
+
25
+ video_data = response.json()
26
+
27
+ # videoSrc varsa doğrudan kullan
28
+ if video_data.get("videoSrc"):
29
+ m3u_link = video_data["videoSrc"]
30
+ # videoSources listesi varsa son elemanı al
31
+ elif video_data.get("videoSources"):
32
+ sources = video_data["videoSources"]
33
+ m3u_link = sources[-1].get("file") if sources else None
34
+ else:
35
+ m3u_link = None
36
+
37
+ if not m3u_link:
38
+ raise ValueError("Video URL not found in response")
39
+
40
+ # Recursive extraction check
41
+ try:
42
+ from KekikStream.Core.Extractor.ExtractorManager import ExtractorManager
43
+ # Import inside method to avoid circular dependency
44
+ manager = ExtractorManager()
45
+ if nested_extractor := manager.find_extractor(m3u_link):
46
+ # Use recursive extraction
47
+ return await nested_extractor.extract(m3u_link, referer=final_referer)
48
+ except Exception:
49
+ # If recursion fails, fallback to standard result
50
+ pass
51
+
52
+ return ExtractResult(
53
+ name = self.name,
54
+ url = m3u_link,
55
+ referer = None if "disk.yandex" in m3u_link else ext_ref,
56
+ subtitles = []
57
+ )
@@ -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
- name = self.name,
12
- url = url,
13
- referer = url.replace("/sheila", ""),
14
- headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0"},
15
- subtitles = []
16
- )
29
+ name = self.name,
30
+ url = video,
31
+ referer = video.replace("/sheila", ""),
32
+ user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0",
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.httpx.headers.update(headers)
24
+
21
25
  try:
22
26
  istek = await self.fetch_with_redirects(url)
23
27
  istek.raise_for_status()
@@ -78,10 +82,11 @@ class Odnoklassniki(ExtractorBase):
78
82
  best_video = f"https:{best_video}"
79
83
 
80
84
  return ExtractResult(
81
- name = self.name,
82
- url = best_video,
83
- referer = self.main_url,
84
- subtitles = []
85
+ name = self.name,
86
+ url = best_video,
87
+ referer = referer,
88
+ user_agent = headers.get("User-Agent", None),
89
+ subtitles = []
85
90
  )
86
91
 
87
92
  async def fetch_with_redirects(self, url, max_redirects=5):
@@ -4,4 +4,8 @@ from KekikStream.Extractors.Odnoklassniki import Odnoklassniki
4
4
 
5
5
  class OkRuHTTP(Odnoklassniki):
6
6
  name = "OkRuHTTP"
7
- main_url = "http://ok.ru"
7
+ main_url = "http://ok.ru"
8
+
9
+ class OkRuSSL(Odnoklassniki):
10
+ name = "OkRuSSL"
11
+ main_url = "https://ok.ru"
@@ -4,4 +4,4 @@ from KekikStream.Extractors.PeaceMakerst import PeaceMakerst
4
4
 
5
5
  class HDStreamAble(PeaceMakerst):
6
6
  name = "HDStreamAble"
7
- main_url = "https://hdstreamable.com"
7
+ main_url = "https://hdstreamable.com"
@@ -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,