KekikStream 1.7.2__py3-none-any.whl → 1.7.5__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 (61) hide show
  1. KekikStream/Core/Extractor/ExtractorBase.py +23 -6
  2. KekikStream/Core/Plugin/PluginBase.py +29 -8
  3. KekikStream/Extractors/CloseLoad.py +2 -2
  4. KekikStream/Extractors/ContentX.py +4 -4
  5. KekikStream/Extractors/DzenRu.py +39 -0
  6. KekikStream/Extractors/ExPlay.py +54 -0
  7. KekikStream/Extractors/FirePlayer.py +61 -0
  8. KekikStream/Extractors/HDPlayerSystem.py +42 -0
  9. KekikStream/Extractors/JetTv.py +46 -0
  10. KekikStream/Extractors/MailRu.py +2 -2
  11. KekikStream/Extractors/MixPlayHD.py +2 -2
  12. KekikStream/Extractors/MixTiger.py +61 -0
  13. KekikStream/Extractors/Odnoklassniki.py +2 -2
  14. KekikStream/Extractors/PeaceMakerst.py +4 -4
  15. KekikStream/Extractors/PixelDrain.py +1 -1
  16. KekikStream/Extractors/PlayerFilmIzle.py +62 -0
  17. KekikStream/Extractors/RapidVid.py +2 -2
  18. KekikStream/Extractors/SetPlay.py +58 -0
  19. KekikStream/Extractors/SetPrime.py +46 -0
  20. KekikStream/Extractors/SibNet.py +2 -2
  21. KekikStream/Extractors/Sobreatsesuyp.py +4 -4
  22. KekikStream/Extractors/TRsTX.py +4 -4
  23. KekikStream/Extractors/TauVideo.py +2 -2
  24. KekikStream/Extractors/TurboImgz.py +2 -2
  25. KekikStream/Extractors/TurkeyPlayer.py +34 -0
  26. KekikStream/Extractors/VidHide.py +72 -0
  27. KekikStream/Extractors/VidMoly.py +4 -4
  28. KekikStream/Extractors/VidMoxy.py +2 -2
  29. KekikStream/Extractors/VidPapi.py +90 -0
  30. KekikStream/Extractors/VideoSeyred.py +3 -3
  31. KekikStream/Extractors/YildizKisaFilm.py +42 -0
  32. KekikStream/Plugins/DiziBox.py +15 -15
  33. KekikStream/Plugins/DiziPal.py +11 -11
  34. KekikStream/Plugins/DiziYou.py +4 -4
  35. KekikStream/Plugins/Dizilla.py +10 -6
  36. KekikStream/Plugins/FilmBip.py +145 -0
  37. KekikStream/Plugins/FilmMakinesi.py +3 -3
  38. KekikStream/Plugins/FilmModu.py +6 -6
  39. KekikStream/Plugins/FullHDFilm.py +164 -0
  40. KekikStream/Plugins/FullHDFilmizlesene.py +3 -3
  41. KekikStream/Plugins/HDFilmCehennemi.py +3 -0
  42. KekikStream/Plugins/JetFilmizle.py +16 -9
  43. KekikStream/Plugins/KultFilmler.py +219 -0
  44. KekikStream/Plugins/RecTV.py +6 -6
  45. KekikStream/Plugins/RoketDizi.py +207 -0
  46. KekikStream/Plugins/SelcukFlix.py +216 -0
  47. KekikStream/Plugins/SezonlukDizi.py +11 -8
  48. KekikStream/Plugins/SineWix.py +4 -4
  49. KekikStream/Plugins/Sinefy.py +214 -0
  50. KekikStream/Plugins/SinemaCX.py +9 -9
  51. KekikStream/Plugins/Sinezy.py +99 -0
  52. KekikStream/Plugins/SuperFilmGeldi.py +121 -0
  53. KekikStream/Plugins/UgurFilm.py +6 -6
  54. KekikStream/requirements.txt +2 -2
  55. {kekikstream-1.7.2.dist-info → kekikstream-1.7.5.dist-info}/METADATA +2 -1
  56. kekikstream-1.7.5.dist-info/RECORD +85 -0
  57. kekikstream-1.7.2.dist-info/RECORD +0 -64
  58. {kekikstream-1.7.2.dist-info → kekikstream-1.7.5.dist-info}/WHEEL +0 -0
  59. {kekikstream-1.7.2.dist-info → kekikstream-1.7.5.dist-info}/entry_points.txt +0 -0
  60. {kekikstream-1.7.2.dist-info → kekikstream-1.7.5.dist-info}/licenses/LICENSE +0 -0
  61. {kekikstream-1.7.2.dist-info → kekikstream-1.7.5.dist-info}/top_level.txt +0 -0
@@ -26,7 +26,7 @@ class DiziPal(PluginBase):
26
26
  }
27
27
 
28
28
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
29
- istek = await self.cffi.get(url)
29
+ istek = await self.httpx.get(url)
30
30
  secici = Selector(istek.text)
31
31
 
32
32
  results = []
@@ -67,12 +67,12 @@ class DiziPal(PluginBase):
67
67
  return results
68
68
 
69
69
  async def search(self, query: str) -> list[SearchResult]:
70
- self.cffi.headers.update({
70
+ self.httpx.headers.update({
71
71
  "Accept" : "application/json, text/javascript, */*; q=0.01",
72
72
  "X-Requested-With" : "XMLHttpRequest"
73
73
  })
74
74
 
75
- istek = await self.cffi.post(
75
+ istek = await self.httpx.post(
76
76
  url = f"{self.main_url}/api/search-autocomplete",
77
77
  data = {"query": query}
78
78
  )
@@ -106,12 +106,12 @@ class DiziPal(PluginBase):
106
106
 
107
107
  async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
108
108
  # Reset headers to get HTML response
109
- self.cffi.headers.update({
109
+ self.httpx.headers.update({
110
110
  "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
111
111
  })
112
- self.cffi.headers.pop("X-Requested-With", None)
112
+ self.httpx.headers.pop("X-Requested-With", None)
113
113
 
114
- istek = await self.cffi.get(url)
114
+ istek = await self.httpx.get(url)
115
115
  secici = Selector(text=istek.text, type="html")
116
116
 
117
117
  poster = self.fix_url(secici.css("meta[property='og:image']::attr(content)").get())
@@ -179,12 +179,12 @@ class DiziPal(PluginBase):
179
179
 
180
180
  async def load_links(self, url: str) -> list[dict]:
181
181
  # Reset headers to get HTML response
182
- self.cffi.headers.update({
182
+ self.httpx.headers.update({
183
183
  "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
184
184
  })
185
- self.cffi.headers.pop("X-Requested-With", None)
185
+ self.httpx.headers.pop("X-Requested-With", None)
186
186
 
187
- istek = await self.cffi.get(url)
187
+ istek = await self.httpx.get(url)
188
188
  secici = Selector(istek.text)
189
189
 
190
190
  iframe = secici.css(".series-player-container iframe::attr(src)").get()
@@ -196,8 +196,8 @@ class DiziPal(PluginBase):
196
196
 
197
197
  results = []
198
198
 
199
- self.cffi.headers.update({"Referer": f"{self.main_url}/"})
200
- i_istek = await self.cffi.get(iframe)
199
+ self.httpx.headers.update({"Referer": f"{self.main_url}/"})
200
+ i_istek = await self.httpx.get(iframe)
201
201
  i_text = i_istek.text
202
202
 
203
203
  # m3u link çıkar
@@ -31,7 +31,7 @@ class DiziYou(PluginBase):
31
31
 
32
32
  #@kekik_cache(ttl=60*60)
33
33
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
34
- istek = await self.cffi.get(f"{url.replace('SAYFA', str(page))}")
34
+ istek = await self.httpx.get(f"{url.replace('SAYFA', str(page))}")
35
35
  secici = Selector(istek.text)
36
36
 
37
37
  return [
@@ -46,7 +46,7 @@ class DiziYou(PluginBase):
46
46
 
47
47
  #@kekik_cache(ttl=60*60)
48
48
  async def search(self, query: str) -> list[SearchResult]:
49
- istek = await self.cffi.get(f"{self.main_url}/?s={query}")
49
+ istek = await self.httpx.get(f"{self.main_url}/?s={query}")
50
50
  secici = Selector(istek.text)
51
51
 
52
52
  return [
@@ -60,7 +60,7 @@ class DiziYou(PluginBase):
60
60
 
61
61
  #@kekik_cache(ttl=60*60)
62
62
  async def load_item(self, url: str) -> SeriesInfo:
63
- istek = await self.cffi.get(url)
63
+ istek = await self.httpx.get(url)
64
64
  secici = Selector(istek.text)
65
65
 
66
66
  title = secici.css("h1::text").get().strip()
@@ -109,7 +109,7 @@ class DiziYou(PluginBase):
109
109
 
110
110
  #@kekik_cache(ttl=15*60)
111
111
  async def load_links(self, url: str) -> list[dict]:
112
- istek = await self.cffi.get(url)
112
+ istek = await self.httpx.get(url)
113
113
  secici = Selector(istek.text)
114
114
 
115
115
  item_title = secici.css("div.title h1::text").get()
@@ -26,7 +26,7 @@ class Dizilla(PluginBase):
26
26
 
27
27
  #@kekik_cache(ttl=60*60)
28
28
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
29
- istek = await self.cffi.get(url)
29
+ istek = await self.httpx.get(url)
30
30
  secici = Selector(istek.text)
31
31
 
32
32
  ana_sayfa = []
@@ -51,7 +51,7 @@ class Dizilla(PluginBase):
51
51
  ep_name = ep_name.replace(". Sezon", "x").replace(". Bölüm", "").replace("x ", "x")
52
52
  title = f"{name} - {ep_name}"
53
53
 
54
- ep_req = await self.cffi.get(self.fix_url(veri.css("::attr(href)").get()))
54
+ ep_req = await self.httpx.get(self.fix_url(veri.css("::attr(href)").get()))
55
55
  ep_secici = Selector(ep_req.text)
56
56
  href = self.fix_url(ep_secici.css("nav li:nth-of-type(3) a::attr(href)").get())
57
57
  poster = self.fix_url(ep_secici.css("img.imgt::attr(src)").get())
@@ -90,7 +90,7 @@ class Dizilla(PluginBase):
90
90
 
91
91
  #@kekik_cache(ttl=60*60)
92
92
  async def search(self, query: str) -> list[SearchResult]:
93
- arama_istek = await self.cffi.post(f"{self.main_url}/api/bg/searchcontent?searchterm={query}")
93
+ arama_istek = await self.httpx.post(f"{self.main_url}/api/bg/searchcontent?searchterm={query}")
94
94
  decrypted = await self.decrypt_response(arama_istek.json().get("response"))
95
95
  arama_veri = decrypted.get("result", [])
96
96
 
@@ -116,7 +116,7 @@ class Dizilla(PluginBase):
116
116
 
117
117
  #@kekik_cache(ttl=60*60)
118
118
  async def load_item(self, url: str) -> SeriesInfo:
119
- istek = await self.cffi.get(url)
119
+ istek = await self.httpx.get(url)
120
120
  secici = Selector(istek.text)
121
121
  veri = loads(secici.xpath("//script[@type='application/ld+json']/text()").getall()[-1])
122
122
 
@@ -134,7 +134,11 @@ class Dizilla(PluginBase):
134
134
  bolumler = []
135
135
  sezonlar = veri.get("containsSeason") if isinstance(veri.get("containsSeason"), list) else [veri.get("containsSeason")]
136
136
  for sezon in sezonlar:
137
- for bolum in sezon.get("episode"):
137
+ episodes = sezon.get("episode")
138
+ if isinstance(episodes, dict):
139
+ episodes = [episodes]
140
+
141
+ for bolum in episodes:
138
142
  bolumler.append(Episode(
139
143
  season = sezon.get("seasonNumber"),
140
144
  episode = bolum.get("episodeNumber"),
@@ -156,7 +160,7 @@ class Dizilla(PluginBase):
156
160
 
157
161
  #@kekik_cache(ttl=15*60)
158
162
  async def load_links(self, url: str) -> list[dict]:
159
- istek = await self.cffi.get(url)
163
+ istek = await self.httpx.get(url)
160
164
  secici = Selector(istek.text)
161
165
 
162
166
  next_data = loads(secici.css("script#__NEXT_DATA__::text").get())
@@ -0,0 +1,145 @@
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
+
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 = "Film izleme sitesi."
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[dict]:
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
+ extractor = self.ex_manager.find_extractor(iframe)
139
+ results.append({
140
+ "name" : extractor.name if extractor else "Player",
141
+ "url" : iframe,
142
+ "referer" : f"{self.main_url}/"
143
+ })
144
+
145
+ return results
@@ -53,7 +53,7 @@ class FilmMakinesi(PluginBase):
53
53
 
54
54
  #@kekik_cache(ttl=60*60)
55
55
  async def search(self, query: str) -> list[SearchResult]:
56
- istek = await self.cffi.get(f"{self.main_url}/arama/?s={query}")
56
+ istek = await self.httpx.get(f"{self.main_url}/arama/?s={query}")
57
57
  secici = Selector(istek.text)
58
58
 
59
59
  results = []
@@ -75,7 +75,7 @@ class FilmMakinesi(PluginBase):
75
75
 
76
76
  #@kekik_cache(ttl=60*60)
77
77
  async def load_item(self, url: str) -> MovieInfo:
78
- istek = await self.cffi.get(url)
78
+ istek = await self.httpx.get(url)
79
79
  secici = Selector(istek.text)
80
80
 
81
81
  title = secici.css("h1.title::text").get().strip()
@@ -103,7 +103,7 @@ class FilmMakinesi(PluginBase):
103
103
 
104
104
  #@kekik_cache(ttl=15*60)
105
105
  async def load_links(self, url: str) -> list[dict]:
106
- istek = await self.cffi.get(url)
106
+ istek = await self.httpx.get(url)
107
107
  secici = Selector(istek.text)
108
108
 
109
109
  iframe_src = secici.css("iframe::attr(data-src)").get()
@@ -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()
@@ -88,7 +88,7 @@ class FilmModu(PluginBase):
88
88
  )
89
89
 
90
90
  async def load_links(self, url: str) -> list[dict]:
91
- istek = await self.cffi.get(url)
91
+ istek = await self.httpx.get(url)
92
92
  secici = Selector(istek.text)
93
93
 
94
94
  results = []
@@ -100,7 +100,7 @@ class FilmModu(PluginBase):
100
100
  if alt_name == "Fragman" or not alt_link:
101
101
  continue
102
102
 
103
- alt_istek = await self.cffi.get(alt_link)
103
+ alt_istek = await self.httpx.get(alt_link)
104
104
  alt_text = alt_istek.text
105
105
 
106
106
  vid_id = re.search(r"var videoId = '(.*)'", alt_text)
@@ -109,7 +109,7 @@ class FilmModu(PluginBase):
109
109
  if not vid_id or not vid_type:
110
110
  continue
111
111
 
112
- source_istek = await self.cffi.get(
112
+ source_istek = await self.httpx.get(
113
113
  f"{self.main_url}/get-source?movie_id={vid_id[1]}&type={vid_type[1]}"
114
114
  )
115
115
  source_data = source_istek.json()
@@ -0,0 +1,164 @@
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, base64
6
+
7
+ class FullHDFilm(PluginBase):
8
+ name = "FullHDFilm"
9
+ language = "tr"
10
+ main_url = "https://hdfilm.us"
11
+ favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
12
+ description = "Full HD Film izle, Türkçe Dublaj ve Altyazılı filmler."
13
+
14
+ main_page = {
15
+ f"{main_url}/tur/turkce-altyazili-film-izle" : "Altyazılı Filmler",
16
+ f"{main_url}/tur/netflix-filmleri-izle" : "Netflix",
17
+ f"{main_url}/category/aile-filmleri-izle" : "Aile",
18
+ f"{main_url}/category/aksiyon-filmleri-izle" : "Aksiyon",
19
+ f"{main_url}/category/animasyon-filmleri-izle" : "Animasyon",
20
+ f"{main_url}/category/belgesel-filmleri-izle" : "Belgesel",
21
+ f"{main_url}/category/bilim-kurgu-filmleri-izle" : "Bilim-Kurgu",
22
+ f"{main_url}/category/biyografi-filmleri-izle" : "Biyografi",
23
+ f"{main_url}/category/dram-filmleri-izle" : "Dram",
24
+ f"{main_url}/category/fantastik-filmler-izle" : "Fantastik",
25
+ f"{main_url}/category/gerilim-filmleri-izle" : "Gerilim",
26
+ f"{main_url}/category/gizem-filmleri-izle" : "Gizem",
27
+ f"{main_url}/category/komedi-filmleri-izle" : "Komedi",
28
+ f"{main_url}/category/korku-filmleri-izle" : "Korku",
29
+ f"{main_url}/category/macera-filmleri-izle" : "Macera",
30
+ f"{main_url}/category/romantik-filmler-izle" : "Romantik",
31
+ f"{main_url}/category/savas-filmleri-izle" : "Savaş",
32
+ f"{main_url}/category/suc-filmleri-izle" : "Suç",
33
+ f"{main_url}/tur/yerli-film-izle" : "Yerli Film",
34
+ }
35
+
36
+ async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
37
+ page_url = url if page == 1 else f"{url}/page/{page}"
38
+
39
+ self.httpx.headers.update({
40
+ "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
41
+ "Referer" : f"{self.main_url}/"
42
+ })
43
+
44
+ istek = await self.httpx.get(page_url)
45
+ secici = Selector(istek.text)
46
+
47
+ return [
48
+ MainPageResult(
49
+ category = category,
50
+ title = veri.css("img::attr(alt)").get(),
51
+ url = self.fix_url(veri.css("a::attr(href)").get()),
52
+ poster = self.fix_url(veri.css("img::attr(src)").get()),
53
+ )
54
+ for veri in secici.css("div.movie-poster")
55
+ if veri.css("img::attr(alt)").get()
56
+ ]
57
+
58
+ async def search(self, query: str) -> list[SearchResult]:
59
+ istek = await self.httpx.get(f"{self.main_url}/?s={query}")
60
+ secici = Selector(istek.text)
61
+
62
+ return [
63
+ SearchResult(
64
+ title = veri.css("img::attr(alt)").get(),
65
+ url = self.fix_url(veri.css("a::attr(href)").get()),
66
+ poster = self.fix_url(veri.css("img::attr(src)").get()),
67
+ )
68
+ for veri in secici.css("div.movie-poster")
69
+ if veri.css("img::attr(alt)").get()
70
+ ]
71
+
72
+ async def load_item(self, url: str) -> MovieInfo:
73
+ istek = await self.httpx.get(url)
74
+ secici = Selector(istek.text)
75
+
76
+ title = secici.css("h1::text").get()
77
+ poster = self.fix_url(secici.css("div.poster img::attr(src)").get())
78
+ description = secici.css("div#details div.text::text").get() or \
79
+ secici.css("div#details div::text").get()
80
+
81
+ actors_text = secici.css("div.oyuncular.info::text").get()
82
+ if actors_text:
83
+ actors_text = actors_text.replace("Oyuncular:", "").strip()
84
+ actors = [a.strip() for a in actors_text.split(",")]
85
+ else:
86
+ actors = []
87
+
88
+ year = secici.css("div.yayin-tarihi.info::text").re_first(r"(\d{4})")
89
+ tags = secici.css("div.tur.info a::text").getall()
90
+ rating = secici.css("div.imdb::text").re_first(r"IMDb\s*([\d\.]+)")
91
+
92
+ # Açıklama usually above .others
93
+ description = secici.xpath("//div[contains(@class, 'others')]/preceding-sibling::div[1]//text()").getall()
94
+ description = "".join(description).strip() if description else None
95
+
96
+ return MovieInfo(
97
+ url = url,
98
+ poster = poster,
99
+ title = self.clean_title(title) if title else "",
100
+ description = description,
101
+ tags = tags,
102
+ year = year,
103
+ actors = actors,
104
+ rating = rating.strip() if rating else None,
105
+ )
106
+
107
+ def _get_iframe(self, source_code: str) -> str:
108
+ """Base64 kodlu iframe'i çözümle"""
109
+ match = re.search(r'<script[^>]*>(PCEtLWJhc2xpazp[^<]*)</script>', source_code)
110
+ if not match:
111
+ return ""
112
+
113
+ try:
114
+ decoded_html = base64.b64decode(match[1]).decode("utf-8")
115
+ iframe_match = re.search(r'<iframe[^>]+src=["\']([^"\']+)["\']', decoded_html)
116
+ return self.fix_url(iframe_match[1]) if iframe_match else ""
117
+ except Exception:
118
+ return ""
119
+
120
+ def _extract_subtitle_url(self, source_code: str) -> str | None:
121
+ """playerjsSubtitle değişkeninden .srt URL çıkar"""
122
+ patterns = [
123
+ r'var playerjsSubtitle = "\[Türkçe\](https?://[^\s"]+?\.srt)";',
124
+ r'var playerjsSubtitle = "(https?://[^\s"]+?\.srt)";',
125
+ r'subtitle:\s*"(https?://[^\s"]+?\.srt)"',
126
+ ]
127
+
128
+ for pattern in patterns:
129
+ if match := re.search(pattern, source_code):
130
+ return match[1]
131
+
132
+ return None
133
+
134
+ async def load_links(self, url: str) -> list[dict]:
135
+ self.httpx.headers.update({
136
+ "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
137
+ "Referer" : self.main_url
138
+ })
139
+
140
+ istek = await self.httpx.get(url)
141
+ source_code = istek.text
142
+
143
+ # Ana sayfadan altyazı URL'sini çek
144
+ subtitle_url = self._extract_subtitle_url(source_code)
145
+
146
+ # Iframe'den altyazı URL'sini çek
147
+ iframe_src = self._get_iframe(source_code)
148
+
149
+ if not subtitle_url and iframe_src:
150
+ iframe_istek = await self.httpx.get(iframe_src)
151
+ subtitle_url = self._extract_subtitle_url(iframe_istek.text)
152
+
153
+ results = []
154
+
155
+ if iframe_src:
156
+ extractor = self.ex_manager.find_extractor(iframe_src)
157
+ results.append({
158
+ "name" : extractor.name if extractor else "FullHDFilm Player",
159
+ "url" : iframe_src,
160
+ "referer" : self.main_url,
161
+ "subtitles" : [Subtitle(name="Türkçe", url=subtitle_url)] if subtitle_url else []
162
+ })
163
+
164
+ return results
@@ -57,7 +57,7 @@ class FullHDFilmizlesene(PluginBase):
57
57
 
58
58
  #@kekik_cache(ttl=60*60)
59
59
  async def search(self, query: str) -> list[SearchResult]:
60
- istek = await self.cffi.get(f"{self.main_url}/arama/{query}")
60
+ istek = await self.httpx.get(f"{self.main_url}/arama/{query}")
61
61
  secici = Selector(istek.text)
62
62
 
63
63
  results = []
@@ -79,7 +79,7 @@ class FullHDFilmizlesene(PluginBase):
79
79
 
80
80
  #@kekik_cache(ttl=60*60)
81
81
  async def load_item(self, url: str) -> MovieInfo:
82
- istek = await self.cffi.get(url)
82
+ istek = await self.httpx.get(url)
83
83
  secici = Selector(istek.text)
84
84
 
85
85
  title = secici.xpath("normalize-space(//div[@class='izle-titles'])").get().strip()
@@ -105,7 +105,7 @@ class FullHDFilmizlesene(PluginBase):
105
105
 
106
106
  #@kekik_cache(ttl=15*60)
107
107
  async def load_links(self, url: str) -> list[dict]:
108
- istek = await self.cffi.get(url)
108
+ istek = await self.httpx.get(url)
109
109
  secici = Selector(istek.text)
110
110
 
111
111
  script = secici.xpath("(//script)[1]").get()
@@ -11,6 +11,9 @@ class HDFilmCehennemi(PluginBase):
11
11
  main_url = "https://www.hdfilmcehennemi.ws"
12
12
  favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
13
13
  description = "Türkiye'nin en hızlı hd film izleme sitesi"
14
+
15
+ # Bu site domain değişikliği yapıyor ve potansiyel anti-bot koruması var
16
+ requires_cffi = True
14
17
 
15
18
  main_page = {
16
19
  f"{main_url}" : "Yeni Eklenen Filmler",
@@ -21,7 +21,7 @@ class JetFilmizle(PluginBase):
21
21
 
22
22
  #@kekik_cache(ttl=60*60)
23
23
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
24
- istek = await self.cffi.get(f"{url}{page}", allow_redirects=True)
24
+ istek = await self.httpx.get(f"{url}{page}", allow_redirects=True)
25
25
  secici = Selector(istek.text)
26
26
 
27
27
  return [
@@ -36,7 +36,7 @@ class JetFilmizle(PluginBase):
36
36
 
37
37
  #@kekik_cache(ttl=60*60)
38
38
  async def search(self, query: str) -> list[SearchResult]:
39
- istek = await self.cffi.post(
39
+ istek = await self.httpx.post(
40
40
  url = f"{self.main_url}/filmara.php",
41
41
  data = {"s": query},
42
42
  headers = {"Referer": f"{self.main_url}/"}
@@ -62,14 +62,21 @@ class JetFilmizle(PluginBase):
62
62
 
63
63
  #@kekik_cache(ttl=60*60)
64
64
  async def load_item(self, url: str) -> MovieInfo:
65
- istek = await self.cffi.get(url)
65
+ istek = await self.httpx.get(url)
66
66
  secici = Selector(istek.text)
67
67
 
68
68
  title = self.clean_title(secici.css("div.movie-exp-title::text").get())
69
- poster = secici.css("section.movie-exp img::attr(data-src), section.movie-exp img::attr(src)").get().strip()
70
- description = secici.css("section.movie-exp p.aciklama::text").get().strip()
69
+ poster_raw = secici.css("section.movie-exp img::attr(data-src), section.movie-exp img::attr(src)").get()
70
+ poster = poster_raw.strip() if poster_raw else None
71
+
72
+ desc_raw = secici.css("section.movie-exp p.aciklama::text").get()
73
+ description = desc_raw.strip() if desc_raw else None
74
+
71
75
  tags = secici.css("section.movie-exp div.catss a::text").getall()
72
- rating = secici.css("section.movie-exp div.imdb_puan span::text").get().strip()
76
+
77
+ rating_raw = secici.css("section.movie-exp div.imdb_puan span::text").get()
78
+ rating = rating_raw.strip() if rating_raw else None
79
+
73
80
  year = secici.xpath("//div[@class='yap' and (contains(., 'Vizyon') or contains(., 'Yapım'))]/text()").get()
74
81
  year = year.strip() if year else None
75
82
  actors = secici.css("div[itemprop='actor'] a span::text").getall()
@@ -87,7 +94,7 @@ class JetFilmizle(PluginBase):
87
94
 
88
95
  #@kekik_cache(ttl=15*60)
89
96
  async def load_links(self, url: str) -> list[dict]:
90
- istek = await self.cffi.get(url)
97
+ istek = await self.httpx.get(url)
91
98
  secici = Selector(istek.text)
92
99
 
93
100
  iframes = []
@@ -99,7 +106,7 @@ class JetFilmizle(PluginBase):
99
106
  if not part_href:
100
107
  continue
101
108
 
102
- part_istek = await self.cffi.get(part_href)
109
+ part_istek = await self.httpx.get(part_href)
103
110
  part_secici = Selector(part_istek.text)
104
111
 
105
112
  if iframe := part_secici.css("div#movie iframe::attr(data-src), div#movie iframe::attr(data), div#movie iframe::attr(src)").get():
@@ -112,7 +119,7 @@ class JetFilmizle(PluginBase):
112
119
  processed_iframes = []
113
120
  for iframe in iframes:
114
121
  if "jetv.xyz" in iframe:
115
- jetv_istek = await self.cffi.get(iframe)
122
+ jetv_istek = await self.httpx.get(iframe)
116
123
  jetv_secici = Selector(jetv_istek.text)
117
124
 
118
125
  if jetv_iframe := jetv_secici.css("iframe::attr(src)").get():