kickzero 1.3.1__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.
- kickzero/__init__.py +1038 -0
- kickzero-1.3.1.dist-info/METADATA +53 -0
- kickzero-1.3.1.dist-info/RECORD +5 -0
- kickzero-1.3.1.dist-info/WHEEL +5 -0
- kickzero-1.3.1.dist-info/top_level.txt +1 -0
kickzero/__init__.py
ADDED
|
@@ -0,0 +1,1038 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import aiohttp
|
|
3
|
+
import websockets
|
|
4
|
+
import json
|
|
5
|
+
import inspect
|
|
6
|
+
import colorama
|
|
7
|
+
import re
|
|
8
|
+
import sys # sys mutlaka kalmalı
|
|
9
|
+
from typing import Optional, Dict, Callable, Any
|
|
10
|
+
from colorama import Fore, Style
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
if "kickzero" not in sys.modules:
|
|
14
|
+
sys.modules["kickzero"] = sys.modules[__name__]
|
|
15
|
+
|
|
16
|
+
__all__ = ['kickbot', 'message_context', 'decorators']
|
|
17
|
+
|
|
18
|
+
class zerror:
|
|
19
|
+
"""
|
|
20
|
+
### 🇹🇷 [TR] Hata ve Log Yöneticisi (Error Logger)
|
|
21
|
+
Projedeki tüm konsol çıktılarını, hata mesajlarını ve uyarıları merkezi bir
|
|
22
|
+
noktadan yönetir. Renkli çıktılar, emojiler ve çoklu dil (TR/EN) desteği sunar.
|
|
23
|
+
Sınıf başlatılmadan (Singleton mantığıyla) doğrudan sınıf üzerinden kullanılır.
|
|
24
|
+
|
|
25
|
+
### 🇺🇸 [EN] Global Error and Log Manager
|
|
26
|
+
Centralizes all console outputs, error messages, and warnings across the project.
|
|
27
|
+
Features colored outputs, emojis, and multi-language (TR/EN) support.
|
|
28
|
+
Operates directly on the class level (Singleton) without instantiation.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
### 🛠️ Değişkenler / Attributes (Variables):
|
|
32
|
+
|
|
33
|
+
#### 🖨️ L1: Çıktı Kontrolleri / Output Toggles
|
|
34
|
+
- print_errors (bool): Hata mesajları gösterilsin mi? (Show error logs?)
|
|
35
|
+
- print_warns (bool): Uyarı mesajları gösterilsin mi? (Show warning logs?)
|
|
36
|
+
- print_notes (bool): Not mesajları gösterilsin mi? (Show note logs?)
|
|
37
|
+
- print_success (bool): Başarı mesajları gösterilsin mi? (Show success logs?)
|
|
38
|
+
- print_messages (bool): Standart mesajlar gösterilsin mi? (Show standard messages?)
|
|
39
|
+
|
|
40
|
+
#### 🎭 L2: Görsel Ayarlar / Visual Settings
|
|
41
|
+
- use_colors (bool): Çıktılar renkli mi olsun? (Enable colored terminal output?)
|
|
42
|
+
- use_emojis (bool): Emojiler genel olarak açık mı olsun? (Global emoji toggle?)
|
|
43
|
+
- preety_print (bool): Gelişmiş okunabilirlik sağlansın mı? (Use pretty formatting?)
|
|
44
|
+
|
|
45
|
+
#### 😊 L3: Detaylı Emoji Kontrolleri / Granular Emoji Toggles
|
|
46
|
+
- print_error_emoji (bool): Hatalarda [❌] gösterilsin mi? (Show emoji on errors?)
|
|
47
|
+
- print_warnn_emoji (bool): Uyarılarda [🔔] gösterilsin mi? (Show emoji on warnings?)
|
|
48
|
+
- print_note_emoji (bool): Notlarda [📝] gösterilsin mi? (Show emoji on notes?)
|
|
49
|
+
- print_succes_emoji (bool): Başarılarda [✅] gösterilsin mi? (Show emoji on success?)
|
|
50
|
+
- print_message_emoji (bool): Mesajlarda [💬] gösterilsin mi? (Show emoji on messages?)
|
|
51
|
+
|
|
52
|
+
#### 🌍 L4: Sistem Ayarları / System Settings
|
|
53
|
+
- lang (str): Çıktı dili, "tr" veya "en". (Global output language)
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
### ⚡ Metodlar / Methods:
|
|
57
|
+
- log(level, msg_tr, msg_en, msg): Belirtilen seviyeye (error, warn, note, vb.) ve
|
|
58
|
+
sistemin o anki diline göre formatlanmış renkli log çıktısı verir.
|
|
59
|
+
(Prints a color-formatted log based on the specified level and language.)
|
|
60
|
+
"""
|
|
61
|
+
print_errors: bool = True
|
|
62
|
+
print_warns: bool = True
|
|
63
|
+
print_notes: bool = True
|
|
64
|
+
print_success: bool = True
|
|
65
|
+
print_error_emoji: bool = True
|
|
66
|
+
print_warnn_emoji: bool = True
|
|
67
|
+
print_note_emoji: bool = True
|
|
68
|
+
print_succes_emoji: bool = True
|
|
69
|
+
print_messages: bool = True
|
|
70
|
+
print_message_emoji: bool = True
|
|
71
|
+
pretty_print: bool = True
|
|
72
|
+
use_emojis: bool = True
|
|
73
|
+
use_colors: bool = True
|
|
74
|
+
lang: str = "en"
|
|
75
|
+
@classmethod
|
|
76
|
+
def log(cls: 'zerror', level: str, msg_tr: str = "", msg_en: str = "",msg: str = ""):
|
|
77
|
+
emoji, color = "", ""
|
|
78
|
+
lvl = level.lower()
|
|
79
|
+
if lvl in ["err", "error"] and not cls.print_errors: return
|
|
80
|
+
elif lvl in ["warn", "warnn", "warning"] and not cls.print_warns: return
|
|
81
|
+
elif lvl in ["note", "not"] and not cls.print_notes: return
|
|
82
|
+
elif lvl in ["succ", "success"] and not cls.print_success: return
|
|
83
|
+
elif lvl in ["msg", "mesaj", "message"] and not cls.print_messages: return
|
|
84
|
+
if cls.lang.lower() in ["tr", "en"]:
|
|
85
|
+
message = msg if msg else msg_tr if cls.lang.lower() == "tr" else msg_en
|
|
86
|
+
else:
|
|
87
|
+
print(f"{Fore.RED}[❌] {Style.BRIGHT}[Hata/Error] {Fore.WHITE}Dil tr veya en seçilmeli{Style.RESET_ALL}")
|
|
88
|
+
return
|
|
89
|
+
if lvl in ["err", "error"]:
|
|
90
|
+
level_text = "hata" if cls.lang == "tr" else "error"
|
|
91
|
+
emoji = "[❌] " if cls.use_emojis and cls.print_error_emoji else ""
|
|
92
|
+
color = Fore.RED if cls.use_colors else ""
|
|
93
|
+
elif lvl in ["warn", "warnn", "warning"]:
|
|
94
|
+
level_text = "uyarı" if cls.lang == "tr" else "warning"
|
|
95
|
+
emoji = "[🔔] " if cls.use_emojis and cls.print_warnn_emoji else ""
|
|
96
|
+
color = Fore.YELLOW if cls.use_colors else ""
|
|
97
|
+
elif lvl in ["note", "not"]:
|
|
98
|
+
level_text = "not" if cls.lang == "tr" else "note"
|
|
99
|
+
emoji = "[📝] " if cls.use_emojis and cls.print_note_emoji else ""
|
|
100
|
+
color = Fore.CYAN if cls.use_colors else ""
|
|
101
|
+
elif lvl in ["succ", "success"]:
|
|
102
|
+
level_text = "başarı" if cls.lang == "tr" else "success"
|
|
103
|
+
emoji = "[✅] " if cls.use_emojis and cls.print_succes_emoji else ""
|
|
104
|
+
color = Fore.GREEN if cls.use_colors else ""
|
|
105
|
+
elif lvl in ["msg", "mesaj", "message"]:
|
|
106
|
+
level_text = "mesaj" if cls.lang == "tr" else "message"
|
|
107
|
+
emoji = "[💬] " if cls.use_emojis and cls.print_message_emoji else ""
|
|
108
|
+
color = Fore.WHITE if cls.use_colors else ""
|
|
109
|
+
else:
|
|
110
|
+
level_text = lvl
|
|
111
|
+
color = Fore.WHITE
|
|
112
|
+
print(f"{color}{emoji}{Style.BRIGHT}[{level_text.upper()}] {Fore.WHITE}{message}{Style.RESET_ALL}")
|
|
113
|
+
|
|
114
|
+
class tasks:
|
|
115
|
+
"""
|
|
116
|
+
### 🇹🇷 [TR] Görev ve Rutin Yöneticisi
|
|
117
|
+
Botun arka planda çalışması gereken periyodik görevlerini (timers), başlangıç
|
|
118
|
+
fonksiyonlarını ve sistem kontrollerini koordine eder. Asenkron (asyncio)
|
|
119
|
+
yapısı sayesinde ana akışı bozmadan paralel iş yükleri oluşturur.
|
|
120
|
+
|
|
121
|
+
### 🇺🇸 [EN] Task and Routine Manager
|
|
122
|
+
Coordinates the bot's background periodic tasks (timers), startup functions,
|
|
123
|
+
and system checks. Uses asynchronous (asyncio) operations to create parallel
|
|
124
|
+
workloads without interrupting the main execution flow.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
### ⚡ Metodlar / Methods:
|
|
128
|
+
|
|
129
|
+
#### 🚀 L1: Başlatıcılar / Startup Executers
|
|
130
|
+
- run_ready_funcs(bot): Bot bağlandığında `@on_ready` ile işaretlenmiş tüm
|
|
131
|
+
fonksiyonları birer 'task' olarak başlatır. (Starts all @on_ready functions
|
|
132
|
+
as individual tasks upon connection.)
|
|
133
|
+
|
|
134
|
+
#### ⏱️ L2: Zamanlayıcılar / Timer Coordination
|
|
135
|
+
- run_timer_tasks(bot): `@timer_task` ile tanımlanan periyodik döngüleri kurar.
|
|
136
|
+
Fonksiyonun parametre alıp almadığını kontrol ederek (inspect), gerekirse
|
|
137
|
+
sahte bir bağlam (fake context) ile besler. (Sets up periodic loops defined
|
|
138
|
+
by @timer_task. Checks function signatures to feed them with a fake context
|
|
139
|
+
if required.)
|
|
140
|
+
|
|
141
|
+
#### 🔍 L3: Sistem Denetimi / System Check
|
|
142
|
+
- check(bot): Botun temel bilgilerini ve bağlı olduğu kanalları doğrulayarak
|
|
143
|
+
konsola durum raporu geçer. (Verifies basic bot info and connected channels,
|
|
144
|
+
then logs a status report to the console.)
|
|
145
|
+
"""
|
|
146
|
+
@staticmethod
|
|
147
|
+
async def run_ready_funcs(bot:'kickbot'):
|
|
148
|
+
for ready_func in bot._on_ready_tasks: asyncio.create_task(ready_func())
|
|
149
|
+
@staticmethod
|
|
150
|
+
async def run_timer_tasks(bot:'kickbot'):
|
|
151
|
+
async def _internal_worker(task_info):
|
|
152
|
+
while True:
|
|
153
|
+
await asyncio.sleep(task_info["interval"])
|
|
154
|
+
try:
|
|
155
|
+
sig = inspect.signature(task_info["func"])
|
|
156
|
+
if len(sig.parameters) > 0:
|
|
157
|
+
fake_data = {"content":"Timer","sender":{"username":"System"}}
|
|
158
|
+
await task_info["func"](message_context(fake_data,bot))
|
|
159
|
+
else:
|
|
160
|
+
await task_info["func"]()
|
|
161
|
+
except Exception as e:
|
|
162
|
+
zerror.log(level="warn",
|
|
163
|
+
msg_tr=f"Timer Hatası ({task_info['func'].__name__}): {e}",
|
|
164
|
+
msg_en=f"Timer Error ({task_info['func'].__name__}): {e}")
|
|
165
|
+
for task in bot._timer_tasks:
|
|
166
|
+
asyncio.create_task(_internal_worker(task))
|
|
167
|
+
zerror.log(level="succ",
|
|
168
|
+
msg_tr="Tüm zamanlayıcılar arka planda başlatıldı.",
|
|
169
|
+
msg_en="All timers started in the background.")
|
|
170
|
+
@staticmethod
|
|
171
|
+
async def check(bot:'kickbot'):
|
|
172
|
+
if len(bot._on_ready_tasks) == 0:
|
|
173
|
+
zerror.log(
|
|
174
|
+
level="succ",
|
|
175
|
+
msg_tr=f"Bot {bot.user_name} adıyla giriş yaptı ve filodaki {len(bot.channels)} kanalı dinliyor!",
|
|
176
|
+
msg_en=f"Bot logged in as {bot.user_name} and listening to {len(bot.channels)} channels in the fleet!")
|
|
177
|
+
|
|
178
|
+
class engine:
|
|
179
|
+
"""
|
|
180
|
+
### 🇹🇷 [TR] WebSocket ve Bağlantı Motoru
|
|
181
|
+
Kick.com'un kullandığı Pusher (WebSocket) altyapısı ile olan tüm iletişimi
|
|
182
|
+
yönetir. Kanallara abone olma (subscribe), ping-pong (keep-alive) trafiği
|
|
183
|
+
ve gelen ham verilerin ilgili işlemcilere (processors) dağıtılmasından sorumludur.
|
|
184
|
+
|
|
185
|
+
### 🇺🇸 [EN] WebSocket and Connection Engine
|
|
186
|
+
Manages all communication with the Pusher (WebSocket) infrastructure used
|
|
187
|
+
by Kick.com. Responsible for channel subscriptions, keep-alive (ping-pong)
|
|
188
|
+
traffic, and routing raw incoming data to the appropriate processors.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
### ⚡ Metodlar / Methods:
|
|
192
|
+
|
|
193
|
+
#### 🔌 L1: Bağlantı Kurucu / Connection Establisher
|
|
194
|
+
- connect(bot): Belirlenen 'cluster' ve 'app_key' üzerinden Kick WebSocket
|
|
195
|
+
sunucusuna fiziksel bağlantıyı başlatır. (Establishes the physical connection
|
|
196
|
+
to the Kick WebSocket server using the defined cluster and app_key.)
|
|
197
|
+
|
|
198
|
+
#### 📡 L2: Radar Abonelikleri / Subscription Services
|
|
199
|
+
- subscribe_to_chatroom(ch, ws): Sohbet mesajlarını ve mod aksiyonlarını dinlemek
|
|
200
|
+
için kanala abone olur. (Subscribes to the channel to listen for chat messages
|
|
201
|
+
and mod actions.)
|
|
202
|
+
- subscribe_to_channel_points(ch, ws): Kanal puanı (Reward) kullanımlarını yakalamak
|
|
203
|
+
için abone olur. (Subscribes to capture channel point/reward redemptions.)
|
|
204
|
+
- subscribe_to_channel_events(ch, ws): [Beta] Takipçi ve diğer kanal olaylarını
|
|
205
|
+
yakalamak için abone olur. (Subscribes to capture followers and other channel events.)
|
|
206
|
+
- subscribe_all(bot, ws): Filodaki tüm benzersiz kanallar için tüm abonelik
|
|
207
|
+
türlerini topluca başlatır. (Bulk starts all subscription types for every
|
|
208
|
+
unique channel in the fleet.)
|
|
209
|
+
|
|
210
|
+
#### 💓 L3: Yaşam Sinyali / Keep Alive
|
|
211
|
+
- keep_alive(bot, ws): Sunucudan gelen 'ping' sinyallerine 'pong' ile yanıt
|
|
212
|
+
vererek bağlantının kopmasını engeller. (Prevents connection loss by responding
|
|
213
|
+
with 'pong' to incoming 'ping' signals from the server.)
|
|
214
|
+
|
|
215
|
+
#### 🚥 L4: Olay Dağıtıcı / Event Dispatcher
|
|
216
|
+
- process_all_events(bot, ws): Sürekli dinleme yaparak gelen verinin türünü
|
|
217
|
+
ayrıştırır (Chat, Reward, Ping) ve ilgili işlemciye yönlendirir. (Constantly
|
|
218
|
+
listens to parse the event type and routes it to the specific processor.)
|
|
219
|
+
"""
|
|
220
|
+
@staticmethod
|
|
221
|
+
def connect(bot):
|
|
222
|
+
websocket = websockets.connect(uri=f"wss://ws-{bot.cluster}.pusher.com/app/{bot.app_key}?protocol=7&client=js&version=7.6.0")
|
|
223
|
+
return websocket
|
|
224
|
+
@staticmethod
|
|
225
|
+
async def subscribe_to_chatroom(ch, websocket):
|
|
226
|
+
await websocket.send(json.dumps({ "event": "pusher:subscribe","data": {"channel": f"chatrooms.{ch.chat_id}.v2"}})) # Mod actions ve chat
|
|
227
|
+
@staticmethod
|
|
228
|
+
async def subscribe_to_channel_points(ch, websocket):
|
|
229
|
+
await websocket.send(json.dumps({ "event": "pusher:subscribe","data": {"channel": f"chatroom_{ch.chat_id}"}}))
|
|
230
|
+
""" st Untested Beta"""
|
|
231
|
+
@staticmethod
|
|
232
|
+
async def subscribe_to_channel_events(ch, websocket): # Kicks puanları ve takipler
|
|
233
|
+
await websocket.send(json.dumps({"event": "pusher:subscribe","data": {"channel": f"channel_{ch.channel_id}"}}))
|
|
234
|
+
""" en Untested Beta """
|
|
235
|
+
|
|
236
|
+
@staticmethod
|
|
237
|
+
async def subscribe_all(bot, websocket):
|
|
238
|
+
# ⚓ DÜZELTME: Sadece isimle kaydedilen gerçek objeleri alıyoruz
|
|
239
|
+
unique_channels = []
|
|
240
|
+
for key, value in bot.channels.items():
|
|
241
|
+
if not key.isdigit() and value not in unique_channels:
|
|
242
|
+
unique_channels.append(value)
|
|
243
|
+
|
|
244
|
+
for ch in unique_channels:
|
|
245
|
+
await engine.subscribe_to_chatroom(ch, websocket)
|
|
246
|
+
await engine.subscribe_to_channel_points(ch, websocket)
|
|
247
|
+
await engine.subscribe_to_channel_events(ch, websocket)
|
|
248
|
+
|
|
249
|
+
zerror.log(level="note", msg_tr=f"[{ch.name}] Radar abonelikleri tamamlandı!", msg_en=f"[{ch.name}] Radar subscriptions completed!")
|
|
250
|
+
@staticmethod
|
|
251
|
+
async def keep_alive(bot,websocket):
|
|
252
|
+
await websocket.send(json.dumps({"event": "pusher:pong"}))
|
|
253
|
+
@staticmethod
|
|
254
|
+
async def process_all_events(bot,websocket):
|
|
255
|
+
raw_data = await websocket.recv()
|
|
256
|
+
data = json.loads(raw_data)
|
|
257
|
+
if data.get("event") == "App\\Events\\ChatMessageEvent":
|
|
258
|
+
await processor.process_chat(bot,raw_data)
|
|
259
|
+
elif data.get("event") == "RewardRedeemedEvent":
|
|
260
|
+
await processor.process_channel_points(bot,raw_data)
|
|
261
|
+
elif data.get("event") == "pusher:ping":
|
|
262
|
+
await engine.keep_alive(bot,websocket)
|
|
263
|
+
|
|
264
|
+
class processor:
|
|
265
|
+
"""
|
|
266
|
+
### 🇹🇷 [TR] Veri İşleme ve Olay Dağıtıcı (Event Dispatcher)
|
|
267
|
+
Kick sunucularından gelen ham WebSocket verilerini analiz eder, uygun bağlam
|
|
268
|
+
(context) nesnelerini oluşturur ve tetikleyicileri (commands, messages, rewards)
|
|
269
|
+
çalıştırır. Botun mantıksal karar merkezidir.
|
|
270
|
+
|
|
271
|
+
### 🇺🇸 [EN] Data Processor and Event Dispatcher
|
|
272
|
+
Analyzes raw WebSocket data from Kick servers, creates appropriate context
|
|
273
|
+
objects, and executes triggers (commands, messages, rewards). It serves
|
|
274
|
+
as the logical decision center of the bot.
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
### ⚡ Metodlar / Methods:
|
|
278
|
+
|
|
279
|
+
#### ⚔️ L1: Dinamik Fonksiyon Çalıştırıcı / Dynamic Executor
|
|
280
|
+
- execute(fx, ctx, args): Hedef fonksiyonun parametre yapısını (inspect)
|
|
281
|
+
analiz eder ve uygun argümanlarla güvenli bir şekilde çalıştırır.
|
|
282
|
+
(Analyzes the target function's signature and executes it safely
|
|
283
|
+
with the appropriate arguments.)
|
|
284
|
+
|
|
285
|
+
#### 💬 L2: Sohbet İşleyici / Chat Processor
|
|
286
|
+
- process_chat(bot, raw_data): Gelen sohbet verisini çözümler; canlı sohbeti
|
|
287
|
+
ekrana basar, genel mesaj izleyicilerini, özel kelime tetikleyicilerini
|
|
288
|
+
ve komutları paralel olarak tetikler. (Parses incoming chat data; logs
|
|
289
|
+
live chat, triggers global watchers, word triggers, and commands in parallel.)
|
|
290
|
+
|
|
291
|
+
#### 💎 L3: Kanal Ödülü İşleyici / Reward Processor
|
|
292
|
+
- process_channel_points(bot, raw_data): Kanal puanı ile alınan ödülleri
|
|
293
|
+
yakalar; ödül ismine göre kayıtlı fonksiyonları bulur ve ödülü kullanan
|
|
294
|
+
kişinin bilgilerini ilgili göreve iletir. (Captures reward redemptions;
|
|
295
|
+
matches reward titles with registered functions and forwards user info to the task.)
|
|
296
|
+
"""
|
|
297
|
+
@staticmethod
|
|
298
|
+
async def execute(fx,ctx,args):
|
|
299
|
+
try:
|
|
300
|
+
sig = inspect.signature(fx)
|
|
301
|
+
params_count = len(sig.parameters)
|
|
302
|
+
if params_count == 2: await fx(ctx,args)
|
|
303
|
+
elif params_count == 1: await fx(ctx)
|
|
304
|
+
else: await fx()
|
|
305
|
+
except Exception as e:
|
|
306
|
+
zerror.log(level="error", msg_tr=f"{fx.__name__} çalışırken hata: {e}", msg_en=f"Error running {fx.__name__}: {e}")
|
|
307
|
+
@staticmethod
|
|
308
|
+
async def process_chat(bot:'kickbot',raw_data):
|
|
309
|
+
data = json.loads(raw_data)
|
|
310
|
+
inner_data = json.loads(data["data"])
|
|
311
|
+
ctx = message_context(inner_data,bot)
|
|
312
|
+
async def display_messages():
|
|
313
|
+
if bot.display_live_chat and (not ctx.is_bot or bot.display_bot_messages):
|
|
314
|
+
perms = " | ".join(ctx.badge_texts) if ctx.badge_texts else (r"İzleyici" if zerror.lang == "tr" else r"Viewer")
|
|
315
|
+
msg_log = f"{Fore.YELLOW}{ctx.author}{Fore.WHITE}: {ctx.content} {Fore.BLACK}({perms})"
|
|
316
|
+
zerror.log(level="message", msg=msg_log)
|
|
317
|
+
async def process_message_funcs():
|
|
318
|
+
if not (bot.filter_bot_messages and ctx.is_bot):
|
|
319
|
+
for watcher in bot._on_message_tasks:
|
|
320
|
+
asyncio.create_task(processor.execute(watcher,ctx,[]))
|
|
321
|
+
if ctx.is_bot: return
|
|
322
|
+
for trigger,configs in bot._message_handlers.items():
|
|
323
|
+
for config in configs:
|
|
324
|
+
if ctx.is_bot and not config.get("execute_bot",False): continue
|
|
325
|
+
is_lower = config.get("lower",True)
|
|
326
|
+
msg_c = ctx.content.lower() if is_lower else ctx.content
|
|
327
|
+
trig_c = trigger.lower() if is_lower else trigger
|
|
328
|
+
is_trig = (msg_c == trig_c) if config.get("exact",True) else msg_c.startswith(trig_c)
|
|
329
|
+
if is_trig:
|
|
330
|
+
args = ctx.content.split()[len(trig_c.split()):]
|
|
331
|
+
asyncio.create_task(processor.execute(config["func"],ctx,args))
|
|
332
|
+
async def process_command_funcs():
|
|
333
|
+
if ctx.content.startswith(bot.prefix):
|
|
334
|
+
parts = ctx.content[len(bot.prefix):].split()
|
|
335
|
+
if parts:
|
|
336
|
+
cmd_raw = parts[0]
|
|
337
|
+
cmd_lower = parts[0].lower()
|
|
338
|
+
cmd_configs = bot._commands.get(cmd_raw, []) + (bot._commands.get(cmd_lower,[]) if cmd_lower != cmd_raw else [])
|
|
339
|
+
for cmd_info in cmd_configs:
|
|
340
|
+
if ctx.is_bot and not cmd_info.get("execute_bot",False): continue
|
|
341
|
+
asyncio.create_task(processor.execute(cmd_info["func"],ctx,parts[1:]))
|
|
342
|
+
asyncio.create_task(display_messages())
|
|
343
|
+
asyncio.create_task(process_message_funcs())
|
|
344
|
+
asyncio.create_task(process_command_funcs())
|
|
345
|
+
@staticmethod
|
|
346
|
+
async def process_channel_points(bot:'kickbot',raw_data):
|
|
347
|
+
data = json.loads(raw_data)
|
|
348
|
+
rctx = points_context(data,bot)
|
|
349
|
+
### Log
|
|
350
|
+
log_msg = f"{Fore.MAGENTA}{rctx.username}{Fore.WHITE}, {Fore.GREEN}'{rctx.title}'{Fore.WHITE} ödülünü kullandı! {Fore.BLACK}(Kanal: {rctx.channel})"
|
|
351
|
+
if rctx.input:
|
|
352
|
+
log_msg += f" {Fore.CYAN}(Mesaj: {rctx.input})"
|
|
353
|
+
## Dedektör Taraması
|
|
354
|
+
title_lower = rctx.title.lower()
|
|
355
|
+
reward_configs = bot._reward_handlers.get(title_lower, [])
|
|
356
|
+
for config in reward_configs:
|
|
357
|
+
asyncio.create_task(processor.execute(config["func"], rctx, []))
|
|
358
|
+
zerror.log(level="succ", msg=log_msg)
|
|
359
|
+
|
|
360
|
+
### contexts
|
|
361
|
+
class message_context:
|
|
362
|
+
"""
|
|
363
|
+
### 🇹🇷 [TR] Bağlam Merkezi (context)
|
|
364
|
+
Kick.com API'den gelen verileri, botun o anki çalışma durumuyla birleştirir.
|
|
365
|
+
Bu sınıf; mesajın içeriğine, gönderen kişinin yetkilerine ve botun fonksiyonlarına
|
|
366
|
+
tek bir noktadan (`ctx`) erişim sağlar.
|
|
367
|
+
|
|
368
|
+
### 🇺🇸 [EN] Command context
|
|
369
|
+
Unifies data from the Kick.com API with the bot's current operational state.
|
|
370
|
+
This class provides a single point of access (`ctx`) to message content,
|
|
371
|
+
sender permissions, and bot methods.
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
### 🛠️ Değişkenler / Attributes (Variables):
|
|
375
|
+
|
|
376
|
+
#### 📦 L1: Akış Verileri / Stream Data
|
|
377
|
+
- id (str): Mesajın benzersiz kimliği. (Unique message ID)
|
|
378
|
+
- chatroom_id (int): Mesajın düştüğü odanın ID'si. (Target chatroom ID)
|
|
379
|
+
- content (str): Mesajın ham metni. (Raw message content)
|
|
380
|
+
- created_at (str): Gönderilme zamanı. (Creation timestamp)
|
|
381
|
+
|
|
382
|
+
#### 👤 L2: Aktör / The Actor (Sender)
|
|
383
|
+
- author (str): Kullanıcı adı. (Sender's username)
|
|
384
|
+
- author_id (int): Kullanıcının kalıcı sayısal ID'si. (User's permanent ID)
|
|
385
|
+
- slug (str): URL uyumlu kullanıcı adı. (Sender's URL slug)
|
|
386
|
+
|
|
387
|
+
#### 🎨 L3: Görsel Kimlik / Visual Identity
|
|
388
|
+
- color (str): Kullanıcı renk kodu. (User hex color)
|
|
389
|
+
- badges (list): Sahip olunan ham rozetler. (Raw badge list)
|
|
390
|
+
- badge_texts (list): Rozetlerin isimleri. (Badge display names)
|
|
391
|
+
|
|
392
|
+
#### 🛡️ L4: Yetki Kalkanları / Permission Shields
|
|
393
|
+
- is_broadcaster (bool): Kanal sahibi mi? (Is broadcaster?)
|
|
394
|
+
- is_mod (bool): Moderatör mü? (Is moderator?)
|
|
395
|
+
- is_sub (bool): Abone mi? (Is subscriber?)
|
|
396
|
+
- is_vip (bool): VIP mi? (Is VIP?)
|
|
397
|
+
- is_staff (bool): Kick görevlisi mi? (Is Kick staff?)
|
|
398
|
+
- is_verified (bool): Onaylı hesap mı? (Is verified?)
|
|
399
|
+
|
|
400
|
+
#### 🤖 L5: Sistem Kontrolü / System Check
|
|
401
|
+
- bot (kickbot): Ana bot sınıfına olan bağlantı. (Reference to main kickbot instance)
|
|
402
|
+
- is_bot (bool): Bu mesajı botun kendisi mi attı? (Did the bot send this message?)
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
### ⚡ Metodlar / Methods:
|
|
406
|
+
- reply(content): Kullanıcıyı etiketleyerek cevap verir. (Reply with mention)
|
|
407
|
+
- send(content): Kanala düz metin gönderir. (Send plain text)
|
|
408
|
+
"""
|
|
409
|
+
bot: 'kickbot'
|
|
410
|
+
id: str
|
|
411
|
+
chatroom_id: int
|
|
412
|
+
content: str
|
|
413
|
+
type: str
|
|
414
|
+
created_at: str
|
|
415
|
+
sender_id: int
|
|
416
|
+
author: str
|
|
417
|
+
slug: str
|
|
418
|
+
color: str
|
|
419
|
+
badges: list
|
|
420
|
+
badge_texts: list
|
|
421
|
+
is_broadcaster: bool
|
|
422
|
+
is_mod: bool
|
|
423
|
+
is_sub: bool
|
|
424
|
+
is_vip: bool
|
|
425
|
+
is_staff: bool
|
|
426
|
+
is_verified: bool
|
|
427
|
+
is_og: bool
|
|
428
|
+
metadata: dict
|
|
429
|
+
message_ref: str
|
|
430
|
+
is_bot: bool
|
|
431
|
+
|
|
432
|
+
#Garanti seviyeler, ekle
|
|
433
|
+
def __init__(self,data:dict,bot:'kickbot'):
|
|
434
|
+
self.bot = bot
|
|
435
|
+
# --- L1: Ana Veriler ---
|
|
436
|
+
self.id = data.get("id")
|
|
437
|
+
self.chatroom_id = data.get("chatroom_id")
|
|
438
|
+
self.content = data.get("content")
|
|
439
|
+
self.type = data.get("type")
|
|
440
|
+
self.created_at = data.get("created_at")
|
|
441
|
+
# --- L2: Gönderici (Sender) --
|
|
442
|
+
Sender = data.get("sender",{})
|
|
443
|
+
self.sender_id = Sender.get("id")
|
|
444
|
+
self.author = Sender.get("username")
|
|
445
|
+
self.slug = Sender.get("slug")
|
|
446
|
+
# --- L3: Kimlik ve Rozetler (Identity) ---
|
|
447
|
+
Identity = Sender.get("identity",{})
|
|
448
|
+
self.color = Identity.get("color")
|
|
449
|
+
self.badges = Identity.get("badges",[])
|
|
450
|
+
# --- L4: Yetki ve Rozet İşleme ---
|
|
451
|
+
BadgeTypes = [badge.get("type") for badge in self.badges]
|
|
452
|
+
self.is_broadcaster = "broadcaster" in BadgeTypes
|
|
453
|
+
self.is_mod = "moderator" in BadgeTypes
|
|
454
|
+
self.is_sub = "subscriber" in BadgeTypes
|
|
455
|
+
self.is_vip = "vip" in BadgeTypes
|
|
456
|
+
self.is_staff = "staff" in BadgeTypes
|
|
457
|
+
self.is_verified = "verified" in BadgeTypes
|
|
458
|
+
self.is_og = "og" in BadgeTypes
|
|
459
|
+
#L4.1 İleride Eklenicek
|
|
460
|
+
self.badge_texts = [badge.get("text") for badge in self.badges]
|
|
461
|
+
# --- L5: Meta Veri (Metadata) ---
|
|
462
|
+
self.metadata = data.get("metadata", {})
|
|
463
|
+
self.message_ref = self.metadata.get("message_ref")
|
|
464
|
+
# |
|
|
465
|
+
AuthorName = str(self.author).lower()
|
|
466
|
+
BotName = str(self.bot.user_name).lower()
|
|
467
|
+
self.is_bot = (AuthorName == BotName)
|
|
468
|
+
# ---Ş6 Channel
|
|
469
|
+
self.channel = self.bot._get_channel(self.chatroom_id)
|
|
470
|
+
async def reply(self, content: str):
|
|
471
|
+
if hasattr(self, 'channel') and self.channel and type(self.channel) != str:
|
|
472
|
+
return await self.channel.send(f"@{self.author} {content}")
|
|
473
|
+
zerror.log(level="error", msg_tr="Kanal bulunamadı! Timer görevlerinden mesaj atıyorsanız ctx.bot.find_channel('isim').send() kullanmalısınız.")
|
|
474
|
+
|
|
475
|
+
async def send(self, content: str):
|
|
476
|
+
if hasattr(self, 'channel') and self.channel and type(self.channel) != str:
|
|
477
|
+
return await self.channel.send(content)
|
|
478
|
+
|
|
479
|
+
# Kanalı belli değilse ana gemiye at
|
|
480
|
+
return await self.bot.send_message(content)
|
|
481
|
+
class points_context:
|
|
482
|
+
"""
|
|
483
|
+
### 🇹🇷 [TR] Kanal Puanı Bağlamı (Reward Context)
|
|
484
|
+
Kick.com üzerindeki sadakat puanı (Stream Rewards) kullanımlarını temsil eder.
|
|
485
|
+
Ödülü kimin, hangi kanalda ve hangi girdiyle (input) kullandığını takip eder.
|
|
486
|
+
|
|
487
|
+
### 🇺🇸 [EN] Reward Redemption Context
|
|
488
|
+
Represents stream reward redemptions on Kick.com. Tracks who used the
|
|
489
|
+
reward, in which channel, and with what user input.
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
### 🛠️ Değişkenler / Attributes (Variables):
|
|
493
|
+
|
|
494
|
+
#### 💎 L1: Ödül Detayları / Reward Details
|
|
495
|
+
- title (str): Kullanılan ödülün tam adı. (Title of the redeemed reward)
|
|
496
|
+
- input (str): Kullanıcının ödülle birlikte gönderdiği mesaj. (User's input message)
|
|
497
|
+
- color (str): Ödülün paneldeki arka plan renk kodu. (Reward's hex background color)
|
|
498
|
+
|
|
499
|
+
#### 👤 L2: Aktör / The Actor (User)
|
|
500
|
+
- username (str): Ödülü kullanan kişinin adı. (Username of the redeemer)
|
|
501
|
+
- user_id (int): Kullanıcının sayısal ID'si. (Permanent ID of the user)
|
|
502
|
+
|
|
503
|
+
#### 📡 L3: Konum / Location
|
|
504
|
+
- channel (channel_context): Ödülün tetiklendiği kanal objesi. (Channel object where the reward was used)
|
|
505
|
+
- channel_id (int): Kanalın sayısal ID'si. (Permanent ID of the channel)
|
|
506
|
+
|
|
507
|
+
#### 🤖 L4: Sistem / System
|
|
508
|
+
- bot (kickbot): Ana bot motoruna erişim. (Reference to the main kickbot instance)
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
### ⚡ Metodlar / Methods:
|
|
512
|
+
- reply(content): Ödülü kullanan kişiyi etiketleyerek cevap verir. (Reply with mention)
|
|
513
|
+
- send(content): Ödülün kullanıldığı kanala düz metin gönderir. (Send plain text)
|
|
514
|
+
"""
|
|
515
|
+
bot: 'kickbot'
|
|
516
|
+
title: str
|
|
517
|
+
user_id: int
|
|
518
|
+
channel_id: int
|
|
519
|
+
username: str
|
|
520
|
+
user_input: str
|
|
521
|
+
color: str
|
|
522
|
+
channel: dict
|
|
523
|
+
def __init__(self,data: dict,bot:'kickbot'):
|
|
524
|
+
self.bot = bot
|
|
525
|
+
self.event = data.get("event", "")
|
|
526
|
+
raw_inner = data.get("data", "{}")
|
|
527
|
+
inner_data:dict = json.loads(raw_inner) if isinstance(raw_inner, str) else raw_inner
|
|
528
|
+
self.title = inner_data.get("reward_title", "")
|
|
529
|
+
self.user_id = inner_data.get("user_id", 0)
|
|
530
|
+
self.channel_id = inner_data.get("channel_id", 0)
|
|
531
|
+
raw_channel_str = data.get("channel", "")
|
|
532
|
+
extracted_chat_id = raw_channel_str.split("_")[-1] if "_" in raw_channel_str else raw_channel_str
|
|
533
|
+
self.channel = self.bot._get_channel(extracted_chat_id)
|
|
534
|
+
self.username = inner_data.get("username", "")
|
|
535
|
+
self.input = inner_data.get("user_input", "")
|
|
536
|
+
self.color = inner_data.get("reward_background_color", "")
|
|
537
|
+
async def reply(self,content:str):
|
|
538
|
+
return await self.bot.send_message(f"@{self.username} {content}")
|
|
539
|
+
async def send(self,content:str):
|
|
540
|
+
return await self.bot.send_message(f"{content}")
|
|
541
|
+
class channel_context:
|
|
542
|
+
"""
|
|
543
|
+
### 🇹🇷 [TR] Kanal Bağlamı (Channel Context)
|
|
544
|
+
Botun bağlı olduğu her bir bağımsız kanalı (odayı) temsil eder.
|
|
545
|
+
Kanal bazlı mesaj gönderme işlemlerinin merkezidir.
|
|
546
|
+
|
|
547
|
+
### 🇺🇸 [EN] Channel Context
|
|
548
|
+
Represents each independent channel (room) the bot is connected to.
|
|
549
|
+
The hub for channel-specific message sending operations.
|
|
550
|
+
|
|
551
|
+
---
|
|
552
|
+
### 🛠️ Değişkenler / Attributes (Variables):
|
|
553
|
+
|
|
554
|
+
#### ⚓ L1: Kimlik Bilgileri / Identity
|
|
555
|
+
- name (str): Kanalın görünen adı/kullanıcı adı. (Channel's display name)
|
|
556
|
+
- channel_id (int): Kanalın ana sayısal ID'si. (Main channel ID)
|
|
557
|
+
- chat_id (int): Sohbet odasının benzersiz API ID'si. (Unique API chatroom ID)
|
|
558
|
+
|
|
559
|
+
#### 🤖 L2: Sistem / System
|
|
560
|
+
- bot (kickbot): Bağlı olduğu ana bot sınıfı. (The main kickbot instance it belongs to)
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
### ⚡ Metodlar / Methods:
|
|
564
|
+
- send(content): Bu kanala özel asenkron mesaj gönderir. (Sends an async message specifically to this channel.)
|
|
565
|
+
"""
|
|
566
|
+
def __init__(self, bot:'kickbot',name:'str',channel_id: int,chat_id:int):
|
|
567
|
+
self.bot = bot
|
|
568
|
+
self.name:str = name
|
|
569
|
+
self.channel_id: int = channel_id
|
|
570
|
+
self.chat_id: int = chat_id
|
|
571
|
+
async def send(self,content:str):
|
|
572
|
+
url = f"https://kick.com/api/v2/messages/send/{self.chat_id}"
|
|
573
|
+
headers = {"Authorization": self.bot.bearer_token,"Content-Type": "application/json","User-Agent": "Mozilla/5.0"}
|
|
574
|
+
payload = {"content": str(content), "type": "message"}
|
|
575
|
+
async with aiohttp.ClientSession() as session:
|
|
576
|
+
async with session.post(url, json=payload, headers=headers) as resp:
|
|
577
|
+
if resp.status not in [200, 201]:
|
|
578
|
+
zerror.log(level="error",
|
|
579
|
+
msg_tr=f"[{self.name}] Mesaj gönderilemedi! Kod: {resp.status}",
|
|
580
|
+
msg_en=f"[{self.name}] Failed to send message! Code: {resp.status}")
|
|
581
|
+
return resp.status
|
|
582
|
+
|
|
583
|
+
class decorators:
|
|
584
|
+
@classmethod
|
|
585
|
+
def command(cls, name: str = None, lower: bool = True, execute_bot: bool = False):
|
|
586
|
+
"""
|
|
587
|
+
### 🇹🇷 [TR] Komut Kaydedici
|
|
588
|
+
Prefix (!) ile başlayan komutları listeye ekler.
|
|
589
|
+
Aynı isimde birden fazla fonksiyon tanımlanabilir.
|
|
590
|
+
|
|
591
|
+
### 🇺🇸 [EN] Command Registerer
|
|
592
|
+
Registers prefix (!) commands into a list.
|
|
593
|
+
Multiple functions can be defined under the same name.
|
|
594
|
+
"""
|
|
595
|
+
def Decorator(fx: Callable):
|
|
596
|
+
RawName = name if name else fx.__name__
|
|
597
|
+
CommandName = RawName.lower() if lower else RawName
|
|
598
|
+
# ⚓ Liste kontrolü ve ekleme
|
|
599
|
+
if CommandName not in kickbot._commands:
|
|
600
|
+
kickbot._commands[CommandName] = []
|
|
601
|
+
kickbot._commands[CommandName].append({"func": fx, "execute_bot": execute_bot})
|
|
602
|
+
return fx
|
|
603
|
+
return Decorator
|
|
604
|
+
@classmethod
|
|
605
|
+
def message(cls, content: str, exact: bool = None, lower: bool = True, execute_bot: bool = False):
|
|
606
|
+
"""
|
|
607
|
+
### 🇹🇷 [TR] Kelime Takip Kaydedici
|
|
608
|
+
Belirli kelimeleri bir listeye ekler. Birden fazla fonksiyon aynı kelimeyi dinleyebilir.
|
|
609
|
+
|
|
610
|
+
### 🇺🇸 [EN] Word Watcher Registerer
|
|
611
|
+
Adds specific words to a list. Multiple functions can listen to the same word.
|
|
612
|
+
"""
|
|
613
|
+
def Decorator(fx: Callable):
|
|
614
|
+
sig = inspect.signature(fx)
|
|
615
|
+
final_exact = (len(sig.parameters) == 1) if exact is None else exact
|
|
616
|
+
if content not in kickbot._message_handlers:
|
|
617
|
+
kickbot._message_handlers[content] = []
|
|
618
|
+
kickbot._message_handlers[content].append({
|
|
619
|
+
"func": fx, "exact": final_exact, "lower": lower, "execute_bot": execute_bot
|
|
620
|
+
})
|
|
621
|
+
return fx
|
|
622
|
+
return Decorator
|
|
623
|
+
@classmethod
|
|
624
|
+
def on_message(cls):
|
|
625
|
+
"""
|
|
626
|
+
### 🇹🇷 [TR] Genel Mesaj İzleyici
|
|
627
|
+
Tüm mesajları dinleyen fonksiyonları 'liste'ye ekler.
|
|
628
|
+
|
|
629
|
+
### 🇺🇸 [EN] Global Message Watcher
|
|
630
|
+
Appends functions listening to all messages to the 'list'.
|
|
631
|
+
"""
|
|
632
|
+
def Decorator(func: Callable):
|
|
633
|
+
kickbot._on_message_tasks.append(func)
|
|
634
|
+
return func
|
|
635
|
+
return Decorator
|
|
636
|
+
@classmethod
|
|
637
|
+
def on_ready(cls):
|
|
638
|
+
"""
|
|
639
|
+
### 🇹🇷 [TR] Hazır Olma Görevleri
|
|
640
|
+
Bot açıldığında çalışacak görevleri listeye ekler.
|
|
641
|
+
|
|
642
|
+
### 🇺🇸 [EN] On Ready Tasks
|
|
643
|
+
Appends tasks to execute when bot is ready to the list.
|
|
644
|
+
"""
|
|
645
|
+
def Decorator(func: Callable):
|
|
646
|
+
kickbot._on_ready_tasks.append(func)
|
|
647
|
+
return func
|
|
648
|
+
return Decorator
|
|
649
|
+
@classmethod
|
|
650
|
+
def timer_task(cls, hours: int = 0, minutes: int = 0, seconds: int = 0):
|
|
651
|
+
"""
|
|
652
|
+
### 🇹🇷 [TR] Zamanlanmış Görevler
|
|
653
|
+
Periyodik görevleri paketleyip listeye ekler.
|
|
654
|
+
"""
|
|
655
|
+
def Decorator(fx: Callable):
|
|
656
|
+
total_time = (hours * 3600) + (minutes * 60) + seconds
|
|
657
|
+
if total_time > 0:
|
|
658
|
+
kickbot._timer_tasks.append({"func": fx, "interval": total_time})
|
|
659
|
+
return fx
|
|
660
|
+
return Decorator
|
|
661
|
+
## ⚓
|
|
662
|
+
@classmethod
|
|
663
|
+
def on_rewards_redemption(cls,title:str):
|
|
664
|
+
def Decorator(fx: Callable):
|
|
665
|
+
title_lower = title.lower()
|
|
666
|
+
if title_lower not in kickbot._reward_handlers:
|
|
667
|
+
kickbot._reward_handlers[title_lower] = []
|
|
668
|
+
kickbot._reward_handlers[title_lower].append({"func":fx})
|
|
669
|
+
return fx
|
|
670
|
+
return Decorator
|
|
671
|
+
|
|
672
|
+
# ⚓
|
|
673
|
+
class kickbot:
|
|
674
|
+
_commands: Dict[str, list] = {}
|
|
675
|
+
_message_handlers: Dict[str, list] = {}
|
|
676
|
+
_timer_tasks: list = []
|
|
677
|
+
_on_message_tasks: list = []
|
|
678
|
+
_on_ready_tasks: list = []
|
|
679
|
+
_reward_handlers: Dict[str, list] = {}
|
|
680
|
+
|
|
681
|
+
# ⚓ GEREKSİZ DEĞİŞKENLER SİLİNDİ, SADECE TEMEL TAŞLAR KALDI
|
|
682
|
+
user_name: str = ""
|
|
683
|
+
bearer_token: str = ""
|
|
684
|
+
app_key: str = ""
|
|
685
|
+
cluster: str = "us2"
|
|
686
|
+
prefix: str = "!"
|
|
687
|
+
|
|
688
|
+
def __init__(self, user_name, bearer_token, **kwargs): # ⚓ channel_name parametresi silindi!
|
|
689
|
+
_raw_lang = kwargs.get("framework_lang", "en")
|
|
690
|
+
if not isinstance(_raw_lang, str):
|
|
691
|
+
print(f"[❌] [ERROR/HATA] framework_lang must be a string! | framework_lang bir metin (string) olmalı! (Provided/Verilen: {type(_raw_lang).__name__})")
|
|
692
|
+
sys.exit(1)
|
|
693
|
+
zerror.lang = _raw_lang.lower()
|
|
694
|
+
|
|
695
|
+
def __validate(param_value, expected_types: list, param_name: Optional[str] = "",param_name_tr: Optional[str] = "",param_name_en: Optional[str]=""):
|
|
696
|
+
is_invalid_bool = isinstance(param_value, bool) and bool not in expected_types
|
|
697
|
+
if not any(isinstance(param_value, t) for t in expected_types) or is_invalid_bool:
|
|
698
|
+
_is_tr = zerror.lang.lower() == "tr"
|
|
699
|
+
_sep = " veya " if _is_tr else " or "
|
|
700
|
+
_final_name = (param_name_tr if _is_tr else param_name_en) if param_name == "" else param_name
|
|
701
|
+
types_str = _sep.join([t.__name__ for t in expected_types])
|
|
702
|
+
zerror.log(level="error",
|
|
703
|
+
msg_tr=f"{_final_name} şu tiplerden biri olmalı: {types_str}! (Verilen: {type(param_value).__name__})",
|
|
704
|
+
msg_en=f"{_final_name} must be one of these: {types_str}! (Provided: {type(param_value).__name__})")
|
|
705
|
+
zerror.log(level="warn", msg_tr=f"Çıkış yapılıyor...", msg_en=f"Exiting...")
|
|
706
|
+
sys.exit(1)
|
|
707
|
+
|
|
708
|
+
__validate(user_name,[str],param_name_tr="Kullanıcı Adı",param_name_en="User Name"); self.user_name = user_name.lower()
|
|
709
|
+
__validate(bearer_token, [str], param_name="Bearer Token"); _bt = bearer_token.strip(); self.bearer_token = f"Bearer {_bt[7:].strip()}" if _bt.lower().startswith("bearer ") else f"Bearer {_bt}"
|
|
710
|
+
|
|
711
|
+
if "prefix" in kwargs:
|
|
712
|
+
_val = kwargs.get("prefix","!")
|
|
713
|
+
__validate(_val,[str,int], param_name="Prefix")
|
|
714
|
+
self.prefix = _val
|
|
715
|
+
else:
|
|
716
|
+
self.prefix = '!'
|
|
717
|
+
|
|
718
|
+
if "cluster" in kwargs:
|
|
719
|
+
_val = kwargs.get("cluster","us2")
|
|
720
|
+
__validate(_val,[str],param_name="Cluster")
|
|
721
|
+
self.cluster = _val
|
|
722
|
+
else:
|
|
723
|
+
self.cluster = "us2"
|
|
724
|
+
|
|
725
|
+
if "display_live_chat" in kwargs:
|
|
726
|
+
_val = kwargs.get("display_live_chat",True)
|
|
727
|
+
__validate(_val,[bool],param_name="DisplayLiveChat")
|
|
728
|
+
self.display_live_chat = _val
|
|
729
|
+
else:
|
|
730
|
+
self.display_live_chat = True
|
|
731
|
+
|
|
732
|
+
if "display_bot_messages" in kwargs:
|
|
733
|
+
_val = kwargs.get("display_bot_messages",True)
|
|
734
|
+
__validate(_val,[bool],param_name="DisplayBotMessages")
|
|
735
|
+
self.display_bot_messages = _val
|
|
736
|
+
else:
|
|
737
|
+
self.display_bot_messages = True
|
|
738
|
+
|
|
739
|
+
if "filter_bot_messages" in kwargs:
|
|
740
|
+
_val = kwargs.get("filter_bot_messages",True)
|
|
741
|
+
__validate(_val,[bool],param_name="filter_bot_messages")
|
|
742
|
+
self.filter_bot_messages = _val
|
|
743
|
+
else:
|
|
744
|
+
self.filter_bot_messages = True
|
|
745
|
+
|
|
746
|
+
if "app_key" in kwargs:
|
|
747
|
+
_val = kwargs.get("app_key",False)
|
|
748
|
+
__validate(_val,[str,int],param_name="App Key")
|
|
749
|
+
self.app_key = _val
|
|
750
|
+
else:
|
|
751
|
+
self.app_key = 0
|
|
752
|
+
|
|
753
|
+
# ⚓ SADECE BOŞ FİLO SÖZLÜĞÜ KALDI (Kullanıcı add_channel ile dolduracak)
|
|
754
|
+
self.channels: Dict[str, 'channel_context'] = {}
|
|
755
|
+
# --- ⭐ SARI METODLAR (Yıldızlı Yetenekler) ---
|
|
756
|
+
|
|
757
|
+
""""""
|
|
758
|
+
|
|
759
|
+
def add_channel(self,name:str,channel_id:int,chat_id:int):
|
|
760
|
+
channel = channel_context(self,name,channel_id,chat_id)
|
|
761
|
+
self.channels[name.lower()] = channel
|
|
762
|
+
self.channels[str(channel_id)] = channel
|
|
763
|
+
self.channels[str(chat_id)] = channel
|
|
764
|
+
zerror.log(level="note", msg_tr=f"Yeni kanal eklendi: {name}")
|
|
765
|
+
return channel
|
|
766
|
+
def _get_channel(self,identifier) -> Optional['channel_context']:
|
|
767
|
+
return self.channels.get(str(identifier).lower())
|
|
768
|
+
def find_channel(self, identifier) -> Optional['channel_context']:
|
|
769
|
+
"""Kanalı isminden veya ID'sinden bulup objesini döndürür (get_channel ile aynıdır)."""
|
|
770
|
+
return self._get_channel(identifier)
|
|
771
|
+
|
|
772
|
+
""""""
|
|
773
|
+
|
|
774
|
+
def command(self, name: str = None, *, lower: bool = True, execute_bot: bool = False):
|
|
775
|
+
"""
|
|
776
|
+
### 🇹🇷 [TR] Komut Kaydedici
|
|
777
|
+
Prefix (örn: !) ile başlayan tetikleyicileri bir listeye ekler.
|
|
778
|
+
Aynı isimde birden fazla fonksiyon tanımlanabilir.
|
|
779
|
+
|
|
780
|
+
### 🇺🇸 [EN] Command Registerer
|
|
781
|
+
Registers triggers starting with a prefix (e.g., !) into a list.
|
|
782
|
+
Multiple functions can be defined under the same command name.
|
|
783
|
+
|
|
784
|
+
---
|
|
785
|
+
**Args:**
|
|
786
|
+
- name (str): 🇹🇷 Komut ismi (örn: 'selam'). Boş bırakılırsa fonksiyon adını alır. / 🇺🇸 Command name.
|
|
787
|
+
- lower (bool): 🇹🇷 True ise '!SELAM' ve '!selam' aynı kabul edilir. / 🇺🇸 Case insensitivity.
|
|
788
|
+
- execute_bot (bool): 🇹🇷 Botların bu komutu kullanmasına izin verir. / 🇺🇸 Allows bots to trigger this.
|
|
789
|
+
"""
|
|
790
|
+
return decorators.command(name, lower=lower, execute_bot=execute_bot)
|
|
791
|
+
|
|
792
|
+
def message(self, content: str, *, exact: bool = None, lower: bool = True, execute_bot: bool = False):
|
|
793
|
+
"""
|
|
794
|
+
### 🇹🇷 [TR] Kelime/Mesaj İzleyici Kaydedici
|
|
795
|
+
Belirli bir kelime veya cümle chate yazıldığında tetiklenecek fonksiyonları kaydeder.
|
|
796
|
+
|
|
797
|
+
### 🇺🇸 [EN] Word/Message Watcher Registerer
|
|
798
|
+
Registers functions to be triggered when a specific word or phrase is typed in chat.
|
|
799
|
+
|
|
800
|
+
---
|
|
801
|
+
**Args:**
|
|
802
|
+
- content (str): 🇹🇷 Takip edilecek kelime. / 🇺🇸 Word to follow.
|
|
803
|
+
- exact (bool): 🇹🇷 Tam eşleşme mi? (True: Sadece 'sa', False: 'sa nasılsın' içinde de yakalar). / 🇺🇸 Exact match?
|
|
804
|
+
- lower (bool): 🇹🇷 Büyük/küçük harf duyarsızlığı. / 🇺🇸 Case insensitivity.
|
|
805
|
+
- execute_bot (bool): 🇹🇷 Bot mesajları bu izleyiciyi tetiklesin mi? / 🇺🇸 Should bot messages trigger this?
|
|
806
|
+
"""
|
|
807
|
+
return decorators.message(content, exact, lower, execute_bot)
|
|
808
|
+
|
|
809
|
+
def on_message(self):
|
|
810
|
+
"""
|
|
811
|
+
### 🇹🇷 [TR] Genel Mesaj İzleyici Kaydedici
|
|
812
|
+
Gelen her mesajda (komut olsun ya da olmasın) çalışacak fonksiyonları bir listeye ekler.
|
|
813
|
+
Artık birden fazla genel izleyici tanımlayabilirsiniz.
|
|
814
|
+
|
|
815
|
+
### 🇺🇸 [EN] Global Message Watcher Registerer
|
|
816
|
+
Appends functions to a list that will execute on every incoming message
|
|
817
|
+
(whether it's a command or not). Multiple global watchers can now be defined.
|
|
818
|
+
|
|
819
|
+
---
|
|
820
|
+
**Args:** (Yok / None)
|
|
821
|
+
"""
|
|
822
|
+
return decorators.on_message()
|
|
823
|
+
|
|
824
|
+
def on_ready(self):
|
|
825
|
+
"""
|
|
826
|
+
### 🇹🇷 [TR] Hazır Olma Görevi Kaydedici
|
|
827
|
+
Bot Kick sunucularına başarıyla bağlandığında çalışacak fonksiyonları listeye ekler.
|
|
828
|
+
Artık birden fazla 'on_ready' fonksiyonu tanımlayabilirsiniz.
|
|
829
|
+
|
|
830
|
+
### 🇺🇸 [EN] On Ready Task Registerer
|
|
831
|
+
Appends functions to a list that will execute once the bot successfully
|
|
832
|
+
connects to Kick servers. Multiple 'on_ready' functions can now be defined.
|
|
833
|
+
|
|
834
|
+
----
|
|
835
|
+
**Args:** (None / Yok)
|
|
836
|
+
"""
|
|
837
|
+
return decorators.on_ready()
|
|
838
|
+
|
|
839
|
+
def timer_task(self, hours: int = 0, minutes: int = 0, seconds: int = 0):
|
|
840
|
+
"""
|
|
841
|
+
### 🇹🇷 [TR] Zamanlanmış Görev Kaydedici
|
|
842
|
+
Belirlenen saat, dakika veya saniye aralıklarıyla sürekli çalışacak fonksiyonları listeye ekler.
|
|
843
|
+
|
|
844
|
+
### 🇺🇸 [EN] Scheduled Task Registerer
|
|
845
|
+
Appends functions to a list that will execute repeatedly at defined
|
|
846
|
+
hour, minute, or second intervals.
|
|
847
|
+
|
|
848
|
+
---
|
|
849
|
+
**Args:**
|
|
850
|
+
- hours (int): 🇹🇷 Kaç saatte bir çalışsın? / 🇺🇸 Every X hours.
|
|
851
|
+
- minutes (int): 🇹🇷 Kaç dakikada bir çalışsın? / 🇺🇸 Every X minutes.
|
|
852
|
+
- seconds (int): 🇹🇷 Kaç saniyede bir çalışsın? / 🇺🇸 Every X seconds.
|
|
853
|
+
"""
|
|
854
|
+
return decorators.timer_task(hours, minutes, seconds)
|
|
855
|
+
|
|
856
|
+
""""""
|
|
857
|
+
|
|
858
|
+
def on_rewards_redemption(self,title:str):
|
|
859
|
+
return decorators.on_rewards_redemption(title=title)
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
r"""
|
|
863
|
+
### 🛡️ [DEPRECATED / V2.0] - Emekli Metodlar (Legacy Methods)
|
|
864
|
+
|
|
865
|
+
🇹🇷 [TR] Aşağıdaki `__fetch_chat_id` ve `__fetch_app_key` metodları, Kick'in Cloudflare korumasını
|
|
866
|
+
artırması ve dinamik yapıya geçmesi nedeniyle v2.0 sürümüyle birlikte emekli edilmiştir.
|
|
867
|
+
Bağlantı kararlılığı için `chat_id` ve `app_key` parametrelerinin manuel girilmesi zorunludur.
|
|
868
|
+
|
|
869
|
+
🇺🇸 [EN] The following `__fetch_chat_id` and `__fetch_app_key` methods have been deprecated
|
|
870
|
+
with v2.0 due to enhanced Cloudflare protections and Kick's dynamic infrastructure.
|
|
871
|
+
For connection stability, `chat_id` and `app_key` parameters must now be provided manually.
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
@classmethod
|
|
875
|
+
async def __fetch_chat_id(cls) -> bool:
|
|
876
|
+
---
|
|
877
|
+
### 🇹🇷 [TR] Gizli Koordinat Belirleyici (Name Mangling)
|
|
878
|
+
Hedef kanalın (`channel_name`) Kick API üzerindeki benzersiz sohbet odası kimliğini (Chat ID) bulur.
|
|
879
|
+
Bu metod çift alttan tire (`__`) ile korunmaktadır, sınıf dışından doğrudan erişilemez.
|
|
880
|
+
|
|
881
|
+
### 🇺🇸 [EN] Private Coordinate Resolver
|
|
882
|
+
Fetches the unique chatroom ID for the target `channel_name` via Kick API.
|
|
883
|
+
Protected by name mangling (`__`), preventing direct external access.
|
|
884
|
+
---
|
|
885
|
+
__url = f"https://kick.com/api/v1/channels/{cls.channel_name}"
|
|
886
|
+
__headers = {
|
|
887
|
+
"accept": "application/json",
|
|
888
|
+
"authorization": cls.bearer_token,
|
|
889
|
+
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
|
|
890
|
+
"referer": "https://kick.com/"
|
|
891
|
+
}
|
|
892
|
+
Zerror.log(level="warn",msg_tr="Chat id tanımlanmamış, otomatik olarak alınıyor...",msg_en="Chat id is undefined, fetching...")
|
|
893
|
+
try:
|
|
894
|
+
async with aiohttp.ClientSession(headers=__headers) as __session:
|
|
895
|
+
async with __session.get(__url) as __resp:
|
|
896
|
+
if __resp.status == 200:
|
|
897
|
+
__data = await __resp.json()
|
|
898
|
+
cls.chat_id = __data.get("chatroom", {}).get("id")
|
|
899
|
+
if cls.chat_id:
|
|
900
|
+
Zerror.log(level="succ",
|
|
901
|
+
msg_tr=f"Chat ID başarıyla alındı: {cls.chat_id} | İPUCU: Botun daha hızlı başlaması için bu ID'yi 'chat_id' parametresine manuel ekle!",
|
|
902
|
+
msg_en=f"Chat ID fetched: {cls.chat_id} | HINT: To run the bot faster, define this ID manually to the 'chat_id' parameter!")
|
|
903
|
+
return True
|
|
904
|
+
Zerror.log(level="error",
|
|
905
|
+
msg_tr=f"Chat ID alınırken bir hata oluştu! Sunucu yanıtı: {__resp.status}",
|
|
906
|
+
msg_en=f"An error occurred while fetching Chat ID! Server response: {__resp.status}")
|
|
907
|
+
return False
|
|
908
|
+
except Exception as __e:
|
|
909
|
+
Zerror.log(level="error",
|
|
910
|
+
msg_tr=f"Chat ID alınırken kritik bir hata oluştu: {__e}",
|
|
911
|
+
msg_en=f"A critical error occurred while fetching Chat ID: {__e}")
|
|
912
|
+
return False
|
|
913
|
+
@classmethod
|
|
914
|
+
async def __fetch_app_key(cls) -> Optional[str]:
|
|
915
|
+
---
|
|
916
|
+
### 🇹🇷 [TR] Dinamik Anahtar Avcısı
|
|
917
|
+
Kick'in ana sayfasındaki JavaScript chunk'larını tarayarak güncel Pusher
|
|
918
|
+
App Key'i (anahtarı) bulur ve geri döndürür.
|
|
919
|
+
|
|
920
|
+
### 🇺🇸 [EN] Dynamic Key Hunter
|
|
921
|
+
Fetches the current Pusher App Key by scanning JavaScript chunks
|
|
922
|
+
on Kick's main page and returns it.
|
|
923
|
+
---
|
|
924
|
+
_base_url = "https://kick.com"
|
|
925
|
+
# Tarayıcı gibi görünmek için maske takıyoruz
|
|
926
|
+
_headers = {
|
|
927
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
|
928
|
+
}
|
|
929
|
+
Zerror.log(level="warnn",
|
|
930
|
+
msg_tr="App Key tanımlanmamış; güncel anahtar JavaScript paketleri içinde aranıyor...",
|
|
931
|
+
msg_en="App Key is undefined; searching for current key within JavaScript chunks...")
|
|
932
|
+
try:
|
|
933
|
+
async with aiohttp.ClientSession(headers=_headers) as _session:
|
|
934
|
+
# 1. Ana sayfaya sızıp HTML iskeletini alıyoruz
|
|
935
|
+
async with _session.get(_base_url, timeout=10) as _resp:
|
|
936
|
+
if _resp.status != 200:
|
|
937
|
+
Zerror.log(level="error",
|
|
938
|
+
msg_tr=f"Kick ana sayfasına ulaşılamadı! Durum kodu: {_resp.status}",
|
|
939
|
+
msg_en=f"Could not reach Kick main page! Status code: {_resp.status}")
|
|
940
|
+
return None
|
|
941
|
+
_html = await _resp.text()
|
|
942
|
+
|
|
943
|
+
# 2. HTML içindeki tüm .js dosyalarını (chunk'ları) buluyoruz
|
|
944
|
+
_scripts = re.findall(r'src="([^"]+\.js)"', _html)
|
|
945
|
+
|
|
946
|
+
for _script_url in _scripts:
|
|
947
|
+
# Kısa yolları tam URL'ye çeviriyoruz
|
|
948
|
+
if not _script_url.startswith('http'):
|
|
949
|
+
_script_url = f"{_base_url}{_script_url}"
|
|
950
|
+
|
|
951
|
+
# Sadece potansiyel hazine olan 'chunks' klasörüne bakıyoruz
|
|
952
|
+
if "_next/static/chunks/" in _script_url:
|
|
953
|
+
try:
|
|
954
|
+
async with _session.get(_script_url, timeout=5) as _s_resp:
|
|
955
|
+
if _s_resp.status == 200:
|
|
956
|
+
_js_content = await _s_resp.text()
|
|
957
|
+
|
|
958
|
+
# Nokta atışı: NEXT_PUBLIC_PUSHER_KEY kalıbını arıyoruz
|
|
959
|
+
_match = re.search(r'NEXT_PUBLIC_PUSHER_KEY\s*:\s*"([^"]+)"', _js_content)
|
|
960
|
+
if _match:
|
|
961
|
+
_found_key = _match.group(1)
|
|
962
|
+
Zerror.log(level="succ",
|
|
963
|
+
msg_tr=f"App Key başarıyla yakalandı: {_found_key} | İPUCU: Daha hızlı açılış için bu anahtarı 'app_key' parametresine manuel ekle!",
|
|
964
|
+
msg_en=f"App Key captured: {_found_key} | HINT: To start the bot faster, provide this key manually to the 'app_key' parameter!")
|
|
965
|
+
return _found_key
|
|
966
|
+
except:
|
|
967
|
+
continue # Bir dosya okunamazsa pes etme, sonrakine geç
|
|
968
|
+
|
|
969
|
+
except Exception as _e:
|
|
970
|
+
Zerror.log(level="error",
|
|
971
|
+
msg_tr=f"App Key avı sırasında kritik bir hata oluştu: {_e}",
|
|
972
|
+
msg_en=f"A critical error occurred during App Key hunt: {_e}")
|
|
973
|
+
return None
|
|
974
|
+
"""
|
|
975
|
+
|
|
976
|
+
""""""
|
|
977
|
+
|
|
978
|
+
async def send_message(self, content: str, identifier=None):
|
|
979
|
+
"""
|
|
980
|
+
### 🇹🇷 [TR] Genel Mesaj Gönderme / 🇺🇸 [EN] Global Message Sender
|
|
981
|
+
Belirtilen kanala (isim veya ID ile) veya varsayılan (ilk eklenen) kanala mesaj gönderir.
|
|
982
|
+
"""
|
|
983
|
+
# Eğer özel bir tanımlayıcı (İsim veya ID) verilmişse o kanalı bul
|
|
984
|
+
if identifier:
|
|
985
|
+
target_channel = self._get_channel(identifier)
|
|
986
|
+
else:
|
|
987
|
+
# Belirtilmemişse, listeye eklenen ilk kanalı seç (Ana kanal)
|
|
988
|
+
target_channel = next(iter(self.channels.values())) if self.channels else None
|
|
989
|
+
|
|
990
|
+
if target_channel:
|
|
991
|
+
return await target_channel.send(content)
|
|
992
|
+
|
|
993
|
+
zerror.log(level="error",
|
|
994
|
+
msg_tr=f"[{identifier}] adında/ID'sinde bir kanal bulunamadı! add_channel() ile eklediğine emin ol.",
|
|
995
|
+
msg_en=f"No channel found with identifier [{identifier}]! Make sure you added it with add_channel().")
|
|
996
|
+
return False
|
|
997
|
+
|
|
998
|
+
""""""
|
|
999
|
+
|
|
1000
|
+
async def __start(self):
|
|
1001
|
+
try:
|
|
1002
|
+
colorama.init(autoreset=True)
|
|
1003
|
+
await tasks.check(self)
|
|
1004
|
+
await tasks.run_ready_funcs(self)
|
|
1005
|
+
await tasks.run_timer_tasks(self)
|
|
1006
|
+
zerror.log(level="succ", msg_tr=f"KickZero Framework Aktif! (Kaptan: {self.user_name})", msg_en=f"KickZero Framework Active! (Captain: {self.user_name})")
|
|
1007
|
+
while True:
|
|
1008
|
+
try:
|
|
1009
|
+
async with engine.connect(self) as websocket:
|
|
1010
|
+
await engine.subscribe_all(self,websocket)
|
|
1011
|
+
while True:
|
|
1012
|
+
await engine.process_all_events(self,websocket)
|
|
1013
|
+
|
|
1014
|
+
except Exception as e:
|
|
1015
|
+
zerror.log(level="warn", msg_tr=f"Bağlantı koptu, 5sn sonra tekrar bağlanılıyor: {e}", msg_en=f"Connection lost, reconnecting in 5s: {e}")
|
|
1016
|
+
await asyncio.sleep(5)
|
|
1017
|
+
|
|
1018
|
+
except KeyboardInterrupt:
|
|
1019
|
+
print("\n")
|
|
1020
|
+
zerror.log(level="warn", msg_tr="Bot durduruluyor...", msg_en="Bot stopping...")
|
|
1021
|
+
sys.exit(0)
|
|
1022
|
+
return
|
|
1023
|
+
except Exception as e:
|
|
1024
|
+
zerror.log(level="error", msg_tr=f"Kritik Başlatma Hatası: {e}", msg_en=f"Critical Startup Error: {e}")
|
|
1025
|
+
def run(self):
|
|
1026
|
+
try:
|
|
1027
|
+
asyncio.run(self.__start())
|
|
1028
|
+
except KeyboardInterrupt:
|
|
1029
|
+
zerror.log(
|
|
1030
|
+
level="note",
|
|
1031
|
+
msg_tr=f"{Fore.MAGENTA}Bot durduruldu.",
|
|
1032
|
+
msg_en=f"{Fore.MAGENTA}Bot has been stopped."
|
|
1033
|
+
)
|
|
1034
|
+
pass
|
|
1035
|
+
except Exception as e:
|
|
1036
|
+
zerror.log(level="error",
|
|
1037
|
+
msg_tr=f"Bot başlatılırken beklenmedik bir hata: {e}",
|
|
1038
|
+
msg_en=f"Unexpected error while starting the bot: {e}")
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kickzero
|
|
3
|
+
Version: 1.3.1
|
|
4
|
+
Summary: A modular and asynchronous framework for Kick.com chatbots.
|
|
5
|
+
Home-page: https://github.com/SeymenSozen/KickZero
|
|
6
|
+
Author: Seymen Sözen
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/SeymenSozen/KickZero/issues
|
|
8
|
+
Project-URL: Documentation, https://github.com/SeymenSozen/KickZero#readme
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: Other/Proprietary License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Topic :: Communications :: Chat
|
|
13
|
+
Requires-Python: >=3.8
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: aiohttp
|
|
16
|
+
Requires-Dist: websockets
|
|
17
|
+
Requires-Dist: colorama
|
|
18
|
+
Dynamic: author
|
|
19
|
+
Dynamic: classifier
|
|
20
|
+
Dynamic: description
|
|
21
|
+
Dynamic: description-content-type
|
|
22
|
+
Dynamic: home-page
|
|
23
|
+
Dynamic: project-url
|
|
24
|
+
Dynamic: requires-dist
|
|
25
|
+
Dynamic: requires-python
|
|
26
|
+
Dynamic: summary
|
|
27
|
+
|
|
28
|
+
# 🏴☠️ KickZero Framework (v1.3.1)
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+

|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
**KickZero**, Kick.com platformu için geliştirilmiş, modüler ve tamamen asenkron bir chatbot framework'üdür. Geliştiricilere karmaşık WebSocket trafiğiyle uğraşmadan, hızlı ve güçlü botlar üretme imkanı sağlar.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 🚀 Özellikler / Features
|
|
39
|
+
|
|
40
|
+
- **Asynchronous Engine:** `asyncio` ve `aiohttp` tabanlı, donma yapmayan hızlı yapı.
|
|
41
|
+
- **Multi-Channel Support:** Aynı anda birden fazla kanalı tek bir botla yönetme.
|
|
42
|
+
- **Easy Decoration:** `@bot.command`, `@bot.message` ve `@bot.timer_task` dekoratörleri ile kolay geliştirme.
|
|
43
|
+
- **Smart Context:** Mesajın yetki, renk ve içerik bilgilerine tek noktadan (`ctx`) erişim.
|
|
44
|
+
- **Reward Integration:** Kanal puanı (Reward) kullanımlarını anında yakalama.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 📦 Kurulum / Installation
|
|
49
|
+
|
|
50
|
+
Terminalinize şu komutu yazarak okyanusa açılabilirsiniz:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install kickzero
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
kickzero/__init__.py,sha256=O0ApX9xpQ-cMkkdz_RL3LGXKozDAQrATBnF4bUu6Z0M,51932
|
|
2
|
+
kickzero-1.3.1.dist-info/METADATA,sha256=naLcRT7QcFsf_BU7dWYQuej2IrNKXVYOASvvJ3xFWSs,2041
|
|
3
|
+
kickzero-1.3.1.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
|
|
4
|
+
kickzero-1.3.1.dist-info/top_level.txt,sha256=_orY-HradFlzPKqx8lP-GPqV5ZyXaEG1go3ZlfzEtlE,9
|
|
5
|
+
kickzero-1.3.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
kickzero
|