UNPKG

erela.js

Version:

An easy-to-use Lavalink client for NodeJS.

756 lines (749 loc) 24.7 kB
/// <reference types="node" /> import { Collection } from '@discordjs/collection'; import { EventEmitter } from 'events'; import WebSocket from 'ws'; import { Pool, Dispatcher } from 'undici'; /** * The player's queue, the `current` property is the currently playing track, think of the rest as the up-coming tracks. * @noInheritDoc */ declare class Queue extends Array<Track | UnresolvedTrack> { /** The total duration of the queue. */ get duration(): number; /** The total size of tracks in the queue including the current track. */ get totalSize(): number; /** The size of tracks in the queue. */ get size(): number; /** The current track */ current: Track | UnresolvedTrack | null; /** The previous track */ previous: Track | UnresolvedTrack | null; /** * Adds a track to the queue. * @param track * @param [offset=null] */ add(track: (Track | UnresolvedTrack) | (Track | UnresolvedTrack)[], offset?: number): void; /** * Removes a track from the queue. Defaults to the first track, returning the removed track, EXCLUDING THE `current` TRACK. * @param [position=0] */ remove(position?: number): Track[]; /** * Removes an amount of tracks using a exclusive start and end exclusive index, returning the removed tracks, EXCLUDING THE `current` TRACK. * @param start * @param end */ remove(start: number, end: number): (Track | UnresolvedTrack)[]; /** Clears the queue. */ clear(): void; /** Shuffles the queue. */ shuffle(): void; } declare abstract class TrackUtils { static trackPartial: string[] | null; private static manager; /** @hidden */ static init(manager: Manager): void; static setTrackPartial(partial: string[]): void; /** * Checks if the provided argument is a valid Track or UnresolvedTrack, if provided an array then every element will be checked. * @param trackOrTracks */ static validate(trackOrTracks: unknown): boolean; /** * Checks if the provided argument is a valid UnresolvedTrack. * @param track */ static isUnresolvedTrack(track: unknown): boolean; /** * Checks if the provided argument is a valid Track. * @param track */ static isTrack(track: unknown): boolean; /** * Builds a Track from the raw data from Lavalink and a optional requester. * @param data * @param requester */ static build(data: TrackData, requester?: unknown): Track; /** * Builds a UnresolvedTrack to be resolved before being played . * @param query * @param requester */ static buildUnresolved(query: string | UnresolvedQuery, requester?: unknown): UnresolvedTrack; static getClosestTrack(unresolvedTrack: UnresolvedTrack): Promise<Track>; } /** Gets or extends structures to extend the built in, or already extended, classes to add more functionality. */ declare abstract class Structure { /** * Extends a class. * @param name * @param extender */ static extend<K extends keyof Extendable, T extends Extendable[K]>(name: K, extender: (target: Extendable[K]) => T): T; /** * Get a structure from available structures by name. * @param name */ static get<K extends keyof Extendable>(name: K): Extendable[K]; } declare class Plugin { load(manager: Manager): void; unload(manager: Manager): void; } interface UnresolvedQuery { /** The title of the unresolved track. */ title: string; /** The author of the unresolved track. If provided it will have a more precise search. */ author?: string; /** The duration of the unresolved track. If provided it will have a more precise search. */ duration?: number; } declare type Sizes = "0" | "1" | "2" | "3" | "default" | "mqdefault" | "hqdefault" | "maxresdefault"; declare type LoadType = "TRACK_LOADED" | "PLAYLIST_LOADED" | "SEARCH_RESULT" | "LOAD_FAILED" | "NO_MATCHES"; declare type State = "CONNECTED" | "CONNECTING" | "DISCONNECTED" | "DISCONNECTING" | "DESTROYING"; declare type PlayerEvents = TrackStartEvent | TrackEndEvent | TrackStuckEvent | TrackExceptionEvent | WebSocketClosedEvent; declare type PlayerEventType = "TrackStartEvent" | "TrackEndEvent" | "TrackExceptionEvent" | "TrackStuckEvent" | "WebSocketClosedEvent"; declare type TrackEndReason = "FINISHED" | "LOAD_FAILED" | "STOPPED" | "REPLACED" | "CLEANUP"; declare type Severity = "COMMON" | "SUSPICIOUS" | "FAULT"; interface TrackData { track: string; info: TrackDataInfo; } interface TrackDataInfo { title: string; identifier: string; author: string; length: number; isSeekable: boolean; isStream: boolean; uri: string; } interface Extendable { Player: typeof Player; Queue: typeof Queue; Node: typeof Node; } interface VoiceServer { token: string; guild_id: string; endpoint: string; } interface VoiceState { op: "voiceUpdate"; guildId: string; event: VoiceServer; sessionId?: string; } interface VoiceState { guild_id: string; user_id: string; session_id: string; channel_id: string; } interface VoicePacket { t?: "VOICE_SERVER_UPDATE" | "VOICE_STATE_UPDATE"; d: VoiceState | VoiceServer; } interface NodeMessage extends NodeStats { type: PlayerEventType; op: "stats" | "playerUpdate" | "event"; guildId: string; } interface PlayerEvent { op: "event"; type: PlayerEventType; guildId: string; } interface Exception { severity: Severity; message: string; cause: string; } interface TrackStartEvent extends PlayerEvent { type: "TrackStartEvent"; track: string; } interface TrackEndEvent extends PlayerEvent { type: "TrackEndEvent"; track: string; reason: TrackEndReason; } interface TrackExceptionEvent extends PlayerEvent { type: "TrackExceptionEvent"; exception?: Exception; error: string; } interface TrackStuckEvent extends PlayerEvent { type: "TrackStuckEvent"; thresholdMs: number; } interface WebSocketClosedEvent extends PlayerEvent { type: "WebSocketClosedEvent"; code: number; byRemote: boolean; reason: string; } interface PlayerUpdate { op: "playerUpdate"; state: { position: number; time: number; }; guildId: string; } declare class Player { options: PlayerOptions; /** The Queue for the Player. */ readonly queue: Queue; /** Whether the queue repeats the track. */ trackRepeat: boolean; /** Whether the queue repeats the queue. */ queueRepeat: boolean; /** The time the player is in the track. */ position: number; /** Whether the player is playing. */ playing: boolean; /** Whether the player is paused. */ paused: boolean; /** The volume for the player */ volume: number; /** The Node for the Player. */ node: Node; /** The guild for the player. */ guild: string; /** The voice channel for the player. */ voiceChannel: string | null; /** The text channel for the player. */ textChannel: string | null; /** The current state of the player. */ state: State; /** The equalizer bands array. */ bands: number[]; /** The voice state object from Discord. */ voiceState: VoiceState; /** The Manager. */ manager: Manager; private static _manager; private readonly data; /** * Set custom data. * @param key * @param value */ set(key: string, value: unknown): void; /** * Get custom data. * @param key */ get<T>(key: string): T; /** @hidden */ static init(manager: Manager): void; /** * Creates a new player, returns one if it already exists. * @param options */ constructor(options: PlayerOptions); /** * Same as Manager#search() but a shortcut on the player itself. * @param query * @param requester */ search(query: string | SearchQuery, requester?: unknown): Promise<SearchResult>; /** * Sets the players equalizer band on-top of the existing ones. * @param bands */ setEQ(...bands: EqualizerBand[]): this; /** Clears the equalizer bands. */ clearEQ(): this; /** Connect to the voice channel. */ connect(): this; /** Disconnect from the voice channel. */ disconnect(): this; /** Destroys the player. */ destroy(disconnect?: boolean): void; /** * Sets the player voice channel. * @param channel */ setVoiceChannel(channel: string): this; /** * Sets the player text channel. * @param channel */ setTextChannel(channel: string): this; /** Plays the next track. */ play(): Promise<void>; /** * Plays the specified track. * @param track */ play(track: Track | UnresolvedTrack): Promise<void>; /** * Plays the next track with some options. * @param options */ play(options: PlayOptions): Promise<void>; /** * Plays the specified track with some options. * @param track * @param options */ play(track: Track | UnresolvedTrack, options: PlayOptions): Promise<void>; /** * Sets the player volume. * @param volume */ setVolume(volume: number): this; /** * Sets the track repeat. * @param repeat */ setTrackRepeat(repeat: boolean): this; /** * Sets the queue repeat. * @param repeat */ setQueueRepeat(repeat: boolean): this; /** Stops the current track, optionally give an amount to skip to, e.g 5 would play the 5th song. */ stop(amount?: number): this; /** * Pauses the current track. * @param pause */ pause(pause: boolean): this; /** * Seeks to the position in the current track. * @param position */ seek(position: number): this; } interface PlayerOptions { /** The guild the Player belongs to. */ guild: string; /** The text channel the Player belongs to. */ textChannel: string; /** The voice channel the Player belongs to. */ voiceChannel?: string; /** The node the Player uses. */ node?: string; /** The initial volume the Player will use. */ volume?: number; /** If the player should mute itself. */ selfMute?: boolean; /** If the player should deaf itself. */ selfDeafen?: boolean; } /** If track partials are set some of these will be `undefined` as they were removed. */ interface Track { /** The base64 encoded track. */ readonly track: string; /** The title of the track. */ readonly title: string; /** The identifier of the track. */ readonly identifier: string; /** The author of the track. */ readonly author: string; /** The duration of the track. */ readonly duration: number; /** 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. */ readonly requester: unknown | null; /** Displays the track thumbnail with optional size or null if it's a unsupported source. */ displayThumbnail(size?: Sizes): string; } /** Unresolved tracks can't be played normally, they will resolve before playing into a Track. */ interface UnresolvedTrack extends Partial<Track> { /** The title to search against. */ title: string; /** The author to search against. */ author?: string; /** The duration to search within 1500 milliseconds of the results from YouTube. */ duration?: number; /** Resolves into a Track. */ resolve(): Promise<void>; } interface PlayOptions { /** The position to start the track. */ readonly startTime?: number; /** The position to end the track. */ readonly endTime?: number; /** Whether to not replace the track if a play payload is sent. */ readonly noReplace?: boolean; } interface EqualizerBand { /** The band number being 0 to 14. */ band: number; /** The gain amount being -0.25 to 1.00, 0.25 being double. */ gain: number; } declare class Node { options: NodeOptions; /** The socket for the node. */ socket: WebSocket | null; /** The HTTP pool used for rest calls. */ http: Pool; /** The amount of rest calls the node has made. */ calls: number; /** The stats for the node. */ stats: NodeStats; manager: Manager; private static _manager; private reconnectTimeout?; private reconnectAttempts; /** Returns if connected to the Node. */ get connected(): boolean; /** Returns the address for this node. */ get address(): string; /** @hidden */ static init(manager: Manager): void; /** * Creates an instance of Node. * @param options */ constructor(options: NodeOptions); /** Connects to the Node. */ connect(): void; /** Destroys the Node and all players connected with it. */ destroy(): void; /** * Makes an API call to the Node * @param endpoint The endpoint that we will make the call to * @param modify Used to modify the request before being sent * @returns The returned data */ makeRequest<T>(endpoint: string, modify?: ModifyRequest): Promise<T>; /** * Sends data to the Node. * @param data */ send(data: unknown): Promise<boolean>; private reconnect; protected open(): void; protected close(code: number, reason: string): void; protected error(error: Error): void; protected message(d: Buffer | string): void; protected handleEvent(payload: PlayerEvent & PlayerEvents): void; protected trackStart(player: Player, track: Track, payload: TrackStartEvent): void; protected trackEnd(player: Player, track: Track, payload: TrackEndEvent): void; protected queueEnd(player: Player, track: Track, payload: TrackEndEvent): void; protected trackStuck(player: Player, track: Track, payload: TrackStuckEvent): void; protected trackError(player: Player, track: Track | UnresolvedTrack, payload: TrackExceptionEvent): void; protected socketClosed(player: Player, payload: WebSocketClosedEvent): void; } /** Modifies any outgoing REST requests. */ declare type ModifyRequest = (options: Dispatcher.RequestOptions) => void; interface NodeOptions { /** The host for the node. */ host: string; /** The port for the node. */ port?: number; /** The password for the node. */ password?: string; /** Whether the host uses SSL. */ secure?: boolean; /** The identifier for the node. */ identifier?: string; /** The retryAmount for the node. */ retryAmount?: number; /** The retryDelay for the node. */ retryDelay?: number; /** The timeout used for api calls */ requestTimeout?: number; /** Options for the undici http pool used for http requests */ poolOptions?: Pool.Options; } 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; } 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; } interface CPUStats { /** The core amount the host machine has. */ cores: number; /** The system load. */ systemLoad: number; /** The lavalink load. */ lavalinkLoad: number; } interface FrameStats { /** The amount of sent frames. */ sent?: number; /** The amount of nulled frames. */ nulled?: number; /** The amount of deficit frames. */ deficit?: number; } interface Manager { /** * Emitted when a Node is created. * @event Manager#nodeCreate */ on(event: "nodeCreate", listener: (node: Node) => void): this; /** * Emitted when a Node is destroyed. * @event Manager#nodeDestroy */ on(event: "nodeDestroy", listener: (node: Node) => void): this; /** * Emitted when a Node connects. * @event Manager#nodeConnect */ on(event: "nodeConnect", listener: (node: Node) => void): this; /** * Emitted when a Node reconnects. * @event Manager#nodeReconnect */ on(event: "nodeReconnect", listener: (node: Node) => void): this; /** * Emitted when a Node disconnects. * @event Manager#nodeDisconnect */ on(event: "nodeDisconnect", listener: (node: Node, reason: { code?: number; reason?: string; }) => void): this; /** * Emitted when a Node has an error. * @event Manager#nodeError */ on(event: "nodeError", listener: (node: Node, error: Error) => void): this; /** * Emitted whenever any Lavalink event is received. * @event Manager#nodeRaw */ on(event: "nodeRaw", listener: (payload: unknown) => void): this; /** * Emitted when a player is created. * @event Manager#playerCreate */ on(event: "playerCreate", listener: (player: Player) => void): this; /** * Emitted when a player is destroyed. * @event Manager#playerDestroy */ on(event: "playerDestroy", listener: (player: Player) => void): this; /** * Emitted when a player queue ends. * @event Manager#queueEnd */ on(event: "queueEnd", listener: (player: Player, track: Track | UnresolvedTrack, payload: TrackEndEvent) => void): this; /** * Emitted when a player is moved to a new voice channel. * @event Manager#playerMove */ on(event: "playerMove", listener: (player: Player, initChannel: string, newChannel: string) => void): this; /** * Emitted when a player is disconnected from it's current voice channel. * @event Manager#playerDisconnect */ on(event: "playerDisconnect", listener: (player: Player, oldChannel: string) => void): this; /** * Emitted when a track starts. * @event Manager#trackStart */ on(event: "trackStart", listener: (player: Player, track: Track, payload: TrackStartEvent) => void): this; /** * Emitted when a track ends. * @event Manager#trackEnd */ on(event: "trackEnd", listener: (player: Player, track: Track, payload: TrackEndEvent) => void): this; /** * Emitted when a track gets stuck during playback. * @event Manager#trackStuck */ on(event: "trackStuck", listener: (player: Player, track: Track, payload: TrackStuckEvent) => void): this; /** * Emitted when a track has an error during playback. * @event Manager#trackError */ on(event: "trackError", listener: (player: Player, track: Track | UnresolvedTrack, payload: TrackExceptionEvent) => void): this; /** * Emitted when a voice connection is closed. * @event Manager#socketClosed */ on(event: "socketClosed", listener: (player: Player, payload: WebSocketClosedEvent) => void): this; } /** * The main hub for interacting with Lavalink and using Erela.JS, * @noInheritDoc */ declare class Manager extends EventEmitter { static readonly DEFAULT_SOURCES: Record<SearchPlatform, string>; /** The map of players. */ readonly players: Collection<string, Player>; /** The map of nodes. */ readonly nodes: Collection<string, Node>; /** The options that were set. */ readonly options: ManagerOptions; private initiated; /** Returns the least used Nodes. */ get leastUsedNodes(): Collection<string, Node>; /** Returns the least system load Nodes. */ get leastLoadNodes(): Collection<string, Node>; /** * Initiates the Manager class. * @param options */ constructor(options: ManagerOptions); /** * Initiates the Manager. * @param clientId */ init(clientId?: string): this; /** * Searches the enabled sources based off the URL or the `source` property. * @param query * @param requester * @returns The search result. */ search(query: string | SearchQuery, requester?: unknown): Promise<SearchResult>; /** * Decodes the base64 encoded tracks and returns a TrackData array. * @param tracks */ decodeTracks(tracks: string[]): Promise<TrackData[]>; /** * Decodes the base64 encoded track and returns a TrackData. * @param track */ decodeTrack(track: string): Promise<TrackData>; /** * Creates a player or returns one if it already exists. * @param options */ create(options: PlayerOptions): Player; /** * Returns a player or undefined if it does not exist. * @param guild */ get(guild: string): Player | undefined; /** * Destroys a player if it exists. * @param guild */ destroy(guild: string): void; /** * Creates a node or returns one if it already exists. * @param options */ createNode(options: NodeOptions): Node; /** * Destroys a node if it exists. * @param identifier */ destroyNode(identifier: string): void; /** * Sends voice data to the Lavalink server. * @param data */ updateVoiceState(data: VoicePacket | VoiceServer | VoiceState): void; } interface Payload { /** The OP code */ op: number; d: { guild_id: string; channel_id: string | null; self_mute: boolean; self_deaf: boolean; }; } interface ManagerOptions { /** The array of nodes to connect to. */ nodes?: NodeOptions[]; /** The client ID to use. */ clientId?: string; /** Value to use for the `Client-Name` header. */ clientName?: string; /** The shard count. */ shards?: number; /** A array of plugins to use. */ plugins?: Plugin[]; /** Whether players should automatically play the next song. */ autoPlay?: boolean; /** An array of track properties to keep. `track` will always be present. */ trackPartial?: string[]; /** The default search platform to use, can be "youtube", "youtube music", or "soundcloud". */ defaultSearchPlatform?: SearchPlatform; /** * Function to send data to the websocket. * @param id * @param payload */ send(id: string, payload: Payload): void; } declare type SearchPlatform = "youtube" | "youtube music" | "soundcloud"; interface SearchQuery { /** The source to search from. */ source?: SearchPlatform | string; /** The query to search for. */ query: string; } interface SearchResult { /** The load type of the result. */ loadType: LoadType; /** The array of tracks from the result. */ tracks: Track[]; /** The playlist info if the load type is PLAYLIST_LOADED. */ playlist?: PlaylistInfo; /** The exception when searching if one. */ exception?: { /** The message for the exception. */ message: string; /** The severity of exception. */ severity: string; }; } interface PlaylistInfo { /** The playlist name. */ name: string; /** The playlist selected track. */ selectedTrack?: Track; /** The duration of the playlist. */ duration: number; } interface LavalinkResult { tracks: TrackData[]; loadType: LoadType; exception?: { /** The message for the exception. */ message: string; /** The severity of exception. */ severity: string; }; playlistInfo: { name: string; selectedTrack?: number; }; } export { CPUStats, EqualizerBand, Exception, Extendable, FrameStats, LavalinkResult, LoadType, Manager, ManagerOptions, MemoryStats, ModifyRequest, Node, NodeMessage, NodeOptions, NodeStats, Payload, PlayOptions, Player, PlayerEvent, PlayerEventType, PlayerEvents, PlayerOptions, PlayerUpdate, PlaylistInfo, Plugin, Queue, SearchPlatform, SearchQuery, SearchResult, Severity, Sizes, State, Structure, Track, TrackData, TrackDataInfo, TrackEndEvent, TrackEndReason, TrackExceptionEvent, TrackStartEvent, TrackStuckEvent, TrackUtils, UnresolvedQuery, UnresolvedTrack, VoicePacket, VoiceServer, VoiceState, WebSocketClosedEvent };