hubber.py 0.1.0__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.
- hubber_py-0.1.0/MANIFEST.in +3 -0
- hubber_py-0.1.0/PKG-INFO +696 -0
- hubber_py-0.1.0/README.md +676 -0
- hubber_py-0.1.0/hubber.py.egg-info/PKG-INFO +696 -0
- hubber_py-0.1.0/hubber.py.egg-info/SOURCES.txt +8 -0
- hubber_py-0.1.0/hubber.py.egg-info/dependency_links.txt +1 -0
- hubber_py-0.1.0/hubber.py.egg-info/requires.txt +2 -0
- hubber_py-0.1.0/hubber.py.egg-info/top_level.txt +1 -0
- hubber_py-0.1.0/pyproject.toml +35 -0
- hubber_py-0.1.0/setup.cfg +4 -0
hubber_py-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,696 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hubber.py
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Discord-like bot framework for Hubber
|
|
5
|
+
Author-email: lane <rsalol@proton.me>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/6umb/elara-hubber
|
|
8
|
+
Project-URL: Repository, https://github.com/6umb/elara-hubber
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Requires-Python: >=3.8
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
19
|
+
Requires-Dist: websockets>=10.0
|
|
20
|
+
|
|
21
|
+
# Elara
|
|
22
|
+
|
|
23
|
+
Elara is an enterprise-grade asynchronous Python wrapper for the Hubber.cc API. Built with performance and simplicity in mind, it provides a clean interface for building powerful bots with minimal code.
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- Fully asynchronous design using asyncio
|
|
28
|
+
- Discord.py-style command system with decorators
|
|
29
|
+
- Cog system for modular bot organization
|
|
30
|
+
- Rich embed builder with method chaining
|
|
31
|
+
- Interactive button components
|
|
32
|
+
- Advanced caching with LRU/LFU/FIFO eviction policies
|
|
33
|
+
- Token bucket rate limiting
|
|
34
|
+
- Automatic reconnection with exponential backoff
|
|
35
|
+
- Type hints throughout the codebase
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install python-socketio aiohttp
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import asyncio
|
|
47
|
+
from elara import Client
|
|
48
|
+
|
|
49
|
+
client = Client("YOUR_BOT_TOKEN", prefix="!")
|
|
50
|
+
|
|
51
|
+
@client.on("ready")
|
|
52
|
+
async def on_ready(data):
|
|
53
|
+
print(f"Bot online as: {data['user']['username']}")
|
|
54
|
+
|
|
55
|
+
@client.command(name="ping")
|
|
56
|
+
async def ping(ctx):
|
|
57
|
+
await ctx.send("Pong!")
|
|
58
|
+
|
|
59
|
+
asyncio.run(client.run())
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Client
|
|
63
|
+
|
|
64
|
+
### Initialization
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
Client(token: str, prefix: str = "!", enable_ratelimit: bool = True, enable_cache: bool = True)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Parameters:**
|
|
71
|
+
- `token`: Your bot token from Hubber.cc
|
|
72
|
+
- `prefix`: Command prefix (default: "!")
|
|
73
|
+
- `enable_ratelimit`: Enable automatic rate limiting (default: True)
|
|
74
|
+
- `enable_cache`: Enable caching system (default: True)
|
|
75
|
+
|
|
76
|
+
**Example:**
|
|
77
|
+
```python
|
|
78
|
+
client = Client("YOUR_TOKEN", prefix=";", enable_ratelimit=True, enable_cache=True)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Methods
|
|
82
|
+
|
|
83
|
+
#### client.run()
|
|
84
|
+
Start the bot and connect to Hubber.cc.
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
asyncio.run(client.run())
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### client.on(event: str)
|
|
91
|
+
Register an event listener.
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
@client.on("message:new")
|
|
95
|
+
async def on_message(ctx):
|
|
96
|
+
print(f"{ctx.author.username}: {ctx.content}")
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### client.command(name: str, description: str = None, aliases: List[str] = None)
|
|
100
|
+
Register a command.
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
@client.command(name="hello", description="Say hello", aliases=["hi", "hey"])
|
|
104
|
+
async def hello(ctx):
|
|
105
|
+
await ctx.send(f"Hello, {ctx.author.username}!")
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### client.load_cog(path: str)
|
|
109
|
+
Load a cog from a file path.
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
await client.load_cog("cogs/moderation.py")
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### client.unload_cog(cog_name: str)
|
|
116
|
+
Unload a loaded cog.
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
await client.unload_cog("ModerationCog")
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### client.reload_cog(cog_name: str)
|
|
123
|
+
Reload a cog.
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
await client.reload_cog("ModerationCog")
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Events
|
|
130
|
+
|
|
131
|
+
### Available Events
|
|
132
|
+
|
|
133
|
+
- `connect` - Connected to Hubber.cc
|
|
134
|
+
- `ready` - Bot is ready and authenticated
|
|
135
|
+
- `message:new` - New message received
|
|
136
|
+
- `message:edit` - Message was edited
|
|
137
|
+
- `message:delete` - Message was deleted
|
|
138
|
+
- `interaction:button` - Button was clicked
|
|
139
|
+
- `typing:start` - User started typing
|
|
140
|
+
- `server:member_join` - Member joined server
|
|
141
|
+
- `server:member_leave` - Member left server
|
|
142
|
+
- `presence:update` - User presence changed
|
|
143
|
+
- `session:expired` - Session token expired (user tokens only)
|
|
144
|
+
|
|
145
|
+
### Event Examples
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
@client.on("connect")
|
|
149
|
+
async def on_connect():
|
|
150
|
+
print("Connected!")
|
|
151
|
+
|
|
152
|
+
@client.on("ready")
|
|
153
|
+
async def on_ready(data):
|
|
154
|
+
client.user = data["user"]
|
|
155
|
+
print(f"Logged in as {client.user['username']}")
|
|
156
|
+
|
|
157
|
+
@client.on("message:new")
|
|
158
|
+
async def on_message(ctx):
|
|
159
|
+
if "hello" in ctx.content.lower():
|
|
160
|
+
await ctx.send("Hi there!")
|
|
161
|
+
|
|
162
|
+
@client.on("interaction:button")
|
|
163
|
+
async def on_button(ctx):
|
|
164
|
+
if ctx.custom_id == "confirm":
|
|
165
|
+
await ctx.reply("Confirmed!", ephemeral=True)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Context
|
|
169
|
+
|
|
170
|
+
The Context object is passed to message event handlers and commands.
|
|
171
|
+
|
|
172
|
+
### Properties
|
|
173
|
+
|
|
174
|
+
- `ctx.message_id` - Message ID
|
|
175
|
+
- `ctx.channel_id` - Channel ID
|
|
176
|
+
- `ctx.server_id` - Server ID
|
|
177
|
+
- `ctx.user_id` - User ID
|
|
178
|
+
- `ctx.content` - Message content
|
|
179
|
+
- `ctx.author` - Author object
|
|
180
|
+
- `ctx.args` - Command arguments (commands only)
|
|
181
|
+
- `ctx.command` - Command object (commands only)
|
|
182
|
+
|
|
183
|
+
### Methods
|
|
184
|
+
|
|
185
|
+
#### ctx.send(content: str = None, embed: Embed = None, embeds: List[Embed] = None, components: List[ActionRow] = None)
|
|
186
|
+
Send a message to the channel.
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
await ctx.send("Hello!")
|
|
190
|
+
await ctx.send(embed=my_embed)
|
|
191
|
+
await ctx.send("Choose:", components=[action_row])
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
#### ctx.reply(content: str = None, embed: Embed = None, embeds: List[Embed] = None, components: List[ActionRow] = None)
|
|
195
|
+
Reply to the message.
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
await ctx.reply("Thanks for your message!")
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
#### ctx.edit(content: str)
|
|
202
|
+
Edit the message.
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
await ctx.edit("Updated content")
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### ctx.delete()
|
|
209
|
+
Delete the message.
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
await ctx.delete()
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### ctx.react(emoji: str)
|
|
216
|
+
Add a reaction to the message.
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
await ctx.react("👍")
|
|
220
|
+
await ctx.react("✅")
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
#### ctx.unreact(emoji: str)
|
|
224
|
+
Remove a reaction from the message.
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
await ctx.unreact("👍")
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
#### ctx.typing()
|
|
231
|
+
Show typing indicator in the channel.
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
await ctx.typing()
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Author
|
|
238
|
+
|
|
239
|
+
The Author object contains information about a user.
|
|
240
|
+
|
|
241
|
+
### Properties
|
|
242
|
+
|
|
243
|
+
- `author.id` - User ID
|
|
244
|
+
- `author.username` - Username
|
|
245
|
+
- `author.avatar` - Avatar path
|
|
246
|
+
- `author.avatar_url` - Full avatar URL
|
|
247
|
+
- `author.avatar_color` - Avatar color hex
|
|
248
|
+
- `author.display_badge` - Display badge
|
|
249
|
+
- `author.role_color` - Role color hex
|
|
250
|
+
|
|
251
|
+
### Example
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
@client.command(name="userinfo")
|
|
255
|
+
async def userinfo(ctx):
|
|
256
|
+
await ctx.send(f"Username: {ctx.author.username}\nID: {ctx.author.id}")
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Interaction
|
|
260
|
+
|
|
261
|
+
The Interaction object is passed to button interaction handlers.
|
|
262
|
+
|
|
263
|
+
### Properties
|
|
264
|
+
|
|
265
|
+
- `ctx.custom_id` - Button custom ID
|
|
266
|
+
- `ctx.channel_id` - Channel ID
|
|
267
|
+
- `ctx.message_id` - Message ID containing the button
|
|
268
|
+
- `ctx.interaction_id` - Interaction ID
|
|
269
|
+
- `ctx.author` - Author object
|
|
270
|
+
|
|
271
|
+
### Methods
|
|
272
|
+
|
|
273
|
+
#### ctx.send(content: str, ephemeral: bool = False)
|
|
274
|
+
Send a response to the interaction.
|
|
275
|
+
|
|
276
|
+
```python
|
|
277
|
+
await ctx.send("Button clicked!", ephemeral=True)
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
#### ctx.reply(content: str, ephemeral: bool = False)
|
|
281
|
+
Reply to the interaction.
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
await ctx.reply("Processing...", ephemeral=False)
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Commands
|
|
288
|
+
|
|
289
|
+
### Basic Command
|
|
290
|
+
|
|
291
|
+
```python
|
|
292
|
+
@client.command(name="ping")
|
|
293
|
+
async def ping(ctx):
|
|
294
|
+
await ctx.send("Pong!")
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Command with Aliases
|
|
298
|
+
|
|
299
|
+
```python
|
|
300
|
+
@client.command(name="info", aliases=["i", "information"])
|
|
301
|
+
async def info(ctx):
|
|
302
|
+
await ctx.send("Bot information here")
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Command with Arguments
|
|
306
|
+
|
|
307
|
+
```python
|
|
308
|
+
@client.command(name="say")
|
|
309
|
+
async def say(ctx):
|
|
310
|
+
if ctx.args:
|
|
311
|
+
await ctx.send(ctx.args)
|
|
312
|
+
else:
|
|
313
|
+
await ctx.send("Please provide text to say")
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Command with Description
|
|
317
|
+
|
|
318
|
+
```python
|
|
319
|
+
@client.command(name="help", description="Show help information")
|
|
320
|
+
async def help(ctx):
|
|
321
|
+
await ctx.send("Available commands: ping, help, info")
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## Embeds
|
|
325
|
+
|
|
326
|
+
Create rich embedded messages with the Embed class.
|
|
327
|
+
|
|
328
|
+
### Basic Embed
|
|
329
|
+
|
|
330
|
+
```python
|
|
331
|
+
from elara import Embed
|
|
332
|
+
|
|
333
|
+
embed = Embed(
|
|
334
|
+
title="My Title",
|
|
335
|
+
description="My description",
|
|
336
|
+
color="#5865F2"
|
|
337
|
+
)
|
|
338
|
+
await ctx.send(embed=embed)
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Full Embed Example
|
|
342
|
+
|
|
343
|
+
```python
|
|
344
|
+
embed = Embed(title="User Profile", color="#00FF00")
|
|
345
|
+
embed.set_author(name=ctx.author.username, icon_url=ctx.author.avatar_url)
|
|
346
|
+
embed.set_description("This is a user profile embed")
|
|
347
|
+
embed.add_field(name="Level", value="10", inline=True)
|
|
348
|
+
embed.add_field(name="XP", value="1500", inline=True)
|
|
349
|
+
embed.set_thumbnail("https://example.com/avatar.png")
|
|
350
|
+
embed.set_image("https://example.com/banner.png")
|
|
351
|
+
embed.set_footer(text="Profile System", icon_url="https://example.com/icon.png")
|
|
352
|
+
embed.set_timestamp()
|
|
353
|
+
|
|
354
|
+
await ctx.send(embed=embed)
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Embed Methods
|
|
358
|
+
|
|
359
|
+
#### Embed(title: str = None, description: str = None, color: str = None, url: str = None)
|
|
360
|
+
Create a new embed.
|
|
361
|
+
|
|
362
|
+
#### embed.set_author(name: str, icon_url: str = None, url: str = None)
|
|
363
|
+
Set the embed author.
|
|
364
|
+
|
|
365
|
+
#### embed.add_field(name: str, value: str, inline: bool = False)
|
|
366
|
+
Add a field to the embed. Maximum 25 fields.
|
|
367
|
+
|
|
368
|
+
#### embed.set_footer(text: str, icon_url: str = None)
|
|
369
|
+
Set the embed footer.
|
|
370
|
+
|
|
371
|
+
#### embed.set_thumbnail(url: str)
|
|
372
|
+
Set the embed thumbnail.
|
|
373
|
+
|
|
374
|
+
#### embed.set_image(url: str)
|
|
375
|
+
Set the embed image.
|
|
376
|
+
|
|
377
|
+
#### embed.set_timestamp(timestamp: datetime = None)
|
|
378
|
+
Set the embed timestamp. Uses current time if not provided.
|
|
379
|
+
|
|
380
|
+
#### embed.set_color(color: str)
|
|
381
|
+
Set the embed color.
|
|
382
|
+
|
|
383
|
+
### Embed Limits
|
|
384
|
+
|
|
385
|
+
- Title: 256 characters
|
|
386
|
+
- Description: 4,096 characters
|
|
387
|
+
- Fields: 25 maximum
|
|
388
|
+
- Field Name: 256 characters
|
|
389
|
+
- Field Value: 1,024 characters
|
|
390
|
+
- Footer: 2,048 characters
|
|
391
|
+
- Total: 6,000 characters
|
|
392
|
+
- Embeds per message: 10 maximum
|
|
393
|
+
|
|
394
|
+
## Buttons and Components
|
|
395
|
+
|
|
396
|
+
Create interactive buttons with ActionRow and Button classes.
|
|
397
|
+
|
|
398
|
+
### Button Styles
|
|
399
|
+
|
|
400
|
+
```python
|
|
401
|
+
from elara import ButtonStyle
|
|
402
|
+
|
|
403
|
+
ButtonStyle.PRIMARY # Blue button
|
|
404
|
+
ButtonStyle.SECONDARY # Gray button
|
|
405
|
+
ButtonStyle.SUCCESS # Green button
|
|
406
|
+
ButtonStyle.DANGER # Red button
|
|
407
|
+
ButtonStyle.LINK # Link button
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Basic Buttons
|
|
411
|
+
|
|
412
|
+
```python
|
|
413
|
+
from elara import ActionRow, ButtonStyle
|
|
414
|
+
|
|
415
|
+
row = ActionRow()
|
|
416
|
+
row.add_button("Click Me", ButtonStyle.PRIMARY, custom_id="my_button")
|
|
417
|
+
row.add_button("Cancel", ButtonStyle.DANGER, custom_id="cancel")
|
|
418
|
+
row.add_button("Website", ButtonStyle.LINK, url="https://example.com")
|
|
419
|
+
|
|
420
|
+
await ctx.send("Choose an option:", components=[row])
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Handling Button Clicks
|
|
424
|
+
|
|
425
|
+
```python
|
|
426
|
+
@client.on("interaction:button")
|
|
427
|
+
async def on_button(ctx):
|
|
428
|
+
if ctx.custom_id == "my_button":
|
|
429
|
+
await ctx.reply(f"{ctx.author.username} clicked the button!")
|
|
430
|
+
elif ctx.custom_id == "cancel":
|
|
431
|
+
await ctx.reply("Cancelled", ephemeral=True)
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Button Limits
|
|
435
|
+
|
|
436
|
+
- Maximum 5 action rows per message
|
|
437
|
+
- Maximum 5 buttons per action row
|
|
438
|
+
- Label: 80 characters maximum
|
|
439
|
+
- custom_id: 100 characters maximum
|
|
440
|
+
- Link buttons require url, not custom_id
|
|
441
|
+
|
|
442
|
+
## Cogs
|
|
443
|
+
|
|
444
|
+
Organize your bot into modular components using cogs.
|
|
445
|
+
|
|
446
|
+
### Creating a Cog
|
|
447
|
+
|
|
448
|
+
```python
|
|
449
|
+
from elara import Cog, command, listener
|
|
450
|
+
from typing import TYPE_CHECKING
|
|
451
|
+
|
|
452
|
+
if TYPE_CHECKING:
|
|
453
|
+
from elara import Client
|
|
454
|
+
|
|
455
|
+
class MyCog(Cog):
|
|
456
|
+
def __init__(self, client: "Client"):
|
|
457
|
+
self.client = client
|
|
458
|
+
self.description = "My cog description"
|
|
459
|
+
super().__init__(client)
|
|
460
|
+
|
|
461
|
+
@command(name="test", description="Test command")
|
|
462
|
+
async def test_command(self, ctx):
|
|
463
|
+
await ctx.send("Test successful!")
|
|
464
|
+
|
|
465
|
+
@listener("message:new")
|
|
466
|
+
async def on_message(self, ctx):
|
|
467
|
+
if "test" in ctx.content:
|
|
468
|
+
await ctx.react("✅")
|
|
469
|
+
|
|
470
|
+
async def cog_load(self):
|
|
471
|
+
print("Cog loaded!")
|
|
472
|
+
|
|
473
|
+
async def cog_unload(self):
|
|
474
|
+
print("Cog unloaded!")
|
|
475
|
+
|
|
476
|
+
async def setup(client: "Client") -> None:
|
|
477
|
+
await client.add_cog(MyCog(client))
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Loading Cogs
|
|
481
|
+
|
|
482
|
+
```python
|
|
483
|
+
@client.on("ready")
|
|
484
|
+
async def on_ready(data):
|
|
485
|
+
await client.load_cog("cogs/moderation.py")
|
|
486
|
+
await client.load_cog("cogs/fun.py")
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Cog Management
|
|
490
|
+
|
|
491
|
+
```python
|
|
492
|
+
await client.load_cog("cogs/music.py")
|
|
493
|
+
await client.unload_cog("MusicCog")
|
|
494
|
+
await client.reload_cog("MusicCog")
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Cog Decorators
|
|
498
|
+
|
|
499
|
+
#### @command(name: str, description: str = None, aliases: List[str] = None)
|
|
500
|
+
Register a command in the cog.
|
|
501
|
+
|
|
502
|
+
#### @listener(event: str)
|
|
503
|
+
Register an event listener in the cog.
|
|
504
|
+
|
|
505
|
+
## Cache
|
|
506
|
+
|
|
507
|
+
Advanced caching system with multiple eviction policies.
|
|
508
|
+
|
|
509
|
+
### Basic Usage
|
|
510
|
+
|
|
511
|
+
```python
|
|
512
|
+
await client.cache.set("key", "value", ttl=60.0)
|
|
513
|
+
value = await client.cache.get("key")
|
|
514
|
+
await client.cache.delete("key")
|
|
515
|
+
await client.cache.clear()
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### Cache Methods
|
|
519
|
+
|
|
520
|
+
#### cache.get(key: str)
|
|
521
|
+
Get a value from cache.
|
|
522
|
+
|
|
523
|
+
```python
|
|
524
|
+
value = await client.cache.get("user:123")
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
#### cache.set(key: str, value: Any, ttl: float = None)
|
|
528
|
+
Set a value in cache with optional TTL.
|
|
529
|
+
|
|
530
|
+
```python
|
|
531
|
+
await client.cache.set("user:123", user_data, ttl=300.0)
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
#### cache.delete(key: str)
|
|
535
|
+
Delete a key from cache.
|
|
536
|
+
|
|
537
|
+
```python
|
|
538
|
+
await client.cache.delete("user:123")
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
#### cache.has(key: str)
|
|
542
|
+
Check if key exists in cache.
|
|
543
|
+
|
|
544
|
+
```python
|
|
545
|
+
if await client.cache.has("user:123"):
|
|
546
|
+
print("User cached")
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
#### cache.clear()
|
|
550
|
+
Clear all cache entries.
|
|
551
|
+
|
|
552
|
+
```python
|
|
553
|
+
await client.cache.clear()
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
#### cache.size()
|
|
557
|
+
Get current cache size.
|
|
558
|
+
|
|
559
|
+
```python
|
|
560
|
+
size = client.cache.size()
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
## Rate Limiting
|
|
564
|
+
|
|
565
|
+
Automatic rate limiting is built-in and enabled by default.
|
|
566
|
+
|
|
567
|
+
### Rate Limits
|
|
568
|
+
|
|
569
|
+
- Messages: 5 per 5 seconds
|
|
570
|
+
- Channel operations: 2 per 5 seconds
|
|
571
|
+
|
|
572
|
+
### Disabling Rate Limiting
|
|
573
|
+
|
|
574
|
+
```python
|
|
575
|
+
client = Client("TOKEN", enable_ratelimit=False)
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
## Message Formatting
|
|
579
|
+
|
|
580
|
+
### User Mentions
|
|
581
|
+
|
|
582
|
+
```python
|
|
583
|
+
await ctx.send(f"Hello <@{ctx.author.id}>!")
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
### Everyone Mention
|
|
587
|
+
|
|
588
|
+
```python
|
|
589
|
+
await ctx.send("@everyone Important announcement!")
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
## Error Handling
|
|
593
|
+
|
|
594
|
+
### Connection Errors
|
|
595
|
+
|
|
596
|
+
The client automatically reconnects with exponential backoff:
|
|
597
|
+
- 5s, 10s, 30s, 60s, 120s, 300s (max)
|
|
598
|
+
|
|
599
|
+
### Example Error Handling
|
|
600
|
+
|
|
601
|
+
```python
|
|
602
|
+
@client.command(name="divide")
|
|
603
|
+
async def divide(ctx):
|
|
604
|
+
try:
|
|
605
|
+
args = ctx.args.split()
|
|
606
|
+
result = int(args[0]) / int(args[1])
|
|
607
|
+
await ctx.send(f"Result: {result}")
|
|
608
|
+
except (ValueError, IndexError):
|
|
609
|
+
await ctx.send("Usage: !divide <num1> <num2>")
|
|
610
|
+
except ZeroDivisionError:
|
|
611
|
+
await ctx.send("Cannot divide by zero!")
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
## Best Practices
|
|
615
|
+
|
|
616
|
+
### Use Type Hints
|
|
617
|
+
|
|
618
|
+
```python
|
|
619
|
+
from typing import TYPE_CHECKING
|
|
620
|
+
|
|
621
|
+
if TYPE_CHECKING:
|
|
622
|
+
from elara import Client
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
### Organize with Cogs
|
|
626
|
+
|
|
627
|
+
Split your bot into logical modules using cogs for better maintainability.
|
|
628
|
+
|
|
629
|
+
### Handle Errors Gracefully
|
|
630
|
+
|
|
631
|
+
Always wrap potentially failing operations in try-except blocks.
|
|
632
|
+
|
|
633
|
+
### Use Ephemeral Responses
|
|
634
|
+
|
|
635
|
+
For sensitive information or temporary messages, use ephemeral responses:
|
|
636
|
+
|
|
637
|
+
```python
|
|
638
|
+
await ctx.reply("This is private", ephemeral=True)
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
### Leverage Caching
|
|
642
|
+
|
|
643
|
+
Cache frequently accessed data to reduce API calls and improve performance.
|
|
644
|
+
|
|
645
|
+
### Rate Limit Awareness
|
|
646
|
+
|
|
647
|
+
Keep rate limiting enabled in production to avoid API bans.
|
|
648
|
+
|
|
649
|
+
## Complete Example
|
|
650
|
+
|
|
651
|
+
```python
|
|
652
|
+
import asyncio
|
|
653
|
+
from elara import Client, Embed, ActionRow, ButtonStyle
|
|
654
|
+
|
|
655
|
+
client = Client("YOUR_TOKEN", prefix="!")
|
|
656
|
+
|
|
657
|
+
@client.on("ready")
|
|
658
|
+
async def on_ready(data):
|
|
659
|
+
print(f"Bot online as: {data['user']['username']}")
|
|
660
|
+
|
|
661
|
+
@client.command(name="profile", description="View user profile")
|
|
662
|
+
async def profile(ctx):
|
|
663
|
+
embed = Embed(
|
|
664
|
+
title=f"{ctx.author.username}'s Profile",
|
|
665
|
+
color="#5865F2"
|
|
666
|
+
)
|
|
667
|
+
embed.set_thumbnail(ctx.author.avatar_url)
|
|
668
|
+
embed.add_field(name="User ID", value=ctx.author.id, inline=True)
|
|
669
|
+
embed.add_field(name="Badge", value=ctx.author.display_badge or "None", inline=True)
|
|
670
|
+
embed.set_footer(text="Profile System")
|
|
671
|
+
embed.set_timestamp()
|
|
672
|
+
|
|
673
|
+
row = ActionRow()
|
|
674
|
+
row.add_button("Refresh", ButtonStyle.PRIMARY, custom_id="refresh_profile")
|
|
675
|
+
|
|
676
|
+
await ctx.send(embed=embed, components=[row])
|
|
677
|
+
|
|
678
|
+
@client.on("interaction:button")
|
|
679
|
+
async def on_button(ctx):
|
|
680
|
+
if ctx.custom_id == "refresh_profile":
|
|
681
|
+
await ctx.reply("Profile refreshed!", ephemeral=True)
|
|
682
|
+
|
|
683
|
+
@client.command(name="ping")
|
|
684
|
+
async def ping(ctx):
|
|
685
|
+
await ctx.send("Pong!")
|
|
686
|
+
|
|
687
|
+
asyncio.run(client.run())
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
## Support
|
|
691
|
+
|
|
692
|
+
For issues and questions, refer to the Hubber.cc API documentation at https://hubber.cc/docs
|
|
693
|
+
|
|
694
|
+
## License
|
|
695
|
+
|
|
696
|
+
This library is provided as-is for use with the Hubber.cc platform.
|