format with tabs
This commit is contained in:
parent
241a22b5d1
commit
83c6179e1e
16 changed files with 2496 additions and 2495 deletions
|
@ -3,5 +3,6 @@
|
|||
"trailingComma": "none",
|
||||
"singleQuote": false,
|
||||
"tabWidth": 4,
|
||||
"useTabs": true,
|
||||
"semi": true
|
||||
}
|
1114
src/Player.ts
1114
src/Player.ts
File diff suppressed because it is too large
Load diff
|
@ -1,73 +1,73 @@
|
|||
import { ExtractorModelData } from "../types/types";
|
||||
|
||||
class ExtractorModel {
|
||||
name: string;
|
||||
private _raw: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
name: string;
|
||||
private _raw: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
||||
/**
|
||||
* Model for raw Discord Player extractors
|
||||
* @param {string} extractorName Name of the extractor
|
||||
* @param {object} data Extractor object
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
constructor(extractorName: string, data: any) {
|
||||
/**
|
||||
* The extractor name
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = extractorName;
|
||||
/**
|
||||
* Model for raw Discord Player extractors
|
||||
* @param {string} extractorName Name of the extractor
|
||||
* @param {object} data Extractor object
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
constructor(extractorName: string, data: any) {
|
||||
/**
|
||||
* The extractor name
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = extractorName;
|
||||
|
||||
/**
|
||||
* The raw model
|
||||
* @name ExtractorModel#_raw
|
||||
* @type {any}
|
||||
* @private
|
||||
*/
|
||||
Object.defineProperty(this, "_raw", { value: data, configurable: false, writable: false, enumerable: false });
|
||||
}
|
||||
/**
|
||||
* The raw model
|
||||
* @name ExtractorModel#_raw
|
||||
* @type {any}
|
||||
* @private
|
||||
*/
|
||||
Object.defineProperty(this, "_raw", { value: data, configurable: false, writable: false, enumerable: false });
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to handle requests from `Player.play()`
|
||||
* @param {string} query Query to handle
|
||||
* @returns {Promise<ExtractorModelData>}
|
||||
*/
|
||||
async handle(query: string): Promise<ExtractorModelData> {
|
||||
const data = await this._raw.getInfo(query);
|
||||
if (!data) return null;
|
||||
/**
|
||||
* Method to handle requests from `Player.play()`
|
||||
* @param {string} query Query to handle
|
||||
* @returns {Promise<ExtractorModelData>}
|
||||
*/
|
||||
async handle(query: string): Promise<ExtractorModelData> {
|
||||
const data = await this._raw.getInfo(query);
|
||||
if (!data) return null;
|
||||
|
||||
return {
|
||||
playlist: data.playlist ?? null,
|
||||
data:
|
||||
(data.info as Omit<ExtractorModelData, "playlist">["data"])?.map((m) => ({
|
||||
title: m.title as string,
|
||||
duration: m.duration as number,
|
||||
thumbnail: m.thumbnail as string,
|
||||
engine: m.engine,
|
||||
views: m.views as number,
|
||||
author: m.author as string,
|
||||
description: m.description as string,
|
||||
url: m.url as string,
|
||||
source: m.source || "arbitrary"
|
||||
})) ?? []
|
||||
};
|
||||
}
|
||||
return {
|
||||
playlist: data.playlist ?? null,
|
||||
data:
|
||||
(data.info as Omit<ExtractorModelData, "playlist">["data"])?.map((m) => ({
|
||||
title: m.title as string,
|
||||
duration: m.duration as number,
|
||||
thumbnail: m.thumbnail as string,
|
||||
engine: m.engine,
|
||||
views: m.views as number,
|
||||
author: m.author as string,
|
||||
description: m.description as string,
|
||||
url: m.url as string,
|
||||
source: m.source || "arbitrary"
|
||||
})) ?? []
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used by Discord Player to validate query with this extractor
|
||||
* @param {string} query The query to validate
|
||||
* @returns {boolean}
|
||||
*/
|
||||
validate(query: string): boolean {
|
||||
return Boolean(this._raw.validate(query));
|
||||
}
|
||||
/**
|
||||
* Method used by Discord Player to validate query with this extractor
|
||||
* @param {string} query The query to validate
|
||||
* @returns {boolean}
|
||||
*/
|
||||
validate(query: string): boolean {
|
||||
return Boolean(this._raw.validate(query));
|
||||
}
|
||||
|
||||
/**
|
||||
* The extractor version
|
||||
* @type {string}
|
||||
*/
|
||||
get version(): string {
|
||||
return this._raw.version ?? "0.0.0";
|
||||
}
|
||||
/**
|
||||
* The extractor version
|
||||
* @type {string}
|
||||
*/
|
||||
get version(): string {
|
||||
return this._raw.version ?? "0.0.0";
|
||||
}
|
||||
}
|
||||
|
||||
export { ExtractorModel };
|
||||
|
|
|
@ -1,53 +1,53 @@
|
|||
export enum ErrorStatusCode {
|
||||
STREAM_ERROR = "StreamError",
|
||||
AUDIO_PLAYER_ERROR = "AudioPlayerError",
|
||||
PLAYER_ERROR = "PlayerError",
|
||||
NO_AUDIO_RESOURCE = "NoAudioResource",
|
||||
UNKNOWN_GUILD = "UnknownGuild",
|
||||
INVALID_ARG_TYPE = "InvalidArgType",
|
||||
UNKNOWN_EXTRACTOR = "UnknownExtractor",
|
||||
INVALID_EXTRACTOR = "InvalidExtractor",
|
||||
INVALID_CHANNEL_TYPE = "InvalidChannelType",
|
||||
INVALID_TRACK = "InvalidTrack",
|
||||
UNKNOWN_REPEAT_MODE = "UnknownRepeatMode",
|
||||
TRACK_NOT_FOUND = "TrackNotFound",
|
||||
NO_CONNECTION = "NoConnection",
|
||||
DESTROYED_QUEUE = "DestroyedQueue"
|
||||
STREAM_ERROR = "StreamError",
|
||||
AUDIO_PLAYER_ERROR = "AudioPlayerError",
|
||||
PLAYER_ERROR = "PlayerError",
|
||||
NO_AUDIO_RESOURCE = "NoAudioResource",
|
||||
UNKNOWN_GUILD = "UnknownGuild",
|
||||
INVALID_ARG_TYPE = "InvalidArgType",
|
||||
UNKNOWN_EXTRACTOR = "UnknownExtractor",
|
||||
INVALID_EXTRACTOR = "InvalidExtractor",
|
||||
INVALID_CHANNEL_TYPE = "InvalidChannelType",
|
||||
INVALID_TRACK = "InvalidTrack",
|
||||
UNKNOWN_REPEAT_MODE = "UnknownRepeatMode",
|
||||
TRACK_NOT_FOUND = "TrackNotFound",
|
||||
NO_CONNECTION = "NoConnection",
|
||||
DESTROYED_QUEUE = "DestroyedQueue"
|
||||
}
|
||||
|
||||
export class PlayerError extends Error {
|
||||
message: string;
|
||||
statusCode: ErrorStatusCode;
|
||||
createdAt = new Date();
|
||||
message: string;
|
||||
statusCode: ErrorStatusCode;
|
||||
createdAt = new Date();
|
||||
|
||||
constructor(message: string, code: ErrorStatusCode = ErrorStatusCode.PLAYER_ERROR) {
|
||||
super();
|
||||
constructor(message: string, code: ErrorStatusCode = ErrorStatusCode.PLAYER_ERROR) {
|
||||
super();
|
||||
|
||||
this.message = `[${code}] ${message}`;
|
||||
this.statusCode = code;
|
||||
this.name = code;
|
||||
this.message = `[${code}] ${message}`;
|
||||
this.statusCode = code;
|
||||
this.name = code;
|
||||
|
||||
Error.captureStackTrace(this);
|
||||
}
|
||||
Error.captureStackTrace(this);
|
||||
}
|
||||
|
||||
get createdTimestamp() {
|
||||
return this.createdAt.getTime();
|
||||
}
|
||||
get createdTimestamp() {
|
||||
return this.createdAt.getTime();
|
||||
}
|
||||
|
||||
valueOf() {
|
||||
return this.statusCode;
|
||||
}
|
||||
valueOf() {
|
||||
return this.statusCode;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
stack: this.stack,
|
||||
code: this.statusCode,
|
||||
message: this.message,
|
||||
created: this.createdTimestamp
|
||||
};
|
||||
}
|
||||
toJSON() {
|
||||
return {
|
||||
stack: this.stack,
|
||||
code: this.statusCode,
|
||||
message: this.message,
|
||||
created: this.createdTimestamp
|
||||
};
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.stack;
|
||||
}
|
||||
toString() {
|
||||
return this.stack;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,136 +3,136 @@ import { Track } from "./Track";
|
|||
import { PlaylistInitData, PlaylistJSON, TrackJSON, TrackSource } from "../types/types";
|
||||
|
||||
class Playlist {
|
||||
public readonly player: Player;
|
||||
public tracks: Track[];
|
||||
public title: string;
|
||||
public description: string;
|
||||
public thumbnail: string;
|
||||
public type: "album" | "playlist";
|
||||
public source: TrackSource;
|
||||
public author: {
|
||||
name: string;
|
||||
url: string;
|
||||
};
|
||||
public id: string;
|
||||
public url: string;
|
||||
public readonly rawPlaylist?: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
public readonly player: Player;
|
||||
public tracks: Track[];
|
||||
public title: string;
|
||||
public description: string;
|
||||
public thumbnail: string;
|
||||
public type: "album" | "playlist";
|
||||
public source: TrackSource;
|
||||
public author: {
|
||||
name: string;
|
||||
url: string;
|
||||
};
|
||||
public id: string;
|
||||
public url: string;
|
||||
public readonly rawPlaylist?: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
||||
/**
|
||||
* Playlist constructor
|
||||
* @param {Player} player The player
|
||||
* @param {PlaylistInitData} data The data
|
||||
*/
|
||||
constructor(player: Player, data: PlaylistInitData) {
|
||||
/**
|
||||
* The player
|
||||
* @name Playlist#player
|
||||
* @type {Player}
|
||||
* @readonly
|
||||
*/
|
||||
this.player = player;
|
||||
/**
|
||||
* Playlist constructor
|
||||
* @param {Player} player The player
|
||||
* @param {PlaylistInitData} data The data
|
||||
*/
|
||||
constructor(player: Player, data: PlaylistInitData) {
|
||||
/**
|
||||
* The player
|
||||
* @name Playlist#player
|
||||
* @type {Player}
|
||||
* @readonly
|
||||
*/
|
||||
this.player = player;
|
||||
|
||||
/**
|
||||
* The tracks in this playlist
|
||||
* @name Playlist#tracks
|
||||
* @type {Track[]}
|
||||
*/
|
||||
this.tracks = data.tracks ?? [];
|
||||
/**
|
||||
* The tracks in this playlist
|
||||
* @name Playlist#tracks
|
||||
* @type {Track[]}
|
||||
*/
|
||||
this.tracks = data.tracks ?? [];
|
||||
|
||||
/**
|
||||
* The author of this playlist
|
||||
* @name Playlist#author
|
||||
* @type {object}
|
||||
*/
|
||||
this.author = data.author;
|
||||
/**
|
||||
* The author of this playlist
|
||||
* @name Playlist#author
|
||||
* @type {object}
|
||||
*/
|
||||
this.author = data.author;
|
||||
|
||||
/**
|
||||
* The description
|
||||
* @name Playlist#description
|
||||
* @type {string}
|
||||
*/
|
||||
this.description = data.description;
|
||||
/**
|
||||
* The description
|
||||
* @name Playlist#description
|
||||
* @type {string}
|
||||
*/
|
||||
this.description = data.description;
|
||||
|
||||
/**
|
||||
* The thumbnail of this playlist
|
||||
* @name Playlist#thumbnail
|
||||
* @type {string}
|
||||
*/
|
||||
this.thumbnail = data.thumbnail;
|
||||
/**
|
||||
* The thumbnail of this playlist
|
||||
* @name Playlist#thumbnail
|
||||
* @type {string}
|
||||
*/
|
||||
this.thumbnail = data.thumbnail;
|
||||
|
||||
/**
|
||||
* The playlist type:
|
||||
* - `album`
|
||||
* - `playlist`
|
||||
* @name Playlist#type
|
||||
* @type {string}
|
||||
*/
|
||||
this.type = data.type;
|
||||
/**
|
||||
* The playlist type:
|
||||
* - `album`
|
||||
* - `playlist`
|
||||
* @name Playlist#type
|
||||
* @type {string}
|
||||
*/
|
||||
this.type = data.type;
|
||||
|
||||
/**
|
||||
* The source of this playlist:
|
||||
* - `youtube`
|
||||
* - `soundcloud`
|
||||
* - `spotify`
|
||||
* - `arbitrary`
|
||||
* @name Playlist#source
|
||||
* @type {string}
|
||||
*/
|
||||
this.source = data.source;
|
||||
/**
|
||||
* The source of this playlist:
|
||||
* - `youtube`
|
||||
* - `soundcloud`
|
||||
* - `spotify`
|
||||
* - `arbitrary`
|
||||
* @name Playlist#source
|
||||
* @type {string}
|
||||
*/
|
||||
this.source = data.source;
|
||||
|
||||
/**
|
||||
* The playlist id
|
||||
* @name Playlist#id
|
||||
* @type {string}
|
||||
*/
|
||||
this.id = data.id;
|
||||
/**
|
||||
* The playlist id
|
||||
* @name Playlist#id
|
||||
* @type {string}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
/**
|
||||
* The playlist url
|
||||
* @name Playlist#url
|
||||
* @type {string}
|
||||
*/
|
||||
this.url = data.url;
|
||||
/**
|
||||
* The playlist url
|
||||
* @name Playlist#url
|
||||
* @type {string}
|
||||
*/
|
||||
this.url = data.url;
|
||||
|
||||
/**
|
||||
* The playlist title
|
||||
* @type {string}
|
||||
*/
|
||||
this.title = data.title;
|
||||
/**
|
||||
* The playlist title
|
||||
* @type {string}
|
||||
*/
|
||||
this.title = data.title;
|
||||
|
||||
/**
|
||||
* @name Playlist#rawPlaylist
|
||||
* @type {any}
|
||||
* @readonly
|
||||
*/
|
||||
}
|
||||
/**
|
||||
* @name Playlist#rawPlaylist
|
||||
* @type {any}
|
||||
* @readonly
|
||||
*/
|
||||
}
|
||||
|
||||
*[Symbol.iterator]() {
|
||||
yield* this.tracks;
|
||||
}
|
||||
*[Symbol.iterator]() {
|
||||
yield* this.tracks;
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON representation of this playlist
|
||||
* @param {boolean} [withTracks=true] If it should build json with tracks
|
||||
* @returns {PlaylistJSON}
|
||||
*/
|
||||
toJSON(withTracks = true) {
|
||||
const payload = {
|
||||
id: this.id,
|
||||
url: this.url,
|
||||
title: this.title,
|
||||
description: this.description,
|
||||
thumbnail: this.thumbnail,
|
||||
type: this.type,
|
||||
source: this.source,
|
||||
author: this.author,
|
||||
tracks: [] as TrackJSON[]
|
||||
};
|
||||
/**
|
||||
* JSON representation of this playlist
|
||||
* @param {boolean} [withTracks=true] If it should build json with tracks
|
||||
* @returns {PlaylistJSON}
|
||||
*/
|
||||
toJSON(withTracks = true) {
|
||||
const payload = {
|
||||
id: this.id,
|
||||
url: this.url,
|
||||
title: this.title,
|
||||
description: this.description,
|
||||
thumbnail: this.thumbnail,
|
||||
type: this.type,
|
||||
source: this.source,
|
||||
author: this.author,
|
||||
tracks: [] as TrackJSON[]
|
||||
};
|
||||
|
||||
if (withTracks) payload.tracks = this.tracks.map((m) => m.toJSON(true));
|
||||
if (withTracks) payload.tracks = this.tracks.map((m) => m.toJSON(true));
|
||||
|
||||
return payload as PlaylistJSON;
|
||||
}
|
||||
return payload as PlaylistJSON;
|
||||
}
|
||||
}
|
||||
|
||||
export { Playlist };
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,185 +5,185 @@ import { Playlist } from "./Playlist";
|
|||
import { Queue } from "./Queue";
|
||||
|
||||
class Track {
|
||||
public player!: Player;
|
||||
public title!: string;
|
||||
public description!: string;
|
||||
public author!: string;
|
||||
public url!: string;
|
||||
public thumbnail!: string;
|
||||
public duration!: string;
|
||||
public views!: number;
|
||||
public requestedBy!: User;
|
||||
public playlist?: Playlist;
|
||||
public readonly raw: RawTrackData = {} as RawTrackData;
|
||||
public readonly id = SnowflakeUtil.generate().toString();
|
||||
public player!: Player;
|
||||
public title!: string;
|
||||
public description!: string;
|
||||
public author!: string;
|
||||
public url!: string;
|
||||
public thumbnail!: string;
|
||||
public duration!: string;
|
||||
public views!: number;
|
||||
public requestedBy!: User;
|
||||
public playlist?: Playlist;
|
||||
public readonly raw: RawTrackData = {} as RawTrackData;
|
||||
public readonly id = SnowflakeUtil.generate().toString();
|
||||
|
||||
/**
|
||||
* Track constructor
|
||||
* @param {Player} player The player that instantiated this Track
|
||||
* @param {RawTrackData} data Track data
|
||||
*/
|
||||
constructor(player: Player, data: RawTrackData) {
|
||||
/**
|
||||
* The player that instantiated this Track
|
||||
* @name Track#player
|
||||
* @type {Player}
|
||||
* @readonly
|
||||
*/
|
||||
Object.defineProperty(this, "player", { value: player, enumerable: false });
|
||||
/**
|
||||
* Track constructor
|
||||
* @param {Player} player The player that instantiated this Track
|
||||
* @param {RawTrackData} data Track data
|
||||
*/
|
||||
constructor(player: Player, data: RawTrackData) {
|
||||
/**
|
||||
* The player that instantiated this Track
|
||||
* @name Track#player
|
||||
* @type {Player}
|
||||
* @readonly
|
||||
*/
|
||||
Object.defineProperty(this, "player", { value: player, enumerable: false });
|
||||
|
||||
/**
|
||||
* Title of this track
|
||||
* @name Track#title
|
||||
* @type {string}
|
||||
*/
|
||||
/**
|
||||
* Title of this track
|
||||
* @name Track#title
|
||||
* @type {string}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Description of this track
|
||||
* @name Track#description
|
||||
* @type {string}
|
||||
*/
|
||||
/**
|
||||
* Description of this track
|
||||
* @name Track#description
|
||||
* @type {string}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Author of this track
|
||||
* @name Track#author
|
||||
* @type {string}
|
||||
*/
|
||||
/**
|
||||
* Author of this track
|
||||
* @name Track#author
|
||||
* @type {string}
|
||||
*/
|
||||
|
||||
/**
|
||||
* URL of this track
|
||||
* @name Track#url
|
||||
* @type {string}
|
||||
*/
|
||||
/**
|
||||
* URL of this track
|
||||
* @name Track#url
|
||||
* @type {string}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Thumbnail of this track
|
||||
* @name Track#thumbnail
|
||||
* @type {string}
|
||||
*/
|
||||
/**
|
||||
* Thumbnail of this track
|
||||
* @name Track#thumbnail
|
||||
* @type {string}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Duration of this track
|
||||
* @name Track#duration
|
||||
* @type {string}
|
||||
*/
|
||||
/**
|
||||
* Duration of this track
|
||||
* @name Track#duration
|
||||
* @type {string}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Views count of this track
|
||||
* @name Track#views
|
||||
* @type {number}
|
||||
*/
|
||||
/**
|
||||
* Views count of this track
|
||||
* @name Track#views
|
||||
* @type {number}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Person who requested this track
|
||||
* @name Track#requestedBy
|
||||
* @type {User}
|
||||
*/
|
||||
/**
|
||||
* Person who requested this track
|
||||
* @name Track#requestedBy
|
||||
* @type {User}
|
||||
*/
|
||||
|
||||
/**
|
||||
* If this track belongs to playlist
|
||||
* @name Track#fromPlaylist
|
||||
* @type {boolean}
|
||||
*/
|
||||
/**
|
||||
* If this track belongs to playlist
|
||||
* @name Track#fromPlaylist
|
||||
* @type {boolean}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Raw track data
|
||||
* @name Track#raw
|
||||
* @type {RawTrackData}
|
||||
*/
|
||||
/**
|
||||
* Raw track data
|
||||
* @name Track#raw
|
||||
* @type {RawTrackData}
|
||||
*/
|
||||
|
||||
/**
|
||||
* The track id
|
||||
* @name Track#id
|
||||
* @type {Snowflake}
|
||||
* @readonly
|
||||
*/
|
||||
/**
|
||||
* The track id
|
||||
* @name Track#id
|
||||
* @type {Snowflake}
|
||||
* @readonly
|
||||
*/
|
||||
|
||||
/**
|
||||
* The playlist which track belongs
|
||||
* @name Track#playlist
|
||||
* @type {Playlist}
|
||||
*/
|
||||
/**
|
||||
* The playlist which track belongs
|
||||
* @name Track#playlist
|
||||
* @type {Playlist}
|
||||
*/
|
||||
|
||||
void this._patch(data);
|
||||
}
|
||||
void this._patch(data);
|
||||
}
|
||||
|
||||
private _patch(data: RawTrackData) {
|
||||
this.title = escapeMarkdown(data.title ?? "");
|
||||
this.description = data.description ?? "";
|
||||
this.author = data.author ?? "";
|
||||
this.url = data.url ?? "";
|
||||
this.thumbnail = data.thumbnail ?? "";
|
||||
this.duration = data.duration ?? "";
|
||||
this.views = data.views ?? 0;
|
||||
this.requestedBy = data.requestedBy;
|
||||
this.playlist = data.playlist;
|
||||
private _patch(data: RawTrackData) {
|
||||
this.title = escapeMarkdown(data.title ?? "");
|
||||
this.description = data.description ?? "";
|
||||
this.author = data.author ?? "";
|
||||
this.url = data.url ?? "";
|
||||
this.thumbnail = data.thumbnail ?? "";
|
||||
this.duration = data.duration ?? "";
|
||||
this.views = data.views ?? 0;
|
||||
this.requestedBy = data.requestedBy;
|
||||
this.playlist = data.playlist;
|
||||
|
||||
// raw
|
||||
Object.defineProperty(this, "raw", { value: Object.assign({}, { source: data.raw?.source ?? data.source }, data.raw ?? data), enumerable: false });
|
||||
}
|
||||
// raw
|
||||
Object.defineProperty(this, "raw", { value: Object.assign({}, { source: data.raw?.source ?? data.source }, data.raw ?? data), enumerable: false });
|
||||
}
|
||||
|
||||
/**
|
||||
* The queue in which this track is located
|
||||
* @type {Queue}
|
||||
*/
|
||||
get queue(): Queue {
|
||||
return this.player.queues.find((q) => q.tracks.some((ab) => ab.id === this.id));
|
||||
}
|
||||
/**
|
||||
* The queue in which this track is located
|
||||
* @type {Queue}
|
||||
*/
|
||||
get queue(): Queue {
|
||||
return this.player.queues.find((q) => q.tracks.some((ab) => ab.id === this.id));
|
||||
}
|
||||
|
||||
/**
|
||||
* The track duration in millisecond
|
||||
* @type {number}
|
||||
*/
|
||||
get durationMS(): number {
|
||||
const times = (n: number, t: number) => {
|
||||
let tn = 1;
|
||||
for (let i = 0; i < t; i++) tn *= n;
|
||||
return t <= 0 ? 1000 : tn * 1000;
|
||||
};
|
||||
/**
|
||||
* The track duration in millisecond
|
||||
* @type {number}
|
||||
*/
|
||||
get durationMS(): number {
|
||||
const times = (n: number, t: number) => {
|
||||
let tn = 1;
|
||||
for (let i = 0; i < t; i++) tn *= n;
|
||||
return t <= 0 ? 1000 : tn * 1000;
|
||||
};
|
||||
|
||||
return this.duration
|
||||
.split(":")
|
||||
.reverse()
|
||||
.map((m, i) => parseInt(m) * times(60, i))
|
||||
.reduce((a, c) => a + c, 0);
|
||||
}
|
||||
return this.duration
|
||||
.split(":")
|
||||
.reverse()
|
||||
.map((m, i) => parseInt(m) * times(60, i))
|
||||
.reduce((a, c) => a + c, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns source of this track
|
||||
* @type {TrackSource}
|
||||
*/
|
||||
get source() {
|
||||
return this.raw.source ?? "arbitrary";
|
||||
}
|
||||
/**
|
||||
* Returns source of this track
|
||||
* @type {TrackSource}
|
||||
*/
|
||||
get source() {
|
||||
return this.raw.source ?? "arbitrary";
|
||||
}
|
||||
|
||||
/**
|
||||
* String representation of this track
|
||||
* @returns {string}
|
||||
*/
|
||||
toString(): string {
|
||||
return `${this.title} by ${this.author}`;
|
||||
}
|
||||
/**
|
||||
* String representation of this track
|
||||
* @returns {string}
|
||||
*/
|
||||
toString(): string {
|
||||
return `${this.title} by ${this.author}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw JSON representation of this track
|
||||
* @returns {TrackJSON}
|
||||
*/
|
||||
toJSON(hidePlaylist?: boolean) {
|
||||
return {
|
||||
id: this.id,
|
||||
title: this.title,
|
||||
description: this.description,
|
||||
author: this.author,
|
||||
url: this.url,
|
||||
thumbnail: this.thumbnail,
|
||||
duration: this.duration,
|
||||
durationMS: this.durationMS,
|
||||
views: this.views,
|
||||
requestedBy: this.requestedBy?.id,
|
||||
playlist: hidePlaylist ? null : this.playlist?.toJSON() ?? null
|
||||
} as TrackJSON;
|
||||
}
|
||||
/**
|
||||
* Raw JSON representation of this track
|
||||
* @returns {TrackJSON}
|
||||
*/
|
||||
toJSON(hidePlaylist?: boolean) {
|
||||
return {
|
||||
id: this.id,
|
||||
title: this.title,
|
||||
description: this.description,
|
||||
author: this.author,
|
||||
url: this.url,
|
||||
thumbnail: this.thumbnail,
|
||||
duration: this.duration,
|
||||
durationMS: this.durationMS,
|
||||
views: this.views,
|
||||
requestedBy: this.requestedBy?.id,
|
||||
playlist: hidePlaylist ? null : this.playlist?.toJSON() ?? null
|
||||
} as TrackJSON;
|
||||
}
|
||||
}
|
||||
|
||||
export default Track;
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import {
|
||||
AudioPlayer,
|
||||
AudioPlayerError,
|
||||
AudioPlayerStatus,
|
||||
AudioResource,
|
||||
createAudioPlayer,
|
||||
createAudioResource,
|
||||
entersState,
|
||||
StreamType,
|
||||
VoiceConnection,
|
||||
VoiceConnectionStatus,
|
||||
VoiceConnectionDisconnectReason
|
||||
AudioPlayer,
|
||||
AudioPlayerError,
|
||||
AudioPlayerStatus,
|
||||
AudioResource,
|
||||
createAudioPlayer,
|
||||
createAudioResource,
|
||||
entersState,
|
||||
StreamType,
|
||||
VoiceConnection,
|
||||
VoiceConnectionStatus,
|
||||
VoiceConnectionDisconnectReason
|
||||
} from "@discordjs/voice";
|
||||
import { StageChannel, VoiceChannel } from "discord.js";
|
||||
import { Duplex, Readable } from "stream";
|
||||
|
@ -19,235 +19,235 @@ import { Util } from "../utils/Util";
|
|||
import { PlayerError, ErrorStatusCode } from "../Structures/PlayerError";
|
||||
|
||||
export interface VoiceEvents {
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
error: (error: AudioPlayerError) => any;
|
||||
debug: (message: string) => any;
|
||||
start: (resource: AudioResource<Track>) => any;
|
||||
finish: (resource: AudioResource<Track>) => any;
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
error: (error: AudioPlayerError) => any;
|
||||
debug: (message: string) => any;
|
||||
start: (resource: AudioResource<Track>) => any;
|
||||
finish: (resource: AudioResource<Track>) => any;
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
}
|
||||
|
||||
class StreamDispatcher extends EventEmitter<VoiceEvents> {
|
||||
public readonly voiceConnection: VoiceConnection;
|
||||
public readonly audioPlayer: AudioPlayer;
|
||||
public channel: VoiceChannel | StageChannel;
|
||||
public audioResource?: AudioResource<Track>;
|
||||
private readyLock = false;
|
||||
public paused: boolean;
|
||||
public readonly voiceConnection: VoiceConnection;
|
||||
public readonly audioPlayer: AudioPlayer;
|
||||
public channel: VoiceChannel | StageChannel;
|
||||
public audioResource?: AudioResource<Track>;
|
||||
private readyLock = false;
|
||||
public paused: boolean;
|
||||
|
||||
/**
|
||||
* Creates new connection object
|
||||
* @param {VoiceConnection} connection The connection
|
||||
* @param {VoiceChannel|StageChannel} channel The connected channel
|
||||
* @private
|
||||
*/
|
||||
constructor(connection: VoiceConnection, channel: VoiceChannel | StageChannel, public readonly connectionTimeout: number = 20000) {
|
||||
super();
|
||||
/**
|
||||
* Creates new connection object
|
||||
* @param {VoiceConnection} connection The connection
|
||||
* @param {VoiceChannel|StageChannel} channel The connected channel
|
||||
* @private
|
||||
*/
|
||||
constructor(connection: VoiceConnection, channel: VoiceChannel | StageChannel, public readonly connectionTimeout: number = 20000) {
|
||||
super();
|
||||
|
||||
/**
|
||||
* The voice connection
|
||||
* @type {VoiceConnection}
|
||||
*/
|
||||
this.voiceConnection = connection;
|
||||
/**
|
||||
* The voice connection
|
||||
* @type {VoiceConnection}
|
||||
*/
|
||||
this.voiceConnection = connection;
|
||||
|
||||
/**
|
||||
* The audio player
|
||||
* @type {AudioPlayer}
|
||||
*/
|
||||
this.audioPlayer = createAudioPlayer();
|
||||
/**
|
||||
* The audio player
|
||||
* @type {AudioPlayer}
|
||||
*/
|
||||
this.audioPlayer = createAudioPlayer();
|
||||
|
||||
/**
|
||||
* The voice channel
|
||||
* @type {VoiceChannel|StageChannel}
|
||||
*/
|
||||
this.channel = channel;
|
||||
/**
|
||||
* The voice channel
|
||||
* @type {VoiceChannel|StageChannel}
|
||||
*/
|
||||
this.channel = channel;
|
||||
|
||||
/**
|
||||
* The paused state
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.paused = false;
|
||||
/**
|
||||
* The paused state
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.paused = false;
|
||||
|
||||
this.voiceConnection.on("stateChange", async (_, newState) => {
|
||||
if (newState.status === VoiceConnectionStatus.Disconnected) {
|
||||
if (newState.reason === VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) {
|
||||
try {
|
||||
await entersState(this.voiceConnection, VoiceConnectionStatus.Connecting, this.connectionTimeout);
|
||||
} catch {
|
||||
try {
|
||||
this.voiceConnection.destroy();
|
||||
} catch (err) {
|
||||
this.emit("error", err as AudioPlayerError);
|
||||
}
|
||||
}
|
||||
} else if (this.voiceConnection.rejoinAttempts < 5) {
|
||||
await Util.wait((this.voiceConnection.rejoinAttempts + 1) * 5000);
|
||||
this.voiceConnection.rejoin();
|
||||
} else {
|
||||
try {
|
||||
this.voiceConnection.destroy();
|
||||
} catch (err) {
|
||||
this.emit("error", err as AudioPlayerError);
|
||||
}
|
||||
}
|
||||
} else if (newState.status === VoiceConnectionStatus.Destroyed) {
|
||||
this.end();
|
||||
} else if (!this.readyLock && (newState.status === VoiceConnectionStatus.Connecting || newState.status === VoiceConnectionStatus.Signalling)) {
|
||||
this.readyLock = true;
|
||||
try {
|
||||
await entersState(this.voiceConnection, VoiceConnectionStatus.Ready, this.connectionTimeout);
|
||||
} catch {
|
||||
if (this.voiceConnection.state.status !== VoiceConnectionStatus.Destroyed) {
|
||||
try {
|
||||
this.voiceConnection.destroy();
|
||||
} catch (err) {
|
||||
this.emit("error", err as AudioPlayerError);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
this.readyLock = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.voiceConnection.on("stateChange", async (_, newState) => {
|
||||
if (newState.status === VoiceConnectionStatus.Disconnected) {
|
||||
if (newState.reason === VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) {
|
||||
try {
|
||||
await entersState(this.voiceConnection, VoiceConnectionStatus.Connecting, this.connectionTimeout);
|
||||
} catch {
|
||||
try {
|
||||
this.voiceConnection.destroy();
|
||||
} catch (err) {
|
||||
this.emit("error", err as AudioPlayerError);
|
||||
}
|
||||
}
|
||||
} else if (this.voiceConnection.rejoinAttempts < 5) {
|
||||
await Util.wait((this.voiceConnection.rejoinAttempts + 1) * 5000);
|
||||
this.voiceConnection.rejoin();
|
||||
} else {
|
||||
try {
|
||||
this.voiceConnection.destroy();
|
||||
} catch (err) {
|
||||
this.emit("error", err as AudioPlayerError);
|
||||
}
|
||||
}
|
||||
} else if (newState.status === VoiceConnectionStatus.Destroyed) {
|
||||
this.end();
|
||||
} else if (!this.readyLock && (newState.status === VoiceConnectionStatus.Connecting || newState.status === VoiceConnectionStatus.Signalling)) {
|
||||
this.readyLock = true;
|
||||
try {
|
||||
await entersState(this.voiceConnection, VoiceConnectionStatus.Ready, this.connectionTimeout);
|
||||
} catch {
|
||||
if (this.voiceConnection.state.status !== VoiceConnectionStatus.Destroyed) {
|
||||
try {
|
||||
this.voiceConnection.destroy();
|
||||
} catch (err) {
|
||||
this.emit("error", err as AudioPlayerError);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
this.readyLock = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.audioPlayer.on("stateChange", (oldState, newState) => {
|
||||
if (newState.status === AudioPlayerStatus.Playing) {
|
||||
if (!this.paused) return void this.emit("start", this.audioResource);
|
||||
} else if (newState.status === AudioPlayerStatus.Idle && oldState.status !== AudioPlayerStatus.Idle) {
|
||||
if (!this.paused) {
|
||||
void this.emit("finish", this.audioResource);
|
||||
this.audioResource = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.audioPlayer.on("stateChange", (oldState, newState) => {
|
||||
if (newState.status === AudioPlayerStatus.Playing) {
|
||||
if (!this.paused) return void this.emit("start", this.audioResource);
|
||||
} else if (newState.status === AudioPlayerStatus.Idle && oldState.status !== AudioPlayerStatus.Idle) {
|
||||
if (!this.paused) {
|
||||
void this.emit("finish", this.audioResource);
|
||||
this.audioResource = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.audioPlayer.on("debug", (m) => void this.emit("debug", m));
|
||||
this.audioPlayer.on("error", (error) => void this.emit("error", error));
|
||||
this.voiceConnection.subscribe(this.audioPlayer);
|
||||
}
|
||||
this.audioPlayer.on("debug", (m) => void this.emit("debug", m));
|
||||
this.audioPlayer.on("error", (error) => void this.emit("error", error));
|
||||
this.voiceConnection.subscribe(this.audioPlayer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates stream
|
||||
* @param {Readable|Duplex|string} src The stream source
|
||||
* @param {object} [ops] Options
|
||||
* @returns {AudioResource}
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
createStream(src: Readable | Duplex | string, ops?: { type?: StreamType; data?: any; disableVolume?: boolean }) {
|
||||
this.audioResource = createAudioResource(src, {
|
||||
inputType: ops?.type ?? StreamType.Arbitrary,
|
||||
metadata: ops?.data,
|
||||
// eslint-disable-next-line no-extra-boolean-cast
|
||||
inlineVolume: !Boolean(ops?.disableVolume)
|
||||
});
|
||||
/**
|
||||
* Creates stream
|
||||
* @param {Readable|Duplex|string} src The stream source
|
||||
* @param {object} [ops] Options
|
||||
* @returns {AudioResource}
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
createStream(src: Readable | Duplex | string, ops?: { type?: StreamType; data?: any; disableVolume?: boolean }) {
|
||||
this.audioResource = createAudioResource(src, {
|
||||
inputType: ops?.type ?? StreamType.Arbitrary,
|
||||
metadata: ops?.data,
|
||||
// eslint-disable-next-line no-extra-boolean-cast
|
||||
inlineVolume: !Boolean(ops?.disableVolume)
|
||||
});
|
||||
|
||||
return this.audioResource;
|
||||
}
|
||||
return this.audioResource;
|
||||
}
|
||||
|
||||
/**
|
||||
* The player status
|
||||
* @type {AudioPlayerStatus}
|
||||
*/
|
||||
get status() {
|
||||
return this.audioPlayer.state.status;
|
||||
}
|
||||
/**
|
||||
* The player status
|
||||
* @type {AudioPlayerStatus}
|
||||
*/
|
||||
get status() {
|
||||
return this.audioPlayer.state.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects from voice
|
||||
* @returns {void}
|
||||
*/
|
||||
disconnect() {
|
||||
try {
|
||||
this.audioPlayer.stop(true);
|
||||
this.voiceConnection.destroy();
|
||||
} catch {} // eslint-disable-line no-empty
|
||||
}
|
||||
/**
|
||||
* Disconnects from voice
|
||||
* @returns {void}
|
||||
*/
|
||||
disconnect() {
|
||||
try {
|
||||
this.audioPlayer.stop(true);
|
||||
this.voiceConnection.destroy();
|
||||
} catch {} // eslint-disable-line no-empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the player
|
||||
* @returns {void}
|
||||
*/
|
||||
end() {
|
||||
this.audioPlayer.stop();
|
||||
}
|
||||
/**
|
||||
* Stops the player
|
||||
* @returns {void}
|
||||
*/
|
||||
end() {
|
||||
this.audioPlayer.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
const success = this.audioPlayer.pause(interpolateSilence);
|
||||
this.paused = success;
|
||||
return success;
|
||||
}
|
||||
/**
|
||||
* 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) {
|
||||
const success = this.audioPlayer.pause(interpolateSilence);
|
||||
this.paused = success;
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the stream playback
|
||||
* @returns {boolean}
|
||||
*/
|
||||
resume() {
|
||||
const success = this.audioPlayer.unpause();
|
||||
this.paused = !success;
|
||||
return success;
|
||||
}
|
||||
/**
|
||||
* Resumes the stream playback
|
||||
* @returns {boolean}
|
||||
*/
|
||||
resume() {
|
||||
const success = this.audioPlayer.unpause();
|
||||
this.paused = !success;
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Play stream
|
||||
* @param {AudioResource<Track>} [resource=this.audioResource] The audio resource to play
|
||||
* @returns {Promise<StreamDispatcher>}
|
||||
*/
|
||||
async playStream(resource: AudioResource<Track> = this.audioResource) {
|
||||
if (!resource) throw new PlayerError("Audio resource is not available!", ErrorStatusCode.NO_AUDIO_RESOURCE);
|
||||
if (resource.ended) return void this.emit("error", new PlayerError("Cannot play a resource that has already ended.") as unknown as AudioPlayerError);
|
||||
if (!this.audioResource) this.audioResource = resource;
|
||||
if (this.voiceConnection.state.status !== VoiceConnectionStatus.Ready) {
|
||||
try {
|
||||
await entersState(this.voiceConnection, VoiceConnectionStatus.Ready, this.connectionTimeout);
|
||||
} catch (err) {
|
||||
return void this.emit("error", err as AudioPlayerError);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Play stream
|
||||
* @param {AudioResource<Track>} [resource=this.audioResource] The audio resource to play
|
||||
* @returns {Promise<StreamDispatcher>}
|
||||
*/
|
||||
async playStream(resource: AudioResource<Track> = this.audioResource) {
|
||||
if (!resource) throw new PlayerError("Audio resource is not available!", ErrorStatusCode.NO_AUDIO_RESOURCE);
|
||||
if (resource.ended) return void this.emit("error", new PlayerError("Cannot play a resource that has already ended.") as unknown as AudioPlayerError);
|
||||
if (!this.audioResource) this.audioResource = resource;
|
||||
if (this.voiceConnection.state.status !== VoiceConnectionStatus.Ready) {
|
||||
try {
|
||||
await entersState(this.voiceConnection, VoiceConnectionStatus.Ready, this.connectionTimeout);
|
||||
} catch (err) {
|
||||
return void this.emit("error", err as AudioPlayerError);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
this.audioPlayer.play(resource);
|
||||
} catch (e) {
|
||||
this.emit("error", e as AudioPlayerError);
|
||||
}
|
||||
try {
|
||||
this.audioPlayer.play(resource);
|
||||
} catch (e) {
|
||||
this.emit("error", e as AudioPlayerError);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets playback volume
|
||||
* @param {number} value The volume amount
|
||||
* @returns {boolean}
|
||||
*/
|
||||
setVolume(value: number) {
|
||||
if (!this.audioResource?.volume || isNaN(value) || value < 0 || value > Infinity) return false;
|
||||
/**
|
||||
* Sets playback volume
|
||||
* @param {number} value The volume amount
|
||||
* @returns {boolean}
|
||||
*/
|
||||
setVolume(value: number) {
|
||||
if (!this.audioResource?.volume || isNaN(value) || value < 0 || value > Infinity) return false;
|
||||
|
||||
this.audioResource.volume.setVolumeLogarithmic(value / 100);
|
||||
return true;
|
||||
}
|
||||
this.audioResource.volume.setVolumeLogarithmic(value / 100);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The current volume
|
||||
* @type {number}
|
||||
*/
|
||||
get volume() {
|
||||
if (!this.audioResource?.volume) return 100;
|
||||
const currentVol = this.audioResource.volume.volume;
|
||||
return Math.round(Math.pow(currentVol, 1 / 1.660964) * 100);
|
||||
}
|
||||
/**
|
||||
* The current volume
|
||||
* @type {number}
|
||||
*/
|
||||
get volume() {
|
||||
if (!this.audioResource?.volume) return 100;
|
||||
const currentVol = this.audioResource.volume.volume;
|
||||
return Math.round(Math.pow(currentVol, 1 / 1.660964) * 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* The playback time
|
||||
* @type {number}
|
||||
*/
|
||||
get streamTime() {
|
||||
if (!this.audioResource) return 0;
|
||||
return this.audioResource.playbackDuration;
|
||||
}
|
||||
/**
|
||||
* The playback time
|
||||
* @type {number}
|
||||
*/
|
||||
get streamTime() {
|
||||
if (!this.audioResource) return 0;
|
||||
return this.audioResource.playbackDuration;
|
||||
}
|
||||
}
|
||||
|
||||
export { StreamDispatcher as StreamDispatcher };
|
||||
|
|
|
@ -3,80 +3,80 @@ import { DiscordGatewayAdapterCreator, joinVoiceChannel, VoiceConnection } from
|
|||
import { StreamDispatcher } from "./StreamDispatcher";
|
||||
|
||||
class VoiceUtils {
|
||||
public cache: Collection<Snowflake, StreamDispatcher>;
|
||||
public cache: Collection<Snowflake, StreamDispatcher>;
|
||||
|
||||
/**
|
||||
* The voice utils
|
||||
* @private
|
||||
*/
|
||||
constructor() {
|
||||
/**
|
||||
* The cache where voice utils stores stream managers
|
||||
* @type {Collection<Snowflake, StreamDispatcher>}
|
||||
*/
|
||||
this.cache = new Collection<Snowflake, StreamDispatcher>();
|
||||
}
|
||||
/**
|
||||
* The voice utils
|
||||
* @private
|
||||
*/
|
||||
constructor() {
|
||||
/**
|
||||
* The cache where voice utils stores stream managers
|
||||
* @type {Collection<Snowflake, StreamDispatcher>}
|
||||
*/
|
||||
this.cache = new Collection<Snowflake, StreamDispatcher>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins a voice channel, creating basic stream dispatch manager
|
||||
* @param {StageChannel|VoiceChannel} channel The voice channel
|
||||
* @param {object} [options] Join options
|
||||
* @returns {Promise<StreamDispatcher>}
|
||||
*/
|
||||
public async connect(
|
||||
channel: VoiceChannel | StageChannel,
|
||||
options?: {
|
||||
deaf?: boolean;
|
||||
maxTime?: number;
|
||||
}
|
||||
): Promise<StreamDispatcher> {
|
||||
const conn = await this.join(channel, options);
|
||||
const sub = new StreamDispatcher(conn, channel, options.maxTime);
|
||||
this.cache.set(channel.guild.id, sub);
|
||||
return sub;
|
||||
}
|
||||
/**
|
||||
* Joins a voice channel, creating basic stream dispatch manager
|
||||
* @param {StageChannel|VoiceChannel} channel The voice channel
|
||||
* @param {object} [options] Join options
|
||||
* @returns {Promise<StreamDispatcher>}
|
||||
*/
|
||||
public async connect(
|
||||
channel: VoiceChannel | StageChannel,
|
||||
options?: {
|
||||
deaf?: boolean;
|
||||
maxTime?: number;
|
||||
}
|
||||
): Promise<StreamDispatcher> {
|
||||
const conn = await this.join(channel, options);
|
||||
const sub = new StreamDispatcher(conn, channel, options.maxTime);
|
||||
this.cache.set(channel.guild.id, sub);
|
||||
return sub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins a voice channel
|
||||
* @param {StageChannel|VoiceChannel} [channel] The voice/stage channel to join
|
||||
* @param {object} [options] Join options
|
||||
* @returns {VoiceConnection}
|
||||
*/
|
||||
public async join(
|
||||
channel: VoiceChannel | StageChannel,
|
||||
options?: {
|
||||
deaf?: boolean;
|
||||
maxTime?: number;
|
||||
}
|
||||
) {
|
||||
const conn = joinVoiceChannel({
|
||||
guildId: channel.guild.id,
|
||||
channelId: channel.id,
|
||||
adapterCreator: channel.guild.voiceAdapterCreator as unknown as DiscordGatewayAdapterCreator,
|
||||
selfDeaf: Boolean(options.deaf)
|
||||
});
|
||||
/**
|
||||
* Joins a voice channel
|
||||
* @param {StageChannel|VoiceChannel} [channel] The voice/stage channel to join
|
||||
* @param {object} [options] Join options
|
||||
* @returns {VoiceConnection}
|
||||
*/
|
||||
public async join(
|
||||
channel: VoiceChannel | StageChannel,
|
||||
options?: {
|
||||
deaf?: boolean;
|
||||
maxTime?: number;
|
||||
}
|
||||
) {
|
||||
const conn = joinVoiceChannel({
|
||||
guildId: channel.guild.id,
|
||||
channelId: channel.id,
|
||||
adapterCreator: channel.guild.voiceAdapterCreator as unknown as DiscordGatewayAdapterCreator,
|
||||
selfDeaf: Boolean(options.deaf)
|
||||
});
|
||||
|
||||
return conn;
|
||||
}
|
||||
return conn;
|
||||
}
|
||||