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

@@ -0,0 +1,243 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult, Subtitle, HTMLHelper
4
+ import base64, asyncio, contextlib
5
+
6
+ class HDFilm(PluginBase):
7
+ name = "HDFilm"
8
+ language = "tr"
9
+ main_url = "https://hdfilm.us"
10
+ favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
11
+ description = "Full HD Film izle, Türkçe Dublaj ve Altyazılı filmler."
12
+
13
+ main_page = {
14
+ f"{main_url}/tur/turkce-altyazili-film-izle" : "Altyazılı Filmler",
15
+ f"{main_url}/tur/netflix-filmleri-izle" : "Netflix",
16
+ f"{main_url}/tur/yerli-film-izle" : "Yerli Film",
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/kisa" : "Kısa",
28
+ f"{main_url}/category/komedi-filmleri-izle" : "Komedi",
29
+ f"{main_url}/category/korku-filmleri-izle" : "Korku",
30
+ f"{main_url}/category/macera-filmleri-izle" : "Macera",
31
+ f"{main_url}/category/muzik" : "Müzik",
32
+ f"{main_url}/category/muzikal-filmleri-izle" : "Müzikal",
33
+ f"{main_url}/category/romantik-filmler-izle" : "Romantik",
34
+ f"{main_url}/category/savas-filmleri-izle" : "Savaş",
35
+ f"{main_url}/category/spor-filmleri-izle" : "Spor",
36
+ f"{main_url}/category/suc-filmleri-izle" : "Suç",
37
+ f"{main_url}/category/tarih-filmleri-izle" : "Tarih",
38
+ f"{main_url}/category/western-filmleri-izle" : "Western",
39
+ }
40
+
41
+ async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
42
+ istek = await self.httpx.get(url if page == 1 else f"{url}/page/{page}")
43
+ secici = HTMLHelper(istek.text)
44
+
45
+ results = []
46
+ for veri in secici.select("div.movie-poster"):
47
+ title = secici.select_attr("img", "alt", veri)
48
+ poster = secici.select_attr("img", "src", veri)
49
+ href = secici.select_attr("a", "href", veri)
50
+
51
+ if title and href:
52
+ results.append(MainPageResult(
53
+ category = category,
54
+ title = self.clean_title(title),
55
+ url = self.fix_url(href),
56
+ poster = self.fix_url(poster)
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
+
65
+ results = []
66
+ for veri in secici.select("div.movie-poster"):
67
+ title = secici.select_attr("img", "alt", veri)
68
+ poster = secici.select_attr("img", "src", veri)
69
+ href = secici.select_attr("a", "href", veri)
70
+
71
+ if title and href:
72
+ results.append(SearchResult(
73
+ title = self.clean_title(title),
74
+ url = self.fix_url(href),
75
+ poster = self.fix_url(poster)
76
+ ))
77
+
78
+ return results
79
+
80
+ async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
81
+ istek = await self.httpx.get(url)
82
+ secici = HTMLHelper(istek.text)
83
+
84
+ title = self.clean_title(secici.select_text("h1"))
85
+ poster = secici.select_poster("div.poster img")
86
+ description = secici.select_text("div.film") or secici.select_attr("meta[property='og:description']", "content")
87
+ year = secici.extract_year("div.yayin-tarihi.info") or secici.regex_first(r"\((\d{4})\)")
88
+ tags = secici.select_texts("div.tur.info a")
89
+ rating = secici.regex_first(r"IMDb\s*([\d\.]+)", secici.select_text("div.imdb"))
90
+ actors = secici.select_direct_text("div.oyuncular")
91
+
92
+ is_series = "-dizi" in url.lower() or any("dizi" in tag.lower() for tag in tags)
93
+ if is_series:
94
+ episodes = []
95
+ for idx, el in enumerate(secici.select("li.psec")):
96
+ part_id = el.attrs.get("id")
97
+ part_name = secici.select_text("a", el) or ""
98
+ if not part_name or "fragman" in part_name.lower():
99
+ continue
100
+
101
+ s, e = secici.extract_season_episode(f"{part_id} {part_name}")
102
+ episodes.append(Episode(
103
+ season = s or 1,
104
+ episode = e or (idx+1),
105
+ title = f"{s or 1}. Sezon {e or idx+1}. Bölüm",
106
+ url = url
107
+ ))
108
+
109
+ return SeriesInfo(
110
+ url = url,
111
+ poster = self.fix_url(poster),
112
+ title = title,
113
+ description = description,
114
+ tags = tags,
115
+ year = year,
116
+ actors = actors,
117
+ rating = rating,
118
+ episodes = episodes
119
+ )
120
+
121
+ return MovieInfo(
122
+ url = url,
123
+ poster = self.fix_url(poster),
124
+ title = title,
125
+ description = description,
126
+ tags = tags,
127
+ year = year,
128
+ actors = actors,
129
+ rating = rating
130
+ )
131
+
132
+ def _get_iframe(self, source_code: str) -> str:
133
+ """Base64 kodlu iframe'i çözümle"""
134
+ script_val = HTMLHelper(source_code).regex_first(r'<script[^>]*>(PCEtLWJhc2xpazp[^<]*)</script>')
135
+ if not script_val:
136
+ return ""
137
+
138
+ try:
139
+ decoded_html = base64.b64decode(script_val).decode("utf-8")
140
+ iframe_src = HTMLHelper(decoded_html).regex_first(r'<iframe[^>]+src=["\']([^"\']+)["\']')
141
+ return self.fix_url(iframe_src) if iframe_src else ""
142
+ except Exception:
143
+ return ""
144
+
145
+ def _extract_subtitle_url(self, source_code: str) -> str | None:
146
+ """playerjsSubtitle değişkeninden .srt URL çıkar"""
147
+ patterns = [
148
+ r'var playerjsSubtitle = "\[Türkçe\](https?://[^\s"]+?\.srt)";',
149
+ r'var playerjsSubtitle = "(https?://[^\s"]+?\.srt)";',
150
+ r'subtitle:\s*"(https?://[^\s"]+?\.srt)"',
151
+ ]
152
+
153
+ for pattern in patterns:
154
+ val = HTMLHelper(source_code).regex_first(pattern)
155
+ if val:
156
+ return val
157
+
158
+ return None
159
+
160
+ async def _get_source_links(self, url: str, initial_text: str | None = None) -> list[ExtractResult]:
161
+ results = []
162
+ try:
163
+ if initial_text:
164
+ source_code = initial_text
165
+ secici = HTMLHelper(source_code)
166
+ else:
167
+ resp = await self.httpx.get(url)
168
+ source_code = resp.text
169
+ secici = HTMLHelper(source_code)
170
+
171
+ iframe_src = self._get_iframe(source_code)
172
+ subtitle_url = self._extract_subtitle_url(source_code)
173
+
174
+ # İsim Oluştur (Dil | Player)
175
+ parts = []
176
+
177
+ if action_parts := secici.select_first("div#action-parts"):
178
+ # Aktif olan wrapper'ları bul
179
+ for wrapper in secici.select("div.button-custom-wrapper", action_parts):
180
+ # Aktif buton/link
181
+ active_el = secici.select_first("button", wrapper) or secici.select_first("a.button", wrapper)
182
+ if active_el:
183
+ parts.append(active_el.text(strip=True))
184
+
185
+ final_name = " | ".join(parts) if parts else "HDFilm"
186
+
187
+ if not subtitle_url and iframe_src:
188
+ with contextlib.suppress(Exception):
189
+ iframe_istek = await self.httpx.get(iframe_src)
190
+ subtitle_url = self._extract_subtitle_url(iframe_istek.text)
191
+
192
+ if iframe_src:
193
+ data = await self.extract(iframe_src, name_override=final_name)
194
+ if data:
195
+ sub = Subtitle(name="Türkçe", url=subtitle_url) if subtitle_url else None
196
+ if isinstance(data, list):
197
+ for d in data:
198
+ if sub:
199
+ d.subtitles.append(sub)
200
+ results.append(d)
201
+ else:
202
+ if sub:
203
+ data.subtitles.append(sub)
204
+ results.append(data)
205
+
206
+ return results
207
+ except Exception:
208
+ return []
209
+
210
+ async def load_links(self, url: str) -> list[ExtractResult]:
211
+ initial_istek = await self.httpx.get(url)
212
+ initial_text = initial_istek.text
213
+ secici = HTMLHelper(initial_text)
214
+
215
+ base_url = url.split("?")[0].rstrip("/")
216
+ unique_urls = {base_url} # ?page=1 varsa da base_url olarak sakla
217
+
218
+ if action_parts := secici.select_first("div#action-parts"):
219
+ for link in secici.select("a[href]", action_parts):
220
+ href = link.attrs.get("href", "")
221
+ if "?page=" in href:
222
+ if href.endswith("?page=1") or href == "?page=1":
223
+ unique_urls.add(base_url)
224
+ elif href.startswith("?"):
225
+ unique_urls.add(f"{base_url}{href}")
226
+ else:
227
+ unique_urls.add(self.fix_url(href))
228
+
229
+ tasks = []
230
+ for p_url in unique_urls:
231
+ # Eğer p_url şu anki url ile eşleşiyorsa (veya ?page=1 farkı varsa) metni kullan
232
+ # Basit eşleşme: Eğer p_url == base_url ve (url == base_url veya url == base_url + "?page=1")
233
+
234
+ use_initial = False
235
+ if p_url == base_url:
236
+ if url.rstrip("/") == base_url or url.rstrip("/") == f"{base_url}?page=1":
237
+ use_initial = True
238
+ elif p_url == url.rstrip("/"):
239
+ use_initial = True
240
+
241
+ tasks.append(self._get_source_links(p_url, initial_text if use_initial else None))
242
+
243
+ return [item for sublist in await asyncio.gather(*tasks) for item in sublist]