KekikStream 1.7.1__py3-none-any.whl → 2.2.0__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 (88) hide show
  1. KekikStream/Core/Extractor/ExtractorBase.py +20 -9
  2. KekikStream/Core/Extractor/ExtractorLoader.py +25 -17
  3. KekikStream/Core/Extractor/ExtractorManager.py +53 -9
  4. KekikStream/Core/Extractor/ExtractorModels.py +5 -7
  5. KekikStream/Core/Extractor/YTDLPCache.py +35 -0
  6. KekikStream/Core/Media/MediaHandler.py +44 -26
  7. KekikStream/Core/Media/MediaManager.py +0 -3
  8. KekikStream/Core/Plugin/PluginBase.py +82 -22
  9. KekikStream/Core/Plugin/PluginLoader.py +11 -7
  10. KekikStream/Core/Plugin/PluginModels.py +25 -26
  11. KekikStream/Core/__init__.py +1 -0
  12. KekikStream/Extractors/CloseLoad.py +21 -7
  13. KekikStream/Extractors/ContentX.py +21 -6
  14. KekikStream/Extractors/DonilasPlay.py +86 -0
  15. KekikStream/Extractors/DzenRu.py +38 -0
  16. KekikStream/Extractors/ExPlay.py +53 -0
  17. KekikStream/Extractors/Filemoon.py +78 -0
  18. KekikStream/Extractors/HDPlayerSystem.py +41 -0
  19. KekikStream/Extractors/JetTv.py +45 -0
  20. KekikStream/Extractors/MailRu.py +3 -4
  21. KekikStream/Extractors/MixPlayHD.py +2 -3
  22. KekikStream/Extractors/MixTiger.py +57 -0
  23. KekikStream/Extractors/MolyStream.py +5 -5
  24. KekikStream/Extractors/Odnoklassniki.py +13 -7
  25. KekikStream/Extractors/PeaceMakerst.py +10 -5
  26. KekikStream/Extractors/PixelDrain.py +1 -2
  27. KekikStream/Extractors/PlayerFilmIzle.py +65 -0
  28. KekikStream/Extractors/RapidVid.py +23 -8
  29. KekikStream/Extractors/SetPlay.py +66 -0
  30. KekikStream/Extractors/SetPrime.py +45 -0
  31. KekikStream/Extractors/SibNet.py +2 -3
  32. KekikStream/Extractors/Sobreatsesuyp.py +4 -5
  33. KekikStream/Extractors/TRsTX.py +4 -5
  34. KekikStream/Extractors/TauVideo.py +2 -3
  35. KekikStream/Extractors/TurboImgz.py +2 -3
  36. KekikStream/Extractors/TurkeyPlayer.py +34 -0
  37. KekikStream/Extractors/VCTPlay.py +41 -0
  38. KekikStream/Extractors/VidHide.py +81 -0
  39. KekikStream/Extractors/VidMoly.py +55 -34
  40. KekikStream/Extractors/VidMoxy.py +2 -3
  41. KekikStream/Extractors/VidPapi.py +89 -0
  42. KekikStream/Extractors/VideoSeyred.py +3 -4
  43. KekikStream/Extractors/YTDLP.py +211 -0
  44. KekikStream/Extractors/YildizKisaFilm.py +41 -0
  45. KekikStream/Plugins/BelgeselX.py +196 -0
  46. KekikStream/Plugins/DiziBox.py +25 -34
  47. KekikStream/Plugins/DiziPal.py +24 -35
  48. KekikStream/Plugins/DiziYou.py +54 -37
  49. KekikStream/Plugins/Dizilla.py +66 -46
  50. KekikStream/Plugins/FilmBip.py +142 -0
  51. KekikStream/Plugins/FilmMakinesi.py +36 -28
  52. KekikStream/Plugins/FilmModu.py +20 -24
  53. KekikStream/Plugins/FullHDFilm.py +220 -0
  54. KekikStream/Plugins/FullHDFilmizlesene.py +9 -15
  55. KekikStream/Plugins/HDFilmCehennemi.py +141 -69
  56. KekikStream/Plugins/JetFilmizle.py +85 -52
  57. KekikStream/Plugins/KultFilmler.py +217 -0
  58. KekikStream/Plugins/RecTV.py +22 -34
  59. KekikStream/Plugins/RoketDizi.py +222 -0
  60. KekikStream/Plugins/SelcukFlix.py +328 -0
  61. KekikStream/Plugins/SetFilmIzle.py +252 -0
  62. KekikStream/Plugins/SezonlukDizi.py +54 -21
  63. KekikStream/Plugins/SineWix.py +17 -29
  64. KekikStream/Plugins/Sinefy.py +241 -0
  65. KekikStream/Plugins/SinemaCX.py +154 -0
  66. KekikStream/Plugins/Sinezy.py +143 -0
  67. KekikStream/Plugins/SuperFilmGeldi.py +130 -0
  68. KekikStream/Plugins/UgurFilm.py +13 -19
  69. KekikStream/__init__.py +47 -56
  70. KekikStream/requirements.txt +3 -4
  71. kekikstream-2.2.0.dist-info/METADATA +312 -0
  72. kekikstream-2.2.0.dist-info/RECORD +81 -0
  73. KekikStream/Extractors/FourCX.py +0 -7
  74. KekikStream/Extractors/FourPichive.py +0 -7
  75. KekikStream/Extractors/FourPlayRu.py +0 -7
  76. KekikStream/Extractors/HDStreamAble.py +0 -7
  77. KekikStream/Extractors/Hotlinger.py +0 -7
  78. KekikStream/Extractors/OkRuHTTP.py +0 -7
  79. KekikStream/Extractors/OkRuSSL.py +0 -7
  80. KekikStream/Extractors/Pichive.py +0 -7
  81. KekikStream/Extractors/PlayRu.py +0 -7
  82. KekikStream/Extractors/VidMolyMe.py +0 -7
  83. kekikstream-1.7.1.dist-info/METADATA +0 -109
  84. kekikstream-1.7.1.dist-info/RECORD +0 -63
  85. {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.dist-info}/WHEEL +0 -0
  86. {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.dist-info}/entry_points.txt +0 -0
  87. {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.dist-info}/licenses/LICENSE +0 -0
  88. {kekikstream-1.7.1.dist-info → kekikstream-2.2.0.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,16 +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
- duration : Optional[int] = None
70
- 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
71
70
 
72
71
  @field_validator("tags", "actors", mode="before")
73
72
  @classmethod
@@ -77,4 +76,4 @@ class SeriesInfo(BaseModel):
77
76
  @field_validator("rating", "year", mode="before")
78
77
  @classmethod
79
78
  def ensure_string(cls, value):
80
- 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,27 +1,41 @@
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
4
  from Kekik.Sifreleme import Packer, StreamDecoder
5
+ from parsel import Selector
5
6
  import re
6
7
 
7
8
  class CloseLoadExtractor(ExtractorBase):
8
9
  name = "CloseLoad"
9
- main_url = "https://closeload.filmmakinesi.sh"
10
+ main_url = "https://closeload.filmmakinesi.to"
10
11
 
11
12
  async def extract(self, url, referer=None) -> ExtractResult:
12
13
  if referer:
13
- self.cffi.headers.update({"Referer": referer})
14
+ self.httpx.headers.update({"Referer": referer})
14
15
 
15
- istek = await self.cffi.get(url)
16
+ istek = await self.httpx.get(url)
16
17
  istek.raise_for_status()
17
18
 
19
+ # Video URL'sini çıkar
18
20
  eval_func = re.compile(r'\s*(eval\(function[\s\S].*)\s*').findall(istek.text)[0]
19
21
  m3u_link = StreamDecoder.extract_stream_url(Packer.unpack(eval_func))
20
22
 
23
+ # Subtitle'ları parse et (Kotlin referansı: track elementleri)
24
+ subtitles = []
25
+ secici = Selector(istek.text)
26
+ for track in secici.css("track"):
27
+ raw_src = track.css("::attr(src)").get() or ""
28
+ raw_src = raw_src.strip()
29
+ label = track.css("::attr(label)").get() or track.css("::attr(srclang)").get() or "Altyazı"
30
+
31
+ if raw_src:
32
+ full_url = raw_src if raw_src.startswith("http") else f"{self.main_url}{raw_src}"
33
+ subtitles.append(Subtitle(name=label, url=full_url))
34
+
21
35
  return ExtractResult(
22
36
  name = self.name,
23
37
  url = m3u_link,
24
38
  referer = self.main_url,
25
- headers = {},
26
- subtitles = []
27
- )
39
+ subtitles = subtitles
40
+ )
41
+
@@ -7,11 +7,27 @@ class ContentX(ExtractorBase):
7
7
  name = "ContentX"
8
8
  main_url = "https://contentx.me"
9
9
 
10
+ # Birden fazla domain destekle
11
+ supported_domains = [
12
+ "contentx.me", "four.contentx.me",
13
+ "dplayer82.site", "sn.dplayer82.site", "four.dplayer82.site", "org.dplayer82.site",
14
+ "dplayer74.site", "sn.dplayer74.site",
15
+ "hotlinger.com", "sn.hotlinger.com",
16
+ "playru.net", "four.playru.net",
17
+ "pichive.online", "four.pichive.online", "pichive.me", "four.pichive.me"
18
+ ]
19
+
20
+ def can_handle_url(self, url: str) -> bool:
21
+ return any(domain in url for domain in self.supported_domains)
22
+
10
23
  async def extract(self, url, referer=None) -> list[ExtractResult]:
11
24
  if referer:
12
- self.cffi.headers.update({"Referer": referer})
25
+ self.httpx.headers.update({"Referer": referer})
26
+
27
+ # Dinamik base URL kullan
28
+ base_url = self.get_base_url(url)
13
29
 
14
- istek = await self.cffi.get(url)
30
+ istek = await self.httpx.get(url)
15
31
  istek.raise_for_status()
16
32
  i_source = istek.text
17
33
 
@@ -39,7 +55,8 @@ class ContentX(ExtractorBase):
39
55
  )
40
56
  )
41
57
 
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})
58
+ # base_url kullan (contentx.me yerine)
59
+ vid_source_request = await self.httpx.get(f"{base_url}/source2.php?v={i_extract_value}", headers={"Referer": referer or base_url})
43
60
  vid_source_request.raise_for_status()
44
61
 
45
62
  vid_source = vid_source_request.text
@@ -53,14 +70,13 @@ class ContentX(ExtractorBase):
53
70
  name = self.name,
54
71
  url = m3u_link,
55
72
  referer = url,
56
- headers = {},
57
73
  subtitles = subtitles
58
74
  )
59
75
  ]
60
76
 
61
77
  if i_dublaj := re.search(r',\"([^"]+)\",\"Türkçe"', i_source):
62
78
  dublaj_value = i_dublaj[1]
63
- dublaj_source_request = await self.cffi.get(f"{self.main_url}/source2.php?v={dublaj_value}", headers={"Referer": referer or self.main_url})
79
+ dublaj_source_request = await self.httpx.get(f"{base_url}/source2.php?v={dublaj_value}", headers={"Referer": referer or base_url})
64
80
  dublaj_source_request.raise_for_status()
65
81
 
66
82
  dublaj_source = dublaj_source_request.text
@@ -74,7 +90,6 @@ class ContentX(ExtractorBase):
74
90
  name = f"{self.name} Türkçe Dublaj",
75
91
  url = dublaj_link,
76
92
  referer = url,
77
- headers = {},
78
93
  subtitles = []
79
94
  )
80
95
  )
@@ -0,0 +1,86 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
4
+ from Kekik.Sifreleme import AESManager
5
+ import re, json
6
+
7
+ class DonilasPlay(ExtractorBase):
8
+ name = "DonilasPlay"
9
+ main_url = "https://donilasplay.com"
10
+
11
+ async def extract(self, url, referer=None) -> ExtractResult:
12
+ if referer:
13
+ self.httpx.headers.update({"Referer": referer})
14
+
15
+ istek = await self.httpx.get(url)
16
+ istek.raise_for_status()
17
+ i_source = istek.text
18
+
19
+ m3u_link = None
20
+ subtitles = []
21
+
22
+ # bePlayer pattern
23
+ be_player_match = re.search(r"bePlayer\('([^']+)',\s*'(\{[^}]+\})'\);", i_source)
24
+ if be_player_match:
25
+ be_player_pass = be_player_match.group(1)
26
+ be_player_data = be_player_match.group(2)
27
+
28
+ try:
29
+ # AES decrypt
30
+ decrypted = AESManager.decrypt(be_player_data, be_player_pass)
31
+ data = json.loads(decrypted)
32
+
33
+ m3u_link = data.get("video_location")
34
+
35
+ # Altyazıları işle
36
+ str_subtitles = data.get("strSubtitles", [])
37
+ if str_subtitles:
38
+ for sub in str_subtitles:
39
+ label = sub.get("label", "")
40
+ file = sub.get("file", "")
41
+ # Forced altyazıları hariç tut
42
+ if "Forced" in label:
43
+ continue
44
+ if file:
45
+ # Türkçe kontrolü
46
+ keywords = ["tur", "tr", "türkçe", "turkce"]
47
+ language = "Turkish" if any(k in label.lower() for k in keywords) else label
48
+ subtitles.append(Subtitle(
49
+ name = language,
50
+ url = self.fix_url(file)
51
+ ))
52
+ except Exception:
53
+ pass
54
+
55
+ # Fallback: file pattern
56
+ if not m3u_link:
57
+ file_match = re.search(r'file:"([^"]+)"', i_source)
58
+ if file_match:
59
+ m3u_link = file_match.group(1)
60
+
61
+ # tracks pattern for subtitles
62
+ tracks_match = re.search(r'tracks:\[([^\]]+)', i_source)
63
+ if tracks_match:
64
+ try:
65
+ tracks_str = f"[{tracks_match.group(1)}]"
66
+ tracks = json.loads(tracks_str)
67
+ for track in tracks:
68
+ file_url = track.get("file")
69
+ label = track.get("label", "")
70
+ if file_url and "Forced" not in label:
71
+ subtitles.append(Subtitle(
72
+ name = label,
73
+ url = self.fix_url(file_url)
74
+ ))
75
+ except Exception:
76
+ pass
77
+
78
+ if not m3u_link:
79
+ raise ValueError("m3u link not found")
80
+
81
+ return ExtractResult(
82
+ name = self.name,
83
+ url = m3u_link,
84
+ referer = url,
85
+ subtitles = subtitles
86
+ )
@@ -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,78 @@
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
+ from parsel import Selector
6
+ import re
7
+
8
+ class Filemoon(ExtractorBase):
9
+ name = "Filemoon"
10
+ main_url = "https://filemoon.to"
11
+
12
+ # Filemoon'un farklı domainlerini destekle
13
+ supported_domains = [
14
+ "filemoon.to",
15
+ "filemoon.in",
16
+ "filemoon.sx",
17
+ "filemoon.nl",
18
+ "filemoon.com"
19
+ ]
20
+
21
+ def can_handle_url(self, url: str) -> bool:
22
+ return any(domain in url for domain in self.supported_domains)
23
+
24
+ async def extract(self, url: str, referer: str = None) -> ExtractResult:
25
+ headers = {
26
+ "Referer" : url,
27
+ "Sec-Fetch-Dest" : "iframe",
28
+ "Sec-Fetch-Mode" : "navigate",
29
+ "Sec-Fetch-Site" : "cross-site",
30
+ }
31
+ self.httpx.headers.update(headers)
32
+
33
+ # İlk sayfayı al
34
+ istek = await self.httpx.get(url)
35
+ response = istek.text
36
+ secici = Selector(response)
37
+
38
+ # Eğer iframe varsa, iframe'e git
39
+ iframe_src = secici.css("iframe::attr(src)").get()
40
+ if iframe_src:
41
+ iframe_url = self.fix_url(iframe_src)
42
+ self.httpx.headers.update({
43
+ "Accept-Language" : "en-US,en;q=0.5",
44
+ "Sec-Fetch-Dest" : "iframe"
45
+ })
46
+ istek = await self.httpx.get(iframe_url)
47
+ response = istek.text
48
+
49
+ # Packed script'i bul ve unpack et
50
+ m3u8_url = None
51
+
52
+ if Packer.detect_packed(response):
53
+ try:
54
+ unpacked = Packer.unpack(response)
55
+ # sources:[{file:"..." pattern'ını ara
56
+ if match := re.search(r'sources:\s*\[\s*\{\s*file:\s*"([^"]+)"', unpacked):
57
+ m3u8_url = match.group(1)
58
+ elif match := re.search(r'file:\s*"([^"]*?\.m3u8[^"]*)"', unpacked):
59
+ m3u8_url = match.group(1)
60
+ except Exception:
61
+ pass
62
+
63
+ # Fallback: Doğrudan response'ta ara
64
+ if not m3u8_url:
65
+ if match := re.search(r'sources:\s*\[\s*\{\s*file:\s*"([^"]+)"', response):
66
+ m3u8_url = match.group(1)
67
+ elif match := re.search(r'file:\s*"([^"]*?\.m3u8[^"]*)"', response):
68
+ m3u8_url = match.group(1)
69
+
70
+ if not m3u8_url:
71
+ raise ValueError(f"Filemoon: Video URL bulunamadı. {url}")
72
+
73
+ return ExtractResult(
74
+ name = self.name,
75
+ url = self.fix_url(m3u8_url),
76
+ referer = f"{self.main_url}/",
77
+ subtitles = []
78
+ )
@@ -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
+ )
@@ -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.cffi.headers.update({"Referer": referer})
14
+ self.httpx.headers.update({"Referer": referer})
15
15
 
16
- istek = await self.cffi.get(video_meta_url)
16
+ istek = await self.httpx.get(video_meta_url)
17
17
  istek.raise_for_status()
18
18
 
19
19
  video_key = istek.cookies.get("video_key")
@@ -34,6 +34,5 @@ class MailRuExtractor(ExtractorBase):
34
34
  name = self.name,
35
35
  url = video_url,
36
36
  referer = self.main_url,
37
- headers = {"Cookie": f"video_key={video_key}"},
38
37
  subtitles = []
39
- )
38
+ )
@@ -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.cffi.headers.update({"Referer": referer})
13
+ self.httpx.headers.update({"Referer": referer})
14
14
 
15
- istek = await self.cffi.get(url)
15
+ istek = await self.httpx.get(url)
16
16
  istek.raise_for_status()
17
17
 
18
18
  be_player_match = re.search(r"bePlayer\('([^']+)',\s*'(\{[^\}]+\})'\);", istek.text)
@@ -36,7 +36,6 @@ class MixPlayHD(ExtractorBase):
36
36
  name = self.name,
37
37
  url = video_url_match[1],
38
38
  referer = self.main_url,
39
- headers = {},
40
39
  subtitles = []
41
40
  )
42
41
  else:
@@ -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 - başka extractor kullanılabilir mi?
41
+ try:
42
+ from KekikStream.Core.Extractor.ExtractorManager import ExtractorManager
43
+ manager = ExtractorManager()
44
+ if nested_extractor := manager.find_extractor(m3u_link):
45
+ # Nested extractor ile çıkar
46
+ return await nested_extractor.extract(m3u_link, referer=ext_ref)
47
+ except Exception:
48
+ # Recursive extraction başarısız olursa standart sonucu döndür
49
+ pass
50
+
51
+ return ExtractResult(
52
+ name = self.name,
53
+ url = m3u_link,
54
+ referer = None if "disk.yandex" in m3u_link else ext_ref,
55
+ subtitles = []
56
+ )
57
+
@@ -26,9 +26,9 @@ class MolyStream(ExtractorBase):
26
26
  ]
27
27
 
28
28
  return ExtractResult(
29
- name = self.name,
30
- url = video,
31
- referer = video.replace("/sheila", ""),
32
- headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0"},
33
- subtitles = subtitles
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
34
  )