KekikStream 1.8.1__py3-none-any.whl → 1.9.0__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.
@@ -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, MovieInfo
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo
4
4
  from parsel import Selector
5
5
  from Kekik.Sifreleme import StringCodec
6
6
  import json, re
@@ -40,7 +40,6 @@ class FullHDFilmizlesene(PluginBase):
40
40
  f"{main_url}/filmizle/yerli-filmler-hd-izle/" : "Yerli Filmler"
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
44
  istek = self.cloudscraper.get(f"{url}{page}")
46
45
  secici = Selector(istek.text)
@@ -55,7 +54,6 @@ class FullHDFilmizlesene(PluginBase):
55
54
  for veri in secici.css("li.film")
56
55
  ]
57
56
 
58
- #@kekik_cache(ttl=60*60)
59
57
  async def search(self, query: str) -> list[SearchResult]:
60
58
  istek = await self.httpx.get(f"{self.main_url}/arama/{query}")
61
59
  secici = Selector(istek.text)
@@ -77,7 +75,6 @@ class FullHDFilmizlesene(PluginBase):
77
75
 
78
76
  return results
79
77
 
80
- #@kekik_cache(ttl=60*60)
81
78
  async def load_item(self, url: str) -> MovieInfo:
82
79
  istek = await self.httpx.get(url)
83
80
  secici = Selector(istek.text)
@@ -103,7 +100,6 @@ class FullHDFilmizlesene(PluginBase):
103
100
  duration = duration
104
101
  )
105
102
 
106
- #@kekik_cache(ttl=15*60)
107
103
  async def load_links(self, url: str) -> list[dict]:
108
104
  istek = await self.httpx.get(url)
109
105
  secici = Selector(istek.text)
@@ -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, MovieInfo, ExtractResult, Subtitle
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult, Subtitle
4
4
  from parsel import Selector
5
5
  from Kekik.Sifreleme import Packer, StreamDecoder
6
6
  import random, string, re
@@ -12,8 +12,7 @@ class HDFilmCehennemi(PluginBase):
12
12
  favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
13
13
  description = "Türkiye'nin en hızlı hd film izleme sitesi"
14
14
 
15
- # Bu site domain değişikliği yapıyor ve potansiyel anti-bot koruması var
16
- requires_cffi = True
15
+
17
16
 
18
17
  main_page = {
19
18
  f"{main_url}" : "Yeni Eklenen Filmler",
@@ -32,9 +31,8 @@ class HDFilmCehennemi(PluginBase):
32
31
  f"{main_url}/tur/romantik-filmleri-izle-1" : "Romantik Filmleri"
33
32
  }
34
33
 
35
- #@kekik_cache(ttl=60*60)
36
34
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
37
- istek = await self.cffi.get(f"{url}", allow_redirects=True)
35
+ istek = await self.httpx.get(f"{url}", follow_redirects=True)
38
36
  secici = Selector(istek.text)
39
37
 
40
38
  return [
@@ -47,9 +45,8 @@ class HDFilmCehennemi(PluginBase):
47
45
  for veri in secici.css("div.section-content a.poster")
48
46
  ]
49
47
 
50
- #@kekik_cache(ttl=60*60)
51
48
  async def search(self, query: str) -> list[SearchResult]:
52
- istek = await self.cffi.get(
49
+ istek = await self.httpx.get(
53
50
  url = f"{self.main_url}/search/?q={query}",
54
51
  headers = {
55
52
  "Referer" : f"{self.main_url}/",
@@ -76,9 +73,8 @@ class HDFilmCehennemi(PluginBase):
76
73
 
77
74
  return results
78
75
 
79
- #@kekik_cache(ttl=60*60)
80
76
  async def load_item(self, url: str) -> MovieInfo:
81
- istek = await self.cffi.get(url, headers = {"Referer": f"{self.main_url}/"})
77
+ istek = await self.httpx.get(url, headers = {"Referer": f"{self.main_url}/"})
82
78
  secici = Selector(istek.text)
83
79
 
84
80
  title = secici.css("h1.section-title::text").get().strip()
@@ -111,11 +107,10 @@ class HDFilmCehennemi(PluginBase):
111
107
  def generate_random_cookie(self):
112
108
  return "".join(random.choices(string.ascii_letters + string.digits, k=16))
113
109
 
114
- #@kekik_cache(ttl=15*60)
115
110
  async def cehennempass(self, video_id: str) -> list[dict]:
116
111
  results = []
117
112
 
118
- istek = await self.cffi.post(
113
+ istek = await self.httpx.post(
119
114
  url = "https://cehennempass.pw/process_quality_selection.php",
120
115
  headers = {
121
116
  "Referer" : f"https://cehennempass.pw/download/{video_id}",
@@ -132,7 +127,7 @@ class HDFilmCehennemi(PluginBase):
132
127
  "referer" : f"https://cehennempass.pw/download/{video_id}"
133
128
  })
134
129
 
135
- istek = await self.cffi.post(
130
+ istek = await self.httpx.post(
136
131
  url = "https://cehennempass.pw/process_quality_selection.php",
137
132
  headers = {
138
133
  "Referer" : f"https://cehennempass.pw/download/{video_id}",
@@ -151,10 +146,9 @@ class HDFilmCehennemi(PluginBase):
151
146
 
152
147
  return results
153
148
 
154
- #@kekik_cache(ttl=15*60)
155
149
  async def invoke_local_source(self, iframe: str, source: str, url: str):
156
- self.cffi.headers.update({"Referer": f"{self.main_url}/"})
157
- istek = await self.cffi.get(iframe)
150
+ self.httpx.headers.update({"Referer": f"{self.main_url}/"})
151
+ istek = await self.httpx.get(iframe)
158
152
 
159
153
  try:
160
154
  eval_func = re.compile(r'\s*(eval\(function[\s\S].*)\s*').findall(istek.text)[0]
@@ -182,9 +176,8 @@ class HDFilmCehennemi(PluginBase):
182
176
  "subtitles" : subtitles
183
177
  }]
184
178
 
185
- #@kekik_cache(ttl=15*60)
186
179
  async def load_links(self, url: str) -> list[dict]:
187
- istek = await self.cffi.get(url)
180
+ istek = await self.httpx.get(url)
188
181
  secici = Selector(istek.text)
189
182
 
190
183
  results = []
@@ -195,7 +188,7 @@ class HDFilmCehennemi(PluginBase):
195
188
  source = f"{link.css('::text').get().replace('(HDrip Xbet)', '').strip()} {lang_code}"
196
189
  video_id = link.css("::attr(data-video)").get()
197
190
 
198
- api_get = await self.cffi.get(
191
+ api_get = await self.httpx.get(
199
192
  url = f"{self.main_url}/video/{video_id}/",
200
193
  headers = {
201
194
  "Content-Type" : "application/json",
@@ -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, MovieInfo
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo
4
4
  from parsel import Selector
5
5
 
6
6
  class JetFilmizle(PluginBase):
@@ -19,7 +19,6 @@ class JetFilmizle(PluginBase):
19
19
  f"{main_url}/kategoriler/yesilcam-filmleri-izlee/page/" : "Yeşilçam Filmleri"
20
20
  }
21
21
 
22
- #@kekik_cache(ttl=60*60)
23
22
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
24
23
  istek = await self.httpx.get(f"{url}{page}", follow_redirects=True)
25
24
  secici = Selector(istek.text)
@@ -34,7 +33,6 @@ class JetFilmizle(PluginBase):
34
33
  for veri in secici.css("article.movie") if veri.css("h2 a::text, h3 a::text, h4 a::text, h5 a::text, h6 a::text").get()
35
34
  ]
36
35
 
37
- #@kekik_cache(ttl=60*60)
38
36
  async def search(self, query: str) -> list[SearchResult]:
39
37
  istek = await self.httpx.post(
40
38
  url = f"{self.main_url}/filmara.php",
@@ -60,7 +58,6 @@ class JetFilmizle(PluginBase):
60
58
 
61
59
  return results
62
60
 
63
- #@kekik_cache(ttl=60*60)
64
61
  async def load_item(self, url: str) -> MovieInfo:
65
62
  istek = await self.httpx.get(url)
66
63
  secici = Selector(istek.text)
@@ -92,7 +89,6 @@ class JetFilmizle(PluginBase):
92
89
  actors = actors
93
90
  )
94
91
 
95
- #@kekik_cache(ttl=15*60)
96
92
  async def load_links(self, url: str) -> list[dict]:
97
93
  istek = await self.httpx.get(url)
98
94
  secici = Selector(istek.text)
@@ -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, MovieInfo, Episode, SeriesInfo, ExtractResult, Subtitle
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, Episode, SeriesInfo, ExtractResult, Subtitle
4
4
  from json import dumps, loads
5
5
  import re
6
6
 
@@ -30,7 +30,6 @@ class RecTV(PluginBase):
30
30
  f"{main_url}/api/movie/by/filtres/5/created/SAYFA/{sw_key}/" : "Romantik"
31
31
  }
32
32
 
33
- #@kekik_cache(ttl=60*60)
34
33
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
35
34
  self.httpx.headers.update({"user-agent": "okhttp/4.12.0"})
36
35
  istek = await self.httpx.get(f"{url.replace('SAYFA', str(int(page) - 1))}")
@@ -46,7 +45,6 @@ class RecTV(PluginBase):
46
45
  for veri in veriler
47
46
  ]
48
47
 
49
- #@kekik_cache(ttl=60*60)
50
48
  async def search(self, query: str) -> list[SearchResult]:
51
49
  self.httpx.headers.update({"user-agent": "okhttp/4.12.0"})
52
50
  istek = await self.httpx.get(f"{self.main_url}/api/search/{query}/{self.sw_key}/")
@@ -67,7 +65,6 @@ class RecTV(PluginBase):
67
65
  for veri in tum_veri
68
66
  ]
69
67
 
70
- #@kekik_cache(ttl=60*60)
71
68
  async def load_item(self, url: str) -> MovieInfo:
72
69
  self.httpx.headers.update({"user-agent": "okhttp/4.12.0"})
73
70
  veri = loads(url)
@@ -119,7 +116,6 @@ class RecTV(PluginBase):
119
116
  actors = []
120
117
  )
121
118
 
122
- #@kekik_cache(ttl=15*60)
123
119
  async def load_links(self, url: str) -> list[dict]:
124
120
  try:
125
121
  veri = loads(url)
@@ -2,15 +2,16 @@
2
2
 
3
3
  from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, MovieInfo
4
4
  from parsel import Selector
5
- import re, base64, json, urllib.parse
5
+ import re, base64, json
6
6
 
7
7
  class RoketDizi(PluginBase):
8
8
  name = "RoketDizi"
9
9
  lang = "tr"
10
10
  main_url = "https://roketdizi.to"
11
+ favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
12
+ description = "Türkiye'nin en tatlış yabancı dizi izleme sitesi. Türkçe dublaj, altyazılı, eski ve yeni yabancı dizilerin yanı sıra kore (asya) dizileri izleyebilirsiniz."
13
+
11
14
 
12
- # Domain doğrulama ve anti-bot mekanizmaları var
13
- requires_cffi = True
14
15
 
15
16
  main_page = {
16
17
  "dizi/tur/aksiyon" : "Aksiyon",
@@ -25,7 +26,7 @@ class RoketDizi(PluginBase):
25
26
 
26
27
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
27
28
  full_url = f"{self.main_url}/{url}?&page={page}"
28
- resp = await self.cffi.get(full_url)
29
+ resp = await self.httpx.get(full_url)
29
30
  sel = Selector(resp.text)
30
31
 
31
32
  results = []
@@ -45,45 +46,50 @@ class RoketDizi(PluginBase):
45
46
  return results
46
47
 
47
48
  async def search(self, query: str) -> list[SearchResult]:
48
- # Get Cookies and Keys
49
- main_req = await self.cffi.get(self.main_url)
50
- sel = Selector(main_req.text)
51
-
52
- c_key = sel.css("input[name='cKey']::attr(value)").get()
53
- c_value = sel.css("input[name='cValue']::attr(value)").get()
54
-
55
49
  post_url = f"{self.main_url}/api/bg/searchContent?searchterm={query}"
56
50
 
57
51
  headers = {
58
52
  "Accept" : "application/json, text/javascript, */*; q=0.01",
59
53
  "X-Requested-With" : "XMLHttpRequest",
60
54
  "Referer" : f"{self.main_url}/",
61
- "CNT" : "vakTR"
62
55
  }
63
-
64
- data = {}
65
- if c_key and c_value:
66
- data = {"cKey": c_key, "cValue": c_value}
67
56
 
68
- search_req = await self.cffi.post(post_url, data=data, headers=headers)
57
+ search_req = await self.httpx.post(post_url, headers=headers)
69
58
 
70
59
  try:
71
60
  resp_json = search_req.json()
72
- if not resp_json.get("state"):
61
+
62
+ # Response is base64 encoded!
63
+ if not resp_json.get("success"):
64
+ return []
65
+
66
+ encoded_response = resp_json.get("response", "")
67
+ if not encoded_response:
68
+ return []
69
+
70
+ # Decode base64
71
+ decoded = base64.b64decode(encoded_response).decode('utf-8')
72
+ data = json.loads(decoded)
73
+
74
+ if not data.get("state"):
73
75
  return []
74
76
 
75
- html_content = resp_json.get("html", "").strip()
76
- sel_results = Selector(html_content)
77
-
78
77
  results = []
79
- items = re.findall(r'<a href="([^"]+)".*?data-srcset="([^"]+).*?<span class="text-white">([^<]+)', html_content, re.DOTALL)
78
+ result_items = data.get("result", [])
80
79
 
81
- for href, poster, title in items:
82
- results.append(SearchResult(
83
- title = title.strip(),
84
- url = self.fix_url(href.strip()),
85
- poster = self.fix_url(poster.strip())
86
- ))
80
+ for item in result_items:
81
+ title = item.get("object_name", "")
82
+ slug = item.get("used_slug", "")
83
+ poster = item.get("object_poster_url", "")
84
+
85
+ if title and slug:
86
+ # Construct full URL from slug
87
+ full_url = f"{self.main_url}/{slug}"
88
+ results.append(SearchResult(
89
+ title = title.strip(),
90
+ url = full_url,
91
+ poster = self.fix_url(poster) if poster else None
92
+ ))
87
93
 
88
94
  return results
89
95
 
@@ -92,21 +98,48 @@ class RoketDizi(PluginBase):
92
98
 
93
99
  async def load_item(self, url: str) -> SeriesInfo:
94
100
  # Note: Handling both Movie and Series logic in one, returning SeriesInfo generally or MovieInfo
95
- resp = await self.cffi.get(url)
101
+ resp = await self.httpx.get(url)
96
102
  sel = Selector(resp.text)
97
103
 
98
104
  title = sel.css("h1.text-white::text").get()
99
105
  poster = sel.css("div.w-full.page-top img::attr(src)").get()
100
106
  description = sel.css("div.mt-2.text-sm::text").get()
101
107
 
102
- year = None # Implement if critical
108
+ # Tags - genre bilgileri (Detaylar bölümünde)
109
+ tags = []
110
+ genre_text = sel.css("h3.text-white.opacity-90::text").get()
111
+ if genre_text:
112
+ tags = [t.strip() for t in genre_text.split(",")]
103
113
 
104
- tags = sel.css("h3.text-white.opacity-60::text").get()
105
- if tags:
106
- tags = [t.strip() for t in tags.split(",")]
107
-
114
+ # Rating
108
115
  rating = sel.css("div.flex.items-center span.text-white.text-sm::text").get()
109
- actors = sel.css("div.global-box h5::text").getall()
116
+
117
+ # Year ve Actors - Detaylar (Details) bölümünden
118
+ year = None
119
+ actors = []
120
+
121
+ # Detaylar bölümündeki tüm flex-col div'leri al
122
+ detail_items = sel.css("div.flex.flex-col")
123
+ for item in detail_items:
124
+ # Label ve value yapısı: span.text-base ve span.text-sm.opacity-90
125
+ label = item.css("span.text-base::text").get()
126
+ value = item.css("span.text-sm.opacity-90::text").get()
127
+
128
+ if label and value:
129
+ label = label.strip()
130
+ value = value.strip()
131
+
132
+ # Yayın tarihi (yıl)
133
+ if label == "Yayın tarihi":
134
+ # "16 Ekim 2018" formatından yılı çıkar
135
+ year_match = re.search(r'\d{4}', value)
136
+ if year_match:
137
+ year = year_match.group()
138
+
139
+ # Yaratıcılar veya Oyuncular
140
+ elif label in ["Yaratıcılar", "Oyuncular"]:
141
+ if value:
142
+ actors.append(value)
110
143
 
111
144
  # Check urls for episodes
112
145
  all_urls = re.findall(r'"url":"([^"]*)"', resp.text)
@@ -114,22 +147,27 @@ class RoketDizi(PluginBase):
114
147
 
115
148
  episodes = []
116
149
  if is_series:
117
- seen_eps = set()
150
+ # Dict kullanarak duplicate'leri önle ama sıralı tut
151
+ episodes_dict = {}
118
152
  for u in all_urls:
119
- if "bolum" in u and u not in seen_eps:
120
- seen_eps.add(u)
153
+ if "bolum" in u and u not in episodes_dict:
121
154
  season_match = re.search(r'/sezon-(\d+)', u)
122
155
  ep_match = re.search(r'/bolum-(\d+)', u)
123
156
 
124
157
  season = int(season_match.group(1)) if season_match else 1
125
158
  episode_num = int(ep_match.group(1)) if ep_match else 1
126
159
 
127
- episodes.append(Episode(
160
+ # Key olarak (season, episode) tuple kullan
161
+ key = (season, episode_num)
162
+ episodes_dict[key] = Episode(
128
163
  season = season,
129
164
  episode = episode_num,
130
- title = f"{season}. Sezon {episode_num}. Bölüm", # Placeholder title
165
+ title = f"{season}. Sezon {episode_num}. Bölüm",
131
166
  url = self.fix_url(u)
132
- ))
167
+ )
168
+
169
+ # Sıralı liste oluştur
170
+ episodes = [episodes_dict[key] for key in sorted(episodes_dict.keys())]
133
171
 
134
172
  return SeriesInfo(
135
173
  title = title,
@@ -144,7 +182,7 @@ class RoketDizi(PluginBase):
144
182
  )
145
183
 
146
184
  async def load_links(self, url: str) -> list[dict]:
147
- resp = await self.cffi.get(url)
185
+ resp = await self.httpx.get(url)
148
186
  sel = Selector(resp.text)
149
187
 
150
188
  next_data = sel.css("script#__NEXT_DATA__::text").get()