KekikStream 2.1.9__py3-none-any.whl → 2.2.7__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 (36) hide show
  1. KekikStream/Extractors/CloseLoad.py +7 -8
  2. KekikStream/Extractors/Filemoon.py +7 -6
  3. KekikStream/Extractors/JFVid.py +40 -0
  4. KekikStream/Extractors/MolyStream.py +6 -5
  5. KekikStream/Extractors/PlayerFilmIzle.py +6 -2
  6. KekikStream/Extractors/VidHide.py +0 -1
  7. KekikStream/Extractors/VidMoly.py +17 -9
  8. KekikStream/Plugins/BelgeselX.py +39 -20
  9. KekikStream/Plugins/DiziBox.py +115 -59
  10. KekikStream/Plugins/DiziPal.py +87 -40
  11. KekikStream/Plugins/DiziYou.py +105 -64
  12. KekikStream/Plugins/Dizilla.py +58 -29
  13. KekikStream/Plugins/FilmBip.py +60 -31
  14. KekikStream/Plugins/FilmMakinesi.py +75 -51
  15. KekikStream/Plugins/FilmModu.py +73 -36
  16. KekikStream/Plugins/FullHDFilm.py +82 -48
  17. KekikStream/Plugins/FullHDFilmizlesene.py +94 -39
  18. KekikStream/Plugins/HDFilmCehennemi.py +79 -54
  19. KekikStream/Plugins/JetFilmizle.py +98 -51
  20. KekikStream/Plugins/KultFilmler.py +64 -34
  21. KekikStream/Plugins/RoketDizi.py +43 -26
  22. KekikStream/Plugins/SelcukFlix.py +27 -14
  23. KekikStream/Plugins/SetFilmIzle.py +74 -43
  24. KekikStream/Plugins/SezonlukDizi.py +102 -46
  25. KekikStream/Plugins/Sinefy.py +130 -101
  26. KekikStream/Plugins/SinemaCX.py +82 -37
  27. KekikStream/Plugins/Sinezy.py +61 -47
  28. KekikStream/Plugins/SuperFilmGeldi.py +72 -36
  29. KekikStream/Plugins/UgurFilm.py +72 -34
  30. KekikStream/requirements.txt +1 -1
  31. {kekikstream-2.1.9.dist-info → kekikstream-2.2.7.dist-info}/METADATA +40 -32
  32. {kekikstream-2.1.9.dist-info → kekikstream-2.2.7.dist-info}/RECORD +36 -35
  33. {kekikstream-2.1.9.dist-info → kekikstream-2.2.7.dist-info}/WHEEL +0 -0
  34. {kekikstream-2.1.9.dist-info → kekikstream-2.2.7.dist-info}/entry_points.txt +0 -0
  35. {kekikstream-2.1.9.dist-info → kekikstream-2.2.7.dist-info}/licenses/LICENSE +0 -0
  36. {kekikstream-2.1.9.dist-info → kekikstream-2.2.7.dist-info}/top_level.txt +0 -0
@@ -1,7 +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
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult
4
+ from selectolax.parser import HTMLParser
5
+ import re
5
6
 
6
7
  class FilmBip(PluginBase):
7
8
  name = "FilmBip"
@@ -36,21 +37,23 @@ class FilmBip(PluginBase):
36
37
  page_url = page_url.rstrip("/")
37
38
 
38
39
  istek = await self.httpx.get(page_url)
39
- secici = Selector(istek.text)
40
+ secici = HTMLParser(istek.text)
40
41
 
41
42
  results = []
42
43
  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())
44
+ img = veri.css_first("a.block img.lazy")
45
+ link_el = veri.css_first("a.block")
46
+
47
+ title = img.attrs.get("alt") if img else None
48
+ href = link_el.attrs.get("href") if link_el else None
49
+ poster = (img.attrs.get("data-src") or img.attrs.get("src")) if img else None
47
50
 
48
51
  if title and href:
49
52
  results.append(MainPageResult(
50
53
  category = category,
51
54
  title = title,
52
- url = href,
53
- poster = poster,
55
+ url = self.fix_url(href),
56
+ poster = self.fix_url(poster) if poster else None,
54
57
  ))
55
58
 
56
59
  return results
@@ -77,47 +80,71 @@ class FilmBip(PluginBase):
77
80
  except Exception:
78
81
  return []
79
82
 
80
- secici = Selector(text=html_content)
83
+ secici = HTMLParser(html_content)
81
84
 
82
85
  results = []
83
86
  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
+ link_el = veri.css_first("a.block.truncate")
88
+ href_el = veri.css_first("a")
89
+ img_el = veri.css_first("img.lazy")
90
+
91
+ title = link_el.text(strip=True) if link_el else None
92
+ href = href_el.attrs.get("href") if href_el else None
93
+ poster = img_el.attrs.get("data-src") if img_el else None
87
94
 
88
95
  if title and href:
89
96
  results.append(SearchResult(
90
97
  title = title.strip(),
91
- url = href,
92
- poster = poster,
98
+ url = self.fix_url(href),
99
+ poster = self.fix_url(poster) if poster else None,
93
100
  ))
94
101
 
95
102
  return results
96
103
 
97
104
  async def load_item(self, url: str) -> MovieInfo:
98
105
  istek = await self.httpx.get(url)
99
- secici = Selector(istek.text)
106
+ secici = HTMLParser(istek.text)
107
+ html_text = istek.text
108
+
109
+ title_el = secici.css_first("div.page-title h1")
110
+ title = title_el.text(strip=True) if title_el else ""
111
+
112
+ og_image = secici.css_first("meta[property='og:image']")
113
+ poster = og_image.attrs.get("content") if og_image else None
100
114
 
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()
115
+ trailer_el = secici.css_first("div.series-profile-trailer")
116
+ trailer = trailer_el.attrs.get("data-yt") if trailer_el else None
117
+
118
+ desc_el = secici.css_first("div.series-profile-infos-in.article p")
119
+ if not desc_el:
120
+ desc_el = secici.css_first("div.series-profile-summary p")
121
+ description = desc_el.text(strip=True) if desc_el else None
106
122
 
107
- tags = secici.css("div.series-profile-type.tv-show-profile-type a::text").getall()
123
+ tags = [a.text(strip=True) for a in secici.css("div.series-profile-type.tv-show-profile-type a") if a.text(strip=True)]
124
+
125
+ # XPath yerine regex kullanarak yıl, süre vs. çıkarma
126
+ year = None
127
+ year_match = re.search(r'Yapım yılı.*?<p[^>]*>(\d{4})</p>', html_text, re.IGNORECASE | re.DOTALL)
128
+ if year_match:
129
+ year = year_match.group(1)
130
+
131
+ duration = None
132
+ duration_match = re.search(r'Süre.*?<p[^>]*>(\d+)', html_text, re.IGNORECASE | re.DOTALL)
133
+ if duration_match:
134
+ duration = duration_match.group(1)
108
135
 
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()
136
+ rating = None
137
+ rating_match = re.search(r'IMDB Puanı.*?<span[^>]*>([0-9.]+)</span>', html_text, re.IGNORECASE | re.DOTALL)
138
+ if rating_match:
139
+ rating = rating_match.group(1)
113
140
 
114
- actors = secici.css("div.series-profile-cast ul li a img::attr(alt)").getall()
141
+ actors = [img.attrs.get("alt") for img in secici.css("div.series-profile-cast ul li a img") if img.attrs.get("alt")]
115
142
 
116
143
  return MovieInfo(
117
144
  url = url,
118
- poster = poster,
145
+ poster = self.fix_url(poster) if poster else None,
119
146
  title = self.clean_title(title) if title else "",
120
- description = description.strip() if description else None,
147
+ description = description,
121
148
  tags = tags,
122
149
  year = year,
123
150
  rating = rating,
@@ -127,14 +154,16 @@ class FilmBip(PluginBase):
127
154
 
128
155
  async def load_links(self, url: str) -> list[ExtractResult]:
129
156
  istek = await self.httpx.get(url)
130
- secici = Selector(istek.text)
157
+ secici = HTMLParser(istek.text)
131
158
 
132
159
  results = []
133
160
 
134
161
  for player in secici.css("div#tv-spoox2"):
135
- iframe = self.fix_url(player.css("iframe::attr(src)").get())
162
+ iframe_el = player.css_first("iframe")
163
+ iframe = iframe_el.attrs.get("src") if iframe_el else None
136
164
 
137
165
  if iframe:
166
+ iframe = self.fix_url(iframe)
138
167
  data = await self.extract(iframe)
139
168
  if data:
140
169
  results.append(data)
@@ -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
 
6
6
  class FilmMakinesi(PluginBase):
7
7
  name = "FilmMakinesi"
@@ -36,65 +36,88 @@ class FilmMakinesi(PluginBase):
36
36
 
37
37
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
38
38
  istek = self.cloudscraper.get(f"{url}{'' if page == 1 else f'page/{page}/'}")
39
- secici = Selector(istek.text)
39
+ secici = HTMLParser(istek.text)
40
40
 
41
- veriler = secici.css("div.item-relative")
41
+ results = []
42
+ for veri in secici.css("div.item-relative"):
43
+ title_el = veri.css_first("div.title")
44
+ link_el = veri.css_first("a")
45
+ img_el = veri.css_first("img")
46
+
47
+ title = title_el.text(strip=True) if title_el else None
48
+ href = link_el.attrs.get("href") if link_el else None
49
+ poster = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
50
+
51
+ if title and href:
52
+ results.append(MainPageResult(
53
+ category = category,
54
+ title = title,
55
+ url = self.fix_url(href),
56
+ poster = self.fix_url(poster) if poster else None,
57
+ ))
42
58
 
43
- return [
44
- MainPageResult(
45
- category = category,
46
- title = veri.css("div.title::text").get(),
47
- url = self.fix_url(veri.css("a::attr(href)").get()),
48
- poster = self.fix_url(veri.css("img::attr(data-src)").get() or veri.css("img::attr(src)").get()),
49
- )
50
- for veri in veriler
51
- ]
59
+ return results
52
60
 
53
61
  async def search(self, query: str) -> list[SearchResult]:
54
62
  istek = await self.httpx.get(f"{self.main_url}/arama/?s={query}")
55
- secici = Selector(istek.text)
63
+ secici = HTMLParser(istek.text)
56
64
 
57
65
  results = []
58
66
  for article in secici.css("div.item-relative"):
59
- title = article.css("div.title::text").get()
60
- href = article.css("a::attr(href)").get()
61
- poster = article.css("img::attr(data-src)").get() or article.css("img::attr(src)").get()
67
+ title_el = article.css_first("div.title")
68
+ link_el = article.css_first("a")
69
+ img_el = article.css_first("img")
70
+
71
+ title = title_el.text(strip=True) if title_el else None
72
+ href = link_el.attrs.get("href") if link_el else None
73
+ poster = (img_el.attrs.get("data-src") or img_el.attrs.get("src")) if img_el else None
62
74
 
63
75
  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
- )
76
+ results.append(SearchResult(
77
+ title = title.strip(),
78
+ url = self.fix_url(href.strip()),
79
+ poster = self.fix_url(poster.strip()) if poster else None,
80
+ ))
71
81
 
72
82
  return results
73
83
 
74
84
  async def load_item(self, url: str) -> MovieInfo:
75
85
  istek = await self.httpx.get(url)
76
- secici = Selector(istek.text)
77
-
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
- rating = secici.css("div.score::text").get()
85
- if rating:
86
- rating = rating.strip().split()[0]
87
- year = secici.css("span.date a::text").get()
88
- year = year.strip() if year else ""
89
- actors = secici.css("div.cast-name::text").getall()
90
- tags = secici.css("div.genre a::text").getall()
91
- duration = secici.css("div.time::text").get()
92
- if duration:
93
- duration = duration.split()[1].strip() if len(duration.split()) > 1 else ""
86
+ secici = HTMLParser(istek.text)
87
+
88
+ title_el = secici.css_first("h1.title")
89
+ title = title_el.text(strip=True) if title_el else ""
90
+
91
+ poster_el = secici.css_first("img.cover-img")
92
+ poster = poster_el.attrs.get("src", "").strip() if poster_el else ""
93
+
94
+ desc_el = secici.css_first("div.info-description p")
95
+ description = desc_el.text(strip=True) if desc_el else ""
96
+
97
+ rating_el = secici.css_first("div.score")
98
+ rating = None
99
+ if rating_el:
100
+ rating_text = rating_el.text(strip=True)
101
+ if rating_text:
102
+ rating = rating_text.split()[0]
103
+
104
+ year_el = secici.css_first("span.date a")
105
+ year = year_el.text(strip=True) if year_el else ""
106
+
107
+ actors = [el.text(strip=True) for el in secici.css("div.cast-name") if el.text(strip=True)]
108
+ tags = [el.text(strip=True) for el in secici.css("div.genre a") if el.text(strip=True)]
109
+
110
+ duration_el = secici.css_first("div.time")
111
+ duration = None
112
+ if duration_el:
113
+ duration_text = duration_el.text(strip=True)
114
+ parts = duration_text.split()
115
+ if len(parts) > 1:
116
+ duration = parts[1].strip()
94
117
 
95
118
  return MovieInfo(
96
119
  url = url,
97
- poster = self.fix_url(poster),
120
+ poster = self.fix_url(poster) if poster else None,
98
121
  title = self.clean_title(title),
99
122
  description = description,
100
123
  tags = tags,
@@ -106,23 +129,24 @@ class FilmMakinesi(PluginBase):
106
129
 
107
130
  async def load_links(self, url: str) -> list[ExtractResult]:
108
131
  istek = await self.httpx.get(url)
109
- secici = Selector(istek.text)
132
+ secici = HTMLParser(istek.text)
110
133
 
111
134
  response = []
112
135
 
113
136
  # Video parts linklerini ve etiketlerini al
114
137
  for link in secici.css("div.video-parts a[data-video_url]"):
115
- video_url = link.attrib.get("data-video_url")
116
- label = link.css("::text").get() or ""
117
- label = label.strip()
138
+ video_url = link.attrs.get("data-video_url")
139
+ label = link.text(strip=True) if link.text(strip=True) else ""
118
140
 
119
- data = await self.extract(video_url, prefix=label.split()[0] if label else None)
120
- if data:
121
- response.append(data)
141
+ if video_url:
142
+ data = await self.extract(video_url, prefix=label.split()[0] if label else None)
143
+ if data:
144
+ response.append(data)
122
145
 
123
146
  # Eğer video-parts yoksa iframe kullan
124
147
  if not response:
125
- iframe_src = secici.css("iframe::attr(data-src)").get()
148
+ iframe_el = secici.css_first("iframe")
149
+ iframe_src = iframe_el.attrs.get("data-src") if iframe_el else None
126
150
  if iframe_src:
127
151
  data = await self.extract(iframe_src)
128
152
  if data:
@@ -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, Subtitle, ExtractResult
4
- from parsel import Selector
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, Subtitle, ExtractResult
4
+ from selectolax.parser import HTMLParser
5
5
  import re
6
6
 
7
7
  class FilmModu(PluginBase):
@@ -42,68 +42,105 @@ class FilmModu(PluginBase):
42
42
 
43
43
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
44
44
  istek = await self.httpx.get(url.replace("SAYFA", str(page)))
45
- secici = Selector(istek.text)
46
-
47
- return [
48
- MainPageResult(
49
- category = category,
50
- title = veri.css("a::text").get(),
51
- url = self.fix_url(veri.css("a::attr(href)").get()),
52
- poster = self.fix_url(veri.css("picture img::attr(data-src)").get()),
53
- )
54
- for veri in secici.css("div.movie")
55
- if veri.css("a::text").get()
56
- ]
45
+ secici = HTMLParser(istek.text)
46
+
47
+ results = []
48
+ for veri in secici.css("div.movie"):
49
+ link_el = veri.css_first("a")
50
+ img_el = veri.css_first("picture img")
51
+
52
+ title = link_el.text(strip=True) if link_el else None
53
+ href = link_el.attrs.get("href") if link_el else None
54
+ poster = img_el.attrs.get("data-src") if img_el else None
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) if poster else None,
62
+ ))
63
+
64
+ return results
57
65
 
58
66
  async def search(self, query: str) -> list[SearchResult]:
59
67
  istek = await self.httpx.get(f"{self.main_url}/film-ara?term={query}")
60
- secici = Selector(istek.text)
68
+ secici = HTMLParser(istek.text)
61
69
 
62
- return [
63
- SearchResult(
64
- title = veri.css("a::text").get(),
65
- url = self.fix_url(veri.css("a::attr(href)").get()),
66
- poster = self.fix_url(veri.css("picture img::attr(data-src)").get()),
67
- )
68
- for veri in secici.css("div.movie")
69
- if veri.css("a::text").get()
70
- ]
70
+ results = []
71
+ for veri in secici.css("div.movie"):
72
+ link_el = veri.css_first("a")
73
+ img_el = veri.css_first("picture img")
74
+
75
+ title = link_el.text(strip=True) if link_el else None
76
+ href = link_el.attrs.get("href") if link_el else None
77
+ poster = img_el.attrs.get("data-src") if img_el else None
78
+
79
+ if title and href:
80
+ results.append(SearchResult(
81
+ title = title,
82
+ url = self.fix_url(href),
83
+ poster = self.fix_url(poster) if poster else None,
84
+ ))
85
+
86
+ return results
71
87
 
72
88
  async def load_item(self, url: str) -> MovieInfo:
73
89
  istek = await self.httpx.get(url)
74
- secici = Selector(istek.text)
90
+ secici = HTMLParser(istek.text)
75
91
 
76
- org_title = secici.css("div.titles h1::text").get()
77
- alt_title = secici.css("div.titles h2::text").get()
92
+ org_title_el = secici.css_first("div.titles h1")
93
+ alt_title_el = secici.css_first("div.titles h2")
94
+
95
+ org_title = org_title_el.text(strip=True) if org_title_el else ""
96
+ alt_title = alt_title_el.text(strip=True) if alt_title_el else ""
78
97
  title = f"{org_title} - {alt_title}" if alt_title else org_title
79
98
 
99
+ poster_el = secici.css_first("img.img-responsive")
100
+ poster = poster_el.attrs.get("src") if poster_el else None
101
+
102
+ desc_el = secici.css_first("p[itemprop='description']")
103
+ description = desc_el.text(strip=True) if desc_el else None
104
+
105
+ tags = [a.text(strip=True) for a in secici.css("a[href*='film-tur/']") if a.text(strip=True)]
106
+
107
+ year_el = secici.css_first("span[itemprop='dateCreated']")
108
+ year = year_el.text(strip=True) if year_el else None
109
+
110
+ actors = []
111
+ for a in secici.css("a[itemprop='actor']"):
112
+ span_el = a.css_first("span")
113
+ if span_el and span_el.text(strip=True):
114
+ actors.append(span_el.text(strip=True))
115
+
80
116
  return MovieInfo(
81
117
  url = url,
82
- poster = self.fix_url(secici.css("img.img-responsive::attr(src)").get()),
118
+ poster = self.fix_url(poster) if poster else None,
83
119
  title = title,
84
- description = secici.css("p[itemprop='description']::text").get(),
85
- tags = [a.css("::text").get() for a in secici.css("a[href*='film-tur/']")],
86
- year = secici.css("span[itemprop='dateCreated']::text").get(),
87
- actors = [a.css("span::text").get() for a in secici.css("a[itemprop='actor']")],
120
+ description = description,
121
+ tags = tags,
122
+ year = year,
123
+ actors = actors,
88
124
  )
89
125
 
90
126
  async def load_links(self, url: str) -> list[ExtractResult]:
91
127
  istek = await self.httpx.get(url)
92
- secici = Selector(istek.text)
128
+ secici = HTMLParser(istek.text)
93
129
 
94
130
  alternates = secici.css("div.alternates a")
95
131
  if not alternates:
96
- return [] # No alternates available
132
+ return []
97
133
 
98
134
  results = []
99
135
 
100
136
  for alternatif in alternates:
101
- alt_link = self.fix_url(alternatif.css("::attr(href)").get())
102
- alt_name = alternatif.css("::text").get()
137
+ alt_link = alternatif.attrs.get("href")
138
+ alt_name = alternatif.text(strip=True)
103
139
 
104
140
  if alt_name == "Fragman" or not alt_link:
105
141
  continue
106
142
 
143
+ alt_link = self.fix_url(alt_link)
107
144
  alt_istek = await self.httpx.get(alt_link)
108
145
  alt_text = alt_istek.text
109
146
 
@@ -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, SeriesInfo, Episode, ExtractResult, Subtitle
4
- from parsel import Selector
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult, Subtitle
4
+ from selectolax.parser import HTMLParser
5
5
  import re, base64
6
6
 
7
7
  class FullHDFilm(PluginBase):
@@ -48,55 +48,88 @@ class FullHDFilm(PluginBase):
48
48
  })
49
49
 
50
50
  istek = await self.httpx.get(page_url)
51
- secici = Selector(istek.text)
52
-
53
- return [
54
- MainPageResult(
55
- category = category,
56
- title = veri.css("img::attr(alt)").get(),
57
- url = self.fix_url(veri.css("a::attr(href)").get()),
58
- poster = self.fix_url(veri.css("img::attr(src)").get()),
59
- )
60
- for veri in secici.css("div.movie-poster")
61
- if veri.css("img::attr(alt)").get()
62
- ]
51
+ secici = HTMLParser(istek.text)
52
+
53
+ results = []
54
+ for veri in secici.css("div.movie-poster"):
55
+ img_el = veri.css_first("img")
56
+ link_el = veri.css_first("a")
57
+
58
+ alt = img_el.attrs.get("alt") if img_el else None
59
+ poster = img_el.attrs.get("src") if img_el else None
60
+ href = link_el.attrs.get("href") if link_el else None
61
+
62
+ if alt and href:
63
+ results.append(MainPageResult(
64
+ category = category,
65
+ title = alt,
66
+ url = self.fix_url(href),
67
+ poster = self.fix_url(poster) if poster else None,
68
+ ))
69
+
70
+ return results
63
71
 
64
72
  async def search(self, query: str) -> list[SearchResult]:
65
73
  istek = await self.httpx.get(f"{self.main_url}/?s={query}")
66
- secici = Selector(istek.text)
74
+ secici = HTMLParser(istek.text)
67
75
 
68
- return [
69
- SearchResult(
70
- title = veri.css("img::attr(alt)").get(),
71
- url = self.fix_url(veri.css("a::attr(href)").get()),
72
- poster = self.fix_url(veri.css("img::attr(src)").get()),
73
- )
74
- for veri in secici.css("div.movie-poster")
75
- if veri.css("img::attr(alt)").get()
76
- ]
76
+ results = []
77
+ for veri in secici.css("div.movie-poster"):
78
+ img_el = veri.css_first("img")
79
+ link_el = veri.css_first("a")
80
+
81
+ alt = img_el.attrs.get("alt") if img_el else None
82
+ poster = img_el.attrs.get("src") if img_el else None
83
+ href = link_el.attrs.get("href") if link_el else None
84
+
85
+ if alt and href:
86
+ results.append(SearchResult(
87
+ title = alt,
88
+ url = self.fix_url(href),
89
+ poster = self.fix_url(poster) if poster else None,
90
+ ))
91
+
92
+ return results
77
93
 
78
94
  async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
79
95
  istek = await self.httpx.get(url)
80
- secici = Selector(istek.text)
96
+ secici = HTMLParser(istek.text)
97
+ html_text = istek.text
81
98
 
82
- title = secici.css("h1::text").get() or ""
83
- title = title.strip() if title else ""
84
- poster = self.fix_url(secici.css("div.poster img::attr(src)").get() or "")
85
-
86
- actors_text = secici.css("div.oyuncular.info::text").get()
87
- if actors_text:
88
- actors_text = actors_text.replace("Oyuncular:", "").strip()
89
- actors = [a.strip() for a in actors_text.split(",")]
90
- else:
91
- actors = []
99
+ title_el = secici.css_first("h1")
100
+ title = title_el.text(strip=True) if title_el else ""
92
101
 
93
- year = secici.css("div.yayin-tarihi.info::text").re_first(r"(\d{4})")
94
- tags = secici.css("div.tur.info a::text").getall()
95
- rating = secici.css("div.imdb::text").re_first(r"IMDb\s*([\d\.]+)")
102
+ poster_el = secici.css_first("div.poster img")
103
+ poster = self.fix_url(poster_el.attrs.get("src")) if poster_el else ""
96
104
 
97
- # Description
98
- description = secici.xpath("//div[contains(@class, 'others')]/preceding-sibling::div[1]//text()").getall()
99
- description = "".join(description).strip() if description else None
105
+ actors_el = secici.css_first("div.oyuncular.info")
106
+ actors = []
107
+ if actors_el:
108
+ actors_text = actors_el.text(strip=True)
109
+ if actors_text:
110
+ actors_text = actors_text.replace("Oyuncular:", "").strip()
111
+ actors = [a.strip() for a in actors_text.split(",")]
112
+
113
+ # Year: re_first ile regex
114
+ year_el = secici.css_first("div.yayin-tarihi.info")
115
+ year_text = year_el.text(strip=True) if year_el else ""
116
+ year_match = re.search(r"(\d{4})", year_text)
117
+ year = year_match.group(1) if year_match else None
118
+
119
+ tags = [a.text(strip=True) for a in secici.css("div.tur.info a") if a.text(strip=True)]
120
+
121
+ # Rating: regex
122
+ rating_el = secici.css_first("div.imdb")
123
+ rating_text = rating_el.text(strip=True) if rating_el else ""
124
+ rating_match = re.search(r"IMDb\s*([\d\.]+)", rating_text)
125
+ rating = rating_match.group(1) if rating_match else None
126
+
127
+ # Description: others div'den önceki div içindeki text
128
+ # XPath yerine basit yaklaşım: özet sınıfı ile veya ilk paragraf
129
+ description = None
130
+ desc_el = secici.css_first("div.film")
131
+ if desc_el:
132
+ description = desc_el.text(strip=True)
100
133
 
101
134
  # Kotlin referansı: URL'de -dizi kontrolü veya tags içinde "dizi" kontrolü
102
135
  is_series = "-dizi" in url.lower() or any("dizi" in tag.lower() for tag in tags)
@@ -104,16 +137,17 @@ class FullHDFilm(PluginBase):
104
137
  if is_series:
105
138
  episodes = []
106
139
  part_elements = secici.css("li.psec")
107
- part_names = secici.css("li.psec a::text").getall()
108
140
 
109
141
  # pdata değerlerini çıkar
110
- pdata_matches = re.findall(r"pdata\['([^']+)'\]\s*=\s*'([^']+)'", istek.text)
142
+ pdata_matches = re.findall(r"pdata\['([^']+)'\]\s*=\s*'([^']+)'", html_text)
111
143
 
112
- for idx, (part_id, part_name) in enumerate(zip([el.css("::attr(id)").get() for el in part_elements], part_names)):
144
+ for idx, el in enumerate(part_elements):
145
+ part_id = el.attrs.get("id")
146
+ link_el = el.css_first("a")
147
+ part_name = link_el.text(strip=True) if link_el else None
148
+
113
149
  if not part_name:
114
150
  continue
115
-
116
- part_name = part_name.strip()
117
151
 
118
152
  # Fragman'ları atla
119
153
  if "fragman" in part_name.lower() or (part_id and "fragman" in part_id.lower()):
@@ -146,7 +180,7 @@ class FullHDFilm(PluginBase):
146
180
  tags = tags,
147
181
  year = year,
148
182
  actors = actors,
149
- rating = rating.strip() if rating else None,
183
+ rating = rating,
150
184
  episodes = episodes
151
185
  )
152
186
  else:
@@ -158,7 +192,7 @@ class FullHDFilm(PluginBase):
158
192
  tags = tags,
159
193
  year = year,
160
194
  actors = actors,
161
- rating = rating.strip() if rating else None,
195
+ rating = rating,
162
196
  )
163
197
 
164
198
  def _get_iframe(self, source_code: str) -> str: