KekikStream 2.5.7__py3-none-any.whl → 2.5.9__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.

Potentially problematic release.


This version of KekikStream might be problematic. Click here for more details.

Files changed (109) hide show
  1. KekikStream/CLI/__pycache__/pypi_kontrol.cpython-314.pyc +0 -0
  2. KekikStream/Core/Extractor/__pycache__/ExtractorBase.cpython-314.pyc +0 -0
  3. KekikStream/Core/Extractor/__pycache__/ExtractorLoader.cpython-314.pyc +0 -0
  4. KekikStream/Core/Extractor/__pycache__/ExtractorManager.cpython-314.pyc +0 -0
  5. KekikStream/Core/Extractor/__pycache__/ExtractorModels.cpython-314.pyc +0 -0
  6. KekikStream/Core/Extractor/__pycache__/YTDLPCache.cpython-314.pyc +0 -0
  7. KekikStream/Core/Media/__pycache__/MediaHandler.cpython-314.pyc +0 -0
  8. KekikStream/Core/Media/__pycache__/MediaManager.cpython-314.pyc +0 -0
  9. KekikStream/Core/Plugin/__pycache__/PluginBase.cpython-314.pyc +0 -0
  10. KekikStream/Core/Plugin/__pycache__/PluginLoader.cpython-314.pyc +0 -0
  11. KekikStream/Core/Plugin/__pycache__/PluginManager.cpython-314.pyc +0 -0
  12. KekikStream/Core/Plugin/__pycache__/PluginModels.cpython-314.pyc +0 -0
  13. KekikStream/Core/UI/__pycache__/UIManager.cpython-314.pyc +0 -0
  14. KekikStream/Core/__pycache__/HTMLHelper.cpython-314.pyc +0 -0
  15. KekikStream/Core/__pycache__/__init__.cpython-314.pyc +0 -0
  16. KekikStream/Extractors/HotStream.py +7 -2
  17. KekikStream/Extractors/StreamWish.py +80 -0
  18. KekikStream/Extractors/VidHide.py +46 -44
  19. KekikStream/Extractors/VidStack.py +88 -0
  20. KekikStream/Extractors/__pycache__/Abstream.cpython-314.pyc +0 -0
  21. KekikStream/Extractors/__pycache__/CloseLoad.cpython-314.pyc +0 -0
  22. KekikStream/Extractors/__pycache__/ContentX.cpython-314.pyc +0 -0
  23. KekikStream/Extractors/__pycache__/DonilasPlay.cpython-314.pyc +0 -0
  24. KekikStream/Extractors/__pycache__/DzenRu.cpython-314.pyc +0 -0
  25. KekikStream/Extractors/__pycache__/ExPlay.cpython-314.pyc +0 -0
  26. KekikStream/Extractors/__pycache__/Filemoon.cpython-314.pyc +0 -0
  27. KekikStream/Extractors/__pycache__/HDMomPlayer.cpython-314.pyc +0 -0
  28. KekikStream/Extractors/__pycache__/HDPlayerSystem.cpython-314.pyc +0 -0
  29. KekikStream/Extractors/__pycache__/HotStream.cpython-314.pyc +0 -0
  30. KekikStream/Extractors/__pycache__/JFVid.cpython-314.pyc +0 -0
  31. KekikStream/Extractors/__pycache__/JetTv.cpython-314.pyc +0 -0
  32. KekikStream/Extractors/__pycache__/JetV.cpython-314.pyc +0 -0
  33. KekikStream/Extractors/__pycache__/LuciferPlays.cpython-314.pyc +0 -0
  34. KekikStream/Extractors/__pycache__/MailRu.cpython-314.pyc +0 -0
  35. KekikStream/Extractors/__pycache__/MixPlayHD.cpython-314.pyc +0 -0
  36. KekikStream/Extractors/__pycache__/MixTiger.cpython-314.pyc +0 -0
  37. KekikStream/Extractors/__pycache__/MolyStream.cpython-314.pyc +0 -0
  38. KekikStream/Extractors/__pycache__/Odnoklassniki.cpython-314.pyc +0 -0
  39. KekikStream/Extractors/__pycache__/PeaceMakerst.cpython-314.pyc +0 -0
  40. KekikStream/Extractors/__pycache__/PixelDrain.cpython-314.pyc +0 -0
  41. KekikStream/Extractors/__pycache__/PlayerFilmIzle.cpython-314.pyc +0 -0
  42. KekikStream/Extractors/__pycache__/RapidVid.cpython-314.pyc +0 -0
  43. KekikStream/Extractors/__pycache__/SetPlay.cpython-314.pyc +0 -0
  44. KekikStream/Extractors/__pycache__/SetPrime.cpython-314.pyc +0 -0
  45. KekikStream/Extractors/__pycache__/SibNet.cpython-314.pyc +0 -0
  46. KekikStream/Extractors/__pycache__/Sobreatsesuyp.cpython-314.pyc +0 -0
  47. KekikStream/Extractors/__pycache__/StreamWish.cpython-314.pyc +0 -0
  48. KekikStream/Extractors/__pycache__/TRsTX.cpython-314.pyc +0 -0
  49. KekikStream/Extractors/__pycache__/TauVideo.cpython-314.pyc +0 -0
  50. KekikStream/Extractors/__pycache__/TurboImgz.cpython-314.pyc +0 -0
  51. KekikStream/Extractors/__pycache__/TurkeyPlayer.cpython-314.pyc +0 -0
  52. KekikStream/Extractors/__pycache__/VCTPlay.cpython-314.pyc +0 -0
  53. KekikStream/Extractors/__pycache__/Veev.cpython-314.pyc +0 -0
  54. KekikStream/Extractors/__pycache__/VidBiz.cpython-314.pyc +0 -0
  55. KekikStream/Extractors/__pycache__/VidHide.cpython-314.pyc +0 -0
  56. KekikStream/Extractors/__pycache__/VidMoly.cpython-314.pyc +0 -0
  57. KekikStream/Extractors/__pycache__/VidMoxy.cpython-314.pyc +0 -0
  58. KekikStream/Extractors/__pycache__/VidPapi.cpython-314.pyc +0 -0
  59. KekikStream/Extractors/__pycache__/VidStack.cpython-314.pyc +0 -0
  60. KekikStream/Extractors/__pycache__/VideoSeyred.cpython-314.pyc +0 -0
  61. KekikStream/Extractors/__pycache__/Videostr.cpython-314.pyc +0 -0
  62. KekikStream/Extractors/__pycache__/Vidoza.cpython-314.pyc +0 -0
  63. KekikStream/Extractors/__pycache__/Vtbe.cpython-314.pyc +0 -0
  64. KekikStream/Extractors/__pycache__/YTDLP.cpython-314.pyc +0 -0
  65. KekikStream/Extractors/__pycache__/YildizKisaFilm.cpython-314.pyc +0 -0
  66. KekikStream/Extractors/__pycache__/Zeus.cpython-314.pyc +0 -0
  67. KekikStream/Plugins/DDizi.py +176 -0
  68. KekikStream/Plugins/RealFilmIzle.py +94 -0
  69. KekikStream/Plugins/ShowFlix.py +211 -0
  70. KekikStream/Plugins/__pycache__/BelgeselX.cpython-314.pyc +0 -0
  71. KekikStream/Plugins/__pycache__/DDizi.cpython-314.pyc +0 -0
  72. KekikStream/Plugins/__pycache__/DiziBox.cpython-314.pyc +0 -0
  73. KekikStream/Plugins/__pycache__/DiziMom.cpython-314.pyc +0 -0
  74. KekikStream/Plugins/__pycache__/DiziPal.cpython-314.pyc +0 -0
  75. KekikStream/Plugins/__pycache__/DiziYou.cpython-314.pyc +0 -0
  76. KekikStream/Plugins/__pycache__/Dizilla.cpython-314.pyc +0 -0
  77. KekikStream/Plugins/__pycache__/FilmBip.cpython-314.pyc +0 -0
  78. KekikStream/Plugins/__pycache__/FilmEkseni.cpython-314.pyc +0 -0
  79. KekikStream/Plugins/__pycache__/FilmMakinesi.cpython-314.pyc +0 -0
  80. KekikStream/Plugins/__pycache__/FilmModu.cpython-314.pyc +0 -0
  81. KekikStream/Plugins/__pycache__/Filmatek.cpython-314.pyc +0 -0
  82. KekikStream/Plugins/__pycache__/FilmciBaba.cpython-314.pyc +0 -0
  83. KekikStream/Plugins/__pycache__/FullHDFilmizlesene.cpython-314.pyc +0 -0
  84. KekikStream/Plugins/__pycache__/HDFilm.cpython-314.pyc +0 -0
  85. KekikStream/Plugins/__pycache__/HDFilmCehennemi.cpython-314.pyc +0 -0
  86. KekikStream/Plugins/__pycache__/JetFilmizle.cpython-314.pyc +0 -0
  87. KekikStream/Plugins/__pycache__/KultFilmler.cpython-314.pyc +0 -0
  88. KekikStream/Plugins/__pycache__/RealFilmIzle.cpython-314.pyc +0 -0
  89. KekikStream/Plugins/__pycache__/RecTV.cpython-314.pyc +0 -0
  90. KekikStream/Plugins/__pycache__/RoketDizi.cpython-314.pyc +0 -0
  91. KekikStream/Plugins/__pycache__/SelcukFlix.cpython-314.pyc +0 -0
  92. KekikStream/Plugins/__pycache__/SetFilmIzle.cpython-314.pyc +0 -0
  93. KekikStream/Plugins/__pycache__/SezonlukDizi.cpython-314.pyc +0 -0
  94. KekikStream/Plugins/__pycache__/ShowFlix.cpython-314.pyc +0 -0
  95. KekikStream/Plugins/__pycache__/SineWix.cpython-314.pyc +0 -0
  96. KekikStream/Plugins/__pycache__/Sinefy.cpython-314.pyc +0 -0
  97. KekikStream/Plugins/__pycache__/SinemaCX.cpython-314.pyc +0 -0
  98. KekikStream/Plugins/__pycache__/Sinezy.cpython-314.pyc +0 -0
  99. KekikStream/Plugins/__pycache__/SuperFilmIzle.cpython-314.pyc +0 -0
  100. KekikStream/Plugins/__pycache__/UgurFilm.cpython-314.pyc +0 -0
  101. KekikStream/Plugins/__pycache__/Watch32.cpython-314.pyc +0 -0
  102. KekikStream/Plugins/__pycache__/YabanciDizi.cpython-314.pyc +0 -0
  103. {kekikstream-2.5.7.dist-info → kekikstream-2.5.9.dist-info}/METADATA +1 -1
  104. kekikstream-2.5.9.dist-info/RECORD +200 -0
  105. kekikstream-2.5.7.dist-info/RECORD +0 -100
  106. {kekikstream-2.5.7.dist-info → kekikstream-2.5.9.dist-info}/WHEEL +0 -0
  107. {kekikstream-2.5.7.dist-info → kekikstream-2.5.9.dist-info}/entry_points.txt +0 -0
  108. {kekikstream-2.5.7.dist-info → kekikstream-2.5.9.dist-info}/licenses/LICENSE +0 -0
  109. {kekikstream-2.5.7.dist-info → kekikstream-2.5.9.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,176 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
4
+ from contextlib import suppress
5
+
6
+ class DDizi(PluginBase):
7
+ name = "DDizi"
8
+ language = "tr"
9
+ main_url = "https://www.ddizi.im"
10
+ favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
11
+ description = "Ddizi, dizi izle, dizi seyret, yerli dizi izle, canlı dizi, türk dizi izle, dizi izle full, diziizle, eski diziler"
12
+
13
+ main_page = {
14
+ f"{main_url}/yeni-eklenenler7" : "Son Eklenen Bölümler",
15
+ f"{main_url}/yabanci-dizi-izle" : "Yabancı Diziler",
16
+ f"{main_url}/eski.diziler" : "Eski Diziler",
17
+ f"{main_url}/yerli-diziler" : "Yerli Diziler"
18
+ }
19
+
20
+ async def get_articles(self, secici: HTMLHelper) -> list[dict]:
21
+ articles = []
22
+ for veri in secici.select("div.dizi-boxpost-cat, div.dizi-boxpost"):
23
+ title = secici.select_text("a", veri)
24
+ href = secici.select_attr("a", "href", veri)
25
+ img = secici.select_first("img.img-back, img.img-back-cat", veri)
26
+ poster = img.attrs.get("data-src") or img.attrs.get("src") if img else None
27
+
28
+ if title and href:
29
+ articles.append({
30
+ "title" : self.clean_title(title),
31
+ "url" : self.fix_url(href),
32
+ "poster": self.fix_url(poster),
33
+ })
34
+
35
+ return articles
36
+
37
+ async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
38
+ # DDizi'de sayfalama /sayfa-X formatında (0'dan başlıyor)
39
+ if page > 1:
40
+ target_url = f"{url}/sayfa-{page-1}"
41
+ else:
42
+ target_url = url
43
+
44
+ istek = await self.httpx.get(target_url, follow_redirects=True)
45
+ secici = HTMLHelper(istek.text)
46
+ veriler = await self.get_articles(secici)
47
+
48
+ return [MainPageResult(**veri, category=category) for veri in veriler if veri]
49
+
50
+ async def search(self, query: str) -> list[SearchResult]:
51
+ istek = await self.httpx.post(
52
+ url = f"{self.main_url}/arama/",
53
+ headers = {"Referer": f"{self.main_url}/"},
54
+ data = {"arama": query}
55
+ )
56
+ secici = HTMLHelper(istek.text)
57
+ veriler = await self.get_articles(secici)
58
+
59
+ return [SearchResult(**veri) for veri in veriler if veri]
60
+
61
+ async def load_item(self, url: str) -> SeriesInfo:
62
+ istek = await self.httpx.get(url)
63
+ secici = HTMLHelper(istek.text)
64
+
65
+ title = self.clean_title(secici.select_text("h1, h2, div.dizi-boxpost-cat a"))
66
+ poster = secici.select_poster("div.afis img, img.afis, img.img-back, img.img-back-cat")
67
+ description = secici.select_text("div.dizi-aciklama, div.aciklama, p")
68
+ rating = secici.select_text("span.comments-ss")
69
+
70
+ # Meta verileri (DDizi'de pek yok ama deniyoruz)
71
+ # Year için sadece açıklama kısmına bakalım ki URL'deki ID'yi almasın
72
+ year = HTMLHelper(description).regex_first(r"(\d{4})") if description else None
73
+ actors = secici.select_texts("div.oyuncular a, ul.bilgi li a")
74
+
75
+ episodes = []
76
+ current_page = 1
77
+ has_next = True
78
+
79
+ while has_next:
80
+ page_url = f"{url}/sayfa-{current_page}" if current_page > 1 else url
81
+ if current_page > 1:
82
+ istek = await self.httpx.get(page_url)
83
+ secici = HTMLHelper(istek.text)
84
+
85
+ page_eps = secici.select("div.bolumler a, div.sezonlar a, div.dizi-arsiv a, div.dizi-boxpost-cat a")
86
+ if not page_eps:
87
+ break
88
+
89
+ for ep in page_eps:
90
+ name = ep.text().strip()
91
+ href = ep.attrs.get("href")
92
+ if name and href:
93
+ # 'Bölüm Final' gibi durumları temizleyelim
94
+ clean_name = name.replace("Final", "").strip()
95
+ s, e = secici.extract_season_episode(clean_name)
96
+ episodes.append(Episode(
97
+ season = s or 1,
98
+ episode = e or 1,
99
+ title = name,
100
+ url = self.fix_url(href)
101
+ ))
102
+
103
+ # Sonraki sayfa kontrolü
104
+ has_next = any("Sonraki" in a.text() for a in secici.select(".pagination a"))
105
+ current_page += 1
106
+ if current_page > 10: break # Emniyet kilidi
107
+
108
+ if not episodes:
109
+ s, e = secici.extract_season_episode(title)
110
+ episodes.append(Episode(
111
+ season = s or 1,
112
+ episode = e or 1,
113
+ title = title,
114
+ url = url
115
+ ))
116
+
117
+ return SeriesInfo(
118
+ url = url,
119
+ poster = self.fix_url(poster),
120
+ title = title,
121
+ description = description,
122
+ rating = rating.strip() if rating else None,
123
+ year = year,
124
+ actors = actors,
125
+ episodes = episodes
126
+ )
127
+
128
+ async def load_links(self, url: str) -> list[ExtractResult]:
129
+ istek = await self.httpx.get(url)
130
+ secici = HTMLHelper(istek.text)
131
+
132
+ results = []
133
+ # og:video ve JWPlayer kontrolü
134
+ og_video = secici.select_attr("meta[property='og:video']", "content")
135
+ if og_video:
136
+ og_video = self.fix_url(og_video)
137
+ with suppress(Exception):
138
+ player_istek = await self.httpx.get(og_video, headers={"Referer": url})
139
+ player_secici = HTMLHelper(player_istek.text)
140
+
141
+ # file: '...' logic
142
+ sources = player_secici.regex_all(r'file:\s*["\']([^"\']+)["\']')
143
+ for src in sources:
144
+ src = self.fix_url(src)
145
+ # Direkt link kontrolü - Extractor gerektirmeyenler
146
+ is_direct = any(x in src.lower() for x in ["google", "twimg", "mncdn", "akamai", "streambox", ".m3u8", ".mp4", "master.txt"])
147
+
148
+ if is_direct:
149
+ results.append(ExtractResult(
150
+ url = src,
151
+ name = "Video",
152
+ user_agent = "googleusercontent",
153
+ referer = "https://twitter.com/"
154
+ ))
155
+ else:
156
+ res = await self.extract(src, referer=og_video)
157
+ if res:
158
+ if isinstance(res, list): results.extend(res)
159
+ else: results.append(res)
160
+
161
+ # Fallback to direct extraction if nothing found but we have og_video
162
+ if not results:
163
+ if any(x in og_video.lower() for x in ["google", "twimg", "mncdn", "akamai", "streambox", ".m3u8", ".mp4", "master.txt"]):
164
+ results.append(ExtractResult(
165
+ url = og_video,
166
+ name = "Video",
167
+ user_agent = "googleusercontent",
168
+ referer = "https://twitter.com/"
169
+ ))
170
+ else:
171
+ res = await self.extract(og_video)
172
+ if res:
173
+ if isinstance(res, list): results.extend(res)
174
+ else: results.append(res)
175
+
176
+ return results
@@ -0,0 +1,94 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult, HTMLHelper
4
+
5
+ class RealFilmIzle(PluginBase):
6
+ name = "RealFilmIzle"
7
+ language = "tr"
8
+ main_url = "https://realfilmizle.com"
9
+ favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
10
+ description = "realfilmizle.com, sinemayı seven kullanıcılar için hazırlanmış, zengin içerik yapısına sahip bir online film izleme sitesidir."
11
+
12
+ main_page = {
13
+ f"{main_url}/dizi/aile-filmleri/page" : "Aile",
14
+ f"{main_url}/dizi/aksiyon-filmleri/page" : "Aksiyon",
15
+ f"{main_url}/dizi/animasyon-filmleri/page" : "Animasyon",
16
+ f"{main_url}/dizi/anime-filmleri/page" : "Anime",
17
+ f"{main_url}/dizi/belgeseler-filmleri/page" : "Belgeseler",
18
+ f"{main_url}/dizi/bilim-kurgu-filmleri/page" : "Bilim-Kurgu",
19
+ f"{main_url}/dizi/biyografi-filmleri/page" : "Biyoğrafi",
20
+ f"{main_url}/dizi/dram-filmleri/page" : "Dram",
21
+ f"{main_url}/dizi/erotik-filmleri/page" : "Erotik",
22
+ f"{main_url}/dizi/fantastik-filmleri/page" : "Fantastik",
23
+ f"{main_url}/dizi/gerilim-filmleri/page" : "Gerilim",
24
+ f"{main_url}/dizi/gizem-filmleri/page" : "Gizem",
25
+ f"{main_url}/dizi/hint-filmleri/page" : "Hint",
26
+ f"{main_url}/dizi/komedi-filmleri/page" : "Komedi",
27
+ f"{main_url}/dizi/korku-filmleri/page" : "Korku",
28
+ f"{main_url}/dizi/macera-filmleri/page" : "Macera",
29
+ f"{main_url}/dizi/muzikal-filmleri/page" : "Müzikal",
30
+ f"{main_url}/dizi/netflix-filmleri/page" : "Netflix",
31
+ f"{main_url}/dizi/romantik-filmleri/page" : "Romantik",
32
+ f"{main_url}/dizi/savas-filmleri/page" : "Savaş",
33
+ f"{main_url}/dizi/spor-filmleri/page" : "Spor",
34
+ f"{main_url}/dizi/suc-filmleri/page" : "Suç",
35
+ f"{main_url}/dizi/tarihi-filmleri/page" : "Tarihi",
36
+ f"{main_url}/dizi/western-filmleri/page" : "Western",
37
+ f"{main_url}/dizi/yerli-filmleri/page" : "Yerli",
38
+ }
39
+
40
+ async def get_articles(self, secici: HTMLHelper) -> list[dict]:
41
+ articles = []
42
+ for veri in secici.select("article.movie-box"):
43
+ title = secici.select_text("div.name a", veri)
44
+ href = secici.select_attr("div.name a", "href", veri)
45
+ poster = secici.select_poster("img", veri)
46
+
47
+ articles.append({
48
+ "title" : self.clean_title(title),
49
+ "url" : self.fix_url(href),
50
+ "poster": self.fix_url(poster),
51
+ })
52
+
53
+ return articles
54
+
55
+ async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
56
+ istek = await self.httpx.get(f"{url}/{page}")
57
+ secici = HTMLHelper(istek.text)
58
+ veriler = await self.get_articles(secici)
59
+
60
+ return [MainPageResult(**veri, category=category) for veri in veriler if veri]
61
+
62
+ async def search(self, query: str) -> list[SearchResult]:
63
+ istek = await self.httpx.get(f"{self.main_url}/?s={query}")
64
+ secici = HTMLHelper(istek.text)
65
+ veriler = await self.get_articles(secici)
66
+
67
+ return [SearchResult(**veri) for veri in veriler if veri]
68
+
69
+ async def load_item(self, url: str) -> MovieInfo:
70
+ istek = await self.httpx.get(url)
71
+ secici = HTMLHelper(istek.text)
72
+
73
+ title = self.clean_title(secici.select_text("div.film h1"))
74
+ poster = secici.select_poster("div.poster img")
75
+ description = secici.select_direct_text("div.description")
76
+ tags = secici.select_texts("ol.scheme-breadcrumbs li a")
77
+ tags = [tag.replace("✅ ", "").replace(" Filmleri", "") for tag in tags if tag != "Film izle"]
78
+
79
+ return MovieInfo(
80
+ url = url,
81
+ poster = self.fix_url(poster),
82
+ title = self.clean_title(title),
83
+ description = description,
84
+ tags = tags
85
+ )
86
+
87
+ async def load_links(self, url: str) -> list[ExtractResult]:
88
+ istek = await self.httpx.get(url)
89
+ secici = HTMLHelper(istek.text)
90
+
91
+ iframe = secici.select_attr("div.video-content iframe", "src")
92
+ result = await self.extract(iframe)
93
+
94
+ return [result] if result else []
@@ -0,0 +1,211 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult, HTMLHelper
4
+ import json
5
+
6
+ class ShowFlix(PluginBase):
7
+ name = "ShowFlix"
8
+ language = "en"
9
+ main_url = "https://showflix.store"
10
+ favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
11
+ description = "Showflix - Watch and Download Latest Movies and TV Shows for Free. Stream in HD with No Ads!"
12
+
13
+ # Kotlin'den gelen API endpoint'leri
14
+ movie_api = "https://parse.showflix.sbs/parse/classes/moviesv2"
15
+ tv_api = "https://parse.showflix.sbs/parse/classes/seriesv2"
16
+
17
+ # Parse API ayarları (Kotlin'den uyarlandı) - Bu placeholder'lar çalışıyor!
18
+ app_id = "SHOWFLIXAPPID"
19
+ js_key = "SHOWFLIXMASTERKEY"
20
+
21
+ def get_payload(self, extra: dict) -> dict:
22
+ base = {
23
+ "_method": "GET",
24
+ "_ApplicationId": self.app_id,
25
+ "_JavaScriptKey": self.js_key,
26
+ "_ClientVersion": "js3.4.1",
27
+ "_InstallationId": "60f6b1a7-8860-4edf-b255-6bc465b6c704"
28
+ }
29
+ base.update(extra)
30
+ return base
31
+
32
+ main_page = {
33
+ "movie" : "Movies",
34
+ "tv" : "TV Shows"
35
+ }
36
+
37
+ async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
38
+ api_url = self.movie_api if url == "movie" else self.tv_api
39
+ skip = (page - 1) * 20
40
+
41
+ payload = self.get_payload({
42
+ "limit": 20,
43
+ "skip": skip,
44
+ "order": "-updatedAt"
45
+ })
46
+
47
+ istek = await self.httpx.post(api_url, json=payload)
48
+ data = istek.json().get("results", [])
49
+
50
+ results = []
51
+ for item in data:
52
+ title = item.get("name")
53
+ poster = item.get("posterURL") or item.get("image")
54
+ # Detay sayfasına gitmek için ID'yi kullanacağız, ancak Plugin yapısına uygun bir URL uydurmalıyız
55
+ # load_item içinde bu URL'den ID'yi geri alacağız
56
+ item_type = "movie" if url == "movie" else "tv"
57
+ href = f"{self.main_url}/detail/{item_type}/{item.get('objectId')}"
58
+
59
+ if title:
60
+ results.append(MainPageResult(
61
+ category = category,
62
+ title = self.clean_title(title),
63
+ url = href,
64
+ poster = self.fix_url(poster)
65
+ ))
66
+
67
+ return results
68
+
69
+ async def search(self, query: str) -> list[SearchResult]:
70
+ results = []
71
+ for api_url, item_type in [(self.movie_api, "movie"), (self.tv_api, "tv")]:
72
+ payload = self.get_payload({
73
+ "where": {"name": {"$regex": query, "$options": "i"}},
74
+ "limit": 10
75
+ })
76
+ istek = await self.httpx.post(api_url, json=payload)
77
+ data = istek.json().get("results", [])
78
+
79
+ for item in data:
80
+ results.append(SearchResult(
81
+ title = self.clean_title(item.get("name")),
82
+ url = f"{self.main_url}/detail/{item_type}/{item.get('objectId')}",
83
+ poster = self.fix_url(item.get("posterURL") or item.get("image"))
84
+ ))
85
+
86
+ return results
87
+
88
+ async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
89
+ # URL formatımız: .../detail/{type}/{id}
90
+ parts = url.split("/")
91
+ item_type = parts[-2]
92
+ obj_id = parts[-1]
93
+
94
+ api_url = self.movie_api if item_type == "movie" else self.tv_api
95
+ payload = self.get_payload({})
96
+
97
+ istek = await self.httpx.post(f"{api_url}/{obj_id}", json=payload)
98
+ item = istek.json()
99
+
100
+ title = item.get("name")
101
+ poster = self.fix_url(item.get("posterURL") or item.get("image"))
102
+ description = item.get("storyline") or item.get("description")
103
+ year = item.get("releaseYear") or item.get("year")
104
+ rating = item.get("rating")
105
+
106
+ if item_type == "movie":
107
+ return MovieInfo(
108
+ url = url,
109
+ poster = poster,
110
+ title = title,
111
+ description = description,
112
+ year = str(year) if year else None,
113
+ rating = str(rating) if rating else None
114
+ )
115
+ else:
116
+ # Sezon ve bölümleri ayrı API çağrılarıyla alıyoruz
117
+ episodes = await self.get_seasons_with_episodes(obj_id)
118
+
119
+ return SeriesInfo(
120
+ url = url,
121
+ poster = poster,
122
+ title = title,
123
+ description = description,
124
+ year = str(year) if year else None,
125
+ rating = str(rating) if rating else None,
126
+ episodes = episodes
127
+ )
128
+
129
+ async def get_seasons_with_episodes(self, series_id: str) -> list[Episode]:
130
+ # Sezonları al
131
+ season_url = "https://parse.showflix.sbs/parse/classes/seasonv2"
132
+ payload = self.get_payload({"where": {"seriesId": series_id}})
133
+ istek = await self.httpx.post(season_url, json=payload)
134
+ seasons = istek.json().get("results", [])
135
+
136
+ all_episodes = []
137
+ for season in seasons:
138
+ season_id = season.get("objectId")
139
+ season_num = int("".join(filter(str.isdigit, season.get("name", "1"))) or "1")
140
+
141
+ # Bölümleri al
142
+ episode_url = "https://parse.showflix.sbs/parse/classes/episodev2"
143
+ ep_payload = self.get_payload({"where": {"seasonId": season_id}})
144
+ ep_istek = await self.httpx.post(episode_url, json=ep_payload)
145
+ eps = ep_istek.json().get("results", [])
146
+
147
+ for ep in eps:
148
+ # Gömülü linkleri 'data' alanında saklayabiliriz
149
+ embeds = ep.get("embedLinks", {})
150
+ data = {
151
+ "streamwish": embeds.get("streamwish"),
152
+ "streamruby": embeds.get("streamruby"),
153
+ "upnshare": embeds.get("upnshare"),
154
+ "vihide": embeds.get("vihide")
155
+ }
156
+
157
+ all_episodes.append(Episode(
158
+ season = season_num,
159
+ episode = ep.get("episodeNumber", 1),
160
+ title = ep.get("name"),
161
+ url = f"showflix://{json.dumps(data)}" # Custom protocol for load_links
162
+ ))
163
+
164
+ return sorted(all_episodes, key=lambda x: (x.season, x.episode))
165
+
166
+ async def load_links(self, url: str) -> list[ExtractResult]:
167
+ if url.startswith("showflix://"):
168
+ data = json.loads(url.replace("showflix://", ""))
169
+ results = []
170
+
171
+ mapping = {
172
+ "streamwish": "https://embedwish.com/e/{}",
173
+ "streamruby": "https://rubyvidhub.com/embed-{}.html",
174
+ "upnshare": "https://showflix.upns.one/#{}",
175
+ "vihide": "https://smoothpre.com/v/{}.html"
176
+ }
177
+
178
+ for key, template in mapping.items():
179
+ if val := data.get(key):
180
+ res = await self.extract(template.format(val))
181
+ if res:
182
+ if isinstance(res, list):
183
+ results.extend(res)
184
+ else:
185
+ results.append(res)
186
+ return results
187
+
188
+ # Movie Fallback
189
+ parts = url.split("/")
190
+ obj_id = parts[-1]
191
+ payload = self.get_payload({})
192
+ istek = await self.httpx.post(f"{self.movie_api}/{obj_id}", json=payload)
193
+ item = istek.json()
194
+ embeds = item.get("embedLinks", {})
195
+
196
+ results = []
197
+ mapping = {
198
+ "streamwish": "https://embedwish.com/e/{}",
199
+ "streamruby": "https://rubyvidhub.com/embed-{}.html",
200
+ "upnshare": "https://showflix.upns.one/#{}",
201
+ "vihide": "https://smoothpre.com/v/{}.html"
202
+ }
203
+
204
+ for key, template in mapping.items():
205
+ if val := embeds.get(key):
206
+ res = await self.extract(template.format(val))
207
+ if res:
208
+ if isinstance(res, list): results.extend(res)
209
+ else: results.append(res)
210
+
211
+ return results
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: KekikStream
3
- Version: 2.5.7
3
+ Version: 2.5.9
4
4
  Summary: terminal üzerinden medya içeriği aramanızı ve VLC/MPV gibi popüler medya oynatıcılar aracılığıyla doğrudan izlemenizi sağlayan modüler ve genişletilebilir bir bıdı bıdı
5
5
  Home-page: https://github.com/keyiflerolsun/KekikStream
6
6
  Author: keyiflerolsun