KekikStream 2.4.5__py3-none-any.whl → 2.4.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 (38) hide show
  1. KekikStream/Core/HTMLHelper.py +20 -43
  2. KekikStream/Core/Plugin/PluginBase.py +15 -4
  3. KekikStream/Extractors/Odnoklassniki.py +14 -2
  4. KekikStream/Extractors/VidMoly.py +2 -2
  5. KekikStream/Extractors/YTDLP.py +2 -2
  6. KekikStream/Plugins/BelgeselX.py +44 -17
  7. KekikStream/Plugins/DiziBox.py +11 -8
  8. KekikStream/Plugins/DiziMom.py +72 -54
  9. KekikStream/Plugins/DiziPal.py +37 -23
  10. KekikStream/Plugins/DiziYou.py +23 -11
  11. KekikStream/Plugins/Dizilla.py +35 -30
  12. KekikStream/Plugins/FilmBip.py +90 -18
  13. KekikStream/Plugins/FilmEkseni.py +78 -40
  14. KekikStream/Plugins/FilmMakinesi.py +29 -14
  15. KekikStream/Plugins/FilmModu.py +17 -19
  16. KekikStream/Plugins/Filmatek.py +103 -91
  17. KekikStream/Plugins/Full4kizle.py +6 -6
  18. KekikStream/Plugins/FullHDFilm.py +6 -6
  19. KekikStream/Plugins/FullHDFilmizlesene.py +6 -7
  20. KekikStream/Plugins/HDFilmCehennemi.py +3 -3
  21. KekikStream/Plugins/JetFilmizle.py +5 -5
  22. KekikStream/Plugins/KultFilmler.py +6 -6
  23. KekikStream/Plugins/RoketDizi.py +5 -5
  24. KekikStream/Plugins/SelcukFlix.py +2 -2
  25. KekikStream/Plugins/SetFilmIzle.py +5 -5
  26. KekikStream/Plugins/SezonlukDizi.py +4 -4
  27. KekikStream/Plugins/Sinefy.py +5 -5
  28. KekikStream/Plugins/SinemaCX.py +6 -6
  29. KekikStream/Plugins/Sinezy.py +5 -5
  30. KekikStream/Plugins/SuperFilmGeldi.py +5 -5
  31. KekikStream/Plugins/UgurFilm.py +4 -4
  32. KekikStream/Plugins/YabanciDizi.py +5 -5
  33. {kekikstream-2.4.5.dist-info → kekikstream-2.4.7.dist-info}/METADATA +1 -1
  34. {kekikstream-2.4.5.dist-info → kekikstream-2.4.7.dist-info}/RECORD +38 -38
  35. {kekikstream-2.4.5.dist-info → kekikstream-2.4.7.dist-info}/WHEEL +0 -0
  36. {kekikstream-2.4.5.dist-info → kekikstream-2.4.7.dist-info}/entry_points.txt +0 -0
  37. {kekikstream-2.4.5.dist-info → kekikstream-2.4.7.dist-info}/licenses/LICENSE +0 -0
  38. {kekikstream-2.4.5.dist-info → kekikstream-2.4.7.dist-info}/top_level.txt +0 -0
@@ -33,22 +33,22 @@ class HTMLHelper:
33
33
  return element
34
34
  return self._root(element).css_first(selector)
35
35
 
36
- def select_text(self, selector: str | None = None, element: Node | None = None, strip: bool = True) -> str | None:
36
+ def select_text(self, selector: str | None = None, element: Node | None = None) -> str | None:
37
37
  """CSS selector ile element bul ve text içeriğini döndür."""
38
38
  el = self.select_first(selector, element)
39
39
  if not el:
40
40
  return None
41
- val = el.text(strip=strip)
41
+ val = el.text(strip=True)
42
42
  return val or None
43
43
 
44
- def select_texts(self, selector: str, element: Node | None = None, strip: bool = True) -> list[str]:
44
+ def select_texts(self, selector: str, element: Node | None = None) -> list[str] | None:
45
45
  """CSS selector ile tüm eşleşen elementlerin text içeriklerini döndür."""
46
46
  out: list[str] = []
47
47
  for el in self.select(selector, element):
48
- txt = el.text(strip=strip)
48
+ txt = el.text(strip=True)
49
49
  if txt:
50
50
  out.append(txt)
51
- return out
51
+ return out or None
52
52
 
53
53
  def select_attr(self, selector: str | None, attr: str, element: Node | None = None) -> str | None:
54
54
  """CSS selector ile element bul ve attribute değerini döndür."""
@@ -71,42 +71,23 @@ class HTMLHelper:
71
71
  return None
72
72
  return el.attrs.get("data-src") or el.attrs.get("src")
73
73
 
74
- def select_direct_text(self, selector: str, element: Node | None = None, strip: bool = True) -> str | None:
74
+ def select_direct_text(self, selector: str, element: Node | None = None) -> str | None:
75
75
  """
76
76
  Elementin yalnızca "kendi" düz metnini döndürür (child elementlerin text'ini katmadan).
77
- Selectolax sürüm farklarına göre deep=False dene, yoksa node sibling-walk ile fallback yapar.
78
77
  """
79
78
  el = self.select_first(selector, element)
80
79
  if not el:
81
80
  return None
82
81
 
83
- # 1) Bazı sürümlerde var: sadece direct text
84
- try:
85
- val = el.text(strip=strip, deep=False) # type: ignore[call-arg]
86
- return val or None
87
- except TypeError:
88
- pass # deep parametresi yok, fallback'e geç
89
-
90
- # 2) Fallback: direct children'ı el.child + next ile dolaş
91
- parts: list[str] = []
92
- ch = el.child
93
- while ch is not None:
94
- if ch.tag == "-text":
95
- t = ch.text(strip=strip)
96
- if t:
97
- parts.append(t)
98
- elif ch.tag == "br":
99
- parts.append("\n")
100
- ch = ch.next
101
-
102
- out = "".join(parts).strip()
103
- return out or None
82
+ # type: ignore[call-arg]
83
+ val = el.text(strip=True, deep=False)
84
+ return val or None
104
85
 
105
86
  # ========================
106
87
  # META (LABEL -> VALUE) İŞLEMLERİ
107
88
  # ========================
108
89
 
109
- def meta_value(self, label: str, container_selector: str | None = None, strip: bool = True) -> str | None:
90
+ def meta_value(self, label: str, container_selector: str | None = None) -> str | None:
110
91
  """
111
92
  Herhangi bir container içinde: LABEL metnini içeren bir elementten SONRA gelen metni döndürür.
112
93
  label örn: "Oyuncular", "Yapım Yılı", "IMDB"
@@ -127,7 +108,7 @@ class HTMLHelper:
127
108
 
128
109
  # 1) Elementin kendi içindeki text'te LABEL: VALUE formatı olabilir
129
110
  # "Oyuncular: Brad Pitt" gibi. LABEL: sonrasını al.
130
- full_txt = label_el.text(strip=strip)
111
+ full_txt = label_el.text(strip=True)
131
112
  if ":" in full_txt and needle in full_txt.split(":")[0].casefold():
132
113
  val = full_txt.split(":", 1)[1].strip()
133
114
  if val: return val
@@ -136,10 +117,10 @@ class HTMLHelper:
136
117
  curr = label_el.next
137
118
  while curr:
138
119
  if curr.tag == "-text":
139
- val = curr.text(strip=strip).strip(" :")
120
+ val = curr.text(strip=True).strip(" :")
140
121
  if val: return val
141
122
  elif curr.tag != "br":
142
- val = curr.text(strip=strip).strip(" :")
123
+ val = curr.text(strip=True).strip(" :")
143
124
  if val: return val
144
125
  else: # <br> gördüysek satır bitmiştir
145
126
  break
@@ -175,29 +156,25 @@ class HTMLHelper:
175
156
  """Regex için kaynak metni döndürür."""
176
157
  return target if isinstance(target, str) else self.html
177
158
 
178
- def _regex_flags(self, target: str | int | None, flags: int) -> int:
179
- """Regex flags değerini döndürür."""
180
- return target if isinstance(target, int) else flags
181
-
182
- def regex_first(self, pattern: str, target: str | int | None = None, flags: int = 0, group: int | None = 1) -> str | tuple | None:
159
+ def regex_first(self, pattern: str, target: str | int | None = None, group: int | None = 1) -> str | tuple | None:
183
160
  """Regex ile arama yap, istenen grubu döndür (group=None ise tüm grupları tuple olarak döndür)."""
184
- match = re.search(pattern, self._regex_source(target), self._regex_flags(target, flags))
161
+ match = re.search(pattern, self._regex_source(target))
185
162
  if not match:
186
163
  return None
187
-
164
+
188
165
  if group is None:
189
166
  return match.groups()
190
167
 
191
168
  last_idx = match.lastindex or 0
192
169
  return match.group(group) if last_idx >= group else match.group(0)
193
170
 
194
- def regex_all(self, pattern: str, target: str | int | None = None, flags: int = 0) -> list[str]:
171
+ def regex_all(self, pattern: str, target: str | int | None = None) -> list[str] | list[tuple]:
195
172
  """Regex ile tüm eşleşmeleri döndür."""
196
- return re.findall(pattern, self._regex_source(target), self._regex_flags(target, flags))
173
+ return re.findall(pattern, self._regex_source(target))
197
174
 
198
- def regex_replace(self, pattern: str, repl: str, target: str | int | None = None, flags: int = 0) -> str:
175
+ def regex_replace(self, pattern: str, repl: str, target: str | int | None = None) -> str:
199
176
  """Regex ile replace yap."""
200
- return re.sub(pattern, repl, self._regex_source(target), flags=self._regex_flags(target, flags))
177
+ return re.sub(pattern, repl, self._regex_source(target))
201
178
 
202
179
  # ========================
203
180
  # ÖZEL AYIKLAYICILAR
@@ -106,7 +106,13 @@ class PluginBase(ABC):
106
106
  url = f"https:{url}" if url.startswith("//") else urljoin(self.main_url, url)
107
107
  return url.replace("\\", "")
108
108
 
109
- async def extract(self, url: str, referer: str = None, prefix: str | None = None) -> ExtractResult | None:
109
+ async def extract(
110
+ self,
111
+ url: str,
112
+ referer: str = None,
113
+ prefix: str | None = None,
114
+ name_override: str | None = None
115
+ ) -> ExtractResult | list[ExtractResult] | None:
110
116
  """
111
117
  Extractor ile video URL'sini çıkarır.
112
118
 
@@ -114,6 +120,7 @@ class PluginBase(ABC):
114
120
  url: Iframe veya video URL'si
115
121
  referer: Referer header (varsayılan: plugin main_url)
116
122
  prefix: İsmin başına eklenecek opsiyonel etiket (örn: "Türkçe Dublaj")
123
+ name_override: İsmi tamamen değiştirecek opsiyonel etiket (Extractor adını ezer)
117
124
 
118
125
  Returns:
119
126
  ExtractResult: Extractor sonucu (name prefix ile birleştirilmiş) veya None
@@ -131,15 +138,19 @@ class PluginBase(ABC):
131
138
  try:
132
139
  data = await extractor.extract(url, referer=referer)
133
140
 
134
- # Liste ise her bir öğe için prefix ekle
141
+ # Liste ise her bir öğe için prefix/override ekle
135
142
  if isinstance(data, list):
136
143
  for item in data:
137
- if prefix and item.name:
144
+ if name_override:
145
+ item.name = name_override
146
+ elif prefix and item.name:
138
147
  item.name = f"{prefix} | {item.name}"
139
148
  return data
140
149
 
141
150
  # Tekil öğe ise
142
- if prefix and data.name:
151
+ if name_override:
152
+ data.name = name_override
153
+ elif prefix and data.name:
143
154
  data.name = f"{prefix} | {data.name}"
144
155
 
145
156
  return data
@@ -1,7 +1,7 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
3
  from KekikStream.Core import ExtractorBase, ExtractResult, HTMLHelper
4
- import json
4
+ import json, html
5
5
 
6
6
  class Odnoklassniki(ExtractorBase):
7
7
  name = "Odnoklassniki"
@@ -19,12 +19,18 @@ class Odnoklassniki(ExtractorBase):
19
19
  resp = await self.httpx.get(url, follow_redirects=True)
20
20
  sel = HTMLHelper(resp.text)
21
21
 
22
- v_data = sel.regex_first(r'"videos":(\[.*?\])')
22
+ # Metadata içinden videos array'ini al (esnek regex)
23
+ v_data = sel.regex_first(r'videos[^:]+:(\[.*?\])')
23
24
  if not v_data:
25
+ if "Видео заблокировано" in resp.text or "copyrightsRestricted" in resp.text:
26
+ raise ValueError("Odnoklassniki: Video telif nedeniyle silinmiş/erişilemiyor.")
24
27
  raise ValueError(f"Odnoklassniki: Video verisi bulunamadı. {url}")
25
28
 
26
29
  # Kalite sıralaması (En yüksekten düşüğe)
27
30
  order = ["ULTRA", "QUAD", "FULL", "HD", "SD", "LOW", "MOBILE"]
31
+ # Escaped string'i temizle
32
+ v_data = html.unescape(v_data)
33
+ v_data = v_data.replace('\\"', '"').replace('\\/', '/')
28
34
  videos = json.loads(v_data)
29
35
 
30
36
  best_url = None
@@ -38,4 +44,10 @@ class Odnoklassniki(ExtractorBase):
38
44
  if not best_url:
39
45
  raise ValueError("Odnoklassniki: Geçerli video URL'si bulunamadı.")
40
46
 
47
+ # URL temizliği (u0026 -> & ve olası unicode kaçışları)
48
+ best_url = best_url.replace("u0026", "&").replace("\\u0026", "&")
49
+ # Eğer hala \uXXXX formatında unicode kaçışları varsa çöz
50
+ if "\\u" in best_url:
51
+ best_url = best_url.encode().decode('unicode-escape')
52
+
41
53
  return ExtractResult(name=self.name, url=self.fix_url(best_url), referer=referer)
@@ -47,7 +47,7 @@ class VidMoly(ExtractorBase):
47
47
 
48
48
  # Altyazı kaynaklarını ayrıştır
49
49
  subtitles = []
50
- if sub_str := sel.regex_first(r"tracks:\s*\[(.*?)\]", flags=re.DOTALL):
50
+ if sub_str := sel.regex_first(r"(?s)tracks:\s*\[(.*?)\]"):
51
51
  sub_data = self._add_marks(sub_str, "file")
52
52
  sub_data = self._add_marks(sub_data, "label")
53
53
  sub_data = self._add_marks(sub_data, "kind")
@@ -68,7 +68,7 @@ class VidMoly(ExtractorBase):
68
68
  break
69
69
 
70
70
  if not video_url:
71
- if src_str := sel.regex_first(r"sources:\s*\[(.*?)\],", flags=re.DOTALL):
71
+ if src_str := sel.regex_first(r"(?s)sources:\s*\[(.*?)\],"):
72
72
  vid_data = self._add_marks(src_str, "file")
73
73
  with contextlib.suppress(json.JSONDecodeError):
74
74
  vid_sources = json.loads(f"[{vid_data}]")
@@ -151,8 +151,8 @@ class YTDLP(ExtractorBase):
151
151
  ydl_opts = {
152
152
  "quiet" : True,
153
153
  "no_warnings" : True,
154
- "extract_flat" : False, # Tam bilgi al
155
- "format" : "best", # En iyi kalite
154
+ "extract_flat" : False, # Tam bilgi al
155
+ "format" : "best/all", # En iyi kalite, yoksa herhangi biri
156
156
  "no_check_certificates" : True,
157
157
  "socket_timeout" : 3,
158
158
  "retries" : 1
@@ -34,31 +34,46 @@ class BelgeselX(PluginBase):
34
34
  @staticmethod
35
35
  def _to_title_case(text: str) -> str:
36
36
  """Türkçe için title case dönüşümü."""
37
- return " ".join(
38
- word.lower().replace("i", "İ").capitalize() if word.lower().startswith("i") else word.capitalize()
39
- for word in text.split()
40
- )
37
+ if not text:
38
+ return ""
39
+
40
+ words = text.split()
41
+ new_words = []
42
+
43
+ for word in words:
44
+ # Önce Türkçe karakterleri koruyarak küçült
45
+ # İ -> i, I -> ı
46
+ word = word.replace("İ", "i").replace("I", "ı").lower()
47
+
48
+ # Sonra ilk harfi Türkçe kurallarına göre büyüt
49
+ if word:
50
+ if word[0] == "i":
51
+ word = "İ" + word[1:]
52
+ elif word[0] == "ı":
53
+ word = "I" + word[1:]
54
+ else:
55
+ word = word[0].upper() + word[1:]
56
+
57
+ new_words.append(word)
58
+
59
+ return " ".join(new_words)
41
60
 
42
61
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
43
62
  istek = self.cloudscraper.get(f"{url}{page}")
44
63
  secici = HTMLHelper(istek.text)
45
64
 
46
65
  results = []
47
- # xpath kullanamıyoruz, en üst seviye gen-movie-contain'leri alıp içlerinden bilgileri çekelim
48
66
  for container in secici.select("div.gen-movie-contain"):
49
- # Poster için img'i container'ın içinden alalım
50
67
  poster = secici.select_attr("div.gen-movie-img img", "src", container)
51
-
52
- # Title ve href için gen-movie-info
53
- title = secici.select_text("div.gen-movie-info h3 a", container)
54
- href = secici.select_attr("div.gen-movie-info h3 a", "href", container)
68
+ title = secici.select_text("div.gen-movie-info h3 a", container)
69
+ href = secici.select_attr("div.gen-movie-info h3 a", "href", container)
55
70
 
56
71
  if title and href:
57
72
  results.append(MainPageResult(
58
73
  category = category,
59
74
  title = self._to_title_case(title),
60
75
  url = self.fix_url(href),
61
- poster = self.fix_url(poster) if poster else None
76
+ poster = self.fix_url(poster)
62
77
  ))
63
78
 
64
79
  return results
@@ -98,7 +113,6 @@ class BelgeselX(PluginBase):
98
113
  poster = images[i] if i < len(images) else None
99
114
 
100
115
  if not url_val or "diziresimleri" not in url_val:
101
- # URL'den belgesel linkini oluştur
102
116
  if poster and "diziresimleri" in poster:
103
117
  file_name = poster.rsplit("/", 1)[-1]
104
118
  file_name = HTMLHelper(file_name).regex_replace(r"\.(jpe?g|png|webp)$", "")
@@ -135,6 +149,7 @@ class BelgeselX(PluginBase):
135
149
  if not rating:
136
150
  if r_match := secici.regex_first(r"%\s*(\d+)\s*Puan", item):
137
151
  rating = float(r_match) / 10
152
+ rating = rating or None
138
153
 
139
154
  episodes = []
140
155
  for i, ep in enumerate(secici.select("div.gen-movie-contain")):
@@ -147,12 +162,23 @@ class BelgeselX(PluginBase):
147
162
  final_url = self.fix_url(href)
148
163
  if item_id:
149
164
  final_url = f"{final_url}?id={item_id}"
150
-
151
- episodes.append(Episode(season=s or 1, episode=e or (i + 1), title=name, url=final_url))
165
+
166
+ episodes.append(Episode(
167
+ season = s or 1,
168
+ episode = e or (i + 1),
169
+ title = name,
170
+ url = final_url
171
+ ))
152
172
 
153
173
  return SeriesInfo(
154
- url=url, poster=self.fix_url(poster) if poster else None, title=title or "Bilinmiyor",
155
- description=description, tags=tags, year=year, rating=rating, episodes=episodes
174
+ url = url,
175
+ poster = self.fix_url(poster),
176
+ title = title,
177
+ description = description,
178
+ tags = tags,
179
+ year = year,
180
+ rating = rating,
181
+ episodes = episodes
156
182
  )
157
183
 
158
184
  async def load_links(self, url: str) -> list[ExtractResult]:
@@ -179,6 +205,7 @@ class BelgeselX(PluginBase):
179
205
 
180
206
  for i, video_url in enumerate(files):
181
207
  quality = labels[i] if i < len(labels) else "HD"
208
+ name = f"{'Google' if 'google' in video_url.lower() or 'blogspot' in video_url.lower() or quality == 'FULL' else self.name} | {'1080p' if quality == 'FULL' else quality}"
182
209
 
183
210
  # belgeselx.php redirect'ini çöz
184
211
  if "belgeselx.php" in video_url or "belgeselx2.php" in video_url:
@@ -191,7 +218,7 @@ class BelgeselX(PluginBase):
191
218
 
192
219
  links.append(ExtractResult(
193
220
  url = video_url,
194
- name = f"{'Google' if 'google' in video_url.lower() or 'blogspot' in video_url.lower() or quality == 'FULL' else self.name} | {'1080p' if quality == 'FULL' else quality}",
221
+ name = name,
195
222
  referer = main_url
196
223
  ))
197
224
 
@@ -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, SeriesInfo, Episode, ExtractResult, HTMLHelper
4
- from Kekik.Sifreleme import CryptoJS
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
4
+ from Kekik.Sifreleme import CryptoJS
5
5
  import urllib.parse, base64, contextlib, asyncio, time
6
6
 
7
7
  class DiziBox(PluginBase):
@@ -61,7 +61,7 @@ class DiziBox(PluginBase):
61
61
  category = category,
62
62
  title = title,
63
63
  url = self.fix_url(href),
64
- poster = self.fix_url(poster) if poster else None,
64
+ poster = self.fix_url(poster),
65
65
  ))
66
66
 
67
67
  return results
@@ -84,7 +84,7 @@ class DiziBox(PluginBase):
84
84
  results.append(SearchResult(
85
85
  title = title,
86
86
  url = self.fix_url(href),
87
- poster = self.fix_url(poster) if poster else None,
87
+ poster = self.fix_url(poster),
88
88
  ))
89
89
 
90
90
  return results
@@ -114,12 +114,12 @@ class DiziBox(PluginBase):
114
114
 
115
115
  return SeriesInfo(
116
116
  url = url,
117
- poster = self.fix_url(poster) if poster else None,
117
+ poster = self.fix_url(poster),
118
118
  title = title,
119
119
  description = description,
120
120
  tags = tags,
121
121
  rating = rating,
122
- year = str(year) if year else None,
122
+ year = year,
123
123
  episodes = episodes,
124
124
  actors = actors,
125
125
  )
@@ -182,13 +182,16 @@ class DiziBox(PluginBase):
182
182
  istek = await self.httpx.get(url)
183
183
  secici = HTMLHelper(istek.text)
184
184
 
185
+ # Aktif kaynağın adını bul (DBX Pro vs.)
186
+ current_source_name = secici.select_text("div.video-toolbar option[selected]") or self.name
187
+
185
188
  results = []
186
189
  main_iframe = secici.select_attr("div#video-area iframe", "src")
187
190
 
188
191
  if main_iframe:
189
192
  if decoded := await self._iframe_decode(self.name, main_iframe, url):
190
193
  for iframe in decoded:
191
- data = await self.extract(iframe)
194
+ data = await self.extract(iframe, name_override=current_source_name)
192
195
  if data:
193
196
  results.append(data)
194
197
 
@@ -209,7 +212,7 @@ class DiziBox(PluginBase):
209
212
  if alt_iframe:
210
213
  if decoded := await self._iframe_decode(alt_name, alt_iframe, url):
211
214
  for iframe in decoded:
212
- data = await self.extract(iframe, prefix=alt_name)
215
+ data = await self.extract(iframe, name_override=alt_name)
213
216
  if data:
214
217
  results.append(data)
215
218
 
@@ -1,8 +1,6 @@
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, HTMLHelper
4
- from json import dumps, loads
5
- import re
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
6
4
 
7
5
  class DiziMom(PluginBase):
8
6
  name = "DiziMom"
@@ -31,23 +29,33 @@ class DiziMom(PluginBase):
31
29
  href = helper.select_attr("div.episode-name a", "href", item)
32
30
  img = helper.select_poster("div.cat-img img", item)
33
31
  if title and href:
34
- results.append(MainPageResult(category=category, title=title.split(" izle")[0], url=self.fix_url(href), poster=self.fix_url(img)))
32
+ results.append(MainPageResult(
33
+ category = category,
34
+ title = title.split(" izle")[0],
35
+ url = self.fix_url(href),
36
+ poster = self.fix_url(img)
37
+ ))
35
38
  else:
36
39
  for item in helper.select("div.single-item"):
37
40
  title = helper.select_text("div.categorytitle a", item)
38
41
  href = helper.select_attr("div.categorytitle a", "href", item)
39
42
  img = helper.select_poster("div.cat-img img", item)
40
43
  if title and href:
41
- results.append(MainPageResult(category=category, title=title.split(" izle")[0], url=self.fix_url(href), poster=self.fix_url(img)))
44
+ results.append(MainPageResult(
45
+ category = category,
46
+ title = title.split(" izle")[0],
47
+ url = self.fix_url(href),
48
+ poster = self.fix_url(img)
49
+ ))
42
50
 
43
51
  return results
44
52
 
45
53
  async def search(self, query: str) -> list[SearchResult]:
46
- url = f"{self.main_url}/?s={query}"
47
- istek = await self.httpx.get(url)
54
+ url = f"{self.main_url}/?s={query}"
55
+ istek = await self.httpx.get(url)
48
56
  helper = HTMLHelper(istek.text)
49
- items = helper.select("div.single-item")
50
-
57
+ items = helper.select("div.single-item")
58
+
51
59
  return [
52
60
  SearchResult(
53
61
  title = helper.select_text("div.categorytitle a", item).split(" izle")[0],
@@ -65,7 +73,7 @@ class DiziMom(PluginBase):
65
73
  poster = helper.select_poster("div.category_image img")
66
74
  description = helper.select_direct_text("div.category_desc")
67
75
  tags = helper.select_texts("div.genres a")
68
- rating = helper.regex_first(r"IMDB\s*:\s*(?:</span>)?\s*([\d\.]+)", helper.html, flags=re.DOTALL)
76
+ rating = helper.regex_first(r"(?s)IMDB\s*:\s*(?:</span>)?\s*([\d\.]+)", helper.html)
69
77
  year = helper.extract_year("div.category_text")
70
78
  actors = helper.meta_list("Oyuncular", container_selector="div#icerikcat2")
71
79
 
@@ -78,68 +86,78 @@ class DiziMom(PluginBase):
78
86
  episodes.append(Episode(
79
87
  season = s or 1,
80
88
  episode = e or 1,
81
- title = self.clean_title(name.replace(title or "", "").strip()),
89
+ title = self.clean_title(name.replace(title, "").strip()),
82
90
  url = self.fix_url(href)
83
91
  ))
84
92
 
85
93
  return SeriesInfo(
86
94
  url = url,
87
- poster = self.fix_url(poster) if poster else None,
88
- title = title or "Bilinmiyor",
95
+ poster = self.fix_url(poster),
96
+ title = title,
89
97
  description = description,
90
98
  tags = tags,
91
99
  rating = rating,
92
- year = str(year) if year else None,
100
+ year = year,
93
101
  actors = actors,
94
102
  episodes = episodes
95
103
  )
96
104
 
97
105
  async def load_links(self, url: str) -> list[ExtractResult]:
98
- # Login simulation headers
99
- headers = {
100
- "User-Agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
101
- "sec-ch-ua": 'Not/A)Brand";v="8", "Chromium";v="137", "Google Chrome";v="137"',
102
- "sec-ch-ua-mobile": "?1",
103
- "sec-ch-ua-platform": "Android"
104
- }
105
-
106
- # Simulate login (as seen in Kotlin)
107
- login_url = f"{self.main_url}/wp-login.php"
108
- login_data = {
109
- "log": "keyiflerolsun",
110
- "pwd": "12345",
111
- "rememberme": "forever",
112
- "redirect_to": self.main_url
113
- }
114
-
115
- await self.httpx.post(login_url, headers=headers, data=login_data)
116
-
117
- istek = await self.httpx.get(url, headers=headers)
106
+ await self.httpx.post(
107
+ url = f"{self.main_url}/wp-login.php",
108
+ headers = {
109
+ "User-Agent" : "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
110
+ "sec-ch-ua" : 'Not/A)Brand";v="8", "Chromium";v="137", "Google Chrome";v="137"',
111
+ "sec-ch-ua-mobile" : "?1",
112
+ "sec-ch-ua-platform" : "Android"
113
+ },
114
+ data = {
115
+ "log" : "keyiflerolsun",
116
+ "pwd" : "12345",
117
+ "rememberme" : "forever",
118
+ "redirect_to" : self.main_url
119
+ }
120
+ )
121
+
122
+ istek = await self.httpx.get(url)
118
123
  helper = HTMLHelper(istek.text)
119
-
120
- iframes = []
121
-
124
+
125
+ iframe_data = []
126
+
127
+ # Aktif kaynağın (main iframe) adını bul
128
+ current_name = helper.select_text("div.sources span.current_dil") or ""
122
129
  main_iframe = helper.select_attr("iframe[src]", "src")
130
+
131
+ # Bazen iframe doğrudan video p içinde olabilir
132
+ if not main_iframe:
133
+ main_iframe = helper.select_attr("div.video p iframe", "src")
134
+
123
135
  if main_iframe:
124
- iframes.append(main_iframe)
125
-
126
- sources = helper.select("div.sources a")
136
+ iframe_data.append((main_iframe, current_name))
137
+
138
+ # Diğer kaynakları (Partlar) gez
139
+ sources = helper.select("div.sources a.post-page-numbers")
127
140
  for source in sources:
128
- href = source.attrs.get("href")
141
+ href = helper.select_attr(None, "href", source)
142
+ name = helper.select_text("span.dil", source)
143
+
129
144
  if href:
130
- sub_istek = await self.httpx.get(href, headers=headers)
145
+ # Part sayfasına git
146
+ sub_istek = await self.httpx.get(href)
131
147
  sub_helper = HTMLHelper(sub_istek.text)
132
- sub_iframe = sub_helper.select_attr("div.video p iframe", "src")
148
+ sub_iframe = sub_helper.select_attr("div.video p iframe", "src") or sub_helper.select_attr("iframe[src]", "src")
149
+
133
150
  if sub_iframe:
134
- iframes.append(sub_iframe)
135
-
151
+ iframe_data.append((sub_iframe, name or f"{len(iframe_data)+1}.Kısım"))
152
+
136
153
  results = []
137
- for iframe_url in iframes:
138
- # Check for known extractors
139
- if iframe_url.startswith("//"):
140
- iframe_url = f"https:{iframe_url}"
141
-
142
- extract_result = await self.extract(iframe_url)
154
+ for iframe_url, source_name in iframe_data:
155
+ # URL düzeltme
156
+ iframe_url = self.fix_url(iframe_url)
157
+
158
+ # Prefix olarak kaynak adını kullan (1.Kısım | HDMomPlayer)
159
+ extract_result = await self.extract(iframe_url, prefix=source_name)
160
+
143
161
  if extract_result:
144
162
  if isinstance(extract_result, list):
145
163
  results.extend(extract_result)
@@ -147,9 +165,9 @@ class DiziMom(PluginBase):
147
165
  results.append(extract_result)
148
166
  else:
149
167
  results.append(ExtractResult(
150
- url = iframe_url,
151
- name = f"{self.name} | External",
168
+ url = iframe_url,
169
+ name = f"{source_name} | External",
152
170
  referer = self.main_url
153
171
  ))
154
-
172
+
155
173
  return results