KekikStream 2.4.2__py3-none-any.whl → 2.4.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.
Files changed (72) hide show
  1. KekikStream/Core/Extractor/ExtractorBase.py +3 -2
  2. KekikStream/Core/HTMLHelper.py +134 -40
  3. KekikStream/Core/Plugin/PluginBase.py +3 -2
  4. KekikStream/Extractors/CloseLoad.py +30 -54
  5. KekikStream/Extractors/ContentX.py +27 -72
  6. KekikStream/Extractors/DonilasPlay.py +33 -77
  7. KekikStream/Extractors/DzenRu.py +10 -24
  8. KekikStream/Extractors/ExPlay.py +20 -38
  9. KekikStream/Extractors/Filemoon.py +19 -45
  10. KekikStream/Extractors/HDMomPlayer.py +24 -56
  11. KekikStream/Extractors/HDPlayerSystem.py +13 -31
  12. KekikStream/Extractors/HotStream.py +14 -32
  13. KekikStream/Extractors/JFVid.py +3 -24
  14. KekikStream/Extractors/JetTv.py +21 -34
  15. KekikStream/Extractors/MailRu.py +11 -29
  16. KekikStream/Extractors/MixPlayHD.py +15 -28
  17. KekikStream/Extractors/MixTiger.py +17 -40
  18. KekikStream/Extractors/MolyStream.py +17 -21
  19. KekikStream/Extractors/Odnoklassniki.py +28 -104
  20. KekikStream/Extractors/PeaceMakerst.py +18 -45
  21. KekikStream/Extractors/PixelDrain.py +8 -16
  22. KekikStream/Extractors/PlayerFilmIzle.py +22 -41
  23. KekikStream/Extractors/RapidVid.py +21 -35
  24. KekikStream/Extractors/SetPlay.py +18 -43
  25. KekikStream/Extractors/SibNet.py +7 -17
  26. KekikStream/Extractors/Sobreatsesuyp.py +23 -45
  27. KekikStream/Extractors/TRsTX.py +23 -53
  28. KekikStream/Extractors/TurboImgz.py +7 -14
  29. KekikStream/Extractors/VCTPlay.py +10 -28
  30. KekikStream/Extractors/VidHide.py +10 -31
  31. KekikStream/Extractors/VidMoly.py +65 -99
  32. KekikStream/Extractors/VidMoxy.py +16 -27
  33. KekikStream/Extractors/VidPapi.py +24 -54
  34. KekikStream/Extractors/VideoSeyred.py +19 -40
  35. KekikStream/Extractors/Videostr.py +42 -99
  36. KekikStream/Extractors/Vidoza.py +8 -15
  37. KekikStream/Extractors/YildizKisaFilm.py +13 -31
  38. KekikStream/Plugins/BelgeselX.py +63 -69
  39. KekikStream/Plugins/DiziBox.py +16 -36
  40. KekikStream/Plugins/DiziMom.py +37 -129
  41. KekikStream/Plugins/DiziPal.py +26 -75
  42. KekikStream/Plugins/DiziYou.py +44 -152
  43. KekikStream/Plugins/Dizilla.py +18 -44
  44. KekikStream/Plugins/FilmBip.py +10 -24
  45. KekikStream/Plugins/FilmEkseni.py +12 -32
  46. KekikStream/Plugins/FilmMakinesi.py +24 -77
  47. KekikStream/Plugins/FilmModu.py +11 -18
  48. KekikStream/Plugins/Filmatek.py +13 -39
  49. KekikStream/Plugins/Full4kizle.py +33 -133
  50. KekikStream/Plugins/FullHDFilm.py +23 -93
  51. KekikStream/Plugins/FullHDFilmizlesene.py +10 -29
  52. KekikStream/Plugins/HDFilmCehennemi.py +27 -66
  53. KekikStream/Plugins/JetFilmizle.py +19 -20
  54. KekikStream/Plugins/KultFilmler.py +16 -50
  55. KekikStream/Plugins/RecTV.py +47 -85
  56. KekikStream/Plugins/SelcukFlix.py +29 -47
  57. KekikStream/Plugins/SetFilmIzle.py +28 -84
  58. KekikStream/Plugins/SezonlukDizi.py +27 -59
  59. KekikStream/Plugins/Sinefy.py +37 -100
  60. KekikStream/Plugins/SinemaCX.py +12 -18
  61. KekikStream/Plugins/Sinezy.py +11 -12
  62. KekikStream/Plugins/SuperFilmGeldi.py +8 -13
  63. KekikStream/Plugins/UgurFilm.py +14 -14
  64. KekikStream/Plugins/Watch32.py +42 -74
  65. KekikStream/Plugins/YabanciDizi.py +33 -87
  66. {kekikstream-2.4.2.dist-info → kekikstream-2.4.3.dist-info}/METADATA +1 -1
  67. kekikstream-2.4.3.dist-info/RECORD +93 -0
  68. kekikstream-2.4.2.dist-info/RECORD +0 -93
  69. {kekikstream-2.4.2.dist-info → kekikstream-2.4.3.dist-info}/WHEEL +0 -0
  70. {kekikstream-2.4.2.dist-info → kekikstream-2.4.3.dist-info}/entry_points.txt +0 -0
  71. {kekikstream-2.4.2.dist-info → kekikstream-2.4.3.dist-info}/licenses/LICENSE +0 -0
  72. {kekikstream-2.4.2.dist-info → kekikstream-2.4.3.dist-info}/top_level.txt +0 -0
@@ -93,44 +93,24 @@ class DiziBox(PluginBase):
93
93
  istek = await self.httpx.get(url)
94
94
  secici = HTMLHelper(istek.text)
95
95
 
96
- title = secici.select_text("div.tv-overview h1 a")
97
-
98
- poster = secici.select_attr("div.tv-overview figure img", "src")
99
-
96
+ title = secici.select_text("div.tv-overview h1 a")
97
+ poster = secici.select_poster("div.tv-overview figure img")
100
98
  description = secici.select_text("div.tv-story p")
101
-
102
- # year
103
- year_text = secici.select_text("a[href*='/yil/']")
104
- year = secici.regex_first(r"(\d{4})", year_text)
105
-
106
- tags = secici.select_all_text("a[href*='/tur/']")
107
-
108
- # rating
109
- rating_text = secici.select_text("span.label-imdb b")
110
- rating = secici.regex_first(r"[\d.,]+", rating_text)
111
-
112
- actors = secici.select_all_text("a[href*='/oyuncu/']")
99
+ year = secici.extract_year("a[href*='/yil/']")
100
+ tags = secici.select_texts("a[href*='/tur/']")
101
+ rating = secici.regex_first(r"[\d.,]+", secici.select_text("span.label-imdb b"))
102
+ actors = secici.select_texts("a[href*='/oyuncu/']")
113
103
 
114
104
  episodes = []
115
- for sezon_link in secici.select_all_attr("div#seasons-list a", "href"):
116
- sezon_url = self.fix_url(sezon_link)
117
- sezon_istek = await self.httpx.get(sezon_url)
118
- sezon_secici = HTMLHelper(sezon_istek.text)
119
-
120
- for bolum in sezon_secici.select("article.grid-box"):
121
- ep_title = sezon_secici.select_text("div.post-title a", bolum)
122
- ep_href = sezon_secici.select_attr("div.post-title a", "href", bolum)
123
-
124
- ep_season = sezon_secici.regex_first(r"(\d+)\. ?Sezon", ep_title)
125
- ep_episode = sezon_secici.regex_first(r"(\d+)\. ?Bölüm", ep_title)
126
-
127
- if ep_title and ep_href:
128
- episodes.append(Episode(
129
- season = ep_season,
130
- episode = ep_episode,
131
- title = ep_title,
132
- url = self.fix_url(ep_href),
133
- ))
105
+ for link in secici.select_attrs("div#seasons-list a", "href"):
106
+ r = await self.httpx.get(self.fix_url(link))
107
+ s_secici = HTMLHelper(r.text)
108
+ for bolum in s_secici.select("article.grid-box"):
109
+ name = s_secici.select_text("div.post-title a", bolum)
110
+ href = s_secici.select_attr("div.post-title a", "href", bolum)
111
+ if name and href:
112
+ s, e = s_secici.extract_season_episode(name)
113
+ episodes.append(Episode(season=s, episode=e, title=name, url=self.fix_url(href)))
134
114
 
135
115
  return SeriesInfo(
136
116
  url = url,
@@ -139,7 +119,7 @@ class DiziBox(PluginBase):
139
119
  description = description,
140
120
  tags = tags,
141
121
  rating = rating,
142
- year = year,
122
+ year = str(year) if year else None,
143
123
  episodes = episodes,
144
124
  actors = actors,
145
125
  )
@@ -19,34 +19,28 @@ class DiziMom(PluginBase):
19
19
  }
20
20
 
21
21
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
22
- istek = await self.httpx.get(f"{url}/{page}/")
23
- helper = HTMLHelper(istek.text)
22
+ full_url = f"{url}/{page}/"
23
+ istek = await self.httpx.get(full_url)
24
+ helper = HTMLHelper(istek.text)
24
25
 
26
+ results = []
27
+ # Eğer "tum-bolumler" ise Episode kutularını, değilse Dizi kutularını tara
25
28
  if "/tum-bolumler/" in url:
26
- items = helper.select("div.episode-box")
27
- results = []
28
- for item in items:
29
- name_el = helper.select_first("div.episode-name a", item)
30
- if not name_el: continue
31
- name = name_el.text(strip=True).split(" izle")[0]
32
- title = name.replace(".Sezon ", "x").replace(".Bölüm", "")
33
-
34
- ep_href = self.fix_url(name_el.attrs.get("href"))
35
- pass
36
-
37
- # Revert to standard categories if "tum-bolumler" is complex
38
- return []
29
+ for item in helper.select("div.episode-box"):
30
+ title = helper.select_text("div.episode-name a", item)
31
+ href = helper.select_attr("div.episode-name a", "href", item)
32
+ img = helper.select_poster("div.cat-img img", item)
33
+ 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)))
39
35
  else:
40
- items = helper.select("div.single-item")
41
- return [
42
- MainPageResult(
43
- category = category,
44
- title = helper.select_text("div.categorytitle a", item).split(" izle")[0],
45
- url = self.fix_url(helper.select_attr("div.categorytitle a", "href", item)),
46
- poster = self.fix_url(helper.select_attr("div.cat-img img", "src", item))
47
- )
48
- for item in items
49
- ]
36
+ for item in helper.select("div.single-item"):
37
+ title = helper.select_text("div.categorytitle a", item)
38
+ href = helper.select_attr("div.categorytitle a", "href", item)
39
+ img = helper.select_poster("div.cat-img img", item)
40
+ 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)))
42
+
43
+ return results
50
44
 
51
45
  async def search(self, query: str) -> list[SearchResult]:
52
46
  url = f"{self.main_url}/?s={query}"
@@ -67,117 +61,31 @@ class DiziMom(PluginBase):
67
61
  istek = await self.httpx.get(url)
68
62
  helper = HTMLHelper(istek.text)
69
63
 
70
- title_raw = helper.select_text("div.title h1")
71
- title = title_raw.split(" izle")[0] if title_raw else "Bilinmiyor"
72
-
73
- poster = self.fix_url(helper.select_attr("div.category_image img", "src"))
74
-
75
- # Custom extraction for fields that were using xpath_text
76
- year = None
77
- rating = None
78
- actors = None
79
-
80
- # Regex approach based on debug output (multiline support)
81
- # Context: <span class="dizimeta"><i class="fas fa-globe"></i> Yapım Yılı : </span>\n 2022
82
- year_val_all = helper.regex_all(r"Yapım Yılı\s*:\s*(?:</span>)?\s*(\d{4})", flags=re.DOTALL)
83
- if year_val_all:
84
- year = int(year_val_all[0])
85
-
86
- # Context: <span class="dizimeta"><i class="fas fa-star"></i> IMDB : </span>\n 4.5
87
- rating_val_all = helper.regex_all(r"IMDB\s*:\s*(?:</span>)?\s*([\d\.]+)", flags=re.DOTALL)
88
- if rating_val_all:
89
- rating = rating_val_all[0]
90
-
91
- actors_val = helper.regex_first(r"Oyuncular\s*:\s*(.+?)(?:</div>|<br|$)")
92
- if not actors_val:
93
- # Try selecting the div text directly if regex fails due to HTML tags
94
- # Find div containing "Oyuncular :"
95
- all_divs = helper.select("div")
96
- for div in all_divs:
97
- txt = div.text()
98
- if "Oyuncular :" in txt:
99
- actors_val = txt.split("Oyuncular :")[1].strip()
100
- break
101
-
102
- if actors_val:
103
- # Remove footer / junk from actors
104
- if "IMDB :" in actors_val:
105
- actors_val = actors_val.split("IMDB :")[0].strip()
106
-
107
- if "IMDB :" in actors_val:
108
- actors_val = actors_val.split("IMDB :")[0].strip()
109
-
110
- # Remove '×' and other junk if present at end
111
- if "×" in actors_val:
112
- actors_val = actors_val.split("×")[0].strip()
113
-
114
- # Remove simple tags if any remaining
115
- clean_actors = [a.strip() for a in actors_val.split(",")]
116
- # Filter empty
117
- clean_actors = [a for a in clean_actors if a]
118
-
119
- actors = ", ".join(clean_actors)
120
-
121
- description_raw = helper.select_text("div.category_desc")
122
- description = None
123
- if description_raw:
124
- # Clean header "The Librarians izle..." etc. if present, usually it is fine.
125
- # Clean "IMDB :" if attached
126
- if "IMDB :" in description_raw:
127
- description_raw = description_raw.split("IMDB :")[0].strip()
128
-
129
- # Clean footer text start
130
- # The footer block usually starts with "Dizimom, dizi ve film..."
131
- if "Dizimom," in description_raw:
132
- description = description_raw.split("Dizimom,")[0].strip()
133
- elif "dizi izle film izle" in description_raw:
134
- description = description_raw.split("dizi izle film izle")[0].strip()
135
- else:
136
- description = description_raw
137
-
138
- # Fallback cleanup for JSON
139
- if description and "{" in description:
140
- description = description.split("{")[0].strip()
141
-
142
- tags = helper.select_all_text("div.genres a")
143
-
144
- # Improved year regex
145
- if not year:
146
- # Look for "Yapım Yılı : 2014" pattern in ANY text
147
- # Get all text from category_text which usually contains it
148
- meta_text = helper.select_text("div.category_text")
149
- if meta_text:
150
- match = re.search(r"Yapım Yılı\s*:\s*(\d{4})", meta_text)
151
- if match:
152
- year = int(match.group(1))
64
+ title = self.clean_title(helper.select_text("div.title h1"))
65
+ poster = helper.select_poster("div.category_image img")
66
+ description = helper.select_direct_text("div.category_desc")
67
+ tags = helper.select_texts("div.genres a")
68
+ rating = helper.regex_first(r"IMDB\s*:\s*(?:</span>)?\s*([\d\.]+)", helper.html, flags=re.DOTALL)
69
+ year = helper.extract_year("div.category_text")
70
+ actors = helper.meta_list("Oyuncular", container_selector="div#icerikcat2")
153
71
 
154
72
  episodes = []
155
- ep_items = helper.select("div.bolumust")
156
- for item in ep_items:
157
- ep_name_raw = helper.select_text("div.baslik", item)
158
- ep_href = self.fix_url(helper.select_attr("a", "href", item))
159
-
160
- if ep_name_raw:
161
- # 1.Sezon 1.Bölüm
162
- s_m = re.search(r"(\d+)\.Sezon", ep_name_raw)
163
- e_m = re.search(r"(\d+)\.Bölüm", ep_name_raw)
164
-
165
- season = int(s_m.group(1)) if s_m else 1
166
- episode = int(e_m.group(1)) if e_m else 1
167
-
168
- name = ep_name_raw.split(" izle")[0].replace(title, "").strip()
169
-
73
+ for item in helper.select("div.bolumust"):
74
+ name = helper.select_text("div.baslik", item)
75
+ href = helper.select_attr("a", "href", item)
76
+ if name and href:
77
+ s, e = helper.extract_season_episode(name)
170
78
  episodes.append(Episode(
171
- season = season,
172
- episode = episode,
173
- title = name,
174
- url = ep_href
79
+ season = s or 1,
80
+ episode = e or 1,
81
+ title = self.clean_title(name.replace(title or "", "").strip()),
82
+ url = self.fix_url(href)
175
83
  ))
176
84
 
177
85
  return SeriesInfo(
178
86
  url = url,
179
- poster = poster,
180
- title = title,
87
+ poster = self.fix_url(poster) if poster else None,
88
+ title = title or "Bilinmiyor",
181
89
  description = description,
182
90
  tags = tags,
183
91
  rating = rating,
@@ -5,7 +5,7 @@ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInf
5
5
  class DiziPal(PluginBase):
6
6
  name = "DiziPal"
7
7
  language = "tr"
8
- main_url = "https://dizipal1226.com"
8
+ main_url = "https://dizipal.cc"
9
9
  favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
10
10
  description = "dizipal güncel, dizipal yeni ve gerçek adresi. dizipal en yeni dizi ve filmleri güvenli ve hızlı şekilde sunar."
11
11
 
@@ -116,94 +116,45 @@ class DiziPal(PluginBase):
116
116
 
117
117
  async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
118
118
  # Reset headers to get HTML response
119
- self.httpx.headers.update({
120
- "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
121
- })
119
+ self.httpx.headers.update({"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"})
122
120
  self.httpx.headers.pop("X-Requested-With", None)
123
121
 
124
122
  istek = await self.httpx.get(url)
125
123
  secici = HTMLHelper(istek.text)
126
- html_text = istek.text
127
-
128
- poster = self.fix_url(secici.select_attr("meta[property='og:image']", "content")) if secici.select_attr("meta[property='og:image']", "content") else None
129
-
130
- # Sidebar bilgilerini topla
131
- info = {}
132
- for li in secici.select("li"):
133
- key = secici.select_text("div.key", li)
134
- val = secici.select_text("div.value", li)
135
- if key and val:
136
- info[key.strip(":")] = val.strip()
137
-
138
- year = info.get("Yapım Yılı")
139
- rating = info.get("IMDB Puanı")
140
-
141
- tags_raw = info.get("Türler", "")
142
- tags = [t.strip() for t in tags_raw.split() if t.strip()] if tags_raw else None
143
-
144
- actors_raw = info.get("Oyuncular")
145
- actors = [a.strip() for a in actors_raw.split(",") if a.strip()] if actors_raw else None
146
124
 
125
+ poster = self.fix_url(secici.select_attr("meta[property='og:image']", "content"))
147
126
  description = secici.select_text("div.summary p")
148
-
149
- duration_raw = info.get("Ortalama Süre")
150
- duration = int(secici.regex_first(r"(\d+)", duration_raw)) if duration_raw else None
127
+ year = secici.meta_value("Yapım Yılı", container_selector="div.sidebar")
128
+ rating = secici.meta_value("IMDB Puanı", container_selector="div.sidebar")
129
+ duration = secici.meta_value("Ortalama Süre", container_selector="div.sidebar")
130
+ duration = int(secici.regex_first(r"(\d+)", duration)) if duration else None
131
+ tags = secici.meta_list("Türler", sep=" ", container_selector="div.sidebar")
132
+ actors = secici.meta_list("Oyuncular", container_selector="div.sidebar")
151
133
 
152
134
  if "/dizi/" in url:
153
135
  title = secici.select_text("div.cover h5")
154
-
155
136
  episodes = []
156
137
  for ep in secici.select("div.episode-item"):
157
- ep_name = secici.select_text("div.name", ep)
158
- ep_href = secici.select_attr("a", "href", ep)
159
- ep_text = secici.select_text("div.episode", ep)
160
- ep_parts = ep_text.split(" ")
161
-
162
- ep_season = None
163
- ep_episode = None
164
- if len(ep_parts) >= 4:
165
- try:
166
- ep_season = int(ep_parts[0].replace(".", ""))
167
- ep_episode = int(ep_parts[2].replace(".", ""))
168
- except ValueError:
169
- pass
170
-
171
- if ep_name and ep_href:
172
- episodes.append(Episode(
173
- season = ep_season,
174
- episode = ep_episode,
175
- title = ep_name,
176
- url = self.fix_url(ep_href),
177
- ))
138
+ name = secici.select_text("div.name", ep)
139
+ href = secici.select_attr("a", "href", ep)
140
+ text = secici.select_text("div.episode", ep)
141
+ if name and href:
142
+ s, e = secici.extract_season_episode(text or "")
143
+ episodes.append(Episode(season=s, episode=e, title=name, url=self.fix_url(href)))
178
144
 
179
145
  return SeriesInfo(
180
- url = url,
181
- poster = poster,
182
- title = title,
183
- description = description,
184
- tags = tags,
185
- rating = rating,
186
- year = year,
187
- duration = duration,
188
- episodes = episodes if episodes else None,
189
- actors = actors,
190
- )
191
- else:
192
- # Film için title - g-title div'lerinin 2. olanı
193
- g_titles = secici.select("div.g-title div")
194
- title = secici.select_text(element=g_titles[1]) if len(g_titles) >= 2 else None
195
-
196
- return MovieInfo(
197
- url = url,
198
- poster = poster,
199
- title = title,
200
- description = description,
201
- tags = tags,
202
- rating = rating,
203
- year = year,
204
- duration = duration,
205
- actors = actors,
146
+ url=url, poster=poster, title=title, description=description, tags=tags,
147
+ rating=rating, year=year, duration=duration, episodes=episodes or None, actors=actors
206
148
  )
149
+
150
+ # Film için title - g-title div'lerinin 2. olanı
151
+ g_titles = secici.select("div.g-title div")
152
+ title = secici.select_text(element=g_titles[1]) if len(g_titles) >= 2 else None
153
+
154
+ return MovieInfo(
155
+ url=url, poster=poster, title=title, description=description, tags=tags,
156
+ rating=rating, year=year, duration=duration, actors=actors
157
+ )
207
158
 
208
159
  async def load_links(self, url: str) -> list[ExtractResult]:
209
160
  # Reset headers to get HTML response
@@ -69,173 +69,65 @@ class DiziYou(PluginBase):
69
69
  async def load_item(self, url: str) -> SeriesInfo:
70
70
  istek = await self.httpx.get(url)
71
71
  secici = HTMLHelper(istek.text)
72
- html_text = istek.text
73
72
 
74
- # Title - div.title h1 içinde
75
- title = (secici.select_text("div.title h1") or "").strip()
76
-
77
- # Fallback: Eğer title boşsa URL'den çıkar (telif kısıtlaması olan sayfalar için)
78
- if not title:
79
- # URL'den slug'ı al: https://www.diziyou.one/jasmine/ -> jasmine -> Jasmine
80
- slug = url.rstrip('/').split('/')[-1]
81
- title = slug.replace('-', ' ').title()
82
-
83
- # Poster
84
- poster_src = secici.select_attr("div.category_image img", "src") or secici.select_attr("meta[property='og:image']", "content")
85
- poster = self.fix_url(poster_src) if poster_src else ""
86
-
87
- # Year - regex ile çıkarma (xpath yerine)
88
- year = secici.regex_first(r"(?is)Yapım Yılı.*?(\d{4})", secici.html)
89
-
90
- description_el = secici.select("div.diziyou_desc") or secici.select("div#icerikcat")
91
- description = ""
92
- if description_el:
93
- # Scriptleri temizle
94
- for script in secici.select("script", description_el[0]):
95
- script.decompose()
96
- description = secici.select_text(None, description_el[0])
97
-
98
- tags = [secici.select_text(None, a) for a in secici.select("div.genres a") if secici.select_text(None, a)]
99
-
100
- # Rating - daha spesifik regex ile
101
- rating = secici.regex_first(r"(?is)IMDB\s*:\s*</span>([0-9.]+)", secici.html)
102
-
103
- # Actors - regex ile
104
- actors_raw = secici.regex_first(r"(?is)Oyuncular.*?</span>([^<]+)", secici.html)
105
- actors = [actor.strip() for actor in actors_raw.split(",") if actor.strip()] if actors_raw else []
73
+ poster = secici.select_poster("div.category_image img")
74
+ title = secici.select_text("h1.title-border")
75
+ description = secici.select_direct_text("div#icerikcatright")
76
+ tags = secici.select_texts("div.genres a")
77
+ rating = secici.regex_first(r"(?is)IMDB\s*:\s*</span>([0-9.]+)", secici.html)
78
+ year = secici.extract_year("div#icerikcat2")
79
+ actors = secici.meta_value("Oyuncular", container_selector="div#icerikcat2")
80
+ actors = [a.strip() for a in actors.split(",")] if actors else []
106
81
 
107
82
  episodes = []
108
- # Episodes - div#scrollbar-container a (kısıtlı alan)
109
83
  for link in secici.select("div#scrollbar-container a"):
110
- ep_href = secici.select_attr(None, "href", link)
111
- if not ep_href:
112
- continue
113
-
114
- # Link metni veya alt başlık al
115
- ep_name = (secici.select_text(None, link) or "").strip()
116
- title_child = secici.select_text("div.baslik", link) or secici.select_text("div.bolumismi", link)
117
- if title_child:
118
- ep_name = title_child
119
-
120
- # Önce metin üzerinden sezon/bölüm çıkart
121
- s_val, e_val = HTMLHelper.extract_season_episode(ep_name)
122
-
123
- # URL bazlı kalıplar: -1-sezon-2-bolum gibi
124
- if not (s_val or e_val):
125
- pairs = HTMLHelper(ep_href).regex_all(r"-(\d+)-sezon-(\d+)-bolum")
126
- if pairs:
127
- s_val, e_val = int(pairs[0][0]), int(pairs[0][1])
128
- else:
129
- pairs = HTMLHelper(ep_href).regex_all(r"(\d+)-sezon-(\d+)-bolum")
130
- if pairs:
131
- s_val, e_val = int(pairs[0][0]), int(pairs[0][1])
132
- else:
133
- e_val_str = HTMLHelper(ep_href).regex_first(r"(\d+)-bolum")
134
- if e_val_str:
135
- e_val = int(e_val_str)
136
- # Metin üzerinden son bir deneme
137
- if not e_val:
138
- e_str = HTMLHelper(ep_name).regex_first(r"(\d+)\s*\.\s*[Bb]ölüm")
139
- if e_str:
140
- e_val = int(e_str)
141
- if not s_val:
142
- s_str = HTMLHelper(ep_name).regex_first(r"(\d+)\s*\.\s*[Ss]ezon")
143
- if s_str:
144
- s_val = int(s_str)
145
-
146
- if e_val or HTMLHelper(ep_href).regex_first(r"-\d+-sezon-\d+-bolum"):
147
- episodes.append(Episode(
148
- season = s_val,
149
- episode = e_val,
150
- title = ep_name if ep_name else None,
151
- url = self.fix_url(ep_href),
152
- ))
84
+ href = secici.select_attr(None, "href", link)
85
+ if href:
86
+ name = secici.select_text("div.bolumismi", link).strip("()")
87
+ s, e = secici.extract_season_episode(f"{name} {href}")
88
+ if e:
89
+ episodes.append(Episode(season=s or 1, episode=e, title=name, url=self.fix_url(href)))
153
90
 
154
91
  return SeriesInfo(
155
- url = url,
156
- poster = poster,
157
- title = title,
158
- description = description,
159
- tags = tags,
160
- rating = rating,
161
- year = year,
162
- episodes = episodes,
163
- actors = actors
92
+ url=url, poster=poster, title=title or "Bilinmiyor", description=description,
93
+ tags=tags, rating=rating, year=str(year) if year else None, episodes=episodes, actors=actors
164
94
  )
165
95
 
166
96
  async def load_links(self, url: str) -> list[ExtractResult]:
167
97
  istek = await self.httpx.get(url)
168
98
  secici = HTMLHelper(istek.text)
169
-
170
- # Title ve episode name - None kontrolü ekle
171
- item_title = secici.select_text("div.title h1")
172
- ep_name = secici.select_text("div#bolum-ismi")
173
99
 
174
- # Player src'den item_id çıkar
175
- # Player src'den item_id çıkar - önce özel player seçicisini dene
176
- player_src = None
177
- # Yaygın locatorlar
178
- for sel in ["iframe#diziyouPlayer", "div.player iframe", "iframe[src*='/player/']", "iframe[src*='/episodes/']", "iframe"]:
179
- p = secici.select_attr(sel, "src")
180
- if p and any(x in p.lower() for x in ["/player/", "/episodes/", "diziyou"]):
181
- player_src = p
182
- break
183
-
184
- # Eğer hâlâ bulunamadıysa, varsa bir bölüm sayfasına git ve oradan player'ı çek
185
- if not player_src:
186
- for a in secici.select("a"):
187
- href = secici.select_attr("a", "href", a)
188
- if not href:
189
- continue
190
- if HTMLHelper(href).regex_first(r"(-\d+-sezon-\d+-bolum|/bolum|/episode|/episodes|/play)"):
191
- break
192
-
193
- if not player_src:
194
- return [] # Player bulunamadıysa boş liste döndür
195
-
196
- item_id = player_src.split("/")[-1].replace(".html", "")
197
-
198
- subtitles = []
199
- stream_urls = []
200
-
201
- for secenek in secici.select("span.diziyouOption"):
202
- opt_id = secici.select_attr("span.diziyouOption", "id", secenek)
203
- op_name = secici.select_text("span.diziyouOption", secenek)
204
-
205
- match opt_id:
206
- case "turkceAltyazili":
207
- subtitles.append(Subtitle(
208
- name = op_name,
209
- url = self.fix_url(f"{self.main_url.replace('www', 'storage')}/subtitles/{item_id}/tr.vtt"),
210
- ))
211
- veri = {
212
- "dil": "Orjinal Dil (TR Altyazı)",
213
- "url": f"{self.main_url.replace('www', 'storage')}/episodes/{item_id}/play.m3u8"
214
- }
215
- if veri not in stream_urls:
216
- stream_urls.append(veri)
217
- case "ingilizceAltyazili":
218
- subtitles.append(Subtitle(
219
- name = op_name,
220
- url = self.fix_url(f"{self.main_url.replace('www', 'storage')}/subtitles/{item_id}/en.vtt"),
221
- ))
222
- veri = {
223
- "dil": "Orjinal Dil (EN Altyazı)",
224
- "url": f"{self.main_url.replace('www', 'storage')}/episodes/{item_id}/play.m3u8"
225
- }
226
- if veri not in stream_urls:
227
- stream_urls.append(veri)
228
- case "turkceDublaj":
229
- stream_urls.append({
230
- "dil": "Türkçe Dublaj",
231
- "url": f"{self.main_url.replace('www', 'storage')}/episodes/{item_id}_tr/play.m3u8"
232
- })
100
+ # Player iframe'inden ID'yi yakala
101
+ iframe_src = secici.select_attr("iframe#diziyouPlayer", "src") or secici.select_attr("iframe[src*='/player/']", "src")
102
+ if not iframe_src:
103
+ return []
104
+
105
+ item_id = iframe_src.split("/")[-1].replace(".html", "")
106
+ base_storage = self.main_url.replace("www", "storage")
107
+
108
+ subtitles = []
109
+ for sub in [("turkceAltyazili", "tr", "Türkçe"), ("ingilizceAltyazili", "en", "İngilizce")]:
110
+ if secici.select_first(f"span#{sub[0]}"):
111
+ subtitles.append(Subtitle(
112
+ name = f"{sub[2]} Altyazı",
113
+ url = f"{base_storage}/subtitles/{item_id}/{sub[1]}.vtt"
114
+ ))
233
115
 
234
116
  results = []
235
- for stream in stream_urls:
117
+ # Altyazılı Seçenek (Eğer varsa)
118
+ if secici.select_first("span#turkceAltyazili") or secici.select_first("span#ingilizceAltyazili"):
119
+ results.append(ExtractResult(
120
+ name = "Altyazılı",
121
+ url = f"{base_storage}/episodes/{item_id}/play.m3u8",
122
+ referer = url,
123
+ subtitles = subtitles
124
+ ))
125
+
126
+ # Dublaj Seçeneği (Eğer varsa)
127
+ if secici.select_first("span#turkceDublaj"):
236
128
  results.append(ExtractResult(
237
- url = stream.get("url"),
238
- name = f"{stream.get('dil')}",
129
+ name = "Türkçe Dublaj",
130
+ url = f"{base_storage}/episodes/{item_id}_tr/play.m3u8",
239
131
  referer = url,
240
132
  subtitles = subtitles
241
133
  ))