ryanlink 1.0.1
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.
- package/LICENSE +37 -0
- package/README.md +455 -0
- package/dist/index.d.mts +1335 -0
- package/dist/index.d.ts +1335 -0
- package/dist/index.js +4694 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +4604 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +82 -0
- package/src/audio/AudioFilters.ts +316 -0
- package/src/audio/AudioQueue.ts +782 -0
- package/src/audio/AudioTrack.ts +242 -0
- package/src/audio/QueueController.ts +252 -0
- package/src/audio/TrackCollection.ts +138 -0
- package/src/audio/index.ts +9 -0
- package/src/config/defaults.ts +223 -0
- package/src/config/endpoints.ts +99 -0
- package/src/config/index.ts +9 -0
- package/src/config/patterns.ts +55 -0
- package/src/config/presets.ts +400 -0
- package/src/config/symbols.ts +31 -0
- package/src/core/PluginSystem.ts +50 -0
- package/src/core/RyanlinkPlayer.ts +403 -0
- package/src/core/index.ts +6 -0
- package/src/extensions/AutoplayExtension.ts +283 -0
- package/src/extensions/FairPlayExtension.ts +154 -0
- package/src/extensions/LyricsExtension.ts +187 -0
- package/src/extensions/PersistenceExtension.ts +182 -0
- package/src/extensions/SponsorBlockExtension.ts +81 -0
- package/src/extensions/index.ts +9 -0
- package/src/index.ts +19 -0
- package/src/lavalink/ConnectionPool.ts +326 -0
- package/src/lavalink/HttpClient.ts +316 -0
- package/src/lavalink/LavalinkConnection.ts +409 -0
- package/src/lavalink/index.ts +7 -0
- package/src/metadata.ts +88 -0
- package/src/types/api/Rest.ts +949 -0
- package/src/types/api/Websocket.ts +463 -0
- package/src/types/api/index.ts +6 -0
- package/src/types/audio/FilterManager.ts +29 -0
- package/src/types/audio/Queue.ts +4 -0
- package/src/types/audio/QueueManager.ts +30 -0
- package/src/types/audio/index.ts +7 -0
- package/src/types/common.ts +63 -0
- package/src/types/core/Player.ts +322 -0
- package/src/types/core/index.ts +5 -0
- package/src/types/index.ts +6 -0
- package/src/types/lavalink/Node.ts +173 -0
- package/src/types/lavalink/NodeManager.ts +34 -0
- package/src/types/lavalink/REST.ts +144 -0
- package/src/types/lavalink/index.ts +32 -0
- package/src/types/voice/VoiceManager.ts +176 -0
- package/src/types/voice/index.ts +5 -0
- package/src/utils/helpers.ts +169 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/validators.ts +184 -0
- package/src/voice/RegionSelector.ts +184 -0
- package/src/voice/VoiceConnection.ts +451 -0
- package/src/voice/VoiceSession.ts +297 -0
- package/src/voice/index.ts +7 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
2. Grant of Copyright License.
|
|
10
|
+
|
|
11
|
+
3. Grant of Patent License.
|
|
12
|
+
|
|
13
|
+
4. Redistribution.
|
|
14
|
+
|
|
15
|
+
5. Submission of Contributions.
|
|
16
|
+
|
|
17
|
+
6. Trademarks.
|
|
18
|
+
|
|
19
|
+
7. Disclaimer of Warranty.
|
|
20
|
+
|
|
21
|
+
8. Limitation of Liability.
|
|
22
|
+
|
|
23
|
+
9. Accepting Warranty or Additional Liability.
|
|
24
|
+
|
|
25
|
+
Copyright 2026 RY4N
|
|
26
|
+
|
|
27
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
28
|
+
you may not use this file except in compliance with the License.
|
|
29
|
+
You may obtain a copy of the License at
|
|
30
|
+
|
|
31
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
32
|
+
|
|
33
|
+
Unless required by applicable law or agreed to in writing, software
|
|
34
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
35
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
36
|
+
See the License for the specific language governing permissions and
|
|
37
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img alt="Ryanlink" src="assets/ryanlink.jpeg" width="120" />
|
|
3
|
+
|
|
4
|
+
# Ryanlink
|
|
5
|
+
|
|
6
|
+
A modern, feature-rich Lavalink client for Node.js with TypeScript support
|
|
7
|
+
|
|
8
|
+
<br/>
|
|
9
|
+
|
|
10
|
+
[](https://www.npmjs.com/package/ryanlink)
|
|
11
|
+
[](LICENSE)
|
|
12
|
+
[](https://nodejs.org)
|
|
13
|
+
[](https://www.typescriptlang.org/)
|
|
14
|
+
[](https://github.com/ryanwtf7/ryanlink/actions)
|
|
15
|
+
|
|
16
|
+
[Documentation](https://ryanwtf7.github.io/ryanlink) • [NPM Package](https://www.npmjs.com/package/ryanlink) • [GitHub](https://github.com/ryanwtf7/ryanlink)
|
|
17
|
+
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Overview
|
|
23
|
+
|
|
24
|
+
Ryanlink is a powerful Lavalink client library designed to simplify music bot development for Discord. Built with modern TypeScript and featuring a unique architecture, it provides an intuitive interface for managing audio playback, queues, and advanced audio processing.
|
|
25
|
+
|
|
26
|
+
### Key Features
|
|
27
|
+
|
|
28
|
+
- **Modern Lavalink v4 Support** - Full compatibility with the latest Lavalink API
|
|
29
|
+
- **Cross-Runtime Compatibility** - Works seamlessly with Node.js, Bun, and Deno
|
|
30
|
+
- **Professional Audio Processing** - 17 built-in EQ presets for instant audio enhancement
|
|
31
|
+
- **Advanced Queue Management** - Sort, filter, search, and manipulate tracks with ease
|
|
32
|
+
- **Powerful Extensions System** - Autoplay, Lyrics, SponsorBlock, FairPlay, and Persistence
|
|
33
|
+
- **Type-Safe** - Complete TypeScript definitions with full IntelliSense support
|
|
34
|
+
- **Production Ready** - Comprehensive error handling, automatic reconnection, and session management
|
|
35
|
+
- **Flexible Architecture** - Feature-based organization for better maintainability
|
|
36
|
+
|
|
37
|
+
### Supported Platforms
|
|
38
|
+
|
|
39
|
+
Ryanlink supports audio from 20+ streaming platforms through LavaSrc integration:
|
|
40
|
+
|
|
41
|
+
<div align="center">
|
|
42
|
+
|
|
43
|
+
| Platform | Support | Platform | Support | Platform | Support |
|
|
44
|
+
| ------------ | ------- | --------- | ------- | ------------ | ------- |
|
|
45
|
+
| YouTube | ✓ | Spotify | ✓ | Apple Music | ✓ |
|
|
46
|
+
| SoundCloud | ✓ | Deezer | ✓ | Tidal | ✓ |
|
|
47
|
+
| Bandcamp | ✓ | Twitch | ✓ | Amazon Music | ✓ |
|
|
48
|
+
| Yandex Music | ✓ | JioSaavn | ✓ | Pandora | ✓ |
|
|
49
|
+
| Qobuz | ✓ | Audiomack | ✓ | Mixcloud | ✓ |
|
|
50
|
+
| Anghami | ✓ | Audius | ✓ | Gaana | ✓ |
|
|
51
|
+
| Instagram | ✓ | Shazam | ✓ | Direct URLs | ✓ |
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# npm
|
|
59
|
+
npm install ryanlink
|
|
60
|
+
|
|
61
|
+
# yarn
|
|
62
|
+
yarn add ryanlink
|
|
63
|
+
|
|
64
|
+
# pnpm
|
|
65
|
+
pnpm add ryanlink
|
|
66
|
+
|
|
67
|
+
# bun
|
|
68
|
+
bun add ryanlink
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Deno
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { RyanlinkPlayer } from "npm:ryanlink@latest";
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Quick Start
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { Client } from "discord.js";
|
|
81
|
+
import { RyanlinkPlayer } from "ryanlink";
|
|
82
|
+
|
|
83
|
+
const client = new Client({ intents: ["Guilds", "GuildVoiceStates"] });
|
|
84
|
+
|
|
85
|
+
const player = new RyanlinkPlayer({
|
|
86
|
+
nodes: [
|
|
87
|
+
{
|
|
88
|
+
name: "main",
|
|
89
|
+
host: "localhost",
|
|
90
|
+
port: 2333,
|
|
91
|
+
password: "youshallnotpass",
|
|
92
|
+
secure: false,
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
forwardVoiceUpdate: async (guildId, payload) => {
|
|
96
|
+
const guild = client.guilds.cache.get(guildId);
|
|
97
|
+
if (guild) guild.shard.send(payload);
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
client.on("ready", async () => {
|
|
102
|
+
await player.init(client.user.id);
|
|
103
|
+
console.log(`${client.user.tag} is ready!`);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
client.on("raw", (packet) => {
|
|
107
|
+
player.voices.handleDispatch(packet);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
client.login("YOUR_BOT_TOKEN");
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Core Concepts
|
|
114
|
+
|
|
115
|
+
### Playing Music
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// Play from URL or search query
|
|
119
|
+
const queue = await player.play("Never Gonna Give You Up", {
|
|
120
|
+
guildId: interaction.guildId,
|
|
121
|
+
voiceId: interaction.member.voice.channelId,
|
|
122
|
+
textId: interaction.channelId,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Play from direct URL
|
|
126
|
+
await player.play("https://open.spotify.com/track/...", {
|
|
127
|
+
guildId: interaction.guildId,
|
|
128
|
+
voiceId: interaction.member.voice.channelId,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Search with specific source
|
|
132
|
+
const results = await player.search("ytsearch:Rick Astley");
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Queue Management
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
const queue = player.getQueue(guildId);
|
|
139
|
+
|
|
140
|
+
// Basic controls
|
|
141
|
+
await queue.pause();
|
|
142
|
+
await queue.resume();
|
|
143
|
+
await queue.stop();
|
|
144
|
+
await queue.skip();
|
|
145
|
+
await queue.previous();
|
|
146
|
+
|
|
147
|
+
// Volume control
|
|
148
|
+
await queue.setVolume(0.5); // 50%
|
|
149
|
+
|
|
150
|
+
// Repeat modes
|
|
151
|
+
await queue.setRepeatMode("track"); // Repeat current track
|
|
152
|
+
await queue.setRepeatMode("queue"); // Repeat entire queue
|
|
153
|
+
await queue.setRepeatMode("off"); // No repeat
|
|
154
|
+
|
|
155
|
+
// Shuffle
|
|
156
|
+
await queue.shuffle();
|
|
157
|
+
await queue.shuffle(true); // Include previous tracks
|
|
158
|
+
|
|
159
|
+
// Seek
|
|
160
|
+
await queue.seek(60000); // Seek to 1 minute
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Advanced Queue Operations
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// Sort tracks
|
|
167
|
+
await queue.sortBy("duration", "desc");
|
|
168
|
+
await queue.sortBy("title", "asc");
|
|
169
|
+
await queue.sortBy((a, b) => a.duration - b.duration);
|
|
170
|
+
|
|
171
|
+
// Filter tracks
|
|
172
|
+
const longTracks = queue.filterTracks({
|
|
173
|
+
duration: { min: 180000 }, // 3+ minutes
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const rockTracks = queue.filterTracks({
|
|
177
|
+
title: "rock",
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Find specific track
|
|
181
|
+
const track = queue.findTrack({ title: "Never Gonna" });
|
|
182
|
+
|
|
183
|
+
// Move tracks
|
|
184
|
+
await queue.move(5, 0); // Move track at index 5 to front
|
|
185
|
+
|
|
186
|
+
// Remove tracks
|
|
187
|
+
await queue.remove(3); // Remove track at index 3
|
|
188
|
+
|
|
189
|
+
// Get track range
|
|
190
|
+
const nextTen = queue.getTracks(0, 10);
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Audio Filters
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// Apply EQ preset
|
|
197
|
+
await queue.filters.setEQPreset("BassboostHigh");
|
|
198
|
+
await queue.filters.setEQPreset("Rock");
|
|
199
|
+
await queue.filters.setEQPreset("Nightcore");
|
|
200
|
+
|
|
201
|
+
// Get available presets
|
|
202
|
+
const presets = queue.filters.getEQPresetNames();
|
|
203
|
+
// ["BassboostEarrape", "BassboostHigh", "BassboostMedium", "BassboostLow",
|
|
204
|
+
// "Rock", "Classic", "Pop", "Electronic", "Gaming", "Nightcore",
|
|
205
|
+
// "Vaporwave", "TrebleBass", "HighQuality", "BetterMusic", "FullSound",
|
|
206
|
+
// "Soft", "TV", "Radio", "Normalization"]
|
|
207
|
+
|
|
208
|
+
// Custom filters
|
|
209
|
+
await queue.filters.apply({
|
|
210
|
+
equalizer: [
|
|
211
|
+
{ band: 0, gain: 0.2 },
|
|
212
|
+
{ band: 1, gain: 0.15 },
|
|
213
|
+
],
|
|
214
|
+
timescale: { speed: 1.5, pitch: 1.2 },
|
|
215
|
+
volume: 1.0,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Individual filter control
|
|
219
|
+
await queue.filters.set("timescale", { speed: 1.5 });
|
|
220
|
+
await queue.filters.delete("timescale");
|
|
221
|
+
await queue.filters.clear();
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Extensions
|
|
225
|
+
|
|
226
|
+
### Autoplay Extension
|
|
227
|
+
|
|
228
|
+
Automatically plays related tracks when the queue ends.
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
import { AutoplayExtension } from "ryanlink";
|
|
232
|
+
|
|
233
|
+
const player = new RyanlinkPlayer({
|
|
234
|
+
plugins: [
|
|
235
|
+
new AutoplayExtension({
|
|
236
|
+
enabled: true,
|
|
237
|
+
maxHistory: 50,
|
|
238
|
+
sources: {
|
|
239
|
+
spotify: true,
|
|
240
|
+
youtube: true,
|
|
241
|
+
youtubemusic: true,
|
|
242
|
+
soundcloud: false,
|
|
243
|
+
},
|
|
244
|
+
}),
|
|
245
|
+
],
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Lyrics Extension
|
|
250
|
+
|
|
251
|
+
Fetch synchronized lyrics from multiple sources.
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
import { LyricsExtension } from "ryanlink";
|
|
255
|
+
|
|
256
|
+
const player = new RyanlinkPlayer({
|
|
257
|
+
plugins: [
|
|
258
|
+
new LyricsExtension({
|
|
259
|
+
sources: ["lrclib", "genius", "musixmatch"],
|
|
260
|
+
cache: true,
|
|
261
|
+
}),
|
|
262
|
+
],
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// Get lyrics
|
|
266
|
+
const lyrics = await queue.getLyrics();
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### SponsorBlock Extension
|
|
270
|
+
|
|
271
|
+
Skip sponsored segments in YouTube videos.
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
import { SponsorBlockExtension } from "ryanlink";
|
|
275
|
+
|
|
276
|
+
const player = new RyanlinkPlayer({
|
|
277
|
+
plugins: [
|
|
278
|
+
new SponsorBlockExtension({
|
|
279
|
+
categories: ["sponsor", "intro", "outro", "selfpromo"],
|
|
280
|
+
autoSkip: true,
|
|
281
|
+
}),
|
|
282
|
+
],
|
|
283
|
+
});
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### FairPlay Extension
|
|
287
|
+
|
|
288
|
+
Limit tracks per user for fair queue distribution.
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
import { FairPlayExtension } from "ryanlink";
|
|
292
|
+
|
|
293
|
+
const player = new RyanlinkPlayer({
|
|
294
|
+
plugins: [
|
|
295
|
+
new FairPlayExtension({
|
|
296
|
+
maxPerUser: 3,
|
|
297
|
+
enforceLimit: true,
|
|
298
|
+
}),
|
|
299
|
+
],
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Persistence Extension
|
|
304
|
+
|
|
305
|
+
Save and restore queues across bot restarts.
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
import { PersistenceExtension } from "ryanlink";
|
|
309
|
+
|
|
310
|
+
const player = new RyanlinkPlayer({
|
|
311
|
+
plugins: [
|
|
312
|
+
new PersistenceExtension({
|
|
313
|
+
autoSave: true,
|
|
314
|
+
saveInterval: 60000, // 1 minute
|
|
315
|
+
}),
|
|
316
|
+
],
|
|
317
|
+
});
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Events
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
// Track events
|
|
324
|
+
player.on("trackStart", (queue, track) => {
|
|
325
|
+
console.log(`Now playing: ${track.title}`);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
player.on("trackFinish", (queue, track, reason) => {
|
|
329
|
+
console.log(`Finished: ${track.title} (${reason})`);
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
player.on("trackError", (queue, track, error) => {
|
|
333
|
+
console.error(`Error: ${error.message}`);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
player.on("trackStuck", (queue, track, threshold) => {
|
|
337
|
+
console.warn(`Track stuck: ${track.title}`);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// Queue events
|
|
341
|
+
player.on("queueCreate", (queue) => {
|
|
342
|
+
console.log(`Queue created for guild ${queue.guildId}`);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
player.on("queueFinish", (queue) => {
|
|
346
|
+
console.log("Queue finished!");
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
player.on("queueDestroy", (queue, reason) => {
|
|
350
|
+
console.log(`Queue destroyed: ${reason}`);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
// Node events
|
|
354
|
+
player.on("nodeConnect", (node, reconnects) => {
|
|
355
|
+
console.log(`Node ${node.name} connected`);
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
player.on("nodeReady", (node, resumed, sessionId) => {
|
|
359
|
+
console.log(`Node ${node.name} ready`);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
player.on("nodeDisconnect", (node, code, reason) => {
|
|
363
|
+
console.log(`Node ${node.name} disconnected`);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
player.on("nodeError", (node, error) => {
|
|
367
|
+
console.error(`Node error: ${error.message}`);
|
|
368
|
+
});
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## TypeScript Support
|
|
372
|
+
|
|
373
|
+
Ryanlink is built with TypeScript and provides complete type definitions.
|
|
374
|
+
|
|
375
|
+
### Module Augmentation
|
|
376
|
+
|
|
377
|
+
Extend types for custom data:
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
declare module "ryanlink" {
|
|
381
|
+
interface QueueContext {
|
|
382
|
+
textChannelId: string;
|
|
383
|
+
requesterId: string;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
interface CommonUserData {
|
|
387
|
+
id: string;
|
|
388
|
+
username: string;
|
|
389
|
+
requestedAt: number;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
interface CommonPluginInfo {
|
|
393
|
+
customField?: string;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Requirements
|
|
399
|
+
|
|
400
|
+
- **Node.js**: 18.0.0 or higher
|
|
401
|
+
- **Bun**: 1.0.0 or higher
|
|
402
|
+
- **Deno**: 1.30.0 or higher
|
|
403
|
+
- **Lavalink**: 4.0.0 or higher
|
|
404
|
+
|
|
405
|
+
## Architecture
|
|
406
|
+
|
|
407
|
+
Ryanlink uses a feature-based architecture for better organization:
|
|
408
|
+
|
|
409
|
+
```
|
|
410
|
+
src/
|
|
411
|
+
├── core/ # Player and plugin system
|
|
412
|
+
├── lavalink/ # Lavalink connection and HTTP client
|
|
413
|
+
├── audio/ # Queue, tracks, and filters
|
|
414
|
+
├── voice/ # Voice connection management
|
|
415
|
+
├── extensions/ # Built-in extensions
|
|
416
|
+
├── config/ # Configuration and constants
|
|
417
|
+
├── utils/ # Utility functions
|
|
418
|
+
└── types/ # TypeScript definitions
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
## Performance
|
|
422
|
+
|
|
423
|
+
- **Efficient Memory Usage** - Optimized data structures and caching
|
|
424
|
+
- **Fast Track Loading** - Parallel track resolution
|
|
425
|
+
- **Minimal Overhead** - Native fetch API, no unnecessary dependencies
|
|
426
|
+
- **Smart Reconnection** - Automatic recovery with exponential backoff
|
|
427
|
+
|
|
428
|
+
## Contributing
|
|
429
|
+
|
|
430
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
|
|
431
|
+
|
|
432
|
+
## License
|
|
433
|
+
|
|
434
|
+
This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
|
|
435
|
+
|
|
436
|
+
## Acknowledgements
|
|
437
|
+
|
|
438
|
+
Ryanlink was inspired by and builds upon concepts from:
|
|
439
|
+
|
|
440
|
+
- [distube](https://github.com/skick1234/DisTube) - Player-queue design patterns
|
|
441
|
+
- [discord.js](https://github.com/discordjs/discord.js) - Manager-cache architecture
|
|
442
|
+
- [Hoshimi](https://github.com/Ganyu-Studios/Hoshimi) - Module augmentation patterns
|
|
443
|
+
- [discolink](https://github.com/execaman/discolink) - Modern Lavalink client design
|
|
444
|
+
|
|
445
|
+
## Support
|
|
446
|
+
|
|
447
|
+
- [Documentation](https://ryanwtf7.github.io/ryanlink)
|
|
448
|
+
- [GitHub Issues](https://github.com/ryanwtf7/ryanlink/issues)
|
|
449
|
+
- [GitHub Discussions](https://github.com/ryanwtf7/ryanlink/discussions)
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
<div align="center">
|
|
454
|
+
Made with ❤️ by RY4N
|
|
455
|
+
</div>
|