KekikStream 0.2.7__py3-none-any.whl → 0.2.9__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.
@@ -11,33 +11,53 @@ class ExtractorLoader:
11
11
  self.local_extractors_dir = Path(extractors_dir)
12
12
  self.global_extractors_dir = Path(__file__).parent.parent / extractors_dir
13
13
  if not self.local_extractors_dir.exists() and not self.global_extractors_dir.exists():
14
- konsol.log(f"[red][!] Extractor dizini bulunamadı: {self.extractors_dir}[/red]")
14
+ konsol.log(f"[red][!] Extractor dizini bulunamadı: {self.global_extractors_dir}[/red]")
15
15
  cikis_yap(False)
16
16
 
17
17
  def load_all(self) -> list[ExtractorBase]:
18
18
  extractors = []
19
19
 
20
+ # Global Extractor'ları yükle
20
21
  if self.global_extractors_dir.exists():
21
22
  konsol.log(f"[green][*] Global Extractor dizininden yükleniyor: {self.global_extractors_dir}[/green]")
22
- extractors.extend(self._load_from_directory(self.global_extractors_dir))
23
+ global_extractors = self._load_from_directory(self.global_extractors_dir)
24
+ konsol.log(f"[green]Global Extractor'lar: {[e.__name__ for e in global_extractors]}[/green]")
25
+ extractors.extend(global_extractors)
23
26
 
27
+ # Yerel Extractor'ları yükle
24
28
  if self.local_extractors_dir.exists():
25
29
  konsol.log(f"[green][*] Yerel Extractor dizininden yükleniyor: {self.local_extractors_dir}[/green]")
26
- extractors.extend(self._load_from_directory(self.local_extractors_dir))
30
+ local_extractors = self._load_from_directory(self.local_extractors_dir)
31
+ konsol.log(f"[green]Yerel Extractor'lar: {[e.__name__ for e in local_extractors]}[/green]")
32
+ extractors.extend(local_extractors)
27
33
 
28
- if not extractors:
29
- konsol.print("[yellow][!] Yüklenecek bir Extractor bulunamadı![/yellow]")
34
+ # Benzersizliği sağlama (modül adı + sınıf adı bazında)
35
+ unique_extractors = []
36
+ seen = set()
37
+ for ext in extractors:
38
+ identifier = f"{ext.__module__}.{ext.__name__}"
39
+ if identifier not in seen:
40
+ unique_extractors.append(ext)
41
+ seen.add(identifier)
30
42
 
31
- return extractors
43
+ konsol.log(f"[blue]Sonuç Extractor'lar: {[e.__name__ for e in unique_extractors]}[/blue]")
44
+
45
+ if not unique_extractors:
46
+ konsol.log("[yellow][!] Yüklenecek bir Extractor bulunamadı![/yellow]")
47
+
48
+ return unique_extractors
32
49
 
33
50
  def _load_from_directory(self, directory: Path) -> list[ExtractorBase]:
34
51
  extractors = []
35
52
  for file in os.listdir(directory):
36
53
  if file.endswith(".py") and not file.startswith("__"):
37
54
  module_name = file[:-3]
55
+ konsol.log(f"[cyan]Modül yükleniyor: {module_name}[/cyan]")
38
56
  if extractor := self._load_extractor(directory, module_name):
57
+ konsol.log(f"[magenta]Extractor bulundu: {extractor.__name__}[/magenta]")
39
58
  extractors.append(extractor)
40
59
 
60
+ konsol.log(f"[yellow]{directory} dizininden yüklenen Extractor'lar: {[e.__name__ for e in extractors]}[/yellow]")
41
61
  return extractors
42
62
 
43
63
  def _load_extractor(self, directory: Path, module_name: str):
@@ -50,12 +70,14 @@ class ExtractorLoader:
50
70
  module = importlib.util.module_from_spec(spec)
51
71
  spec.loader.exec_module(module)
52
72
 
73
+ # Yalnızca doğru modülden gelen ExtractorBase sınıflarını yükle
53
74
  for attr in dir(module):
54
75
  obj = getattr(module, attr)
55
- if isinstance(obj, type) and issubclass(obj, ExtractorBase) and obj is not ExtractorBase:
76
+ if obj.__module__ == module_name and isinstance(obj, type) and issubclass(obj, ExtractorBase) and obj is not ExtractorBase:
77
+ konsol.log(f"[green]Yüklenen sınıf: {module_name}.{obj.__name__} ({obj.__module__}.{obj.__name__})[/green]")
56
78
  return obj
57
79
 
58
80
  except Exception as hata:
59
- konsol.print(f"[red][!] Extractor yüklenirken hata oluştu: {module_name}\nHata: {hata}")
81
+ konsol.log(f"[red][!] Extractor yüklenirken hata oluştu: {module_name}\nHata: {hata}")
60
82
 
61
83
  return None
@@ -2,6 +2,7 @@
2
2
 
3
3
  from abc import ABC, abstractmethod
4
4
  from httpx import AsyncClient, Timeout
5
+ from cloudscraper import CloudScraper
5
6
  from .PluginModels import SearchResult, MovieInfo
6
7
  from .MediaHandler import MediaHandler
7
8
  from urllib.parse import urljoin
@@ -21,6 +22,9 @@ class PluginBase(ABC):
21
22
  timeout = Timeout(10.0),
22
23
  )
23
24
  self.media_handler = MediaHandler()
25
+ self.cloudscraper = CloudScraper()
26
+ self.oturum.headers.update(self.cloudscraper.headers)
27
+ self.oturum.cookies.update(self.cloudscraper.cookies)
24
28
 
25
29
  @abstractmethod
26
30
  async def search(self, query: str) -> list[SearchResult]:
@@ -1,5 +1,6 @@
1
1
  # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
+ from KekikStream.CLI import konsol
3
4
  from KekikStream.Core import ExtractorBase, ExtractResult
4
5
  import re
5
6
  import json
@@ -16,18 +17,11 @@ class Odnoklassniki(ExtractorBase):
16
17
  "User-Agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36"
17
18
  })
18
19
 
19
- try:
20
- # İlk isteği yap, ancak yönlendirmeyi manuel olarak kontrol et.
21
- istek = await self.oturum.get(url, follow_redirects=False)
22
- if istek.status_code == 302: # Yönlendirme varsa
23
- redirected_url = istek.headers.get("Location")
24
- if not redirected_url:
25
- raise ValueError("Redirect location not found.")
26
-
27
- # Yönlendirilmiş URL'yi kullanarak isteği yeniden yap.
28
- url = redirected_url if redirected_url.startswith("http") else f"https://{redirected_url}"
29
- istek = await self.oturum.get(url)
20
+ if "/video/" in url:
21
+ url = url.replace("/video/", "/videoembed/")
30
22
 
23
+ try:
24
+ istek = await self.fetch_with_redirects(url)
31
25
  istek.raise_for_status()
32
26
  except Exception as e:
33
27
  raise RuntimeError(f"Failed to fetch the URL: {url}, Error: {e}")
@@ -91,4 +85,25 @@ class Odnoklassniki(ExtractorBase):
91
85
  url = best_video,
92
86
  referer = self.main_url,
93
87
  subtitles = []
94
- )
88
+ )
89
+
90
+ async def fetch_with_redirects(self, url, max_redirects=5):
91
+ """Yönlendirmeleri takip eden bir fonksiyon"""
92
+ redirects = 0
93
+ while redirects < max_redirects:
94
+ istek = await self.oturum.get(url, follow_redirects=False)
95
+
96
+ if istek.status_code in [301, 302]: # Yönlendirme varsa
97
+ redirected_url = istek.headers.get("Location")
98
+ print(redirected_url)
99
+ if not redirected_url:
100
+ raise ValueError("Redirect location not found.")
101
+
102
+ url = redirected_url if redirected_url.startswith("http") else f"https://{redirected_url}"
103
+ redirects += 1
104
+ else:
105
+ break # Yönlendirme yoksa çık
106
+
107
+ if redirects == max_redirects:
108
+ raise RuntimeError(f"Max redirects ({max_redirects}) reached.")
109
+ return istek
@@ -9,6 +9,7 @@ import os
9
9
  class UIManager:
10
10
  @staticmethod
11
11
  def clear_console():
12
+ # return True
12
13
  os.system("cls" if os.name == "nt" else "clear")
13
14
 
14
15
  @staticmethod
@@ -0,0 +1,139 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import PluginBase, SearchResult, SeriesInfo, Episode
4
+ from Kekik.Sifreleme import CryptoJS
5
+ from parsel import Selector
6
+ import re, urllib.parse, base64
7
+
8
+ class DiziBox(PluginBase):
9
+ name = "DiziBox"
10
+ main_url = "https://www.dizibox.plus"
11
+
12
+ async def search(self, query: str) -> list[SearchResult]:
13
+ self.oturum.cookies.update({
14
+ "LockUser" : "true",
15
+ "isTrustedUser" : "true",
16
+ "dbxu" : "1722403730363"
17
+ })
18
+ istek = await self.oturum.get(f"{self.main_url}/?s={query}")
19
+ secici = Selector(istek.text)
20
+
21
+ return [
22
+ SearchResult(
23
+ title = item.css("h3 a::text").get(),
24
+ url = self.fix_url(item.css("h3 a::attr(href)").get()),
25
+ poster = self.fix_url(item.css("img::attr(src)").get()),
26
+ )
27
+ for item in secici.css("article.detailed-article")
28
+ ]
29
+
30
+ async def load_item(self, url: str) -> SeriesInfo:
31
+ istek = await self.oturum.get(url)
32
+ secici = Selector(istek.text)
33
+
34
+ title = secici.css("div.tv-overview h1 a::text").get()
35
+ poster = self.fix_url(secici.css("div.tv-overview figure img::attr(src)").get())
36
+ description = secici.css("div.tv-story p::text").get()
37
+ year = secici.css("a[href*='/yil/']::text").re_first(r"(\d{4})")
38
+ tags = secici.css("a[href*='/tur/']::text").getall()
39
+ rating = secici.css("span.label-imdb b::text").re_first(r"[\d.,]+")
40
+ actors = [actor.css("::text").get() for actor in secici.css("a[href*='/oyuncu/']")]
41
+
42
+ episodes = []
43
+ for sezon_link in secici.css("div#seasons-list a::attr(href)").getall():
44
+ sezon_url = self.fix_url(sezon_link)
45
+ sezon_istek = await self.oturum.get(sezon_url)
46
+ sezon_secici = Selector(sezon_istek.text)
47
+
48
+ for bolum in sezon_secici.css("article.grid-box"):
49
+ ep_title = bolum.css("div.post-title a::text").get()
50
+ ep_href = self.fix_url(bolum.css("div.post-title a::attr(href)").get())
51
+ ep_season = bolum.css("div.post-title a::text").re_first(r"(\d+)\. ?Sezon")
52
+ ep_episode = bolum.css("div.post-title a::text").re_first(r"(\d+)\. ?Bölüm")
53
+
54
+ if ep_title and ep_href:
55
+ episodes.append(Episode(
56
+ season = ep_season,
57
+ episode = ep_episode,
58
+ title = ep_title.strip(),
59
+ url = ep_href,
60
+ ))
61
+
62
+ return SeriesInfo(
63
+ url = url,
64
+ poster = poster,
65
+ title = title,
66
+ description = description,
67
+ tags = tags,
68
+ rating = rating,
69
+ year = year,
70
+ episodes = episodes,
71
+ actors = actors,
72
+ )
73
+
74
+ async def _iframe_decode(self, name:str, iframe_link:str, referer:str) -> list[str]:
75
+ results = []
76
+
77
+ if "/player/king/king.php" in iframe_link:
78
+ iframe_link = iframe_link.replace("king.php?v=", "king.php?wmode=opaque&v=")
79
+ self.oturum.headers.update({"Referer": referer})
80
+
81
+ istek = await self.oturum.get(iframe_link)
82
+ secici = Selector(istek.text)
83
+ iframe = secici.css("div#Player iframe::attr(src)").get()
84
+
85
+ self.oturum.headers.update({"Referer": self.main_url})
86
+ istek = await self.oturum.get(iframe)
87
+
88
+ crypt_data = re.search(r"CryptoJS\.AES\.decrypt\(\"(.*)\",\"", istek.text).group(1)
89
+ crypt_pass = re.search(r"\",\"(.*)\"\);", istek.text).group(1)
90
+
91
+ results.append(CryptoJS.decrypt(crypt_pass, crypt_data))
92
+
93
+ elif "/player/moly/moly.php" in iframe_link:
94
+ iframe_link = iframe_link.replace("moly.php?h=", "moly.php?wmode=opaque&h=")
95
+ self.oturum.headers.update({"Referer": referer})
96
+ istek = await self.oturum.get(iframe_link)
97
+
98
+ if atob_data := re.search(r"unescape\(\"(.*)\"\)", istek.text).group(1):
99
+ decoded_atob = urllib.parse.unquote(atob_data)
100
+ str_atob = base64.b64decode(decoded_atob).decode('utf-8')
101
+
102
+ if iframe := Selector(str_atob).css("div#Player iframe::attr(src)").get():
103
+ results.append(iframe)
104
+
105
+ elif "/player/haydi.php" in iframe_link:
106
+ okru_url = base64.b64decode(iframe_link.split("?v=")[-1]).decode("utf-8")
107
+ results.append(okru_url)
108
+
109
+ return results
110
+
111
+ async def load_links(self, url: str) -> list[str]:
112
+ istek = await self.oturum.get(url)
113
+ secici = Selector(istek.text)
114
+
115
+ iframes = []
116
+ main_iframe = secici.css("div#video-area iframe::attr(src)").get()
117
+ if main_iframe:
118
+ if decoded := await self._iframe_decode(self.name, main_iframe, url):
119
+ iframes.extend(decoded)
120
+
121
+ for alternatif in secici.css("div.video-toolbar option[value]"):
122
+ alt_name = alternatif.css("::text").get()
123
+ alt_link = alternatif.css("::attr(value)").get()
124
+
125
+ if not alt_link:
126
+ continue
127
+
128
+ self.oturum.headers.update({"Referer": url})
129
+ alt_istek = await self.oturum.get(alt_link)
130
+ alt_istek.raise_for_status()
131
+
132
+ alt_secici = Selector(alt_istek.text)
133
+ alt_iframe = alt_secici.css("div#video-area iframe::attr(src)").get()
134
+
135
+ if alt_iframe:
136
+ if decoded := await self._iframe_decode(alt_name, alt_iframe, url):
137
+ iframes.extend(decoded)
138
+
139
+ return iframes
KekikStream/__init__.py CHANGED
@@ -185,7 +185,12 @@ class KekikStream:
185
185
  konsol.print("[bold red]Uygun Extractor bulunamadı.[/bold red]")
186
186
  return
187
187
 
188
- extract_data = await extractor.extract(selected_link, referer=self.current_plugin.main_url)
188
+ try:
189
+ extract_data = await extractor.extract(selected_link, referer=self.current_plugin.main_url)
190
+ except Exception as hata:
191
+ konsol.print(f"[bold red]{extractor.name} » hata oluştu: {hata}[/bold red]")
192
+ await self.handle_no_results()
193
+ return
189
194
 
190
195
  if isinstance(extract_data, list):
191
196
  selected_data = await self.ui_manager.select_from_list(
@@ -3,6 +3,7 @@ wheel
3
3
 
4
4
  Kekik
5
5
  httpx
6
+ cloudscraper
6
7
  parsel
7
8
 
8
9
  pydantic
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: KekikStream
3
- Version: 0.2.7
3
+ Version: 0.2.9
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
@@ -17,6 +17,7 @@ Requires-Dist: setuptools
17
17
  Requires-Dist: wheel
18
18
  Requires-Dist: Kekik
19
19
  Requires-Dist: httpx
20
+ Requires-Dist: cloudscraper
20
21
  Requires-Dist: parsel
21
22
  Requires-Dist: pydantic
22
23
  Requires-Dist: InquirerPy
@@ -1,13 +1,13 @@
1
- KekikStream/__init__.py,sha256=LILP4dz-FpG8-GyUIsaZKX2t3uhh662U0AttlmgLviI,10137
1
+ KekikStream/__init__.py,sha256=SZzntUwOYPjSWgtjGmoF2Iu77Y_7A4BtgwV_UX-abHk,10341
2
2
  KekikStream/__main__.py,sha256=4U-NO1f0Mts5Mf_QnWhWqRbTsRBy2y2VPlpHyaqG9_I,137
3
- KekikStream/requirements.txt,sha256=Kh3E0NzIkAmhVODtIwRVffVOHLiElO6Ua9kIgjbocPE,57
3
+ KekikStream/requirements.txt,sha256=gS_TUUQx5A7FUmRGxj2dQedxheD7qA6AswdUb2y_Ub8,70
4
4
  KekikStream/CLI/__init__.py,sha256=9YlF135BVff85y492hX4sq2WY2CNqa4BuVzF9hIIaKE,233
5
5
  KekikStream/CLI/check_update.py,sha256=rOa16bO9sGN-p78yaTRaccFoNfhHWEfDgGZNavpcwNI,1642
6
6
  KekikStream/Core/ExtractorBase.py,sha256=SPXKZPfpzvgkJeMds-USzgpm8-qb0vgZjjLDs58NfGU,1069
7
- KekikStream/Core/ExtractorLoader.py,sha256=JovJJr6Clk3xpbRLlh7v_XOl3FGwVXCjTZivec1FktI,2533
7
+ KekikStream/Core/ExtractorLoader.py,sha256=1S0XaZDJnpFX9dUC4eoqRXx9la6Nlxk6EemJvvSknPA,3921
8
8
  KekikStream/Core/ExtractorModels.py,sha256=vJeh4qd05K7nbqdCCGU29UkGQpce6jXfsCm7LuDL1G8,454
9
9
  KekikStream/Core/MediaHandler.py,sha256=TFFngsvWGV-zllYlrb2HTvFSluGYZ8t83vH_8AXAoO4,3247
10
- KekikStream/Core/PluginBase.py,sha256=MmhGy0XtbkWxE5SNvsag0M_jNehMxPGtVyZFOKlJPM8,2304
10
+ KekikStream/Core/PluginBase.py,sha256=44sJRS8LqkOo0Ul7lE8R4A464wxyym4UplqkpMUJXqY,2511
11
11
  KekikStream/Core/PluginLoader.py,sha256=og5EPfnVqrb2kUkeGU65AY0fU43IbiUo_h3ix6ZiINY,2596
12
12
  KekikStream/Core/PluginModels.py,sha256=WWPEz8PpZZ4bLMDJzTE19BsQEJObkyhaYjDkyLaF2Ck,2365
13
13
  KekikStream/Core/__init__.py,sha256=HZpXs3MKy4joO0sDpIGcZ2DrUKwK49IKG-GQgKbO2jk,416
@@ -20,7 +20,7 @@ KekikStream/Extractors/HDStreamAble.py,sha256=66n5EvIdX_or5cdnlJ_Uqmzi50n4rl9c5V
20
20
  KekikStream/Extractors/Hotlinger.py,sha256=NFMRgUmb6BCrJfa7Hi0VarDNYvCeVknBWEk24FKBBa0,224
21
21
  KekikStream/Extractors/MailRu.py,sha256=lB3Xy912EaSEUw7Im65L5TwtIeM7OLFV1_9lan39g40,1308
22
22
  KekikStream/Extractors/MixPlayHD.py,sha256=4sSHingB3gquakFesnbC0LmkJZWW2Jvv5F4kOdo58tA,1528
23
- KekikStream/Extractors/Odnoklassniki.py,sha256=rP9jzJ42PGyguoEckpm-9nMtfqyXTN2lVzWgG-WYVaI,3296
23
+ KekikStream/Extractors/Odnoklassniki.py,sha256=xt8gWi750ykkWVkFiP6o7HQc-0RwrSx1FxxuoNUU-Js,3765
24
24
  KekikStream/Extractors/OkRuHTTP.py,sha256=L-B0i_i_Vnm61GvUfd6cGIW-o_H4M-C7DO_cdw2rQPU,228
25
25
  KekikStream/Extractors/OkRuSSL.py,sha256=FHJ5XZ1dO5ED3mIku3e3vnq8K0slrcr0jqhaUnHmfVk,227
26
26
  KekikStream/Extractors/PeaceMakerst.py,sha256=1l5Y5AQB_P53upVqgBuJTnjNV7nHVMr56tp673Q8omU,2123
@@ -39,17 +39,18 @@ KekikStream/Extractors/VideoSeyred.py,sha256=Sx1qHNBMboGgU_bXHVgx3MlxtyKpR_LBJIQ
39
39
  KekikStream/Managers/ExtractorManager.py,sha256=9rGlUsnedJ7fwIeObN5Vsm8H5VLal0ODO7F93dDRx8w,976
40
40
  KekikStream/Managers/MediaManager.py,sha256=F7mkSvAttAaMHRvnDcxnV2K1D_sK644BCSrEaAmMl_U,522
41
41
  KekikStream/Managers/PluginManager.py,sha256=YDBLHB_Fh79A3Pei0ny2KLVY4VSihdNiKBh_w5tBl-0,637
42
- KekikStream/Managers/UIManager.py,sha256=PmGabWjHACnaOZLyIfOd0j4cfqpuV34RO58QeeIbF6E,1590
42
+ KekikStream/Managers/UIManager.py,sha256=OrGxzbhRPTCqiLEXjipLb8ChF7saV3fvFIUXLKT9w6Q,1612
43
43
  KekikStream/Managers/__init__.py,sha256=3085I_9Sa2L_Vq6Z-QvYUYn1BapkN4sQqBo8ITZoD_4,251
44
+ KekikStream/Plugins/DiziBox.py,sha256=G2v0ArIGgnOai92-PQ6qj8awQxc-tlOo_UYZs1YK4oU,5791
44
45
  KekikStream/Plugins/FilmMakinesi.py,sha256=g4LRDP5Atn97PqbgnEdm0-wjVdXaJIVk1Ru0F8B66Ws,2902
45
46
  KekikStream/Plugins/FullHDFilmizlesene.py,sha256=HJzHDXHhhMpvXxiD2SjpoZEYs7dmnPymE8EXCSvLKVo,3106
46
47
  KekikStream/Plugins/JetFilmizle.py,sha256=DPdvTEns8r2MI9pHY8d9EEsUZmlQU7N2C9yr8ox80qU,4016
47
48
  KekikStream/Plugins/SezonlukDizi.py,sha256=5BZVzQ2eQtymHxO0bzjA2ho4FFNahPFQly4hoHuH8lo,4441
48
49
  KekikStream/Plugins/SineWix.py,sha256=ZtcIwPW0ONGkSjT7Ye8b71RWdHZMUZefX-JTWu6uGSs,4854
49
50
  KekikStream/Plugins/UgurFilm.py,sha256=U7ryNWpjSZJWuYlMGX1Be9uuyiM3SfuI9VJcEiXedNs,2960
50
- KekikStream-0.2.7.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
51
- KekikStream-0.2.7.dist-info/METADATA,sha256=ZT9huME1aHbhfr_MShWmLS9fEtGdeQBCofWXjwk2pPw,3959
52
- KekikStream-0.2.7.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
53
- KekikStream-0.2.7.dist-info/entry_points.txt,sha256=dFwdiTx8djyehI0Gsz-rZwjAfZzUzoBSrmzRu9ubjJc,50
54
- KekikStream-0.2.7.dist-info/top_level.txt,sha256=DNmGJDXl27Drdfobrak8KYLmocW_uznVYFJOzcjUgmY,12
55
- KekikStream-0.2.7.dist-info/RECORD,,
51
+ KekikStream-0.2.9.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
52
+ KekikStream-0.2.9.dist-info/METADATA,sha256=CtKt_zVjdQzUUk1yyjfulCcc7o6pobvZFWUZZJWehIg,3987
53
+ KekikStream-0.2.9.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
54
+ KekikStream-0.2.9.dist-info/entry_points.txt,sha256=dFwdiTx8djyehI0Gsz-rZwjAfZzUzoBSrmzRu9ubjJc,50
55
+ KekikStream-0.2.9.dist-info/top_level.txt,sha256=DNmGJDXl27Drdfobrak8KYLmocW_uznVYFJOzcjUgmY,12
56
+ KekikStream-0.2.9.dist-info/RECORD,,