KekikStream 2.2.3__py3-none-any.whl → 2.2.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 (34) hide show
  1. KekikStream/Extractors/CloseLoad.py +7 -8
  2. KekikStream/Extractors/Filemoon.py +7 -6
  3. KekikStream/Extractors/MolyStream.py +6 -5
  4. KekikStream/Extractors/VidHide.py +0 -1
  5. KekikStream/Extractors/VidMoly.py +17 -9
  6. KekikStream/Plugins/BelgeselX.py +39 -20
  7. KekikStream/Plugins/DiziBox.py +115 -59
  8. KekikStream/Plugins/DiziPal.py +87 -40
  9. KekikStream/Plugins/DiziYou.py +105 -64
  10. KekikStream/Plugins/Dizilla.py +57 -28
  11. KekikStream/Plugins/FilmBip.py +60 -31
  12. KekikStream/Plugins/FilmMakinesi.py +75 -51
  13. KekikStream/Plugins/FilmModu.py +73 -36
  14. KekikStream/Plugins/FullHDFilm.py +82 -48
  15. KekikStream/Plugins/FullHDFilmizlesene.py +94 -39
  16. KekikStream/Plugins/HDFilmCehennemi.py +78 -53
  17. KekikStream/Plugins/JetFilmizle.py +78 -50
  18. KekikStream/Plugins/KultFilmler.py +64 -34
  19. KekikStream/Plugins/RoketDizi.py +43 -26
  20. KekikStream/Plugins/SelcukFlix.py +27 -14
  21. KekikStream/Plugins/SetFilmIzle.py +69 -43
  22. KekikStream/Plugins/SezonlukDizi.py +102 -46
  23. KekikStream/Plugins/Sinefy.py +130 -101
  24. KekikStream/Plugins/SinemaCX.py +82 -37
  25. KekikStream/Plugins/Sinezy.py +61 -47
  26. KekikStream/Plugins/SuperFilmGeldi.py +72 -36
  27. KekikStream/Plugins/UgurFilm.py +72 -34
  28. KekikStream/requirements.txt +1 -1
  29. {kekikstream-2.2.3.dist-info → kekikstream-2.2.5.dist-info}/METADATA +2 -2
  30. {kekikstream-2.2.3.dist-info → kekikstream-2.2.5.dist-info}/RECORD +34 -34
  31. {kekikstream-2.2.3.dist-info → kekikstream-2.2.5.dist-info}/WHEEL +0 -0
  32. {kekikstream-2.2.3.dist-info → kekikstream-2.2.5.dist-info}/entry_points.txt +0 -0
  33. {kekikstream-2.2.3.dist-info → kekikstream-2.2.5.dist-info}/licenses/LICENSE +0 -0
  34. {kekikstream-2.2.3.dist-info → kekikstream-2.2.5.dist-info}/top_level.txt +0 -0
@@ -1,8 +1,8 @@
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
4
- from parsel import Selector
5
- from Kekik.Sifreleme import StringCodec
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult
4
+ from selectolax.parser import HTMLParser
5
+ from Kekik.Sifreleme import StringCodec
6
6
  import json, re
7
7
 
8
8
  class FullHDFilmizlesene(PluginBase):
@@ -42,55 +42,102 @@ class FullHDFilmizlesene(PluginBase):
42
42
 
43
43
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
44
44
  istek = self.cloudscraper.get(f"{url}{page}")
45
- secici = Selector(istek.text)
46
-
47
- return [
48
- MainPageResult(
49
- category = category,
50
- title = veri.css("span.film-title::text").get(),
51
- url = self.fix_url(veri.css("a::attr(href)").get()),
52
- poster = self.fix_url(veri.css("img::attr(data-src)").get()),
53
- )
54
- for veri in secici.css("li.film")
55
- ]
45
+ secici = HTMLParser(istek.text)
46
+
47
+ results = []
48
+ for veri in secici.css("li.film"):
49
+ title_el = veri.css_first("span.film-title")
50
+ link_el = veri.css_first("a")
51
+ img_el = veri.css_first("img")
52
+
53
+ title = title_el.text(strip=True) if title_el else None
54
+ href = link_el.attrs.get("href") if link_el else None
55
+ poster = img_el.attrs.get("data-src") if img_el else None
56
+
57
+ if title and href:
58
+ results.append(MainPageResult(
59
+ category = category,
60
+ title = title,
61
+ url = self.fix_url(href),
62
+ poster = self.fix_url(poster) if poster else None,
63
+ ))
64
+
65
+ return results
56
66
 
57
67
  async def search(self, query: str) -> list[SearchResult]:
58
68
  istek = await self.httpx.get(f"{self.main_url}/arama/{query}")
59
- secici = Selector(istek.text)
69
+ secici = HTMLParser(istek.text)
60
70
 
61
71
  results = []
62
72
  for film in secici.css("li.film"):
63
- title = film.css("span.film-title::text").get()
64
- href = film.css("a::attr(href)").get()
65
- poster = film.css("img::attr(data-src)").get()
73
+ title_el = film.css_first("span.film-title")
74
+ link_el = film.css_first("a")
75
+ img_el = film.css_first("img")
76
+
77
+ title = title_el.text(strip=True) if title_el else None
78
+ href = link_el.attrs.get("href") if link_el else None
79
+ poster = img_el.attrs.get("data-src") if img_el else None
66
80
 
67
81
  if title and href:
68
- results.append(
69
- SearchResult(
70
- title = title.strip(),
71
- url = self.fix_url(href.strip()),
72
- poster = self.fix_url(poster.strip()) if poster else None,
73
- )
74
- )
82
+ results.append(SearchResult(
83
+ title = title,
84
+ url = self.fix_url(href),
85
+ poster = self.fix_url(poster) if poster else None,
86
+ ))
75
87
 
76
88
  return results
77
89
 
78
90
  async def load_item(self, url: str) -> MovieInfo:
79
91
  istek = await self.httpx.get(url)
80
- secici = Selector(istek.text)
81
-
82
- title = secici.xpath("normalize-space(//div[@class='izle-titles'])").get().strip()
83
- poster = secici.css("div img::attr(data-src)").get().strip()
84
- description = secici.css("div.ozet-ic p::text").get().strip()
85
- tags = secici.css("a[rel='category tag']::text").getall()
86
- rating = secici.xpath("normalize-space(//div[@class='puanx-puan'])").get().split()[-1]
87
- year = secici.css("div.dd a.category::text").get().strip().split()[0]
88
- actors = secici.css("div.film-info ul li:nth-child(2) a > span::text").getall()
89
- duration = secici.css("span.sure::text").get("0 Dakika").split()[0]
92
+ secici = HTMLParser(istek.text)
93
+ html_text = istek.text
94
+
95
+ # Title: normalize-space yerine doğrudan class ile
96
+ title_el = secici.css_first("div.izle-titles")
97
+ title = title_el.text(strip=True) if title_el else ""
98
+
99
+ img_el = secici.css_first("div img[data-src]")
100
+ poster = img_el.attrs.get("data-src", "").strip() if img_el else ""
101
+
102
+ desc_el = secici.css_first("div.ozet-ic p")
103
+ description = desc_el.text(strip=True) if desc_el else ""
104
+
105
+ tags = [a.text(strip=True) for a in secici.css("a[rel='category tag']") if a.text(strip=True)]
106
+
107
+ # Rating: normalize-space yerine doğrudan class ile ve son kelimeyi al
108
+ rating_el = secici.css_first("div.puanx-puan")
109
+ rating = None
110
+ if rating_el:
111
+ rating_text = rating_el.text(strip=True)
112
+ if rating_text:
113
+ parts = rating_text.split()
114
+ rating = parts[-1] if parts else None
115
+
116
+ # Year: ilk yıl formatında değer
117
+ year_el = secici.css_first("div.dd a.category")
118
+ year = None
119
+ if year_el:
120
+ year_text = year_el.text(strip=True)
121
+ if year_text:
122
+ parts = year_text.split()
123
+ year = parts[0] if parts else None
124
+
125
+ # Actors: nth-child yerine tüm li'leri alıp 2. index
126
+ lis = secici.css("div.film-info ul li")
127
+ actors = []
128
+ if len(lis) >= 2:
129
+ actors = [a.text(strip=True) for a in lis[1].css("a > span") if a.text(strip=True)]
130
+
131
+ duration_el = secici.css_first("span.sure")
132
+ duration = "0"
133
+ if duration_el:
134
+ duration_text = duration_el.text(strip=True)
135
+ duration_parts = duration_text.split()
136
+ duration = duration_parts[0] if duration_parts else "0"
90
137
 
91
138
  return MovieInfo(
92
139
  url = url,
93
- poster = self.fix_url(poster),
140
+ poster = self.fix_url(poster) if poster else None,
94
141
  title = title,
95
142
  description = description,
96
143
  tags = tags,
@@ -102,10 +149,18 @@ class FullHDFilmizlesene(PluginBase):
102
149
 
103
150
  async def load_links(self, url: str) -> list[ExtractResult]:
104
151
  istek = await self.httpx.get(url)
105
- secici = Selector(istek.text)
152
+ secici = HTMLParser(istek.text)
153
+ html_text = istek.text
154
+
155
+ # İlk script'i al (xpath (//script)[1] yerine)
156
+ scripts = secici.css("script")
157
+ script_content = scripts[0].text() if scripts else ""
158
+
159
+ scx_match = re.search(r"scx = (.*?);", script_content)
160
+ if not scx_match:
161
+ return []
106
162
 
107
- script = secici.xpath("(//script)[1]").get()
108
- scx_data = json.loads(re.findall(r"scx = (.*?);", script)[0])
163
+ scx_data = json.loads(scx_match.group(1))
109
164
  scx_keys = list(scx_data.keys())
110
165
 
111
166
  link_list = []
@@ -1,8 +1,8 @@
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, SeriesInfo, Episode, Subtitle, ExtractResult
4
- from parsel import Selector
5
- from Kekik.Sifreleme import Packer, StreamDecoder
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, Subtitle, ExtractResult
4
+ from selectolax.parser import HTMLParser
5
+ from Kekik.Sifreleme import Packer, StreamDecoder
6
6
  import random, string, re
7
7
 
8
8
  class HDFilmCehennemi(PluginBase):
@@ -31,17 +31,26 @@ class HDFilmCehennemi(PluginBase):
31
31
 
32
32
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
33
33
  istek = await self.httpx.get(f"{url}", follow_redirects=True)
34
- secici = Selector(istek.text)
35
-
36
- return [
37
- MainPageResult(
38
- category = category,
39
- title = veri.css("strong.poster-title::text").get(),
40
- url = self.fix_url(veri.css("::attr(href)").get()),
41
- poster = self.fix_url(veri.css("img::attr(data-src)").get()),
42
- )
43
- for veri in secici.css("div.section-content a.poster")
44
- ]
34
+ secici = HTMLParser(istek.text)
35
+
36
+ results = []
37
+ for veri in secici.css("div.section-content a.poster"):
38
+ title_el = veri.css_first("strong.poster-title")
39
+ img_el = veri.css_first("img")
40
+
41
+ title = title_el.text(strip=True) if title_el else None
42
+ href = veri.attrs.get("href")
43
+ poster = img_el.attrs.get("data-src") if img_el else None
44
+
45
+ if title and href:
46
+ results.append(MainPageResult(
47
+ category = category,
48
+ title = title,
49
+ url = self.fix_url(href),
50
+ poster = self.fix_url(poster) if poster else None,
51
+ ))
52
+
53
+ return results
45
54
 
46
55
  async def search(self, query: str) -> list[SearchResult]:
47
56
  istek = await self.httpx.get(
@@ -54,57 +63,69 @@ class HDFilmCehennemi(PluginBase):
54
63
  )
55
64
 
56
65
  results = []
57
- for veri in istek.json().get("results"):
58
- secici = Selector(veri)
59
- title = secici.css("h4.title::text").get()
60
- href = secici.css("a::attr(href)").get()
61
- poster = secici.css("img::attr(data-src)").get() or secici.css("img::attr(src)").get()
66
+ for veri in istek.json().get("results", []):
67
+ secici = HTMLParser(veri)
68
+ title_el = secici.css_first("h4.title")
69
+ link_el = secici.css_first("a")
70
+ img_el = secici.css_first("img")
71
+
72
+ title = title_el.text(strip=True) if title_el else None
73
+ href = link_el.attrs.get("href") if link_el else None
74
+ poster = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
62
75
 
63
76
  if title and href:
64
- results.append(
65
- SearchResult(
66
- title = title.strip(),
67
- url = self.fix_url(href.strip()),
68
- poster = self.fix_url(poster.strip()) if poster else None,
69
- )
70
- )
77
+ results.append(SearchResult(
78
+ title = title,
79
+ url = self.fix_url(href),
80
+ poster = self.fix_url(poster) if poster else None,
81
+ ))
71
82
 
72
83
  return results
73
84
 
74
85
  async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
75
86
  istek = await self.httpx.get(url, headers = {"Referer": f"{self.main_url}/"})
76
- secici = Selector(istek.text)
77
-
78
- title = secici.css("h1.section-title::text").get()
79
- title = title.strip() if title else ""
80
- poster = secici.css("aside.post-info-poster img.lazyload::attr(data-src)").get() or ""
81
- poster = poster.strip() if poster else ""
82
- description = secici.css("article.post-info-content > p::text").get() or ""
83
- description = description.strip() if description else ""
84
- tags = secici.css("div.post-info-genres a::text").getall()
85
- rating = secici.css("div.post-info-imdb-rating span::text").get() or ""
86
- rating = rating.strip() if rating else ""
87
- year = secici.css("div.post-info-year-country a::text").get() or ""
88
- year = year.strip() if year else ""
89
- actors = secici.css("div.post-info-cast a > strong::text").getall()
90
- duration = secici.css("div.post-info-duration::text").get() or "0"
91
- duration = duration.replace("dakika", "").strip()
87
+ secici = HTMLParser(istek.text)
88
+
89
+ title_el = secici.css_first("h1.section-title")
90
+ title = title_el.text(strip=True) if title_el else ""
91
+
92
+ poster_el = secici.css_first("aside.post-info-poster img.lazyload")
93
+ poster = poster_el.attrs.get("data-src", "").strip() if poster_el else ""
94
+
95
+ desc_el = secici.css_first("article.post-info-content > p")
96
+ description = desc_el.text(strip=True) if desc_el else ""
97
+
98
+ tags = [a.text(strip=True) for a in secici.css("div.post-info-genres a") if a.text(strip=True)]
99
+
100
+ rating_el = secici.css_first("div.post-info-imdb-rating span")
101
+ rating = rating_el.text(strip=True) if rating_el else ""
102
+
103
+ year_el = secici.css_first("div.post-info-year-country a")
104
+ year = year_el.text(strip=True) if year_el else ""
105
+
106
+ actors = [a.text(strip=True) for a in secici.css("div.post-info-cast a > strong") if a.text(strip=True)]
107
+
108
+ duration_el = secici.css_first("div.post-info-duration")
109
+ duration_str = duration_el.text(strip=True) if duration_el else "0"
110
+ duration_str = duration_str.replace("dakika", "").strip()
92
111
 
93
112
  try:
94
- duration_minutes = int(re.search(r'\d+', duration).group()) if re.search(r'\d+', duration) else 0
113
+ duration_match = re.search(r'\d+', duration_str)
114
+ duration_minutes = int(duration_match.group()) if duration_match else 0
95
115
  except Exception:
96
116
  duration_minutes = 0
97
117
 
98
118
  # Dizi mi film mi kontrol et (Kotlin referansı: div.seasons kontrolü)
99
- is_series = len(secici.css("div.seasons").getall()) > 0
119
+ is_series = len(secici.css("div.seasons")) > 0
100
120
 
101
121
  if is_series:
102
122
  episodes = []
103
123
  for ep in secici.css("div.seasons-tab-content a"):
104
- ep_name = ep.css("h4::text").get()
105
- ep_href = ep.css("::attr(href)").get()
124
+ ep_name_el = ep.css_first("h4")
125
+ ep_name = ep_name_el.text(strip=True) if ep_name_el else None
126
+ ep_href = ep.attrs.get("href")
127
+
106
128
  if ep_name and ep_href:
107
- ep_name = ep_name.strip()
108
129
  # Regex ile sezon ve bölüm numarası çıkar
109
130
  ep_match = re.search(r'(\d+)\.\s*Bölüm', ep_name)
110
131
  sz_match = re.search(r'(\d+)\.\s*Sezon', ep_name)
@@ -120,7 +141,7 @@ class HDFilmCehennemi(PluginBase):
120
141
 
121
142
  return SeriesInfo(
122
143
  url = url,
123
- poster = self.fix_url(poster),
144
+ poster = self.fix_url(poster) if poster else None,
124
145
  title = self.clean_title(title),
125
146
  description = description,
126
147
  tags = tags,
@@ -132,7 +153,7 @@ class HDFilmCehennemi(PluginBase):
132
153
  else:
133
154
  return MovieInfo(
134
155
  url = url,
135
- poster = self.fix_url(poster),
156
+ poster = self.fix_url(poster) if poster else None,
136
157
  title = self.clean_title(title),
137
158
  description = description,
138
159
  tags = tags,
@@ -255,15 +276,19 @@ class HDFilmCehennemi(PluginBase):
255
276
 
256
277
  async def load_links(self, url: str) -> list[ExtractResult]:
257
278
  istek = await self.httpx.get(url)
258
- secici = Selector(istek.text)
279
+ secici = HTMLParser(istek.text)
259
280
 
260
281
  results = []
261
282
  for alternatif in secici.css("div.alternative-links"):
262
- lang_code = alternatif.css("::attr(data-lang)").get().upper()
283
+ lang_code = alternatif.attrs.get("data-lang", "").upper()
263
284
 
264
285
  for link in alternatif.css("button.alternative-link"):
265
- source = f"{link.css('::text').get().replace('(HDrip Xbet)', '').strip()} {lang_code}"
266
- video_id = link.css("::attr(data-video)").get()
286
+ source_text = link.text(strip=True).replace('(HDrip Xbet)', '').strip()
287
+ source = f"{source_text} {lang_code}"
288
+ video_id = link.attrs.get("data-video")
289
+
290
+ if not video_id:
291
+ continue
267
292
 
268
293
  api_get = await self.httpx.get(
269
294
  url = f"{self.main_url}/video/{video_id}/",
@@ -1,7 +1,7 @@
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
4
- from parsel import Selector
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult
4
+ from selectolax.parser import HTMLParser
5
5
  import re
6
6
 
7
7
  class JetFilmizle(PluginBase):
@@ -40,17 +40,33 @@ class JetFilmizle(PluginBase):
40
40
 
41
41
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
42
42
  istek = await self.httpx.get(f"{url}{page}", follow_redirects=True)
43
- secici = Selector(istek.text)
44
-
45
- return [
46
- MainPageResult(
47
- category = category,
48
- title = self.clean_title(veri.css("h2 a::text, h3 a::text, h4 a::text, h5 a::text, h6 a::text").get()),
49
- url = self.fix_url(veri.css("a::attr(href)").get()),
50
- poster = self.fix_url(veri.css("img::attr(data-src)").get() or veri.css("img::attr(src)").get()),
51
- )
52
- for veri in secici.css("article.movie") if veri.css("h2 a::text, h3 a::text, h4 a::text, h5 a::text, h6 a::text").get()
53
- ]
43
+ secici = HTMLParser(istek.text)
44
+
45
+ results = []
46
+ for veri in secici.css("article.movie"):
47
+ # h2-h6 içindeki a linki
48
+ title_link = None
49
+ for h_tag in ["h2", "h3", "h4", "h5", "h6"]:
50
+ title_link = veri.css_first(f"{h_tag} a")
51
+ if title_link:
52
+ break
53
+
54
+ link_el = veri.css_first("a")
55
+ img_el = veri.css_first("img")
56
+
57
+ title = self.clean_title(title_link.text(strip=True)) if title_link else None
58
+ href = link_el.attrs.get("href") if link_el else None
59
+ poster = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
60
+
61
+ if title and href:
62
+ results.append(MainPageResult(
63
+ category = category,
64
+ title = title,
65
+ url = self.fix_url(href),
66
+ poster = self.fix_url(poster) if poster else None,
67
+ ))
68
+
69
+ return results
54
70
 
55
71
  async def search(self, query: str) -> list[SearchResult]:
56
72
  istek = await self.httpx.post(
@@ -58,55 +74,66 @@ class JetFilmizle(PluginBase):
58
74
  data = {"s": query},
59
75
  headers = {"Referer": f"{self.main_url}/"}
60
76
  )
61
- secici = Selector(istek.text)
77
+ secici = HTMLParser(istek.text)
62
78
 
63
79
  results = []
64
80
  for article in secici.css("article.movie"):
65
- title = self.clean_title(article.css("h2 a::text, h3 a::text, h4 a::text, h5 a::text, h6 a::text").get())
66
- href = article.css("a::attr(href)").get()
67
- poster = article.css("img::attr(data-src)").get() or article.css("img::attr(src)").get()
81
+ # h2-h6 içindeki a linki
82
+ title_link = None
83
+ for h_tag in ["h2", "h3", "h4", "h5", "h6"]:
84
+ title_link = article.css_first(f"{h_tag} a")
85
+ if title_link:
86
+ break
87
+
88
+ link_el = article.css_first("a")
89
+ img_el = article.css_first("img")
90
+
91
+ title = self.clean_title(title_link.text(strip=True)) if title_link else None
92
+ href = link_el.attrs.get("href") if link_el else None
93
+ poster = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
68
94
 
69
95
  if title and href:
70
- results.append(
71
- SearchResult(
72
- title = title.strip(),
73
- url = self.fix_url(href.strip()),
74
- poster = self.fix_url(poster.strip()) if poster else None,
75
- )
76
- )
96
+ results.append(SearchResult(
97
+ title = title,
98
+ url = self.fix_url(href),
99
+ poster = self.fix_url(poster) if poster else None,
100
+ ))
77
101
 
78
102
  return results
79
103
 
80
104
  async def load_item(self, url: str) -> MovieInfo:
81
105
  istek = await self.httpx.get(url)
82
- secici = Selector(istek.text)
106
+ secici = HTMLParser(istek.text)
107
+ html_text = istek.text
83
108
 
84
- title = self.clean_title(secici.css("div.movie-exp-title::text").get())
85
- poster_raw = secici.css("section.movie-exp img::attr(data-src), section.movie-exp img::attr(src)").get()
86
- poster = poster_raw.strip() if poster_raw else None
87
-
88
- desc_raw = secici.css("section.movie-exp p.aciklama::text").get()
89
- description = desc_raw.strip() if desc_raw else None
109
+ title_el = secici.css_first("div.movie-exp-title")
110
+ title = self.clean_title(title_el.text(strip=True)) if title_el else None
111
+
112
+ img_el = secici.css_first("section.movie-exp img")
113
+ poster_raw = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
114
+ poster = poster_raw.strip() if poster_raw else None
90
115
 
91
- tags = secici.css("section.movie-exp div.catss a::text").getall()
116
+ desc_el = secici.css_first("section.movie-exp p.aciklama")
117
+ description = desc_el.text(strip=True) if desc_el else None
92
118
 
93
- rating_raw = secici.css("section.movie-exp div.imdb_puan span::text").get()
94
- rating = rating_raw.strip() if rating_raw else None
119
+ tags = [a.text(strip=True) for a in secici.css("section.movie-exp div.catss a") if a.text(strip=True)]
95
120
 
121
+ rating_el = secici.css_first("section.movie-exp div.imdb_puan span")
122
+ rating = rating_el.text(strip=True) if rating_el else None
96
123
 
97
- # Year - div.yap içinde 4 haneli sayı ara
98
- year_div = secici.xpath("//div[@class='yap' and (contains(., 'Vizyon') or contains(., 'Yapım'))]/text()").get()
124
+ # Year - div.yap içinde 4 haneli sayı ara (xpath yerine regex)
99
125
  year = None
100
- if year_div:
101
- year_match = re.search(r'(\d{4})', year_div.strip())
126
+ yap_match = re.search(r'<div class="yap"[^>]*>([^<]*(?:Vizyon|Yapım)[^<]*)</div>', html_text, re.IGNORECASE)
127
+ if yap_match:
128
+ year_match = re.search(r'(\d{4})', yap_match.group(1))
102
129
  if year_match:
103
130
  year = year_match.group(1)
104
131
 
105
- actors = secici.css("div[itemprop='actor'] a span::text").getall()
132
+ actors = [a.text(strip=True) for a in secici.css("div[itemprop='actor'] a span") if a.text(strip=True)]
106
133
 
107
134
  return MovieInfo(
108
135
  url = url,
109
- poster = self.fix_url(poster),
136
+ poster = self.fix_url(poster) if poster else None,
110
137
  title = title,
111
138
  description = description,
112
139
  tags = tags,
@@ -117,15 +144,15 @@ class JetFilmizle(PluginBase):
117
144
 
118
145
  async def load_links(self, url: str) -> list[ExtractResult]:
119
146
  istek = await self.httpx.get(url)
120
- secici = Selector(istek.text)
147
+ secici = HTMLParser(istek.text)
121
148
 
122
149
  results = []
123
150
 
124
151
  # 1) Ana iframe'leri kontrol et
125
152
  for iframe in secici.css("iframe"):
126
- src = (iframe.css("::attr(src)").get() or
127
- iframe.css("::attr(data-src)").get() or
128
- iframe.css("::attr(data-lazy-src)").get())
153
+ src = (iframe.attrs.get("src") or
154
+ iframe.attrs.get("data-src") or
155
+ iframe.attrs.get("data-lazy-src"))
129
156
 
130
157
  if src and src != "about:blank":
131
158
  iframe_url = self.fix_url(src)
@@ -136,9 +163,10 @@ class JetFilmizle(PluginBase):
136
163
  # 2) Sayfa numaralarından linkleri topla (Fragman hariç)
137
164
  page_links = []
138
165
  for link in secici.css("a.post-page-numbers"):
139
- isim = link.css("span::text").get() or ""
166
+ span_el = link.css_first("span")
167
+ isim = span_el.text(strip=True) if span_el else ""
140
168
  if isim != "Fragman":
141
- href = link.css("::attr(href)").get()
169
+ href = link.attrs.get("href")
142
170
  if href:
143
171
  page_links.append((self.fix_url(href), isim))
144
172
 
@@ -146,12 +174,12 @@ class JetFilmizle(PluginBase):
146
174
  for page_url, isim in page_links:
147
175
  try:
148
176
  page_resp = await self.httpx.get(page_url)
149
- page_sel = Selector(page_resp.text)
177
+ page_sel = HTMLParser(page_resp.text)
150
178
 
151
179
  for iframe in page_sel.css("div#movie iframe"):
152
- src = (iframe.css("::attr(src)").get() or
153
- iframe.css("::attr(data-src)").get() or
154
- iframe.css("::attr(data-lazy-src)").get())
180
+ src = (iframe.attrs.get("src") or
181
+ iframe.attrs.get("data-src") or
182
+ iframe.attrs.get("data-lazy-src"))
155
183
 
156
184
  if src and src != "about:blank":
157
185
  iframe_url = self.fix_url(src)