discord-player
Version:
Complete framework to facilitate music commands using discord.js
1,760 lines (1,741 loc) • 106 kB
TypeScript
import * as discord_js from 'discord.js';
import { Client, User, UserResolvable, GuildVoiceChannelResolvable, VoiceChannel, StageChannel, Guild, VoiceState, VoiceBasedChannel, GuildResolvable, Snowflake } from 'discord.js';
import Eris from 'eris';
import { ListenerSignature, DefaultListener, EventEmitter, Collection, Queue, QueueStrategy } from '@discord-player/utils';
import { Readable, Duplex } from 'stream';
import * as _discord_player_equalizer from '@discord-player/equalizer';
import { EqualizerBand, BiquadFilters, PCMFilters, FiltersChain } from '@discord-player/equalizer';
export { AF_NIGHTCORE_RATE, AF_VAPORWAVE_RATE, BASS_EQ_BANDS, FilterType as BiquadFilterType, BiquadFilters, FiltersChain, AudioFilters as PCMAudioFilters, PCMFilters, Q_BUTTERWORTH, VolumeTransformer } from '@discord-player/equalizer';
import { AudioResource, StreamType, AudioPlayerError, VoiceConnection, AudioPlayer, AudioPlayerStatus } from 'discord-voip';
export { AudioPlayer, CreateAudioPlayerOptions, JoinConfig, JoinVoiceChannelOptions, StreamType, createAudioPlayer, createAudioResource, getVoiceConnection, getVoiceConnections, joinVoiceChannel } from 'discord-voip';
import { Transform, Writable, TransformCallback } from 'node:stream';
import { RequestOptions } from 'http';
import { FFmpegLib } from '@discord-player/ffmpeg';
export * from '@discord-player/ffmpeg';
declare function isErisProxy(client: any): client is Eris.Client;
/**
* Allows Eris clients to be used with discord-player. When this method is called, discord-player creates a proxy object that intercepts certain methods and properties to make it compatible with discord-player.
* @param client The Eris client to be used.
* @returns The Eris client with discord-player compatibility.
*/
declare function createErisCompat(client: Eris.Client): Client;
declare class PlayerEventsEmitter<L extends ListenerSignature<L> = DefaultListener> extends EventEmitter<L> {
#private;
requiredEvents: Array<keyof L>;
constructor(requiredEvents?: Array<keyof L>);
on<K extends keyof L>(name: K, listener: L[K]): this;
once<K extends keyof L>(name: K, listener: L[K]): this;
addListener<K extends keyof L>(name: K, listener: L[K]): this;
off<K extends keyof L>(name: K, listener: L[K]): this;
removeListener<K extends keyof L>(name: K, listener: L[K]): this;
removeAllListeners<K extends keyof L>(name?: K): this;
emit<K extends keyof L>(name: K, ...args: Parameters<L[K]>): boolean;
get hasDebugger(): boolean;
}
type FiltersName = keyof QueueFilters;
/**
* Represents FFmpeg filters
*/
interface QueueFilters {
bassboost_low?: boolean;
bassboost?: boolean;
bassboost_high?: boolean;
'8D'?: boolean;
vaporwave?: boolean;
nightcore?: boolean;
phaser?: boolean;
tremolo?: boolean;
vibrato?: boolean;
reverse?: boolean;
treble?: boolean;
normalizer?: boolean;
normalizer2?: boolean;
surrounding?: boolean;
pulsator?: boolean;
subboost?: boolean;
karaoke?: boolean;
flanger?: boolean;
gate?: boolean;
haas?: boolean;
mcompand?: boolean;
mono?: boolean;
mstlr?: boolean;
mstrr?: boolean;
compressor?: boolean;
expander?: boolean;
softlimiter?: boolean;
chorus?: boolean;
chorus2d?: boolean;
chorus3d?: boolean;
fadein?: boolean;
dim?: boolean;
earrape?: boolean;
lofi?: boolean;
silenceremove?: boolean;
}
declare class AudioFilters {
constructor();
static filters: Record<FiltersName, string>;
static get<K extends FiltersName>(name: K): Record<keyof QueueFilters, string>[K];
static has<K extends FiltersName>(name: K): boolean;
static [Symbol.iterator](): IterableIterator<{
name: FiltersName;
value: string;
}>;
static get names(): (keyof QueueFilters)[];
static get length(): number;
static toString(): string;
/**
* Create ffmpeg args from the specified filters name
* @param filter The filter name
* @returns
*/
static create<K extends FiltersName>(filters?: (K | string)[]): string;
/**
* Defines audio filter
* @param filterName The name of the filter
* @param value The ffmpeg args
*/
static define(filterName: string, value: string): void;
/**
* Defines multiple audio filters
* @param filtersArray Array of filters containing the filter name and ffmpeg args
*/
static defineBulk(filtersArray: {
name: string;
value: string;
}[]): void;
}
/**
* The search query type
* This can be one of:
* - AUTO
* - YOUTUBE
* - YOUTUBE_PLAYLIST
* - SOUNDCLOUD_TRACK
* - SOUNDCLOUD_PLAYLIST
* - SOUNDCLOUD
* - SPOTIFY_SONG
* - SPOTIFY_ALBUM
* - SPOTIFY_PLAYLIST
* - SPOTIFY_SEARCH
* - FACEBOOK
* - VIMEO
* - ARBITRARY
* - REVERBNATION
* - YOUTUBE_SEARCH
* - YOUTUBE_VIDEO
* - SOUNDCLOUD_SEARCH
* - APPLE_MUSIC_SONG
* - APPLE_MUSIC_ALBUM
* - APPLE_MUSIC_PLAYLIST
* - APPLE_MUSIC_SEARCH
* - FILE
* - AUTO_SEARCH
* - DISCORD_PLAYER_BLOB
* @typedef {string} QueryType
*/
declare const QueryType: {
readonly AUTO: "auto";
readonly YOUTUBE: "youtube";
readonly YOUTUBE_PLAYLIST: "youtubePlaylist";
readonly SOUNDCLOUD_TRACK: "soundcloudTrack";
readonly SOUNDCLOUD_PLAYLIST: "soundcloudPlaylist";
readonly SOUNDCLOUD: "soundcloud";
readonly SPOTIFY_SONG: "spotifySong";
readonly SPOTIFY_ALBUM: "spotifyAlbum";
readonly SPOTIFY_PLAYLIST: "spotifyPlaylist";
readonly SPOTIFY_SEARCH: "spotifySearch";
readonly FACEBOOK: "facebook";
readonly VIMEO: "vimeo";
readonly ARBITRARY: "arbitrary";
readonly REVERBNATION: "reverbnation";
readonly YOUTUBE_SEARCH: "youtubeSearch";
readonly YOUTUBE_VIDEO: "youtubeVideo";
readonly SOUNDCLOUD_SEARCH: "soundcloudSearch";
readonly APPLE_MUSIC_SONG: "appleMusicSong";
readonly APPLE_MUSIC_ALBUM: "appleMusicAlbum";
readonly APPLE_MUSIC_PLAYLIST: "appleMusicPlaylist";
readonly APPLE_MUSIC_SEARCH: "appleMusicSearch";
readonly FILE: "file";
readonly AUTO_SEARCH: "autoSearch";
readonly DISCORD_PLAYER_BLOB: "discordPlayerBlob";
};
type QueryType = (typeof QueryType)[keyof typeof QueryType];
type SearchQueryType = keyof typeof QueryType | QueryType;
interface ResolvedQuery {
type: (typeof QueryType)[keyof typeof QueryType];
query: string;
}
declare class QueryResolver {
/**
* Query resolver
*/
private constructor();
static get regex(): {
spotifyAlbumRegex: RegExp;
spotifyPlaylistRegex: RegExp;
spotifySongRegex: RegExp;
vimeoRegex: RegExp;
reverbnationRegex: RegExp;
attachmentRegex: RegExp;
appleMusicAlbumRegex: RegExp;
appleMusicPlaylistRegex: RegExp;
appleMusicSongRegex: RegExp;
soundcloudTrackRegex: RegExp;
soundcloudPlaylistRegex: RegExp;
youtubePlaylistRegex: RegExp;
discordPlayerBlobRegex: RegExp;
};
/**
* Pre-resolve redirect urls
*/
static preResolve(query: string, maxDepth?: number): Promise<string>;
/**
* Resolves the given search query
* @param {string} query The query
*/
static resolve(query: string, fallbackSearchEngine?: (typeof QueryType)[keyof typeof QueryType]): ResolvedQuery;
/**
* Parses vimeo id from url
* @param {string} query The query
* @returns {string}
*/
static getVimeoID(query: string): string | null | undefined;
static validateId(q: string): boolean;
static validateURL(q: string): boolean;
}
interface SearchResultData {
query: string;
queryType?: SearchQueryType | QueryExtractorSearch | null;
extractor?: BaseExtractor | null;
playlist?: Playlist | null;
tracks?: Track[];
requestedBy?: User | null;
}
interface PlayOptions {
/**
* If this play was triggered for filters update
*/
filtersUpdate?: boolean;
/**
* FFmpeg args passed to encoder
*/
encoderArgs?: string[];
/**
* Time to seek to before playing
*/
seek?: number;
/**
* If it should start playing the provided track immediately
*/
immediate?: boolean;
}
type QueryExtractorSearch = `ext:${string}`;
interface SearchOptions {
/**
* The user who requested this search
*/
requestedBy?: UserResolvable;
/**
* The query search engine, can be extractor name to target specific one (custom)
*/
searchEngine?: SearchQueryType | QueryExtractorSearch;
/**
* List of the extractors to block
*/
blockExtractors?: string[];
/**
* If it should ignore query cache lookup
*/
ignoreCache?: boolean;
/**
* Fallback search engine to use
*/
requestOptions?: any;
/**
* Fallback search engine to use
*/
fallbackSearchEngine?: (typeof QueryType)[keyof typeof QueryType];
}
interface PlayerSearchResult {
playlist: Playlist | null;
tracks: Track[];
}
declare class SearchResult {
player: Player;
private _data;
constructor(player: Player, _data: SearchResultData);
setQueryType(type: SearchQueryType | QueryExtractorSearch): this;
setRequestedBy(user: User): this;
setExtractor(extractor: BaseExtractor): this;
setTracks(tracks: Track[]): this;
setQuery(query: string): this;
setPlaylist(playlist: Playlist): this;
/**
* The search query
*/
get query(): string;
/**
* The search query type
*/
get queryType(): SearchQueryType | `ext:${string}`;
/**
* The extractor
*/
get extractor(): BaseExtractor<object> | null;
/**
* Playlist result
*/
get playlist(): Playlist | null | undefined;
/**
* Tracks result
*/
get tracks(): Track<unknown>[];
/**
* Requested by
*/
get requestedBy(): User | null;
/**
* Re-execute this search
*/
execute(): Promise<SearchResult>;
/**
* If this search result is empty
*/
isEmpty(): boolean;
/**
* If this search result has playlist
*/
hasPlaylist(): boolean;
/**
* If this search result has tracks
*/
hasTracks(): boolean;
/**
* JSON representation of this search
*/
toJSON(): {
query: string;
queryType: SearchQueryType | `ext:${string}`;
playlist: PlaylistJSON | null;
tracks: TrackJSON[];
extractor: string | null;
requestedBy: {} | null;
};
}
declare enum SerializedType {
Track = "track",
Playlist = "playlist"
}
type Encodable = SerializedTrack | SerializedPlaylist;
declare function serialize(data: Track | Playlist | any): any;
declare function deserialize(player: Player, data: Encodable): Track<unknown> | Playlist;
declare function encode(data: Encodable): string;
declare function decode(data: string): any;
declare function tryIntoThumbnailString(data: any): any;
type TrackResolvable = Track | string | number;
type WithMetadata<T extends object, M> = T & {
metadata: M;
requestMetadata(): Promise<M>;
};
type SerializedTrack = ReturnType<Track['serialize']>;
/**
* The track source:
* - soundcloud
* - youtube
* - spotify
* - apple_music
* - arbitrary
*/
type TrackSource = 'soundcloud' | 'youtube' | 'spotify' | 'apple_music' | 'arbitrary';
interface RawTrackData {
/**
* The title
*/
title: string;
/**
* The description
*/
description: string;
/**
* The author
*/
author: string;
/**
* The url
*/
url: string;
/**
* The thumbnail
*/
thumbnail: string;
/**
* The duration
*/
duration: string;
/**
* The duration in ms
*/
views: number;
/**
* The user who requested this track
*/
requestedBy?: User | null;
/**
* The playlist
*/
playlist?: Playlist;
/**
* The source
*/
source?: TrackSource;
/**
* The engine
*/
engine?: any;
/**
* If this track is live
*/
live?: boolean;
/**
* The raw data
*/
raw?: any;
/**
* The query type
*/
queryType?: SearchQueryType;
/**
* The serialized title
*/
cleanTitle?: string;
}
interface TrackJSON {
/**
* The track id
*/
id: string;
/**
* The track title
*/
title: string;
/**
* The track description
*/
description: string;
/**
* The track author
*/
author: string;
/**
* The track url
*/
url: string;
/**
* The track thumbnail
*/
thumbnail: string;
/**
* The track duration
*/
duration: string;
/**
* The track duration in ms
*/
durationMS: number;
/**
* The track views
*/
views: number;
/**
* The user id who requested this track
*/
requestedBy: string;
/**
* The playlist info (if any)
*/
playlist?: PlaylistJSON;
}
declare class Track<T = unknown> {
#private;
readonly player: Player;
title: string;
description: string;
author: string;
url: string;
thumbnail: string;
duration: string;
views: number;
requestedBy: User | null;
playlist?: Playlist;
queryType: SearchQueryType | null | undefined;
raw: any;
extractor: BaseExtractor | null;
readonly id: string;
private __metadata;
private __reqMetadataFn;
cleanTitle: string;
live: boolean;
bridgedExtractor: BaseExtractor | null;
bridgedTrack: Track | null;
/**
* Track constructor
* @param player The player that instantiated this Track
* @param data Track data
*/
constructor(player: Player, data: Partial<WithMetadata<RawTrackData, T>>);
/**
* Sets audio resource for this track. This is not useful outside of the library.
* @param resource Audio resource
*/
setResource(resource: AudioResource<Track> | null): void;
/**
* Gets audio resource for this track
*/
get resource(): AudioResource<Track<unknown>> | null;
/**
* Whether this track has an audio resource
*/
get hasResource(): boolean;
/**
* Request metadata for this track
*/
requestMetadata(): Promise<T | null>;
/**
* Set metadata for this track
*/
setMetadata(m: T | null): void;
/**
* Metadata of this track
*/
get metadata(): T | null;
/**
* If this track has metadata
*/
get hasMetadata(): boolean;
/**
* The queue in which this track is located
*/
get queue(): GuildQueue;
/**
* The track duration in millisecond
*/
get durationMS(): number;
/**
* Discord hyperlink representation of this track
*/
toHyperlink(): string;
/**
* Returns source of this track
*/
get source(): any;
/**
* String representation of this track
*/
toString(): string;
/**
* Raw JSON representation of this track
*/
toJSON(hidePlaylist?: boolean): TrackJSON;
/**
* Serialized track data that can be reconstructed
*/
serialize(): {
title: string;
description: string;
author: string;
url: string;
thumbnail: any;
duration: string;
views: number;
requested_by: {} | null;
source: any;
live: boolean;
query_type: SearchQueryType | null | undefined;
extractor: string | null;
metadata: T | null;
$type: SerializedType;
$encoder_version: string;
};
/**
* Construct a track from serialized data
* @param player Player instance
* @param data Serialized data
*/
static fromSerialized(player: Player, data: ReturnType<Track['serialize']>): Track<unknown>;
/**
* Get belonging queues of this track
*/
getBelongingQueues(): Collection<string, GuildQueue<unknown>>;
/**
* Play this track to the given voice channel. If queue exists and another track is being played, this track will be added to the queue.
* @param channel Voice channel on which this track shall be played
* @param options Node initialization options
*/
play<T = unknown>(channel: GuildVoiceChannelResolvable, options?: PlayerNodeInitializerOptions<T>): Promise<PlayerNodeInitializationResult<T>>;
}
interface CreateStreamOps {
type?: StreamType;
data: Track;
disableVolume?: boolean;
disableEqualizer?: boolean;
disableBiquad?: boolean;
eq?: EqualizerBand[];
biquadFilter?: BiquadFilters;
disableFilters?: boolean;
defaultFilters?: PCMFilters[];
volume?: number;
disableResampler?: boolean;
sampleRate?: number;
skipFFmpeg?: boolean;
}
interface VoiceEvents {
error: (error: AudioPlayerError) => any;
debug: (message: string) => any;
start: (resource: AudioResource<Track>) => any;
finish: (resource: AudioResource<Track>) => any;
dsp: (filters: PCMFilters[]) => any;
eqBands: (filters: EqualizerBand[]) => any;
sampleRate: (filters: number) => any;
biquad: (filters: BiquadFilters) => any;
volume: (volume: number) => any;
destroyed: () => any;
}
declare class StreamDispatcher extends EventEmitter<VoiceEvents> {
#private;
queue: GuildQueue;
readonly connectionTimeout: number;
voiceConnection: VoiceConnection;
audioPlayer: AudioPlayer;
channel: VoiceChannel | StageChannel;
audioResource?: AudioResource<Track> | null;
dsp: FiltersChain;
/**
* Creates new connection object
* @param {VoiceConnection} connection The connection
* @param {VoiceChannel|StageChannel} channel The connected channel
* @private
*/
constructor(connection: VoiceConnection, channel: VoiceChannel | StageChannel, queue: GuildQueue, connectionTimeout?: number, audioPlayer?: AudioPlayer);
/**
* Check if the player has been paused manually
*/
get paused(): boolean;
set paused(val: boolean);
/**
* Whether or not the player is currently paused automatically or manually.
*/
isPaused(): boolean;
/**
* Whether or not the player is currently buffering
*/
isBuffering(): boolean;
/**
* Whether or not the player is currently playing
*/
isPlaying(): boolean;
/**
* Whether or not the player is currently idle
*/
isIdle(): boolean;
/**
* Whether or not the voice connection has been destroyed
*/
isDestroyed(): boolean;
/**
* Whether or not the voice connection has been destroyed
*/
isDisconnected(): boolean;
/**
* Whether or not the voice connection is ready to play
*/
isReady(): boolean;
/**
* Whether or not the voice connection is signalling
*/
isSignalling(): boolean;
/**
* Whether or not the voice connection is connecting
*/
isConnecting(): boolean;
/**
* Creates stream
* @param {Readable} src The stream source
* @param {object} [ops] Options
* @returns {AudioResource}
*/
createStream(src: Readable, ops: CreateStreamOps): Promise<AudioResource<Track<unknown>>>;
get resampler(): _discord_player_equalizer.PCMResampler | null;
get filters(): _discord_player_equalizer.AudioFilter | null;
get biquad(): _discord_player_equalizer.BiquadStream | null;
get equalizer(): _discord_player_equalizer.EqualizerStream | null;
/**
* The player status
* @type {AudioPlayerStatus}
*/
get status(): AudioPlayerStatus;
/**
* Disconnects from voice
* @returns {void}
*/
disconnect(): void;
/**
* Destroys this dispatcher
*/
destroy(): void;
/**
* Stops the player
* @returns {void}
*/
end(): void;
/**
* Pauses the stream playback
* @param {boolean} [interpolateSilence=false] If true, the player will play 5 packets of silence after pausing to prevent audio glitches.
* @returns {boolean}
*/
pause(interpolateSilence?: boolean): boolean;
/**
* Resumes the stream playback
* @returns {boolean}
*/
resume(): boolean;
/**
* Play stream
* @param {AudioResource<Track>} [resource=this.audioResource] The audio resource to play
* @param {boolean} [opus=false] Whether or not to use opus
* @returns {Promise<StreamDispatcher>}
*/
playStream(resource?: AudioResource<Track>): Promise<this | undefined>;
/**
* Sets playback volume
* @param {number} value The volume amount
* @returns {boolean}
*/
setVolume(value: number): boolean;
/**
* The current volume
* @type {number}
*/
get volume(): number;
/**
* The playback time
* @type {number}
*/
get streamTime(): number;
}
declare class GuildQueueHistory<Meta = unknown> {
queue: GuildQueue<Meta>;
tracks: Queue<Track<unknown>>;
constructor(queue: GuildQueue<Meta>);
/**
* Current track in the queue
*/
get currentTrack(): Track<unknown> | null;
/**
* Next track in the queue
*/
get nextTrack(): Track<unknown> | null;
/**
* Previous track in the queue
*/
get previousTrack(): Track<unknown> | null;
/**
* If history is disabled
*/
get disabled(): boolean;
/**
* Gets the size of the queue
*/
get size(): number;
getSize(): number;
/**
* If history is empty
*/
isEmpty(): boolean;
/**
* Add track to track history
* @param track The track to add
*/
push(track: Track | Track[]): boolean;
/**
* Clear history
*/
clear(): void;
/**
* Play the next track in the queue
*/
next(): Promise<void>;
/**
* Play the previous track in the queue
*/
previous(preserveCurrent?: boolean): Promise<void>;
/**
* Alias to [GuildQueueHistory].previous()
*/
back(preserveCurrent?: boolean): Promise<void>;
/**
* Resize history store
*/
resize(): void;
}
interface AsyncQueueAcquisitionOptions {
/**
* AbortSignal to cancel this entry
*/
signal?: AbortSignal;
}
type AsyncQueueExceptionHandler = (exception: Error) => void;
declare class AsyncQueue {
/**
* The queued entries
*/
entries: Array<AsyncQueueEntry>;
exceptionHandler?: AsyncQueueExceptionHandler;
/**
* Clear entries queue
* @param consume Whether or not to consume all entries before clearing
*/
clear(consume?: boolean): void;
/**
* The total number of entries in this queue. Returns `0` if no entries are available.
*/
get size(): number;
/**
* Acquire an entry.
*
* @example // lock the queue
* const entry = asyncQueue.acquire();
* // wait until previous task is completed
* await entry.getTask();
* // do something expensive
* await performSomethingExpensive();
* // make sure to release the lock once done
* asyncQueue.release();
*
*/
acquire(options?: AsyncQueueAcquisitionOptions): AsyncQueueEntry;
/**
* Release the current acquisition and move to next entry.
*/
release(): void;
/**
* Cancel all entries
*/
cancelAll(): void;
/**
* Remove the given entry from the queue
* @param entry The entry to remove
*/
removeEntry(entry: AsyncQueueEntry): boolean;
}
declare class AsyncQueueEntry {
queue: AsyncQueue;
options?: AsyncQueueAcquisitionOptions | undefined;
readonly id: string;
private readonly promise;
signal: AbortSignal | null;
onAbort: (() => void) | null;
private resolve;
private reject;
constructor(queue: AsyncQueue, options?: AsyncQueueAcquisitionOptions | undefined);
setAbortSignal(signal: AbortSignal): void;
consume(): void;
release(): void;
cancel(): void;
cleanup(): void;
getTask(): Promise<void>;
}
declare const FFMPEG_SRATE_REGEX: RegExp;
interface PlayerProgressbarOptions {
/**
* If it should render time codes
*/
timecodes?: boolean;
/**
* If it should create progress bar for the whole queue
*/
length?: number;
/**
* The bar length
*/
leftChar?: string;
/**
* The elapsed time track
*/
rightChar?: string;
/**
* The remaining time track
*/
separator?: string;
/**
* The separation between timestamp and line
*/
indicator?: string;
/**
* The indicator
*/
queue?: boolean;
}
interface ResourcePlayOptions {
queue?: boolean;
seek?: number;
transitionMode?: boolean;
}
interface SkipOptions {
reason: TrackSkipReason;
description: string;
}
interface PlayerTimestamp {
current: {
label: string;
value: number;
};
total: {
label: string;
value: number;
};
progress: number;
}
interface StreamConfig {
dispatcherConfig: CreateStreamOps;
playerConfig: ResourcePlayOptions;
}
declare class GuildQueuePlayerNode<Meta = unknown> {
#private;
queue: GuildQueue<Meta>;
tasksQueue: AsyncQueue;
constructor(queue: GuildQueue<Meta>);
/**
* If the player is currently in idle mode
*/
isIdle(): boolean;
/**
* If the player is currently buffering the track
*/
isBuffering(): boolean;
/**
* If the player is currently playing a track
*/
isPlaying(): boolean;
/**
* If the player is currently paused
*/
isPaused(): boolean;
/**
* Reset progress history
*/
resetProgress(): void;
/**
* Set player progress
*/
setProgress(progress: number): void;
/**
* The stream time for current session
*/
get streamTime(): number;
/**
* Current playback duration with history included
*/
get playbackTime(): number;
/**
* Get duration multiplier
*/
getDurationMultiplier(): number;
/**
* Estimated progress of the player
*/
get estimatedPlaybackTime(): number;
/**
* Estimated total duration of the player
*/
get estimatedDuration(): number;
/**
* Total duration of the current audio track
*/
get totalDuration(): number;
/**
* Get stream progress
* @param ignoreFilters Ignore filters
*/
getTimestamp(ignoreFilters?: boolean): PlayerTimestamp | null;
/**
* Create progress bar for current progress
* @param options Progress bar options
*/
createProgressBar(options?: PlayerProgressbarOptions): string | null;
/**
* Seek the player
* @param duration The duration to seek to
*/
seek(duration: number): Promise<boolean>;
/**
* Current volume
*/
get volume(): number;
/**
* Set volume
* @param vol Volume amount to set
*/
setVolume(vol: number): boolean;
/**
* Set bit rate
* @param rate The bit rate to set
*/
setBitrate(rate: number | 'auto'): void;
/**
* Set paused state
* @param state The state
*/
setPaused(state: boolean): boolean;
/**
* Pause the playback
*/
pause(): boolean;
/**
* Resume the playback
*/
resume(): boolean;
/**
* Skip current track
*/
skip(options?: SkipOptions): boolean;
/**
* Remove the given track from queue
* @param track The track to remove
* @param emitEvent Whether or not to emit the event @defaultValue true
*/
remove(track: TrackResolvable, emitEvent?: boolean): Track<unknown> | null;
/**
* Jump to specific track on the queue
* @param track The track to jump to without removing other tracks
*/
jump(track: TrackResolvable): boolean;
/**
* Get track position
* @param track The track
*/
getTrackPosition(track: TrackResolvable): number;
/**
* Skip to the given track, removing others on the way
* @param track The track to skip to
*/
skipTo(track: TrackResolvable): boolean;
/**
* Insert a track on the given position in queue
* @param track The track to insert
* @param index The position to insert to, defaults to 0.
*/
insert(track: Track, index?: number): void;
/**
* Moves a track in the queue
* @param from The track to move
* @param to The position to move to
*/
move(from: TrackResolvable, to: number): void;
/**
* Copy a track in the queue
* @param from The track to clone
* @param to The position to clone at
*/
copy(from: TrackResolvable, to: number): void;
/**
* Swap two tracks in the queue
* @param first The first track to swap
* @param second The second track to swap
*/
swap(first: TrackResolvable, second: TrackResolvable): void;
/**
* Stop the playback
* @param force Whether or not to forcefully stop the playback
*/
stop(force?: boolean): boolean;
/**
* Play the given track
* @param res The track to play
* @param options Options for playing the track
*/
play(res?: Track | null, options?: ResourcePlayOptions): Promise<void>;
}
interface FFmpegStreamOptions {
fmt?: string;
encoderArgs?: string[];
seek?: number;
skip?: boolean;
cookies?: string;
}
declare function FFMPEG_ARGS_STRING(stream: string, fmt?: string, cookies?: string): string[];
declare function FFMPEG_ARGS_PIPED(fmt?: string): string[];
/**
* Creates FFmpeg stream
* @param stream The source stream
* @param options FFmpeg stream options
*/
declare function createFFmpegStream(stream: Readable | Duplex | string, options?: FFmpegStreamOptions): Readable;
type Filters = keyof typeof AudioFilters.filters;
type EQPreset = {
Flat: EqualizerBand[];
Classical: EqualizerBand[];
Club: EqualizerBand[];
Dance: EqualizerBand[];
FullBass: EqualizerBand[];
FullBassTreble: EqualizerBand[];
FullTreble: EqualizerBand[];
Headphones: EqualizerBand[];
LargeHall: EqualizerBand[];
Live: EqualizerBand[];
Party: EqualizerBand[];
Pop: EqualizerBand[];
Reggae: EqualizerBand[];
Rock: EqualizerBand[];
Ska: EqualizerBand[];
Soft: EqualizerBand[];
SoftRock: EqualizerBand[];
Techno: EqualizerBand[];
};
declare const EqualizerConfigurationPreset: Readonly<EQPreset>;
declare class FFmpegFilterer<Meta = unknown> {
#private;
af: GuildQueueAudioFilters<Meta>;
constructor(af: GuildQueueAudioFilters<Meta>);
/**
* Indicates whether ffmpeg may be skipped
*/
get skippable(): boolean;
/**
* Set input args for FFmpeg
*/
setInputArgs(args: string[]): void;
/**
* Get input args
*/
get inputArgs(): string[];
/**
* Get encoder args
*/
get encoderArgs(): string[];
/**
* Get final ffmpeg args
*/
get args(): string[];
/**
* Create ffmpeg stream
* @param source The stream source
* @param options The stream options
*/
createStream(source: string | Readable, options: FFmpegStreamOptions): Readable;
/**
* Set ffmpeg filters
* @param filters The filters
*/
setFilters(filters: Filters[] | Record<Filters, boolean> | string[] | boolean): Promise<boolean>;
/**
* Currently active ffmpeg filters
*/
get filters(): Filters[];
set filters(filters: Filters[]);
/**
* Toggle given ffmpeg filter(s)
* @param filters The filter(s)
*/
toggle(filters: Filters[] | Filters): Promise<boolean>;
/**
* Set default filters
* @param ff Filters list
*/
setDefaults(ff: Filters[]): void;
/**
* Get list of enabled filters
*/
getFiltersEnabled(): (keyof QueueFilters)[];
/**
* Get list of disabled filters
*/
getFiltersDisabled(): (keyof QueueFilters)[];
/**
* Check if the given filter is enabled
* @param filter The filter
*/
isEnabled<T extends Filters>(filter: T): boolean;
/**
* Check if the given filter is disabled
* @param filter The filter
*/
isDisabled<T extends Filters>(filter: T): boolean;
/**
* Check if the given filter is a valid filter
* @param filter The filter to test
*/
isValidFilter(filter: string): filter is FiltersName;
/**
* Convert current filters to array
*/
toArray(): string[];
/**
* Convert current filters to JSON object
*/
toJSON(): Record<keyof QueueFilters, string>;
/**
* String representation of current filters
*/
toString(): string;
}
interface GuildQueueAFiltersCache {
equalizer: EqualizerBand[];
biquad: BiquadFilters | null;
filters: PCMFilters[];
volume: number;
sampleRate: number;
}
declare class GuildQueueAudioFilters<Meta = unknown> {
queue: GuildQueue<Meta>;
graph: AFilterGraph<Meta>;
ffmpeg: FFmpegFilterer<Meta>;
equalizerPresets: Readonly<EQPreset>;
_lastFiltersCache: GuildQueueAFiltersCache;
constructor(queue: GuildQueue<Meta>);
/**
* Volume transformer
*/
get volume(): _discord_player_equalizer.VolumeTransformer | null;
/**
* 15 Band Equalizer
*/
get equalizer(): _discord_player_equalizer.EqualizerStream | null;
/**
* Digital biquad filters
*/
get biquad(): _discord_player_equalizer.BiquadStream | null;
/**
* DSP filters
*/
get filters(): _discord_player_equalizer.AudioFilter | null;
/**
* Audio resampler
*/
get resampler(): _discord_player_equalizer.PCMResampler | null;
/**
* Replay current track in transition mode
* @param seek The duration to seek to
*/
triggerReplay(seek?: number): Promise<boolean>;
}
declare class AFilterGraph<Meta = unknown> {
af: GuildQueueAudioFilters<Meta>;
constructor(af: GuildQueueAudioFilters<Meta>);
get ffmpeg(): (keyof QueueFilters)[];
get equalizer(): EqualizerBand[];
get biquad(): "SinglePoleLowPassApprox" | "SinglePoleLowPass" | "LowPass" | "HighPass" | "BandPass" | "Notch" | "AllPass" | "LowShelf" | "HighShelf" | "PeakingEQ" | null;
get filters(): ("8D" | "Tremolo" | "Vibrato")[];
get volume(): _discord_player_equalizer.VolumeTransformer | null;
get resampler(): _discord_player_equalizer.PCMResampler | null;
dump(): FilterGraph;
}
interface FilterGraph {
ffmpeg: Filters[];
equalizer: EqualizerBand[];
biquad: Exclude<BiquadFilters, number> | null;
filters: PCMFilters[];
volume: number;
sampleRate: number;
}
interface GuildQueueStatisticsMetadata {
latency: {
eventLoop: number;
voiceConnection: number;
};
status: {
buffering: boolean;
playing: boolean;
paused: boolean;
idle: boolean;
};
tracksCount: number;
historySize: number;
extractors: number;
listeners: number;
memoryUsage: NodeJS.MemoryUsage;
versions: {
node: string;
player: string;
};
}
declare class GuildQueueStatistics<Meta = unknown> {
queue: GuildQueue<Meta>;
constructor(queue: GuildQueue<Meta>);
/**
* Generate statistics of this queue
*/
generate(): GuildQueueStatisticsMetadata;
}
type RequestEntity = () => Promise<Response>;
declare class SequentialBucket {
limit: number;
remaining: number;
resetAfter: number;
queue: AsyncQueue;
MAX_RETRIES: number;
/**
* Checks if the bucket is rate limited.
*/
isRateLimited(): boolean;
/**
* Enqueues a request.
* @param req The request function to enqueue
*/
enqueue(req: RequestEntity): Promise<Response>;
private _request;
private _patchHeaders;
}
interface LrcSearchParams {
/**
* The query to search for. Either this or trackName is required.
*/
q?: string;
/**
* The track name to search for. Either this or query is required.
*/
trackName?: string;
/**
* The artist name
*/
artistName?: string;
/**
* The album name
*/
albumName?: string;
}
interface LrcGetParams extends Required<Omit<LrcSearchParams, 'query'>> {
/**
* The duration of the track
*/
duration: number;
}
interface LrcSearchResult {
/**
* The track id
*/
id: number;
/**
* The track name
*/
name: string;
/**
* The artist name
*/
trackName: string;
/**
* The album name
*/
artistName: string;
/**
* The album name
*/
albumName: string;
/**
* The duration of the track
*/
duration: number;
/**
* The release date of the track
*/
instrumental: boolean;
/**
* The release date of the track
*/
plainLyrics: string;
/**
* The release date of the track
*/
syncedLyrics?: string;
}
type LrcGetResult = Omit<LrcSearchResult, 'name'>;
declare class LrcLib {
readonly player: Player;
/**
* The API URL
*/
api: string;
/**
* The request timeout. Default is 15 seconds.
*/
timeout: number;
/**
* The request bucket
*/
bucket: SequentialBucket;
/**
* Creates a new LrcLib instance
* @param {Player} player The player instance
*/
constructor(player: Player);
/**
* Sets the request timeout
* @param {number} timeout The timeout in milliseconds
*/
setRequestTimeout(timeout: number): void;
/**
* Sets the retry limit. Default is 5.
* @param {number} limit The retry limit
*/
setRetryLimit(limit: number): void;
/**
* Gets lyrics
* @param params The get params
*/
get(params: LrcGetParams): Promise<LrcSearchResult>;
/**
* Gets lyrics by ID
* @param id The lyrics ID
*/
getById(id: `${number}` | number): Promise<LrcSearchResult>;
/**
* Gets cached lyrics
* @param params The get params
*/
getCached(params: LrcGetParams): Promise<LrcSearchResult>;
/**
* Searches for lyrics
* @param params The search params
*/
search(params: LrcSearchParams): Promise<LrcSearchResult[]>;
/**
* Requests the API
* @param path The path
* @param options The request options
*/
request<T>(path: string, options?: RequestInit): Promise<T>;
}
type LyricsData = Map<number, string>;
type Unsubscribe = () => void;
type LyricsCallback = (lyrics: string, timestamp: number) => unknown;
type LyricsAt = {
timestamp: number;
line: string;
};
declare class SyncedLyricsProvider {
#private;
readonly queue: GuildQueue;
readonly raw?: LrcSearchResult | LrcGetResult | undefined;
interval: number;
readonly lyrics: LyricsData;
constructor(queue: GuildQueue, raw?: LrcSearchResult | LrcGetResult | undefined);
isSubscribed(): boolean;
load(lyrics: string): void;
/**
* Returns the lyrics at a specific time or at the closest time (±2 seconds)
* @param time The time in milliseconds
*/
at(time: number): LyricsAt | null;
/**
* Callback for the lyrics change.
* @param callback The callback function
*/
onChange(callback: LyricsCallback): void;
/**
* Callback to detect when the provider is unsubscribed.
* @param callback The callback function
*/
onUnsubscribe(callback: Unsubscribe): void;
/**
* Unsubscribes from the queue.
*/
unsubscribe(): void;
/**
* Subscribes to the queue to monitor the current time.
* @returns The unsubscribe function
*/
subscribe(): Unsubscribe;
/**
* Pauses the lyrics provider.
*/
pause(): boolean;
/**
* Resumes the lyrics provider.
*/
resume(): boolean;
}
interface GuildNodeInit<Meta = unknown> {
guild: Guild;
queueStrategy: QueueStrategy;
equalizer: EqualizerBand[] | boolean;
volume: number | boolean;
biquad: BiquadFilters | boolean | undefined;
resampler: number | boolean;
filterer: PCMFilters[] | boolean;
ffmpegFilters: FiltersName[];
disableHistory: boolean;
onBeforeCreateStream?: OnBeforeCreateStreamHandler;
onAfterCreateStream?: OnAfterCreateStreamHandler;
repeatMode?: QueueRepeatMode;
leaveOnEmpty: boolean;
leaveOnEmptyCooldown: number;
leaveOnEnd: boolean;
leaveOnEndCooldown: number;
leaveOnStop: boolean;
leaveOnStopCooldown: number;
connectionTimeout: number;
selfDeaf?: boolean;
metadata?: Meta | null;
bufferingTimeout: number;
noEmitInsert: boolean;
maxSize?: number;
maxHistorySize?: number;
preferBridgedMetadata: boolean;
pauseOnEmpty?: boolean;
disableVolume: boolean;
disableEqualizer: boolean;
disableFilterer: boolean;
disableBiquad: boolean;
disableResampler: boolean;
disableFallbackStream: boolean;
enableStreamInterceptor: boolean;
}
interface VoiceConnectConfig {
deaf?: boolean;
timeout?: number;
group?: string;
audioPlayer?: AudioPlayer;
}
interface PostProcessedResult {
stream: Readable;
type: StreamType;
}
type OnBeforeCreateStreamHandler = (track: Track, queryType: SearchQueryType, queue: GuildQueue) => Promise<Readable | null>;
type OnAfterCreateStreamHandler<T = unknown> = (stream: Readable, queue: GuildQueue, track: Track<T>) => Promise<PostProcessedResult | null>;
type PlayerTriggeredReason = 'filters' | 'normal';
declare const GuildQueueEvent: {
/**
* Emitted when audio track is added to the queue
*/
readonly AudioTrackAdd: "audioTrackAdd";
/**
* Emitted when audio tracks were added to the queue
*/
readonly AudioTracksAdd: "audioTracksAdd";
/**
* Emitted when audio track is removed from the queue
*/
readonly AudioTrackRemove: "audioTrackRemove";
/**
* Emitted when audio tracks are removed from the queue
*/
readonly AudioTracksRemove: "audioTracksRemove";
/**
* Emitted when a connection is created
*/
readonly Connection: "connection";
/**
* Emitted when a voice connection is destroyed
*/
readonly ConnectionDestroyed: "connectionDestroyed";
/**
* Emitted when the bot is disconnected from the channel
*/
readonly Disconnect: "disconnect";
/**
* Emitted when the queue sends a debug info
*/
readonly Debug: "debug";
/**
* Emitted when the queue encounters error
*/
readonly Error: "error";
/**
* Emitted when the voice channel is empty
*/
readonly EmptyChannel: "emptyChannel";
/**
* Emitted when the queue is empty
*/
readonly EmptyQueue: "emptyQueue";
/**
* Emitted when the audio player starts streaming audio track
*/
readonly PlayerStart: "playerStart";
/**
* Emitted when the audio player errors while streaming audio track
*/
readonly PlayerError: "playerError";
/**
* Emitted when the audio player finishes streaming audio track
*/
readonly PlayerFinish: "playerFinish";
/**
* Emitted when the audio player skips current track
*/
readonly PlayerSkip: "playerSkip";
/**
* Emitted when the audio player is triggered
*/
readonly PlayerTrigger: "playerTrigger";
/**
* Emitted when the voice state is updated. Consuming this event may disable default voice state update handler if `Player.isVoiceStateHandlerLocked()` returns `false`.
*/
readonly VoiceStateUpdate: "voiceStateUpdate";
/**
* Emitted when volume is updated
*/
readonly VolumeChange: "volumeChange";
/**
* Emitted when player is paused
*/
readonly PlayerPause: "playerPause";
/**
* Emitted when player is resumed
*/
readonly PlayerResume: "playerResume";
/**
* Biquad Filters Update
*/
readonly BiquadFiltersUpdate: "biquadFiltersUpdate";
/**
* Equalizer Update
*/
readonly EqualizerUpdate: "equalizerUpdate";
/**
* DSP update
*/
readonly DSPUpdate: "dspUpdate";
/**
* Audio Filters Update
*/
readonly AudioFiltersUpdate: "audioFiltersUpdate";
/**
* Audio player will play next track
*/
readonly WillPlayTrack: "willPlayTrack";
/**
* Emitted when a voice channel is repopulated
*/
readonly ChannelPopulate: "channelPopulate";
/**
* Emitted when a queue is successfully created
*/
readonly QueueCreate: "queueCreate";
/**
* Emitted when a queue is deleted
*/
readonly QueueDelete: "queueDelete";
/**
* Emitted when a queue is trying to add similar track for autoplay
*/
readonly WillAutoPlay: "willAutoPlay";
};
type GuildQueueEvent = (typeof GuildQueueEvent)[keyof typeof GuildQueueEvent];
declare enum TrackSkipReason {
NoStream = "ERR_NO_STREAM",
Manual = "MANUAL",
SEEK_OVER_THRESHOLD = "SEEK_OVER_THRESHOLD",
Jump = "JUMPED_TO_ANOTHER_TRACK",
SkipTo = "SKIP_TO_ANOTHER_TRACK",
HistoryNext = "HISTORY_NEXT_TRACK"
}
interface GuildQueueEvents<Meta = any> {
/**
* Emitted when audio track is added to the queue
* @param queue The queue where this event occurred
* @param track The track
*/
[GuildQueueEvent.AudioTrackAdd]: (queue: GuildQueue<Meta>, track: Track) => unknown;
/**
* Emitted when audio tracks were added to the queue
* @param queue The queue where this event occurred
* @param tracks The tracks array
*/
[GuildQueueEvent.AudioTracksAdd]: (queue: GuildQueue<Meta>, track: Track[]) => unknown;
/**
* Emitted when audio track is removed from the queue
* @param queue The queue where this event occurred
* @param track The track
*/
[GuildQueueEvent.AudioTrackRemove]: (queue: GuildQueue<Meta>, track: Track) => unknown;
/**
* Emitted when audio tracks are removed from the queue
* @param queue The queue where this event occurred
* @param track The track
*/
[GuildQueueEvent.AudioTracksRemove]: (queue: GuildQueue<Meta>, track: Track[]) => unknown;
/**
* Emitted when a connection is created
* @param queue The queue where this event occurred
*/
[GuildQueueEvent.Connection]: (queue: GuildQueue<Meta>) => unknown;
/**
* Emitted when a connection is destroyed
* @param queue The queue where this event occurred
*/
[GuildQueueEvent.ConnectionDestroyed]: (queue: GuildQueue<Meta>) => unknown;
/**
* Emitted when the bot is disconnected from the channel
* @param queue The queue where this event occurred
*/
[GuildQueueEvent.Disconnect]: (queue: GuildQueue<Meta>) => unknown;
/**
* Emitted when the queue sends a debug info
* @param queue The queue where this event occurred
* @param message The debug message
*/
[GuildQueueEvent.Debug]: (queue: GuildQueue<Meta>, message: string) => unknown;
/**
* Emitted when the queue encounters error
* @param queue The queue where this event occurred
* @param error The error
*/
[GuildQueueEvent.Error]: (queue: GuildQueue<Meta>, error: Error) => unknown;
/**
* Emitted when the voice channel is empty
* @param queue The queue where this event occurred
*/
[GuildQueueEvent.EmptyChannel]: (queue: GuildQueue<Meta>) => unknown;
/**
* Emitted when the queue is empty
* @param queue The queue where this event occurred
*/
[GuildQueueEvent.EmptyQueue]: (queue: GuildQueue<Meta>) => unknown;
/**
* Emitted when the audio player starts streaming audio track
* @param queue The queue where this event occurred
* @param track The track that is being streamed
*/
[GuildQueueEvent.PlayerStart]: (queue: GuildQueue<Meta>, track: Track) => unknown;
/**
* Emitted when the audio player errors while streaming audio track
* @param queue The queue where this event occurred
* @param error The error
* @param track The track that is being streamed
*/
[GuildQueueEvent.PlayerError]: (queue: GuildQueue<Meta>, error: Error, track: Track) => unknown;
/**
* Emitted when the audio player finishes streaming audio track
* @param queue The queue where this event occurred
* @param track The track that was being streamed
*/
[GuildQueueEvent.PlayerFinish]: (queue: GuildQueue<Meta>, track: Track) => unknown;
/**
* Emitted when the audio player skips current track
* @param queue The queue where this event occurred
* @param track The track that was skipped
* @param reason The reason for skipping
* @param description The description for skipping
*/
[GuildQueueEvent.PlayerSkip]: (queue: GuildQueue<Meta>, track: Track, reason: TrackSkipReason, description: string) => unknown;
/**
* Emitted when the audio player is triggered
* @param queue The queue where this event occurred
* @param track The track which was played in this event
*/
[GuildQueueEvent.PlayerTrigger]: (queue: GuildQueue<Meta>, track: Track, reason: PlayerTriggeredReason) => unknown;
/**
* Emitted when the voice state is updated. Consuming this event may disable default voice state update handler if `Player.isVoiceStateHandlerLocked()` returns `false`.
* @param queue The queue where this event occurred
* @param oldState The old voice state
* @param newState The new voice state
*/
[GuildQueueEvent.VoiceStateUpdate]: (queue: GuildQueue<Meta>, oldState: VoiceState, newState: VoiceState) => unknown;
/**
* Emitted when audio player is paused
* @param queue The queue where this event occurred
*/
[GuildQueueEvent.PlayerPause]: (queue: GuildQueue<Meta>) => unknown;
/**