KekikStream 2.3.4__tar.gz → 2.3.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.
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Core/Plugin/PluginBase.py +8 -1
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/ContentX.py +27 -22
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/MolyStream.py +10 -0
- kekikstream-2.3.5/KekikStream/Plugins/DiziWatch.py +217 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/Dizilla.py +3 -1
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/SezonlukDizi.py +3 -3
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/Sinefy.py +5 -0
- kekikstream-2.3.5/KekikStream/Plugins/YabanciDizi.py +274 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream.egg-info/PKG-INFO +1 -1
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream.egg-info/SOURCES.txt +3 -1
- {kekikstream-2.3.4 → kekikstream-2.3.5}/PKG-INFO +1 -1
- {kekikstream-2.3.4 → kekikstream-2.3.5}/setup.py +1 -1
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/CLI/__init__.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/CLI/pypi_kontrol.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Core/Extractor/ExtractorBase.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Core/Extractor/ExtractorLoader.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Core/Extractor/ExtractorManager.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Core/Extractor/ExtractorModels.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Core/Extractor/YTDLPCache.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Core/HTMLHelper.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Core/Media/MediaHandler.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Core/Media/MediaManager.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Core/Plugin/PluginLoader.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Core/Plugin/PluginManager.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Core/Plugin/PluginModels.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Core/UI/UIManager.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Core/__init__.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/CloseLoad.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/DonilasPlay.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/DzenRu.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/ExPlay.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/Filemoon.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/HDPlayerSystem.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/JFVid.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/JetTv.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/MailRu.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/MixPlayHD.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/MixTiger.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/Odnoklassniki.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/PeaceMakerst.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/PixelDrain.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/PlayerFilmIzle.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/RapidVid.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/SetPlay.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/SetPrime.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/SibNet.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/Sobreatsesuyp.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/TRsTX.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/TauVideo.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/TurboImgz.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/TurkeyPlayer.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/VCTPlay.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/VidHide.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/VidMoly.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/VidMoxy.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/VidPapi.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/VideoSeyred.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/YTDLP.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Extractors/YildizKisaFilm.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/BelgeselX.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/DiziBox.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/DiziPal.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/DiziYou.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/FilmBip.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/FilmMakinesi.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/FilmModu.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/FullHDFilm.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/FullHDFilmizlesene.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/HDFilmCehennemi.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/JetFilmizle.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/KultFilmler.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/RecTV.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/RoketDizi.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/SelcukFlix.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/SetFilmIzle.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/SineWix.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/SinemaCX.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/Sinezy.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/SuperFilmGeldi.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/Plugins/UgurFilm.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/__init__.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/__main__.py +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream/requirements.txt +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream.egg-info/dependency_links.txt +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream.egg-info/entry_points.txt +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream.egg-info/requires.txt +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/KekikStream.egg-info/top_level.txt +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/LICENSE +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/MANIFEST.in +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/README.md +0 -0
- {kekikstream-2.3.4 → kekikstream-2.3.5}/setup.cfg +0 -0
|
@@ -122,7 +122,14 @@ class PluginBase(ABC):
|
|
|
122
122
|
try:
|
|
123
123
|
data = await extractor.extract(url, referer=referer)
|
|
124
124
|
|
|
125
|
-
#
|
|
125
|
+
# Liste ise her bir öğe için prefix ekle
|
|
126
|
+
if isinstance(data, list):
|
|
127
|
+
for item in data:
|
|
128
|
+
if prefix and item.name:
|
|
129
|
+
item.name = f"{prefix} | {item.name}"
|
|
130
|
+
return data
|
|
131
|
+
|
|
132
|
+
# Tekil öğe ise
|
|
126
133
|
if prefix and data.name:
|
|
127
134
|
data.name = f"{prefix} | {data.name}"
|
|
128
135
|
|
|
@@ -30,7 +30,7 @@ class ContentX(ExtractorBase):
|
|
|
30
30
|
istek.raise_for_status()
|
|
31
31
|
i_source = istek.text
|
|
32
32
|
|
|
33
|
-
i_extract_value = HTMLHelper(i_source).regex_first(r"window\.openPlayer\('([^']+)'
|
|
33
|
+
i_extract_value = HTMLHelper(i_source).regex_first(r"window\.openPlayer\('([^']+)'")
|
|
34
34
|
if not i_extract_value:
|
|
35
35
|
raise ValueError("i_extract is null")
|
|
36
36
|
|
|
@@ -47,8 +47,12 @@ class ContentX(ExtractorBase):
|
|
|
47
47
|
name = sub_lang.replace("\\u0131", "ı")
|
|
48
48
|
.replace("\\u0130", "İ")
|
|
49
49
|
.replace("\\u00fc", "ü")
|
|
50
|
-
.replace("\\u00e7", "ç")
|
|
51
|
-
|
|
50
|
+
.replace("\\u00e7", "ç")
|
|
51
|
+
.replace("\\u011f", "ğ")
|
|
52
|
+
.replace("\\u015f", "ş")
|
|
53
|
+
.replace("\\u011e", "Ğ")
|
|
54
|
+
.replace("\\u015e", "Ş"),
|
|
55
|
+
url = self.fix_url(sub_url.replace("\\/", "/").replace("\\", ""))
|
|
52
56
|
)
|
|
53
57
|
)
|
|
54
58
|
|
|
@@ -61,7 +65,7 @@ class ContentX(ExtractorBase):
|
|
|
61
65
|
if not m3u_link:
|
|
62
66
|
raise ValueError("vidExtract is null")
|
|
63
67
|
|
|
64
|
-
m3u_link = m3u_link.replace("\\", "")
|
|
68
|
+
m3u_link = m3u_link.replace("\\", "").replace("/m.php", "/master.m3u8")
|
|
65
69
|
results = [
|
|
66
70
|
ExtractResult(
|
|
67
71
|
name = self.name,
|
|
@@ -71,24 +75,25 @@ class ContentX(ExtractorBase):
|
|
|
71
75
|
)
|
|
72
76
|
]
|
|
73
77
|
|
|
74
|
-
dublaj_value = HTMLHelper(i_source).regex_first(r'
|
|
78
|
+
dublaj_value = HTMLHelper(i_source).regex_first(r'["\']([^"\']+)["\'],["\']Türkçe["\']')
|
|
75
79
|
if dublaj_value:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
80
|
+
try:
|
|
81
|
+
dublaj_source_request = await self.httpx.get(f"{base_url}/source2.php?v={dublaj_value}", headers={"Referer": referer or base_url})
|
|
82
|
+
dublaj_source_request.raise_for_status()
|
|
83
|
+
|
|
84
|
+
dublaj_source = dublaj_source_request.text
|
|
85
|
+
dublaj_link = HTMLHelper(dublaj_source).regex_first(r'file":"([^\"]+)"')
|
|
86
|
+
if dublaj_link:
|
|
87
|
+
dublaj_link = dublaj_link.replace("\\", "")
|
|
88
|
+
results.append(
|
|
89
|
+
ExtractResult(
|
|
90
|
+
name = f"{self.name} Türkçe Dublaj",
|
|
91
|
+
url = dublaj_link,
|
|
92
|
+
referer = url,
|
|
93
|
+
subtitles = []
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
except Exception:
|
|
97
|
+
pass
|
|
93
98
|
|
|
94
99
|
return results[0] if len(results) == 1 else results
|
|
@@ -7,6 +7,16 @@ class MolyStream(ExtractorBase):
|
|
|
7
7
|
name = "MolyStream"
|
|
8
8
|
main_url = "https://dbx.molystream.org"
|
|
9
9
|
|
|
10
|
+
# Birden fazla domain destekle
|
|
11
|
+
supported_domains = [
|
|
12
|
+
"ydx.molystream.org",
|
|
13
|
+
"yd.sheila.stream",
|
|
14
|
+
"ydf.popcornvakti.net",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
def can_handle_url(self, url: str) -> bool:
|
|
18
|
+
return any(domain in url for domain in self.supported_domains)
|
|
19
|
+
|
|
10
20
|
async def extract(self, url, referer=None) -> ExtractResult:
|
|
11
21
|
if "doctype html" in url:
|
|
12
22
|
secici = HTMLHelper(url)
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, Episode, ExtractResult, HTMLHelper
|
|
4
|
+
import urllib.parse
|
|
5
|
+
|
|
6
|
+
class DiziWatch(PluginBase):
|
|
7
|
+
name = "DiziWatch"
|
|
8
|
+
language = "tr"
|
|
9
|
+
main_url = "https://diziwatch.to"
|
|
10
|
+
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
11
|
+
description = "Diziwatch; en güncel yabancı dizileri ve animeleri, Türkçe altyazılı ve dublaj seçenekleriyle izleyebileceğiniz platform."
|
|
12
|
+
|
|
13
|
+
main_page = {
|
|
14
|
+
f"{main_url}/episodes" : "Yeni Bölümler",
|
|
15
|
+
"9" : "Aksiyon",
|
|
16
|
+
"17" : "Animasyon",
|
|
17
|
+
"5" : "Bilim Kurgu",
|
|
18
|
+
"2" : "Dram",
|
|
19
|
+
"12" : "Fantastik",
|
|
20
|
+
"3" : "Gizem",
|
|
21
|
+
"4" : "Komedi",
|
|
22
|
+
"8" : "Korku",
|
|
23
|
+
"24" : "Macera",
|
|
24
|
+
"14" : "Müzik",
|
|
25
|
+
"7" : "Romantik",
|
|
26
|
+
"23" : "Spor",
|
|
27
|
+
"1" : "Suç",
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
def __init__(self):
|
|
31
|
+
super().__init__()
|
|
32
|
+
self.c_key = None
|
|
33
|
+
self.c_value = None
|
|
34
|
+
|
|
35
|
+
async def _init_session(self):
|
|
36
|
+
if self.c_key and self.c_value:
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
# Fetch anime-arsivi to get CSRF tokens
|
|
40
|
+
resp = await self.httpx.get(f"{self.main_url}/anime-arsivi")
|
|
41
|
+
sel = HTMLHelper(resp.text)
|
|
42
|
+
|
|
43
|
+
# form.bg-[rgba(255,255,255,.15)] > input
|
|
44
|
+
# We can just look for the first two inputs in that specific form
|
|
45
|
+
inputs = sel.select("form.bg-\\[rgba\\(255\\,255\\,255\\,\\.15\\)\\] input")
|
|
46
|
+
if len(inputs) >= 2:
|
|
47
|
+
self.c_key = inputs[0].attrs.get("value")
|
|
48
|
+
self.c_value = inputs[1].attrs.get("value")
|
|
49
|
+
|
|
50
|
+
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
51
|
+
await self._init_session()
|
|
52
|
+
|
|
53
|
+
if url.startswith("https://"):
|
|
54
|
+
full_url = f"{url}?page={page}"
|
|
55
|
+
resp = await self.httpx.get(full_url, headers={"Referer": f"{self.main_url}/"})
|
|
56
|
+
sel = HTMLHelper(resp.text)
|
|
57
|
+
items = sel.select("div.swiper-slide a")
|
|
58
|
+
else:
|
|
59
|
+
# Category ID based
|
|
60
|
+
full_url = f"{self.main_url}/anime-arsivi?category={url}&minImdb=&name=&release_year=&sort=date_desc&page={page}"
|
|
61
|
+
resp = await self.httpx.get(full_url, headers={"Referer": f"{self.main_url}/"})
|
|
62
|
+
sel = HTMLHelper(resp.text)
|
|
63
|
+
items = sel.select("div.content-inner a")
|
|
64
|
+
|
|
65
|
+
results = []
|
|
66
|
+
for item in items:
|
|
67
|
+
title = sel.select_text("h2", item)
|
|
68
|
+
href = item.attrs.get("href") if item.tag == "a" else sel.select_attr("a", "href", item)
|
|
69
|
+
poster = sel.select_attr("img", "src", item) or sel.select_attr("img", "data-src", item)
|
|
70
|
+
|
|
71
|
+
if title and href:
|
|
72
|
+
# If it's an episode link, clean it to get show link
|
|
73
|
+
# Regex in Kotlin: /sezon-\d+/bolum-\d+/?$
|
|
74
|
+
clean_href = HTMLHelper(href).regex_replace(r"/sezon-\d+/bolum-\d+/?$", "")
|
|
75
|
+
|
|
76
|
+
# If cleaning changed something, it was an episode link, maybe add it to title
|
|
77
|
+
if clean_href != href:
|
|
78
|
+
se_info = sel.select_text("div.flex.gap-1.items-center", item)
|
|
79
|
+
if se_info:
|
|
80
|
+
title = f"{title} - {se_info}"
|
|
81
|
+
|
|
82
|
+
results.append(MainPageResult(
|
|
83
|
+
category = category,
|
|
84
|
+
title = title,
|
|
85
|
+
url = self.fix_url(clean_href),
|
|
86
|
+
poster = self.fix_url(poster) if poster else None
|
|
87
|
+
))
|
|
88
|
+
|
|
89
|
+
return results
|
|
90
|
+
|
|
91
|
+
async def search(self, query: str) -> list[SearchResult]:
|
|
92
|
+
await self._init_session()
|
|
93
|
+
|
|
94
|
+
post_url = f"{self.main_url}/bg/searchcontent"
|
|
95
|
+
data = {
|
|
96
|
+
"cKey" : self.c_key,
|
|
97
|
+
"cValue" : self.c_value,
|
|
98
|
+
"searchterm" : query
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
headers = {
|
|
102
|
+
"X-Requested-With" : "XMLHttpRequest",
|
|
103
|
+
"Accept" : "application/json, text/javascript, */*; q=0.01",
|
|
104
|
+
"Referer" : f"{self.main_url}/"
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
resp = await self.httpx.post(post_url, data=data, headers=headers)
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
raw = resp.json()
|
|
111
|
+
# Kotlin maps this to ApiResponse -> DataWrapper -> Icerikler
|
|
112
|
+
res_array = raw.get("data", {}).get("result", [])
|
|
113
|
+
|
|
114
|
+
results = []
|
|
115
|
+
for item in res_array:
|
|
116
|
+
title = item.get("object_name", "").replace("\\", "")
|
|
117
|
+
slug = item.get("used_slug", "").replace("\\", "")
|
|
118
|
+
poster = item.get("object_poster_url", "")
|
|
119
|
+
|
|
120
|
+
# Cleanup poster URL as in Kotlin
|
|
121
|
+
if poster:
|
|
122
|
+
poster = poster.replace("images-macellan-online.cdn.ampproject.org/i/s/", "") \
|
|
123
|
+
.replace("file.dizilla.club", "file.macellan.online") \
|
|
124
|
+
.replace("images.dizilla.club", "images.macellan.online") \
|
|
125
|
+
.replace("images.dizimia4.com", "images.macellan.online") \
|
|
126
|
+
.replace("file.dizimia4.com", "file.macellan.online")
|
|
127
|
+
poster = HTMLHelper(poster).regex_replace(r"(file\.)[\w\.]+\/?", r"\1macellan.online/")
|
|
128
|
+
poster = HTMLHelper(poster).regex_replace(r"(images\.)[\w\.]+\/?", r"\1macellan.online/")
|
|
129
|
+
poster = poster.replace("/f/f/", "/630/910/")
|
|
130
|
+
|
|
131
|
+
if title and slug:
|
|
132
|
+
results.append(SearchResult(
|
|
133
|
+
title = title,
|
|
134
|
+
url = self.fix_url(slug),
|
|
135
|
+
poster = self.fix_url(poster) if poster else None
|
|
136
|
+
))
|
|
137
|
+
return results
|
|
138
|
+
except Exception:
|
|
139
|
+
return []
|
|
140
|
+
|
|
141
|
+
async def load_item(self, url: str) -> SeriesInfo:
|
|
142
|
+
resp = await self.httpx.get(url)
|
|
143
|
+
sel = HTMLHelper(resp.text)
|
|
144
|
+
|
|
145
|
+
title = sel.select_text("h2")
|
|
146
|
+
poster = sel.select_attr("img.rounded-md", "src")
|
|
147
|
+
description = sel.select_text("div.text-sm")
|
|
148
|
+
|
|
149
|
+
year = sel.regex_first(r"Yap\u0131m Y\u0131l\u0131\s*:\s*(\d+)", resp.text)
|
|
150
|
+
|
|
151
|
+
tags = []
|
|
152
|
+
tags_raw = sel.regex_first(r"T\u00fcr\s*:\s*([^<]+)", resp.text)
|
|
153
|
+
if tags_raw:
|
|
154
|
+
tags = [t.strip() for t in tags_raw.split(",")]
|
|
155
|
+
|
|
156
|
+
rating = sel.select_text(".font-semibold.text-white")
|
|
157
|
+
if rating:
|
|
158
|
+
rating = rating.replace(",", ".").strip()
|
|
159
|
+
|
|
160
|
+
actors = [a.text(strip=True) for a in sel.select("span.valor a")]
|
|
161
|
+
|
|
162
|
+
trailer_match = sel.regex_first(r"embed\/(.*)\?rel", resp.text)
|
|
163
|
+
trailer = f"https://www.youtube.com/embed/{trailer_match}" if trailer_match else None
|
|
164
|
+
|
|
165
|
+
duration_text = sel.select_text("span.runtime")
|
|
166
|
+
duration = duration_text.split(" ")[0] if duration_text else None
|
|
167
|
+
|
|
168
|
+
episodes = []
|
|
169
|
+
# ul a handles episodes
|
|
170
|
+
for ep_link in sel.select("ul a"):
|
|
171
|
+
href = ep_link.attrs.get("href")
|
|
172
|
+
if not href or "/sezon-" not in href:
|
|
173
|
+
continue
|
|
174
|
+
|
|
175
|
+
ep_name = sel.select_text("span.hidden.sm\\:block", ep_link)
|
|
176
|
+
|
|
177
|
+
season_match = sel.regex_first(r"sezon-(\d+)", href)
|
|
178
|
+
episode_match = sel.regex_first(r"bolum-(\d+)", href)
|
|
179
|
+
|
|
180
|
+
season = season_match if season_match else None
|
|
181
|
+
episode_num = episode_match if episode_match else None
|
|
182
|
+
|
|
183
|
+
episodes.append(Episode(
|
|
184
|
+
season = int(season) if season and season.isdigit() else None,
|
|
185
|
+
episode = int(episode_num) if episode_num and episode_num.isdigit() else None,
|
|
186
|
+
title = ep_name if ep_name else f"{season}x{episode_num}",
|
|
187
|
+
url = self.fix_url(href)
|
|
188
|
+
))
|
|
189
|
+
|
|
190
|
+
return SeriesInfo(
|
|
191
|
+
title = title,
|
|
192
|
+
url = url,
|
|
193
|
+
poster = self.fix_url(poster) if poster else None,
|
|
194
|
+
description = description,
|
|
195
|
+
rating = rating,
|
|
196
|
+
tags = tags,
|
|
197
|
+
actors = actors,
|
|
198
|
+
year = year,
|
|
199
|
+
episodes = episodes,
|
|
200
|
+
duration = int(duration) if duration and str(duration).isdigit() else None
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
204
|
+
resp = await self.httpx.get(url)
|
|
205
|
+
sel = HTMLHelper(resp.text)
|
|
206
|
+
|
|
207
|
+
iframe = sel.select_attr("iframe", "src")
|
|
208
|
+
if not iframe:
|
|
209
|
+
return []
|
|
210
|
+
|
|
211
|
+
iframe_url = self.fix_url(iframe)
|
|
212
|
+
data = await self.extract(iframe_url, referer=f"{self.main_url}/")
|
|
213
|
+
|
|
214
|
+
if not data:
|
|
215
|
+
return []
|
|
216
|
+
|
|
217
|
+
return data if isinstance(data, list) else [data]
|
|
@@ -248,4 +248,6 @@ class Dizilla(PluginBase):
|
|
|
248
248
|
return []
|
|
249
249
|
|
|
250
250
|
data = await self.extract(iframe_url, referer=f"{self.main_url}/", prefix=first_result.get('language_name', 'Unknown'))
|
|
251
|
-
|
|
251
|
+
if not data:
|
|
252
|
+
return []
|
|
253
|
+
return data if isinstance(data, list) else [data]
|
|
@@ -75,9 +75,9 @@ class SezonlukDizi(PluginBase):
|
|
|
75
75
|
|
|
76
76
|
results = []
|
|
77
77
|
for afis in secici.select("div.afis a"):
|
|
78
|
-
title = secici.select_text("div.description",
|
|
79
|
-
href = secici.select_attr("a", "href",
|
|
80
|
-
poster = secici.select_attr("img", "data-src",
|
|
78
|
+
title = secici.select_text("div.description", afis)
|
|
79
|
+
href = secici.select_attr("a", "href", afis)
|
|
80
|
+
poster = secici.select_attr("img", "data-src", afis)
|
|
81
81
|
|
|
82
82
|
if title and href:
|
|
83
83
|
results.append(SearchResult(
|
|
@@ -159,6 +159,11 @@ class Sinefy(PluginBase):
|
|
|
159
159
|
actors = [h5.text(strip=True) for h5 in sel.select("div.content h5") if h5.text(strip=True)]
|
|
160
160
|
|
|
161
161
|
year = sel.select_text("span.item.year")
|
|
162
|
+
if not year and title:
|
|
163
|
+
# Try to extract year from title like "Movie Name(2024)"
|
|
164
|
+
year_match = sel.regex_first(r"\((\d{4})\)", title)
|
|
165
|
+
if year_match:
|
|
166
|
+
year = year_match
|
|
162
167
|
|
|
163
168
|
episodes = []
|
|
164
169
|
episodes_box_list = sel.select("section.episodes-box")
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
|
|
2
|
+
|
|
3
|
+
from KekikStream.Core import PluginBase, MainPageResult, SearchResult, SeriesInfo, MovieInfo, Episode, ExtractResult, HTMLHelper
|
|
4
|
+
import json, asyncio, time
|
|
5
|
+
|
|
6
|
+
class YabanciDizi(PluginBase):
|
|
7
|
+
name = "YabanciDizi"
|
|
8
|
+
language = "tr"
|
|
9
|
+
main_url = "https://yabancidizi.so"
|
|
10
|
+
favicon = f"https://www.google.com/s2/favicons?domain={main_url}&sz=64"
|
|
11
|
+
description = "Yabancidizi.so platformu üzerinden en güncel yabancı dizileri ve filmleri izleyebilir, favori içeriklerinizi takip edebilirsiniz."
|
|
12
|
+
|
|
13
|
+
main_page = {
|
|
14
|
+
f"{main_url}/kesfet/eyJvcmRlciI6ImRhdGVfYm90dG9tIiwia2F0ZWdvcnkiOlsiMTciXX0=" : "Diziler",
|
|
15
|
+
f"{main_url}/kesfet/eyJvcmRlciI6ImRhdGVfYm90dG9tIiwia2F0ZWdvcnkiOlsiMTgiXX0=" : "Filmler",
|
|
16
|
+
f"{main_url}/kesfet/eyJvcmRlciI6ImRhdGVfYm90dG9tIiwiY291bnRyeSI6eyJLUiI6IktSIn19" : "Kdrama",
|
|
17
|
+
f"{main_url}/kesfet/eyJvcmRlciI6ImRhdGVfYm90dG9tIiwiY291bnRyeSI6eyJKUCI6IkpQIn0sImNhdGVnb3J5IjpbXX0=" : "Jdrama",
|
|
18
|
+
f"{main_url}/kesfet/eyJvcmRlciI6ImRhdGVfYm90dG9tIiwiY2F0ZWdvcnkiOnsiMyI6IjMifX0=" : "Animasyon",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async def get_main_page(self, page: int, url: str, category: str) -> list[MainPageResult]:
|
|
22
|
+
full_url = url if page == 1 else f"{url}/{page}"
|
|
23
|
+
|
|
24
|
+
resp = await self.httpx.get(full_url, headers={"Referer": f"{self.main_url}/"})
|
|
25
|
+
sel = HTMLHelper(resp.text)
|
|
26
|
+
|
|
27
|
+
results = []
|
|
28
|
+
for item in sel.select("li.mb-lg, li.segment-poster"):
|
|
29
|
+
title = sel.select_text("h2", item)
|
|
30
|
+
href = sel.select_attr("a", "href", item)
|
|
31
|
+
poster = sel.select_attr("img", "src", item)
|
|
32
|
+
score = sel.select_text("span.rating", item)
|
|
33
|
+
|
|
34
|
+
if title and href:
|
|
35
|
+
results.append(MainPageResult(
|
|
36
|
+
category = category,
|
|
37
|
+
title = title,
|
|
38
|
+
url = self.fix_url(href),
|
|
39
|
+
poster = self.fix_url(poster) if poster else None,
|
|
40
|
+
))
|
|
41
|
+
|
|
42
|
+
return results
|
|
43
|
+
|
|
44
|
+
async def search(self, query: str) -> list[SearchResult]:
|
|
45
|
+
search_url = f"{self.main_url}/search?qr={query}"
|
|
46
|
+
|
|
47
|
+
headers = {
|
|
48
|
+
"X-Requested-With" : "XMLHttpRequest",
|
|
49
|
+
"Referer" : f"{self.main_url}/"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
resp = await self.httpx.post(search_url, headers=headers)
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
raw = resp.json()
|
|
56
|
+
# Kotlin mapping: JsonResponse -> Data -> ResultItem
|
|
57
|
+
res_array = raw.get("data", {}).get("result", [])
|
|
58
|
+
|
|
59
|
+
results = []
|
|
60
|
+
for item in res_array:
|
|
61
|
+
title = item.get("s_name")
|
|
62
|
+
image = item.get("s_image")
|
|
63
|
+
slug = item.get("s_link")
|
|
64
|
+
s_type = item.get("s_type") # 0: dizi, 1: film
|
|
65
|
+
|
|
66
|
+
poster = f"{self.main_url}/uploads/series/{image}" if image else None
|
|
67
|
+
|
|
68
|
+
if s_type == "1":
|
|
69
|
+
href = f"{self.main_url}/film/{slug}"
|
|
70
|
+
else:
|
|
71
|
+
href = f"{self.main_url}/dizi/{slug}"
|
|
72
|
+
|
|
73
|
+
if title and slug:
|
|
74
|
+
results.append(SearchResult(
|
|
75
|
+
title = title,
|
|
76
|
+
url = self.fix_url(href),
|
|
77
|
+
poster = self.fix_url(poster) if poster else None
|
|
78
|
+
))
|
|
79
|
+
return results
|
|
80
|
+
except Exception:
|
|
81
|
+
return []
|
|
82
|
+
|
|
83
|
+
async def load_item(self, url: str) -> SeriesInfo | MovieInfo:
|
|
84
|
+
resp = await self.httpx.get(url, follow_redirects=True)
|
|
85
|
+
sel = HTMLHelper(resp.text)
|
|
86
|
+
|
|
87
|
+
og_title = sel.select_attr("meta[property='og:title']", "content")
|
|
88
|
+
title = og_title.split("|")[0].strip() if og_title else sel.select_text("h1")
|
|
89
|
+
|
|
90
|
+
poster = sel.select_attr("meta[property='og:image']", "content")
|
|
91
|
+
description = sel.select_text("p#tv-series-desc")
|
|
92
|
+
|
|
93
|
+
year = sel.select_text("td div.truncate")
|
|
94
|
+
if year:
|
|
95
|
+
year = year.strip()
|
|
96
|
+
|
|
97
|
+
tags = []
|
|
98
|
+
rating = None
|
|
99
|
+
duration = None
|
|
100
|
+
year = None
|
|
101
|
+
actors = []
|
|
102
|
+
for item in sel.select("div.item"):
|
|
103
|
+
text = item.text(strip=True)
|
|
104
|
+
if "T\u00fcr\u00fc:" in text:
|
|
105
|
+
tags = [t.strip() for t in text.replace("T\u00fcr\u00fc:", "").split(",")]
|
|
106
|
+
elif "IMDb Puan\u0131" in text:
|
|
107
|
+
rating = text.replace("IMDb Puan\u0131", "").strip()
|
|
108
|
+
elif "Yap\u0131m Y\u0131l\u0131" in text:
|
|
109
|
+
year_match = sel.regex_first(r"(\d{4})", text)
|
|
110
|
+
if year_match:
|
|
111
|
+
year = year_match
|
|
112
|
+
elif "Takip\u00e7iler" in text:
|
|
113
|
+
continue
|
|
114
|
+
elif "S\u00fcre" in text:
|
|
115
|
+
dur_match = sel.regex_first(r"(\d+)", text)
|
|
116
|
+
if dur_match:
|
|
117
|
+
duration = dur_match
|
|
118
|
+
elif "Oyuncular:" in text:
|
|
119
|
+
actors = [a.text(strip=True) for a in sel.select("a", item)]
|
|
120
|
+
|
|
121
|
+
if not actors:
|
|
122
|
+
actors = [a.text(strip=True) for a in sel.select("div#common-cast-list div.item h5")]
|
|
123
|
+
|
|
124
|
+
trailer_match = sel.regex_first(r"embed\/(.*)\?rel", resp.text)
|
|
125
|
+
trailer = f"https://www.youtube.com/embed/{trailer_match}" if trailer_match else None
|
|
126
|
+
|
|
127
|
+
if "/film/" in url:
|
|
128
|
+
return MovieInfo(
|
|
129
|
+
title = title,
|
|
130
|
+
url = url,
|
|
131
|
+
poster = self.fix_url(poster) if poster else None,
|
|
132
|
+
description = description,
|
|
133
|
+
rating = rating,
|
|
134
|
+
tags = tags,
|
|
135
|
+
actors = actors,
|
|
136
|
+
year = year,
|
|
137
|
+
duration = int(duration) if duration and duration.isdigit() else None
|
|
138
|
+
)
|
|
139
|
+
else:
|
|
140
|
+
episodes = []
|
|
141
|
+
for bolum_item in sel.select("div.episodes-list div.ui td:has(h6)"):
|
|
142
|
+
link_el = sel.select_first("a", bolum_item)
|
|
143
|
+
if not link_el: continue
|
|
144
|
+
|
|
145
|
+
bolum_href = link_el.attrs.get("href")
|
|
146
|
+
bolum_name = sel.select_text("h6", bolum_item) or link_el.text(strip=True)
|
|
147
|
+
|
|
148
|
+
season = sel.regex_first(r"sezon-(\d+)", bolum_href)
|
|
149
|
+
episode = sel.regex_first(r"bolum-(\d+)", bolum_href)
|
|
150
|
+
|
|
151
|
+
ep_season = int(season) if season and season.isdigit() else None
|
|
152
|
+
ep_episode = int(episode) if episode and episode.isdigit() else None
|
|
153
|
+
|
|
154
|
+
episodes.append(Episode(
|
|
155
|
+
season = ep_season,
|
|
156
|
+
episode = ep_episode,
|
|
157
|
+
title = bolum_name,
|
|
158
|
+
url = self.fix_url(bolum_href)
|
|
159
|
+
))
|
|
160
|
+
|
|
161
|
+
if episodes and (episodes[0].episode or 0) > (episodes[-1].episode or 0):
|
|
162
|
+
episodes.reverse()
|
|
163
|
+
|
|
164
|
+
return SeriesInfo(
|
|
165
|
+
title = title,
|
|
166
|
+
url = url,
|
|
167
|
+
poster = self.fix_url(poster) if poster else None,
|
|
168
|
+
description = description,
|
|
169
|
+
rating = rating,
|
|
170
|
+
tags = tags,
|
|
171
|
+
actors = actors,
|
|
172
|
+
year = year,
|
|
173
|
+
episodes = episodes
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
async def load_links(self, url: str) -> list[ExtractResult]:
|
|
177
|
+
resp = await self.httpx.get(url, headers={"Referer": f"{self.main_url}/"})
|
|
178
|
+
sel = HTMLHelper(resp.text)
|
|
179
|
+
|
|
180
|
+
results = []
|
|
181
|
+
|
|
182
|
+
# Method 1: alternatives-for-this
|
|
183
|
+
for alt in sel.select("div.alternatives-for-this div.item:not(.active)"):
|
|
184
|
+
data_hash = alt.attrs.get("data-hash")
|
|
185
|
+
data_link = alt.attrs.get("data-link")
|
|
186
|
+
q_type = alt.attrs.get("data-querytype")
|
|
187
|
+
|
|
188
|
+
if not data_hash or not data_link: continue
|
|
189
|
+
|
|
190
|
+
try:
|
|
191
|
+
post_resp = await self.httpx.post(
|
|
192
|
+
f"{self.main_url}/ajax/service",
|
|
193
|
+
data = {
|
|
194
|
+
"link" : data_link,
|
|
195
|
+
"hash" : data_hash,
|
|
196
|
+
"querytype" : q_type,
|
|
197
|
+
"type" : "videoGet"
|
|
198
|
+
},
|
|
199
|
+
headers = {
|
|
200
|
+
"X-Requested-With" : "XMLHttpRequest",
|
|
201
|
+
"Referer" : f"{self.main_url}/"
|
|
202
|
+
},
|
|
203
|
+
cookies = {"udys": "1760709729873", "level": "1"}
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
service_data = post_resp.json()
|
|
207
|
+
api_iframe = service_data.get("api_iframe")
|
|
208
|
+
if api_iframe:
|
|
209
|
+
extract_res = await self._fetch_and_extract(api_iframe, prefix="Alt")
|
|
210
|
+
if extract_res:
|
|
211
|
+
results.extend(extract_res if isinstance(extract_res, list) else [extract_res])
|
|
212
|
+
except Exception:
|
|
213
|
+
continue
|
|
214
|
+
|
|
215
|
+
# Method 2: pointing[data-eid]
|
|
216
|
+
for id_el in sel.select("a.ui.pointing[data-eid]"):
|
|
217
|
+
dil = id_el.text(strip=True)
|
|
218
|
+
v_lang = "tr" if "Dublaj" in dil else "en"
|
|
219
|
+
data_eid = id_el.attrs.get("data-eid")
|
|
220
|
+
|
|
221
|
+
try:
|
|
222
|
+
post_resp = await self.httpx.post(
|
|
223
|
+
f"{self.main_url}/ajax/service",
|
|
224
|
+
data = {
|
|
225
|
+
"e_id" : data_eid,
|
|
226
|
+
"v_lang" : v_lang,
|
|
227
|
+
"type" : "get_whatwehave"
|
|
228
|
+
},
|
|
229
|
+
headers = {
|
|
230
|
+
"X-Requested-With" : "XMLHttpRequest",
|
|
231
|
+
"Referer" : f"{self.main_url}/"
|
|
232
|
+
},
|
|
233
|
+
cookies = {"udys": "1760709729873", "level": "1"}
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
service_data = post_resp.json()
|
|
237
|
+
api_iframe = service_data.get("api_iframe")
|
|
238
|
+
if api_iframe:
|
|
239
|
+
extract_res = await self._fetch_and_extract(api_iframe, prefix=dil)
|
|
240
|
+
if extract_res:
|
|
241
|
+
results.extend(extract_res if isinstance(extract_res, list) else [extract_res])
|
|
242
|
+
except Exception:
|
|
243
|
+
continue
|
|
244
|
+
|
|
245
|
+
return results
|
|
246
|
+
|
|
247
|
+
async def _fetch_and_extract(self, iframe_url, prefix=""):
|
|
248
|
+
# Initial fetch
|
|
249
|
+
resp = await self.httpx.get(
|
|
250
|
+
iframe_url,
|
|
251
|
+
headers = {"Referer": f"{self.main_url}/"},
|
|
252
|
+
cookies = {"udys": "1760709729873", "level": "1"}
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# Handle "Lütfen bekleyiniz" check from Kotlin
|
|
256
|
+
if "Lütfen bekleyiniz" in resp.text:
|
|
257
|
+
await asyncio.sleep(1)
|
|
258
|
+
timestamp = int(time.time())
|
|
259
|
+
# Retry with t=timestamp as in Kotlin
|
|
260
|
+
sep = "&" if "?" in iframe_url else "?"
|
|
261
|
+
resp = await self.httpx.get(
|
|
262
|
+
f"{iframe_url}{sep}t={timestamp}",
|
|
263
|
+
headers = {"Referer": f"{self.main_url}/"},
|
|
264
|
+
cookies = resp.cookies # Use cookies from first response
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
sel = HTMLHelper(resp.text)
|
|
268
|
+
final_iframe = sel.select_attr("iframe", "src")
|
|
269
|
+
|
|
270
|
+
if final_iframe:
|
|
271
|
+
final_url = self.fix_url(final_iframe)
|
|
272
|
+
return await self.extract(final_url, referer=f"{self.main_url}/", prefix=prefix)
|
|
273
|
+
|
|
274
|
+
return None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: KekikStream
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.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
|
|
@@ -64,6 +64,7 @@ KekikStream/Extractors/YildizKisaFilm.py
|
|
|
64
64
|
KekikStream/Plugins/BelgeselX.py
|
|
65
65
|
KekikStream/Plugins/DiziBox.py
|
|
66
66
|
KekikStream/Plugins/DiziPal.py
|
|
67
|
+
KekikStream/Plugins/DiziWatch.py
|
|
67
68
|
KekikStream/Plugins/DiziYou.py
|
|
68
69
|
KekikStream/Plugins/Dizilla.py
|
|
69
70
|
KekikStream/Plugins/FilmBip.py
|
|
@@ -84,4 +85,5 @@ KekikStream/Plugins/Sinefy.py
|
|
|
84
85
|
KekikStream/Plugins/SinemaCX.py
|
|
85
86
|
KekikStream/Plugins/Sinezy.py
|
|
86
87
|
KekikStream/Plugins/SuperFilmGeldi.py
|
|
87
|
-
KekikStream/Plugins/UgurFilm.py
|
|
88
|
+
KekikStream/Plugins/UgurFilm.py
|
|
89
|
+
KekikStream/Plugins/YabanciDizi.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: KekikStream
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.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
|
|
@@ -6,7 +6,7 @@ from io import open
|
|
|
6
6
|
setup(
|
|
7
7
|
# ? Genel Bilgiler
|
|
8
8
|
name = "KekikStream",
|
|
9
|
-
version = "2.3.
|
|
9
|
+
version = "2.3.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|