0
# Wavelink
1
2
A robust and powerful, fully asynchronous Lavalink wrapper built for discord.py in Python. Wavelink enables Discord bot developers to integrate advanced audio playback capabilities through a comprehensive, object-oriented API that supports Lavalink v4+ servers, advanced AutoPlay functionality, full type annotation compliance, and seamless integration with Discord.py's voice system.
3
4
## Package Information
5
6
- **Package Name**: wavelink
7
- **Language**: Python
8
- **Installation**: `pip install wavelink`
9
- **Version**: 3.4.1
10
- **License**: MIT
11
- **Documentation**: https://wavelink.dev/en/latest
12
13
## Core Imports
14
15
```python
16
import wavelink
17
```
18
19
Common imports for typical use cases:
20
21
```python
22
from wavelink import Pool, Node, Player, Playable, Playlist, Queue
23
from wavelink import Filters, AutoPlayMode, QueueMode, TrackSource
24
```
25
26
## Basic Usage
27
28
```python
29
import discord
30
from discord.ext import commands
31
import wavelink
32
33
class Bot(commands.Bot):
34
def __init__(self):
35
super().__init__(command_prefix='!', intents=discord.Intents.all())
36
37
async def on_ready(self):
38
print(f'{self.user} is ready!')
39
40
# Connect to Lavalink node
41
await wavelink.Pool.connect(
42
uri="http://localhost:2333",
43
password="youshallnotpass",
44
client=self
45
)
46
47
async def on_wavelink_track_end(self, payload):
48
# Handle track end events
49
player = payload.player
50
if not player.queue.is_empty:
51
await player.play(player.queue.get())
52
53
bot = Bot()
54
55
@bot.command()
56
async def play(ctx, *, query: str):
57
"""Play a song from YouTube, SoundCloud, etc."""
58
if not ctx.voice_client:
59
player = await ctx.author.voice.channel.connect(cls=wavelink.Player)
60
else:
61
player = ctx.voice_client
62
63
# Search for tracks
64
tracks = await wavelink.Pool.fetch_tracks(query)
65
if not tracks:
66
return await ctx.send("No tracks found!")
67
68
if isinstance(tracks, wavelink.Playlist):
69
# Add entire playlist
70
player.queue.put(tracks)
71
await ctx.send(f"Added playlist: {tracks.name}")
72
else:
73
# Add single track
74
track = tracks[0]
75
player.queue.put(track)
76
await ctx.send(f"Added: {track.title}")
77
78
# Start playing if nothing is currently playing
79
if not player.playing:
80
await player.play(player.queue.get())
81
82
@bot.command()
83
async def skip(ctx):
84
"""Skip the current track."""
85
player = ctx.voice_client
86
if player:
87
await player.skip()
88
await ctx.send("Skipped!")
89
90
bot.run('YOUR_BOT_TOKEN')
91
```
92
93
## Architecture
94
95
Wavelink follows a hierarchical architecture that provides comprehensive control over audio playback:
96
97
- **Pool**: Global node manager that handles connections to multiple Lavalink servers, load balancing, and track searching
98
- **Node**: Individual Lavalink server connection with REST API access, WebSocket communication, and player management
99
- **Player**: Discord voice client extension providing playback control, queue management, filters, and event handling
100
- **Queue**: Thread-safe track queue with multiple modes (normal, loop, loop_all), history tracking, and AutoPlay support
101
- **Tracks**: Rich track and playlist objects with metadata, source information, and search capabilities
102
103
This design enables seamless integration with discord.py while providing advanced features like AutoPlay recommendations, comprehensive audio filtering, and robust event handling for sophisticated music bot development.
104
105
## Capabilities
106
107
### Node Management
108
109
Connection and management of Lavalink servers including pool management, node discovery, health monitoring, and load balancing across multiple nodes.
110
111
```python { .api }
112
class Pool:
113
@classmethod
114
async def connect(
115
cls,
116
uri: str,
117
password: str,
118
*,
119
identifier: str | None = None,
120
client: discord.Client,
121
**kwargs
122
) -> Node: ...
123
124
@classmethod
125
def get_node(cls, identifier: str | None = None) -> Node: ...
126
127
@classmethod
128
async def fetch_tracks(
129
cls,
130
query: str,
131
*,
132
node: Node | None = None
133
) -> list[Playable] | Playlist: ...
134
135
class Node:
136
@property
137
def status(self) -> NodeStatus: ...
138
139
@property
140
def players(self) -> dict[int, Player]: ...
141
142
async def fetch_stats(self) -> StatsResponsePayload: ...
143
```
144
145
[Node Management](./node-management.md)
146
147
### Player Control
148
149
Main audio player interface providing playback control, volume management, seeking, and voice channel operations with full discord.py VoiceProtocol integration.
150
151
```python { .api }
152
class Player(discord.VoiceProtocol):
153
queue: Queue
154
auto_queue: Queue
155
156
@property
157
def current(self) -> Playable | None: ...
158
159
@property
160
def playing(self) -> bool: ...
161
162
@property
163
def paused(self) -> bool: ...
164
165
async def play(
166
self,
167
track: Playable,
168
*,
169
replace: bool = True,
170
start: int = 0,
171
end: int | None = None,
172
volume: int | None = None,
173
paused: bool | None = None,
174
add_history: bool = True
175
) -> None: ...
176
177
async def pause(self, value: bool) -> None: ...
178
179
async def seek(self, position: int = 0) -> None: ...
180
181
async def skip(self, *, force: bool = True) -> Playable | None: ...
182
```
183
184
[Player Control](./player-control.md)
185
186
### Track Search & Management
187
188
Comprehensive track searching across multiple platforms (YouTube, SoundCloud, YouTube Music) with rich metadata, playlist support, and advanced search capabilities.
189
190
```python { .api }
191
class Playable:
192
title: str
193
author: str
194
length: int
195
uri: str
196
source: TrackSource
197
198
@classmethod
199
async def search(
200
cls,
201
query: str,
202
*,
203
source: TrackSource | None = None,
204
node: Node | None = None
205
) -> list[Playable]: ...
206
207
class Playlist:
208
name: str
209
tracks: list[Playable]
210
211
def pop(self, index: int = -1) -> Playable: ...
212
213
# Search result type
214
Search = list[Playable] | Playlist
215
```
216
217
[Track Search & Management](./track-search.md)
218
219
### Queue System
220
221
Advanced queue management with multiple modes, history tracking, AutoPlay functionality, and thread-safe operations for robust track management.
222
223
```python { .api }
224
class Queue:
225
mode: QueueMode
226
history: Queue | None
227
228
@property
229
def is_empty(self) -> bool: ...
230
231
@property
232
def count(self) -> int: ...
233
234
def put(
235
self,
236
item: list[Playable] | Playable | Playlist,
237
*,
238
atomic: bool = True
239
) -> int: ...
240
241
def get() -> Playable: ...
242
243
async def get_wait() -> Playable: ...
244
245
def shuffle(self) -> None: ...
246
247
def clear(self) -> None: ...
248
249
# Queue modes
250
class QueueMode(enum.Enum):
251
normal = 0
252
loop = 1
253
loop_all = 2
254
255
# AutoPlay modes
256
class AutoPlayMode(enum.Enum):
257
enabled = 0
258
partial = 1
259
disabled = 2
260
```
261
262
[Queue System](./queue-system.md)
263
264
### Audio Filters
265
266
Comprehensive audio filter system including equalizer, distortion, karaoke, timescale, and plugin filters for advanced audio processing and effects.
267
268
```python { .api }
269
class Filters:
270
volume: float | None
271
equalizer: Equalizer
272
karaoke: Karaoke
273
timescale: Timescale
274
tremolo: Tremolo
275
vibrato: Vibrato
276
rotation: Rotation
277
distortion: Distortion
278
channel_mix: ChannelMix
279
low_pass: LowPass
280
plugin_filters: PluginFilters
281
282
def set_filters(self, **filters) -> None: ...
283
284
def reset(self) -> None: ...
285
286
@classmethod
287
def from_filters(cls, **filters) -> Self: ...
288
289
class Equalizer:
290
def set(self, *, bands: list[dict] | None = None) -> Self: ...
291
292
def reset(self) -> Self: ...
293
294
@property
295
def payload(self) -> dict[int, dict]: ...
296
```
297
298
[Audio Filters](./audio-filters.md)
299
300
### Events & Exceptions
301
302
Rich event system for track lifecycle, player state changes, and WebSocket events, plus comprehensive exception hierarchy for robust error handling.
303
304
```python { .api }
305
# Exception hierarchy
306
class WavelinkException(Exception): ...
307
308
class NodeException(WavelinkException):
309
status: int | None
310
311
class LavalinkException(WavelinkException):
312
timestamp: int
313
status: int
314
error: str
315
trace: str | None
316
path: str
317
318
class QueueEmpty(WavelinkException): ...
319
320
# Event payloads (data structures for event handlers)
321
class TrackStartEventPayload: ...
322
class TrackEndEventPayload: ...
323
class PlayerUpdateEventPayload: ...
324
```
325
326
[Events & Exceptions](./events-exceptions.md)
327
328
## Types
329
330
Core type definitions used across the wavelink API.
331
332
```python { .api }
333
# Enums
334
class NodeStatus(enum.Enum):
335
DISCONNECTED = 0
336
CONNECTING = 1
337
CONNECTED = 2
338
339
class TrackSource(enum.Enum):
340
YouTube = 0
341
YouTubeMusic = 1
342
SoundCloud = 2
343
344
class DiscordVoiceCloseType(enum.Enum):
345
"""Discord Voice WebSocket close codes."""
346
CLOSE_NORMAL = 1000
347
UNKNOWN_OPCODE = 4001
348
FAILED_DECODE_PAYLOAD = 4002
349
NOT_AUTHENTICATED = 4003
350
AUTHENTICATION_FAILED = 4004
351
ALREADY_AUTHENTICATED = 4005
352
SESSION_INVALID = 4006
353
SESSION_TIMEOUT = 4009
354
SERVER_NOT_FOUND = 4011
355
UNKNOWN_PROTOCOL = 4012
356
DISCONNECTED = 4014
357
VOICE_SERVER_CRASHED = 4015
358
UNKNOWN_ENCRYPTION_MODE = 4016
359
360
# Namespace for extras and metadata
361
class ExtrasNamespace:
362
"""
363
A namespace for additional track metadata and custom attributes.
364
365
Supports construction with dict of str keys and Any values,
366
keyword pairs, or a mix of both. Can access dict version
367
by calling dict() on instance.
368
"""
369
def __init__(self, __dict: dict[str, Any] = {}, /, **kwargs: Any) -> None: ...
370
371
# Cache implementation for internal use
372
class LFUCache:
373
"""
374
Least Frequently Used cache implementation used internally
375
by Pool for track caching.
376
"""
377
def __init__(self, *, capacity: int) -> None: ...
378
379
@property
380
def capacity(self) -> int: ...
381
382
def get(self, key: Any, default: Any = ...) -> Any: ...
383
384
def put(self, key: Any, value: Any) -> None: ...
385
```