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,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, SeriesInfo, Episode
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult
4
4
  from parsel import Selector
5
5
  from json import loads
6
6
  from urllib.parse import urlparse, urlunparse
@@ -12,36 +12,47 @@ class Dizilla(PluginBase):
12
12
  language = "tr"
13
13
  main_url = "https://dizilla40.com"
14
14
  favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
15
- description = "Dizilla tüm yabancı dizileri ücretsiz olarak Türkçe Dublaj ve altyazılı seçenekleri ile 1080P kalite izleyebileceğiniz yeni nesil yabancı dizi izleme siteniz."
15
+ description = "1080p yabancı dizi izle. Türkçe altyazılı veya dublaj seçenekleriyle 1080p çözünürlükte yabancı dizilere anında ulaş. Popüler dizileri kesintisiz izle."
16
16
 
17
17
  main_page = {
18
- f"{main_url}/tum-bolumler" : "Altyazılı Bölümler",
19
- f"{main_url}/dublaj-bolumler" : "Dublaj Bölümler",
20
- f"{main_url}/dizi-turu/aile" : "Aile",
21
- f"{main_url}/dizi-turu/aksiyon" : "Aksiyon",
22
- f"{main_url}/dizi-turu/bilim-kurgu" : "Bilim Kurgu",
23
- f"{main_url}/dizi-turu/romantik" : "Romantik",
24
- f"{main_url}/dizi-turu/komedi" : "Komedi"
18
+ f"{main_url}/tum-bolumler" : "Altyazılı Bölümler",
19
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=15&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Aile",
20
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=9&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Aksiyon",
21
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=17&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Animasyon",
22
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=5&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Bilim Kurgu",
23
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=2&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Dram",
24
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=12&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Fantastik",
25
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=18&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Gerilim",
26
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=3&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Gizem",
27
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=4&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Komedi",
28
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=8&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Korku",
29
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=24&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Macera",
30
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=7&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Romantik",
31
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=26&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Savaş",
32
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=1&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Suç",
33
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=11&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Western",
25
34
  }
26
35
 
27
- #@kekik_cache(ttl=60*60)
28
36
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
29
- istek = await self.cffi.get(url)
30
- secici = Selector(istek.text)
31
-
32
37
  ana_sayfa = []
33
38
 
34
- if "dizi-turu" in url:
39
+ if "api/bg" in url:
40
+ istek = await self.httpx.post(url.replace("SAYFA", str(page)))
41
+ decrypted = await self.decrypt_response(istek.json().get("response"))
42
+ veriler = decrypted.get("result", [])
35
43
  ana_sayfa.extend([
36
44
  MainPageResult(
37
45
  category = category,
38
- title = veri.css("h2::text").get(),
39
- url = self.fix_url(veri.css("::attr(href)").get()),
40
- poster = self.fix_url(veri.css("img::attr(src)").get() or veri.css("img::attr(data-src)").get())
46
+ title = veri.get("original_title"),
47
+ url = self.fix_url(f"{self.main_url}/{veri.get('used_slug')}"),
48
+ poster = self.fix_url(veri.get("object_poster_url")),
41
49
  )
42
- for veri in secici.css("div.grid-cols-3 a")
50
+ for veri in veriler
43
51
  ])
44
52
  else:
53
+ istek = await self.httpx.get(url.replace("SAYFA", str(page)))
54
+ secici = Selector(istek.text)
55
+
45
56
  for veri in secici.css("div.tab-content > div.grid a"):
46
57
  name = veri.css("h2::text").get()
47
58
  ep_name = veri.xpath("normalize-space(//div[contains(@class, 'opacity-80')])").get()
@@ -51,7 +62,7 @@ class Dizilla(PluginBase):
51
62
  ep_name = ep_name.replace(". Sezon", "x").replace(". Bölüm", "").replace("x ", "x")
52
63
  title = f"{name} - {ep_name}"
53
64
 
54
- ep_req = await self.cffi.get(self.fix_url(veri.css("::attr(href)").get()))
65
+ ep_req = await self.httpx.get(self.fix_url(veri.css("::attr(href)").get()))
55
66
  ep_secici = Selector(ep_req.text)
56
67
  href = self.fix_url(ep_secici.css("nav li:nth-of-type(3) a::attr(href)").get())
57
68
  poster = self.fix_url(ep_secici.css("img.imgt::attr(src)").get())
@@ -88,9 +99,8 @@ class Dizilla(PluginBase):
88
99
  # JSON decode
89
100
  return loads(decrypted.decode("utf-8"))
90
101
 
91
- #@kekik_cache(ttl=60*60)
92
102
  async def search(self, query: str) -> list[SearchResult]:
93
- arama_istek = await self.cffi.post(f"{self.main_url}/api/bg/searchcontent?searchterm={query}")
103
+ arama_istek = await self.httpx.post(f"{self.main_url}/api/bg/searchcontent?searchterm={query}")
94
104
  decrypted = await self.decrypt_response(arama_istek.json().get("response"))
95
105
  arama_veri = decrypted.get("result", [])
96
106
 
@@ -103,7 +113,6 @@ class Dizilla(PluginBase):
103
113
  for veri in arama_veri
104
114
  ]
105
115
 
106
- #@kekik_cache(ttl=60*60)
107
116
  async def url_base_degis(self, eski_url:str, yeni_base:str) -> str:
108
117
  parsed_url = urlparse(eski_url)
109
118
  parsed_yeni_base = urlparse(yeni_base)
@@ -114,27 +123,34 @@ class Dizilla(PluginBase):
114
123
 
115
124
  return urlunparse(yeni_url)
116
125
 
117
- #@kekik_cache(ttl=60*60)
118
126
  async def load_item(self, url: str) -> SeriesInfo:
119
- istek = await self.cffi.get(url)
127
+ istek = await self.httpx.get(url)
120
128
  secici = Selector(istek.text)
121
129
  veri = loads(secici.xpath("//script[@type='application/ld+json']/text()").getall()[-1])
122
130
 
123
- title = veri.get("name")
131
+ title = veri.get("name")
124
132
  if alt_title := veri.get("alternateName"):
125
133
  title += f" - ({alt_title})"
126
134
 
127
135
  poster = self.fix_url(veri.get("image"))
128
136
  description = veri.get("description")
129
137
  year = veri.get("datePublished").split("-")[0]
130
- tags = []
131
- rating = veri.get("aggregateRating", {}).get("ratingValue")
132
- actors = [actor.get("name") for actor in veri.get("actor", []) if actor.get("name")]
138
+
139
+ # Tags extraction from page content (h3 tag)
140
+ tags_raw = secici.css("div.poster.poster h3::text").get()
141
+ tags = [t.strip() for t in tags_raw.split(",")] if tags_raw else []
142
+
143
+ rating = veri.get("aggregateRating", {}).get("ratingValue")
144
+ actors = [actor.get("name") for actor in veri.get("actor", []) if actor.get("name")]
133
145
 
134
146
  bolumler = []
135
147
  sezonlar = veri.get("containsSeason") if isinstance(veri.get("containsSeason"), list) else [veri.get("containsSeason")]
136
148
  for sezon in sezonlar:
137
- for bolum in sezon.get("episode"):
149
+ episodes = sezon.get("episode")
150
+ if isinstance(episodes, dict):
151
+ episodes = [episodes]
152
+
153
+ for bolum in episodes:
138
154
  bolumler.append(Episode(
139
155
  season = sezon.get("seasonNumber"),
140
156
  episode = bolum.get("episodeNumber"),
@@ -154,9 +170,8 @@ class Dizilla(PluginBase):
154
170
  actors = actors
155
171
  )
156
172
 
157
- #@kekik_cache(ttl=15*60)
158
- async def load_links(self, url: str) -> list[dict]:
159
- istek = await self.cffi.get(url)
173
+ async def load_links(self, url: str) -> list[ExtractResult]:
174
+ istek = await self.httpx.get(url)
160
175
  secici = Selector(istek.text)
161
176
 
162
177
  next_data = loads(secici.css("script#__NEXT_DATA__::text").get())
@@ -164,17 +179,22 @@ class Dizilla(PluginBase):
164
179
  decrypted = await self.decrypt_response(secure_data)
165
180
  results = decrypted.get("RelatedResults", {}).get("getEpisodeSources", {}).get("result", [])
166
181
 
167
- links = []
168
- for result in results:
169
- iframe_src = Selector(result.get("source_content")).css("iframe::attr(src)").get()
170
- iframe_url = self.fix_url(iframe_src)
171
- if not iframe_url:
172
- continue
173
-
174
- extractor = self.ex_manager.find_extractor(iframe_url)
175
- links.append({
176
- "url" : iframe_url,
177
- "name" : f"{extractor.name if extractor else 'Main Player'} | {result.get('language_name')}",
178
- })
179
-
180
- return links
182
+ if not results:
183
+ return []
184
+
185
+ # Get first source (matching Kotlin)
186
+ first_result = results[0]
187
+ source_content = first_result.get("source_content", "")
188
+
189
+ # Clean the source_content string (matching Kotlin: .replace("\"", "").replace("\\", ""))
190
+ cleaned_source = source_content.replace('"', '').replace('\\', '')
191
+
192
+ # Parse cleaned HTML
193
+ iframe_src = Selector(cleaned_source).css("iframe::attr(src)").get()
194
+ iframe_url = self.fix_url(iframe_src)
195
+
196
+ if not iframe_url:
197
+ return []
198
+
199
+ data = await self.extract(iframe_url, prefix=first_result.get('language_name', 'Unknown'))
200
+ return [data] if data else []
@@ -0,0 +1,142 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult
4
+ from parsel import Selector
5
+
6
+ class FilmBip(PluginBase):
7
+ name = "FilmBip"
8
+ language = "tr"
9
+ main_url = "https://filmbip.com"
10
+ favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
11
+ description = "FilmBip adlı film sitemizde Full HD film izle. Yerli ve yabancı filmleri Türkçe dublaj veya altyazılı şekilde 1080p yüksek kalite film izle"
12
+
13
+ main_page = {
14
+ f"{main_url}/filmler/SAYFA" : "Yeni Filmler",
15
+ f"{main_url}/film/tur/aile/SAYFA" : "Aile",
16
+ f"{main_url}/film/tur/aksiyon/SAYFA" : "Aksiyon",
17
+ f"{main_url}/film/tur/belgesel/SAYFA" : "Belgesel",
18
+ f"{main_url}/film/tur/bilim-kurgu/SAYFA" : "Bilim Kurgu",
19
+ f"{main_url}/film/tur/dram/SAYFA" : "Dram",
20
+ f"{main_url}/film/tur/fantastik/SAYFA" : "Fantastik",
21
+ f"{main_url}/film/tur/gerilim/SAYFA" : "Gerilim",
22
+ f"{main_url}/film/tur/gizem/SAYFA" : "Gizem",
23
+ f"{main_url}/film/tur/komedi/SAYFA" : "Komedi",
24
+ f"{main_url}/film/tur/korku/SAYFA" : "Korku",
25
+ f"{main_url}/film/tur/macera/SAYFA" : "Macera",
26
+ f"{main_url}/film/tur/muzik/SAYFA" : "Müzik",
27
+ f"{main_url}/film/tur/romantik/SAYFA" : "Romantik",
28
+ f"{main_url}/film/tur/savas/SAYFA" : "Savaş",
29
+ f"{main_url}/film/tur/suc/SAYFA" : "Suç",
30
+ f"{main_url}/film/tur/tarih/SAYFA" : "Tarih",
31
+ f"{main_url}/film/tur/vahsi-bati/SAYFA" : "Western",
32
+ }
33
+
34
+ async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
35
+ page_url = url.replace("SAYFA", "") if page == 1 else url.replace("SAYFA", str(page))
36
+ page_url = page_url.rstrip("/")
37
+
38
+ istek = await self.httpx.get(page_url)
39
+ secici = Selector(istek.text)
40
+
41
+ results = []
42
+ for veri in secici.css("div.poster-long"):
43
+ img = veri.css("a.block img.lazy")
44
+ title = img.css("::attr(alt)").get()
45
+ href = self.fix_url(veri.css("a.block::attr(href)").get())
46
+ poster = self.fix_url(img.css("::attr(data-src)").get() or img.css("::attr(src)").get())
47
+
48
+ if title and href:
49
+ results.append(MainPageResult(
50
+ category = category,
51
+ title = title,
52
+ url = href,
53
+ poster = poster,
54
+ ))
55
+
56
+ return results
57
+
58
+ async def search(self, query: str) -> list[SearchResult]:
59
+ istek = await self.httpx.post(
60
+ url = f"{self.main_url}/search",
61
+ headers = {
62
+ "Accept" : "application/json, text/javascript, */*; q=0.01",
63
+ "X-Requested-With" : "XMLHttpRequest",
64
+ "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
65
+ "Origin" : self.main_url,
66
+ "Referer" : f"{self.main_url}/"
67
+ },
68
+ data = {"query": query}
69
+ )
70
+
71
+ try:
72
+ json_data = istek.json()
73
+ if not json_data.get("success"):
74
+ return []
75
+
76
+ html_content = json_data.get("theme", "")
77
+ except Exception:
78
+ return []
79
+
80
+ secici = Selector(text=html_content)
81
+
82
+ results = []
83
+ for veri in secici.css("li"):
84
+ title = veri.css("a.block.truncate::text").get()
85
+ href = self.fix_url(veri.css("a::attr(href)").get())
86
+ poster = self.fix_url(veri.css("img.lazy::attr(data-src)").get())
87
+
88
+ if title and href:
89
+ results.append(SearchResult(
90
+ title = title.strip(),
91
+ url = href,
92
+ poster = poster,
93
+ ))
94
+
95
+ return results
96
+
97
+ async def load_item(self, url: str) -> MovieInfo:
98
+ istek = await self.httpx.get(url)
99
+ secici = Selector(istek.text)
100
+
101
+ title = secici.css("div.page-title h1::text").get()
102
+ poster = self.fix_url(secici.css("meta[property='og:image']::attr(content)").get())
103
+ trailer = secici.css("div.series-profile-trailer::attr(data-yt)").get()
104
+ description = secici.css("div.series-profile-infos-in.article p::text").get() or \
105
+ secici.css("div.series-profile-summary p::text").get()
106
+
107
+ tags = secici.css("div.series-profile-type.tv-show-profile-type a::text").getall()
108
+
109
+ # XPath ile yıl, süre ve puan
110
+ year = secici.xpath("//li[span[contains(text(), 'Yapım yılı')]]/p/text()").re_first(r"(\d{4})")
111
+ duration = secici.xpath("//li[span[contains(text(), 'Süre')]]/p/text()").re_first(r"(\d+)")
112
+ rating = secici.xpath("//li[span[contains(text(), 'IMDB Puanı')]]/p/span/text()").get()
113
+
114
+ actors = secici.css("div.series-profile-cast ul li a img::attr(alt)").getall()
115
+
116
+ return MovieInfo(
117
+ url = url,
118
+ poster = poster,
119
+ title = self.clean_title(title) if title else "",
120
+ description = description.strip() if description else None,
121
+ tags = tags,
122
+ year = year,
123
+ rating = rating,
124
+ duration = int(duration) if duration else None,
125
+ actors = actors,
126
+ )
127
+
128
+ async def load_links(self, url: str) -> list[ExtractResult]:
129
+ istek = await self.httpx.get(url)
130
+ secici = Selector(istek.text)
131
+
132
+ results = []
133
+
134
+ for player in secici.css("div#tv-spoox2"):
135
+ iframe = self.fix_url(player.css("iframe::attr(src)").get())
136
+
137
+ if iframe:
138
+ data = await self.extract(iframe)
139
+ if data:
140
+ results.append(data)
141
+
142
+ return results
@@ -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
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult
4
4
  from parsel import Selector
5
5
 
6
6
  class FilmMakinesi(PluginBase):
@@ -8,7 +8,7 @@ class FilmMakinesi(PluginBase):
8
8
  language = "tr"
9
9
  main_url = "https://filmmakinesi.to"
10
10
  favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
11
- description = "Film Makinesi, en yeni ve en güncel filmleri sitemizde full HD kalite farkı ile izleyebilirsiniz. HD film izle denildiğinde akla gelen en kaliteli film izleme sitesi."
11
+ description = "Film Makinesi ile en yeni ve güncel filmleri Full HD kalite farkı ile izleyebilirsiniz. Film izle denildiğinde akla gelen en kaliteli film sitesi."
12
12
 
13
13
  main_page = {
14
14
  f"{main_url}/filmler-1/" : "Son Filmler",
@@ -34,7 +34,6 @@ class FilmMakinesi(PluginBase):
34
34
  f"{main_url}/tur/western-fm1/film/" : "Western"
35
35
  }
36
36
 
37
- #@kekik_cache(ttl=60*60)
38
37
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
39
38
  istek = self.cloudscraper.get(f"{url}{'' if page == 1 else f'page/{page}/'}")
40
39
  secici = Selector(istek.text)
@@ -51,9 +50,8 @@ class FilmMakinesi(PluginBase):
51
50
  for veri in veriler
52
51
  ]
53
52
 
54
- #@kekik_cache(ttl=60*60)
55
53
  async def search(self, query: str) -> list[SearchResult]:
56
- istek = await self.cffi.get(f"{self.main_url}/arama/?s={query}")
54
+ istek = await self.httpx.get(f"{self.main_url}/arama/?s={query}")
57
55
  secici = Selector(istek.text)
58
56
 
59
57
  results = []
@@ -73,51 +71,61 @@ class FilmMakinesi(PluginBase):
73
71
 
74
72
  return results
75
73
 
76
- #@kekik_cache(ttl=60*60)
77
74
  async def load_item(self, url: str) -> MovieInfo:
78
- istek = await self.cffi.get(url)
75
+ istek = await self.httpx.get(url)
79
76
  secici = Selector(istek.text)
80
77
 
81
- title = secici.css("h1.title::text").get().strip()
82
- poster = secici.css("img.cover-img::attr(src)").get().strip()
83
- description = secici.css("div.info-description p::text").get().strip()
78
+ title = secici.css("h1.title::text").get()
79
+ title = title.strip() if title else ""
80
+ poster = secici.css("img.cover-img::attr(src)").get()
81
+ poster = poster.strip() if poster else ""
82
+ description = secici.css("div.info-description p::text").get()
83
+ description = description.strip() if description else ""
84
84
  rating = secici.css("div.score::text").get()
85
85
  if rating:
86
86
  rating = rating.strip().split()[0]
87
- year = secici.css("span.date a::text").get().strip()
87
+ year = secici.css("span.date a::text").get()
88
+ year = year.strip() if year else ""
88
89
  actors = secici.css("div.cast-name::text").getall()
90
+ tags = secici.css("div.genre a::text").getall()
89
91
  duration = secici.css("div.time::text").get()
90
92
  if duration:
91
- duration = duration.split()[1].strip()
93
+ duration = duration.split()[1].strip() if len(duration.split()) > 1 else ""
92
94
 
93
95
  return MovieInfo(
94
96
  url = url,
95
97
  poster = self.fix_url(poster),
96
98
  title = self.clean_title(title),
97
99
  description = description,
100
+ tags = tags,
98
101
  rating = rating,
99
102
  year = year,
100
103
  actors = actors,
101
104
  duration = duration
102
105
  )
103
106
 
104
- #@kekik_cache(ttl=15*60)
105
- async def load_links(self, url: str) -> list[dict]:
106
- istek = await self.cffi.get(url)
107
+ async def load_links(self, url: str) -> list[ExtractResult]:
108
+ istek = await self.httpx.get(url)
107
109
  secici = Selector(istek.text)
108
110
 
109
- iframe_src = secici.css("iframe::attr(data-src)").get()
111
+ response = []
110
112
 
111
- all_links = [iframe_src] if iframe_src else []
113
+ # Video parts linklerini ve etiketlerini al
112
114
  for link in secici.css("div.video-parts a[data-video_url]"):
113
- all_links.append(link.attrib.get("data-video_url"))
114
-
115
- response = []
116
- for idx, link in enumerate(all_links):
117
- extractor = self.ex_manager.find_extractor(link)
118
- response.append({
119
- "url" : link,
120
- "name" : f"{extractor.name if extractor else f'Player {idx + 1}'}",
121
- })
122
-
123
- return response
115
+ video_url = link.attrib.get("data-video_url")
116
+ label = link.css("::text").get() or ""
117
+ label = label.strip()
118
+
119
+ data = await self.extract(video_url, prefix=label.split()[0] if label else None)
120
+ if data:
121
+ response.append(data)
122
+
123
+ # Eğer video-parts yoksa iframe kullan
124
+ if not response:
125
+ iframe_src = secici.css("iframe::attr(data-src)").get()
126
+ if iframe_src:
127
+ data = await self.extract(iframe_src)
128
+ if data:
129
+ response.append(data)
130
+
131
+ return response
@@ -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 PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult, Subtitle
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, Subtitle, ExtractResult
4
4
  from parsel import Selector
5
5
  import re
6
6
 
@@ -9,7 +9,7 @@ class FilmModu(PluginBase):
9
9
  language = "tr"
10
10
  main_url = "https://www.filmmodu.ws"
11
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."
12
+ description = "Film modun geldiyse yüksek kalitede yeni filmleri izle, 1080p izleyebileceğiniz reklamsız tek film sitesi."
13
13
 
14
14
  main_page = {
15
15
  f"{main_url}/hd-film-kategori/4k-film-izle?page=SAYFA" : "4K",
@@ -41,7 +41,7 @@ class FilmModu(PluginBase):
41
41
  }
42
42
 
43
43
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
44
- istek = await self.cffi.get(url.replace("SAYFA", str(page)))
44
+ istek = await self.httpx.get(url.replace("SAYFA", str(page)))
45
45
  secici = Selector(istek.text)
46
46
 
47
47
  return [
@@ -56,7 +56,7 @@ class FilmModu(PluginBase):
56
56
  ]
57
57
 
58
58
  async def search(self, query: str) -> list[SearchResult]:
59
- istek = await self.cffi.get(f"{self.main_url}/film-ara?term={query}")
59
+ istek = await self.httpx.get(f"{self.main_url}/film-ara?term={query}")
60
60
  secici = Selector(istek.text)
61
61
 
62
62
  return [
@@ -70,7 +70,7 @@ class FilmModu(PluginBase):
70
70
  ]
71
71
 
72
72
  async def load_item(self, url: str) -> MovieInfo:
73
- istek = await self.cffi.get(url)
73
+ istek = await self.httpx.get(url)
74
74
  secici = Selector(istek.text)
75
75
 
76
76
  org_title = secici.css("div.titles h1::text").get()
@@ -87,20 +87,24 @@ class FilmModu(PluginBase):
87
87
  actors = [a.css("span::text").get() for a in secici.css("a[itemprop='actor']")],
88
88
  )
89
89
 
90
- async def load_links(self, url: str) -> list[dict]:
91
- istek = await self.cffi.get(url)
90
+ async def load_links(self, url: str) -> list[ExtractResult]:
91
+ istek = await self.httpx.get(url)
92
92
  secici = Selector(istek.text)
93
93
 
94
+ alternates = secici.css("div.alternates a")
95
+ if not alternates:
96
+ return [] # No alternates available
97
+
94
98
  results = []
95
99
 
96
- for alternatif in secici.css("div.alternates a"):
100
+ for alternatif in alternates:
97
101
  alt_link = self.fix_url(alternatif.css("::attr(href)").get())
98
102
  alt_name = alternatif.css("::text").get()
99
103
 
100
104
  if alt_name == "Fragman" or not alt_link:
101
105
  continue
102
106
 
103
- alt_istek = await self.cffi.get(alt_link)
107
+ alt_istek = await self.httpx.get(alt_link)
104
108
  alt_text = alt_istek.text
105
109
 
106
110
  vid_id = re.search(r"var videoId = '(.*)'", alt_text)
@@ -109,7 +113,7 @@ class FilmModu(PluginBase):
109
113
  if not vid_id or not vid_type:
110
114
  continue
111
115
 
112
- source_istek = await self.cffi.get(
116
+ source_istek = await self.httpx.get(
113
117
  f"{self.main_url}/get-source?movie_id={vid_id[1]}&type={vid_type[1]}"
114
118
  )
115
119
  source_data = source_istek.json()
@@ -120,19 +124,11 @@ class FilmModu(PluginBase):
120
124
  subtitle_url = None
121
125
 
122
126
  for source in source_data.get("sources", []):
123
- results.append({
124
- "name" : f"{self.name} | {alt_name} | {source.get('label', 'Bilinmiyor')}",
125
- "url" : self.fix_url(source["src"]),
126
- "referer" : f"{self.main_url}/",
127
- "subtitles" : [Subtitle(name="Türkçe", url=subtitle_url)] if subtitle_url else []
128
- })
127
+ results.append(ExtractResult(
128
+ name = f"{self.name} | {alt_name} | {source.get('label', 'Bilinmiyor')}",
129
+ url = self.fix_url(source["src"]),
130
+ referer = f"{self.main_url}/",
131
+ subtitles = [Subtitle(name="Türkçe", url=subtitle_url)] if subtitle_url else []
132
+ ))
129
133
 
130
134
  return results
131
-
132
- async def play(self, name: str, url: str, referer: str, subtitles: list[Subtitle]):
133
- extract_result = ExtractResult(name=name, url=url, referer=referer, subtitles=subtitles)
134
- self.media_handler.title = name
135
- if self.name not in self.media_handler.title:
136
- self.media_handler.title = f"{self.name} | {self.media_handler.title}"
137
-
138
- self.media_handler.play_media(extract_result)