lavalink-client 1.0.3 → 1.0.5
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/README.md +32 -98
- package/dist/cjs/structures/LavalinkManager.d.ts +17 -15
- package/dist/cjs/structures/LavalinkManager.js +66 -16
- package/dist/cjs/structures/Node.js +16 -13
- package/dist/cjs/structures/NodeManager.d.ts +1 -1
- package/dist/cjs/structures/NodeManager.js +55 -5
- package/dist/cjs/structures/Player.d.ts +4 -4
- package/dist/cjs/structures/Player.js +22 -7
- package/dist/cjs/structures/Queue.d.ts +13 -11
- package/dist/cjs/structures/Queue.js +31 -28
- package/dist/cjs/structures/Track.d.ts +14 -3
- package/dist/cjs/structures/Utils.d.ts +34 -7
- package/dist/cjs/structures/Utils.js +136 -13
- package/dist/esm/structures/LavalinkManager.d.ts +17 -15
- package/dist/esm/structures/LavalinkManager.js +66 -16
- package/dist/esm/structures/Node.js +16 -13
- package/dist/esm/structures/NodeManager.d.ts +1 -1
- package/dist/esm/structures/NodeManager.js +55 -5
- package/dist/esm/structures/Player.d.ts +4 -4
- package/dist/esm/structures/Player.js +22 -7
- package/dist/esm/structures/Queue.d.ts +13 -11
- package/dist/esm/structures/Queue.js +32 -29
- package/dist/esm/structures/Track.d.ts +14 -3
- package/dist/esm/structures/Utils.d.ts +34 -7
- package/dist/esm/structures/Utils.js +136 -13
- package/dist/types/structures/LavalinkManager.d.ts +17 -15
- package/dist/types/structures/NodeManager.d.ts +1 -1
- package/dist/types/structures/Player.d.ts +4 -4
- package/dist/types/structures/Queue.d.ts +13 -11
- package/dist/types/structures/Track.d.ts +14 -3
- package/dist/types/structures/Utils.d.ts +34 -7
- package/package.json +1 -1
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { ManagerUitls
|
|
1
|
+
import { ManagerUitls } from "./Utils";
|
|
2
2
|
export class QueueSaver {
|
|
3
|
-
constructor(
|
|
4
|
-
this._ =
|
|
5
|
-
this.options =
|
|
3
|
+
constructor(options) {
|
|
4
|
+
this._ = options.queueStore || new DefaultQueueStore();
|
|
5
|
+
this.options = {
|
|
6
|
+
maxPreviousTracks: options.maxPreviousTracks
|
|
7
|
+
};
|
|
6
8
|
}
|
|
7
9
|
async get(guildId) {
|
|
8
10
|
return await this._.parse(await this._.get(guildId));
|
|
@@ -57,17 +59,18 @@ export class Queue {
|
|
|
57
59
|
options = { maxPreviousTracks: 25 };
|
|
58
60
|
guildId = "";
|
|
59
61
|
QueueSaver = null;
|
|
60
|
-
static StaticSymbol = QueueSymbol;
|
|
61
62
|
managerUtils = new ManagerUitls();
|
|
62
63
|
queueChanges;
|
|
63
|
-
constructor(guildId, data = {}, QueueSaver,
|
|
64
|
-
this.queueChanges = queueChangesWatcher || null;
|
|
64
|
+
constructor(guildId, data = {}, QueueSaver, queueOptions) {
|
|
65
|
+
this.queueChanges = queueOptions.queueChangesWatcher || null;
|
|
65
66
|
this.guildId = guildId;
|
|
66
67
|
this.QueueSaver = QueueSaver;
|
|
67
68
|
this.options.maxPreviousTracks = this.QueueSaver?.options?.maxPreviousTracks ?? this.options.maxPreviousTracks;
|
|
68
69
|
this.current = this.managerUtils.isTrack(data.current) ? data.current : null;
|
|
69
|
-
this.previous = Array.isArray(data.previous) && data.previous.some(track => this.managerUtils.isTrack(track)) ? data.previous.filter(track => this.managerUtils.isTrack(track)) : [];
|
|
70
|
-
this.tracks = Array.isArray(data.tracks) && data.tracks.some(track => this.managerUtils.isTrack(track)) ? data.tracks.filter(track => this.managerUtils.isTrack(track)) : [];
|
|
70
|
+
this.previous = Array.isArray(data.previous) && data.previous.some(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) ? data.previous.filter(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) : [];
|
|
71
|
+
this.tracks = Array.isArray(data.tracks) && data.tracks.some(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) ? data.tracks.filter(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) : [];
|
|
72
|
+
}
|
|
73
|
+
applyData(data) {
|
|
71
74
|
}
|
|
72
75
|
/**
|
|
73
76
|
* Utils for a Queue
|
|
@@ -79,7 +82,7 @@ export class Queue {
|
|
|
79
82
|
save: async () => {
|
|
80
83
|
if (this.previous.length > this.options.maxPreviousTracks)
|
|
81
84
|
this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
|
|
82
|
-
return await this.QueueSaver.set(this.guildId, this.utils.
|
|
85
|
+
return await this.QueueSaver.set(this.guildId, this.utils.toJSON());
|
|
83
86
|
},
|
|
84
87
|
/**
|
|
85
88
|
* Sync the current queue database/server with the cached one
|
|
@@ -89,12 +92,12 @@ export class Queue {
|
|
|
89
92
|
const data = await this.QueueSaver.get(this.guildId);
|
|
90
93
|
if (!data)
|
|
91
94
|
return console.log("No data found to sync for guildId: ", this.guildId);
|
|
92
|
-
if (!dontSyncCurrent && !this.current && this.managerUtils.isTrack(data.current))
|
|
95
|
+
if (!dontSyncCurrent && !this.current && (this.managerUtils.isTrack(data.current)))
|
|
93
96
|
this.current = data.current;
|
|
94
|
-
if (Array.isArray(data.tracks) && data?.tracks.length && data.tracks.some(track => this.managerUtils.isTrack(track)))
|
|
95
|
-
this.tracks.splice(override ? 0 : this.tracks.length, override ? this.tracks.length : 0, ...data.tracks.filter(track => this.managerUtils.isTrack(track)));
|
|
96
|
-
if (Array.isArray(data.previous) && data?.previous.length && data.previous.some(track => this.managerUtils.isTrack(track)))
|
|
97
|
-
this.previous.splice(0, override ? this.tracks.length : 0, ...data.previous.filter(track => this.managerUtils.isTrack(track)));
|
|
97
|
+
if (Array.isArray(data.tracks) && data?.tracks.length && data.tracks.some(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)))
|
|
98
|
+
this.tracks.splice(override ? 0 : this.tracks.length, override ? this.tracks.length : 0, ...data.tracks.filter(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)));
|
|
99
|
+
if (Array.isArray(data.previous) && data?.previous.length && data.previous.some(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)))
|
|
100
|
+
this.previous.splice(0, override ? this.tracks.length : 0, ...data.previous.filter(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)));
|
|
98
101
|
await this.utils.save();
|
|
99
102
|
return;
|
|
100
103
|
},
|
|
@@ -104,13 +107,13 @@ export class Queue {
|
|
|
104
107
|
/**
|
|
105
108
|
* @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the storeManager
|
|
106
109
|
*/
|
|
107
|
-
|
|
110
|
+
toJSON: () => {
|
|
108
111
|
if (this.previous.length > this.options.maxPreviousTracks)
|
|
109
112
|
this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
|
|
110
113
|
return {
|
|
111
|
-
current: this.current,
|
|
112
|
-
previous: this.previous,
|
|
113
|
-
tracks: this.tracks,
|
|
114
|
+
current: this.current ? { ...this.current } : null,
|
|
115
|
+
previous: this.previous ? [...this.previous] : [],
|
|
116
|
+
tracks: this.tracks ? [...this.tracks] : [],
|
|
114
117
|
};
|
|
115
118
|
},
|
|
116
119
|
/**
|
|
@@ -126,7 +129,7 @@ export class Queue {
|
|
|
126
129
|
* @returns Amount of Tracks in the Queue
|
|
127
130
|
*/
|
|
128
131
|
async shuffle() {
|
|
129
|
-
const oldStored = typeof this.queueChanges?.shuffled === "function" ? this.utils.
|
|
132
|
+
const oldStored = typeof this.queueChanges?.shuffled === "function" ? this.utils.toJSON() : null;
|
|
130
133
|
if (this.tracks.length <= 1)
|
|
131
134
|
return this.tracks.length;
|
|
132
135
|
// swap #1 and #2 if only 2 tracks.
|
|
@@ -141,7 +144,7 @@ export class Queue {
|
|
|
141
144
|
}
|
|
142
145
|
// LOG
|
|
143
146
|
if (typeof this.queueChanges?.shuffled === "function")
|
|
144
|
-
this.queueChanges.shuffled(this.guildId, oldStored, this.utils.
|
|
147
|
+
this.queueChanges.shuffled(this.guildId, oldStored, this.utils.toJSON());
|
|
145
148
|
await this.utils.save();
|
|
146
149
|
return this.tracks.length;
|
|
147
150
|
}
|
|
@@ -153,14 +156,14 @@ export class Queue {
|
|
|
153
156
|
*/
|
|
154
157
|
async add(TrackOrTracks, index) {
|
|
155
158
|
if (typeof index === "number" && index >= 0 && index < this.tracks.length)
|
|
156
|
-
return await this.splice(index, 0, ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v)));
|
|
157
|
-
const oldStored = typeof this.queueChanges?.tracksAdd === "function" ? this.utils.
|
|
159
|
+
return await this.splice(index, 0, ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)));
|
|
160
|
+
const oldStored = typeof this.queueChanges?.tracksAdd === "function" ? this.utils.toJSON() : null;
|
|
158
161
|
// add the track(s)
|
|
159
|
-
this.tracks.push(...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v)));
|
|
162
|
+
this.tracks.push(...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)));
|
|
160
163
|
// log if available
|
|
161
164
|
if (typeof this.queueChanges?.tracksAdd === "function")
|
|
162
165
|
try {
|
|
163
|
-
this.queueChanges.tracksAdd(this.guildId, (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v)), this.tracks.length, oldStored, this.utils.
|
|
166
|
+
this.queueChanges.tracksAdd(this.guildId, (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)), this.tracks.length, oldStored, this.utils.toJSON());
|
|
164
167
|
}
|
|
165
168
|
catch (e) { /* */ }
|
|
166
169
|
// save the queue
|
|
@@ -176,7 +179,7 @@ export class Queue {
|
|
|
176
179
|
* @returns {Track} Spliced Track
|
|
177
180
|
*/
|
|
178
181
|
async splice(index, amount, TrackOrTracks) {
|
|
179
|
-
const oldStored = typeof this.queueChanges?.tracksAdd === "function" || typeof this.queueChanges?.tracksRemoved === "function" ? this.utils.
|
|
182
|
+
const oldStored = typeof this.queueChanges?.tracksAdd === "function" || typeof this.queueChanges?.tracksRemoved === "function" ? this.utils.toJSON() : null;
|
|
180
183
|
// if no tracks to splice, add the tracks
|
|
181
184
|
if (!this.tracks.length) {
|
|
182
185
|
if (TrackOrTracks)
|
|
@@ -186,17 +189,17 @@ export class Queue {
|
|
|
186
189
|
// Log if available
|
|
187
190
|
if ((TrackOrTracks) && typeof this.queueChanges?.tracksAdd === "function")
|
|
188
191
|
try {
|
|
189
|
-
this.queueChanges.tracksAdd(this.guildId, (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v)), index, oldStored, this.utils.
|
|
192
|
+
this.queueChanges.tracksAdd(this.guildId, (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)), index, oldStored, this.utils.toJSON());
|
|
190
193
|
}
|
|
191
194
|
catch (e) { /* */ }
|
|
192
195
|
// remove the tracks (and add the new ones)
|
|
193
|
-
let spliced = TrackOrTracks ? this.tracks.splice(index, amount, ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v))) : this.tracks.splice(index, amount);
|
|
196
|
+
let spliced = TrackOrTracks ? this.tracks.splice(index, amount, ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v))) : this.tracks.splice(index, amount);
|
|
194
197
|
// get the spliced array
|
|
195
198
|
spliced = (Array.isArray(spliced) ? spliced : [spliced]);
|
|
196
199
|
// Log if available
|
|
197
200
|
if (typeof this.queueChanges?.tracksRemoved === "function")
|
|
198
201
|
try {
|
|
199
|
-
this.queueChanges.tracksRemoved(this.guildId, spliced, index, oldStored, this.utils.
|
|
202
|
+
this.queueChanges.tracksRemoved(this.guildId, spliced, index, oldStored, this.utils.toJSON());
|
|
200
203
|
}
|
|
201
204
|
catch (e) { /* */ }
|
|
202
205
|
// save the queue
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Player } from "./Player";
|
|
1
2
|
import { Base64 } from "./Utils";
|
|
2
3
|
type LavalinkSourceNames = "youtube" | "youtubemusic" | "soundcloud" | "bandcamp" | "twitch";
|
|
3
4
|
type LavalinkPlugin_LavaSrc_SourceNames = "deezer" | "spotify" | "applemusic" | "yandexmusic" | "flowery-tts";
|
|
@@ -44,11 +45,21 @@ export interface Track extends LavalinkTrack {
|
|
|
44
45
|
/** The Track's Requester */
|
|
45
46
|
requester?: unknown;
|
|
46
47
|
}
|
|
47
|
-
export interface
|
|
48
|
+
export interface UnresolvedTrackInfo extends Partial<TrackInfo> {
|
|
49
|
+
/** Required */
|
|
50
|
+
title: string;
|
|
51
|
+
}
|
|
52
|
+
export interface UnresolvedQuery extends UnresolvedTrackInfo {
|
|
48
53
|
/** The base64 of the unresolved track to "encode" */
|
|
49
54
|
encoded?: Base64;
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
}
|
|
56
|
+
export interface UnresolvedTrack {
|
|
57
|
+
/** Required */
|
|
58
|
+
resolve: (player: Player) => Promise<void>;
|
|
59
|
+
/** The Base 64 encoded String */
|
|
60
|
+
encoded?: Base64;
|
|
61
|
+
/** Track Information */
|
|
62
|
+
info: UnresolvedTrackInfo;
|
|
52
63
|
/** The Track's Requester */
|
|
53
64
|
requester?: unknown;
|
|
54
65
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { LavalinkFilterData } from "./Filters";
|
|
2
2
|
import { LavalinkManager } from "./LavalinkManager";
|
|
3
|
-
import { LavalinkNode, NodeStats } from "./Node";
|
|
4
|
-
import { PlayOptions } from "./Player";
|
|
5
|
-
import {
|
|
6
|
-
import { PluginInfo, Track } from "./Track";
|
|
3
|
+
import { LavalinkNode, LavalinkNodeOptions, NodeStats } from "./Node";
|
|
4
|
+
import { PlayOptions, Player } from "./Player";
|
|
5
|
+
import { PluginInfo, Track, UnresolvedTrack, UnresolvedQuery } from "./Track";
|
|
7
6
|
export declare const TrackSymbol: unique symbol;
|
|
8
7
|
export declare const UnresolvedTrackSymbol: unique symbol;
|
|
9
8
|
export declare const QueueSymbol: unique symbol;
|
|
@@ -40,12 +39,39 @@ export interface ManagerUitls {
|
|
|
40
39
|
export declare class ManagerUitls {
|
|
41
40
|
constructor(LavalinkManager?: LavalinkManager);
|
|
42
41
|
buildTrack(data: any, requester: any): Track;
|
|
42
|
+
/**
|
|
43
|
+
* Validate if a data is equal to a node
|
|
44
|
+
* @param data
|
|
45
|
+
*/
|
|
46
|
+
isNode(data: LavalinkNode): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Validate if a data is equal to node options
|
|
49
|
+
* @param data
|
|
50
|
+
*/
|
|
51
|
+
isNodeOptions(data: LavalinkNodeOptions | any): boolean;
|
|
43
52
|
/**
|
|
44
53
|
* Validate if a data is euqal to a track
|
|
45
|
-
* @param
|
|
46
|
-
* @returns
|
|
54
|
+
* @param data the Track to validate
|
|
55
|
+
* @returns
|
|
47
56
|
*/
|
|
48
57
|
isTrack(data: Track | any): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Checks if the provided argument is a valid UnresolvedTrack.
|
|
60
|
+
* @param track
|
|
61
|
+
*/
|
|
62
|
+
isUnresolvedTrack(data: UnresolvedTrack | any): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Checks if the provided argument is a valid UnresolvedTrack.
|
|
65
|
+
* @param track
|
|
66
|
+
*/
|
|
67
|
+
isUnresolvedTrackQuery(data: UnresolvedTrack | any): boolean;
|
|
68
|
+
getClosestTrack(data: UnresolvedTrack, player: Player): Promise<Track>;
|
|
69
|
+
/**
|
|
70
|
+
* Builds a UnresolvedTrack to be resolved before being played .
|
|
71
|
+
* @param query
|
|
72
|
+
* @param requester
|
|
73
|
+
*/
|
|
74
|
+
buildUnresolvedTrack(query: UnresolvedQuery | UnresolvedTrack, requester: unknown): UnresolvedTrack;
|
|
49
75
|
validatedQuery(queryString: string, node: LavalinkNode): void;
|
|
50
76
|
}
|
|
51
77
|
/**
|
|
@@ -85,6 +111,7 @@ export declare class MiniMap<K, V> extends Map<K, V> {
|
|
|
85
111
|
filter<This, K2 extends K>(fn: (this: This, value: V, key: K, miniMap: this) => key is K2, thisArg: This): MiniMap<K2, V>;
|
|
86
112
|
filter<This, V2 extends V>(fn: (this: This, value: V, key: K, miniMap: this) => value is V2, thisArg: This): MiniMap<K, V2>;
|
|
87
113
|
filter<This>(fn: (this: This, value: V, key: K, miniMap: this) => boolean, thisArg: This): MiniMap<K, V>;
|
|
114
|
+
toJSON(): V[];
|
|
88
115
|
/**
|
|
89
116
|
* Maps each item to another value into an array. Identical in behavior to
|
|
90
117
|
* [Array.map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map).
|
|
@@ -254,5 +281,5 @@ export interface NodeMessage extends NodeStats {
|
|
|
254
281
|
op: "stats" | "playerUpdate" | "event";
|
|
255
282
|
guildId: string;
|
|
256
283
|
}
|
|
257
|
-
export declare function queueTrackEnd(
|
|
284
|
+
export declare function queueTrackEnd(player: Player): Promise<Track>;
|
|
258
285
|
export {};
|
|
@@ -38,14 +38,103 @@ export class ManagerUitls {
|
|
|
38
38
|
throw new RangeError(`Argument "data" is not a valid track: ${error.message}`);
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Validate if a data is equal to a node
|
|
43
|
+
* @param data
|
|
44
|
+
*/
|
|
45
|
+
isNode(data) {
|
|
46
|
+
if (!data)
|
|
47
|
+
return false;
|
|
48
|
+
const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(data));
|
|
49
|
+
if (!keys.includes("constructor"))
|
|
50
|
+
return false;
|
|
51
|
+
if (!keys.length)
|
|
52
|
+
return false;
|
|
53
|
+
// all required functions
|
|
54
|
+
if (!["connect", "destroy", "destroyPlayer", "fetchAllPlayers", "fetchInfo", "fetchPlayer", "fetchStats", "fetchVersion", "request", "updatePlayer", "updateSession"].every(v => keys.includes(v)))
|
|
55
|
+
return false;
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Validate if a data is equal to node options
|
|
60
|
+
* @param data
|
|
61
|
+
*/
|
|
62
|
+
isNodeOptions(data) {
|
|
63
|
+
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
64
|
+
return false;
|
|
65
|
+
if (typeof data.host !== "string" || !data.host.length)
|
|
66
|
+
return false;
|
|
67
|
+
if (typeof data.port !== "number" || isNaN(data.port) || data.port < 0 || data.port > 65535)
|
|
68
|
+
return false;
|
|
69
|
+
if (typeof data.authorization !== "string" || !data.authorization.length)
|
|
70
|
+
return false;
|
|
71
|
+
if ("secure" in data && typeof data.secure !== "boolean")
|
|
72
|
+
return false;
|
|
73
|
+
if ("sessionId" in data && typeof data.sessionId !== "string")
|
|
74
|
+
return false;
|
|
75
|
+
if ("id" in data && typeof data.id !== "string")
|
|
76
|
+
return false;
|
|
77
|
+
if ("regions" in data && (!Array.isArray(data.regions) || !data.regions.every(v => typeof v === "string")))
|
|
78
|
+
return false;
|
|
79
|
+
if ("poolOptions" in data && typeof data.poolOptions !== "object")
|
|
80
|
+
return false;
|
|
81
|
+
if ("retryAmount" in data && (typeof data.retryAmount !== "number" || isNaN(data.retryAmount) || data.retryAmount <= 0))
|
|
82
|
+
return false;
|
|
83
|
+
if ("retryDelay" in data && (typeof data.retryDelay !== "number" || isNaN(data.retryDelay) || data.retryDelay <= 0))
|
|
84
|
+
return false;
|
|
85
|
+
if ("requestTimeout" in data && (typeof data.requestTimeout !== "number" || isNaN(data.requestTimeout) || data.requestTimeout <= 0))
|
|
86
|
+
return false;
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
41
89
|
/**
|
|
42
90
|
* Validate if a data is euqal to a track
|
|
43
|
-
* @param
|
|
44
|
-
* @returns
|
|
91
|
+
* @param data the Track to validate
|
|
92
|
+
* @returns
|
|
45
93
|
*/
|
|
46
94
|
isTrack(data) {
|
|
47
95
|
return typeof data?.encoded === "string" && typeof data?.info === "object";
|
|
48
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Checks if the provided argument is a valid UnresolvedTrack.
|
|
99
|
+
* @param track
|
|
100
|
+
*/
|
|
101
|
+
isUnresolvedTrack(data) {
|
|
102
|
+
return typeof data === "object" && "info" in data && typeof data.info.title === "string" && typeof data.resolve === "function";
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Checks if the provided argument is a valid UnresolvedTrack.
|
|
106
|
+
* @param track
|
|
107
|
+
*/
|
|
108
|
+
isUnresolvedTrackQuery(data) {
|
|
109
|
+
return typeof data === "object" && !("info" in data) && typeof data.title === "string";
|
|
110
|
+
}
|
|
111
|
+
async getClosestTrack(data, player) {
|
|
112
|
+
return getClosestTrack(data, player, this);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Builds a UnresolvedTrack to be resolved before being played .
|
|
116
|
+
* @param query
|
|
117
|
+
* @param requester
|
|
118
|
+
*/
|
|
119
|
+
buildUnresolvedTrack(query, requester) {
|
|
120
|
+
if (typeof query === "undefined")
|
|
121
|
+
throw new RangeError('Argument "query" must be present.');
|
|
122
|
+
const unresolvedTrack = {
|
|
123
|
+
encoded: query.encoded || undefined,
|
|
124
|
+
info: query.info ?? query,
|
|
125
|
+
requester: typeof this.manager.options?.playerOptions?.requesterTransformer === "function" ? this.manager.options?.playerOptions?.requesterTransformer((query?.requester || requester)) : requester,
|
|
126
|
+
async resolve(player) {
|
|
127
|
+
const closest = await getClosestTrack(this, player, player.LavalinkManager.utils);
|
|
128
|
+
if (!closest)
|
|
129
|
+
throw new SyntaxError("No closest Track found");
|
|
130
|
+
Object.getOwnPropertyNames(this).forEach(prop => delete this[prop]);
|
|
131
|
+
Object.assign(this, closest);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
Object.defineProperty(unresolvedTrack, UnresolvedTrackSymbol, { configurable: true, value: true });
|
|
136
|
+
return unresolvedTrack;
|
|
137
|
+
}
|
|
49
138
|
validatedQuery(queryString, node) {
|
|
50
139
|
if (!node.info)
|
|
51
140
|
throw new Error("No Lavalink Node was provided");
|
|
@@ -148,6 +237,10 @@ export class MiniMap extends Map {
|
|
|
148
237
|
}
|
|
149
238
|
return results;
|
|
150
239
|
}
|
|
240
|
+
toJSON() {
|
|
241
|
+
// toJSON is called recursively by JSON.stringify.
|
|
242
|
+
return [...this.values()];
|
|
243
|
+
}
|
|
151
244
|
map(fn, thisArg) {
|
|
152
245
|
if (typeof thisArg !== 'undefined')
|
|
153
246
|
fn = fn.bind(thisArg);
|
|
@@ -159,19 +252,49 @@ export class MiniMap extends Map {
|
|
|
159
252
|
});
|
|
160
253
|
}
|
|
161
254
|
}
|
|
162
|
-
export async function queueTrackEnd(
|
|
163
|
-
if (queue.current) { // if there was a current Track -> Add it
|
|
164
|
-
queue.previous.unshift(queue.current);
|
|
165
|
-
if (queue.previous.length > queue.options.maxPreviousTracks)
|
|
166
|
-
queue.previous.splice(queue.options.maxPreviousTracks, queue.previous.length);
|
|
255
|
+
export async function queueTrackEnd(player) {
|
|
256
|
+
if (player.queue.current) { // if there was a current Track -> Add it
|
|
257
|
+
player.queue.previous.unshift(player.queue.current);
|
|
258
|
+
if (player.queue.previous.length > player.queue.options.maxPreviousTracks)
|
|
259
|
+
player.queue.previous.splice(player.queue.options.maxPreviousTracks, player.queue.previous.length);
|
|
167
260
|
}
|
|
168
|
-
// change the current Track to the next upcoming one
|
|
169
|
-
queue.current = queue.tracks.shift() || null;
|
|
170
261
|
// and if repeatMode == queue, add it back to the queue!
|
|
171
|
-
if (
|
|
172
|
-
queue.tracks.push(queue.current);
|
|
262
|
+
if (player.repeatMode === "queue" && player.queue.current)
|
|
263
|
+
player.queue.tracks.push(player.queue.current);
|
|
264
|
+
// change the current Track to the next upcoming one
|
|
265
|
+
const nextSong = player.queue.tracks.shift();
|
|
266
|
+
if (player.LavalinkManager.utils.isUnresolvedTrack(nextSong))
|
|
267
|
+
await nextSong.resolve(player);
|
|
268
|
+
player.queue.current = nextSong || null;
|
|
173
269
|
// save it in the DB
|
|
174
|
-
await queue.utils.save();
|
|
270
|
+
await player.queue.utils.save();
|
|
175
271
|
// return the new current Track
|
|
176
|
-
return queue.current;
|
|
272
|
+
return player.queue.current;
|
|
273
|
+
}
|
|
274
|
+
async function getClosestTrack(data, player, utils) {
|
|
275
|
+
if (!player || !player.node)
|
|
276
|
+
throw new RangeError("No player with a lavalink node was provided");
|
|
277
|
+
if (utils.isTrack(data))
|
|
278
|
+
return utils.buildTrack(data, data.requester);
|
|
279
|
+
if (!utils.isUnresolvedTrack(data))
|
|
280
|
+
throw new RangeError("Track is not an unresolved Track");
|
|
281
|
+
if (!data?.info?.title)
|
|
282
|
+
throw new SyntaxError("the track title is required for unresolved tracks");
|
|
283
|
+
if (!data.requester)
|
|
284
|
+
throw new SyntaxError("The requester is required");
|
|
285
|
+
if (typeof data.encoded === "string") {
|
|
286
|
+
const r = await player.node.decode.singleTrack(data.encoded);
|
|
287
|
+
if (r)
|
|
288
|
+
return utils.buildTrack(r, data.requester);
|
|
289
|
+
}
|
|
290
|
+
if (typeof data.info.uri === "string") {
|
|
291
|
+
const r = await player.search({ query: data?.info?.uri }, data.requester).then(v => v.tracks[0]);
|
|
292
|
+
if (r)
|
|
293
|
+
return r;
|
|
294
|
+
}
|
|
295
|
+
const query = [data.info?.title, data.info?.author].filter(str => !!str).join(" by ");
|
|
296
|
+
const sourceName = data.info?.sourceName;
|
|
297
|
+
return await player.search({
|
|
298
|
+
query, source: sourceName !== "bandcamp" && sourceName !== "twitch" && sourceName !== "flowery-tts" ? sourceName : player.LavalinkManager.options?.playerOptions?.defaultSearchPlatform,
|
|
299
|
+
}, data.requester).then(v => v.tracks[0]);
|
|
177
300
|
}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { EventEmitter } from "events";
|
|
3
3
|
import { NodeManager } from "./NodeManager";
|
|
4
|
-
import {
|
|
4
|
+
import { QueueSaverOptions } from "./Queue";
|
|
5
5
|
import { GuildShardPayload, LavalinkSearchPlatform, ManagerUitls, MiniMap, SearchPlatform, TrackEndEvent, TrackExceptionEvent, TrackStartEvent, TrackStuckEvent, VoicePacket, VoiceServer, VoiceState, WebSocketClosedEvent } from "./Utils";
|
|
6
6
|
import { LavalinkNodeOptions } from "./Node";
|
|
7
7
|
import { DestroyReasonsType, Player, PlayerOptions } from "./Player";
|
|
8
|
-
import { Track } from "./Track";
|
|
8
|
+
import { Track, UnresolvedTrack } from "./Track";
|
|
9
9
|
export interface LavalinkManager {
|
|
10
10
|
nodeManager: NodeManager;
|
|
11
11
|
utils: ManagerUitls;
|
|
12
12
|
}
|
|
13
13
|
export interface BotClientOptions {
|
|
14
|
-
shards?: number | number[] | "auto";
|
|
15
14
|
id: string;
|
|
16
15
|
username?: string;
|
|
17
16
|
/** So users can pass entire objects / classes */
|
|
@@ -44,8 +43,6 @@ export interface LavalinkPlayerOptions {
|
|
|
44
43
|
export interface ManagerOptions {
|
|
45
44
|
nodes: LavalinkNodeOptions[];
|
|
46
45
|
queueOptions?: QueueSaverOptions;
|
|
47
|
-
queueStore?: StoreManager;
|
|
48
|
-
queueChangesWatcher?: QueueChangesWatcher;
|
|
49
46
|
client?: BotClientOptions;
|
|
50
47
|
playerOptions?: LavalinkPlayerOptions;
|
|
51
48
|
autoSkip?: boolean;
|
|
@@ -55,32 +52,32 @@ export interface ManagerOptions {
|
|
|
55
52
|
interface LavalinkManagerEvents {
|
|
56
53
|
/**
|
|
57
54
|
* Emitted when a Track started playing.
|
|
58
|
-
* @event Manager
|
|
55
|
+
* @event Manager#trackStart
|
|
59
56
|
*/
|
|
60
57
|
"trackStart": (player: Player, track: Track, payload: TrackStartEvent) => void;
|
|
61
58
|
/**
|
|
62
59
|
* Emitted when a Track finished.
|
|
63
|
-
* @event Manager
|
|
60
|
+
* @event Manager#trackEnd
|
|
64
61
|
*/
|
|
65
62
|
"trackEnd": (player: Player, track: Track, payload: TrackEndEvent) => void;
|
|
66
63
|
/**
|
|
67
64
|
* Emitted when a Track got stuck while playing.
|
|
68
|
-
* @event Manager
|
|
65
|
+
* @event Manager#trackStuck
|
|
69
66
|
*/
|
|
70
67
|
"trackStuck": (player: Player, track: Track, payload: TrackStuckEvent) => void;
|
|
71
68
|
/**
|
|
72
69
|
* Emitted when a Track errored.
|
|
73
|
-
* @event Manager
|
|
70
|
+
* @event Manager#trackError
|
|
74
71
|
*/
|
|
75
|
-
"trackError": (player: Player, track: Track, payload: TrackExceptionEvent) => void;
|
|
72
|
+
"trackError": (player: Player, track: Track | UnresolvedTrack, payload: TrackExceptionEvent) => void;
|
|
76
73
|
/**
|
|
77
74
|
* Emitted when the Playing finished and no more tracks in the queue.
|
|
78
|
-
* @event Manager
|
|
75
|
+
* @event Manager#queueEnd
|
|
79
76
|
*/
|
|
80
77
|
"queueEnd": (player: Player, track: Track, payload: TrackEndEvent | TrackStuckEvent | TrackExceptionEvent) => void;
|
|
81
78
|
/**
|
|
82
79
|
* Emitted when a Player is created.
|
|
83
|
-
* @event Manager
|
|
80
|
+
* @event Manager#playerCreate
|
|
84
81
|
*/
|
|
85
82
|
"playerCreate": (player: Player) => void;
|
|
86
83
|
/**
|
|
@@ -90,19 +87,24 @@ interface LavalinkManagerEvents {
|
|
|
90
87
|
"playerMove": (player: Player, oldVoiceChannelId: string, newVoiceChannelId: string) => void;
|
|
91
88
|
/**
|
|
92
89
|
* Emitted when a Player is disconnected from a channel.
|
|
93
|
-
* @event Manager
|
|
90
|
+
* @event Manager#playerDisconnect
|
|
94
91
|
*/
|
|
95
92
|
"playerDisconnect": (player: Player, voiceChannelId: string) => void;
|
|
96
93
|
/**
|
|
97
94
|
* Emitted when a Node-Socket got closed for a specific Player.
|
|
98
|
-
* @event Manager
|
|
95
|
+
* @event Manager#playerSocketClosed
|
|
99
96
|
*/
|
|
100
97
|
"playerSocketClosed": (player: Player, payload: WebSocketClosedEvent) => void;
|
|
101
98
|
/**
|
|
102
99
|
* Emitted when a Player get's destroyed
|
|
103
|
-
* @event Manager
|
|
100
|
+
* @event Manager#playerDestroy
|
|
104
101
|
*/
|
|
105
102
|
"playerDestroy": (player: Player, destroyReason?: DestroyReasonsType) => void;
|
|
103
|
+
/**
|
|
104
|
+
* Always emits when the player (on lavalink side) got updated
|
|
105
|
+
* @event Manager#playerUpdate
|
|
106
|
+
*/
|
|
107
|
+
"playerUpdate": (player: Player) => void;
|
|
106
108
|
}
|
|
107
109
|
export interface LavalinkManager {
|
|
108
110
|
options: ManagerOptions;
|
|
@@ -55,7 +55,7 @@ export declare class NodeManager extends EventEmitter {
|
|
|
55
55
|
nodes: MiniMap<string, LavalinkNode>;
|
|
56
56
|
constructor(LavalinkManager: LavalinkManager);
|
|
57
57
|
createNode(options: LavalinkNodeOptions): LavalinkNode;
|
|
58
|
-
|
|
58
|
+
leastUsedNodes(sortType?: "memory" | "cpuLavalink" | "cpuSystem" | "calls" | "playingPlayers" | "players"): LavalinkNode[];
|
|
59
59
|
deleteNode(node: LavalinkNodeIdentifier | LavalinkNode): void;
|
|
60
60
|
}
|
|
61
61
|
export {};
|
|
@@ -110,7 +110,7 @@ export declare class Player {
|
|
|
110
110
|
* Play the next track from the queue / a specific track, with playoptions for Lavalink
|
|
111
111
|
* @param options
|
|
112
112
|
*/
|
|
113
|
-
play(options?: Partial<PlayOptions>):
|
|
113
|
+
play(options?: Partial<PlayOptions>): any;
|
|
114
114
|
/**
|
|
115
115
|
* Set the Volume for the Player
|
|
116
116
|
* @param volume The Volume in percent
|
|
@@ -143,12 +143,12 @@ export declare class Player {
|
|
|
143
143
|
* Set the Repeatmode of the Player
|
|
144
144
|
* @param repeatMode
|
|
145
145
|
*/
|
|
146
|
-
setRepeatMode(repeatMode: RepeatMode): Promise<
|
|
146
|
+
setRepeatMode(repeatMode: RepeatMode): Promise<RepeatMode>;
|
|
147
147
|
/**
|
|
148
148
|
* Skip the current song, or a specific amount of songs
|
|
149
149
|
* @param amount provide the index of the next track to skip to
|
|
150
150
|
*/
|
|
151
|
-
skip(skipTo?: number): Promise<
|
|
151
|
+
skip(skipTo?: number): Promise<any>;
|
|
152
152
|
/**
|
|
153
153
|
* Connects the Player to the Voice Channel
|
|
154
154
|
* @returns
|
|
@@ -172,6 +172,7 @@ export declare class Player {
|
|
|
172
172
|
/** Converts the Player including Queue to a Json state */
|
|
173
173
|
toJSON(): {
|
|
174
174
|
guildId: string;
|
|
175
|
+
options: PlayerOptions;
|
|
175
176
|
voiceChannelId: string;
|
|
176
177
|
textChannelId: string;
|
|
177
178
|
position: number;
|
|
@@ -184,7 +185,6 @@ export declare class Player {
|
|
|
184
185
|
createdTimeStamp: number;
|
|
185
186
|
filters: {};
|
|
186
187
|
equalizer: import("./Filters").EQBand[];
|
|
187
|
-
queue: import("./Queue").StoredQueue;
|
|
188
188
|
nodeId: string;
|
|
189
189
|
};
|
|
190
190
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Track } from "./Track";
|
|
1
|
+
import { Track, UnresolvedTrack } from "./Track";
|
|
2
2
|
export interface StoredQueue {
|
|
3
3
|
current: Track | null;
|
|
4
4
|
previous: Track[];
|
|
@@ -18,6 +18,8 @@ export interface StoreManager extends Record<any, any> {
|
|
|
18
18
|
}
|
|
19
19
|
export interface QueueSaverOptions {
|
|
20
20
|
maxPreviousTracks: number;
|
|
21
|
+
queueStore?: StoreManager;
|
|
22
|
+
queueChangesWatcher?: QueueChangesWatcher;
|
|
21
23
|
}
|
|
22
24
|
export interface QueueSaver {
|
|
23
25
|
/** @private */
|
|
@@ -26,7 +28,7 @@ export interface QueueSaver {
|
|
|
26
28
|
options: QueueSaverOptions;
|
|
27
29
|
}
|
|
28
30
|
export declare class QueueSaver {
|
|
29
|
-
constructor(
|
|
31
|
+
constructor(options: QueueSaverOptions);
|
|
30
32
|
get(guildId: string): Promise<Partial<StoredQueue>>;
|
|
31
33
|
delete(guildId: string): Promise<any>;
|
|
32
34
|
set(guildId: string, value: any): Promise<any>;
|
|
@@ -43,23 +45,23 @@ export declare class DefaultQueueStore {
|
|
|
43
45
|
}
|
|
44
46
|
export declare class QueueChangesWatcher {
|
|
45
47
|
constructor();
|
|
46
|
-
tracksAdd(guildId: string, tracks: Track[], position: number, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
|
|
47
|
-
tracksRemoved(guildId: string, tracks: Track[], position: number, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
|
|
48
|
+
tracksAdd(guildId: string, tracks: (Track | UnresolvedTrack)[], position: number, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
|
|
49
|
+
tracksRemoved(guildId: string, tracks: (Track | UnresolvedTrack)[], position: number, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
|
|
48
50
|
shuffled(guildId: string, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
|
|
49
51
|
}
|
|
50
52
|
export declare class Queue {
|
|
51
|
-
readonly tracks: Track[];
|
|
53
|
+
readonly tracks: (Track | UnresolvedTrack)[];
|
|
52
54
|
readonly previous: Track[];
|
|
53
55
|
current: Track | null;
|
|
54
56
|
options: {
|
|
55
57
|
maxPreviousTracks: number;
|
|
56
58
|
};
|
|
57
59
|
private readonly guildId;
|
|
58
|
-
|
|
59
|
-
static readonly StaticSymbol: Symbol;
|
|
60
|
+
private readonly QueueSaver;
|
|
60
61
|
private managerUtils;
|
|
61
62
|
private queueChanges;
|
|
62
|
-
constructor(guildId: string, data?: Partial<StoredQueue>, QueueSaver?: QueueSaver,
|
|
63
|
+
constructor(guildId: string, data?: Partial<StoredQueue>, QueueSaver?: QueueSaver, queueOptions?: QueueSaverOptions);
|
|
64
|
+
private applyData;
|
|
63
65
|
/**
|
|
64
66
|
* Utils for a Queue
|
|
65
67
|
*/
|
|
@@ -77,7 +79,7 @@ export declare class Queue {
|
|
|
77
79
|
/**
|
|
78
80
|
* @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the storeManager
|
|
79
81
|
*/
|
|
80
|
-
|
|
82
|
+
toJSON: () => StoredQueue;
|
|
81
83
|
/**
|
|
82
84
|
* Get the Total Duration of the Queue-Songs summed up
|
|
83
85
|
* @returns {number}
|
|
@@ -95,7 +97,7 @@ export declare class Queue {
|
|
|
95
97
|
* @param {number} index At what position to add the Track
|
|
96
98
|
* @returns {number} Queue-Size (for the next Tracks)
|
|
97
99
|
*/
|
|
98
|
-
add(TrackOrTracks: Track | Track[], index?: number): any;
|
|
100
|
+
add(TrackOrTracks: Track | UnresolvedTrack | (Track | UnresolvedTrack)[], index?: number): any;
|
|
99
101
|
/**
|
|
100
102
|
* Splice the tracks in the Queue
|
|
101
103
|
* @param {number} index Where to remove the Track
|
|
@@ -103,5 +105,5 @@ export declare class Queue {
|
|
|
103
105
|
* @param {Track | Track[]} TrackOrTracks Want to Add more Tracks?
|
|
104
106
|
* @returns {Track} Spliced Track
|
|
105
107
|
*/
|
|
106
|
-
splice(index: number, amount: number, TrackOrTracks?: Track | Track[]): any;
|
|
108
|
+
splice(index: number, amount: number, TrackOrTracks?: Track | UnresolvedTrack | (Track | UnresolvedTrack)[]): any;
|
|
107
109
|
}
|