magmastream
Version:
A user-friendly Lavalink client designed for NodeJS.
1,765 lines (1,758 loc) • 142 kB
TypeScript
import { Collection } from '@discordjs/collection';
import { GatewayVoiceStateUpdate } from 'discord-api-types/v10';
import { EventEmitter } from 'events';
import { User, ClientUser, Guild, Message, Client as Client$1 } from 'discord.js';
import { User as User$1, Guild as Guild$1, Message as Message$1, Client as Client$3 } from 'oceanic.js';
import { User as User$2, Guild as Guild$2, Message as Message$2, Bot } from '@discordeno/bot';
import { User as User$3, Guild as Guild$3, Message as Message$3, Client as Client$2 } from 'eris';
import { User as User$4, ClientUser as ClientUser$1, Guild as Guild$4, Message as Message$4, Client as Client$4, WorkerClient } from 'seyfert';
import { RedisOptions, Redis } from 'ioredis';
import WebSocket$1, { WebSocket } from 'ws';
import { Client } from 'cloudstorm';
/** Represents an equalizer band. */
interface Band {
/** The index of the equalizer band (0-12). */
band: number;
/** The gain value of the equalizer band (in decibels). */
gain: number;
}
/**
* State Storage Enum
*/
declare enum StateStorageType {
Memory = "memory",
Redis = "redis",
JSON = "json"
}
/**
* AutoPlay Platform Enum
*/
declare enum AutoPlayPlatform {
Spotify = "spotify",
Deezer = "deezer",
SoundCloud = "soundcloud",
Tidal = "tidal",
VKMusic = "vkmusic",
Qobuz = "qobuz",
Yandex = "yandex",
YouTube = "youtube"
}
/**
* State Types Enum
*/
declare enum StateTypes {
Connected = "CONNECTED",
Connecting = "CONNECTING",
Disconnected = "DISCONNECTED",
Disconnecting = "DISCONNECTING",
Destroying = "DESTROYING"
}
/**
* Load Types Enum
*/
declare enum LoadTypes {
Track = "track",
Playlist = "playlist",
Search = "search",
Empty = "empty",
Error = "error",
/** Nodelink */
Album = "album",
/** Nodelink */
Artist = "artist",
/** Nodelink */
Station = "station",
/** Nodelink */
Podcast = "podcast",
/** Nodelink */
Show = "show",
/** Nodelink */
Short = "short"
}
/**
* Search Platform Enum
*/
declare enum SearchPlatform {
AppleMusic = "amsearch",
Yandex = "ymsearch",
Audius = "audsearch",
Bandcamp = "bcsearch",
Deezer = "dzsearch",
Jiosaavn = "jssearch",
Qobuz = "qbsearch",
SoundCloud = "scsearch",
Spotify = "spsearch",
Tidal = "tdsearch",
TTS = "speak",
VKMusic = "vksearch",
YouTube = "ytsearch",
YouTubeMusic = "ytmsearch"
}
/**
* Player State Event Types Enum
*/
declare enum PlayerStateEventTypes {
AutoPlayChange = "playerAutoplay",
ConnectionChange = "playerConnection",
RepeatChange = "playerRepeat",
PauseChange = "playerPause",
QueueChange = "queueChange",
TrackChange = "trackChange",
VolumeChange = "volumeChange",
ChannelChange = "channelChange",
PlayerCreate = "playerCreate",
PlayerDestroy = "playerDestroy",
FilterChange = "filterChange"
}
/**
* Track Source Types Enum
*/
declare enum TrackSourceTypes {
AppleMusic = "AppleMusic",
Audius = "Audius",
Bandcamp = "Bandcamp",
Deezer = "Deezer",
Jiosaavn = "Jiosaavn",
Qobuz = "Qobuz",
SoundCloud = "SoundCloud",
Spotify = "Spotify",
Tidal = "Tidal",
VKMusic = "VKMusic",
YouTube = "YouTube",
Pornhub = "Pornub",
TikTok = "TikTok",
Flowertts = "Flowertts",
Ocremix = "Ocremix",
Yandex = "Yandex",
Mixcloud = "Mixcloud",
Soundgasm = "Soundgasm",
Reddit = "Reddit",
Clypit = "Clypit",
Http = "Http",
Tts = "Tts"
}
/**
* Use Node Options Enum
*/
declare enum UseNodeOptions {
LeastLoad = "leastLoad",
LeastPlayers = "leastPlayers"
}
/**
* Track Partial Enum
*/
declare enum TrackPartial {
/** The base64 encoded string of the track */
Track = "track",
/** The title of the track */
Title = "title",
/** The track identifier */
Identifier = "identifier",
/** The author of the track */
Author = "author",
/** The length of the track in milliseconds */
Duration = "duration",
/** The ISRC of the track */
Isrc = "isrc",
/** Whether the track is seekable */
IsSeekable = "isSeekable",
/** Whether the track is a stream */
IsStream = "isStream",
/** The URI of the track */
Uri = "uri",
/** The artwork URL of the track */
ArtworkUrl = "artworkUrl",
/** The source name of the track */
SourceName = "sourceName",
/** The thumbnail of the track */
ThumbNail = "thumbnail",
/** The requester of the track */
Requester = "requester",
/** The plugin info of the track */
PluginInfo = "pluginInfo",
/** The custom data of the track */
CustomData = "customData",
/** Whether the track got autoplayed */
IsAutoPlay = "isAutoplay"
}
/**
* Manager Event Types Enum
*/
declare enum ManagerEventTypes {
ChapterStarted = "chapterStarted",
ChaptersLoaded = "chaptersLoaded",
Debug = "debug",
LyricsFound = "lyricsFound",
LyricsLine = "lyricsLine",
LyricsNotFound = "lyricsNotFound",
NodeConnect = "nodeConnect",
NodeCreate = "nodeCreate",
NodeDestroy = "nodeDestroy",
NodeDisconnect = "nodeDisconnect",
NodeError = "nodeError",
NodeRaw = "nodeRaw",
NodeReconnect = "nodeReconnect",
PlayerCreate = "playerCreate",
PlayerDestroy = "playerDestroy",
PlayerDisconnect = "playerDisconnect",
PlayerMove = "playerMove",
PlayerRestored = "playerRestored",
PlayerStateUpdate = "playerStateUpdate",
QueueEnd = "queueEnd",
RestoreComplete = "restoreComplete",
SegmentSkipped = "segmentSkipped",
SegmentsLoaded = "segmentsLoaded",
SocketClosed = "socketClosed",
TrackEnd = "trackEnd",
TrackError = "trackError",
TrackStart = "trackStart",
TrackStuck = "trackStuck",
/** Nodelink */
VoiceReceiverDisconnect = "voiceReceiverDisconnect",
/** Nodelink */
VoiceReceiverConnect = "voiceReceiverConnect",
/** Nodelink */
VoiceReceiverError = "voiceReceiverError",
/** Nodelink */
VoiceReceiverStartSpeaking = "voiceReceiverStartSpeaking",
/** Nodelink */
VoiceReceiverEndSpeaking = "voiceReceiverEndSpeaking"
}
/**
* Track End Reason Enum
*/
declare enum TrackEndReasonTypes {
Finished = "finished",
LoadFailed = "loadFailed",
Stopped = "stopped",
Replaced = "replaced",
Cleanup = "cleanup"
}
/**
* Severity Types Enum
*/
declare enum SeverityTypes {
Common = "common",
Suspicious = "suspicious",
Fault = "fault"
}
/**
* SponsorBlock Segment Enum
*/
declare enum SponsorBlockSegment {
Filler = "filler",
Interaction = "interaction",
Intro = "intro",
MusicOfftopic = "music_offtopic",
Outro = "outro",
Preview = "preview",
SelfPromo = "selfpromo",
Sponsor = "sponsor"
}
/**
* Available Filters Enum
*/
declare enum AvailableFilters {
BassBoost = "bassboost",
China = "china",
Chipmunk = "chipmunk",
Darthvader = "darthvader",
Daycore = "daycore",
Demon = "demon",
Distort = "distort",
Doubletime = "doubletime",
Earrape = "earrape",
EightD = "eightD",
Electronic = "electronic",
Nightcore = "nightcore",
Party = "party",
Pop = "pop",
Radio = "radio",
SetDistortion = "setDistortion",
SetKaraoke = "setKaraoke",
SetRotation = "setRotation",
SetTimescale = "setTimescale",
Slowmo = "slowmo",
Soft = "soft",
TrebleBass = "trebleBass",
Tremolo = "tremolo",
TV = "tv",
Vaporwave = "vaporwave",
Vibrato = "vibrato"
}
/**
* MagmaStream Error Codes Enum
*/
declare enum MagmaStreamErrorCode {
GENERAL_UNKNOWN = "MS_GENERAL_UNKNOWN",
GENERAL_TIMEOUT = "MS_GENERAL_TIMEOUT",
GENERAL_INVALID_MANAGER = "MS_GENERAL_INVALID_MANAGER",
INTENT_MISSING = "MS_INTENT_MISSING",
MANAGER_INIT_FAILED = "MS_MANAGER_INIT_FAILED",
MANAGER_INVALID_CONFIG = "MS_MANAGER_INVALID_CONFIG",
MANAGER_SHUTDOWN_FAILED = "MS_MANAGER_SHUTDOWN_FAILED",
MANAGER_NO_NODES = "MS_MANAGER_NO_NODES",
MANAGER_NODE_NOT_FOUND = "MS_MANAGER_NODE_NOT_FOUND",
MANAGER_SEARCH_FAILED = "MS_MANAGER_SEARCH_FAILED",
MANAGER_CLEANUP_INACTIVE_PLAYERS_FAILED = "MS_MANAGER_CLEANUP_INACTIVE_PLAYERS_FAILED",
NODE_INVALID_CONFIG = "MS_NODE_INVALID_CONFIG",
NODE_CONNECT_FAILED = "MS_NODE_CONNECT_FAILED",
NODE_RECONNECT_FAILED = "MS_NODE_RECONNECT_FAILED",
NODE_DISCONNECTED = "MS_NODE_DISCONNECTED",
NODE_PROTOCOL_ERROR = "MS_NODE_PROTOCOL_ERROR",
NODE_SESSION_IDS_LOAD_FAILED = "MS_NODE_SESSION_IDS_LOAD_FAILED",
NODE_SESSION_IDS_UPDATE_FAILED = "MS_NODE_SESSION_IDS_UPDATE_FAILED",
NODE_PLUGIN_ERROR = "MS_NODE_PLUGIN_ERROR",
PLAYER_INVALID_CONFIG = "MS_PLAYER_INVALID_CONFIG",
PLAYER_STATE_INVALID = "MS_PLAYER_STATE_INVALID",
PLAYER_QUEUE_EMPTY = "MS_PLAYER_QUEUE_EMPTY",
PLAYER_PREVIOUS_EMPTY = "MS_PLAYER_PREVIOUS_EMPTY",
PLAYER_INVALID_NOW_PLAYING_MESSAGE = "MS_PLAYER_INVALID_NOW_PLAYING_MESSAGE",
PLAYER_INVALID_AUTOPLAY = "MS_PLAYER_INVALID_AUTOPLAY",
PLAYER_INVALID_VOLUME = "MS_PLAYER_INVALID_VOLUME",
PLAYER_INVALID_REPEAT = "MS_PLAYER_INVALID_REPEAT",
PLAYER_INVALID_PAUSE = "MS_PLAYER_INVALID_PAUSE",
PLAYER_INVALID_SEEK = "MS_PLAYER_INVALID_SEEK",
PLAYER_MOVE_FAILED = "MS_PLAYER_MOVE_FAILED",
PLAYER_VOICE_RECEIVER_ERROR = "MS_PLAYER_VOICE_RECEIVER_ERROR",
QUEUE_REDIS_ERROR = "MS_QUEUE_REDIS_ERROR",
QUEUE_JSON_ERROR = "MS_QUEUE_JSON_ERROR",
QUEUE_MEMORY_ERROR = "MS_QUEUE_MEMORY_ERROR",
FILTER_APPLY_FAILED = "MS_FILTER_APPLY_FAILED",
REST_REQUEST_FAILED = "MS_REST_REQUEST_FAILED",
REST_UNAUTHORIZED = "MS_REST_UNAUTHORIZED",
UTILS_TRACK_PARTIAL_INVALID = "MS_UTILS_TRACK_PARTIAL_INVALID",
UTILS_TRACK_BUILD_FAILED = "MS_UTILS_TRACK_BUILD_FAILED",
UTILS_AUTOPLAY_BUILD_FAILED = "MS_UTILS_AUTOPLAY_BUILD_FAILED",
UTILS_PLAYER_SERIALIZE_FAILED = "MS_UTILS_PLAYER_SERIALIZE_FAILED",
PLUGIN_LOAD_FAILED = "MS_PLUGIN_LOAD_FAILED",
PLUGIN_RUNTIME_ERROR = "MS_PLUGIN_RUNTIME_ERROR"
}
declare const MagmaStreamErrorNumbers: Record<MagmaStreamErrorCode, number>;
/**
* The player's queue, the `current` property is the currently playing track, think of the rest as the up-coming tracks.
*/
declare class JsonQueue implements IQueue {
readonly guildId: string;
readonly manager: Manager;
/**
* The base path for the queue files.
*/
private basePath;
/**
* Whether the queue has been destroyed.
*/
private destroyed;
/**
* @param guildId The guild ID.
* @param manager The manager.
*/
constructor(guildId: string, manager: Manager);
/**
* @param track The track or tracks to add. Can be a single `Track` or an array of `Track`s.
* @param [offset=null] The position to add the track(s) at. If not provided, the track(s) will be added at the end of the queue.
*/
add(track: Track | Track[], offset?: number): Promise<void>;
/**
* @param track The track to add.
*/
addPrevious(track: Track | Track[]): Promise<void>;
/**
* Clears the queue.
*/
clear(): Promise<void>;
/**
* Clears the previous tracks.
*/
clearPrevious(): Promise<void>;
/**
* Removes the first track from the queue.
*/
dequeue(): Promise<Track | undefined>;
/**
* Destroys the queue and releases all resources.
* After calling this method, the queue must not be used again.
*/
destroy(): Promise<void>;
/**
* @returns The total duration of the queue.
*/
duration(): Promise<number>;
/**
* Adds a track to the front of the queue.
*/
enqueueFront(track: Track | Track[]): Promise<void>;
/**
* Tests whether all elements in the queue pass the test implemented by the provided function.
*/
everyAsync(callback: (track: Track, index: number, array: Track[]) => boolean): Promise<boolean>;
/**
* Filters the queue.
*/
filterAsync(callback: (track: Track, index: number, array: Track[]) => boolean): Promise<Track[]>;
/**
* Finds the first track in the queue that satisfies the provided testing function.
*/
findAsync(callback: (track: Track, index: number, array: Track[]) => boolean): Promise<Track | undefined>;
/**
* @returns The current track.
*/
getCurrent(): Promise<Track | null>;
/**
* @returns The previous tracks.
*/
getPrevious(): Promise<Track[]>;
/**
* @returns The tracks in the queue from start to end.
*/
getSlice(start?: number, end?: number): Promise<Track[]>;
/**
* @returns The tracks in the queue.
*/
getTracks(): Promise<Track[]>;
/**
* Maps the queue to a new array.
*/
mapAsync<T>(callback: (track: Track, index: number, array: Track[]) => T): Promise<T[]>;
/**
* Modifies the queue at the specified index.
*/
modifyAt(start: number, deleteCount?: number, ...items: Track[]): Promise<Track[]>;
/**
* @returns The newest track.
*/
popPrevious(): Promise<Track | null>;
/**
* Removes a track from the queue.
* @param position The position to remove the track at.
* @param end The end position to remove the track at.
*/
remove(position?: number): Promise<Track[]>;
remove(start: number, end: number): Promise<Track[]>;
/**
* Shuffles the queue by round-robin.
*/
roundRobinShuffle(): Promise<void>;
/**
* @param track The track to set.
*/
setCurrent(track: Track | null): Promise<void>;
/**
* @param track The track to set.
*/
setPrevious(track: Track | Track[]): Promise<void>;
/**
* Shuffles the queue.
*/
shuffle(): Promise<void>;
/**
* @returns The size of the queue.
*/
size(): Promise<number>;
/**
* Tests whether at least one element in the queue passes the test implemented by the provided function.
*/
someAsync(callback: (track: Track, index: number, array: Track[]) => boolean): Promise<boolean>;
/**
* @returns The total size of the queue.
*/
totalSize(): Promise<number>;
/**
* Shuffles the queue by user.
*/
userBlockShuffle(): Promise<void>;
/**
* @returns The current path.
*/
private get currentPath();
/**
* @param filePath The file path.
*/
private deleteFile;
/**
* Ensures the directory exists.
*/
private ensureDir;
/**
* @returns The queue.
*/
private getQueue;
/**
* @returns The previous path.
*/
private get previousPath();
/**
* @returns The queue path.
*/
private get queuePath();
/**
* @param filePath The file path.
* @returns The JSON data.
*/
private readJSON;
/**
* @param queue The queue.
*/
private setQueue;
/**
* @param filePath The file path.
* @param data The data to write.
*/
private writeJSON;
}
/**
* The player's queue, the `current` property is the currently playing track, think of the rest as the up-coming tracks.
*/
declare class MemoryQueue extends Array<Track> implements IQueue {
/** The current track */
current: Track | null;
/** The previous tracks */
previous: Track[];
/** The Manager instance. */
manager: Manager;
/** The guild ID property. */
guildId: string;
/**
* Whether the queue has been destroyed.
*/
private destroyed;
/**
* Constructs a new Queue.
* @param guildId The guild ID.
* @param manager The Manager instance.
*/
constructor(guildId: string, manager: Manager);
/**
* Adds a track to the queue.
* @param track The track or tracks to add. Can be a single `Track` or an array of `Track`s.
* @param [offset=null] The position to add the track(s) at. If not provided, the track(s) will be added at the end of the queue.
*/
add(track: Track | Track[], offset?: number): void;
/**
* Adds a track to the previous tracks.
* @param track The track or tracks to add. Can be a single `Track` or an array of `Track`s.
*/
addPrevious(track: Track | Track[]): void;
/**
* Clears the queue.
* This will remove all tracks from the queue and emit a state update event.
*/
clear(): void;
/**
* Clears the previous tracks.
*/
clearPrevious(): void;
/**
* Removes the first element from the queue.
*/
dequeue(): Track | undefined;
/**
* Destroys the queue and releases all resources.
* After calling this method, the queue must not be used again.
*/
destroy(): void;
/**
* The total duration of the queue in milliseconds.
* This includes the duration of the currently playing track.
*/
duration(): number;
/**
* Adds the specified track or tracks to the front of the queue.
* @param track The track or tracks to add.
*/
enqueueFront(track: Track | Track[]): void;
/**
* @returns Whether all elements in the queue satisfy the provided testing function.
*/
everyAsync(callback: (track: Track, index: number, array: Track[]) => boolean): boolean;
/**
* @returns A new array with all elements that pass the test implemented by the provided function.
*/
filterAsync(callback: (track: Track, index: number, array: Track[]) => boolean): Track[];
/**
* @returns The first element in the queue that satisfies the provided testing function.
*/
findAsync(callback: (track: Track, index: number, array: Track[]) => boolean): Track | undefined;
/**
* @returns The current track.
*/
getCurrent(): Track | null;
/**
* @returns The previous tracks.
*/
getPrevious(): Track[];
/**
* @returns The tracks in the queue from start to end.
*/
getSlice(start?: number, end?: number): Track[];
/**
* @returns The tracks in the queue.
*/
getTracks(): Track[];
/**
* @returns A new array with the results of calling a provided function on every element in the queue.
*/
mapAsync<T>(callback: (track: Track, index: number, array: Track[]) => T): T[];
/**
* Modifies the queue at the specified index.
* @param start The index at which to start modifying the queue.
* @param deleteCount The number of elements to remove from the queue.
* @param items The elements to add to the queue.
* @returns The modified queue.
*/
modifyAt(start: number, deleteCount?: number, ...items: Track[]): Track[];
/**
* @returns The newest track.
*/
popPrevious(): Track | null;
/**
* Removes track(s) from the queue.
* @param startOrPosition If a single number is provided, it will be treated as the position of the track to remove.
* If two numbers are provided, they will be used as the start and end of a range of tracks to remove.
* @param end Optional, end of the range of tracks to remove.
* @returns The removed track(s).
*/
remove(position?: number): Track[];
remove(start: number, end: number): Track[];
/**
* Shuffles the queue to play tracks requested by each user one by one.
*/
roundRobinShuffle(): void;
/**
* @param track The track to set.
*/
setCurrent(track: Track | null): void;
/**
* @param tracks The tracks to set.
*/
setPrevious(tracks: Track[]): void;
/**
* Shuffles the queue.
* This will randomize the order of the tracks in the queue and emit a state update event.
*/
shuffle(): void;
/**
* The size of tracks in the queue.
* This does not include the currently playing track.
* @returns The size of tracks in the queue.
*/
size(): number;
/**
* @returns Whether at least one element in the queue satisfies the provided testing function.
*/
someAsync(callback: (track: Track, index: number, array: Track[]) => boolean): boolean;
/**
* The total size of tracks in the queue including the current track.
* This includes the current track if it is not null.
* @returns The total size of tracks in the queue including the current track.
*/
totalSize(): number;
/**
* Shuffles the queue to play tracks requested by each user one block at a time.
*/
userBlockShuffle(): void;
}
/**
* The player's queue, the `current` property is the currently playing track, think of the rest as the up-coming tracks.
*/
declare class RedisQueue implements IQueue {
readonly guildId: string;
readonly manager: Manager;
/**
* The prefix for the Redis keys.
*/
redisPrefix: string;
/**
* The Redis instance.
*/
private redis;
/**
* Whether the queue has been destroyed.
*/
private destroyed;
/**
* Constructs a new RedisQueue.
* @param guildId The guild ID.
* @param manager The Manager instance.
*/
constructor(guildId: string, manager: Manager);
/**
* Adds a track or tracks to the queue.
* @param track The track or tracks to add. Can be a single `Track` or an array of `Track`s.
* @param [offset=null] The position to add the track(s) at. If not provided, the track(s) will be added at the end of the queue.
*/
add(track: Track | Track[], offset?: number): Promise<void>;
/**
* Adds a track or tracks to the previous tracks.
* @param track The track or tracks to add.
*/
addPrevious(track: Track | Track[]): Promise<void>;
/**
* Clears the queue.
*/
clear(): Promise<void>;
/**
* Clears the previous tracks.
*/
clearPrevious(): Promise<void>;
/**
* Removes the first track from the queue.
*/
dequeue(): Promise<Track | undefined>;
/**
* Destroys the queue and releases all resources.
* After calling this method, the queue must not be used again.
*/
destroy(): Promise<void>;
/**
* @returns The total duration of the queue in milliseconds.
* This includes the duration of the currently playing track.
*/
duration(): Promise<number>;
/**
* Adds a track to the front of the queue.
* @param track The track or tracks to add.
*/
enqueueFront(track: Track | Track[]): Promise<void>;
/**
* Whether all tracks in the queue match the specified condition.
* @param callback The condition to match.
* @returns Whether all tracks in the queue match the specified condition.
*/
everyAsync(callback: (track: Track, index: number, array: Track[]) => boolean): Promise<boolean>;
/**
* Filters the tracks in the queue.
* @param callback The condition to match.
* @returns The tracks that match the condition.
*/
filterAsync(callback: (track: Track, index: number, array: Track[]) => boolean): Promise<Track[]>;
/**
* Finds the first track in the queue that matches the specified condition.
* @param callback The condition to match.
* @returns The first track that matches the condition.
*/
findAsync(callback: (track: Track, index: number, array: Track[]) => boolean): Promise<Track | undefined>;
/**
* @returns The current track.
*/
getCurrent(): Promise<Track | null>;
/**
* @returns The previous tracks.
*/
getPrevious(): Promise<Track[]>;
/**
* @returns The tracks in the queue from the start to the end.
*/
getSlice(start?: number, end?: number): Promise<Track[]>;
/**
* @returns The tracks in the queue.
*/
getTracks(): Promise<Track[]>;
/**
* Maps the tracks in the queue.
* @returns The tracks in the queue after the specified index.
*/
mapAsync<T>(callback: (track: Track, index: number, array: Track[]) => T): Promise<T[]>;
/**
* Modifies the queue at the specified index.
* @param start The start index.
* @param deleteCount The number of tracks to delete.
* @param items The tracks to insert.
* @returns The removed tracks.
*/
modifyAt(start: number, deleteCount?: number, ...items: Track[]): Promise<Track[]>;
/**
* Removes the newest track.
* @returns The newest track.
*/
popPrevious(): Promise<Track | null>;
/**
* Removes the track at the specified index.
* @param position The position to remove the track at.
* @param end The end position to remove the track at.
*/
remove(position?: number): Promise<Track[]>;
remove(start: number, end: number): Promise<Track[]>;
/**
* Shuffles the queue round-robin style.
*/
roundRobinShuffle(): Promise<void>;
/**
* Sets the current track.
* @param track The track to set.
*/
setCurrent(track: Track | null): Promise<void>;
/**
* Sets the previous track(s).
* @param track The track to set.
*/
setPrevious(track: Track | Track[]): Promise<void>;
/**
* Shuffles the queue.
*/
shuffle(): Promise<void>;
/**
* @returns The size of the queue.
*/
size(): Promise<number>;
/**
* @returns Whether any tracks in the queue match the specified condition.
*/
someAsync(callback: (track: Track, index: number, array: Track[]) => boolean): Promise<boolean>;
/**
* @returns The total size of tracks in the queue including the current track.
*/
totalSize(): Promise<number>;
/**
* Shuffles the queue, but keeps the tracks of the same user together.
*/
userBlockShuffle(): Promise<void>;
/**
* @returns The current key.
*/
private get currentKey();
/**
* Deserializes a track from a string.
*/
private deserialize;
/**
* @returns The previous key.
*/
private get previousKey();
/**
* @returns The queue key.
*/
private get queueKey();
/**
* Helper to serialize/deserialize Track
*/
private serialize;
}
/**
* Base abstract class for all plugins.
* Users must extend this and implement load and unload methods.
*/
declare abstract class Plugin {
readonly name: string;
/**
* @param name The name of the plugin
*/
constructor(name: string);
/**
* Load the plugin.
* @param manager The MagmaStream Manager instance
*/
abstract load(manager: Manager): void;
/**
* Unload the plugin.
* Called on shutdown to gracefully cleanup resources or detach listeners.
* @param manager The MagmaStream Manager instance
*/
abstract unload(manager: Manager): void;
}
/**
* Manager Options
*/
interface ManagerOptions {
/** The state storage options.
*
* @default { type: StateStorageType.Collection, deleteDestroyedPlayers: true }
*/
stateStorage?: StateStorageOptions;
/** Enable priority mode over least player count or load balancing?
* @default false
*/
enablePriorityMode?: boolean;
/** Automatically play the next track when the current one ends.
* @default true
*/
playNextOnEnd?: boolean;
/** An array of search platforms to use for autoplay. First to last matters
* Use enum `AutoPlayPlatform`.
* @default [AutoPlayPlatform.YouTube]
*/
autoPlaySearchPlatforms?: AutoPlayPlatform[];
/** The client ID to use. */
clientId?: string;
/** Value to use for the `Client-Name` header.
* @default "Magmastream"
*
* For NodeLink, leave it empty.
*/
clientName?: string;
/** The array of shard IDs connected to this manager instance.
* @default 0
*/
clusterId?: number;
/** List of plugins to load. */
enabledPlugins?: Plugin[];
/** The default search platform to use.
* Use enum `SearchPlatform`.
* @default SearchPlatform.YouTube
*/
defaultSearchPlatform?: SearchPlatform;
/** The last.fm API key.
* If you need to create one go here: https://www.last.fm/api/account/create.
* If you already have one, get it from here: https://www.last.fm/api/accounts. */
lastFmApiKey?: string;
/** The maximum number of previous tracks to store.
* @default 20
*/
maxPreviousTracks?: number;
/** The array of nodes to connect to. */
nodes?: NodeOptions[];
/** Whether the YouTube video titles should be replaced if the Author does not exactly match.
* @default false
*/
normalizeYouTubeTitles?: boolean;
/** An array of track properties to keep. `track` will always be present. */
trackPartial?: TrackPartial[];
/** Use the least amount of players or least load?
* Use enum `UseNodeOptions`.
* @default UseNodeOptions.LeastPlayers
*/
useNode?: UseNodeOptions.LeastLoad | UseNodeOptions.LeastPlayers;
/** Whether the manager should listen to SIGINT and SIGTERM events.
* @default true
*/
listenToSIGEvents?: boolean;
/**
* Function to send data to the websocket.
* @param id The ID of the node to send the data to.
* @param payload The payload to send.
*/
send?: (packet: DiscordPacket) => unknown;
/**
* User cache getter. Required when using `new Manager(...)` directly, optional for built-in wrappers.
* When resolving a user from a partial ID, this function will be called first.
* Should return the full user object if cached, or undefined if not.
* @param id The ID of the user to get.
* @returns The user object if cached, or undefined if not.
*/
getUser?: (id: string) => AnyUser | undefined;
/**
* Guild cache getter. Required when using `new Manager(...)` directly, optional for built-in wrappers.
* When resolving a guild from a partial ID, this function will be called first.
* Should return the full guild object if cached, or undefined if not.
* @param id The ID of the guild to get.
* @returns The guild object if cached, or undefined if not.
*/
getGuild?: (id: string) => AnyGuild | undefined;
}
/**
* Manager options for direct `new Manager(...)` usage.
* Built-in wrappers provide these cache hooks automatically, so they only require {@link ManagerOptions}.
*/
interface StandaloneManagerOptions extends ManagerOptions {
getUser: (id: string) => AnyUser | undefined;
getGuild: (id: string) => AnyGuild | undefined;
}
/**
* State Storage Options
*/
interface StateStorageOptions {
type: StateStorageType;
redisConfig?: RedisConfig;
jsonConfig?: JsonConfig;
deleteDestroyedPlayers?: boolean;
}
/**
* Node Options
*/
interface NodeOptions {
/** The host for the node. */
host: string;
/** The port for the node.
* @default 2333
*/
port?: number;
/** The password for the node.
* @default "youshallnotpass"
*/
password?: string;
/** Whether the host uses SSL.
* @default false
*/
useSSL?: boolean;
/** The identifier for the node.
* @default host
*/
identifier?: string;
/** The maxRetryAttempts for the node.
* @default 30
*/
maxRetryAttempts?: number;
/** The retryDelayMs for the node.
* @default 60000
*/
retryDelayMs?: number;
/** Whether to resume the previous session.
* @default false
*/
enableSessionResumeOption?: boolean;
/** The time in seconds the lavalink server will wait before it removes the player.
* @default 60
*/
sessionTimeoutSeconds?: number;
/** The timeout used for api calls.
* @default 10000
*/
apiRequestTimeoutMs?: number;
/** Priority of the node.
* @default 0
*/
nodePriority?: number;
/** Whether the node is a NodeLink.
* @default false
*/
isNodeLink?: boolean;
/** Whether the node is a backup node.
* @default false
*/
isBackup?: boolean;
}
/**
* Portable User
*/
interface PortableUser {
id: string;
username?: string;
}
/**
* Any user
*/
type AnyUser = PortableUser | User | ClientUser | User$1 | User$2 | User$3 | User$4 | ClientUser$1;
/**
* Portable Message
*/
interface PortableMessage {
id: string;
}
/**
* Any message
*/
type AnyMessage = PortableMessage | Message | Message$1 | Message$2 | Message$3 | Message$4;
/**
* Any guild
*/
type AnyGuild = Guild | Guild$1 | Guild$2 | Guild$3 | Guild$4<"cached">;
/**
* Discord Packet
*/
interface DiscordPacket {
/**
* The opcode for the payload
*/
op: number;
/**
* Event data
*/
d: any;
/**
* Sequence number, used for resuming sessions and heartbeats
*/
s?: number;
/**
* The event name for this payload
*/
t?: string;
}
/**
* Player Update Voice State
*/
interface PlayerUpdateVoiceState {
/**
* The session id of the voice connection
*/
sessionId: string;
/**
* Event data
*/
event: VoiceServerUpdate;
}
/**
* Voice Server Update
*/
interface VoiceServerUpdate {
/**
* The token for the session
*/
token: string;
/**
* Guild if of the voice connection
*/
guild_id: string;
/**
* The endpoint lavalink will connect to
*/
endpoint: string;
}
/**
* Redis Configuration
*/
interface RedisConfig extends RedisOptions {
prefix?: string;
}
/**
* JSON Configuration
*/
interface JsonConfig {
path: string;
}
/**
* Player State Update Event
*/
type PlayerStateUpdateEvent = {
changeType: PlayerStateEventTypes.TrackChange;
details: TrackChangeEvent;
} | {
changeType: PlayerStateEventTypes.PauseChange;
details: PauseChangeEvent;
} | {
changeType: PlayerStateEventTypes.QueueChange;
details: QueueChangeEvent;
} | {
changeType: PlayerStateEventTypes.ConnectionChange;
details: ConnectionChangeEvent;
} | {
changeType: PlayerStateEventTypes.AutoPlayChange;
details: AutoplayChangeEvent;
} | {
changeType: PlayerStateEventTypes.ChannelChange;
details: ChannelChangeEvent;
} | {
changeType: PlayerStateEventTypes.VolumeChange;
details: VolumeChangeEvent;
} | {
changeType: PlayerStateEventTypes.RepeatChange;
details: RepeatChangeEvent;
} | {
changeType: PlayerStateEventTypes.FilterChange;
details: FilterChangeEvent;
};
/**
* Autoplay Change Event
*/
interface AutoplayChangeEvent {
type: "autoplay";
action: "toggle";
previousAutoplay: boolean | null;
currentAutoplay: boolean | null;
}
/**
* Connection Change Event
*/
interface ConnectionChangeEvent {
type: "connection";
action: "connect" | "disconnect";
previousConnection: boolean | null;
currentConnection: boolean | null;
}
interface FilterChangeEvent {
type: "filter";
action: "change";
}
/**
* Repeat Change Event
*/
interface RepeatChangeEvent {
type: "repeat";
action: "dynamic" | "track" | "queue" | "none";
previousRepeat: "dynamic" | "track" | "queue" | null;
currentRepeat: "dynamic" | "track" | "queue" | null;
}
/**
* Pause Change Event
*/
interface PauseChangeEvent {
type: "pause";
action: "pause" | "resume" | "toggle";
previousPause: boolean | null;
currentPause: boolean | null;
}
/**
* Queue Change Event
*/
interface QueueChangeEvent {
type: "queue";
action: "add" | "remove" | "clear" | "shuffle" | "roundRobin" | "userBlock" | "autoPlayAdd";
previousQueueLength: number | null;
currentQueueLength: number | null;
tracks?: Track[];
}
/**
* Track Change Event
*/
interface TrackChangeEvent {
type: "track";
action: "start" | "end" | "previous" | "timeUpdate" | "autoPlay";
track: Track;
previousTime?: number | null;
currentTime?: number | null;
}
/**
* Volume Change Event
*/
interface VolumeChangeEvent {
type: "volume";
action: "adjust";
previousVolume: number | null;
currentVolume: number | null;
}
/**
* Channel Change Event
*/
interface ChannelChangeEvent {
type: "channel";
action: "text" | "voice";
previousChannel: string | null;
currentChannel: string | null;
}
/**
* Track
*/
interface Track {
/** The base64 encoded track. */
readonly track: string;
/** The artwork url of the track. */
readonly artworkUrl: string | null;
/** The track source name. */
readonly sourceName: TrackSourceName;
/** The title of the track. */
title: string;
/** The identifier of the track. */
readonly identifier: string;
/** The author of the track. */
author: string;
/** The duration of the track. */
readonly duration: number;
/** The ISRC of the track. */
readonly isrc: string;
/** If the track is seekable. */
readonly isSeekable: boolean;
/** If the track is a stream.. */
readonly isStream: boolean;
/** The uri of the track. */
readonly uri: string;
/** The thumbnail of the track or null if it's a unsupported source. */
readonly thumbnail: string | null;
/** The user that requested the track. */
requester: AnyUser;
/** Displays the track thumbnail with optional size or null if it's a unsupported source. */
displayThumbnail(size?: Sizes): string | null;
/** Additional track info provided by plugins. */
pluginInfo: TrackPluginInfo;
/** Add your own data to the track. */
customData: Record<string, unknown>;
/** If the track got added by autoplay. */
readonly isAutoplay: boolean;
}
/**
* Track Plugin Info
*/
interface TrackPluginInfo {
albumName?: string;
albumUrl?: string;
artistArtworkUrl?: string;
artistUrl?: string;
isPreview?: string;
previewUrl?: string;
}
/**
* Search Query
*/
interface SearchQuery {
/** The source to search from. */
source?: SearchPlatform;
/** The query to search for. */
query: string;
}
/**
* Lavalink Response
*/
interface LavalinkResponse {
loadType: LoadTypes;
data: TrackData[] | PlaylistRawData;
}
/**
* Track Data
*/
interface TrackData {
/** The track information. */
encoded: string;
/** The detailed information of the track. */
info: TrackDataInfo;
/** Additional track info provided by plugins. */
pluginInfo: Record<string, string>;
}
/**
* Playlist Raw Data
*/
interface PlaylistRawData {
info: {
/** The playlist name. */
name: string;
};
/** Addition info provided by plugins. */
pluginInfo: object;
/** The tracks of the playlist */
tracks: TrackData[];
}
/**
* Track Data Info
*/
interface TrackDataInfo {
identifier: string;
isSeekable: boolean;
author: string;
length: number;
isrc?: string;
isStream: boolean;
title: string;
uri?: string;
artworkUrl?: string;
sourceName?: TrackSourceName;
}
/**
* LavaPlayer
*/
interface LavaPlayer {
guildId: string;
track: TrackData;
volume: number;
paused: boolean;
state: {
time: number;
position: number;
connected: boolean;
ping: number;
};
voice: LavalinkVoiceStateResponse;
filters: Record<string, unknown>;
}
/**
* Error or Empty Search Result
*/
interface ErrorOrEmptySearchResult {
/** The load type of the result. */
loadType: LoadTypes.Empty | LoadTypes.Error;
}
/**
* Track Search Result
*/
interface TrackSearchResult {
/** The load type is always 'track' */
loadType: LoadTypes.Track;
/** The track obtained */
tracks: [Track];
}
/**
* Search Result
*/
interface SearchSearchResult {
/** The load type is always 'search' */
loadType: LoadTypes.Search;
/** The tracks of the search result */
tracks: Track[];
}
/**
* Playlist Search Result
*/
interface PlaylistSearchResult {
/** The playlist load type */
loadType: LoadTypes.Playlist;
/** The tracks of the playlist */
tracks: Track[];
/** The playlist info */
playlist: PlaylistData;
}
/**
* Album Search Result
*/
interface AlbumSearchResult {
loadType: LoadTypes.Album;
tracks: Track[];
playlist: PlaylistData;
}
/**
* Artist Search Result
*/
interface ArtistSearchResult {
loadType: LoadTypes.Artist;
tracks: Track[];
playlist: PlaylistData;
}
/**
* Station Search Result
*/
interface StationSearchResult {
loadType: LoadTypes.Station;
tracks: Track[];
playlist: PlaylistData;
}
/**
* Podcast Search Result
*/
interface PodcastSearchResult {
loadType: LoadTypes.Podcast;
tracks: Track[];
playlist: PlaylistData;
}
/**
* Show Search Result
*/
interface ShowSearchResult {
loadType: LoadTypes.Show;
tracks: Track[];
playlist: PlaylistData;
}
/**
* Short Search Result
*/
interface ShortSearchResult {
loadType: LoadTypes.Short;
tracks: [Track];
}
/**
* Playlist Data
*/
interface PlaylistData {
/** The playlist name. */
name: string;
/** Requester of playlist. */
requester: AnyUser;
/** More playlist information. */
playlistInfo: PlaylistInfoData[];
/** The length of the playlist. */
duration: number;
/** The songs of the playlist. */
tracks: Track[];
}
/**
* Playlist Info Data
*/
interface PlaylistInfoData {
/** Url to playlist. */
url: string;
/** Type is always playlist in that case. */
type: string;
/** ArtworkUrl of playlist */
artworkUrl: string;
/** Number of total tracks in playlist */
totalTracks: number;
/** Author of playlist */
author: string;
}
/**
* Manager Events
*/
interface ManagerEvents {
[ManagerEventTypes.ChapterStarted]: [player: Player, track: Track, payload: SponsorBlockChapterStarted];
[ManagerEventTypes.ChaptersLoaded]: [player: Player, track: Track, payload: SponsorBlockChaptersLoaded];
[ManagerEventTypes.Debug]: [info: string];
[ManagerEventTypes.LyricsFound]: [player: Player, track: Track, payload: LyricsFoundEvent];
[ManagerEventTypes.LyricsLine]: [player: Player, track: Track, payload: LyricsLineEvent];
[ManagerEventTypes.LyricsNotFound]: [player: Player, track: Track, payload: LyricsNotFoundEvent];
[ManagerEventTypes.NodeConnect]: [node: Node];
[ManagerEventTypes.NodeCreate]: [node: Node];
[ManagerEventTypes.NodeDestroy]: [node: Node];
[ManagerEventTypes.NodeDisconnect]: [node: Node, reason: {
code?: number;
reason?: string;
}];
[ManagerEventTypes.NodeError]: [node: Node, error: Error];
[ManagerEventTypes.NodeRaw]: [payload: unknown];
[ManagerEventTypes.NodeReconnect]: [node: Node];
[ManagerEventTypes.PlayerCreate]: [player: Player];
[ManagerEventTypes.PlayerDestroy]: [player: Player];
[ManagerEventTypes.PlayerDisconnect]: [player: Player, oldChannel: string];
[ManagerEventTypes.PlayerMove]: [player: Player, oldChannel: string, newChannel: string];
[ManagerEventTypes.PlayerRestored]: [player: Player, node: Node];
[ManagerEventTypes.PlayerStateUpdate]: [oldPlayer: Player, newPlayer: Player, changeType: PlayerStateUpdateEvent];
[ManagerEventTypes.QueueEnd]: [player: Player, track: Track, payload: TrackEndEvent];
[ManagerEventTypes.RestoreComplete]: [node: Node];
[ManagerEventTypes.SegmentSkipped]: [player: Player, track: Track, payload: SponsorBlockSegmentSkipped];
[ManagerEventTypes.SegmentsLoaded]: [player: Player, track: Track, payload: SponsorBlockSegmentsLoaded];
[ManagerEventTypes.SocketClosed]: [player: Player, payload: WebSocketClosedEvent];
[ManagerEventTypes.TrackEnd]: [player: Player, track: Track, payload: TrackEndEvent];
[ManagerEventTypes.TrackError]: [player: Player, track: Track, payload: TrackExceptionEvent];
[ManagerEventTypes.TrackStart]: [player: Player, track: Track, payload: TrackStartEvent];
[ManagerEventTypes.TrackStuck]: [player: Player, track: Track, payload: TrackStuckEvent];
[ManagerEventTypes.VoiceReceiverDisconnect]: [player: Player];
[ManagerEventTypes.VoiceReceiverConnect]: [player: Player];
[ManagerEventTypes.VoiceReceiverError]: [player: Player, error: Error];
[ManagerEventTypes.VoiceReceiverStartSpeaking]: [player: Player, data: unknown];
[ManagerEventTypes.VoiceReceiverEndSpeaking]: [player: Player, data: unknown];
}
/**
* Voice Packet
*/
interface VoicePacket {
t?: "VOICE_SERVER_UPDATE" | "VOICE_STATE_UPDATE";
d: DiscordVoiceState | VoiceServer;
}
/**
* Voice Server
*/
interface VoiceServer {
token: string;
guild_id: string;
endpoint: string;
}
interface Extendable {
Player: typeof Player;
Queue: typeof MemoryQueue | typeof RedisQueue | typeof JsonQueue;
Node: typeof Node;
}
/**
* Voice State
*/
interface PlayerVoiceState {
op: "voiceUpdate";
guildId: string;
event: VoiceServer;
sessionId?: string;
channelId?: string;
}
/**
* Voice State
*/
interface DiscordVoiceState {
guild_id: string;
user_id: string;
session_id: string;
channel_id: string;
}
/** @deprecated Use DiscordVoiceState or PlayerVoiceState instead */
type VoiceState = DiscordVoiceState | PlayerVoiceState;
/**
* Node Message
*/
interface NodeMessage extends NodeStats {
type: PlayerEventType;
op: "stats" | "playerUpdate" | "event";
guildId: string;
}
/**
* PlayerEvent interface
*/
interface PlayerEvent {
op: "event";
type: PlayerEventType;
guildId: string;
}
/**
* Exception interface
*/
interface Exception {
message: string;
severity: SeverityTypes;
cause: string;
}
/**
* TrackStartEvent interface
*/
interface TrackStartEvent extends PlayerEvent {
type: "TrackStartEvent";
track: TrackData;
}
/**
* TrackEndEvent interface
*/
interface TrackEndEvent extends PlayerEvent {
type: "TrackEndEvent";
track: TrackData;
reason: TrackEndReasonTypes;
}
/**
* TrackExceptionEvent interface
*/
interface TrackExceptionEvent extends PlayerEvent {
exception?: Exception;
guildId: string;
type: "TrackExceptionEvent";
}
/**
* TrackStuckEvent interface
*/
interface TrackStuckEvent extends PlayerEvent {
type: "TrackStuckEvent";
thresholdMs: number;
}
/**
* WebSocketClosedEvent interface
*/
interface WebSocketClosedEvent extends PlayerEvent {
type: "WebSocketClosedEvent";
code: number;
reason: string;
byRemote: boolean;
}
/**
* SponsorBlockSegmentsLoaded interface
*/
interface SponsorBlockSegmentsLoaded extends PlayerEvent {
type: "SegmentsLoaded";
segments: {
category: string;
start: number;
end: number;
}[];
}
/**
* SponsorBlockSegmentSkipped interface
*/
interface SponsorBlockSegmentSkipped extends PlayerEvent {
type: "SegmentSkipped";
segment: {
category: string;
start: number;
end: number;
};
}
/**
* SponsorBlockChapterStarted interface
*/
interface SponsorBlockChapterStarted extends PlayerEvent {
type: "ChapterStarted";
/** The chapter which started */
chapter: {
/** The name of the chapter */
name: string;
start: number;
end: number;
duration: number;
};
}
/**
* SponsorBlockChaptersLoaded interface
*/
interface SponsorBlockChaptersLoaded extends PlayerEvent {
type: "ChaptersLoaded";
/** All chapters loaded */
chapters: {
/** The name of the chapter */
name: string;
start: number;
end: number;
duration: number;
}[];
}
/**
* NodeStats interface
*/
interface NodeStats {
/** The amount of players on the node. */
players: number;
/** The amount of playing players on the node. */
playingPlayers: number;
/** The uptime for the node. */
uptime: number;
/** The memory stats for the node. */
memory: MemoryStats;
/** The cpu stats for the node. */
cpu: CPUStats;
/** The frame stats for the node. */
frameStats: FrameStats;
}
/**
* NodeStats interface
*/
interface NodeStats {
/** The amount of players on the node. */
players: number;
/** The amount of playing players on the node. */
playingPlayers: number;
/** The uptime for the node. */
uptime: number;
/** The memory stats for the node. */
memory: MemoryStats;
/** The cpu stats for the node. */
cpu: CPUStats;
/** The frame stats for the node. */
frameStats: FrameStats;
}
/**
* MemoryStats interface
*/
interface MemoryStats {
/** The free memory of the allocated amount. */
free: number;
/** The used memory of the allocated amount. */
used: number;
/** The total allocated memory. */
allocated: number;
/** The reservable memory. */
reservable: number;
}
/**
* CPUStats interface
*/
interface CPUStats {
/** The core amount the host machine has. */
cores: number;
/** The system load. */
systemLoad: number;
/** The lavalink load. */
lavalinkLoad: number;
}
/**
* FrameStats interface
*/
interface FrameStats {
/** The amount of sent frames. */
sent?: number;
/** The amount of nulled frames. */
nulled?: number;
/** The amount of deficit frames. */
deficit?: number;
}
/**
* LavalinkInfo interface
*/
interface LavalinkInfo {
version: {
semver: string;
major: number;
minor: number;
patch: number;
preRelease: string;
};
buildTime: number;
git: {
branch: string;
commit: string;
commitTime: number;
};
jvm: string;
lavaplayer: string;
sourceManagers: string[];
filters: string[];
plugins: {
name: string;
version: string;
}[];
}
/**
* LyricsLine interface
*/
interface LyricsLine {
timestamp: number;
duration: number;
line: string;
plugin: object;
}
/**
* Lyrics interface
*/
interface Lyrics {
source: string;
provider: string;
text?: string;
lines: LyricsLine[];
plugin: object[];
}
/**
* LyricsFoundEvent interface
*/
inter