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
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default configuration options for Ryanlink
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { CLIENT_NAME, CLIENT_VERSION, CLIENT_REPOSITORY } from "../metadata";
|
|
6
|
+
import type { NodeOptions, PlayerOptions, RESTOptions } from "../types";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Default REST client options
|
|
10
|
+
*/
|
|
11
|
+
export const DefaultRestOptions = Object.seal({
|
|
12
|
+
/**
|
|
13
|
+
* Lavalink API version
|
|
14
|
+
*/
|
|
15
|
+
version: 4,
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* User agent string sent with requests
|
|
19
|
+
*/
|
|
20
|
+
userAgent: `${CLIENT_NAME}/${CLIENT_VERSION} (${CLIENT_REPOSITORY})`,
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Whether to include stack traces in error responses
|
|
24
|
+
*/
|
|
25
|
+
stackTrace: false,
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Request timeout in milliseconds
|
|
29
|
+
*/
|
|
30
|
+
requestTimeout: 10_000,
|
|
31
|
+
} as const satisfies Partial<RESTOptions>);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Default Node connection options
|
|
35
|
+
*/
|
|
36
|
+
export const DefaultNodeOptions = Object.seal({
|
|
37
|
+
/**
|
|
38
|
+
* Interval for stats updates in milliseconds
|
|
39
|
+
*/
|
|
40
|
+
statsInterval: 60_000,
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Highest acceptable latency in milliseconds
|
|
44
|
+
*/
|
|
45
|
+
highestLatency: 2_000,
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Delay before reconnection attempts in milliseconds
|
|
49
|
+
*/
|
|
50
|
+
reconnectDelay: 10_000,
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Maximum number of reconnection attempts (-1 = infinite)
|
|
54
|
+
*/
|
|
55
|
+
reconnectLimit: 3,
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* WebSocket handshake timeout in milliseconds
|
|
59
|
+
*/
|
|
60
|
+
handshakeTimeout: 5_000,
|
|
61
|
+
} as const satisfies Partial<Omit<NodeOptions, keyof RESTOptions>>);
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Default Player options
|
|
65
|
+
*/
|
|
66
|
+
export const DefaultPlayerOptions = Object.seal({
|
|
67
|
+
/**
|
|
68
|
+
* Automatically initialize player on construction
|
|
69
|
+
*/
|
|
70
|
+
autoInit: true,
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Automatically sync queue state with Lavalink
|
|
74
|
+
*/
|
|
75
|
+
autoSync: true,
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Default search prefix (ytsearch, ytmsearch, scsearch, etc.)
|
|
79
|
+
*/
|
|
80
|
+
queryPrefix: "ytsearch",
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Automatically relocate queues when nodes disconnect
|
|
84
|
+
*/
|
|
85
|
+
relocateQueues: true,
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Default function to fetch related tracks for autoplay
|
|
89
|
+
* Returns empty array by default (no autoplay)
|
|
90
|
+
*/
|
|
91
|
+
async fetchRelatedTracks() {
|
|
92
|
+
return await Promise.resolve([]);
|
|
93
|
+
},
|
|
94
|
+
} as const satisfies Partial<PlayerOptions>);
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Default queue options
|
|
98
|
+
*/
|
|
99
|
+
export const DefaultQueueOptions = Object.seal({
|
|
100
|
+
/**
|
|
101
|
+
* Default volume (0-1000)
|
|
102
|
+
*/
|
|
103
|
+
volume: 100,
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Default repeat mode
|
|
107
|
+
*/
|
|
108
|
+
repeatMode: "none" as const,
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Default autoplay state
|
|
112
|
+
*/
|
|
113
|
+
autoplay: false,
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Default paused state
|
|
117
|
+
*/
|
|
118
|
+
paused: false,
|
|
119
|
+
} as const);
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Default filter values
|
|
123
|
+
*/
|
|
124
|
+
export const DefaultFilterOptions = Object.seal({
|
|
125
|
+
/**
|
|
126
|
+
* Volume multiplier (0.0 - 5.0)
|
|
127
|
+
*/
|
|
128
|
+
volume: 1.0,
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Equalizer bands (15 bands, -0.25 to 1.0 each)
|
|
132
|
+
*/
|
|
133
|
+
equalizer: [] as Array<{ band: number; gain: number }>,
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Karaoke filter
|
|
137
|
+
*/
|
|
138
|
+
karaoke: null as { level?: number; monoLevel?: number; filterBand?: number; filterWidth?: number } | null,
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Timescale filter (speed, pitch, rate)
|
|
142
|
+
*/
|
|
143
|
+
timescale: null as { speed?: number; pitch?: number; rate?: number } | null,
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Tremolo filter (frequency, depth)
|
|
147
|
+
*/
|
|
148
|
+
tremolo: null as { frequency?: number; depth?: number } | null,
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Vibrato filter (frequency, depth)
|
|
152
|
+
*/
|
|
153
|
+
vibrato: null as { frequency?: number; depth?: number } | null,
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Rotation filter (rotationHz)
|
|
157
|
+
*/
|
|
158
|
+
rotation: null as { rotationHz?: number } | null,
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Distortion filter
|
|
162
|
+
*/
|
|
163
|
+
distortion: null as {
|
|
164
|
+
sinOffset?: number;
|
|
165
|
+
sinScale?: number;
|
|
166
|
+
cosOffset?: number;
|
|
167
|
+
cosScale?: number;
|
|
168
|
+
tanOffset?: number;
|
|
169
|
+
tanScale?: number;
|
|
170
|
+
offset?: number;
|
|
171
|
+
scale?: number;
|
|
172
|
+
} | null,
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Channel mix filter
|
|
176
|
+
*/
|
|
177
|
+
channelMix: null as {
|
|
178
|
+
leftToLeft?: number;
|
|
179
|
+
leftToRight?: number;
|
|
180
|
+
rightToLeft?: number;
|
|
181
|
+
rightToRight?: number;
|
|
182
|
+
} | null,
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Low pass filter
|
|
186
|
+
*/
|
|
187
|
+
lowPass: null as { smoothing?: number } | null,
|
|
188
|
+
} as const);
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Common HTTP status codes
|
|
192
|
+
*/
|
|
193
|
+
export const HttpStatusCodes = Object.freeze({
|
|
194
|
+
OK: 200,
|
|
195
|
+
CREATED: 201,
|
|
196
|
+
NO_CONTENT: 204,
|
|
197
|
+
BAD_REQUEST: 400,
|
|
198
|
+
UNAUTHORIZED: 401,
|
|
199
|
+
FORBIDDEN: 403,
|
|
200
|
+
NOT_FOUND: 404,
|
|
201
|
+
METHOD_NOT_ALLOWED: 405,
|
|
202
|
+
TOO_MANY_REQUESTS: 429,
|
|
203
|
+
INTERNAL_SERVER_ERROR: 500,
|
|
204
|
+
BAD_GATEWAY: 502,
|
|
205
|
+
SERVICE_UNAVAILABLE: 503,
|
|
206
|
+
GATEWAY_TIMEOUT: 504,
|
|
207
|
+
} as const);
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* WebSocket close codes
|
|
211
|
+
*/
|
|
212
|
+
export const WebSocketCloseCodes = Object.freeze({
|
|
213
|
+
NORMAL: 1000,
|
|
214
|
+
GOING_AWAY: 1001,
|
|
215
|
+
PROTOCOL_ERROR: 1002,
|
|
216
|
+
UNSUPPORTED_DATA: 1003,
|
|
217
|
+
NO_STATUS_RECEIVED: 1005,
|
|
218
|
+
ABNORMAL_CLOSURE: 1006,
|
|
219
|
+
INVALID_FRAME_PAYLOAD_DATA: 1007,
|
|
220
|
+
POLICY_VIOLATION: 1008,
|
|
221
|
+
MESSAGE_TOO_BIG: 1009,
|
|
222
|
+
INTERNAL_ERROR: 1011,
|
|
223
|
+
} as const);
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lavalink REST API route constructors
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* An object holding methods that construct API routes based on params
|
|
7
|
+
*/
|
|
8
|
+
export const Routes = {
|
|
9
|
+
/**
|
|
10
|
+
* WebSocket endpoint
|
|
11
|
+
* @returns `/websocket`
|
|
12
|
+
*/
|
|
13
|
+
websocket(): "/websocket" {
|
|
14
|
+
return "/websocket" as const;
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Track loading endpoint
|
|
19
|
+
* @returns `/loadtracks`
|
|
20
|
+
*/
|
|
21
|
+
trackLoading(): "/loadtracks" {
|
|
22
|
+
return "/loadtracks" as const;
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Track decoding endpoint
|
|
27
|
+
* @param multiple Whether to decode multiple tracks
|
|
28
|
+
* @returns `/decodetrack` or `/decodetracks`
|
|
29
|
+
*/
|
|
30
|
+
trackDecoding(multiple?: boolean): "/decodetrack" | "/decodetracks" {
|
|
31
|
+
if (multiple) {
|
|
32
|
+
return "/decodetracks" as const;
|
|
33
|
+
}
|
|
34
|
+
return "/decodetrack" as const;
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Player endpoint
|
|
39
|
+
* @param sessionId Lavalink session ID
|
|
40
|
+
* @param guildId Optional guild ID for specific player
|
|
41
|
+
* @returns `/sessions/{sessionId}/players` or `/sessions/{sessionId}/players/{guildId}`
|
|
42
|
+
*/
|
|
43
|
+
player(sessionId: string, guildId?: string): string {
|
|
44
|
+
if (guildId) {
|
|
45
|
+
return `/sessions/${sessionId}/players/${guildId}` as const;
|
|
46
|
+
}
|
|
47
|
+
return `/sessions/${sessionId}/players` as const;
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Session endpoint
|
|
52
|
+
* @param sessionId Lavalink session ID
|
|
53
|
+
* @returns `/sessions/{sessionId}`
|
|
54
|
+
*/
|
|
55
|
+
session(sessionId: string): string {
|
|
56
|
+
return `/sessions/${sessionId}` as const;
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Info endpoint
|
|
61
|
+
* @returns `/info`
|
|
62
|
+
*/
|
|
63
|
+
info(): "/info" {
|
|
64
|
+
return "/info" as const;
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Stats endpoint
|
|
69
|
+
* @returns `/stats`
|
|
70
|
+
*/
|
|
71
|
+
stats(): "/stats" {
|
|
72
|
+
return "/stats" as const;
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Route planner endpoint
|
|
77
|
+
* @param free Optional action: `address` or `all`
|
|
78
|
+
* @returns `/routeplanner/status` or `/routeplanner/free/{action}`
|
|
79
|
+
*/
|
|
80
|
+
routePlanner(free?: "address" | "all"): string {
|
|
81
|
+
if (free) {
|
|
82
|
+
return `/routeplanner/free/${free}` as const;
|
|
83
|
+
}
|
|
84
|
+
return "/routeplanner/status" as const;
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Version endpoint
|
|
89
|
+
* @returns `/version`
|
|
90
|
+
*/
|
|
91
|
+
version(): "/version" {
|
|
92
|
+
return "/version" as const;
|
|
93
|
+
},
|
|
94
|
+
} as const;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Type helper to extract route return types
|
|
98
|
+
*/
|
|
99
|
+
export type RouteReturnType<T extends keyof typeof Routes> = ReturnType<(typeof Routes)[T]>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export const SnowflakeRegex = /^\d{17,20}$/;
|
|
2
|
+
|
|
3
|
+
export const VoiceRegionIdRegex = /^([-a-z]{2,20})(?=[-a-z\d]*\.discord\.media:\d+$)/;
|
|
4
|
+
|
|
5
|
+
export const UrlRegex = /^https?:\/\/.+/i;
|
|
6
|
+
|
|
7
|
+
export const YoutubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+/i;
|
|
8
|
+
|
|
9
|
+
export const SpotifyRegex = /^https?:\/\/open\.spotify\.com\/(track|album|playlist|artist)\/.+/i;
|
|
10
|
+
|
|
11
|
+
export const SoundCloudRegex = /^https?:\/\/(www\.)?soundcloud\.com\/.+/i;
|
|
12
|
+
|
|
13
|
+
export const BandcampRegex = /^https?:\/\/.+\.bandcamp\.com\/(track|album)\/.+/i;
|
|
14
|
+
|
|
15
|
+
export const TwitchRegex = /^https?:\/\/(www\.)?twitch\.tv\/.+/i;
|
|
16
|
+
|
|
17
|
+
export const AppleMusicRegex = /^https?:\/\/music\.apple\.com\/.+/i;
|
|
18
|
+
|
|
19
|
+
export const DeezerRegex = /^https?:\/\/(www\.)?deezer\.com\/(track|album|playlist)\/.+/i;
|
|
20
|
+
|
|
21
|
+
export const AudioFileRegex = /^https?:\/\/.+\.(mp3|wav|ogg|flac|m4a|aac|opus|webm)(\?.*)?$/i;
|
|
22
|
+
|
|
23
|
+
export const TidalRegex =
|
|
24
|
+
/^https?:\/\/(?:(?:listen|www)\.)?tidal\.com\/(?:browse\/)?(?:album|track|playlist|mix)\/[a-zA-Z0-9-]+(?:\/.*)?(?:\?.*)?$/i;
|
|
25
|
+
|
|
26
|
+
export const YandexMusicRegex =
|
|
27
|
+
/^(?:https?:\/\/)?music\.yandex\.(?:ru|com|kz|by)\/(?:artist|album|track|users\/[0-9A-Za-z@.-]+\/playlists|playlists)\/[0-9A-Za-z-.]+(?:\/track\/[0-9]+)?(?:\/)?$/i;
|
|
28
|
+
|
|
29
|
+
export const AmazonMusicRegex =
|
|
30
|
+
/^https?:\/\/music\.amazon\.[^/]+\/(?:albums|tracks|artists|playlists|user-playlists|community-playlists)\/[A-Za-z0-9]+(?:\/[^/?#]+)?(?:[/?].*)?$/i;
|
|
31
|
+
|
|
32
|
+
export const JioSaavnRegex =
|
|
33
|
+
/^(?:https?:\/\/)?(?:www\.)?jiosaavn\.com\/(?:song|album|featured|artist|s\/playlist)\/[a-zA-Z0-9_-]+(?:\/[a-zA-Z0-9_-]+)?$/i;
|
|
34
|
+
|
|
35
|
+
export const PandoraRegex =
|
|
36
|
+
/^@?(?:https?:\/\/)?(?:www\.)?pandora\.com\/(?:playlist\/PL:[\d:]+|artist\/[\w-]+(?:\/[\w-]+)*\/(?:TR|AL|AR)[A-Za-z0-9]+)(?:[?#].*)?$/i;
|
|
37
|
+
|
|
38
|
+
export const QobuzRegex =
|
|
39
|
+
/^https?:\/\/(?:www\.|play\.|open\.)?qobuz\.com\/(?:(?:[a-z]{2}-[a-z]{2}\/)?(?:album|playlist|track|artist)\/(?:.+?\/)?[a-zA-Z0-9]+|playlist\/\d+)$/i;
|
|
40
|
+
|
|
41
|
+
export const AudiomackRegex =
|
|
42
|
+
/^https?:\/\/audiomack\.com\/(?:(?:[^/]+\/(?:song|album|playlist)|(?:song|album|playlist))\/[^/?#]+)$/i;
|
|
43
|
+
|
|
44
|
+
export const MixcloudRegex =
|
|
45
|
+
/^https?:\/\/(?:(?:www|beta|m)\.)?mixcloud\.com\/[^/]+\/(?:playlists\/[^/]+|(?!stream|uploads|favorites|listens|playlists)[^/]+|(?:uploads|favorites|listens|stream))(?:\/)?$/i;
|
|
46
|
+
|
|
47
|
+
export const AnghamiRegex = /^https?:\/\/(?:play\.)?anghami\.com\/(?:song|album|playlist|artist)\/[0-9]+$/i;
|
|
48
|
+
|
|
49
|
+
export const AudiusRegex = /^https?:\/\/(?:www\.)?audius\.co\/[^/]+\/[^/]+$/i;
|
|
50
|
+
|
|
51
|
+
export const GaanaRegex = /^https?:\/\/(?:www\.)?gaana\.com\/(?:song|album|playlist)\/[^/]+$/i;
|
|
52
|
+
|
|
53
|
+
export const InstagramRegex = /^https?:\/\/(?:www\.)?instagram\.com\/(?:p|reel|tv)\/[A-Za-z0-9_-]+(?:\/)?$/i;
|
|
54
|
+
|
|
55
|
+
export const ShazamRegex = /^https?:\/\/(?:www\.)?shazam\.com\/track\/[0-9]+$/i;
|