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.
Files changed (60) hide show
  1. package/LICENSE +37 -0
  2. package/README.md +455 -0
  3. package/dist/index.d.mts +1335 -0
  4. package/dist/index.d.ts +1335 -0
  5. package/dist/index.js +4694 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/index.mjs +4604 -0
  8. package/dist/index.mjs.map +1 -0
  9. package/package.json +82 -0
  10. package/src/audio/AudioFilters.ts +316 -0
  11. package/src/audio/AudioQueue.ts +782 -0
  12. package/src/audio/AudioTrack.ts +242 -0
  13. package/src/audio/QueueController.ts +252 -0
  14. package/src/audio/TrackCollection.ts +138 -0
  15. package/src/audio/index.ts +9 -0
  16. package/src/config/defaults.ts +223 -0
  17. package/src/config/endpoints.ts +99 -0
  18. package/src/config/index.ts +9 -0
  19. package/src/config/patterns.ts +55 -0
  20. package/src/config/presets.ts +400 -0
  21. package/src/config/symbols.ts +31 -0
  22. package/src/core/PluginSystem.ts +50 -0
  23. package/src/core/RyanlinkPlayer.ts +403 -0
  24. package/src/core/index.ts +6 -0
  25. package/src/extensions/AutoplayExtension.ts +283 -0
  26. package/src/extensions/FairPlayExtension.ts +154 -0
  27. package/src/extensions/LyricsExtension.ts +187 -0
  28. package/src/extensions/PersistenceExtension.ts +182 -0
  29. package/src/extensions/SponsorBlockExtension.ts +81 -0
  30. package/src/extensions/index.ts +9 -0
  31. package/src/index.ts +19 -0
  32. package/src/lavalink/ConnectionPool.ts +326 -0
  33. package/src/lavalink/HttpClient.ts +316 -0
  34. package/src/lavalink/LavalinkConnection.ts +409 -0
  35. package/src/lavalink/index.ts +7 -0
  36. package/src/metadata.ts +88 -0
  37. package/src/types/api/Rest.ts +949 -0
  38. package/src/types/api/Websocket.ts +463 -0
  39. package/src/types/api/index.ts +6 -0
  40. package/src/types/audio/FilterManager.ts +29 -0
  41. package/src/types/audio/Queue.ts +4 -0
  42. package/src/types/audio/QueueManager.ts +30 -0
  43. package/src/types/audio/index.ts +7 -0
  44. package/src/types/common.ts +63 -0
  45. package/src/types/core/Player.ts +322 -0
  46. package/src/types/core/index.ts +5 -0
  47. package/src/types/index.ts +6 -0
  48. package/src/types/lavalink/Node.ts +173 -0
  49. package/src/types/lavalink/NodeManager.ts +34 -0
  50. package/src/types/lavalink/REST.ts +144 -0
  51. package/src/types/lavalink/index.ts +32 -0
  52. package/src/types/voice/VoiceManager.ts +176 -0
  53. package/src/types/voice/index.ts +5 -0
  54. package/src/utils/helpers.ts +169 -0
  55. package/src/utils/index.ts +6 -0
  56. package/src/utils/validators.ts +184 -0
  57. package/src/voice/RegionSelector.ts +184 -0
  58. package/src/voice/VoiceConnection.ts +451 -0
  59. package/src/voice/VoiceSession.ts +297 -0
  60. 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,9 @@
1
+ /**
2
+ * Configuration exports
3
+ */
4
+
5
+ export * from "./defaults";
6
+ export * from "./presets";
7
+ export * from "./patterns";
8
+ export * from "./endpoints";
9
+ export * from "./symbols";
@@ -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;