KekikStream 1.7.1__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 (86) hide show
  1. KekikStream/Core/Extractor/ExtractorBase.py +13 -7
  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 +21 -9
  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 +4 -5
  13. KekikStream/Extractors/ContentX.py +4 -6
  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 +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 +7 -7
  25. KekikStream/Extractors/{OkRuHTTP.py → Odnoklassniki_.py} +5 -1
  26. KekikStream/Extractors/PeaceMakerst.py +4 -5
  27. KekikStream/Extractors/{HDStreamAble.py → PeaceMakerst_.py} +1 -1
  28. KekikStream/Extractors/PixelDrain.py +1 -2
  29. KekikStream/Extractors/PlayerFilmIzle.py +62 -0
  30. KekikStream/Extractors/RapidVid.py +2 -3
  31. KekikStream/Extractors/RapidVid_.py +7 -0
  32. KekikStream/Extractors/SetPlay.py +57 -0
  33. KekikStream/Extractors/SetPrime.py +45 -0
  34. KekikStream/Extractors/SibNet.py +2 -3
  35. KekikStream/Extractors/Sobreatsesuyp.py +4 -5
  36. KekikStream/Extractors/TRsTX.py +4 -5
  37. KekikStream/Extractors/TauVideo.py +2 -3
  38. KekikStream/Extractors/TurboImgz.py +2 -3
  39. KekikStream/Extractors/TurkeyPlayer.py +34 -0
  40. KekikStream/Extractors/VidHide.py +72 -0
  41. KekikStream/Extractors/VidMoly.py +4 -5
  42. KekikStream/Extractors/{VidMolyMe.py → VidMoly_.py} +1 -1
  43. KekikStream/Extractors/VidMoxy.py +2 -3
  44. KekikStream/Extractors/VidPapi.py +89 -0
  45. KekikStream/Extractors/VideoSeyred.py +3 -4
  46. KekikStream/Extractors/YTDLP.py +177 -0
  47. KekikStream/Extractors/YildizKisaFilm.py +41 -0
  48. KekikStream/Plugins/DiziBox.py +18 -23
  49. KekikStream/Plugins/DiziPal.py +16 -16
  50. KekikStream/Plugins/DiziYou.py +48 -23
  51. KekikStream/Plugins/Dizilla.py +47 -32
  52. KekikStream/Plugins/FilmBip.py +145 -0
  53. KekikStream/Plugins/FilmMakinesi.py +6 -8
  54. KekikStream/Plugins/FilmModu.py +9 -9
  55. KekikStream/Plugins/FullHDFilm.py +164 -0
  56. KekikStream/Plugins/FullHDFilmizlesene.py +4 -8
  57. KekikStream/Plugins/HDFilmCehennemi.py +15 -19
  58. KekikStream/Plugins/JetFilmizle.py +67 -49
  59. KekikStream/Plugins/KultFilmler.py +219 -0
  60. KekikStream/Plugins/RecTV.py +18 -22
  61. KekikStream/Plugins/RoketDizi.py +232 -0
  62. KekikStream/Plugins/SelcukFlix.py +309 -0
  63. KekikStream/Plugins/SezonlukDizi.py +12 -13
  64. KekikStream/Plugins/SineWix.py +8 -12
  65. KekikStream/Plugins/Sinefy.py +238 -0
  66. KekikStream/Plugins/SinemaCX.py +157 -0
  67. KekikStream/Plugins/Sinezy.py +146 -0
  68. KekikStream/Plugins/SuperFilmGeldi.py +121 -0
  69. KekikStream/Plugins/UgurFilm.py +7 -11
  70. KekikStream/__init__.py +34 -24
  71. KekikStream/requirements.txt +3 -4
  72. kekikstream-2.0.2.dist-info/METADATA +309 -0
  73. kekikstream-2.0.2.dist-info/RECORD +82 -0
  74. KekikStream/Extractors/FourCX.py +0 -7
  75. KekikStream/Extractors/FourPichive.py +0 -7
  76. KekikStream/Extractors/FourPlayRu.py +0 -7
  77. KekikStream/Extractors/Hotlinger.py +0 -7
  78. KekikStream/Extractors/OkRuSSL.py +0 -7
  79. KekikStream/Extractors/Pichive.py +0 -7
  80. KekikStream/Extractors/PlayRu.py +0 -7
  81. kekikstream-1.7.1.dist-info/METADATA +0 -109
  82. kekikstream-1.7.1.dist-info/RECORD +0 -63
  83. {kekikstream-1.7.1.dist-info → kekikstream-2.0.2.dist-info}/WHEEL +0 -0
  84. {kekikstream-1.7.1.dist-info → kekikstream-2.0.2.dist-info}/entry_points.txt +0 -0
  85. {kekikstream-1.7.1.dist-info → kekikstream-2.0.2.dist-info}/licenses/LICENSE +0 -0
  86. {kekikstream-1.7.1.dist-info → kekikstream-2.0.2.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from KekikStream.Core import kekik_cache, PluginBase, MainPageResult, SearchResult, MovieInfo, Episode, SeriesInfo, ExtractResult, Subtitle
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, Episode, SeriesInfo, ExtractResult, Subtitle
4
4
  import json
5
5
 
6
6
  class SineWix(PluginBase):
@@ -35,9 +35,8 @@ class SineWix(PluginBase):
35
35
  f"{main_url}/sinewix/movies/36" : "Tarih",
36
36
  }
37
37
 
38
- #@kekik_cache(ttl=60*60)
39
38
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
40
- istek = await self.cffi.get(f"{url}/{page}")
39
+ istek = await self.httpx.get(f"{url}/{page}")
41
40
  veriler = istek.json()
42
41
 
43
42
  return [
@@ -50,9 +49,8 @@ class SineWix(PluginBase):
50
49
  for veri in veriler.get("data")
51
50
  ]
52
51
 
53
- #@kekik_cache(ttl=60*60)
54
52
  async def search(self, query: str) -> list[SearchResult]:
55
- istek = await self.cffi.get(f"{self.main_url}/sinewix/search/{query}")
53
+ istek = await self.httpx.get(f"{self.main_url}/sinewix/search/{query}")
56
54
 
57
55
  return [
58
56
  SearchResult(
@@ -63,12 +61,11 @@ class SineWix(PluginBase):
63
61
  for veri in istek.json().get("search")
64
62
  ]
65
63
 
66
- #@kekik_cache(ttl=60*60)
67
64
  async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
68
65
  item_type = url.split("?type=")[-1].split("&id=")[0]
69
66
  item_id = url.split("&id=")[-1]
70
67
 
71
- istek = await self.cffi.get(f"{self.main_url}/sinewix/{item_type}/{item_id}")
68
+ istek = await self.httpx.get(f"{self.main_url}/sinewix/{item_type}/{item_id}")
72
69
  veri = istek.json()
73
70
 
74
71
  match item_type:
@@ -126,7 +123,6 @@ class SineWix(PluginBase):
126
123
  episodes = episodes,
127
124
  )
128
125
 
129
- #@kekik_cache(ttl=15*60)
130
126
  async def load_links(self, url: str) -> list[dict]:
131
127
  try:
132
128
  veri = json.loads(url)
@@ -143,7 +139,7 @@ class SineWix(PluginBase):
143
139
  if not url.startswith(self.main_url) and not url.startswith("{"):
144
140
  return [{"url": url, "name": "Video"}]
145
141
 
146
- istek = await self.cffi.get(url)
142
+ istek = await self.httpx.get(url)
147
143
  veri = istek.json()
148
144
 
149
145
  org_title = veri.get("title")
@@ -161,9 +157,9 @@ class SineWix(PluginBase):
161
157
 
162
158
  return results
163
159
 
164
- async def play(self, name: str, url: str, referer: str, subtitles: list[Subtitle]):
165
- extract_result = ExtractResult(name=name, url=url, referer=referer, subtitles=subtitles)
166
- self.media_handler.title = name
160
+ async def play(self, **kwargs):
161
+ extract_result = ExtractResult(**kwargs)
162
+ self.media_handler.title = kwargs.get("name")
167
163
  if self.name not in self.media_handler.title:
168
164
  self.media_handler.title = f"{self.name} | {self.media_handler.title}"
169
165
 
@@ -0,0 +1,238 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, MovieInfo
4
+ from parsel import Selector
5
+ import re, json, urllib.parse
6
+
7
+ class Sinefy(PluginBase):
8
+ name = "Sinefy"
9
+ language = "tr"
10
+ main_url = "https://sinefy3.com"
11
+ favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
12
+ description = "Yabancı film izle olarak vizyondaki en yeni yabancı filmleri türkçe dublaj ve altyazılı olarak en hızlı şekilde full hd olarak sizlere sunuyoruz."
13
+
14
+ main_page = {
15
+ f"{main_url}/page/" : "Son Eklenenler",
16
+ f"{main_url}/en-yenifilmler" : "Yeni Filmler",
17
+ f"{main_url}/netflix-filmleri-izle" : "Netflix Filmleri",
18
+ f"{main_url}/dizi-izle/netflix" : "Netflix Dizileri",
19
+ f"{main_url}/gozat/filmler/animasyon" : "Animasyon",
20
+ f"{main_url}/gozat/filmler/komedi" : "Komedi",
21
+ f"{main_url}/gozat/filmler/suc" : "Suç",
22
+ f"{main_url}/gozat/filmler/aile" : "Aile",
23
+ f"{main_url}/gozat/filmler/aksiyon" : "Aksiyon",
24
+ f"{main_url}/gozat/filmler/macera" : "Macera",
25
+ f"{main_url}/gozat/filmler/fantastik" : "Fantastik",
26
+ f"{main_url}/gozat/filmler/korku" : "Korku",
27
+ f"{main_url}/gozat/filmler/romantik" : "Romantik",
28
+ f"{main_url}/gozat/filmler/savas" : "Savaş",
29
+ f"{main_url}/gozat/filmler/gerilim" : "Gerilim",
30
+ f"{main_url}/gozat/filmler/bilim-kurgu" : "Bilim Kurgu",
31
+ f"{main_url}/gozat/filmler/dram" : "Dram",
32
+ f"{main_url}/gozat/filmler/gizem" : "Gizem",
33
+ f"{main_url}/gozat/filmler/western" : "Western",
34
+ f"{main_url}/gozat/filmler/ulke/turkiye" : "Türk Filmleri",
35
+ f"{main_url}/gozat/filmler/ulke/kore" : "Kore Filmleri"
36
+ }
37
+
38
+ async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
39
+ if "page/" in url:
40
+ full_url = f"{url}{page}"
41
+ elif "en-yenifilmler" in url or "netflix" in url:
42
+ full_url = f"{url}/{page}"
43
+ else:
44
+ full_url = f"{url}&page={page}"
45
+
46
+ resp = await self.httpx.get(full_url)
47
+ sel = Selector(resp.text)
48
+
49
+ results = []
50
+ # Kotlin: div.poster-with-subject, div.dark-segment div.poster-md.poster
51
+ for item in sel.css("div.poster-with-subject, div.dark-segment div.poster-md.poster"):
52
+ title = item.css("h2::text").get()
53
+ href = item.css("a::attr(href)").get()
54
+ poster = item.css("img::attr(data-srcset)").get()
55
+ if poster:
56
+ poster = poster.split(",")[0].split(" ")[0]
57
+
58
+ if title and href:
59
+ results.append(MainPageResult(
60
+ category = category,
61
+ title = title,
62
+ url = self.fix_url(href),
63
+ poster = self.fix_url(poster)
64
+ ))
65
+
66
+ return results
67
+
68
+ async def search(self, query: str) -> list[SearchResult]:
69
+ # Try to get dynamic keys from main page first
70
+ c_key = "ca1d4a53d0f4761a949b85e51e18f096"
71
+ c_value = "MTc0NzI2OTAwMDU3ZTEwYmZjMDViNWFmOWIwZDViODg0MjU4MjA1ZmYxOThmZTYwMDdjMWQzMzliNzY5NzFlZmViMzRhMGVmNjgwODU3MGIyZA=="
72
+
73
+ try:
74
+ resp = await self.httpx.get(self.main_url)
75
+ sel = Selector(resp.text)
76
+ cke = sel.css("input[name='cKey']::attr(value)").get()
77
+ cval = sel.css("input[name='cValue']::attr(value)").get()
78
+ if cke and cval:
79
+ c_key = cke
80
+ c_value = cval
81
+
82
+ except Exception:
83
+ pass
84
+
85
+ post_url = f"{self.main_url}/bg/searchcontent"
86
+ data = {
87
+ "cKey" : c_key,
88
+ "cValue" : c_value,
89
+ "searchTerm" : query
90
+ }
91
+
92
+ headers = {
93
+ "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0",
94
+ "Accept" : "application/json, text/javascript, */*; q=0.01",
95
+ "X-Requested-With" : "XMLHttpRequest",
96
+ "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8"
97
+ }
98
+
99
+ response = await self.httpx.post(post_url, data=data, headers=headers)
100
+
101
+ try:
102
+ # Extract JSON data from response (might contain garbage chars at start)
103
+ raw = response.text
104
+ json_start = raw.find('{')
105
+ if json_start != -1:
106
+ clean_json = raw[json_start:]
107
+ data = json.loads(clean_json)
108
+
109
+ results = []
110
+ # Result array is in data['data']['result']
111
+ res_array = data.get("data", {}).get("result", [])
112
+
113
+ if not res_array:
114
+ # Fallback manual parsing ?
115
+ pass
116
+
117
+ for item in res_array:
118
+ name = item.get("object_name")
119
+ slug = item.get("used_slug")
120
+ poster = item.get("object_poster_url")
121
+
122
+ if name and slug:
123
+ if "cdn.ampproject.org" in poster:
124
+ poster = "https://images.macellan.online/images/movie/poster/180/275/80/" + poster.split("/")[-1]
125
+
126
+ results.append(SearchResult(
127
+ title=name,
128
+ url=self.fix_url(slug),
129
+ poster=self.fix_url(poster)
130
+ ))
131
+ return results
132
+
133
+ except Exception:
134
+ pass
135
+ return []
136
+
137
+ async def load_item(self, url: str) -> SeriesInfo:
138
+ resp = await self.httpx.get(url)
139
+ sel = Selector(resp.text)
140
+
141
+ title = sel.css("h1::text").get()
142
+ poster_info = sel.css("div.ui.items img::attr(data-srcset)").get()
143
+ poster = None
144
+ if poster_info:
145
+ # take 1x
146
+ parts = str(poster_info).split(",")
147
+ for p in parts:
148
+ if "1x" in p:
149
+ poster = p.strip().split(" ")[0]
150
+ break
151
+
152
+ description = sel.css("p#tv-series-desc::text").get()
153
+ tags = sel.css("div.item.categories a::text").getall()
154
+ rating = sel.css("span.color-imdb::text").get()
155
+ actors = sel.css("div.content h5::text").getall()
156
+ year = sel.css("span.item.year::text").get() # Year bilgisi eklendi
157
+
158
+ episodes = []
159
+ season_elements = sel.css("section.episodes-box")
160
+
161
+ if season_elements:
162
+ # Get season links
163
+ season_links = []
164
+ menu = sel.css("div.ui.vertical.fluid.tabular.menu a")
165
+ for link in menu:
166
+ href = link.css("::attr(href)").get()
167
+ if href:
168
+ season_links.append(self.fix_url(href))
169
+
170
+ for s_url in season_links:
171
+ target_url = s_url if "/bolum-" in s_url else f"{s_url}/bolum-1"
172
+
173
+ try:
174
+ s_resp = await self.httpx.get(target_url)
175
+ s_sel = Selector(s_resp.text)
176
+ ep_links = s_sel.css("div.ui.list.celled a.item")
177
+
178
+ current_season_no = 1
179
+ match = re.search(r"sezon-(\d+)", target_url)
180
+ if match:
181
+ current_season_no = int(match.group(1))
182
+
183
+ for ep_link in ep_links:
184
+ href = ep_link.css("::attr(href)").get()
185
+ name = ep_link.css("div.content div.header::text").get()
186
+
187
+ if href:
188
+ ep_no = 0
189
+ match_ep = re.search(r"bolum-(\d+)", href)
190
+ if match_ep:
191
+ ep_no = int(match_ep.group(1))
192
+
193
+ episodes.append(Episode(
194
+ season = current_season_no,
195
+ episode = ep_no,
196
+ title = name.strip() if name else "",
197
+ url = self.fix_url(href)
198
+ ))
199
+ except Exception:
200
+ pass
201
+
202
+ if episodes:
203
+ return SeriesInfo(
204
+ title = title,
205
+ url = url,
206
+ poster = self.fix_url(poster),
207
+ description = description,
208
+ rating = rating,
209
+ tags = tags,
210
+ actors = actors,
211
+ year = year,
212
+ episodes = episodes
213
+ )
214
+ else:
215
+ return MovieInfo(
216
+ title = title,
217
+ url = url,
218
+ poster = self.fix_url(poster),
219
+ description = description,
220
+ rating = rating,
221
+ tags = tags,
222
+ actors = actors,
223
+ year = year
224
+ )
225
+
226
+ async def load_links(self, url: str) -> list[dict]:
227
+ resp = await self.httpx.get(url)
228
+ sel = Selector(resp.text)
229
+
230
+ iframe = sel.css("iframe::attr(src)").get()
231
+ if iframe:
232
+ iframe = self.fix_url(iframe)
233
+ extractor = self.ex_manager.find_extractor(iframe)
234
+ return [{
235
+ "url" : iframe,
236
+ "name" : extractor.name if extractor else "Iframe"
237
+ }]
238
+ return []
@@ -0,0 +1,157 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult, Subtitle
4
+ from parsel import Selector
5
+ import re
6
+
7
+ class SinemaCX(PluginBase):
8
+ name = "SinemaCX"
9
+ language = "tr"
10
+ main_url = "https://www.sinema.fit"
11
+ favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
12
+ description = "HD Film izle, Türkçe Dublaj ve Altyazılı filmler."
13
+
14
+ main_page = {
15
+ f"{main_url}/page/SAYFA" : "Son Eklenen Filmler",
16
+ f"{main_url}/izle/aile-filmleri/page/SAYFA" : "Aile Filmleri",
17
+ f"{main_url}/izle/aksiyon-filmleri/page/SAYFA" : "Aksiyon Filmleri",
18
+ f"{main_url}/izle/animasyon-filmleri/page/SAYFA" : "Animasyon Filmleri",
19
+ f"{main_url}/izle/belgesel/page/SAYFA" : "Belgesel Filmleri",
20
+ f"{main_url}/izle/bilim-kurgu-filmleri/page/SAYFA" : "Bilim Kurgu Filmler",
21
+ f"{main_url}/izle/biyografi/page/SAYFA" : "Biyografi Filmleri",
22
+ f"{main_url}/izle/fantastik-filmler/page/SAYFA" : "Fantastik Filmler",
23
+ f"{main_url}/izle/gizem-filmleri/page/SAYFA" : "Gizem Filmleri",
24
+ f"{main_url}/izle/komedi-filmleri/page/SAYFA" : "Komedi Filmleri",
25
+ f"{main_url}/izle/korku-filmleri/page/SAYFA" : "Korku Filmleri",
26
+ f"{main_url}/izle/macera-filmleri/page/SAYFA" : "Macera Filmleri",
27
+ f"{main_url}/izle/romantik-filmler/page/SAYFA" : "Romantik Filmler",
28
+ f"{main_url}/izle/erotik-filmler/page/SAYFA" : "Erotik Film",
29
+ }
30
+
31
+ async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
32
+ istek = await self.httpx.get(url.replace("SAYFA", str(page)))
33
+ secici = Selector(istek.text)
34
+
35
+ return [
36
+ MainPageResult(
37
+ category = category,
38
+ title = veri.css("div.yanac span::text").get(),
39
+ url = self.fix_url(veri.css("div.yanac a::attr(href)").get()),
40
+ poster = self.fix_url(veri.css("a.resim img::attr(data-src)").get() or veri.css("a.resim img::attr(src)").get()),
41
+ )
42
+ for veri in secici.css("div.son div.frag-k, div.icerik div.frag-k")
43
+ if veri.css("div.yanac span::text").get()
44
+ ]
45
+
46
+ async def search(self, query: str) -> list[SearchResult]:
47
+ istek = await self.httpx.get(f"{self.main_url}/?s={query}")
48
+ secici = Selector(istek.text)
49
+
50
+ return [
51
+ SearchResult(
52
+ title = veri.css("div.yanac span::text").get(),
53
+ url = self.fix_url(veri.css("div.yanac a::attr(href)").get()),
54
+ poster = self.fix_url(veri.css("a.resim img::attr(data-src)").get() or veri.css("a.resim img::attr(src)").get()),
55
+ )
56
+ for veri in secici.css("div.icerik div.frag-k")
57
+ if veri.css("div.yanac span::text").get()
58
+ ]
59
+
60
+ async def load_item(self, url: str) -> MovieInfo:
61
+ istek = await self.httpx.get(url)
62
+ secici = Selector(istek.text)
63
+
64
+ duration_match = re.search(r"Süre:.*?(\d+)\s*Dakika", istek.text)
65
+ description = secici.css("div.ackl div.scroll-liste::text").get()
66
+
67
+ return MovieInfo(
68
+ url = url,
69
+ poster = self.fix_url(secici.css("link[rel='image_src']::attr(href)").get()),
70
+ title = secici.css("div.f-bilgi h1::text").get(),
71
+ description = description.strip() if description else None,
72
+ tags = [a.css("::text").get() for a in secici.css("div.f-bilgi div.tur a")],
73
+ year = secici.css("div.f-bilgi ul.detay a[href*='yapim']::text").get(),
74
+ actors = [li.css("span.isim::text").get() for li in secici.css("li.oync li.oyuncu-k")],
75
+ duration = int(duration_match[1]) if duration_match else None,
76
+ )
77
+
78
+ async def load_links(self, url: str) -> list[dict]:
79
+ istek = await self.httpx.get(url)
80
+ secici = Selector(istek.text)
81
+
82
+ iframe_list = [iframe.css("::attr(data-vsrc)").get() for iframe in secici.css("iframe")]
83
+ iframe_list = [i for i in iframe_list if i]
84
+
85
+ # Sadece fragman varsa /2/ sayfasından dene
86
+ has_only_trailer = all(
87
+ "youtube" in (i or "").lower() or "fragman" in (i or "").lower() or "trailer" in (i or "").lower()
88
+ for i in iframe_list
89
+ )
90
+
91
+ if has_only_trailer:
92
+ alt_url = url.rstrip("/") + "/2/"
93
+ alt_istek = await self.httpx.get(alt_url)
94
+ alt_sec = Selector(alt_istek.text)
95
+ iframe_list = [iframe.css("::attr(data-vsrc)").get() for iframe in alt_sec.css("iframe")]
96
+ iframe_list = [i for i in iframe_list if i]
97
+
98
+ if not iframe_list:
99
+ return []
100
+
101
+ iframe = self.fix_url(iframe_list[0].split("?img=")[0])
102
+ if not iframe:
103
+ return []
104
+
105
+ results = []
106
+
107
+ # Altyazı kontrolü
108
+ self.httpx.headers.update({"Referer": f"{self.main_url}/"})
109
+ iframe_istek = await self.httpx.get(iframe)
110
+ iframe_text = iframe_istek.text
111
+
112
+ subtitles = []
113
+ sub_match = re.search(r'playerjsSubtitle\s*=\s*"(.+?)"', iframe_text)
114
+ if sub_match:
115
+ sub_section = sub_match[1]
116
+ for sub in re.finditer(r'\[(.*?)](https?://[^\s",]+)', sub_section):
117
+ subtitles.append(Subtitle(name=sub[1], url=self.fix_url(sub[2])))
118
+
119
+ # player.filmizle.in kontrolü
120
+ if "player.filmizle.in" in iframe.lower():
121
+ base_match = re.search(r"https?://([^/]+)", iframe)
122
+ if base_match:
123
+ base_url = base_match[1]
124
+ vid_id = iframe.split("/")[-1]
125
+
126
+ self.httpx.headers.update({"X-Requested-With": "XMLHttpRequest"})
127
+ vid_istek = await self.httpx.post(
128
+ f"https://{base_url}/player/index.php?data={vid_id}&do=getVideo",
129
+ )
130
+ vid_data = vid_istek.json()
131
+
132
+ if vid_data.get("securedLink"):
133
+ results.append({
134
+ "name" : f"{self.name}",
135
+ "url" : vid_data["securedLink"],
136
+ "referer" : iframe,
137
+ "subtitles" : subtitles
138
+ })
139
+ else:
140
+ # Extractor'a yönlendir
141
+ extractor = self.ex_manager.find_extractor(iframe)
142
+ results.append({
143
+ "name" : f"{extractor.name if extractor else self.name}",
144
+ "url" : iframe,
145
+ "referer" : f"{self.main_url}/",
146
+ "subtitles" : subtitles
147
+ })
148
+
149
+ return results
150
+
151
+ async def play(self, **kwargs):
152
+ extract_result = ExtractResult(**kwargs)
153
+ self.media_handler.title = kwargs.get("name")
154
+ if self.name not in self.media_handler.title:
155
+ self.media_handler.title = f"{self.name} | {self.media_handler.title}"
156
+
157
+ self.media_handler.play_media(extract_result)
@@ -0,0 +1,146 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo
4
+ from parsel import Selector
5
+ import re, base64
6
+
7
+ class Sinezy(PluginBase):
8
+ name = "Sinezy"
9
+ language = "tr"
10
+ main_url = "https://sinezy.fit"
11
+ favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
12
+ description = "Yerli ve yabancı film izle! Türkçe Dublaj ve Alt Yazılı Seçenekleriyle full hd film izlemek için En çok tercih edilen adres!"
13
+
14
+ main_page = {
15
+ f"{main_url}/izle/en-yeni-filmler/" : "Yeni Filmler",
16
+ f"{main_url}/izle/en-yi-filmler/" : "En İyi Filmler",
17
+ f"{main_url}/izle/aksiyon-filmleri/" : "Aksiyon ",
18
+ f"{main_url}/izle/animasyon-filmleri/" : "Animasyon",
19
+ f"{main_url}/izle/belgesel-izle/" : "Belgesel",
20
+ f"{main_url}/izle/bilim-kurgu-filmleri/" : "Bilim Kurgu ",
21
+ f"{main_url}/izle/biyografi-filmleri/" : "Biyografi ",
22
+ f"{main_url}/izle/dram-filmleri/" : "Dram",
23
+ f"{main_url}/izle/erotik-film-izle/" : "Erotik ",
24
+ f"{main_url}/izle/fantastik-filmler/" : "Fantastik",
25
+ f"{main_url}/izle/gelecek-filmler/" : "Yakında",
26
+ f"{main_url}/izle/gerilim-filmleri/" : "Gerilim ",
27
+ f"{main_url}/izle/gizem-filmleri/" : "Gizem ",
28
+ f"{main_url}/izle/komedi-filmleri/" : "Komedi ",
29
+ f"{main_url}/izle/korku-filmleri/" : "Korku ",
30
+ f"{main_url}/izle/macera-filmleri/" : "Macera ",
31
+ f"{main_url}/izle/muzikal-izle/" : "Müzikal",
32
+ f"{main_url}/izle/romantik-film/" : "Romantik ",
33
+ f"{main_url}/izle/savas-filmleri/" : "Savaş ",
34
+ f"{main_url}/izle/spor-filmleri/" : "Spor ",
35
+ f"{main_url}/izle/suc-filmleri/" : "Suç ",
36
+ f"{main_url}/izle/tarih-filmleri/" : "Tarih ",
37
+ f"{main_url}/izle/turkce-altyazili-promo/" : "Altyazılı Pro",
38
+ f"{main_url}/izle/yabanci-dizi/" : "Yabancı Dizi",
39
+ f"{main_url}/izle/en-iyi-filmler/" : "En İyi Filmler",
40
+ f"{main_url}/izle/en-yeni-filmler/" : "Yeni Filmler",
41
+ f"{main_url}/izle/yerli-filmler/" : "Yerli Filmler",
42
+ f"{main_url}/izle/yetiskin-film/" : "Yetişkin +18",
43
+ }
44
+
45
+ async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
46
+ full_url = f"{url}page/{page}/"
47
+ resp = await self.httpx.get(full_url)
48
+ sel = Selector(resp.text)
49
+
50
+ results = []
51
+ for item in sel.css("div.container div.content div.movie_box.move_k"):
52
+ title = item.css("a::attr(title)").get()
53
+ href = item.css("a::attr(href)").get()
54
+ poster = item.css("img::attr(data-src)").get()
55
+
56
+ if title and href:
57
+ results.append(MainPageResult(
58
+ category = category,
59
+ title = title,
60
+ url = self.fix_url(href),
61
+ poster = self.fix_url(poster)
62
+ ))
63
+
64
+ return results
65
+
66
+ async def search(self, query: str) -> list[SearchResult]:
67
+ url = f"{self.main_url}/arama/?s={query}"
68
+ resp = await self.httpx.get(url)
69
+ sel = Selector(resp.text)
70
+
71
+ results = []
72
+ for item in sel.css("div.movie_box.move_k"):
73
+ title = item.css("a::attr(title)").get()
74
+ href = item.css("a::attr(href)").get()
75
+ poster = item.css("img::attr(data-src)").get()
76
+
77
+ if title and href:
78
+ results.append(SearchResult(
79
+ title = title,
80
+ url = self.fix_url(href),
81
+ poster = self.fix_url(poster)
82
+ ))
83
+
84
+ return results
85
+
86
+ async def load_item(self, url: str) -> MovieInfo:
87
+ resp = await self.httpx.get(url)
88
+ sel = Selector(resp.text)
89
+
90
+ title = sel.css("div.detail::attr(title)").get()
91
+ poster = sel.css("div.move_k img::attr(data-src)").get()
92
+ description = sel.css("div.desc.yeniscroll p::text").get()
93
+ rating = sel.css("span.info span.imdb::text").get()
94
+
95
+ tags = sel.css("div.detail span a::text").getall()
96
+ actors = sel.css("span.oyn p::text").getall() # Might need splitting logic
97
+
98
+ year = None
99
+ info_text = sel.css("span.info::text").get()
100
+ if info_text:
101
+ year_match = re.search(r'\b(19\d{2}|20\d{2})\b', info_text)
102
+ if year_match:
103
+ year = year_match.group(1)
104
+
105
+ # Bulunamadıysa tüm sayfada ara
106
+ if not year:
107
+ all_text = " ".join(sel.css("::text").getall())
108
+ year_match = re.search(r'\b(19\d{2}|20\d{2})\b', all_text)
109
+ if year_match:
110
+ year = year_match.group(1)
111
+
112
+ return MovieInfo(
113
+ title = title,
114
+ url = url,
115
+ poster = self.fix_url(poster),
116
+ description = description,
117
+ tags = tags,
118
+ rating = rating,
119
+ actors = actors,
120
+ year = year
121
+ )
122
+
123
+ async def load_links(self, url: str) -> list[dict]:
124
+ resp = await self.httpx.get(url)
125
+
126
+ match = re.search(r"ilkpartkod\s*=\s*'([^']+)'", resp.text, re.IGNORECASE)
127
+ if match:
128
+ encoded = match.group(1)
129
+ try:
130
+ decoded = base64.b64decode(encoded).decode('utf-8')
131
+ iframe_match = re.search(r'src="([^"]*)"', decoded)
132
+
133
+ if iframe_match:
134
+ iframe = iframe_match.group(1)
135
+ iframe = self.fix_url(iframe)
136
+
137
+ extractor = self.ex_manager.find_extractor(iframe)
138
+
139
+ return [{
140
+ "url" : iframe,
141
+ "name" : extractor.name if extractor else "Iframe"
142
+ }]
143
+ except Exception:
144
+ pass
145
+
146
+ return []