KekikStream 1.7.1__py3-none-any.whl → 2.0.2__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 (86) hide show
  1. KekikStream/Core/Extractor/ExtractorBase.py +13 -7
  2. KekikStream/Core/Extractor/ExtractorLoader.py +25 -17
  3. KekikStream/Core/Extractor/ExtractorManager.py +53 -9
  4. KekikStream/Core/Extractor/ExtractorModels.py +5 -7
  5. KekikStream/Core/Extractor/YTDLPCache.py +35 -0
  6. KekikStream/Core/Media/MediaHandler.py +44 -26
  7. KekikStream/Core/Media/MediaManager.py +0 -3
  8. KekikStream/Core/Plugin/PluginBase.py +21 -9
  9. KekikStream/Core/Plugin/PluginLoader.py +11 -7
  10. KekikStream/Core/Plugin/PluginModels.py +25 -26
  11. KekikStream/Core/__init__.py +1 -0
  12. KekikStream/Extractors/CloseLoad.py +4 -5
  13. KekikStream/Extractors/ContentX.py +4 -6
  14. KekikStream/Extractors/ContentX_.py +40 -0
  15. KekikStream/Extractors/DzenRu.py +38 -0
  16. KekikStream/Extractors/ExPlay.py +53 -0
  17. KekikStream/Extractors/FirePlayer.py +60 -0
  18. KekikStream/Extractors/HDPlayerSystem.py +41 -0
  19. KekikStream/Extractors/JetTv.py +45 -0
  20. KekikStream/Extractors/MailRu.py +3 -4
  21. KekikStream/Extractors/MixPlayHD.py +2 -3
  22. KekikStream/Extractors/MixTiger.py +57 -0
  23. KekikStream/Extractors/MolyStream.py +5 -5
  24. KekikStream/Extractors/Odnoklassniki.py +7 -7
  25. KekikStream/Extractors/{OkRuHTTP.py → Odnoklassniki_.py} +5 -1
  26. KekikStream/Extractors/PeaceMakerst.py +4 -5
  27. KekikStream/Extractors/{HDStreamAble.py → PeaceMakerst_.py} +1 -1
  28. KekikStream/Extractors/PixelDrain.py +1 -2
  29. KekikStream/Extractors/PlayerFilmIzle.py +62 -0
  30. KekikStream/Extractors/RapidVid.py +2 -3
  31. KekikStream/Extractors/RapidVid_.py +7 -0
  32. KekikStream/Extractors/SetPlay.py +57 -0
  33. KekikStream/Extractors/SetPrime.py +45 -0
  34. KekikStream/Extractors/SibNet.py +2 -3
  35. KekikStream/Extractors/Sobreatsesuyp.py +4 -5
  36. KekikStream/Extractors/TRsTX.py +4 -5
  37. KekikStream/Extractors/TauVideo.py +2 -3
  38. KekikStream/Extractors/TurboImgz.py +2 -3
  39. KekikStream/Extractors/TurkeyPlayer.py +34 -0
  40. KekikStream/Extractors/VidHide.py +72 -0
  41. KekikStream/Extractors/VidMoly.py +4 -5
  42. KekikStream/Extractors/{VidMolyMe.py → VidMoly_.py} +1 -1
  43. KekikStream/Extractors/VidMoxy.py +2 -3
  44. KekikStream/Extractors/VidPapi.py +89 -0
  45. KekikStream/Extractors/VideoSeyred.py +3 -4
  46. KekikStream/Extractors/YTDLP.py +177 -0
  47. KekikStream/Extractors/YildizKisaFilm.py +41 -0
  48. KekikStream/Plugins/DiziBox.py +18 -23
  49. KekikStream/Plugins/DiziPal.py +16 -16
  50. KekikStream/Plugins/DiziYou.py +48 -23
  51. KekikStream/Plugins/Dizilla.py +47 -32
  52. KekikStream/Plugins/FilmBip.py +145 -0
  53. KekikStream/Plugins/FilmMakinesi.py +6 -8
  54. KekikStream/Plugins/FilmModu.py +9 -9
  55. KekikStream/Plugins/FullHDFilm.py +164 -0
  56. KekikStream/Plugins/FullHDFilmizlesene.py +4 -8
  57. KekikStream/Plugins/HDFilmCehennemi.py +15 -19
  58. KekikStream/Plugins/JetFilmizle.py +67 -49
  59. KekikStream/Plugins/KultFilmler.py +219 -0
  60. KekikStream/Plugins/RecTV.py +18 -22
  61. KekikStream/Plugins/RoketDizi.py +232 -0
  62. KekikStream/Plugins/SelcukFlix.py +309 -0
  63. KekikStream/Plugins/SezonlukDizi.py +12 -13
  64. KekikStream/Plugins/SineWix.py +8 -12
  65. KekikStream/Plugins/Sinefy.py +238 -0
  66. KekikStream/Plugins/SinemaCX.py +157 -0
  67. KekikStream/Plugins/Sinezy.py +146 -0
  68. KekikStream/Plugins/SuperFilmGeldi.py +121 -0
  69. KekikStream/Plugins/UgurFilm.py +7 -11
  70. KekikStream/__init__.py +34 -24
  71. KekikStream/requirements.txt +3 -4
  72. kekikstream-2.0.2.dist-info/METADATA +309 -0
  73. kekikstream-2.0.2.dist-info/RECORD +82 -0
  74. KekikStream/Extractors/FourCX.py +0 -7
  75. KekikStream/Extractors/FourPichive.py +0 -7
  76. KekikStream/Extractors/FourPlayRu.py +0 -7
  77. KekikStream/Extractors/Hotlinger.py +0 -7
  78. KekikStream/Extractors/OkRuSSL.py +0 -7
  79. KekikStream/Extractors/Pichive.py +0 -7
  80. KekikStream/Extractors/PlayRu.py +0 -7
  81. kekikstream-1.7.1.dist-info/METADATA +0 -109
  82. kekikstream-1.7.1.dist-info/RECORD +0 -63
  83. {kekikstream-1.7.1.dist-info → kekikstream-2.0.2.dist-info}/WHEEL +0 -0
  84. {kekikstream-1.7.1.dist-info → kekikstream-2.0.2.dist-info}/entry_points.txt +0 -0
  85. {kekikstream-1.7.1.dist-info → kekikstream-2.0.2.dist-info}/licenses/LICENSE +0 -0
  86. {kekikstream-1.7.1.dist-info → kekikstream-2.0.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,41 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import ExtractorBase, ExtractResult
4
+
5
+ class YildizKisaFilm(ExtractorBase):
6
+ name = "YildizKisaFilm"
7
+ main_url = "https://yildizkisafilm.org"
8
+
9
+ async def extract(self, url, referer=None) -> ExtractResult:
10
+ ext_ref = referer or ""
11
+
12
+ if "video/" in url:
13
+ vid_id = url.split("video/")[-1]
14
+ else:
15
+ vid_id = url.split("?data=")[-1]
16
+
17
+ post_url = f"{self.main_url}/player/index.php?data={vid_id}&do=getVideo"
18
+
19
+ response = await self.httpx.post(
20
+ url = post_url,
21
+ data = {"hash": vid_id, "r": ext_ref},
22
+ headers = {
23
+ "Referer" : ext_ref,
24
+ "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
25
+ "X-Requested-With" : "XMLHttpRequest"
26
+ }
27
+ )
28
+ response.raise_for_status()
29
+
30
+ video_data = response.json()
31
+ m3u_link = video_data.get("securedLink")
32
+
33
+ if not m3u_link:
34
+ raise ValueError("securedLink not found in response")
35
+
36
+ return ExtractResult(
37
+ name = self.name,
38
+ url = m3u_link,
39
+ referer = ext_ref,
40
+ subtitles = []
41
+ )
@@ -1,6 +1,6 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from KekikStream.Core import kekik_cache, PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode
4
4
  from Kekik.Sifreleme import CryptoJS
5
5
  from parsel import Selector
6
6
  import re, urllib.parse, base64, contextlib, asyncio, time
@@ -40,15 +40,14 @@ class DiziBox(PluginBase):
40
40
  f"{main_url}/dizi-arsivi/page/SAYFA/?tur[0]=yarisma&yil&imdb" : "Yarışma"
41
41
  }
42
42
 
43
- #@kekik_cache(ttl=60*60)
44
43
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
45
- self.cffi.cookies.update({
44
+ self.httpx.cookies.update({
46
45
  "isTrustedUser" : "true",
47
46
  "dbxu" : str(time.time() * 1000).split(".")[0]
48
47
  })
49
- istek = await self.cffi.get(
48
+ istek = await self.httpx.get(
50
49
  url = f"{url.replace('SAYFA', str(page))}",
51
- allow_redirects = True
50
+ follow_redirects = True
52
51
  )
53
52
  secici = Selector(istek.text)
54
53
 
@@ -62,13 +61,12 @@ class DiziBox(PluginBase):
62
61
  for veri in secici.css("article.detailed-article")
63
62
  ]
64
63
 
65
- #@kekik_cache(ttl=60*60)
66
64
  async def search(self, query: str) -> list[SearchResult]:
67
- self.cffi.cookies.update({
65
+ self.httpx.cookies.update({
68
66
  "isTrustedUser" : "true",
69
67
  "dbxu" : str(time.time() * 1000).split(".")[0]
70
68
  })
71
- istek = await self.cffi.get(f"{self.main_url}/?s={query}")
69
+ istek = await self.httpx.get(f"{self.main_url}/?s={query}")
72
70
  secici = Selector(istek.text)
73
71
 
74
72
  return [
@@ -80,9 +78,8 @@ class DiziBox(PluginBase):
80
78
  for item in secici.css("article.detailed-article")
81
79
  ]
82
80
 
83
- #@kekik_cache(ttl=60*60)
84
81
  async def load_item(self, url: str) -> SeriesInfo:
85
- istek = await self.cffi.get(url)
82
+ istek = await self.httpx.get(url)
86
83
  secici = Selector(istek.text)
87
84
 
88
85
  title = secici.css("div.tv-overview h1 a::text").get()
@@ -96,7 +93,7 @@ class DiziBox(PluginBase):
96
93
  episodes = []
97
94
  for sezon_link in secici.css("div#seasons-list a::attr(href)").getall():
98
95
  sezon_url = self.fix_url(sezon_link)
99
- sezon_istek = await self.cffi.get(sezon_url)
96
+ sezon_istek = await self.httpx.get(sezon_url)
100
97
  sezon_secici = Selector(sezon_istek.text)
101
98
 
102
99
  for bolum in sezon_secici.css("article.grid-box"):
@@ -127,12 +124,11 @@ class DiziBox(PluginBase):
127
124
  actors = actors,
128
125
  )
129
126
 
130
- #@kekik_cache(ttl=60*60)
131
127
  async def _iframe_decode(self, name:str, iframe_link:str, referer:str) -> list[str]:
132
128
  results = []
133
129
 
134
- self.cffi.headers.update({"Referer": referer})
135
- self.cffi.cookies.update({
130
+ self.httpx.headers.update({"Referer": referer})
131
+ self.httpx.cookies.update({
136
132
  "isTrustedUser" : "true",
137
133
  "dbxu" : str(time.time() * 1000).split(".")[0]
138
134
  })
@@ -140,12 +136,12 @@ class DiziBox(PluginBase):
140
136
  if "/player/king/king.php" in iframe_link:
141
137
  iframe_link = iframe_link.replace("king.php?v=", "king.php?wmode=opaque&v=")
142
138
 
143
- istek = await self.cffi.get(iframe_link)
139
+ istek = await self.httpx.get(iframe_link)
144
140
  secici = Selector(istek.text)
145
141
  iframe = secici.css("div#Player iframe::attr(src)").get()
146
142
 
147
- self.cffi.headers.update({"Referer": self.main_url})
148
- istek = await self.cffi.get(iframe)
143
+ self.httpx.headers.update({"Referer": self.main_url})
144
+ istek = await self.httpx.get(iframe)
149
145
 
150
146
  crypt_data = re.search(r"CryptoJS\.AES\.decrypt\(\"(.*)\",\"", istek.text)[1]
151
147
  crypt_pass = re.search(r"\",\"(.*)\"\);", istek.text)[1]
@@ -161,7 +157,7 @@ class DiziBox(PluginBase):
161
157
  while True:
162
158
  await asyncio.sleep(.3)
163
159
  with contextlib.suppress(Exception):
164
- istek = await self.cffi.get(iframe_link)
160
+ istek = await self.httpx.get(iframe_link)
165
161
 
166
162
  if atob_data := re.search(r"unescape\(\"(.*)\"\)", istek.text):
167
163
  decoded_atob = urllib.parse.unquote(atob_data[1])
@@ -178,9 +174,8 @@ class DiziBox(PluginBase):
178
174
 
179
175
  return results
180
176
 
181
- #@kekik_cache(ttl=15*60)
182
177
  async def load_links(self, url: str) -> list[dict]:
183
- istek = await self.cffi.get(url)
178
+ istek = await self.httpx.get(url)
184
179
  secici = Selector(istek.text)
185
180
 
186
181
  results = []
@@ -200,8 +195,8 @@ class DiziBox(PluginBase):
200
195
  if not alt_link:
201
196
  continue
202
197
 
203
- self.cffi.headers.update({"Referer": url})
204
- alt_istek = await self.cffi.get(alt_link)
198
+ self.httpx.headers.update({"Referer": url})
199
+ alt_istek = await self.httpx.get(alt_link)
205
200
  alt_istek.raise_for_status()
206
201
 
207
202
  alt_secici = Selector(alt_istek.text)
@@ -214,4 +209,4 @@ class DiziBox(PluginBase):
214
209
  "name" : f"{extractor.name if extractor else alt_name}"
215
210
  })
216
211
 
217
- return results
212
+ return results
@@ -7,9 +7,9 @@ import re
7
7
  class DiziPal(PluginBase):
8
8
  name = "DiziPal"
9
9
  language = "tr"
10
- main_url = "https://dizipal1222.com"
10
+ main_url = "https://dizipal1223.com"
11
11
  favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
12
- description = "Yabancı Dizi ve Film izle."
12
+ description = "dizipal güncel, dizipal yeni ve gerçek adresi. dizipal en yeni dizi ve filmleri güvenli ve hızlı şekilde sunar."
13
13
 
14
14
  main_page = {
15
15
  f"{main_url}/diziler/son-bolumler" : "Son Bölümler",
@@ -26,7 +26,7 @@ class DiziPal(PluginBase):
26
26
  }
27
27
 
28
28
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
29
- istek = await self.cffi.get(url)
29
+ istek = await self.httpx.get(url)
30
30
  secici = Selector(istek.text)
31
31
 
32
32
  results = []
@@ -67,12 +67,12 @@ class DiziPal(PluginBase):
67
67
  return results
68
68
 
69
69
  async def search(self, query: str) -> list[SearchResult]:
70
- self.cffi.headers.update({
70
+ self.httpx.headers.update({
71
71
  "Accept" : "application/json, text/javascript, */*; q=0.01",
72
72
  "X-Requested-With" : "XMLHttpRequest"
73
73
  })
74
74
 
75
- istek = await self.cffi.post(
75
+ istek = await self.httpx.post(
76
76
  url = f"{self.main_url}/api/search-autocomplete",
77
77
  data = {"query": query}
78
78
  )
@@ -106,12 +106,12 @@ class DiziPal(PluginBase):
106
106
 
107
107
  async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
108
108
  # Reset headers to get HTML response
109
- self.cffi.headers.update({
109
+ self.httpx.headers.update({
110
110
  "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
111
111
  })
112
- self.cffi.headers.pop("X-Requested-With", None)
112
+ self.httpx.headers.pop("X-Requested-With", None)
113
113
 
114
- istek = await self.cffi.get(url)
114
+ istek = await self.httpx.get(url)
115
115
  secici = Selector(text=istek.text, type="html")
116
116
 
117
117
  poster = self.fix_url(secici.css("meta[property='og:image']::attr(content)").get())
@@ -179,12 +179,12 @@ class DiziPal(PluginBase):
179
179
 
180
180
  async def load_links(self, url: str) -> list[dict]:
181
181
  # Reset headers to get HTML response
182
- self.cffi.headers.update({
182
+ self.httpx.headers.update({
183
183
  "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
184
184
  })
185
- self.cffi.headers.pop("X-Requested-With", None)
185
+ self.httpx.headers.pop("X-Requested-With", None)
186
186
 
187
- istek = await self.cffi.get(url)
187
+ istek = await self.httpx.get(url)
188
188
  secici = Selector(istek.text)
189
189
 
190
190
  iframe = secici.css(".series-player-container iframe::attr(src)").get()
@@ -196,8 +196,8 @@ class DiziPal(PluginBase):
196
196
 
197
197
  results = []
198
198
 
199
- self.cffi.headers.update({"Referer": f"{self.main_url}/"})
200
- i_istek = await self.cffi.get(iframe)
199
+ self.httpx.headers.update({"Referer": f"{self.main_url}/"})
200
+ i_istek = await self.httpx.get(iframe)
201
201
  i_text = i_istek.text
202
202
 
203
203
  # m3u link çıkar
@@ -237,9 +237,9 @@ class DiziPal(PluginBase):
237
237
 
238
238
  return results
239
239
 
240
- async def play(self, name: str, url: str, referer: str, subtitles: list[Subtitle]):
241
- extract_result = ExtractResult(name=name, url=url, referer=referer, subtitles=subtitles)
242
- self.media_handler.title = name
240
+ async def play(self, **kwargs):
241
+ extract_result = ExtractResult(**kwargs)
242
+ self.media_handler.title = kwargs.get("name")
243
243
  if self.name not in self.media_handler.title:
244
244
  self.media_handler.title = f"{self.name} | {self.media_handler.title}"
245
245
 
@@ -1,6 +1,6 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from KekikStream.Core import kekik_cache, PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, Subtitle, ExtractResult
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, Subtitle, ExtractResult
4
4
  from parsel import Selector
5
5
  import re
6
6
 
@@ -29,9 +29,8 @@ class DiziYou(PluginBase):
29
29
  f"{main_url}/dizi-arsivi/page/SAYFA/?tur=Vah%C5%9Fi+Bat%C4%B1" : "Vahşi Batı"
30
30
  }
31
31
 
32
- #@kekik_cache(ttl=60*60)
33
32
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
34
- istek = await self.cffi.get(f"{url.replace('SAYFA', str(page))}")
33
+ istek = await self.httpx.get(f"{url.replace('SAYFA', str(page))}")
35
34
  secici = Selector(istek.text)
36
35
 
37
36
  return [
@@ -44,27 +43,36 @@ class DiziYou(PluginBase):
44
43
  for veri in secici.css("div.single-item")
45
44
  ]
46
45
 
47
- #@kekik_cache(ttl=60*60)
48
46
  async def search(self, query: str) -> list[SearchResult]:
49
- istek = await self.cffi.get(f"{self.main_url}/?s={query}")
47
+ istek = await self.httpx.get(f"{self.main_url}/?s={query}")
50
48
  secici = Selector(istek.text)
51
49
 
52
50
  return [
53
51
  SearchResult(
54
52
  title = afis.css("div#categorytitle a::text").get().strip(),
55
53
  url = self.fix_url(afis.css("div#categorytitle a::attr(href)").get()),
56
- poster = self.fix_url(afis.css("img::attr(src)").get()),
54
+ poster = self.fix_url(afis.css("img::attr(src)").get() or afis.css("img::attr(data-src)").get())
57
55
  )
58
56
  for afis in secici.css("div.incontent div#list-series")
59
57
  ]
60
58
 
61
- #@kekik_cache(ttl=60*60)
62
59
  async def load_item(self, url: str) -> SeriesInfo:
63
- istek = await self.cffi.get(url)
60
+ istek = await self.httpx.get(url)
64
61
  secici = Selector(istek.text)
65
62
 
66
- title = secici.css("h1::text").get().strip()
67
- poster = self.fix_url(secici.css("div.category_image img::attr(src)").get().strip())
63
+ # Title - div.title h1 içinde
64
+ title_raw = secici.css("div.title h1::text").get()
65
+ title = title_raw.strip() if title_raw else ""
66
+
67
+ # Fallback: Eğer title boşsa URL'den çıkar (telif kısıtlaması olan sayfalar için)
68
+ if not title:
69
+ # URL'den slug'ı al: https://www.diziyou.one/jasmine/ -> jasmine -> Jasmine
70
+ slug = url.rstrip('/').split('/')[-1]
71
+ title = slug.replace('-', ' ').title()
72
+
73
+ # Poster
74
+ poster_raw = secici.css("div.category_image img::attr(src)").get()
75
+ poster = self.fix_url(poster_raw) if poster_raw else ""
68
76
  year = secici.xpath("//span[contains(., 'Yapım Yılı')]/following-sibling::text()[1]").get()
69
77
  description = secici.css("div.diziyou_desc::text").get()
70
78
  if description:
@@ -75,13 +83,21 @@ class DiziYou(PluginBase):
75
83
  actors = [actor.strip() for actor in _actors.split(",")] if _actors else []
76
84
 
77
85
  episodes = []
78
- for it in secici.css("div.bolumust"):
79
- ep_name = it.css("div.baslik::text").get().strip()
80
- ep_href = it.xpath("ancestor::a/@href").get()
81
- if not ep_name or not ep_href:
86
+ # Episodes - bolumust her bölüm için bir <a> içinde
87
+ # :has() parsel'de çalışmıyor, XPath kullanıyoruz
88
+ for link in secici.xpath('//a[div[@class="bolumust"]]'):
89
+ ep_name_raw = link.css("div.baslik::text").get()
90
+ if not ep_name_raw:
91
+ continue
92
+ ep_name = ep_name_raw.strip()
93
+
94
+ ep_href = self.fix_url(link.css("::attr(href)").get())
95
+ if not ep_href:
82
96
  continue
83
97
 
84
- ep_name_clean = it.css("div.bolumismi::text").get().strip().replace("(", "").replace(")", "").strip() if it.css("div.bolumismi::text").get() else ep_name
98
+ # Bölüm ismi varsa al
99
+ ep_name_raw_clean = link.css("div.bolumismi::text").get()
100
+ ep_name_clean = ep_name_raw_clean.strip().replace("(", "").replace(")", "").strip() if ep_name_raw_clean else ep_name
85
101
 
86
102
  ep_episode = re.search(r"(\d+)\. Bölüm", ep_name)[1]
87
103
  ep_season = re.search(r"(\d+)\. Sezon", ep_name)[1]
@@ -107,14 +123,23 @@ class DiziYou(PluginBase):
107
123
  actors = actors
108
124
  )
109
125
 
110
- #@kekik_cache(ttl=15*60)
111
126
  async def load_links(self, url: str) -> list[dict]:
112
- istek = await self.cffi.get(url)
127
+ istek = await self.httpx.get(url)
113
128
  secici = Selector(istek.text)
114
129
 
115
- item_title = secici.css("div.title h1::text").get()
116
- ep_name = secici.css("div#bolum-ismi::text").get().strip()
117
- item_id = secici.css("iframe#diziyouPlayer::attr(src)").get().split("/")[-1].replace(".html", "")
130
+ # Title ve episode name - None kontrolü ekle
131
+ item_title_raw = secici.css("div.title h1::text").get()
132
+ item_title = item_title_raw.strip() if item_title_raw else ""
133
+
134
+ ep_name_raw = secici.css("div#bolum-ismi::text").get()
135
+ ep_name = ep_name_raw.strip() if ep_name_raw else ""
136
+
137
+ # Player src'den item_id çıkar
138
+ player_src = secici.css("iframe#diziyouPlayer::attr(src)").get()
139
+ if not player_src:
140
+ return [] # Player bulunamadıysa boş liste döndür
141
+
142
+ item_id = player_src.split("/")[-1].replace(".html", "")
118
143
 
119
144
  subtitles = []
120
145
  stream_urls = []
@@ -163,9 +188,9 @@ class DiziYou(PluginBase):
163
188
 
164
189
  return results
165
190
 
166
- async def play(self, name: str, url: str, referer: str, subtitles: list[Subtitle]):
167
- extract_result = ExtractResult(name=name, url=url, referer=referer, subtitles=subtitles)
168
- self.media_handler.title = name
191
+ async def play(self, **kwargs):
192
+ extract_result = ExtractResult(**kwargs)
193
+ self.media_handler.title = kwargs.get("name")
169
194
  if self.name not in self.media_handler.title:
170
195
  self.media_handler.title = f"{self.name} | {self.media_handler.title}"
171
196
 
@@ -1,6 +1,6 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from KekikStream.Core import kekik_cache, PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode
4
4
  from parsel import Selector
5
5
  from json import loads
6
6
  from urllib.parse import urlparse, urlunparse
@@ -12,36 +12,47 @@ class Dizilla(PluginBase):
12
12
  language = "tr"
13
13
  main_url = "https://dizilla40.com"
14
14
  favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
15
- description = "Dizilla tüm yabancı dizileri ücretsiz olarak Türkçe Dublaj ve altyazılı seçenekleri ile 1080P kalite izleyebileceğiniz yeni nesil yabancı dizi izleme siteniz."
15
+ description = "1080p yabancı dizi izle. Türkçe altyazılı veya dublaj seçenekleriyle 1080p çözünürlükte yabancı dizilere anında ulaş. Popüler dizileri kesintisiz izle."
16
16
 
17
17
  main_page = {
18
- f"{main_url}/tum-bolumler" : "Altyazılı Bölümler",
19
- f"{main_url}/dublaj-bolumler" : "Dublaj Bölümler",
20
- f"{main_url}/dizi-turu/aile" : "Aile",
21
- f"{main_url}/dizi-turu/aksiyon" : "Aksiyon",
22
- f"{main_url}/dizi-turu/bilim-kurgu" : "Bilim Kurgu",
23
- f"{main_url}/dizi-turu/romantik" : "Romantik",
24
- f"{main_url}/dizi-turu/komedi" : "Komedi"
18
+ f"{main_url}/tum-bolumler" : "Altyazılı Bölümler",
19
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=15&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Aile",
20
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=9&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Aksiyon",
21
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=17&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Animasyon",
22
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=5&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Bilim Kurgu",
23
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=2&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Dram",
24
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=12&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Fantastik",
25
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=18&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Gerilim",
26
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=3&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Gizem",
27
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=4&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Komedi",
28
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=8&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Korku",
29
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=24&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Macera",
30
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=7&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Romantik",
31
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=26&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Savaş",
32
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=1&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Suç",
33
+ f"{main_url}/api/bg/findSeries?releaseYearStart=1900&releaseYearEnd=2050&imdbPointMin=0&imdbPointMax=10&categoryIdsComma=11&countryIdsComma=&orderType=date_desc&languageId=-1&currentPage=SAYFA&currentPageCount=24&queryStr=&categorySlugsComma=&countryCodesComma=" : "Western",
25
34
  }
26
35
 
27
- #@kekik_cache(ttl=60*60)
28
36
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
29
- istek = await self.cffi.get(url)
30
- secici = Selector(istek.text)
31
-
32
37
  ana_sayfa = []
33
38
 
34
- if "dizi-turu" in url:
39
+ if "api/bg" in url:
40
+ istek = await self.httpx.post(url.replace("SAYFA", str(page)))
41
+ decrypted = await self.decrypt_response(istek.json().get("response"))
42
+ veriler = decrypted.get("result", [])
35
43
  ana_sayfa.extend([
36
44
  MainPageResult(
37
45
  category = category,
38
- title = veri.css("h2::text").get(),
39
- url = self.fix_url(veri.css("::attr(href)").get()),
40
- poster = self.fix_url(veri.css("img::attr(src)").get() or veri.css("img::attr(data-src)").get())
46
+ title = veri.get("original_title"),
47
+ url = self.fix_url(f"{self.main_url}/{veri.get('used_slug')}"),
48
+ poster = self.fix_url(veri.get("object_poster_url")),
41
49
  )
42
- for veri in secici.css("div.grid-cols-3 a")
50
+ for veri in veriler
43
51
  ])
44
52
  else:
53
+ istek = await self.httpx.get(url.replace("SAYFA", str(page)))
54
+ secici = Selector(istek.text)
55
+
45
56
  for veri in secici.css("div.tab-content > div.grid a"):
46
57
  name = veri.css("h2::text").get()
47
58
  ep_name = veri.xpath("normalize-space(//div[contains(@class, 'opacity-80')])").get()
@@ -51,7 +62,7 @@ class Dizilla(PluginBase):
51
62
  ep_name = ep_name.replace(". Sezon", "x").replace(". Bölüm", "").replace("x ", "x")
52
63
  title = f"{name} - {ep_name}"
53
64
 
54
- ep_req = await self.cffi.get(self.fix_url(veri.css("::attr(href)").get()))
65
+ ep_req = await self.httpx.get(self.fix_url(veri.css("::attr(href)").get()))
55
66
  ep_secici = Selector(ep_req.text)
56
67
  href = self.fix_url(ep_secici.css("nav li:nth-of-type(3) a::attr(href)").get())
57
68
  poster = self.fix_url(ep_secici.css("img.imgt::attr(src)").get())
@@ -88,9 +99,8 @@ class Dizilla(PluginBase):
88
99
  # JSON decode
89
100
  return loads(decrypted.decode("utf-8"))
90
101
 
91
- #@kekik_cache(ttl=60*60)
92
102
  async def search(self, query: str) -> list[SearchResult]:
93
- arama_istek = await self.cffi.post(f"{self.main_url}/api/bg/searchcontent?searchterm={query}")
103
+ arama_istek = await self.httpx.post(f"{self.main_url}/api/bg/searchcontent?searchterm={query}")
94
104
  decrypted = await self.decrypt_response(arama_istek.json().get("response"))
95
105
  arama_veri = decrypted.get("result", [])
96
106
 
@@ -103,7 +113,6 @@ class Dizilla(PluginBase):
103
113
  for veri in arama_veri
104
114
  ]
105
115
 
106
- #@kekik_cache(ttl=60*60)
107
116
  async def url_base_degis(self, eski_url:str, yeni_base:str) -> str:
108
117
  parsed_url = urlparse(eski_url)
109
118
  parsed_yeni_base = urlparse(yeni_base)
@@ -114,27 +123,34 @@ class Dizilla(PluginBase):
114
123
 
115
124
  return urlunparse(yeni_url)
116
125
 
117
- #@kekik_cache(ttl=60*60)
118
126
  async def load_item(self, url: str) -> SeriesInfo:
119
- istek = await self.cffi.get(url)
127
+ istek = await self.httpx.get(url)
120
128
  secici = Selector(istek.text)
121
129
  veri = loads(secici.xpath("//script[@type='application/ld+json']/text()").getall()[-1])
122
130
 
123
- title = veri.get("name")
131
+ title = veri.get("name")
124
132
  if alt_title := veri.get("alternateName"):
125
133
  title += f" - ({alt_title})"
126
134
 
127
135
  poster = self.fix_url(veri.get("image"))
128
136
  description = veri.get("description")
129
137
  year = veri.get("datePublished").split("-")[0]
130
- tags = []
131
- rating = veri.get("aggregateRating", {}).get("ratingValue")
132
- actors = [actor.get("name") for actor in veri.get("actor", []) if actor.get("name")]
138
+
139
+ # Tags extraction from page content (h3 tag)
140
+ tags_raw = secici.css("div.poster.poster h3::text").get()
141
+ tags = [t.strip() for t in tags_raw.split(",")] if tags_raw else []
142
+
143
+ rating = veri.get("aggregateRating", {}).get("ratingValue")
144
+ actors = [actor.get("name") for actor in veri.get("actor", []) if actor.get("name")]
133
145
 
134
146
  bolumler = []
135
147
  sezonlar = veri.get("containsSeason") if isinstance(veri.get("containsSeason"), list) else [veri.get("containsSeason")]
136
148
  for sezon in sezonlar:
137
- for bolum in sezon.get("episode"):
149
+ episodes = sezon.get("episode")
150
+ if isinstance(episodes, dict):
151
+ episodes = [episodes]
152
+
153
+ for bolum in episodes:
138
154
  bolumler.append(Episode(
139
155
  season = sezon.get("seasonNumber"),
140
156
  episode = bolum.get("episodeNumber"),
@@ -154,9 +170,8 @@ class Dizilla(PluginBase):
154
170
  actors = actors
155
171
  )
156
172
 
157
- #@kekik_cache(ttl=15*60)
158
173
  async def load_links(self, url: str) -> list[dict]:
159
- istek = await self.cffi.get(url)
174
+ istek = await self.httpx.get(url)
160
175
  secici = Selector(istek.text)
161
176
 
162
177
  next_data = loads(secici.css("script#__NEXT_DATA__::text").get())
@@ -177,4 +192,4 @@ class Dizilla(PluginBase):
177
192
  "name" : f"{extractor.name if extractor else 'Main Player'} | {result.get('language_name')}",
178
193
  })
179
194
 
180
- return links
195
+ return links