KekikStream 2.1.3__tar.gz → 2.1.5__tar.gz

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-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/CloseLoad.py +17 -2
  2. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/FilmMakinesi.py +9 -5
  3. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/FullHDFilm.py +68 -17
  4. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/HDFilmCehennemi.py +61 -21
  5. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/SelcukFlix.py +66 -42
  6. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream.egg-info/PKG-INFO +3 -1
  7. {kekikstream-2.1.3 → kekikstream-2.1.5}/PKG-INFO +3 -1
  8. {kekikstream-2.1.3 → kekikstream-2.1.5}/README.md +2 -0
  9. {kekikstream-2.1.3 → kekikstream-2.1.5}/setup.py +1 -1
  10. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/CLI/__init__.py +0 -0
  11. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/CLI/pypi_kontrol.py +0 -0
  12. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Extractor/ExtractorBase.py +0 -0
  13. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Extractor/ExtractorLoader.py +0 -0
  14. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Extractor/ExtractorManager.py +0 -0
  15. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Extractor/ExtractorModels.py +0 -0
  16. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Extractor/YTDLPCache.py +0 -0
  17. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Media/MediaHandler.py +0 -0
  18. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Media/MediaManager.py +0 -0
  19. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Plugin/PluginBase.py +0 -0
  20. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Plugin/PluginLoader.py +0 -0
  21. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Plugin/PluginManager.py +0 -0
  22. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/Plugin/PluginModels.py +0 -0
  23. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/UI/UIManager.py +0 -0
  24. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Core/__init__.py +0 -0
  25. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/ContentX.py +0 -0
  26. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/DonilasPlay.py +0 -0
  27. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/DzenRu.py +0 -0
  28. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/ExPlay.py +0 -0
  29. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/HDPlayerSystem.py +0 -0
  30. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/JetTv.py +0 -0
  31. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/MailRu.py +0 -0
  32. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/MixPlayHD.py +0 -0
  33. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/MixTiger.py +0 -0
  34. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/MolyStream.py +0 -0
  35. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/Odnoklassniki.py +0 -0
  36. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/PeaceMakerst.py +0 -0
  37. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/PixelDrain.py +0 -0
  38. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/PlayerFilmIzle.py +0 -0
  39. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/RapidVid.py +0 -0
  40. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/SetPlay.py +0 -0
  41. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/SetPrime.py +0 -0
  42. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/SibNet.py +0 -0
  43. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/Sobreatsesuyp.py +0 -0
  44. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/TRsTX.py +0 -0
  45. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/TauVideo.py +0 -0
  46. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/TurboImgz.py +0 -0
  47. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/TurkeyPlayer.py +0 -0
  48. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/VCTPlay.py +0 -0
  49. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/VidHide.py +0 -0
  50. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/VidMoly.py +0 -0
  51. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/VidMoxy.py +0 -0
  52. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/VidPapi.py +0 -0
  53. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/VideoSeyred.py +0 -0
  54. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/YTDLP.py +0 -0
  55. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Extractors/YildizKisaFilm.py +0 -0
  56. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/BelgeselX.py +0 -0
  57. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/DiziBox.py +0 -0
  58. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/DiziPal.py +0 -0
  59. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/DiziYou.py +0 -0
  60. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/Dizilla.py +0 -0
  61. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/FilmBip.py +0 -0
  62. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/FilmModu.py +0 -0
  63. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/FullHDFilmizlesene.py +0 -0
  64. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/JetFilmizle.py +0 -0
  65. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/KultFilmler.py +0 -0
  66. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/RecTV.py +0 -0
  67. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/RoketDizi.py +0 -0
  68. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/SetFilmIzle.py +0 -0
  69. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/SezonlukDizi.py +0 -0
  70. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/SineWix.py +0 -0
  71. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/Sinefy.py +0 -0
  72. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/SinemaCX.py +0 -0
  73. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/Sinezy.py +0 -0
  74. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/SuperFilmGeldi.py +0 -0
  75. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/Plugins/UgurFilm.py +0 -0
  76. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/__init__.py +0 -0
  77. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/__main__.py +0 -0
  78. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream/requirements.txt +0 -0
  79. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream.egg-info/SOURCES.txt +0 -0
  80. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream.egg-info/dependency_links.txt +0 -0
  81. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream.egg-info/entry_points.txt +0 -0
  82. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream.egg-info/requires.txt +0 -0
  83. {kekikstream-2.1.3 → kekikstream-2.1.5}/KekikStream.egg-info/top_level.txt +0 -0
  84. {kekikstream-2.1.3 → kekikstream-2.1.5}/LICENSE +0 -0
  85. {kekikstream-2.1.3 → kekikstream-2.1.5}/MANIFEST.in +0 -0
  86. {kekikstream-2.1.3 → kekikstream-2.1.5}/setup.cfg +0 -0
@@ -1,7 +1,8 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
- from KekikStream.Core import ExtractorBase, ExtractResult
3
+ from KekikStream.Core import ExtractorBase, ExtractResult, Subtitle
4
4
  from Kekik.Sifreleme import Packer, StreamDecoder
5
+ from parsel import Selector
5
6
  import re
6
7
 
7
8
  class CloseLoadExtractor(ExtractorBase):
@@ -15,12 +16,26 @@ class CloseLoadExtractor(ExtractorBase):
15
16
  istek = await self.httpx.get(url)
16
17
  istek.raise_for_status()
17
18
 
19
+ # Video URL'sini çıkar
18
20
  eval_func = re.compile(r'\s*(eval\(function[\s\S].*)\s*').findall(istek.text)[0]
19
21
  m3u_link = StreamDecoder.extract_stream_url(Packer.unpack(eval_func))
20
22
 
23
+ # Subtitle'ları parse et (Kotlin referansı: track elementleri)
24
+ subtitles = []
25
+ secici = Selector(istek.text)
26
+ for track in secici.css("track"):
27
+ raw_src = track.css("::attr(src)").get() or ""
28
+ raw_src = raw_src.strip()
29
+ label = track.css("::attr(label)").get() or track.css("::attr(srclang)").get() or "Altyazı"
30
+
31
+ if raw_src:
32
+ full_url = raw_src if raw_src.startswith("http") else f"{self.main_url}{raw_src}"
33
+ subtitles.append(Subtitle(name=label, url=full_url))
34
+
21
35
  return ExtractResult(
22
36
  name = self.name,
23
37
  url = m3u_link,
24
38
  referer = self.main_url,
25
- subtitles = []
39
+ subtitles = subtitles
26
40
  )
41
+
@@ -75,18 +75,22 @@ class FilmMakinesi(PluginBase):
75
75
  istek = await self.httpx.get(url)
76
76
  secici = Selector(istek.text)
77
77
 
78
- title = secici.css("h1.title::text").get().strip()
79
- poster = secici.css("img.cover-img::attr(src)").get().strip()
80
- description = secici.css("div.info-description p::text").get().strip()
78
+ title = secici.css("h1.title::text").get()
79
+ title = title.strip() if title else ""
80
+ poster = secici.css("img.cover-img::attr(src)").get()
81
+ poster = poster.strip() if poster else ""
82
+ description = secici.css("div.info-description p::text").get()
83
+ description = description.strip() if description else ""
81
84
  rating = secici.css("div.score::text").get()
82
85
  if rating:
83
86
  rating = rating.strip().split()[0]
84
- year = secici.css("span.date a::text").get().strip()
87
+ year = secici.css("span.date a::text").get()
88
+ year = year.strip() if year else ""
85
89
  actors = secici.css("div.cast-name::text").getall()
86
90
  tags = secici.css("div.genre a::text").getall()
87
91
  duration = secici.css("div.time::text").get()
88
92
  if duration:
89
- duration = duration.split()[1].strip()
93
+ duration = duration.split()[1].strip() if len(duration.split()) > 1 else ""
90
94
 
91
95
  return MovieInfo(
92
96
  url = url,
@@ -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 PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult, Subtitle
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, ExtractResult, Subtitle
4
4
  from parsel import Selector
5
5
  import re, base64
6
6
 
@@ -69,14 +69,13 @@ class FullHDFilm(PluginBase):
69
69
  if veri.css("img::attr(alt)").get()
70
70
  ]
71
71
 
72
- async def load_item(self, url: str) -> MovieInfo:
72
+ async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
73
73
  istek = await self.httpx.get(url)
74
74
  secici = Selector(istek.text)
75
75
 
76
- title = secici.css("h1::text").get()
77
- poster = self.fix_url(secici.css("div.poster img::attr(src)").get())
78
- description = secici.css("div#details div.text::text").get() or \
79
- secici.css("div#details div::text").get()
76
+ title = secici.css("h1::text").get() or ""
77
+ title = title.strip() if title else ""
78
+ poster = self.fix_url(secici.css("div.poster img::attr(src)").get() or "")
80
79
 
81
80
  actors_text = secici.css("div.oyuncular.info::text").get()
82
81
  if actors_text:
@@ -89,20 +88,72 @@ class FullHDFilm(PluginBase):
89
88
  tags = secici.css("div.tur.info a::text").getall()
90
89
  rating = secici.css("div.imdb::text").re_first(r"IMDb\s*([\d\.]+)")
91
90
 
92
- # Açıklama usually above .others
91
+ # Description
93
92
  description = secici.xpath("//div[contains(@class, 'others')]/preceding-sibling::div[1]//text()").getall()
94
93
  description = "".join(description).strip() if description else None
95
94
 
96
- return MovieInfo(
97
- url = url,
98
- poster = poster,
99
- title = self.clean_title(title) if title else "",
100
- description = description,
101
- tags = tags,
102
- year = year,
103
- actors = actors,
104
- rating = rating.strip() if rating else None,
105
- )
95
+ # Kotlin referansı: URL'de -dizi kontrolü veya tags içinde "dizi" kontrolü
96
+ is_series = "-dizi" in url.lower() or any("dizi" in tag.lower() for tag in tags)
97
+
98
+ if is_series:
99
+ episodes = []
100
+ part_elements = secici.css("li.psec")
101
+ part_names = secici.css("li.psec a::text").getall()
102
+
103
+ # pdata değerlerini çıkar
104
+ pdata_matches = re.findall(r"pdata\['([^']+)'\]\s*=\s*'([^']+)'", istek.text)
105
+
106
+ for idx, (part_id, part_name) in enumerate(zip([el.css("::attr(id)").get() for el in part_elements], part_names)):
107
+ if not part_name:
108
+ continue
109
+
110
+ part_name = part_name.strip()
111
+
112
+ # Fragman'ları atla
113
+ if "fragman" in part_name.lower() or (part_id and "fragman" in part_id.lower()):
114
+ continue
115
+
116
+ # Sezon ve bölüm numarası çıkar
117
+ sz_match = re.search(r'(\d+)\s*sezon', part_id.lower() if part_id else "")
118
+ ep_match = re.search(r'^(\d+)\.', part_name)
119
+
120
+ sz_num = int(sz_match.group(1)) if sz_match else 1
121
+ ep_num = int(ep_match.group(1)) if ep_match else idx + 1
122
+
123
+ # pdata'dan video URL'si çık (varsa)
124
+ video_url = url # Varsayılan olarak ana URL kullan
125
+ if idx < len(pdata_matches):
126
+ video_url = pdata_matches[idx][1] if pdata_matches[idx][1] else url
127
+
128
+ episodes.append(Episode(
129
+ season = sz_num,
130
+ episode = ep_num,
131
+ title = f"{sz_num}. Sezon {ep_num}. Bölüm",
132
+ url = url # Bölüm URL'leri load_links'te işlenecek
133
+ ))
134
+
135
+ return SeriesInfo(
136
+ url = url,
137
+ poster = poster,
138
+ title = self.clean_title(title) if title else "",
139
+ description = description,
140
+ tags = tags,
141
+ year = year,
142
+ actors = actors,
143
+ rating = rating.strip() if rating else None,
144
+ episodes = episodes
145
+ )
146
+ else:
147
+ return MovieInfo(
148
+ url = url,
149
+ poster = poster,
150
+ title = self.clean_title(title) if title else "",
151
+ description = description,
152
+ tags = tags,
153
+ year = year,
154
+ actors = actors,
155
+ rating = rating.strip() if rating else None,
156
+ )
106
157
 
107
158
  def _get_iframe(self, source_code: str) -> str:
108
159
  """Base64 kodlu iframe'i çözümle"""
@@ -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 PluginBase, MainPageResult, SearchResult, MovieInfo, Subtitle
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode, Subtitle
4
4
  from parsel import Selector
5
5
  from Kekik.Sifreleme import Packer, StreamDecoder
6
6
  import random, string, re
@@ -71,36 +71,76 @@ class HDFilmCehennemi(PluginBase):
71
71
 
72
72
  return results
73
73
 
74
- async def load_item(self, url: str) -> MovieInfo:
74
+ async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
75
75
  istek = await self.httpx.get(url, headers = {"Referer": f"{self.main_url}/"})
76
76
  secici = Selector(istek.text)
77
77
 
78
- title = secici.css("h1.section-title::text").get().strip()
79
- poster = secici.css("aside.post-info-poster img.lazyload::attr(data-src)").get().strip()
80
- description = secici.css("article.post-info-content > p::text").get().strip()
78
+ title = secici.css("h1.section-title::text").get()
79
+ title = title.strip() if title else ""
80
+ poster = secici.css("aside.post-info-poster img.lazyload::attr(data-src)").get() or ""
81
+ poster = poster.strip() if poster else ""
82
+ description = secici.css("article.post-info-content > p::text").get() or ""
83
+ description = description.strip() if description else ""
81
84
  tags = secici.css("div.post-info-genres a::text").getall()
82
- rating = secici.css("div.post-info-imdb-rating span::text").get().strip()
83
- year = secici.css("div.post-info-year-country a::text").get().strip()
85
+ rating = secici.css("div.post-info-imdb-rating span::text").get() or ""
86
+ rating = rating.strip() if rating else ""
87
+ year = secici.css("div.post-info-year-country a::text").get() or ""
88
+ year = year.strip() if year else ""
84
89
  actors = secici.css("div.post-info-cast a > strong::text").getall()
85
- duration = secici.css("div.post-info-duration::text").get().replace("dakika", "").strip()
90
+ duration = secici.css("div.post-info-duration::text").get() or "0"
91
+ duration = duration.replace("dakika", "").strip()
86
92
 
87
-
88
93
  try:
89
- duration_minutes = int(duration[2:-1])
94
+ duration_minutes = int(re.search(r'\d+', duration).group()) if re.search(r'\d+', duration) else 0
90
95
  except Exception:
91
96
  duration_minutes = 0
92
97
 
93
- return MovieInfo(
94
- url = url,
95
- poster = self.fix_url(poster),
96
- title = self.clean_title(title),
97
- description = description,
98
- tags = tags,
99
- rating = rating,
100
- year = year,
101
- actors = actors,
102
- duration = duration_minutes
103
- )
98
+ # Dizi mi film mi kontrol et (Kotlin referansı: div.seasons kontrolü)
99
+ is_series = len(secici.css("div.seasons").getall()) > 0
100
+
101
+ if is_series:
102
+ episodes = []
103
+ for ep in secici.css("div.seasons-tab-content a"):
104
+ ep_name = ep.css("h4::text").get()
105
+ ep_href = ep.css("::attr(href)").get()
106
+ if ep_name and ep_href:
107
+ ep_name = ep_name.strip()
108
+ # Regex ile sezon ve bölüm numarası çıkar
109
+ ep_match = re.search(r'(\d+)\.\s*Bölüm', ep_name)
110
+ sz_match = re.search(r'(\d+)\.\s*Sezon', ep_name)
111
+ ep_num = int(ep_match.group(1)) if ep_match else 1
112
+ sz_num = int(sz_match.group(1)) if sz_match else 1
113
+
114
+ episodes.append(Episode(
115
+ season = sz_num,
116
+ episode = ep_num,
117
+ title = ep_name,
118
+ url = self.fix_url(ep_href)
119
+ ))
120
+
121
+ return SeriesInfo(
122
+ url = url,
123
+ poster = self.fix_url(poster),
124
+ title = self.clean_title(title),
125
+ description = description,
126
+ tags = tags,
127
+ rating = rating,
128
+ year = year,
129
+ actors = actors,
130
+ episodes = episodes
131
+ )
132
+ else:
133
+ return MovieInfo(
134
+ url = url,
135
+ poster = self.fix_url(poster),
136
+ title = self.clean_title(title),
137
+ description = description,
138
+ tags = tags,
139
+ rating = rating,
140
+ year = year,
141
+ actors = actors,
142
+ duration = duration_minutes
143
+ )
104
144
 
105
145
  def generate_random_cookie(self):
106
146
  return "".join(random.choices(string.ascii_letters + string.digits, k=16))
@@ -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 PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo, Episode
4
4
  from parsel import Selector
5
5
  import re, base64, json, urllib.parse
6
6
 
@@ -137,8 +137,13 @@ class SelcukFlix(PluginBase):
137
137
  search_url = f"{self.main_url}/api/bg/searchcontent?searchterm={query}"
138
138
 
139
139
  headers = {
140
+ "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0",
140
141
  "Accept" : "application/json, text/plain, */*",
142
+ "Accept-Language" : "en-US,en;q=0.5",
141
143
  "X-Requested-With" : "XMLHttpRequest",
144
+ "Sec-Fetch-Site" : "same-origin",
145
+ "Sec-Fetch-Mode" : "cors",
146
+ "Sec-Fetch-Dest" : "empty",
142
147
  "Referer" : f"{self.main_url}/"
143
148
  }
144
149
 
@@ -151,15 +156,16 @@ class SelcukFlix(PluginBase):
151
156
  try:
152
157
  decoded_str = raw_data.decode('utf-8')
153
158
  except UnicodeDecodeError:
154
- decoded_str = raw_data.decode('iso-8859-1').encode('utf-8').decode('utf-8')
159
+ decoded_str = raw_data.decode('iso-8859-1')
155
160
 
156
161
  search_data = json.loads(decoded_str)
157
162
 
158
163
  results = []
159
164
  for item in search_data.get("result", []):
160
- title = item.get("title")
161
- slug = item.get("slug")
162
- poster = item.get("poster")
165
+ # API field isimleri: object_name, used_slug, object_poster_url
166
+ title = item.get("object_name") or item.get("title")
167
+ slug = item.get("used_slug") or item.get("slug")
168
+ poster = item.get("object_poster_url") or item.get("poster")
163
169
 
164
170
  if poster:
165
171
  poster = self.clean_image_url(poster)
@@ -176,7 +182,7 @@ class SelcukFlix(PluginBase):
176
182
  except Exception:
177
183
  return []
178
184
 
179
- async def load_item(self, url: str) -> SeriesInfo:
185
+ async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
180
186
  resp = await self.httpx.get(url)
181
187
  sel = Selector(resp.text)
182
188
 
@@ -190,15 +196,17 @@ class SelcukFlix(PluginBase):
190
196
  try:
191
197
  decoded_str = raw_data.decode('utf-8')
192
198
  except UnicodeDecodeError:
193
- decoded_str = raw_data.decode('iso-8859-1') # .encode('utf-8').decode('utf-8') implied
199
+ decoded_str = raw_data.decode('iso-8859-1')
194
200
 
195
201
  content_details = json.loads(decoded_str)
196
202
  item = content_details.get("contentItem", {})
197
203
 
198
- title = item.get("original_title") or item.get("originalTitle")
204
+ title = item.get("original_title") or item.get("originalTitle") or ""
199
205
  poster = self.clean_image_url(item.get("poster_url") or item.get("posterUrl"))
200
206
  description = item.get("description") or item.get("used_description")
201
207
  rating = str(item.get("imdb_point") or item.get("imdbPoint", ""))
208
+ year = item.get("release_year") or item.get("releaseYear")
209
+ duration = item.get("total_minutes") or item.get("totalMinutes")
202
210
 
203
211
  series_data = content_details.get("relatedData", {}).get("seriesData")
204
212
  if not series_data and "RelatedResults" in content_details:
@@ -206,17 +214,18 @@ class SelcukFlix(PluginBase):
206
214
  if series_data and isinstance(series_data, list):
207
215
  pass
208
216
 
209
- episodes = []
217
+ # Dizi mi film mi kontrol et (Kotlin referansı)
210
218
  if series_data:
211
- seasons_list = []
212
- if isinstance(series_data, dict):
213
- seasons_list = series_data.get("seasons", [])
214
- elif isinstance(series_data, list):
215
- seasons_list = series_data
216
-
217
- for season in seasons_list:
219
+ episodes = []
220
+ seasons_list = []
221
+ if isinstance(series_data, dict):
222
+ seasons_list = series_data.get("seasons", [])
223
+ elif isinstance(series_data, list):
224
+ seasons_list = series_data
225
+
226
+ for season in seasons_list:
218
227
  if not isinstance(season, dict): continue
219
- s_no = season.get("season_no") or season.get("seasonNo") # Try snake_case too
228
+ s_no = season.get("season_no") or season.get("seasonNo")
220
229
  ep_list = season.get("episodes", [])
221
230
  for ep in ep_list:
222
231
  episodes.append(Episode(
@@ -225,15 +234,27 @@ class SelcukFlix(PluginBase):
225
234
  title = ep.get("ep_text") or ep.get("epText"),
226
235
  url = self.fix_url(ep.get("used_slug") or ep.get("usedSlug"))
227
236
  ))
228
-
229
- return SeriesInfo(
230
- title = title,
231
- url = url,
232
- poster = poster,
233
- description = description,
234
- rating = rating,
235
- episodes = episodes
236
- )
237
+
238
+ return SeriesInfo(
239
+ title = title,
240
+ url = url,
241
+ poster = poster,
242
+ description = description,
243
+ rating = rating,
244
+ year = year,
245
+ episodes = episodes
246
+ )
247
+ else:
248
+ # Film ise MovieInfo döndür
249
+ return MovieInfo(
250
+ title = title,
251
+ url = url,
252
+ poster = poster,
253
+ description = description,
254
+ rating = rating,
255
+ year = year,
256
+ duration = duration
257
+ )
237
258
 
238
259
  async def load_links(self, url: str) -> list[dict]:
239
260
  resp = await self.httpx.get(url)
@@ -248,42 +269,45 @@ class SelcukFlix(PluginBase):
248
269
  secure_data = data["props"]["pageProps"]["secureData"]
249
270
  raw_data = base64.b64decode(secure_data.replace('"', ''))
250
271
 
251
- # Try UTF-8 first, fallback to ISO-8859-1 (matching Kotlin)
252
272
  try:
253
273
  decoded_str = raw_data.decode('utf-8')
254
274
  except UnicodeDecodeError:
255
275
  decoded_str = raw_data.decode('iso-8859-1')
256
276
 
257
277
  content_details = json.loads(decoded_str)
258
- related_data = content_details.get("relatedData", {})
278
+ related_results = content_details.get("RelatedResults", {})
259
279
 
260
280
  source_content = None
261
281
 
262
- # Check if Series (episode) or Movie
282
+ # Dizi (bölüm) için
263
283
  if "/dizi/" in url:
264
- if related_data.get("episodeSources", {}).get("state"):
265
- res = related_data["episodeSources"].get("result", [])
284
+ episode_sources = related_results.get("getEpisodeSources", {})
285
+ if episode_sources.get("state"):
286
+ res = episode_sources.get("result", [])
266
287
  if res:
267
- source_content = res[0].get("sourceContent")
288
+ source_content = res[0].get("source_content") or res[0].get("sourceContent")
268
289
  else:
269
- # Movie
270
- if related_data.get("movieParts", {}).get("state"):
271
- movie_parts = related_data["movieParts"].get("result", [])
272
- if movie_parts:
273
- first_part_id = movie_parts[0].get("id")
274
- # RelatedResults -> getMoviePartSourcesById_ID
275
- rr = content_details.get("RelatedResults", {})
290
+ # Film için
291
+ movie_parts = related_results.get("getMoviePartsById", {})
292
+ if movie_parts.get("state"):
293
+ parts = movie_parts.get("result", [])
294
+ if parts:
295
+ first_part_id = parts[0].get("id")
276
296
  key = f"getMoviePartSourcesById_{first_part_id}"
277
- if key in rr:
278
- res = rr[key].get("result", [])
297
+ if key in related_results:
298
+ res = related_results[key].get("result", [])
279
299
  if res:
280
- source_content = res[0].get("source_content")
300
+ source_content = res[0].get("source_content") or res[0].get("sourceContent")
281
301
 
282
302
  if source_content:
283
303
  iframe_sel = Selector(source_content)
284
304
  iframe_src = iframe_sel.css("iframe::attr(src)").get()
285
305
  if iframe_src:
286
306
  iframe_src = self.fix_url(iframe_src)
307
+ # Hotlinger domain değişimi (Kotlin referansı)
308
+ if "sn.dplayer74.site" in iframe_src:
309
+ iframe_src = iframe_src.replace("sn.dplayer74.site", "sn.hotlinger.com")
310
+
287
311
  data = await self.extract(iframe_src)
288
312
  if data:
289
313
  return [data]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: KekikStream
3
- Version: 2.1.3
3
+ Version: 2.1.5
4
4
  Summary: terminal üzerinden medya içeriği aramanızı ve VLC/MPV gibi popüler medya oynatıcılar aracılığıyla doğrudan izlemenizi sağlayan modüler ve genişletilebilir bir bıdı bıdı
5
5
  Home-page: https://github.com/keyiflerolsun/KekikStream
6
6
  Author: keyiflerolsun
@@ -292,6 +292,8 @@ Projeyi geliştirmek için katkılarınızı bekliyoruz!
292
292
 
293
293
  - [keyiflerolsun/Kekik-cloudstream](https://github.com/keyiflerolsun/Kekik-cloudstream)
294
294
  - [keyiflerolsun/seyirTurk-Parser](https://github.com/keyiflerolsun/seyirTurk-Parser)
295
+ - [feroxx/Kekik-cloudstream](https://github.com/feroxx/Kekik-cloudstream)
296
+ - [kerimmkirac/cs-kerim](https://github.com/kerimmkirac/cs-kerim)
295
297
 
296
298
  ## 🌐 Telif Hakkı ve Lisans
297
299
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: KekikStream
3
- Version: 2.1.3
3
+ Version: 2.1.5
4
4
  Summary: terminal üzerinden medya içeriği aramanızı ve VLC/MPV gibi popüler medya oynatıcılar aracılığıyla doğrudan izlemenizi sağlayan modüler ve genişletilebilir bir bıdı bıdı
5
5
  Home-page: https://github.com/keyiflerolsun/KekikStream
6
6
  Author: keyiflerolsun
@@ -292,6 +292,8 @@ Projeyi geliştirmek için katkılarınızı bekliyoruz!
292
292
 
293
293
  - [keyiflerolsun/Kekik-cloudstream](https://github.com/keyiflerolsun/Kekik-cloudstream)
294
294
  - [keyiflerolsun/seyirTurk-Parser](https://github.com/keyiflerolsun/seyirTurk-Parser)
295
+ - [feroxx/Kekik-cloudstream](https://github.com/feroxx/Kekik-cloudstream)
296
+ - [kerimmkirac/cs-kerim](https://github.com/kerimmkirac/cs-kerim)
295
297
 
296
298
  ## 🌐 Telif Hakkı ve Lisans
297
299
 
@@ -255,6 +255,8 @@ Projeyi geliştirmek için katkılarınızı bekliyoruz!
255
255
 
256
256
  - [keyiflerolsun/Kekik-cloudstream](https://github.com/keyiflerolsun/Kekik-cloudstream)
257
257
  - [keyiflerolsun/seyirTurk-Parser](https://github.com/keyiflerolsun/seyirTurk-Parser)
258
+ - [feroxx/Kekik-cloudstream](https://github.com/feroxx/Kekik-cloudstream)
259
+ - [kerimmkirac/cs-kerim](https://github.com/kerimmkirac/cs-kerim)
258
260
 
259
261
  ## 🌐 Telif Hakkı ve Lisans
260
262
 
@@ -6,7 +6,7 @@ from io import open
6
6
  setup(
7
7
  # ? Genel Bilgiler
8
8
  name = "KekikStream",
9
- version = "2.1.3",
9
+ version = "2.1.5",
10
10
  url = "https://github.com/keyiflerolsun/KekikStream",
11
11
  description = "terminal üzerinden medya içeriği aramanızı ve VLC/MPV gibi popüler medya oynatıcılar aracılığıyla doğrudan izlemenizi sağlayan modüler ve genişletilebilir bir bıdı bıdı",
12
12
  keywords = ["KekikStream", "KekikAkademi", "keyiflerolsun"],
File without changes
File without changes
File without changes