webhookloggerx 2.0.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.
- webhookloggerx-2.0.0/PKG-INFO +284 -0
- webhookloggerx-2.0.0/README.md +259 -0
- webhookloggerx-2.0.0/setup.cfg +4 -0
- webhookloggerx-2.0.0/setup.py +29 -0
- webhookloggerx-2.0.0/webhooklogger/__init__.py +32 -0
- webhookloggerx-2.0.0/webhooklogger/client.py +179 -0
- webhookloggerx-2.0.0/webhooklogger/embed.py +209 -0
- webhookloggerx-2.0.0/webhooklogger/main.py +2 -0
- webhookloggerx-2.0.0/webhookloggerx.egg-info/PKG-INFO +284 -0
- webhookloggerx-2.0.0/webhookloggerx.egg-info/SOURCES.txt +11 -0
- webhookloggerx-2.0.0/webhookloggerx.egg-info/dependency_links.txt +1 -0
- webhookloggerx-2.0.0/webhookloggerx.egg-info/requires.txt +1 -0
- webhookloggerx-2.0.0/webhookloggerx.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: webhookloggerx
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: A clean, user-friendly Python package for sending Discord webhook messages and rich embeds.
|
|
5
|
+
Author: Nur Mohammad Rafi
|
|
6
|
+
Author-email:
|
|
7
|
+
Keywords: discord webhook embed notification bot
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
13
|
+
Classifier: Topic :: Communications
|
|
14
|
+
Requires-Python: >=3.7
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: requests>=2.20.0
|
|
17
|
+
Dynamic: author
|
|
18
|
+
Dynamic: classifier
|
|
19
|
+
Dynamic: description
|
|
20
|
+
Dynamic: description-content-type
|
|
21
|
+
Dynamic: keywords
|
|
22
|
+
Dynamic: requires-dist
|
|
23
|
+
Dynamic: requires-python
|
|
24
|
+
Dynamic: summary
|
|
25
|
+
|
|
26
|
+
# webhooklogger-python-rafi
|
|
27
|
+
|
|
28
|
+
A clean, user-friendly Python package for sending Discord webhook messages and rich embeds.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install webhookloggerx
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from webhooklogger import WebhookClient, Embed
|
|
40
|
+
|
|
41
|
+
client = WebhookClient("https://discord.com/api/webhooks/YOUR_ID/YOUR_TOKEN")
|
|
42
|
+
client.send("Hello from webhooklogger!")
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- ✅ Send plain text messages
|
|
50
|
+
- ✅ Send rich Discord embeds
|
|
51
|
+
- ✅ Send multiple embeds in one request
|
|
52
|
+
- ✅ Customise webhook display name & avatar
|
|
53
|
+
- ✅ Embed builder with fluent (chainable) API
|
|
54
|
+
- ✅ Built-in colour themes (`success`, `error`, `warning`, etc.)
|
|
55
|
+
- ✅ Set embed title, description, author, footer, images, timestamp, fields
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## WebhookClient
|
|
60
|
+
|
|
61
|
+
### Create a Client
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from webhooklogger import WebhookClient
|
|
65
|
+
|
|
66
|
+
client = WebhookClient("https://discord.com/api/webhooks/...")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Set Webhook Profile (name & avatar)
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
client.set_profile(
|
|
73
|
+
username="MyBot",
|
|
74
|
+
avatar_url="https://example.com/avatar.png"
|
|
75
|
+
)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Send a Plain Text Message
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
client.send("This is a plain message.")
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Send an Embed
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from webhooklogger import Embed
|
|
88
|
+
|
|
89
|
+
embed = Embed().set_title("Hello!").set_description("Embed body here.")
|
|
90
|
+
client.send_embed(embed)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Send Multiple Embeds
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
embed1 = Embed().set_title("First").set_theme("success")
|
|
97
|
+
embed2 = Embed().set_title("Second").set_theme("error")
|
|
98
|
+
client.send_embeds([embed1, embed2])
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Send Text + Embed Together
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
embed = Embed().set_title("Alert").set_description("Check this out!")
|
|
105
|
+
client.send_message(content="Hey team!", embed=embed)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Embed Builder
|
|
111
|
+
|
|
112
|
+
All methods return `self`, so you can **chain** them fluently.
|
|
113
|
+
|
|
114
|
+
### Title & Description
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
embed = (
|
|
118
|
+
Embed()
|
|
119
|
+
.set_title("My Title")
|
|
120
|
+
.set_description("This is the body of the embed.")
|
|
121
|
+
.set_url("https://example.com") # makes title clickable
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Colour
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
# Hex string
|
|
129
|
+
embed.set_color("#FF5733")
|
|
130
|
+
|
|
131
|
+
# Integer
|
|
132
|
+
embed.set_color(16711680)
|
|
133
|
+
|
|
134
|
+
# Named theme
|
|
135
|
+
embed.set_theme("success")
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Available themes:**
|
|
139
|
+
|
|
140
|
+
| Theme | Colour |
|
|
141
|
+
|---|---|
|
|
142
|
+
| `default` | Discord Blurple |
|
|
143
|
+
| `success` | Green |
|
|
144
|
+
| `warning` | Yellow |
|
|
145
|
+
| `error` | Red |
|
|
146
|
+
| `info` | Blue |
|
|
147
|
+
| `dark` | Dark Grey |
|
|
148
|
+
| `light` | White |
|
|
149
|
+
| `purple` | Purple |
|
|
150
|
+
| `orange` | Orange |
|
|
151
|
+
| `pink` | Pink |
|
|
152
|
+
|
|
153
|
+
### Author
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
embed.set_author(
|
|
157
|
+
name="Nur Mohammad Rafi",
|
|
158
|
+
url="https://github.com/yourusername",
|
|
159
|
+
icon_url="https://example.com/icon.png"
|
|
160
|
+
)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Thumbnail & Image
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
embed.set_thumbnail("https://example.com/thumb.png") # top-right corner
|
|
167
|
+
embed.set_image("https://example.com/big-image.png") # large bottom image
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Fields
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
embed.add_field("Status", "Online", inline=True)
|
|
174
|
+
embed.add_field("Server", "Production", inline=True)
|
|
175
|
+
embed.add_field("Message", "All systems go.", inline=False)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
- `inline=True` — fields sit side by side (up to 3 per row)
|
|
179
|
+
- `inline=False` — field takes the full width
|
|
180
|
+
- Max **25 fields** per embed
|
|
181
|
+
|
|
182
|
+
### Footer
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
embed.set_footer("webhooklogger v1.0", icon_url="https://example.com/icon.png")
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Timestamp
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
embed.set_timestamp() # use current UTC time
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
from datetime import datetime, timezone
|
|
196
|
+
embed.set_timestamp(datetime(2025, 1, 1, tzinfo=timezone.utc)) # custom time
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Full Example
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
from webhooklogger import WebhookClient, Embed
|
|
205
|
+
|
|
206
|
+
# Create and configure client
|
|
207
|
+
client = WebhookClient("https://discord.com/api/webhooks/...")
|
|
208
|
+
client.set_profile(username="AlertBot", avatar_url="https://example.com/bot.png")
|
|
209
|
+
|
|
210
|
+
# Build embed
|
|
211
|
+
embed = (
|
|
212
|
+
Embed()
|
|
213
|
+
.set_title("🚨 System Alert")
|
|
214
|
+
.set_description("A critical event has been detected on the server.")
|
|
215
|
+
.set_theme("error")
|
|
216
|
+
.set_author("Monitor System", icon_url="https://example.com/icon.png")
|
|
217
|
+
.set_thumbnail("https://example.com/thumb.png")
|
|
218
|
+
.add_field("Host", "prod-server-01", inline=True)
|
|
219
|
+
.add_field("Status", "❌ Down", inline=True)
|
|
220
|
+
.add_field("Region", "US-East", inline=True)
|
|
221
|
+
.add_field("Details", "Connection timeout after 30s", inline=False)
|
|
222
|
+
.set_image("https://example.com/graph.png")
|
|
223
|
+
.set_footer("webhooklogger • Auto-alert system")
|
|
224
|
+
.set_timestamp()
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# Send it
|
|
228
|
+
client.send_embed(embed)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Error Handling
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
from webhooklogger import WebhookClient, WebhookError
|
|
237
|
+
|
|
238
|
+
client = WebhookClient("https://discord.com/api/webhooks/...")
|
|
239
|
+
|
|
240
|
+
try:
|
|
241
|
+
client.send("Test message")
|
|
242
|
+
except WebhookError as e:
|
|
243
|
+
print(f"Failed: HTTP {e.status_code} — {e.message}")
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## API Reference
|
|
249
|
+
|
|
250
|
+
### `WebhookClient`
|
|
251
|
+
|
|
252
|
+
| Method | Description |
|
|
253
|
+
|---|---|
|
|
254
|
+
| `__init__(url)` | Create client with webhook URL |
|
|
255
|
+
| `set_profile(username, avatar_url)` | Override display name & avatar |
|
|
256
|
+
| `send(content)` | Send plain text message |
|
|
257
|
+
| `send_embed(embed)` | Send a single Embed |
|
|
258
|
+
| `send_embeds(embeds)` | Send a list of Embeds (max 10) |
|
|
259
|
+
| `send_message(content, embed)` | Send text + embed together |
|
|
260
|
+
|
|
261
|
+
### `Embed`
|
|
262
|
+
|
|
263
|
+
| Method | Description |
|
|
264
|
+
|---|---|
|
|
265
|
+
| `set_title(title)` | Embed title |
|
|
266
|
+
| `set_description(text)` | Embed body text |
|
|
267
|
+
| `set_url(url)` | Make title a hyperlink |
|
|
268
|
+
| `set_color(color)` | Hex string or int |
|
|
269
|
+
| `set_colour(color)` | Alias for `set_color` |
|
|
270
|
+
| `set_theme(theme)` | Named colour theme |
|
|
271
|
+
| `set_author(name, url, icon_url)` | Author block |
|
|
272
|
+
| `set_thumbnail(url)` | Small top-right image |
|
|
273
|
+
| `set_image(url)` | Large bottom image |
|
|
274
|
+
| `set_footer(text, icon_url)` | Footer text & icon |
|
|
275
|
+
| `set_timestamp(dt)` | Timestamp (default: now) |
|
|
276
|
+
| `add_field(name, value, inline)` | Add a field |
|
|
277
|
+
| `clear_fields()` | Remove all fields |
|
|
278
|
+
| `build()` | Return raw dict for API |
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## License
|
|
283
|
+
|
|
284
|
+
MIT © Nur Mohammad Rafi
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# webhooklogger-python-rafi
|
|
2
|
+
|
|
3
|
+
A clean, user-friendly Python package for sending Discord webhook messages and rich embeds.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install webhookloggerx
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from webhooklogger import WebhookClient, Embed
|
|
15
|
+
|
|
16
|
+
client = WebhookClient("https://discord.com/api/webhooks/YOUR_ID/YOUR_TOKEN")
|
|
17
|
+
client.send("Hello from webhooklogger!")
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
- ✅ Send plain text messages
|
|
25
|
+
- ✅ Send rich Discord embeds
|
|
26
|
+
- ✅ Send multiple embeds in one request
|
|
27
|
+
- ✅ Customise webhook display name & avatar
|
|
28
|
+
- ✅ Embed builder with fluent (chainable) API
|
|
29
|
+
- ✅ Built-in colour themes (`success`, `error`, `warning`, etc.)
|
|
30
|
+
- ✅ Set embed title, description, author, footer, images, timestamp, fields
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## WebhookClient
|
|
35
|
+
|
|
36
|
+
### Create a Client
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from webhooklogger import WebhookClient
|
|
40
|
+
|
|
41
|
+
client = WebhookClient("https://discord.com/api/webhooks/...")
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Set Webhook Profile (name & avatar)
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
client.set_profile(
|
|
48
|
+
username="MyBot",
|
|
49
|
+
avatar_url="https://example.com/avatar.png"
|
|
50
|
+
)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Send a Plain Text Message
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
client.send("This is a plain message.")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Send an Embed
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from webhooklogger import Embed
|
|
63
|
+
|
|
64
|
+
embed = Embed().set_title("Hello!").set_description("Embed body here.")
|
|
65
|
+
client.send_embed(embed)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Send Multiple Embeds
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
embed1 = Embed().set_title("First").set_theme("success")
|
|
72
|
+
embed2 = Embed().set_title("Second").set_theme("error")
|
|
73
|
+
client.send_embeds([embed1, embed2])
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Send Text + Embed Together
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
embed = Embed().set_title("Alert").set_description("Check this out!")
|
|
80
|
+
client.send_message(content="Hey team!", embed=embed)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Embed Builder
|
|
86
|
+
|
|
87
|
+
All methods return `self`, so you can **chain** them fluently.
|
|
88
|
+
|
|
89
|
+
### Title & Description
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
embed = (
|
|
93
|
+
Embed()
|
|
94
|
+
.set_title("My Title")
|
|
95
|
+
.set_description("This is the body of the embed.")
|
|
96
|
+
.set_url("https://example.com") # makes title clickable
|
|
97
|
+
)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Colour
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
# Hex string
|
|
104
|
+
embed.set_color("#FF5733")
|
|
105
|
+
|
|
106
|
+
# Integer
|
|
107
|
+
embed.set_color(16711680)
|
|
108
|
+
|
|
109
|
+
# Named theme
|
|
110
|
+
embed.set_theme("success")
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Available themes:**
|
|
114
|
+
|
|
115
|
+
| Theme | Colour |
|
|
116
|
+
|---|---|
|
|
117
|
+
| `default` | Discord Blurple |
|
|
118
|
+
| `success` | Green |
|
|
119
|
+
| `warning` | Yellow |
|
|
120
|
+
| `error` | Red |
|
|
121
|
+
| `info` | Blue |
|
|
122
|
+
| `dark` | Dark Grey |
|
|
123
|
+
| `light` | White |
|
|
124
|
+
| `purple` | Purple |
|
|
125
|
+
| `orange` | Orange |
|
|
126
|
+
| `pink` | Pink |
|
|
127
|
+
|
|
128
|
+
### Author
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
embed.set_author(
|
|
132
|
+
name="Nur Mohammad Rafi",
|
|
133
|
+
url="https://github.com/yourusername",
|
|
134
|
+
icon_url="https://example.com/icon.png"
|
|
135
|
+
)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Thumbnail & Image
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
embed.set_thumbnail("https://example.com/thumb.png") # top-right corner
|
|
142
|
+
embed.set_image("https://example.com/big-image.png") # large bottom image
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Fields
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
embed.add_field("Status", "Online", inline=True)
|
|
149
|
+
embed.add_field("Server", "Production", inline=True)
|
|
150
|
+
embed.add_field("Message", "All systems go.", inline=False)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
- `inline=True` — fields sit side by side (up to 3 per row)
|
|
154
|
+
- `inline=False` — field takes the full width
|
|
155
|
+
- Max **25 fields** per embed
|
|
156
|
+
|
|
157
|
+
### Footer
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
embed.set_footer("webhooklogger v1.0", icon_url="https://example.com/icon.png")
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Timestamp
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
embed.set_timestamp() # use current UTC time
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
from datetime import datetime, timezone
|
|
171
|
+
embed.set_timestamp(datetime(2025, 1, 1, tzinfo=timezone.utc)) # custom time
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Full Example
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
from webhooklogger import WebhookClient, Embed
|
|
180
|
+
|
|
181
|
+
# Create and configure client
|
|
182
|
+
client = WebhookClient("https://discord.com/api/webhooks/...")
|
|
183
|
+
client.set_profile(username="AlertBot", avatar_url="https://example.com/bot.png")
|
|
184
|
+
|
|
185
|
+
# Build embed
|
|
186
|
+
embed = (
|
|
187
|
+
Embed()
|
|
188
|
+
.set_title("🚨 System Alert")
|
|
189
|
+
.set_description("A critical event has been detected on the server.")
|
|
190
|
+
.set_theme("error")
|
|
191
|
+
.set_author("Monitor System", icon_url="https://example.com/icon.png")
|
|
192
|
+
.set_thumbnail("https://example.com/thumb.png")
|
|
193
|
+
.add_field("Host", "prod-server-01", inline=True)
|
|
194
|
+
.add_field("Status", "❌ Down", inline=True)
|
|
195
|
+
.add_field("Region", "US-East", inline=True)
|
|
196
|
+
.add_field("Details", "Connection timeout after 30s", inline=False)
|
|
197
|
+
.set_image("https://example.com/graph.png")
|
|
198
|
+
.set_footer("webhooklogger • Auto-alert system")
|
|
199
|
+
.set_timestamp()
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
# Send it
|
|
203
|
+
client.send_embed(embed)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Error Handling
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
from webhooklogger import WebhookClient, WebhookError
|
|
212
|
+
|
|
213
|
+
client = WebhookClient("https://discord.com/api/webhooks/...")
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
client.send("Test message")
|
|
217
|
+
except WebhookError as e:
|
|
218
|
+
print(f"Failed: HTTP {e.status_code} — {e.message}")
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## API Reference
|
|
224
|
+
|
|
225
|
+
### `WebhookClient`
|
|
226
|
+
|
|
227
|
+
| Method | Description |
|
|
228
|
+
|---|---|
|
|
229
|
+
| `__init__(url)` | Create client with webhook URL |
|
|
230
|
+
| `set_profile(username, avatar_url)` | Override display name & avatar |
|
|
231
|
+
| `send(content)` | Send plain text message |
|
|
232
|
+
| `send_embed(embed)` | Send a single Embed |
|
|
233
|
+
| `send_embeds(embeds)` | Send a list of Embeds (max 10) |
|
|
234
|
+
| `send_message(content, embed)` | Send text + embed together |
|
|
235
|
+
|
|
236
|
+
### `Embed`
|
|
237
|
+
|
|
238
|
+
| Method | Description |
|
|
239
|
+
|---|---|
|
|
240
|
+
| `set_title(title)` | Embed title |
|
|
241
|
+
| `set_description(text)` | Embed body text |
|
|
242
|
+
| `set_url(url)` | Make title a hyperlink |
|
|
243
|
+
| `set_color(color)` | Hex string or int |
|
|
244
|
+
| `set_colour(color)` | Alias for `set_color` |
|
|
245
|
+
| `set_theme(theme)` | Named colour theme |
|
|
246
|
+
| `set_author(name, url, icon_url)` | Author block |
|
|
247
|
+
| `set_thumbnail(url)` | Small top-right image |
|
|
248
|
+
| `set_image(url)` | Large bottom image |
|
|
249
|
+
| `set_footer(text, icon_url)` | Footer text & icon |
|
|
250
|
+
| `set_timestamp(dt)` | Timestamp (default: now) |
|
|
251
|
+
| `add_field(name, value, inline)` | Add a field |
|
|
252
|
+
| `clear_fields()` | Remove all fields |
|
|
253
|
+
| `build()` | Return raw dict for API |
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## License
|
|
258
|
+
|
|
259
|
+
MIT © Nur Mohammad Rafi
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as f:
|
|
4
|
+
long_description = f.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="webhookloggerx",
|
|
8
|
+
version="2.0.0",
|
|
9
|
+
packages=find_packages(),
|
|
10
|
+
install_requires=[
|
|
11
|
+
"requests>=2.20.0",
|
|
12
|
+
],
|
|
13
|
+
author="Nur Mohammad Rafi",
|
|
14
|
+
author_email="",
|
|
15
|
+
description="A clean, user-friendly Python package for sending Discord webhook messages and rich embeds.",
|
|
16
|
+
long_description=long_description,
|
|
17
|
+
long_description_content_type="text/markdown",
|
|
18
|
+
# url="https://github.com/yourusername/webhooklogger",
|
|
19
|
+
classifiers=[
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"License :: OSI Approved :: MIT License",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Intended Audience :: Developers",
|
|
24
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
25
|
+
"Topic :: Communications",
|
|
26
|
+
],
|
|
27
|
+
python_requires=">=3.7",
|
|
28
|
+
keywords="discord webhook embed notification bot",
|
|
29
|
+
)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
webhooklogger
|
|
3
|
+
~~~~~~~~~~~~~
|
|
4
|
+
A clean, user-friendly Python package for sending Discord webhook messages
|
|
5
|
+
and rich embeds.
|
|
6
|
+
|
|
7
|
+
Usage::
|
|
8
|
+
|
|
9
|
+
from webhooklogger import WebhookClient, Embed
|
|
10
|
+
|
|
11
|
+
client = WebhookClient("https://discord.com/api/webhooks/...")
|
|
12
|
+
client.set_profile(username="MyBot")
|
|
13
|
+
client.send("Hello from webhooklogger!")
|
|
14
|
+
|
|
15
|
+
embed = (
|
|
16
|
+
Embed()
|
|
17
|
+
.set_title("Notification")
|
|
18
|
+
.set_theme("success")
|
|
19
|
+
.set_description("Everything is running smoothly.")
|
|
20
|
+
.set_timestamp()
|
|
21
|
+
)
|
|
22
|
+
client.send_embed(embed)
|
|
23
|
+
|
|
24
|
+
:license: MIT
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from .client import WebhookClient, WebhookError
|
|
28
|
+
from .embed import Embed
|
|
29
|
+
|
|
30
|
+
__all__ = ["WebhookClient", "WebhookError", "Embed"]
|
|
31
|
+
__version__ = "1.0.0"
|
|
32
|
+
__author__ = "Nur Mohammad Rafi"
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""
|
|
2
|
+
webhooklogger.client
|
|
3
|
+
~~~~~~~~~~~~~~~~~~~~
|
|
4
|
+
WebhookClient — send messages and embeds to Discord webhooks.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
from .embed import Embed
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class WebhookError(Exception):
|
|
12
|
+
"""Raised when the Discord API returns a non-2xx response."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, status_code: int, message: str):
|
|
15
|
+
self.status_code = status_code
|
|
16
|
+
self.message = message
|
|
17
|
+
super().__init__(f"[HTTP {status_code}] {message}")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class WebhookClient:
|
|
21
|
+
"""
|
|
22
|
+
Main client for sending data to a Discord webhook URL.
|
|
23
|
+
|
|
24
|
+
Example::
|
|
25
|
+
|
|
26
|
+
from webhooklogger import WebhookClient, Embed
|
|
27
|
+
|
|
28
|
+
client = WebhookClient("https://discord.com/api/webhooks/...")
|
|
29
|
+
client.set_profile(username="MyBot", avatar_url="https://...")
|
|
30
|
+
client.send("Hello, world!")
|
|
31
|
+
|
|
32
|
+
embed = (
|
|
33
|
+
Embed()
|
|
34
|
+
.set_title("Alert")
|
|
35
|
+
.set_color("error")
|
|
36
|
+
.set_description("Something went wrong!")
|
|
37
|
+
.set_timestamp()
|
|
38
|
+
)
|
|
39
|
+
client.send_embed(embed)
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
BASE_URL = "https://discord.com/api/webhooks/"
|
|
43
|
+
|
|
44
|
+
def __init__(self, url: str):
|
|
45
|
+
"""
|
|
46
|
+
:param url: Full Discord webhook URL.
|
|
47
|
+
"""
|
|
48
|
+
if not url or "discord.com/api/webhooks" not in url:
|
|
49
|
+
raise ValueError(
|
|
50
|
+
"Invalid webhook URL. "
|
|
51
|
+
"It must be a Discord webhook URL "
|
|
52
|
+
"(https://discord.com/api/webhooks/...)."
|
|
53
|
+
)
|
|
54
|
+
self._url = url.rstrip("/") + "?wait=true"
|
|
55
|
+
self._username: str = None
|
|
56
|
+
self._avatar_url: str = None
|
|
57
|
+
|
|
58
|
+
# ------------------------------------------------------------------ #
|
|
59
|
+
# Profile #
|
|
60
|
+
# ------------------------------------------------------------------ #
|
|
61
|
+
|
|
62
|
+
def set_profile(
|
|
63
|
+
self,
|
|
64
|
+
username: str = None,
|
|
65
|
+
avatar_url: str = None,
|
|
66
|
+
) -> "WebhookClient":
|
|
67
|
+
"""
|
|
68
|
+
Override the webhook's display name and/or avatar.
|
|
69
|
+
|
|
70
|
+
:param username: Custom display name shown in Discord.
|
|
71
|
+
:param avatar_url: URL to an image used as the avatar.
|
|
72
|
+
|
|
73
|
+
Returns ``self`` so you can chain calls::
|
|
74
|
+
|
|
75
|
+
client.set_profile(username="AlertBot", avatar_url="https://...")
|
|
76
|
+
"""
|
|
77
|
+
if username:
|
|
78
|
+
self._username = str(username)
|
|
79
|
+
if avatar_url:
|
|
80
|
+
self._avatar_url = str(avatar_url)
|
|
81
|
+
return self
|
|
82
|
+
|
|
83
|
+
# ------------------------------------------------------------------ #
|
|
84
|
+
# Internal helpers #
|
|
85
|
+
# ------------------------------------------------------------------ #
|
|
86
|
+
|
|
87
|
+
def _base_payload(self) -> dict:
|
|
88
|
+
payload = {}
|
|
89
|
+
if self._username:
|
|
90
|
+
payload["username"] = self._username
|
|
91
|
+
if self._avatar_url:
|
|
92
|
+
payload["avatar_url"] = self._avatar_url
|
|
93
|
+
return payload
|
|
94
|
+
|
|
95
|
+
def _post(self, payload: dict) -> dict:
|
|
96
|
+
"""Send the payload and raise WebhookError on failure."""
|
|
97
|
+
response = requests.post(self._url, json=payload, timeout=10)
|
|
98
|
+
if not response.ok:
|
|
99
|
+
try:
|
|
100
|
+
detail = response.json().get("message", response.text)
|
|
101
|
+
except Exception:
|
|
102
|
+
detail = response.text
|
|
103
|
+
raise WebhookError(response.status_code, detail)
|
|
104
|
+
return response.json()
|
|
105
|
+
|
|
106
|
+
# ------------------------------------------------------------------ #
|
|
107
|
+
# Public send methods #
|
|
108
|
+
# ------------------------------------------------------------------ #
|
|
109
|
+
|
|
110
|
+
def send(self, content: str) -> dict:
|
|
111
|
+
"""
|
|
112
|
+
Send a plain text message.
|
|
113
|
+
|
|
114
|
+
:param content: The message text (max 2000 chars).
|
|
115
|
+
:returns: The response dict from Discord.
|
|
116
|
+
"""
|
|
117
|
+
if not content:
|
|
118
|
+
raise ValueError("content cannot be empty")
|
|
119
|
+
payload = self._base_payload()
|
|
120
|
+
payload["content"] = str(content)
|
|
121
|
+
return self._post(payload)
|
|
122
|
+
|
|
123
|
+
def send_embed(self, embed: Embed) -> dict:
|
|
124
|
+
"""
|
|
125
|
+
Send a single :class:`~webhooklogger.Embed`.
|
|
126
|
+
|
|
127
|
+
:param embed: An :class:`~webhooklogger.Embed` instance.
|
|
128
|
+
:returns: The response dict from Discord.
|
|
129
|
+
"""
|
|
130
|
+
if not isinstance(embed, Embed):
|
|
131
|
+
raise TypeError("embed must be an Embed instance")
|
|
132
|
+
payload = self._base_payload()
|
|
133
|
+
payload["embeds"] = [embed.build()]
|
|
134
|
+
return self._post(payload)
|
|
135
|
+
|
|
136
|
+
def send_embeds(self, embeds: list) -> dict:
|
|
137
|
+
"""
|
|
138
|
+
Send multiple embeds in a single request (up to 10).
|
|
139
|
+
|
|
140
|
+
:param embeds: A list of :class:`~webhooklogger.Embed` instances.
|
|
141
|
+
:returns: The response dict from Discord.
|
|
142
|
+
"""
|
|
143
|
+
if not embeds:
|
|
144
|
+
raise ValueError("embeds list cannot be empty")
|
|
145
|
+
if len(embeds) > 10:
|
|
146
|
+
raise ValueError("Discord allows a maximum of 10 embeds per message")
|
|
147
|
+
for i, e in enumerate(embeds):
|
|
148
|
+
if not isinstance(e, Embed):
|
|
149
|
+
raise TypeError(f"Item at index {i} is not an Embed instance")
|
|
150
|
+
payload = self._base_payload()
|
|
151
|
+
payload["embeds"] = [e.build() for e in embeds]
|
|
152
|
+
return self._post(payload)
|
|
153
|
+
|
|
154
|
+
def send_message(self, content: str = None, embed: Embed = None) -> dict:
|
|
155
|
+
"""
|
|
156
|
+
Send a message with optional text content AND an embed together.
|
|
157
|
+
|
|
158
|
+
:param content: Optional plain text message.
|
|
159
|
+
:param embed: Optional :class:`~webhooklogger.Embed`.
|
|
160
|
+
:returns: The response dict from Discord.
|
|
161
|
+
"""
|
|
162
|
+
if content is None and embed is None:
|
|
163
|
+
raise ValueError("Provide at least content or an embed")
|
|
164
|
+
payload = self._base_payload()
|
|
165
|
+
if content:
|
|
166
|
+
payload["content"] = str(content)
|
|
167
|
+
if embed:
|
|
168
|
+
if not isinstance(embed, Embed):
|
|
169
|
+
raise TypeError("embed must be an Embed instance")
|
|
170
|
+
payload["embeds"] = [embed.build()]
|
|
171
|
+
return self._post(payload)
|
|
172
|
+
|
|
173
|
+
# ------------------------------------------------------------------ #
|
|
174
|
+
# Repr #
|
|
175
|
+
# ------------------------------------------------------------------ #
|
|
176
|
+
|
|
177
|
+
def __repr__(self) -> str:
|
|
178
|
+
name = self._username or "<default>"
|
|
179
|
+
return f"<WebhookClient username={name!r}>"
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"""
|
|
2
|
+
webhooklogger.embed
|
|
3
|
+
~~~~~~~~~~~~~~~~~~~
|
|
4
|
+
Chainable Embed builder for Discord webhooks.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Embed:
|
|
11
|
+
"""
|
|
12
|
+
Build a Discord embed with a clean, fluent interface.
|
|
13
|
+
|
|
14
|
+
Example::
|
|
15
|
+
|
|
16
|
+
embed = (
|
|
17
|
+
Embed()
|
|
18
|
+
.set_title("Hello!")
|
|
19
|
+
.set_description("This is a webhook embed.")
|
|
20
|
+
.set_color("#5865F2")
|
|
21
|
+
.add_field("Status", "Online", inline=True)
|
|
22
|
+
.set_footer("Sent by webhooklogger")
|
|
23
|
+
.set_timestamp()
|
|
24
|
+
)
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
# ------------------------------------------------------------------ #
|
|
28
|
+
# Preset colour themes #
|
|
29
|
+
# ------------------------------------------------------------------ #
|
|
30
|
+
THEMES = {
|
|
31
|
+
"default": 0x5865F2, # Discord blurple
|
|
32
|
+
"success": 0x57F287, # green
|
|
33
|
+
"warning": 0xFEE75C, # yellow
|
|
34
|
+
"error": 0xED4245, # red
|
|
35
|
+
"info": 0x5DADE2, # blue
|
|
36
|
+
"dark": 0x2C2F33, # dark grey
|
|
37
|
+
"light": 0xFFFFFF, # white
|
|
38
|
+
"purple": 0x9B59B6,
|
|
39
|
+
"orange": 0xE67E22,
|
|
40
|
+
"pink": 0xFF69B4,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
def __init__(self):
|
|
44
|
+
self._data = {}
|
|
45
|
+
|
|
46
|
+
# ------------------------------------------------------------------ #
|
|
47
|
+
# Core setters #
|
|
48
|
+
# ------------------------------------------------------------------ #
|
|
49
|
+
|
|
50
|
+
def set_title(self, title: str) -> "Embed":
|
|
51
|
+
"""Set the embed title (max 256 chars)."""
|
|
52
|
+
self._data["title"] = str(title)
|
|
53
|
+
return self
|
|
54
|
+
|
|
55
|
+
def set_description(self, description: str) -> "Embed":
|
|
56
|
+
"""Set the embed description / body text (max 4096 chars)."""
|
|
57
|
+
self._data["description"] = str(description)
|
|
58
|
+
return self
|
|
59
|
+
|
|
60
|
+
def set_url(self, url: str) -> "Embed":
|
|
61
|
+
"""Make the title a clickable hyperlink."""
|
|
62
|
+
self._data["url"] = str(url)
|
|
63
|
+
return self
|
|
64
|
+
|
|
65
|
+
# ------------------------------------------------------------------ #
|
|
66
|
+
# Colour / theme #
|
|
67
|
+
# ------------------------------------------------------------------ #
|
|
68
|
+
|
|
69
|
+
def set_color(self, color) -> "Embed":
|
|
70
|
+
"""
|
|
71
|
+
Set the left-border colour.
|
|
72
|
+
|
|
73
|
+
Accepts:
|
|
74
|
+
- Hex string → ``"#FF5733"`` or ``"FF5733"``
|
|
75
|
+
- Integer → ``16711680``
|
|
76
|
+
- Theme name → ``"success"``, ``"error"``, ``"warning"``, etc.
|
|
77
|
+
"""
|
|
78
|
+
if isinstance(color, str):
|
|
79
|
+
color = color.strip().lstrip("#")
|
|
80
|
+
if color.lower() in self.THEMES:
|
|
81
|
+
self._data["color"] = self.THEMES[color.lower()]
|
|
82
|
+
else:
|
|
83
|
+
self._data["color"] = int(color, 16)
|
|
84
|
+
elif isinstance(color, int):
|
|
85
|
+
self._data["color"] = color
|
|
86
|
+
else:
|
|
87
|
+
raise TypeError("color must be a hex string or int")
|
|
88
|
+
return self
|
|
89
|
+
|
|
90
|
+
# Alias for British English users
|
|
91
|
+
set_colour = set_color
|
|
92
|
+
|
|
93
|
+
def set_theme(self, theme: str) -> "Embed":
|
|
94
|
+
"""
|
|
95
|
+
Apply a named colour theme.
|
|
96
|
+
|
|
97
|
+
Available themes: ``default``, ``success``, ``warning``,
|
|
98
|
+
``error``, ``info``, ``dark``, ``light``, ``purple``,
|
|
99
|
+
``orange``, ``pink``.
|
|
100
|
+
"""
|
|
101
|
+
theme = theme.lower()
|
|
102
|
+
if theme not in self.THEMES:
|
|
103
|
+
raise ValueError(
|
|
104
|
+
f"Unknown theme '{theme}'. "
|
|
105
|
+
f"Available: {', '.join(self.THEMES)}"
|
|
106
|
+
)
|
|
107
|
+
self._data["color"] = self.THEMES[theme]
|
|
108
|
+
return self
|
|
109
|
+
|
|
110
|
+
# ------------------------------------------------------------------ #
|
|
111
|
+
# Author #
|
|
112
|
+
# ------------------------------------------------------------------ #
|
|
113
|
+
|
|
114
|
+
def set_author(
|
|
115
|
+
self,
|
|
116
|
+
name: str,
|
|
117
|
+
url: str = None,
|
|
118
|
+
icon_url: str = None,
|
|
119
|
+
) -> "Embed":
|
|
120
|
+
"""Set the author block shown above the title."""
|
|
121
|
+
author = {"name": str(name)}
|
|
122
|
+
if url:
|
|
123
|
+
author["url"] = url
|
|
124
|
+
if icon_url:
|
|
125
|
+
author["icon_url"] = icon_url
|
|
126
|
+
self._data["author"] = author
|
|
127
|
+
return self
|
|
128
|
+
|
|
129
|
+
# ------------------------------------------------------------------ #
|
|
130
|
+
# Images #
|
|
131
|
+
# ------------------------------------------------------------------ #
|
|
132
|
+
|
|
133
|
+
def set_thumbnail(self, url: str) -> "Embed":
|
|
134
|
+
"""Set the small thumbnail image (top-right corner)."""
|
|
135
|
+
self._data["thumbnail"] = {"url": str(url)}
|
|
136
|
+
return self
|
|
137
|
+
|
|
138
|
+
def set_image(self, url: str) -> "Embed":
|
|
139
|
+
"""Set the large image shown below the body."""
|
|
140
|
+
self._data["image"] = {"url": str(url)}
|
|
141
|
+
return self
|
|
142
|
+
|
|
143
|
+
# ------------------------------------------------------------------ #
|
|
144
|
+
# Footer #
|
|
145
|
+
# ------------------------------------------------------------------ #
|
|
146
|
+
|
|
147
|
+
def set_footer(self, text: str, icon_url: str = None) -> "Embed":
|
|
148
|
+
"""Set the footer text and optional icon."""
|
|
149
|
+
footer = {"text": str(text)}
|
|
150
|
+
if icon_url:
|
|
151
|
+
footer["icon_url"] = icon_url
|
|
152
|
+
self._data["footer"] = footer
|
|
153
|
+
return self
|
|
154
|
+
|
|
155
|
+
# ------------------------------------------------------------------ #
|
|
156
|
+
# Timestamp #
|
|
157
|
+
# ------------------------------------------------------------------ #
|
|
158
|
+
|
|
159
|
+
def set_timestamp(self, dt: datetime = None) -> "Embed":
|
|
160
|
+
"""
|
|
161
|
+
Add a timestamp to the footer.
|
|
162
|
+
|
|
163
|
+
Pass a :class:`datetime` object, or leave blank to use **now** (UTC).
|
|
164
|
+
"""
|
|
165
|
+
if dt is None:
|
|
166
|
+
dt = datetime.now(tz=timezone.utc)
|
|
167
|
+
self._data["timestamp"] = dt.isoformat()
|
|
168
|
+
return self
|
|
169
|
+
|
|
170
|
+
# ------------------------------------------------------------------ #
|
|
171
|
+
# Fields #
|
|
172
|
+
# ------------------------------------------------------------------ #
|
|
173
|
+
|
|
174
|
+
def add_field(
|
|
175
|
+
self,
|
|
176
|
+
name: str,
|
|
177
|
+
value: str,
|
|
178
|
+
inline: bool = False,
|
|
179
|
+
) -> "Embed":
|
|
180
|
+
"""
|
|
181
|
+
Add an inline or block field (up to 25 fields per embed).
|
|
182
|
+
|
|
183
|
+
:param name: Field title.
|
|
184
|
+
:param value: Field body text.
|
|
185
|
+
:param inline: If ``True``, fields sit side-by-side (up to 3 per row).
|
|
186
|
+
"""
|
|
187
|
+
fields = self._data.setdefault("fields", [])
|
|
188
|
+
if len(fields) >= 25:
|
|
189
|
+
raise ValueError("Discord embeds support a maximum of 25 fields")
|
|
190
|
+
fields.append({"name": str(name), "value": str(value), "inline": inline})
|
|
191
|
+
return self
|
|
192
|
+
|
|
193
|
+
def clear_fields(self) -> "Embed":
|
|
194
|
+
"""Remove all previously added fields."""
|
|
195
|
+
self._data.pop("fields", None)
|
|
196
|
+
return self
|
|
197
|
+
|
|
198
|
+
# ------------------------------------------------------------------ #
|
|
199
|
+
# Build #
|
|
200
|
+
# ------------------------------------------------------------------ #
|
|
201
|
+
|
|
202
|
+
def build(self) -> dict:
|
|
203
|
+
"""Return the raw embed dictionary ready for the Discord API."""
|
|
204
|
+
return dict(self._data)
|
|
205
|
+
|
|
206
|
+
def __repr__(self) -> str:
|
|
207
|
+
title = self._data.get("title", "<no title>")
|
|
208
|
+
fields = len(self._data.get("fields", []))
|
|
209
|
+
return f"<Embed title={title!r} fields={fields}>"
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: webhookloggerx
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: A clean, user-friendly Python package for sending Discord webhook messages and rich embeds.
|
|
5
|
+
Author: Nur Mohammad Rafi
|
|
6
|
+
Author-email:
|
|
7
|
+
Keywords: discord webhook embed notification bot
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
13
|
+
Classifier: Topic :: Communications
|
|
14
|
+
Requires-Python: >=3.7
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: requests>=2.20.0
|
|
17
|
+
Dynamic: author
|
|
18
|
+
Dynamic: classifier
|
|
19
|
+
Dynamic: description
|
|
20
|
+
Dynamic: description-content-type
|
|
21
|
+
Dynamic: keywords
|
|
22
|
+
Dynamic: requires-dist
|
|
23
|
+
Dynamic: requires-python
|
|
24
|
+
Dynamic: summary
|
|
25
|
+
|
|
26
|
+
# webhooklogger-python-rafi
|
|
27
|
+
|
|
28
|
+
A clean, user-friendly Python package for sending Discord webhook messages and rich embeds.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install webhookloggerx
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from webhooklogger import WebhookClient, Embed
|
|
40
|
+
|
|
41
|
+
client = WebhookClient("https://discord.com/api/webhooks/YOUR_ID/YOUR_TOKEN")
|
|
42
|
+
client.send("Hello from webhooklogger!")
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- ✅ Send plain text messages
|
|
50
|
+
- ✅ Send rich Discord embeds
|
|
51
|
+
- ✅ Send multiple embeds in one request
|
|
52
|
+
- ✅ Customise webhook display name & avatar
|
|
53
|
+
- ✅ Embed builder with fluent (chainable) API
|
|
54
|
+
- ✅ Built-in colour themes (`success`, `error`, `warning`, etc.)
|
|
55
|
+
- ✅ Set embed title, description, author, footer, images, timestamp, fields
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## WebhookClient
|
|
60
|
+
|
|
61
|
+
### Create a Client
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from webhooklogger import WebhookClient
|
|
65
|
+
|
|
66
|
+
client = WebhookClient("https://discord.com/api/webhooks/...")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Set Webhook Profile (name & avatar)
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
client.set_profile(
|
|
73
|
+
username="MyBot",
|
|
74
|
+
avatar_url="https://example.com/avatar.png"
|
|
75
|
+
)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Send a Plain Text Message
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
client.send("This is a plain message.")
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Send an Embed
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from webhooklogger import Embed
|
|
88
|
+
|
|
89
|
+
embed = Embed().set_title("Hello!").set_description("Embed body here.")
|
|
90
|
+
client.send_embed(embed)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Send Multiple Embeds
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
embed1 = Embed().set_title("First").set_theme("success")
|
|
97
|
+
embed2 = Embed().set_title("Second").set_theme("error")
|
|
98
|
+
client.send_embeds([embed1, embed2])
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Send Text + Embed Together
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
embed = Embed().set_title("Alert").set_description("Check this out!")
|
|
105
|
+
client.send_message(content="Hey team!", embed=embed)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Embed Builder
|
|
111
|
+
|
|
112
|
+
All methods return `self`, so you can **chain** them fluently.
|
|
113
|
+
|
|
114
|
+
### Title & Description
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
embed = (
|
|
118
|
+
Embed()
|
|
119
|
+
.set_title("My Title")
|
|
120
|
+
.set_description("This is the body of the embed.")
|
|
121
|
+
.set_url("https://example.com") # makes title clickable
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Colour
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
# Hex string
|
|
129
|
+
embed.set_color("#FF5733")
|
|
130
|
+
|
|
131
|
+
# Integer
|
|
132
|
+
embed.set_color(16711680)
|
|
133
|
+
|
|
134
|
+
# Named theme
|
|
135
|
+
embed.set_theme("success")
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Available themes:**
|
|
139
|
+
|
|
140
|
+
| Theme | Colour |
|
|
141
|
+
|---|---|
|
|
142
|
+
| `default` | Discord Blurple |
|
|
143
|
+
| `success` | Green |
|
|
144
|
+
| `warning` | Yellow |
|
|
145
|
+
| `error` | Red |
|
|
146
|
+
| `info` | Blue |
|
|
147
|
+
| `dark` | Dark Grey |
|
|
148
|
+
| `light` | White |
|
|
149
|
+
| `purple` | Purple |
|
|
150
|
+
| `orange` | Orange |
|
|
151
|
+
| `pink` | Pink |
|
|
152
|
+
|
|
153
|
+
### Author
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
embed.set_author(
|
|
157
|
+
name="Nur Mohammad Rafi",
|
|
158
|
+
url="https://github.com/yourusername",
|
|
159
|
+
icon_url="https://example.com/icon.png"
|
|
160
|
+
)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Thumbnail & Image
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
embed.set_thumbnail("https://example.com/thumb.png") # top-right corner
|
|
167
|
+
embed.set_image("https://example.com/big-image.png") # large bottom image
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Fields
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
embed.add_field("Status", "Online", inline=True)
|
|
174
|
+
embed.add_field("Server", "Production", inline=True)
|
|
175
|
+
embed.add_field("Message", "All systems go.", inline=False)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
- `inline=True` — fields sit side by side (up to 3 per row)
|
|
179
|
+
- `inline=False` — field takes the full width
|
|
180
|
+
- Max **25 fields** per embed
|
|
181
|
+
|
|
182
|
+
### Footer
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
embed.set_footer("webhooklogger v1.0", icon_url="https://example.com/icon.png")
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Timestamp
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
embed.set_timestamp() # use current UTC time
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
from datetime import datetime, timezone
|
|
196
|
+
embed.set_timestamp(datetime(2025, 1, 1, tzinfo=timezone.utc)) # custom time
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Full Example
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
from webhooklogger import WebhookClient, Embed
|
|
205
|
+
|
|
206
|
+
# Create and configure client
|
|
207
|
+
client = WebhookClient("https://discord.com/api/webhooks/...")
|
|
208
|
+
client.set_profile(username="AlertBot", avatar_url="https://example.com/bot.png")
|
|
209
|
+
|
|
210
|
+
# Build embed
|
|
211
|
+
embed = (
|
|
212
|
+
Embed()
|
|
213
|
+
.set_title("🚨 System Alert")
|
|
214
|
+
.set_description("A critical event has been detected on the server.")
|
|
215
|
+
.set_theme("error")
|
|
216
|
+
.set_author("Monitor System", icon_url="https://example.com/icon.png")
|
|
217
|
+
.set_thumbnail("https://example.com/thumb.png")
|
|
218
|
+
.add_field("Host", "prod-server-01", inline=True)
|
|
219
|
+
.add_field("Status", "❌ Down", inline=True)
|
|
220
|
+
.add_field("Region", "US-East", inline=True)
|
|
221
|
+
.add_field("Details", "Connection timeout after 30s", inline=False)
|
|
222
|
+
.set_image("https://example.com/graph.png")
|
|
223
|
+
.set_footer("webhooklogger • Auto-alert system")
|
|
224
|
+
.set_timestamp()
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# Send it
|
|
228
|
+
client.send_embed(embed)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Error Handling
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
from webhooklogger import WebhookClient, WebhookError
|
|
237
|
+
|
|
238
|
+
client = WebhookClient("https://discord.com/api/webhooks/...")
|
|
239
|
+
|
|
240
|
+
try:
|
|
241
|
+
client.send("Test message")
|
|
242
|
+
except WebhookError as e:
|
|
243
|
+
print(f"Failed: HTTP {e.status_code} — {e.message}")
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## API Reference
|
|
249
|
+
|
|
250
|
+
### `WebhookClient`
|
|
251
|
+
|
|
252
|
+
| Method | Description |
|
|
253
|
+
|---|---|
|
|
254
|
+
| `__init__(url)` | Create client with webhook URL |
|
|
255
|
+
| `set_profile(username, avatar_url)` | Override display name & avatar |
|
|
256
|
+
| `send(content)` | Send plain text message |
|
|
257
|
+
| `send_embed(embed)` | Send a single Embed |
|
|
258
|
+
| `send_embeds(embeds)` | Send a list of Embeds (max 10) |
|
|
259
|
+
| `send_message(content, embed)` | Send text + embed together |
|
|
260
|
+
|
|
261
|
+
### `Embed`
|
|
262
|
+
|
|
263
|
+
| Method | Description |
|
|
264
|
+
|---|---|
|
|
265
|
+
| `set_title(title)` | Embed title |
|
|
266
|
+
| `set_description(text)` | Embed body text |
|
|
267
|
+
| `set_url(url)` | Make title a hyperlink |
|
|
268
|
+
| `set_color(color)` | Hex string or int |
|
|
269
|
+
| `set_colour(color)` | Alias for `set_color` |
|
|
270
|
+
| `set_theme(theme)` | Named colour theme |
|
|
271
|
+
| `set_author(name, url, icon_url)` | Author block |
|
|
272
|
+
| `set_thumbnail(url)` | Small top-right image |
|
|
273
|
+
| `set_image(url)` | Large bottom image |
|
|
274
|
+
| `set_footer(text, icon_url)` | Footer text & icon |
|
|
275
|
+
| `set_timestamp(dt)` | Timestamp (default: now) |
|
|
276
|
+
| `add_field(name, value, inline)` | Add a field |
|
|
277
|
+
| `clear_fields()` | Remove all fields |
|
|
278
|
+
| `build()` | Return raw dict for API |
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## License
|
|
283
|
+
|
|
284
|
+
MIT © Nur Mohammad Rafi
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
webhooklogger/__init__.py
|
|
4
|
+
webhooklogger/client.py
|
|
5
|
+
webhooklogger/embed.py
|
|
6
|
+
webhooklogger/main.py
|
|
7
|
+
webhookloggerx.egg-info/PKG-INFO
|
|
8
|
+
webhookloggerx.egg-info/SOURCES.txt
|
|
9
|
+
webhookloggerx.egg-info/dependency_links.txt
|
|
10
|
+
webhookloggerx.egg-info/requires.txt
|
|
11
|
+
webhookloggerx.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests>=2.20.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
webhooklogger
|