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,121 @@
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
+
3
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, ExtractResult, Subtitle
4
+ from parsel import Selector
5
+ import re
6
+
7
+ class SuperFilmGeldi(PluginBase):
8
+ name = "SuperFilmGeldi"
9
+ language = "tr"
10
+ main_url = "https://www.superfilmgeldi13.art"
11
+ favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
12
+ description = "Ücretsiz film izleme sitesi."
13
+
14
+ main_page = {
15
+ f"{main_url}/page/SAYFA" : "Son Eklenenler",
16
+ f"{main_url}/hdizle/category/aksiyon/page/SAYFA" : "Aksiyon",
17
+ f"{main_url}/hdizle/category/animasyon/page/SAYFA" : "Animasyon",
18
+ f"{main_url}/hdizle/category/belgesel/page/SAYFA" : "Belgesel",
19
+ f"{main_url}/hdizle/category/bilim-kurgu/page/SAYFA" : "Bilim Kurgu",
20
+ f"{main_url}/hdizle/category/fantastik/page/SAYFA" : "Fantastik",
21
+ f"{main_url}/hdizle/category/komedi-filmleri/page/SAYFA" : "Komedi Filmleri",
22
+ f"{main_url}/hdizle/category/macera/page/SAYFA" : "Macera",
23
+ f"{main_url}/hdizle/category/gerilim/page/SAYFA" : "Gerilim",
24
+ f"{main_url}/hdizle/category/suc/page/SAYFA" : "Suç",
25
+ f"{main_url}/hdizle/category/karete-filmleri/page/SAYFA" : "Karate Filmleri",
26
+ }
27
+
28
+ async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
29
+ istek = await self.httpx.get(url.replace("SAYFA", str(page)))
30
+ secici = Selector(istek.text)
31
+
32
+ return [
33
+ MainPageResult(
34
+ category = category,
35
+ title = self.clean_title(veri.css("span.movie-title a::text").get().split(" izle")[0]),
36
+ url = self.fix_url(veri.css("span.movie-title a::attr(href)").get()),
37
+ poster = self.fix_url(veri.css("img::attr(src)").get()),
38
+ )
39
+ for veri in secici.css("div.movie-preview-content")
40
+ if veri.css("span.movie-title a::text").get()
41
+ ]
42
+
43
+ async def search(self, query: str) -> list[SearchResult]:
44
+ istek = await self.httpx.get(f"{self.main_url}?s={query}")
45
+ secici = Selector(istek.text)
46
+
47
+ return [
48
+ SearchResult(
49
+ title = self.clean_title(veri.css("span.movie-title a::text").get().split(" izle")[0]),
50
+ url = self.fix_url(veri.css("span.movie-title a::attr(href)").get()),
51
+ poster = self.fix_url(veri.css("img::attr(src)").get()),
52
+ )
53
+ for veri in secici.css("div.movie-preview-content")
54
+ if veri.css("span.movie-title a::text").get()
55
+ ]
56
+
57
+ async def load_item(self, url: str) -> MovieInfo:
58
+ istek = await self.httpx.get(url)
59
+ secici = Selector(istek.text)
60
+
61
+ title = secici.css("div.title h1::text").get()
62
+ title = self.clean_title(title.split(" izle")[0]) if title else ""
63
+ poster = self.fix_url(secici.css("div.poster img::attr(src)").get())
64
+ year = secici.css("div.release a::text").re_first(r"(\d{4})")
65
+ description = secici.css("div.excerpt p::text").get()
66
+ tags = secici.css("div.categories a::text").getall()
67
+ actors = secici.css("div.actor a::text").getall()
68
+
69
+ return MovieInfo(
70
+ url = url,
71
+ poster = poster,
72
+ title = title,
73
+ description = description,
74
+ tags = tags,
75
+ year = year,
76
+ actors = actors,
77
+ )
78
+
79
+ async def load_links(self, url: str) -> list[dict]:
80
+ istek = await self.httpx.get(url)
81
+ secici = Selector(istek.text)
82
+
83
+ iframe = self.fix_url(secici.css("div#vast iframe::attr(src)").get())
84
+ if not iframe:
85
+ return []
86
+
87
+ results = []
88
+
89
+ # Mix player özel işleme
90
+ if "mix" in iframe and "index.php?data=" in iframe:
91
+ iframe_istek = await self.httpx.get(iframe, headers={"Referer": f"{self.main_url}/"})
92
+ mix_point = re.search(r'videoUrl":"(.*)","videoServer', iframe_istek.text)
93
+
94
+ if mix_point:
95
+ mix_point = mix_point[1].replace("\\", "")
96
+
97
+ # Endpoint belirleme
98
+ if "mixlion" in iframe:
99
+ end_point = "?s=3&d="
100
+ elif "mixeagle" in iframe:
101
+ end_point = "?s=1&d="
102
+ else:
103
+ end_point = "?s=0&d="
104
+
105
+ m3u_link = iframe.split("/player")[0] + mix_point + end_point
106
+
107
+ results.append({
108
+ "name" : f"{self.name} | Mix Player",
109
+ "url" : m3u_link,
110
+ "referer" : iframe,
111
+ "subtitles" : []
112
+ })
113
+ else:
114
+ extractor = self.ex_manager.find_extractor(iframe)
115
+ results.append({
116
+ "name" : extractor.name if extractor else "Player",
117
+ "url" : iframe,
118
+ "referer" : f"{self.main_url}/"
119
+ })
120
+
121
+ return results
@@ -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 UgurFilm(PluginBase):
@@ -23,9 +23,8 @@ class UgurFilm(PluginBase):
23
23
  f"{main_url}/category/erotik/page/" : "Erotik"
24
24
  }
25
25
 
26
- #@kekik_cache(ttl=60*60)
27
26
  async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
28
- istek = await self.cffi.get(f"{url}{page}", allow_redirects=True)
27
+ istek = await self.httpx.get(f"{url}{page}", follow_redirects=True)
29
28
  secici = Selector(istek.text)
30
29
 
31
30
  return [
@@ -38,9 +37,8 @@ class UgurFilm(PluginBase):
38
37
  for veri in secici.css("div.icerik div") if veri.css("span:nth-child(1)::text").get()
39
38
  ]
40
39
 
41
- #@kekik_cache(ttl=60*60)
42
40
  async def search(self, query: str) -> list[SearchResult]:
43
- istek = await self.cffi.get(f"{self.main_url}/?s={query}")
41
+ istek = await self.httpx.get(f"{self.main_url}/?s={query}")
44
42
  secici = Selector(istek.text)
45
43
 
46
44
  results = []
@@ -60,9 +58,8 @@ class UgurFilm(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
- istek = await self.cffi.get(url)
62
+ istek = await self.httpx.get(url)
66
63
  secici = Selector(istek.text)
67
64
 
68
65
  title = secici.css("div.bilgi h2::text").get().strip()
@@ -82,14 +79,13 @@ class UgurFilm(PluginBase):
82
79
  actors = actors,
83
80
  )
84
81
 
85
- #@kekik_cache(ttl=15*60)
86
82
  async def load_links(self, url: str) -> list[dict]:
87
- istek = await self.cffi.get(url)
83
+ istek = await self.httpx.get(url)
88
84
  secici = Selector(istek.text)
89
85
  results = []
90
86
 
91
87
  for idx, part_link in enumerate(secici.css("li.parttab a::attr(href)").getall()):
92
- sub_response = await self.cffi.get(part_link)
88
+ sub_response = await self.httpx.get(part_link)
93
89
  sub_selector = Selector(sub_response.text)
94
90
 
95
91
  iframe = sub_selector.css("div#vast iframe::attr(src)").get()
@@ -99,7 +95,7 @@ class UgurFilm(PluginBase):
99
95
  "alternative" : "vidmoly",
100
96
  "ord" : "0",
101
97
  }
102
- player_response = await self.cffi.post(
98
+ player_response = await self.httpx.post(
103
99
  url = f"{self.main_url}/player/ajax_sources.php",
104
100
  data = post_data
105
101
  )
KekikStream/__init__.py CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  from .CLI import konsol, cikis_yap, hata_yakala, pypi_kontrol_guncelle
4
4
  from .Core import PluginManager, ExtractorManager, UIManager, MediaManager, PluginBase, ExtractorBase, SeriesInfo
5
- from asyncio import run
5
+ from asyncio import run, TaskGroup, Semaphore
6
6
  from contextlib import suppress
7
7
 
8
8
  class KekikStream:
@@ -90,21 +90,34 @@ class KekikStream:
90
90
 
91
91
  query = await self.ui.prompt_text("Arama sorgusu:")
92
92
  all_results = []
93
-
94
- for name, plugin in self.plugin.plugins.items():
95
- if not isinstance(plugin, PluginBase) or name == "Shorten":
96
- continue
97
-
98
- konsol.log(f"[yellow][~] {name:<19} aranıyor...[/]")
99
- try:
100
- results = await plugin.search(query)
101
- if results:
102
- all_results.extend([
103
- {"plugin": name, "title": r.title, "url": r.url, "poster": r.poster}
104
- for r in results
105
- ])
106
- except Exception as e:
107
- konsol.print(f"[bold red]{name} hatası: {e}[/bold red]")
93
+
94
+ # Maksimum 5 eşzamanlı arama için semaphore
95
+ semaphore = Semaphore(5)
96
+
97
+ async def search_plugin(name: str, plugin: PluginBase):
98
+ """Tek bir plugin'de ara (semaphore ile sınırlandırılmış)"""
99
+ async with semaphore:
100
+ konsol.log(f"[yellow][~] {name:<19} aranıyor...[/]")
101
+ try:
102
+ results = await plugin.search(query)
103
+ if results:
104
+ return [
105
+ {"plugin": name, "title": r.title, "url": r.url, "poster": r.poster}
106
+ for r in results
107
+ ]
108
+ except Exception as e:
109
+ konsol.print(f"[bold red]{name} hatası: {e}[/bold red]")
110
+ return []
111
+
112
+ # Tüm plugin'leri paralel olarak ara
113
+ async with TaskGroup() as tg:
114
+ tasks = []
115
+ for name, plugin in self.plugin.plugins.items():
116
+ tasks.append(tg.create_task(search_plugin(name, plugin)))
117
+
118
+ # Sonuçları topla
119
+ for task in tasks:
120
+ all_results.extend(task.result())
108
121
 
109
122
  if not all_results:
110
123
  return await self.handle_no_results()
@@ -255,10 +268,11 @@ class KekikStream:
255
268
  self.update_title(selected.get("name"))
256
269
 
257
270
  await self.current_plugin.play(
258
- name = self.media.get_title(),
259
- url = selected.get("url"),
260
- referer = selected.get("referer"),
261
- subtitles = selected.get("subtitles", [])
271
+ name = self.media.get_title(),
272
+ url = selected.get("url"),
273
+ user_agent = selected.get("user_agent"),
274
+ referer = selected.get("referer"),
275
+ subtitles = selected.get("subtitles", [])
262
276
  )
263
277
  return await self.content_finished()
264
278
 
@@ -306,10 +320,6 @@ class KekikStream:
306
320
  self.update_title(selected.get("name"))
307
321
  self.update_title(extract_data.name)
308
322
 
309
- self.media.set_headers(extract_data.headers)
310
- if extract_data.referer and not extract_data.headers.get("Referer"):
311
- self.media.set_headers({"Referer": extract_data.referer})
312
-
313
323
  self.media.play_media(extract_data)
314
324
  await self.content_finished()
315
325
 
@@ -1,10 +1,9 @@
1
1
  setuptools
2
2
  wheel
3
-
4
3
  Kekik
5
- curl-cffi
4
+ httpx
6
5
  cloudscraper
7
6
  parsel
8
-
9
7
  pydantic
10
- InquirerPy
8
+ InquirerPy
9
+ yt-dlp
@@ -0,0 +1,309 @@
1
+ Metadata-Version: 2.4
2
+ Name: KekikStream
3
+ Version: 2.0.2
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
+ Home-page: https://github.com/keyiflerolsun/KekikStream
6
+ Author: keyiflerolsun
7
+ Author-email: keyiflerolsun@gmail.com
8
+ License: GPLv3+
9
+ Keywords: KekikStream,KekikAkademi,keyiflerolsun
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
12
+ Classifier: Programming Language :: Python :: 3
13
+ Requires-Python: >=3.11
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: setuptools
17
+ Requires-Dist: wheel
18
+ Requires-Dist: Kekik
19
+ Requires-Dist: httpx
20
+ Requires-Dist: cloudscraper
21
+ Requires-Dist: parsel
22
+ Requires-Dist: pydantic
23
+ Requires-Dist: InquirerPy
24
+ Requires-Dist: yt-dlp
25
+ Dynamic: author
26
+ Dynamic: author-email
27
+ Dynamic: classifier
28
+ Dynamic: description
29
+ Dynamic: description-content-type
30
+ Dynamic: home-page
31
+ Dynamic: keywords
32
+ Dynamic: license
33
+ Dynamic: license-file
34
+ Dynamic: requires-dist
35
+ Dynamic: requires-python
36
+ Dynamic: summary
37
+
38
+ # <img src="https://github.com/keyiflerolsun/KekikStream/raw/master/.github/icons/KekikStream.png?raw=True" height="32" align="center"> KekikStream
39
+
40
+ [![Boyut](https://img.shields.io/github/repo-size/keyiflerolsun/KekikStream?logo=git&logoColor=white&label=Boyut)](#)
41
+ [![Görüntülenme](https://visitor-badge.laobi.icu/badge?page_id=keyiflerolsun/KekikStream&title=Görüntülenme)](#)
42
+ <a href="https://KekikAkademi.org/Kahve" target="_blank"><img src="https://img.shields.io/badge/☕️-Kahve Ismarla-ffdd00" title="☕️ Kahve Ismarla" style="padding-left:5px;"></a>
43
+
44
+ [![PyPI](https://img.shields.io/pypi/v/KekikStream?logo=pypi&logoColor=white&label=PyPI)](https://pypi.org/project/KekikStream)
45
+ [![PyPI - Yüklenme](https://img.shields.io/pypi/dm/KekikStream?logo=pypi&logoColor=white&label=Yüklenme)](https://pypi.org/project/KekikStream)
46
+ [![PyPI - Wheel](https://img.shields.io/pypi/wheel/KekikStream?logo=pypi&logoColor=white&label=Wheel)](https://pypi.org/project/KekikStream)
47
+
48
+ [![Python Version](https://img.shields.io/pypi/pyversions/KekikStream?logo=python&logoColor=white&label=Python)](#)
49
+ [![Lisans](https://img.shields.io/pypi/l/KekikStream?logo=gnu&logoColor=white&label=Lisans)](#)
50
+ [![Durum](https://img.shields.io/pypi/status/KekikStream?logo=windowsterminal&logoColor=white&label=Durum)](#)
51
+
52
+ [![PyPI Yükle](https://github.com/keyiflerolsun/KekikStream/actions/workflows/pypiYukle.yml/badge.svg)](https://github.com/keyiflerolsun/KekikStream/actions/workflows/pypiYukle.yml)
53
+
54
+ **Modüler ve genişletilebilir medya streaming kütüphanesi**
55
+ Terminal üzerinden içerik arayın, VLC/MPV ile doğrudan izleyin veya kendi API’nizi kurun. 🚀
56
+
57
+ [![Video](https://github.com/user-attachments/assets/63d31bb0-0b69-40b4-84aa-66623f2a253f)](https://github.com/user-attachments/assets/63d31bb0-0b69-40b4-84aa-66623f2a253f)
58
+
59
+ [![ForTheBadge made-with-python](https://ForTheBadge.com/images/badges/made-with-python.svg)](https://www.python.org/)
60
+ [![ForTheBadge built-with-love](https://ForTheBadge.com/images/badges/built-with-love.svg)](https://GitHub.com/keyiflerolsun/)
61
+
62
+ ---
63
+
64
+ ## 🚦 Ne Sunar?
65
+
66
+ KekikStream, Türkçe medya kaynaklarını tek CLI arayüzünde toplayarak hızlı arama ve oynatma sunar. Plugin mimarisi sayesinde yeni kaynaklar eklemek ve [KekikStreamAPI](https://github.com/keyiflerolsun/KekikStreamAPI) ile web/API üzerinden yayın yapmak kolaydır.
67
+
68
+ - 🎥 Çoklu kaynak desteği: Onlarca Türkçe medya sitesi
69
+ - 🔌 Plugin mimarisi: Yeni kaynak eklemek dakikalar sürer
70
+ - 🎬 Çoklu oynatıcı: VLC, MPV, MX Player
71
+ - 🖥️ CLI & kütüphane: Terminalde veya kod içinde kullanın
72
+ - 🌐 API/Web UI: KekikStreamAPI üzerinden uzak erişim
73
+
74
+ ---
75
+
76
+ ## 🚀 Hızlı Başlangıç
77
+
78
+ > Gereksinimler: Python 3.11+, sistemde VLC veya MPV kurulu olmalı (Android için MX Player + ADB).
79
+
80
+ ```bash
81
+ # Kurulum
82
+ pip install KekikStream
83
+
84
+ # Güncelleme
85
+ pip install -U KekikStream
86
+ ```
87
+
88
+ ### Temel Kullanım
89
+
90
+ **CLI:**
91
+ ```bash
92
+ KekikStream
93
+ ```
94
+
95
+ ---
96
+
97
+ ## ✨ Özellikler
98
+
99
+ ### 🔌 Plugin Sistemi
100
+
101
+ KekikStream modüler bir plugin mimarisi kullanır; her medya kaynağı bağımsız bir plugin'dir.
102
+
103
+ **Mevcut Pluginler (örnek):** Dizilla, HDFilmCehennemi, Dizipal, Dizifon, RoketDizi, Sinefy, Moviesseed, FullHDFilmizlesene, HDBestMovies, SuperFilmGeldi, Sinezy ve daha fazlası.
104
+
105
+ **Plugin Geliştirme:**
106
+ ```python
107
+ from KekikStream.Core import PluginBase, MainPageResult, SearchResult, MovieInfo, SeriesInfo
108
+
109
+ class MyPlugin(PluginBase):
110
+ name = "MyPlugin"
111
+ language = "en"
112
+ main_url = "https://example.com"
113
+ favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
114
+ description = "MyPlugin description"
115
+
116
+ main_page = {
117
+ f"{main_url}/category/" : "Category Name"
118
+ }
119
+
120
+ async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
121
+ return results
122
+
123
+ async def search(self, query: str) -> list[SearchResult]:
124
+ return results
125
+
126
+ async def load_item(self, url: str) -> MovieInfo | SeriesInfo:
127
+ return details
128
+
129
+ async def load_links(self, url: str) -> list[dict]:
130
+ return links
131
+ ```
132
+
133
+ ### 🎬 Oynatıcı Desteği
134
+
135
+ | Oynatıcı | Platform | Özellikler |
136
+ |---------------|----------|---------------------------|
137
+ | **MPV** | Desktop | Custom headers, subtitles |
138
+ | **VLC** | Desktop | Custom headers, subtitles |
139
+ | **MX Player** | Android | ADB üzerinden |
140
+
141
+ > Özel durumlar için (Google Drive vb.) arka planda otomatik olarak yt-dlp devreye girer.
142
+
143
+ ### 🔗 Extractor Sistemi
144
+
145
+ Vidmoly, Filemoon, Sibnet, Sendvid, Voe, Doodstream, Streamtape, Upstream, Dailymotion, JWPlayer ve birçok kaynaktan direkt streaming linki çıkarır.
146
+
147
+ ---
148
+
149
+ ## 🏗️ Mimari
150
+
151
+ ```mermaid
152
+ graph TB
153
+ CLI[🖥️ CLI Interface]
154
+ Manager[🔌 Plugin Manager]
155
+
156
+ subgraph Plugins
157
+ P1[📺 Dizilla]
158
+ P2[🎬 HDFilmCehennemi]
159
+ P3[🍿 Dizipal]
160
+ PN[... 20+ Plugin]
161
+ end
162
+
163
+ subgraph Extractors
164
+ E1[🔗 Vidmoly]
165
+ E2[🔗 Filemoon]
166
+ E3[🔗 Sibnet]
167
+ EN[... Extractors]
168
+ end
169
+
170
+ subgraph Players
171
+ MPV[🎥 MPV]
172
+ VLC[🎥 VLC]
173
+ MX[🎥 MX Player]
174
+ end
175
+
176
+ CLI --> Manager
177
+ Manager --> P1
178
+ Manager --> P2
179
+ Manager --> P3
180
+ Manager --> PN
181
+
182
+ %% Her plugin otomatik olarak ihtiyaç duyduğu extractor'ı kullanır
183
+ P1 -.-> E1
184
+ P1 -.-> E2
185
+ P1 -.-> E3
186
+
187
+ P2 -.-> E1
188
+ P2 -.-> E2
189
+ P2 -.-> E3
190
+
191
+ P3 -.-> E1
192
+ P3 -.-> E2
193
+ P3 -.-> E3
194
+
195
+ PN -.-> EN
196
+
197
+ E1 --> VLC
198
+ E2 --> VLC
199
+ E3 --> VLC
200
+ EN --> VLC
201
+
202
+ E1 --> MPV
203
+ E2 --> MPV
204
+ E3 --> MPV
205
+ EN --> MPV
206
+
207
+ E1 --> MX
208
+ E2 --> MX
209
+ E3 --> MX
210
+ EN --> MX
211
+ ```
212
+
213
+ ---
214
+
215
+ ## 🛠️ Geliştirme
216
+
217
+ ### Proje Yapısı
218
+
219
+ ```
220
+ KekikStream/
221
+ ├── KekikStream/
222
+ │ ├── Core/ # Temel sınıflar
223
+ │ ├── Libs/ # Yardımcı kütüphaneler
224
+ │ ├── Plugins/ # Medya kaynak pluginleri
225
+ │ ├── Extractors/ # Video extractorları
226
+ │ └── __init__.py # CLI entry point
227
+ ├── Tests/ # Örnek kullanım
228
+ └── requirements.txt
229
+ ```
230
+
231
+ ### Yeni Plugin Ekleme
232
+
233
+ 1. `KekikStream/Plugins/` altına yeni dosya oluşturun.
234
+ 2. `PluginBase` sınıfından türetin.
235
+ 3. `get_main_page`, `search`, `load_item`, `load_links` metodlarını implemente edin.
236
+ 4. Plugin'i test edin (örnek: `Tests/Single.py`).
237
+
238
+ ### 🔧 Geliştirme Modu
239
+
240
+ KekikStream, eklenti geliştiricileri için otomatik bir **geliştirme modu** sunar:
241
+
242
+ **Plugin Geliştirme:**
243
+ - Çalışma dizininde `Plugins/` klasörü oluşturup içine plugin dosyası eklerseniz, **sadece bu local plugin'ler** yüklenir
244
+ - Global plugin'ler (sisteme kurulu olanlar) otomatik olarak atlanır
245
+ - Bu sayede test sırasında diğer plugin'lerle karışma olmaz
246
+
247
+ **Extractor Geliştirme:**
248
+ - Çalışma dizininde `Extractors/` klasörü oluşturup içine extractor dosyası eklerseniz, **sadece bu local extractor'lar** yüklenir
249
+ - Global extractor'lar otomatik olarak atlanır
250
+ - Kendi extractor'ınızı izole bir ortamda test edebilirsiniz
251
+
252
+ **Örnek:**
253
+ ```bash
254
+ # Çalışma dizininizde
255
+ mkdir Plugins
256
+ touch Plugins/MyTestPlugin.py # Plugin'inizi yazın
257
+
258
+ # KekikStream'i çalıştırın - sadece MyTestPlugin yüklenecek
259
+ KekikStream
260
+ ```
261
+
262
+ > 💡 **Not:** Yerel dizinde herhangi bir Plugin/Extractor dosyası bulunmazsa, sistem normal şekilde global olanları yükler.
263
+
264
+ ---
265
+
266
+ ## 📊 Performans
267
+
268
+ | Metrik | Değer |
269
+ |----------------------|------------------|
270
+ | Plugin Sayısı | 20+ |
271
+ | Extractor Sayısı | 40+ |
272
+ | Desteklenen Platform | Desktop, Android |
273
+ | Async Arama | ✅ |
274
+ | Cache Desteği | ✅ |
275
+
276
+ ---
277
+
278
+ ## 🤝 Katkıda Bulunma
279
+
280
+ Projeyi geliştirmek için katkılarınızı bekliyoruz!
281
+
282
+ 1. Yeni plugin ekleyin
283
+ 2. Bug raporu açın
284
+ 3. Feature request gönderin
285
+ 4. Dokümantasyon iyileştirin
286
+
287
+ ### 🎁 Teşekkürler
288
+
289
+ - [DeoDorqnt387/aniwatch-tr](https://github.com/DeoDorqnt387/aniwatch-tr)
290
+
291
+ ### 💻 Genişletme Referansları
292
+
293
+ - [keyiflerolsun/Kekik-cloudstream](https://github.com/keyiflerolsun/Kekik-cloudstream)
294
+ - [keyiflerolsun/seyirTurk-Parser](https://github.com/keyiflerolsun/seyirTurk-Parser)
295
+
296
+ ## 🌐 Telif Hakkı ve Lisans
297
+
298
+ *Copyright (C) 2024 by* [keyiflerolsun](https://github.com/keyiflerolsun) ❤️️
299
+ [GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007](https://github.com/keyiflerolsun/KekikStream/blob/master/LICENSE) *Koşullarına göre lisanslanmıştır..*
300
+
301
+ ---
302
+
303
+ <p align="center">
304
+ Bu proje <a href="https://github.com/keyiflerolsun">@keyiflerolsun</a> tarafından <a href="https://t.me/KekikAkademi">@KekikAkademi</a> için geliştirilmiştir.
305
+ </p>
306
+
307
+ <p align="center">
308
+ <sub>⭐ Beğendiyseniz yıldız vermeyi unutmayın!</sub>
309
+ </p>