KekikStream 2.2.9__py3-none-any.whl → 2.5.3__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.

Potentially problematic release.


This version of KekikStream might be problematic. Click here for more details.

Files changed (88) hide show
  1. KekikStream/Core/Extractor/ExtractorBase.py +3 -2
  2. KekikStream/Core/Extractor/ExtractorLoader.py +8 -14
  3. KekikStream/Core/HTMLHelper.py +205 -0
  4. KekikStream/Core/Plugin/PluginBase.py +48 -12
  5. KekikStream/Core/Plugin/PluginLoader.py +13 -14
  6. KekikStream/Core/Plugin/PluginManager.py +2 -2
  7. KekikStream/Core/Plugin/PluginModels.py +0 -3
  8. KekikStream/Core/__init__.py +2 -0
  9. KekikStream/Extractors/Abstream.py +27 -0
  10. KekikStream/Extractors/CloseLoad.py +31 -56
  11. KekikStream/Extractors/ContentX.py +28 -71
  12. KekikStream/Extractors/DonilasPlay.py +34 -78
  13. KekikStream/Extractors/DzenRu.py +11 -25
  14. KekikStream/Extractors/ExPlay.py +20 -38
  15. KekikStream/Extractors/Filemoon.py +23 -53
  16. KekikStream/Extractors/HDMomPlayer.py +30 -0
  17. KekikStream/Extractors/HDPlayerSystem.py +13 -31
  18. KekikStream/Extractors/HotStream.py +27 -0
  19. KekikStream/Extractors/JFVid.py +3 -24
  20. KekikStream/Extractors/JetTv.py +21 -34
  21. KekikStream/Extractors/JetV.py +55 -0
  22. KekikStream/Extractors/MailRu.py +11 -29
  23. KekikStream/Extractors/MixPlayHD.py +17 -31
  24. KekikStream/Extractors/MixTiger.py +17 -40
  25. KekikStream/Extractors/MolyStream.py +25 -22
  26. KekikStream/Extractors/Odnoklassniki.py +41 -105
  27. KekikStream/Extractors/PeaceMakerst.py +20 -47
  28. KekikStream/Extractors/PixelDrain.py +9 -16
  29. KekikStream/Extractors/PlayerFilmIzle.py +23 -46
  30. KekikStream/Extractors/RapidVid.py +23 -36
  31. KekikStream/Extractors/SetPlay.py +19 -44
  32. KekikStream/Extractors/SetPrime.py +3 -6
  33. KekikStream/Extractors/SibNet.py +8 -19
  34. KekikStream/Extractors/Sobreatsesuyp.py +25 -47
  35. KekikStream/Extractors/TRsTX.py +25 -55
  36. KekikStream/Extractors/TurboImgz.py +8 -16
  37. KekikStream/Extractors/TurkeyPlayer.py +5 -5
  38. KekikStream/Extractors/VCTPlay.py +10 -28
  39. KekikStream/Extractors/Veev.py +145 -0
  40. KekikStream/Extractors/VidBiz.py +62 -0
  41. KekikStream/Extractors/VidHide.py +59 -34
  42. KekikStream/Extractors/VidMoly.py +67 -89
  43. KekikStream/Extractors/VidMoxy.py +17 -29
  44. KekikStream/Extractors/VidPapi.py +26 -58
  45. KekikStream/Extractors/VideoSeyred.py +21 -42
  46. KekikStream/Extractors/Videostr.py +58 -0
  47. KekikStream/Extractors/Vidoza.py +18 -0
  48. KekikStream/Extractors/Vtbe.py +38 -0
  49. KekikStream/Extractors/YTDLP.py +2 -2
  50. KekikStream/Extractors/YildizKisaFilm.py +13 -31
  51. KekikStream/Extractors/Zeus.py +61 -0
  52. KekikStream/Plugins/BelgeselX.py +108 -99
  53. KekikStream/Plugins/DiziBox.py +61 -106
  54. KekikStream/Plugins/DiziMom.py +179 -0
  55. KekikStream/Plugins/DiziPal.py +104 -192
  56. KekikStream/Plugins/DiziYou.py +66 -149
  57. KekikStream/Plugins/Dizilla.py +93 -126
  58. KekikStream/Plugins/FilmBip.py +102 -72
  59. KekikStream/Plugins/FilmEkseni.py +199 -0
  60. KekikStream/Plugins/FilmMakinesi.py +101 -64
  61. KekikStream/Plugins/FilmModu.py +35 -59
  62. KekikStream/Plugins/Filmatek.py +184 -0
  63. KekikStream/Plugins/FilmciBaba.py +155 -0
  64. KekikStream/Plugins/FullHDFilmizlesene.py +32 -78
  65. KekikStream/Plugins/HDFilm.py +243 -0
  66. KekikStream/Plugins/HDFilmCehennemi.py +261 -222
  67. KekikStream/Plugins/JetFilmizle.py +117 -98
  68. KekikStream/Plugins/KultFilmler.py +153 -143
  69. KekikStream/Plugins/RecTV.py +53 -49
  70. KekikStream/Plugins/RoketDizi.py +92 -123
  71. KekikStream/Plugins/SelcukFlix.py +86 -95
  72. KekikStream/Plugins/SetFilmIzle.py +105 -143
  73. KekikStream/Plugins/SezonlukDizi.py +106 -128
  74. KekikStream/Plugins/Sinefy.py +194 -166
  75. KekikStream/Plugins/SinemaCX.py +159 -113
  76. KekikStream/Plugins/Sinezy.py +44 -73
  77. KekikStream/Plugins/SuperFilmGeldi.py +28 -52
  78. KekikStream/Plugins/UgurFilm.py +94 -72
  79. KekikStream/Plugins/Watch32.py +160 -0
  80. KekikStream/Plugins/YabanciDizi.py +250 -0
  81. {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/METADATA +1 -1
  82. kekikstream-2.5.3.dist-info/RECORD +99 -0
  83. {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/WHEEL +1 -1
  84. KekikStream/Plugins/FullHDFilm.py +0 -254
  85. kekikstream-2.2.9.dist-info/RECORD +0 -82
  86. {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/entry_points.txt +0 -0
  87. {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/licenses/LICENSE +0 -0
  88. {kekikstream-2.2.9.dist-info → kekikstream-2.5.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,179 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
4
+
5
+ class DiziMom(PluginBase):
6
+ name = "DiziMom"
7
+ language = "tr"
8
+ main_url = "https://www.dizimom.one"
9
+ favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
10
+ description = "Binlerce yerli yabancı dizi arşivi, tüm sezonlar, kesintisiz bölümler. Sadece dizi izle, Dizimom heryerde seninle!"
11
+
12
+ main_page = {
13
+ f"{main_url}/tum-bolumler/page" : "Son Bölümler",
14
+ f"{main_url}/yerli-dizi-izle/page" : "Yerli Diziler",
15
+ f"{main_url}/yabanci-dizi-izle/page" : "Yabancı Diziler",
16
+ f"{main_url}/tv-programlari-izle/page" : "TV Programları",
17
+ f"{main_url}/netflix-dizileri-izle/page" : "Netflix Dizileri",
18
+ f"{main_url}/turkce-dublaj-diziler-hd/page" : "Dublajlı Diziler",
19
+ f"{main_url}/yerli-dizi-izle/page" : "Yerli Diziler",
20
+ f"{main_url}/anime-izle/page" : "Animeler",
21
+ f"{main_url}/yabanci-dizi-izle/page" : "Yabancı Diziler",
22
+ f"{main_url}/kore-dizileri-izle-hd/page" : "Kore Dizileri",
23
+ f"{main_url}/full-hd-hint-dizileri-izle/page" : "Hint Dizileri",
24
+ f"{main_url}/pakistan-dizileri-izle/page" : "Pakistan Dizileri",
25
+ f"{main_url}/tv-programlari-izle/page" : "Tv Programları",
26
+ }
27
+
28
+ async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
29
+ istek = await self.httpx.get(f"{url}/{page}/")
30
+ secici = HTMLHelper(istek.text)
31
+
32
+ results = []
33
+ # Eğer "tum-bolumler" ise Episode kutularını, değilse Dizi kutularını tara
34
+ if "/tum-bolumler/" in url:
35
+ for item in secici.select("div.episode-box"):
36
+ title = secici.select_text("div.episode-name a", item)
37
+ href = secici.select_attr("div.episode-name a", "href", item)
38
+ img = secici.select_poster("div.cat-img img", item)
39
+ if title and href:
40
+ results.append(MainPageResult(
41
+ category = category,
42
+ title = title.split(" izle")[0],
43
+ url = self.fix_url(href),
44
+ poster = self.fix_url(img)
45
+ ))
46
+ else:
47
+ for item in secici.select("div.single-item"):
48
+ title = secici.select_text("div.categorytitle a", item)
49
+ href = secici.select_attr("div.categorytitle a", "href", item)
50
+ img = secici.select_poster("div.cat-img img", item)
51
+ if title and href:
52
+ results.append(MainPageResult(
53
+ category = category,
54
+ title = title.split(" izle")[0],
55
+ url = self.fix_url(href),
56
+ poster = self.fix_url(img)
57
+ ))
58
+
59
+ return results
60
+
61
+ async def search(self, query: str) -> list[SearchResult]:
62
+ istek = await self.httpx.get(f"{self.main_url}/?s={query}")
63
+ secici = HTMLHelper(istek.text)
64
+ items = secici.select("div.single-item")
65
+
66
+ return [
67
+ SearchResult(
68
+ title = secici.select_text("div.categorytitle a", item).split(" izle")[0],
69
+ url = self.fix_url(secici.select_attr("div.categorytitle a", "href", item)),
70
+ poster = self.fix_url(secici.select_attr("div.cat-img img", "src", item))
71
+ )
72
+ for item in items
73
+ ]
74
+
75
+ async def load_item(self, url: str) -> SeriesInfo:
76
+ istek = await self.httpx.get(url)
77
+ secici = HTMLHelper(istek.text)
78
+
79
+ title = self.clean_title(secici.select_text("div.title h1"))
80
+ poster = secici.select_poster("div.category_image img")
81
+ description = secici.select_direct_text("div.category_desc")
82
+ tags = secici.select_texts("div.genres a")
83
+ rating = secici.regex_first(r"(?s)IMDB\s*:\s*(?:</span>)?\s*([\d\.]+)", secici.html)
84
+ year = secici.extract_year("div.category_text")
85
+ actors = secici.meta_list("Oyuncular", container_selector="div#icerikcat2")
86
+
87
+ episodes = []
88
+ for item in secici.select("div.bolumust"):
89
+ name = secici.select_text("div.baslik", item)
90
+ href = secici.select_attr("a", "href", item)
91
+ if name and href:
92
+ s, e = secici.extract_season_episode(name)
93
+ episodes.append(Episode(
94
+ season = s or 1,
95
+ episode = e or 1,
96
+ title = self.clean_title(name.replace(title, "").strip()),
97
+ url = self.fix_url(href)
98
+ ))
99
+
100
+ return SeriesInfo(
101
+ url = url,
102
+ poster = self.fix_url(poster),
103
+ title = title,
104
+ description = description,
105
+ tags = tags,
106
+ rating = rating,
107
+ year = year,
108
+ actors = actors,
109
+ episodes = episodes
110
+ )
111
+
112
+ async def load_links(self, url: str) -> list[ExtractResult]:
113
+ await self.httpx.post(
114
+ url = f"{self.main_url}/wp-login.php",
115
+ headers = {
116
+ "User-Agent" : "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
117
+ "sec-ch-ua" : 'Not/A)Brand";v="8", "Chromium";v="137", "Google Chrome";v="137"',
118
+ "sec-ch-ua-mobile" : "?1",
119
+ "sec-ch-ua-platform" : "Android"
120
+ },
121
+ data = {
122
+ "log" : "keyiflerolsun",
123
+ "pwd" : "12345",
124
+ "rememberme" : "forever",
125
+ "redirect_to" : self.main_url
126
+ }
127
+ )
128
+
129
+ istek = await self.httpx.get(url)
130
+ secici = HTMLHelper(istek.text)
131
+
132
+ iframe_data = []
133
+
134
+ # Aktif kaynağın (main iframe) adını bul
135
+ current_name = secici.select_text("div.sources span.current_dil") or ""
136
+ main_iframe = secici.select_attr("iframe[src]", "src")
137
+
138
+ # Bazen iframe doğrudan video p içinde olabilir
139
+ if not main_iframe:
140
+ main_iframe = secici.select_attr("div.video p iframe", "src")
141
+
142
+ if main_iframe:
143
+ iframe_data.append((main_iframe, current_name))
144
+
145
+ # Diğer kaynakları (Partlar) gez
146
+ sources = secici.select("div.sources a.post-page-numbers")
147
+ for source in sources:
148
+ href = secici.select_attr(None, "href", source)
149
+ name = secici.select_text("span.dil", source)
150
+ if href:
151
+ # Part sayfasına git
152
+ sub_istek = await self.httpx.get(href)
153
+ sub_helper = HTMLHelper(sub_istek.text)
154
+ sub_iframe = sub_helper.select_attr("div.video p iframe", "src") or sub_helper.select_attr("iframe[src]", "src")
155
+
156
+ if sub_iframe:
157
+ iframe_data.append((sub_iframe, name or f"{len(iframe_data)+1}.Kısım"))
158
+
159
+ results = []
160
+ for iframe_url, source_name in iframe_data:
161
+ # URL düzeltme
162
+ iframe_url = self.fix_url(iframe_url)
163
+
164
+ # Prefix olarak kaynak adını kullan (1.Kısım | HDMomPlayer)
165
+ extract_result = await self.extract(iframe_url, prefix=source_name)
166
+
167
+ if extract_result:
168
+ if isinstance(extract_result, list):
169
+ results.extend(extract_result)
170
+ else:
171
+ results.append(extract_result)
172
+ else:
173
+ results.append(ExtractResult(
174
+ url = iframe_url,
175
+ name = f"{source_name} | External",
176
+ referer = self.main_url
177
+ ))
178
+
179
+ return results
@@ -1,243 +1,157 @@
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 selectolax.parser import HTMLParser
5
- import re
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, Subtitle, ExtractResult, HTMLHelper
6
4
 
7
5
  class DiziPal(PluginBase):
8
6
  name = "DiziPal"
9
7
  language = "tr"
10
- main_url = "https://dizipal1224.com"
8
+ main_url = "https://dizipal.uk"
11
9
  favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
12
10
  description = "dizipal güncel, dizipal yeni ve gerçek adresi. dizipal en yeni dizi ve filmleri güvenli ve hızlı şekilde sunar."
13
11
 
14
12
  main_page = {
15
- f"{main_url}/diziler/son-bolumler" : "Son Bölümler",
16
- f"{main_url}/diziler" : "Yeni Diziler",
17
- f"{main_url}/filmler" : "Yeni Filmler",
18
- f"{main_url}/koleksiyon/netflix" : "Netflix",
19
- f"{main_url}/koleksiyon/exxen" : "Exxen",
20
- f"{main_url}/koleksiyon/blutv" : "BluTV",
21
- f"{main_url}/koleksiyon/disney" : "Disney+",
22
- f"{main_url}/koleksiyon/amazon-prime" : "Amazon Prime",
23
- f"{main_url}/koleksiyon/tod-bein" : "TOD (beIN)",
24
- f"{main_url}/koleksiyon/gain" : "Gain",
25
- f"{main_url}/tur/mubi" : "Mubi",
13
+ f"{main_url}/kategori/aile/page/" : "Aile",
14
+ f"{main_url}/kategori/aksiyon/page/" : "Aksiyon",
15
+ f"{main_url}/kategori/animasyon/page/" : "Animasyon",
16
+ f"{main_url}/kategori/belgesel/page/" : "Belgesel",
17
+ f"{main_url}/kategori/bilim-kurgu/page/" : "Bilim Kurgu",
18
+ f"{main_url}/kategori/dram/page/" : "Dram",
19
+ f"{main_url}/kategori/fantastik/page/" : "Fantastik",
20
+ f"{main_url}/kategori/gerilim/page/" : "Gerilim",
21
+ f"{main_url}/kategori/gizem/page/" : "Gizem",
22
+ f"{main_url}/kategori/komedi/page/" : "Komedi",
23
+ f"{main_url}/kategori/korku/page/" : "Korku",
24
+ f"{main_url}/kategori/macera/page/" : "Macera",
25
+ f"{main_url}/kategori/muzik/page/" : "Müzik",
26
+ f"{main_url}/kategori/romantik/page/" : "Romantik",
27
+ f"{main_url}/kategori/savas/page/" : "Savaş",
28
+ f"{main_url}/kategori/suc/page/" : "Suç",
29
+ f"{main_url}/kategori/tarih/page/" : "Tarih",
30
+ f"{main_url}/kategori/vahsi-bati/page/" : "Vahşi Batı",
31
+ f"{main_url}/kategori/yerli/page/" : "Yerli",
26
32
  }
27
33
 
28
34
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
29
- istek = await self.httpx.get(url)
30
- secici = HTMLParser(istek.text)
35
+ istek = await self.httpx.get(f"{url}{page}/")
36
+ secici = HTMLHelper(istek.text)
31
37
 
32
38
  results = []
33
-
34
- if "/son-bolumler" in url:
35
- for veri in secici.css("div.episode-item"):
36
- name_el = veri.css_first("div.name")
37
- episode_el = veri.css_first("div.episode")
38
- link_el = veri.css_first("a")
39
- img_el = veri.css_first("img")
40
-
41
- name = name_el.text(strip=True) if name_el else None
42
- episode = episode_el.text(strip=True) if episode_el else None
43
- href = link_el.attrs.get("href") if link_el else None
44
- poster = img_el.attrs.get("src") if img_el else None
45
-
46
- if name and href:
47
- ep_text = episode.replace(". Sezon ", "x").replace(". Bölüm", "") if episode else ""
48
- title = f"{name} {ep_text}"
49
- # Son bölümler linkini dizi sayfasına çevir
50
- dizi_url = href.split("/sezon")[0] if "/sezon" in href else href
51
-
52
- results.append(MainPageResult(
53
- category = category,
54
- title = title,
55
- url = self.fix_url(dizi_url),
56
- poster = self.fix_url(poster) if poster else None,
57
- ))
58
- else:
59
- for veri in secici.css("article.type2 ul li"):
60
- title_el = veri.css_first("span.title")
61
- link_el = veri.css_first("a")
62
- img_el = veri.css_first("img")
63
-
64
- title = title_el.text(strip=True) if title_el else None
65
- href = link_el.attrs.get("href") if link_el else None
66
- poster = img_el.attrs.get("src") if img_el else None
67
-
68
- if title and href:
69
- results.append(MainPageResult(
70
- category = category,
71
- title = title,
72
- url = self.fix_url(href),
73
- poster = self.fix_url(poster) if poster else None,
74
- ))
39
+ for veri in secici.select("div.grid div.post-item"):
40
+ title = secici.select_attr("a", "title", veri)
41
+ href = secici.select_attr("a", "href", veri)
42
+ poster = secici.select_poster("div.poster img", veri)
43
+
44
+ if title and href:
45
+ results.append(MainPageResult(
46
+ category = category,
47
+ title = title,
48
+ url = self.fix_url(href),
49
+ poster = self.fix_url(poster),
50
+ ))
75
51
 
76
52
  return results
77
53
 
78
54
  async def search(self, query: str) -> list[SearchResult]:
79
- self.httpx.headers.update({
80
- "Accept" : "application/json, text/javascript, */*; q=0.01",
81
- "X-Requested-With" : "XMLHttpRequest"
82
- })
83
-
84
- istek = await self.httpx.post(
85
- url = f"{self.main_url}/api/search-autocomplete",
86
- data = {"query": query}
87
- )
88
-
89
- try:
90
- data = istek.json()
91
- except Exception:
92
- return []
55
+ istek = await self.httpx.get(f"{self.main_url}/?s={query}")
56
+ secici = HTMLHelper(istek.text)
93
57
 
94
58
  results = []
59
+ for veri in secici.select("div.grid div.post-item"):
60
+ title = secici.select_attr("a", "title", veri)
61
+ href = secici.select_attr("a", "href", veri)
62
+ poster = secici.select_poster("div.poster img", veri)
95
63
 
96
- # API bazen dict, bazen list döner
97
- items = data.values() if isinstance(data, dict) else data
98
-
99
- for item in items:
100
- if not isinstance(item, dict):
101
- continue
102
-
103
- title = item.get("title")
104
- url = item.get("url")
105
- poster = item.get("poster")
106
-
107
- if title and url:
64
+ if title and href:
108
65
  results.append(SearchResult(
109
66
  title = title,
110
- url = f"{self.main_url}{url}",
111
- poster = self.fix_url(poster) if poster else None,
67
+ url = self.fix_url(href),
68
+ poster = self.fix_url(poster),
112
69
  ))
113
70
 
114
71
  return results
115
72
 
116
- def _find_sibling_text(self, secici: HTMLParser, label_text: str) -> str | None:
117
- """Bir label'ın kardeş div'inden text çıkarır (xpath yerine)"""
118
- for div in secici.css("div"):
119
- if div.text(strip=True) == label_text:
120
- # Sonraki kardeş elementi bul
121
- next_sibling = div.next
122
- while next_sibling:
123
- if hasattr(next_sibling, 'text') and next_sibling.text(strip=True):
124
- return next_sibling.text(strip=True)
125
- next_sibling = next_sibling.next if hasattr(next_sibling, 'next') else None
126
- return None
127
-
128
73
  async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
129
- # Reset headers to get HTML response
130
- self.httpx.headers.update({
131
- "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
132
- })
133
- self.httpx.headers.pop("X-Requested-With", None)
134
-
135
74
  istek = await self.httpx.get(url)
136
- secici = HTMLParser(istek.text)
137
- html_text = istek.text
138
-
139
- og_image = secici.css_first("meta[property='og:image']")
140
- poster = self.fix_url(og_image.attrs.get("content")) if og_image else None
141
-
142
- # XPath yerine regex ile HTML'den çıkarma
143
- year = None
144
- year_match = re.search(r'Yapım Yılı.*?<div[^>]*>(\d{4})</div>', html_text, re.DOTALL | re.IGNORECASE)
145
- if year_match:
146
- year = year_match.group(1)
147
-
148
- desc_el = secici.css_first("div.summary p")
149
- description = desc_el.text(strip=True) if desc_el else None
150
-
151
- rating = None
152
- rating_match = re.search(r'IMDB Puanı.*?<div[^>]*>([0-9.]+)</div>', html_text, re.DOTALL | re.IGNORECASE)
153
- if rating_match:
154
- rating = rating_match.group(1)
155
-
156
- tags = None
157
- tags_match = re.search(r'Türler.*?<div[^>]*>([^<]+)</div>', html_text, re.DOTALL | re.IGNORECASE)
158
- if tags_match:
159
- tags_raw = tags_match.group(1)
160
- tags = [t.strip() for t in tags_raw.split() if t.strip()]
75
+ secici = HTMLHelper(istek.text)
76
+
77
+ poster = self.fix_url(secici.select_attr("meta[property='og:image']", "content"))
78
+ description = secici.select_attr("meta[property='og:description']", "content")
79
+ title = secici.select_text("h1")
80
+
81
+ year = secici.meta_value("Yapım Yılı")
82
+ rating = secici.meta_value("IMDB Puanı")
83
+ duration_raw = secici.meta_value("Süre")
84
+ if duration_raw:
85
+ parts = duration_raw.split()
86
+ saat = 0
87
+ dakika = 0
88
+
89
+ for p in parts:
90
+ if "s" in p:
91
+ saat = int(p.replace("s", ""))
92
+ elif "dk" in p:
93
+ dakika = int(p.replace("dk", ""))
94
+
95
+ duration = saat * 60 + dakika
96
+ else:
97
+ duration = None
161
98
 
162
- duration = None
163
- dur_match = re.search(r'Ortalama Süre.*?<div[^>]*>(\d+)', html_text, re.DOTALL | re.IGNORECASE)
164
- if dur_match:
165
- duration = int(dur_match.group(1))
99
+ tags = secici.meta_list("Tür")
100
+ actors = secici.meta_list("Oyuncular")
101
+ if not actors:
102
+ actors = secici.select_attrs("div.swiper-slide a", "title")
166
103
 
167
104
  if "/dizi/" in url:
168
- title_el = secici.css_first("div.cover h5")
169
- title = title_el.text(strip=True) if title_el else None
170
-
171
105
  episodes = []
172
- for ep in secici.css("div.episode-item"):
173
- ep_name_el = ep.css_first("div.name")
174
- ep_link_el = ep.css_first("a")
175
- ep_episode_el = ep.css_first("div.episode")
106
+ for ep in secici.select("div.episode-item"):
107
+ name = secici.select_text("h4 a", ep)
108
+ href = secici.select_attr("a", "href", ep)
109
+ link_title = secici.select_attr("a", "title", ep)
176
110
 
177
- ep_name = ep_name_el.text(strip=True) if ep_name_el else None
178
- ep_href = ep_link_el.attrs.get("href") if ep_link_el else None
179
- ep_text = ep_episode_el.text(strip=True) if ep_episode_el else ""
180
- ep_parts = ep_text.split(" ")
111
+ h4_texts = secici.select_texts("h4", ep)
112
+ text = h4_texts[1] if len(h4_texts) > 1 else (h4_texts[0] if h4_texts else "")
181
113
 
182
- ep_season = None
183
- ep_episode = None
184
- if len(ep_parts) >= 4:
185
- try:
186
- ep_season = int(ep_parts[0].replace(".", ""))
187
- ep_episode = int(ep_parts[2].replace(".", ""))
188
- except ValueError:
189
- pass
114
+ full_text = f"{text} {link_title}" if link_title else text
190
115
 
191
- if ep_name and ep_href:
116
+ if name and href:
117
+ s, e = secici.extract_season_episode(full_text or "")
192
118
  episodes.append(Episode(
193
- season = ep_season,
194
- episode = ep_episode,
195
- title = ep_name,
196
- url = self.fix_url(ep_href),
119
+ season = s,
120
+ episode = e,
121
+ title = name,
122
+ url = self.fix_url(href)
197
123
  ))
198
124
 
199
125
  return SeriesInfo(
200
126
  url = url,
201
- poster = poster,
127
+ poster = poster.replace("https://test4test.online", self.main_url),
202
128
  title = title,
203
129
  description = description,
204
130
  tags = tags,
205
131
  rating = rating,
206
132
  year = year,
207
133
  duration = duration,
208
- episodes = episodes if episodes else None,
134
+ episodes = episodes,
135
+ actors = actors
209
136
  )
210
- else:
211
- # Film için title - g-title div'lerinin 2. olanı
212
- g_titles = secici.css("div.g-title div")
213
- title = g_titles[1].text(strip=True) if len(g_titles) >= 2 else None
214
137
 
215
- return MovieInfo(
216
- url = url,
217
- poster = poster,
218
- title = title,
219
- description = description,
220
- tags = tags,
221
- rating = rating,
222
- year = year,
223
- duration = duration,
224
- )
138
+ return MovieInfo(
139
+ url = url,
140
+ poster = poster.replace("https://test4test.online", self.main_url),
141
+ title = title,
142
+ description = description,
143
+ tags = tags,
144
+ rating = rating,
145
+ year = year,
146
+ duration = duration,
147
+ actors = actors
148
+ )
225
149
 
226
150
  async def load_links(self, url: str) -> list[ExtractResult]:
227
- # Reset headers to get HTML response
228
- self.httpx.headers.update({
229
- "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
230
- })
231
- self.httpx.headers.pop("X-Requested-With", None)
232
-
233
151
  istek = await self.httpx.get(url)
234
- secici = HTMLParser(istek.text)
235
-
236
- iframe_el = secici.css_first(".series-player-container iframe")
237
- if not iframe_el:
238
- iframe_el = secici.css_first("div#vast_new iframe")
152
+ secici = HTMLHelper(istek.text)
239
153
 
240
- iframe = iframe_el.attrs.get("src") if iframe_el else None
154
+ iframe = secici.select_attr("div.video-player-area iframe", "src") or secici.select_attr("div.responsive-player iframe", "src")
241
155
  if not iframe:
242
156
  return []
243
157
 
@@ -248,15 +162,13 @@ class DiziPal(PluginBase):
248
162
  i_text = i_istek.text
249
163
 
250
164
  # m3u link çıkar
251
- m3u_match = re.search(r'file:"([^"]+)"', i_text)
252
- if m3u_match:
253
- m3u_link = m3u_match[1]
165
+ m3u_link = secici.regex_first(r'file:"([^"]+)"', target=i_text)
166
+ if m3u_link:
254
167
 
255
168
  # Altyazıları çıkar
169
+ sub_text = secici.regex_first(r'"subtitle":"([^"]+)"', target=i_text)
256
170
  subtitles = []
257
- sub_match = re.search(r'"subtitle":"([^"]+)"', i_text)
258
- if sub_match:
259
- sub_text = sub_match[1]
171
+ if sub_text:
260
172
  if "," in sub_text:
261
173
  for sub in sub_text.split(","):
262
174
  lang = sub.split("[")[1].split("]")[0] if "[" in sub else "Türkçe"