UNPKG

synthra-client

Version:

A user-friendly Lavalink client designed for NodeJS.

468 lines (467 loc) 20.7 kB
import { PlayerEvent, PlayerEvents, TrackEndEvent, TrackExceptionEvent, TrackStartEvent, TrackStuckEvent, WebSocketClosedEvent } from "./Utils"; import { Synthra, SearchPlatform } from "./Manager"; import { Player, Track } from "./Player"; import { Rest } from "./Rest"; import WebSocket from "ws"; export declare enum SponsorBlockSegment { Sponsor = "sponsor", SelfPromo = "selfpromo", Interaction = "interaction", Intro = "intro", Outro = "outro", Preview = "preview", MusicOfftopic = "music_offtopic", Filler = "filler" } export declare class Node { options: NodeOptions; /** The socket for the node. */ socket: WebSocket | null; /** The stats for the node. */ stats: NodeStats; /** The manager for the node */ manager: Synthra; /** The node's session ID. */ sessionId: string | null; /** The REST instance. */ readonly rest: Rest; /** Actual Lavalink information of the node. */ info: LavalinkInfo | null; private static _manager; private reconnectTimeout?; private reconnectAttempts; /** * Creates an instance of Node. * @param options */ constructor(options: NodeOptions); /** Returns if connected to the Node. */ get connected(): boolean; /** Returns the address for this node. */ get address(): string; /** @hidden */ static init(manager: Synthra): void; /** * Creates the sessionIds.json file if it doesn't exist. This file is used to * store the session IDs for each node. The session IDs are used to identify * the node when resuming a session. */ createSessionIdsFile(): void; /** * Loads session IDs from the sessionIds.json file if it exists. * The session IDs are used to resume sessions for each node. * * The session IDs are stored in the sessionIds.json file as a composite key * of the node identifier and cluster ID. This allows multiple clusters to * be used with the same node identifier. */ loadSessionIds(): void; /** * Updates the session ID in the sessionIds.json file. * * This method is called after the session ID has been updated, and it * writes the new session ID to the sessionIds.json file. * * @remarks * The session ID is stored in the sessionIds.json file as a composite key * of the node identifier and cluster ID. This allows multiple clusters to * be used with the same node identifier. */ updateSessionId(): void; /** * Connects to the Node. * * @remarks * If the node is already connected, this method will do nothing. * If the node has a session ID, it will be sent in the headers of the WebSocket connection. * If the node has no session ID but the `resumeStatus` option is true, it will use the session ID * stored in the sessionIds.json file if it exists. */ connect(): void; /** * Destroys the node and cleans up associated resources. * * This method emits a debug event indicating that the node is being destroyed and attempts * to automatically move all players connected to the node to a usable one. It then closes * the WebSocket connection, removes all event listeners, and clears the reconnect timeout. * Finally, it emits a "nodeDestroy" event and removes the node from the manager. * * @returns {Promise<void>} A promise that resolves when the node and its resources have been destroyed. */ destroy(): Promise<void>; /** * Attempts to reconnect to the node if the connection is lost. * * This method is called when the WebSocket connection is closed * unexpectedly. It will attempt to reconnect to the node after a * specified delay, and will continue to do so until the maximum * number of retry attempts is reached or the node is manually destroyed. * If the maximum number of retry attempts is reached, an error event * will be emitted and the node will be destroyed. * * @returns {Promise<void>} - Resolves when the reconnection attempt is scheduled. * @emits {debug} - Emits a debug event indicating the node is attempting to reconnect. * @emits {nodeReconnect} - Emits a nodeReconnect event when the node is attempting to reconnect. * @emits {nodeError} - Emits an error event if the maximum number of retry attempts is reached. * @emits {nodeDestroy} - Emits a nodeDestroy event if the maximum number of retry attempts is reached. */ private reconnect; /** * Handles the "open" event emitted by the WebSocket connection. * * This method is called when the WebSocket connection is established. * It clears any existing reconnect timeouts, emits a debug event * indicating the node is connected, and emits a "nodeConnect" event * with the node as the argument. */ protected open(): void; /** * Handles the "close" event emitted by the WebSocket connection. * * This method is called when the WebSocket connection is closed. * It emits a "nodeDisconnect" event with the node and the close event as arguments, * and a debug event indicating the node is disconnected. * It then attempts to move all players connected to that node to a useable one. * If the close event was not initiated by the user, it will also attempt to reconnect. * * @param {number} code The close code of the WebSocket connection. * @param {string} reason The reason for the close event. * @returns {Promise<void>} A promise that resolves when the disconnection is handled. */ protected close(code: number, reason: string): Promise<void>; /** * Handles the "error" event emitted by the WebSocket connection. * * This method is called when an error occurs on the WebSocket connection. * It emits a "nodeError" event with the node and the error as arguments and * a debug event indicating the error on the node. * @param {Error} error The error that occurred. */ protected error(error: Error): void; /** * Handles incoming messages from the Lavalink WebSocket connection. * @param {Buffer | string} d The message received from the WebSocket connection. * @returns {Promise<void>} A promise that resolves when the message is handled. * @emits {debug} - Emits a debug event with the message received from the WebSocket connection. * @emits {nodeError} - Emits a nodeError event if an unexpected op is received. * @emits {nodeRaw} - Emits a nodeRaw event with the raw message received from the WebSocket connection. * @private */ protected message(d: Buffer | string): Promise<void>; /** * Handles an event emitted from the Lavalink node. * @param {PlayerEvent & PlayerEvents} payload The event emitted from the node. * @returns {Promise<void>} A promise that resolves when the event has been handled. * @private */ protected handleEvent(payload: PlayerEvent & PlayerEvents): Promise<void>; /** * Emitted when a new track starts playing. * @param {Player} player The player that started playing the track. * @param {Track} track The track that started playing. * @param {TrackStartEvent} payload The payload of the event emitted by the node. * @private */ protected trackStart(player: Player, track: Track, payload: TrackStartEvent): void; /** * Emitted when a track ends playing. * @param {Player} player - The player that the track ended on. * @param {Track} track - The track that ended. * @param {TrackEndEvent} payload - The payload of the event emitted by the node. * @private */ protected trackEnd(player: Player, track: Track, payload: TrackEndEvent): Promise<void>; /** * Handles autoplay logic for a player. * This method is responsible for selecting an appropriate method of autoplay * and executing it. If autoplay is not enabled or all attempts have failed, * it will return false. * @param {Player} player - The player to handle autoplay for. * @param {number} attempt - The current attempt number of the autoplay. * @returns {Promise<boolean>} A promise that resolves to a boolean indicating if autoplay was successful. * @private */ private handleAutoplay; /** * Selects a platform from the given enabled sources. * @param {string[]} enabledSources - The enabled sources to select from. * @returns {SearchPlatform | null} - The selected platform or null if none was found. */ selectPlatform(enabledSources: string[]): SearchPlatform | null; /** * Handles Last.fm-based autoplay. * @param {Player} player - The player instance. * @param {Track} previousTrack - The previous track. * @param {SearchPlatform} platform - The selected platform. * @param {string} apiKey - The Last.fm API key. * @returns {Promise<boolean>} - Whether the autoplay was successful. */ private handlePlatformAutoplay; /** * Handles YouTube-based autoplay. * @param {Player} player - The player instance. * @param {Track} previousTrack - The previous track. * @returns {Promise<boolean>} - Whether the autoplay was successful. */ private handleYouTubeAutoplay; /** * Handles the scenario when a track fails to play or load. * Shifts the queue to the next track and emits a track end event. * If there is no next track, handles the queue end scenario. * If autoplay is enabled, plays the next track. * * @param {Player} player - The player instance associated with the track. * @param {Track} track - The track that failed. * @param {TrackEndEvent} payload - The event payload containing details about the track end. * @returns {Promise<void>} A promise that resolves when the track failure has been processed. * @private */ private handleFailedTrack; /** * Handles the scenario when a track is repeated. * Shifts the queue to the next track and emits a track end event. * If there is no next track, handles the queue end scenario. * If autoplay is enabled, plays the next track. * * @param {Player} player - The player instance associated with the track. * @param {Track} track - The track that is repeated. * @param {TrackEndEvent} payload - The event payload containing details about the track end. * @returns {Promise<void>} A promise that resolves when the repeated track has been processed. * @private */ private handleRepeatedTrack; /** * Plays the next track in the queue. * Updates the queue by shifting the current track to the previous track * and plays the next track if autoplay is enabled. * * @param {Player} player - The player associated with the track. * @param {Track} track - The track that has ended. * @param {TrackEndEvent} payload - The event payload containing additional data about the track end event. * @returns {void} * @private */ private playNextTrack; /** * Handles the event when a queue ends. * If autoplay is enabled, attempts to play the next track in the queue using the autoplay logic. * If all attempts fail, resets the player state and emits the `queueEnd` event. * @param {Player} player - The player associated with the track. * @param {Track} track - The track that has ended. * @param {TrackEndEvent} payload - The event payload containing additional data about the track end event. * @returns {Promise<void>} A promise that resolves when the queue end processing is complete. */ queueEnd(player: Player, track: Track, payload: TrackEndEvent): Promise<void>; /** * Fetches the lyrics of a track from the Lavalink node. * This method uses the `lavalyrics-plugin` to fetch the lyrics. * If the plugin is not available, it will throw a RangeError. * * @param {Track} track - The track to fetch the lyrics for. * @param {boolean} [skipTrackSource=false] - Whether to skip using the track's source URL. * @returns {Promise<Lyrics>} A promise that resolves with the lyrics data. */ getLyrics(track: Track, skipTrackSource?: boolean): Promise<Lyrics>; /** * Handles the event when a track becomes stuck during playback. * Stops the current track and emits a `trackStuck` event. * * @param {Player} player - The player associated with the track that became stuck. * @param {Track} track - The track that became stuck. * @param {TrackStuckEvent} payload - The event payload containing additional data about the track stuck event. * @returns {void} * @protected */ protected trackStuck(player: Player, track: Track, payload: TrackStuckEvent): Promise<void>; /** * Handles the event when a track has an error during playback. * Stops the current track and emits a `trackError` event. * * @param {Player} player - The player associated with the track that had an error. * @param {Track} track - The track that had an error. * @param {TrackExceptionEvent} payload - The event payload containing additional data about the track error event. * @returns {void} * @protected */ protected trackError(player: Player, track: Track, payload: TrackExceptionEvent): Promise<void>; /** * Emitted when the WebSocket connection for a player closes. * The payload of the event will contain the close code and reason if provided. * @param {Player} player - The player associated with the WebSocket connection. * @param {WebSocketClosedEvent} payload - The event payload containing additional data about the WebSocket close event. */ protected socketClosed(player: Player, payload: WebSocketClosedEvent): void; /** * Emitted when the segments for a track are loaded. * The payload of the event will contain the segments. * @param {Player} player - The player associated with the segments. * @param {Track} track - The track associated with the segments. * @param {SponsorBlockSegmentsLoaded} payload - The event payload containing additional data about the segments loaded event. */ private sponsorBlockSegmentLoaded; /** * Emitted when a segment of a track is skipped using the sponsorblock plugin. * The payload of the event will contain the skipped segment. * @param {Player} player - The player associated with the skipped segment. * @param {Track} track - The track associated with the skipped segment. * @param {SponsorBlockSegmentSkipped} payload - The event payload containing additional data about the segment skipped event. */ private sponsorBlockSegmentSkipped; /** * Emitted when chapters for a track are loaded using the sponsorblock plugin. * The payload of the event will contain the chapters. * @param {Player} player - The player associated with the chapters. * @param {Track} track - The track associated with the chapters. * @param {SponsorBlockChaptersLoaded} payload - The event payload containing additional data about the chapters loaded event. */ private sponsorBlockChaptersLoaded; /** * Emitted when a chapter of a track is started using the sponsorblock plugin. * The payload of the event will contain the started chapter. * @param {Player} player - The player associated with the started chapter. * @param {Track} track - The track associated with the started chapter. * @param {SponsorBlockChapterStarted} payload - The event payload containing additional data about the chapter started event. */ private sponsorBlockChapterStarted; /** * Fetches Lavalink node information. * @returns {Promise<LavalinkInfo>} A promise that resolves to the Lavalink node information. */ fetchInfo(): Promise<LavalinkInfo>; /** * Gets the current sponsorblock segments for a player. * @param {Player} player - The player to get the sponsorblocks for. * @returns {Promise<SponsorBlockSegment[]>} A promise that resolves to the sponsorblock segments. * @throws {RangeError} If the sponsorblock-plugin is not available in the Lavalink node. */ getSponsorBlock(player: Player): Promise<SponsorBlockSegment[]>; /** * Sets the sponsorblock segments for a player. * @param {Player} player - The player to set the sponsor blocks for. * @param {SponsorBlockSegment[]} segments - The sponsorblock segments to set. Defaults to `[SponsorBlockSegment.Sponsor, SponsorBlockSegment.SelfPromo]` if not provided. * @returns {Promise<void>} The promise is resolved when the operation is complete. * @throws {RangeError} If the sponsorblock-plugin is not available in the Lavalink node. * @throws {RangeError} If no segments are provided. * @throws {SyntaxError} If an invalid sponsorblock is provided. * @example * ```ts * // use it on the player via player.setSponsorBlock(); * player.setSponsorBlock([SponsorBlockSegment.Sponsor, SponsorBlockSegment.SelfPromo]); * ``` */ setSponsorBlock(player: Player, segments?: SponsorBlockSegment[]): Promise<void>; /** * Deletes the sponsorblock segments for a player. * @param {Player} player - The player to delete the sponsorblocks for. * @returns {Promise<void>} The promise is resolved when the operation is complete. * @throws {RangeError} If the sponsorblock-plugin is not available in the Lavalink node. */ deleteSponsorBlock(player: Player): Promise<void>; /** * Creates a README.md or README.txt file in the magmastream directory * if it doesn't already exist. This file is used to store player data * for autoresume and other features. * @private */ private createReadmeFile; } export 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; /** Whether to resume the previous session. */ resumeStatus?: boolean; /** The time the lavalink server will wait before it removes the player. */ resumeTimeout?: number; /** The timeout used for api calls. */ requestTimeout?: number; /** Priority of the node. */ priority?: number; } export 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; } export 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; } export interface CPUStats { /** The core amount the host machine has. */ cores: number; /** The system load. */ systemLoad: number; /** The lavalink load. */ lavalinkLoad: number; } export interface FrameStats { /** The amount of sent frames. */ sent?: number; /** The amount of nulled frames. */ nulled?: number; /** The amount of deficit frames. */ deficit?: number; } export 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; }[]; } export interface LyricsLine { timestamp: number; duration: number; line: string; plugin: object; } export interface Lyrics { source: string; provider: string; text?: string; lines: LyricsLine[]; plugin: object[]; }