@persian-caesar/discord-player
Version:
Type definitions and helpers for a Discord music player (MusicPlayer) without external dependencies
643 lines • 45.4 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MusicPlayer = void 0;
const voice_1 = require("@discordjs/voice");
const types_1 = require("./types");
const html_to_text_1 = require("html-to-text");
const ytdl_core_discord_1 = __importDefault(require("ytdl-core-discord"));
const events_1 = __importDefault(require("events"));
const ytdl_core_1 = __importDefault(require("ytdl-core"));
const play_dl_1 = __importDefault(require("play-dl"));
const ytdl_core_2 = __importDefault(require("@distube/ytdl-core"));
const soundcloud_downloader_1 = __importDefault(require("soundcloud-downloader"));
/**
* Manages voice connection, playback, queue, history, and loop modes.
* Emits events defined in MusicPlayerEvent.
*/
class MusicPlayer extends events_1.default {
channel;
// Player main data
previousQueueOrder = [];
connection = null;
player;
volume;
queue = [];
history = [];
loopQueue = false;
loopTrack = false;
playing = false;
autoLeaveOnEmptyQueue;
autoLeaveOnIdleMs;
idleTimer = null;
shuffield = false;
// Radio
radioMode = false;
radioUrls = [];
// Connection
connectionData = null;
/**
* Initializes a new MusicPlayer instance.
* @param channel - Discord voice channel to connect to.
* @param initialVolume - Initial volume (0–100), defaults to 100.
* @param options - Options for auto-leave and idle timeout.
*/
constructor(channel, initialVolume = 100, options = {}) {
super();
this.channel = channel;
this.player = (0, voice_1.createAudioPlayer)(); // Creates a new audio player for streaming music
this.volume = Math.round(initialVolume / 100); // Converts volume from percentage (0–100) to decimal (0–1)
this.autoLeaveOnEmptyQueue = options.autoLeaveOnEmptyQueue ?? true; // Default: leave voice channel when queue is empty
this.autoLeaveOnIdleMs = options.autoLeaveOnIdleMs ?? 5 * 60_000; // Default: 5-minute idle timeout before disconnecting
this.connectionData = {
channelId: channel.id,
guildId: channel.guild.id,
adapterCreator: channel.guild.voiceAdapterCreator,
selfDeaf: true,
selfMute: false,
debug: false
};
// Set up event listeners for error handling, idle state, and playback start
this.player.on("error", err => {
this.emit(types_1.MusicPlayerEvent.Error, this.createError("Player have error => " + err.message));
});
this.player.on(voice_1.AudioPlayerStatus.Idle, () => this.onIdle()); // Triggers when no audio is playing
this.player.on(voice_1.AudioPlayerStatus.Playing, () => this.clearIdleTimer()); // Clears idle timer when music starts
}
/**
* Sets the connection data for the voice channel.
* @param data - Connection settings.
* @returns The current MusicPlayer instance.
*/
setData(data) {
this.connectionData = {
...data,
selfDeaf: data.selfDeaf ?? true,
selfMute: data.selfMute ?? false,
debug: data.debug ?? false
};
return this;
}
/**
* Joins the voice channel using provided or stored connection data.
* @param data - Optional connection settings; uses stored data if not provided.
* @returns The VoiceConnection instance.
*/
join(data) {
if (!data && !this.connectionData) {
throw this.createError("No connection data available to join voice channel.");
}
const connectionData = data || this.connectionData;
this.connection = (0, voice_1.joinVoiceChannel)({
channelId: connectionData.channelId,
guildId: connectionData.guildId,
adapterCreator: connectionData.adapterCreator,
selfDeaf: connectionData.selfDeaf ?? true,
selfMute: connectionData.selfMute ?? false,
group: connectionData.group,
debug: connectionData.debug
});
this.connection.subscribe(this.player);
return this.connection;
}
/**
* Establishes a connection to the voice channel if not already connected.
*/
async ensureConnection() {
if (!this.connection) {
this.connection = this.join();
try {
await (0, voice_1.entersState)(this.connection, voice_1.VoiceConnectionStatus.Ready, 20_000);
}
catch (e) {
this.connection.destroy();
this.connection = null;
this.emit(types_1.MusicPlayerEvent.Error, this.createError("Can't connect to the voice channel. => " + e.message));
}
}
return;
}
/**
* Starts a timer to disconnect after inactivity.
*/
startIdleTimer() {
if (this.autoLeaveOnIdleMs > 0 && !this.idleTimer && !this.playing) {
this.idleTimer = setTimeout(() => {
this.emit(types_1.MusicPlayerEvent.Disconnect);
this.disconnect();
}, this.autoLeaveOnIdleMs);
}
}
/**
* Clears the idle timer if it exists.
*/
clearIdleTimer() {
if (this.idleTimer) {
clearTimeout(this.idleTimer);
this.idleTimer = null;
}
}
/**
* Randomly shuffles an array.
* @param array - Array to shuffle.
* @returns New shuffled array.
*/
shuffleArray(array) {
const shuffled = [...array];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled;
}
/**
* Searches Google for song lyrics and returns them, or null if not found.
* @param title - Song title.
* @param artist - Optional artist name for better accuracy.
*/
async searchLyrics(title, artist) {
const delim1 = '</div></div></div></div><div class="hwc"><div class="BNeawe tAd8D AP7Wnd"><div><div class="BNeawe tAd8D AP7Wnd">';
const delim2 = '</div></div></div></div></div><div><span class="hwc"><div class="BNeawe uEec3 AP7Wnd">';
const GOOGLE = "https://www.google.com/search?q=";
let html = "";
const query = encodeURIComponent(`${artist ? artist + " " : ""}${title}`);
const attempts = [
`${GOOGLE}${query}+lyrics`,
`${GOOGLE}${query}+song+lyrics`,
`${GOOGLE}${query}+song`,
`${GOOGLE}${query}`
];
for (const url of attempts) {
try {
const res = await fetch(url, { headers: { "User-Agent": "Mozilla/5.0" } });
html = await res.text();
break;
}
catch {
continue;
}
}
if (!html)
return null;
let snippet;
try {
[, snippet] = html.split(delim1);
[snippet] = snippet.split(delim2);
}
catch {
return null;
}
const rawLines = snippet.split("\n");
let lyrics = "";
for (const line of rawLines) {
lyrics += (0, html_to_text_1.htmlToText)(line).trim() + "\n";
}
lyrics = lyrics.trim();
return lyrics || null;
}
/**
* Resolves a query to a track URL or returns the URL if provided.
* @param query - Search query or URL.
* @returns Resolved URL.
*/
async search(query) {
if (/^https?:\/\//.test(query))
return query;
const sc_results = await soundcloud_downloader_1.default.search({ query, resourceType: "tracks", limit: 1 });
let url = sc_results.collection?.[0]?.permalink_url;
if (!url) {
const playdl_results = await play_dl_1.default.search(query, {
limit: 1,
source: { spotify: "track", soundcloud: "tracks", youtube: "video", deezer: "track" }
});
url = playdl_results[0]?.url;
}
return url;
}
/**
* Starts radio mode with a list of URLs.
* @param urls - Array of URLs to play.
*/
async startRadio(urls) {
this.radioMode = true;
this.radioUrls = urls;
const shuffledUrls = this.shuffleArray([...urls]);
this.queue = await Promise.all(shuffledUrls.map(async (url) => await this.fetchMetadata(url)));
if (this.queue.length > 0) {
const first = this.queue.shift();
await this.playUrl(first.url, first);
}
}
/**
* Creates a stream from a SoundCloud URL.
* @param url - SoundCloud URL.
* @returns Readable stream.
*/
async createStreamFromScdl(url) {
return await soundcloud_downloader_1.default.download(url);
}
/**
* Creates a stream from a YouTube URL using various ytdl libraries.
* @param url - YouTube URL.
* @returns Readable stream or null if failed.
*/
async createStreamFromYtdl(url) {
const options = { filter: "audioonly", highWaterMark: 1 << 25 };
let stream = null;
try {
stream = (0, ytdl_core_2.default)(url, options);
}
catch { }
if (!stream)
try {
stream = (0, ytdl_core_1.default)(url, options);
}
catch { }
if (!stream)
try {
stream = await (0, ytdl_core_discord_1.default)(url, options);
}
catch { }
return stream;
}
/**
* Creates a stream from a URL using play-dl.
* @param url - URL to stream.
* @returns Readable stream or null if failed.
*/
async createStreamFromPlayDl(url) {
const yt = await play_dl_1.default.stream(url, { quality: 2 });
if (!yt)
return null;
return yt.stream;
}
/**
* Fetches metadata for a track URL.
* @param url - Track URL.
* @returns Track metadata.
*/
async fetchMetadata(url) {
const empity_resualt = { title: undefined, author: undefined, duration: undefined, thumbnail: undefined, source: "unknown", url };
try {
if (/^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\//.test(url)) {
let info;
try {
info = await ytdl_core_2.default.getBasicInfo(url);
}
catch { }
if (!info)
try {
info = await ytdl_core_1.default.getBasicInfo(url);
}
catch { }
if (!info)
try {
info = await ytdl_core_discord_1.default.getBasicInfo(url);
}
catch { }
if (!info)
return empity_resualt;
const details = info.videoDetails;
return {
title: details.title,
author: details.author.name,
duration: parseInt(details.lengthSeconds, 10),
thumbnail: details.thumbnails[details.thumbnails.length - 1].url,
source: "youtube",
url
};
}
if (/^https?:\/\/(soundcloud\.com|snd\.sc)\//.test(url)) {
const info = await soundcloud_downloader_1.default.getInfo(url);
return {
title: info.title,
author: info.user?.username,
duration: Math.floor(info.duration / 1000),
thumbnail: info.artwork_url || info.user?.avatar_url,
source: "soundcloud",
url
};
}
const result = await play_dl_1.default.video_basic_info(url);
const vid = result.video_details;
return {
title: vid.title,
author: vid.channel?.name,
duration: vid.durationInSec,
thumbnail: vid.thumbnails?.[0]?.url,
source: "unknown",
url
};
}
catch {
return empity_resualt;
}
}
/**
* Plays a track URL with its metadata.
* @param url - Track URL.
* @param metadata - Track metadata.
*/
async playUrl(url, metadata) {
this.playing = true;
this.history.push(url);
let stream = null;
if (/^https?:\/\/(soundcloud\.com|snd\.sc)\//.test(url))
try {
stream = await this.createStreamFromScdl(url);
}
catch { }
if (/^https?:\/\/open\.spotify\.com\/(track|album|playlist)\//.test(url))
if (!stream)
try {
stream = await this.createStreamFromPlayDl(url);
}
catch { }
if (/^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\//.test(url))
if (!stream)
try {
stream = await this.createStreamFromYtdl(url);
}
catch { }
const resource = (0, voice_1.createAudioResource)(stream, { inlineVolume: true });
resource.volume?.setVolume(this.volume);
this.player.play(resource);
if (!this.player.state.resource)
this.player.state.resource = resource;
this.emit(types_1.MusicPlayerEvent.Start, { metadata, queue: [...this.queue] });
return;
}
/**
* Plays a song by query or URL, adding to queue if already playing.
* @param input - Search query or URL.
*/
async play(input) {
await this.ensureConnection();
const url = await this.search(input);
const metadata = await this.fetchMetadata(url);
if (this.playing) {
this.queue.push(metadata);
this.emit(types_1.MusicPlayerEvent.QueueAdd, { metadata, queue: [...this.queue] });
}
else {
await this.playUrl(url, metadata);
}
return;
}
/**
* Pauses the current playback.
*/
pause() {
this.player.pause();
this.emit(types_1.MusicPlayerEvent.Pause);
return;
}
/**
* Resumes the current playback.
*/
resume() {
this.player.unpause();
this.emit(types_1.MusicPlayerEvent.Resume);
return;
}
/**
* Sets the playback volume.
* @param percent - Volume percentage (0–200).
*/
setVolume(percent) {
percent /= 100;
if (percent < 0 || percent > 2)
this.volume = 2;
else
this.volume = percent;
const resource = this.player.state.resource;
try {
resource.volume.setVolume(this.volume);
}
catch { }
this.emit(types_1.MusicPlayerEvent.VolumeChange, { volume: Math.round(this.volume * 100) });
return this.volume;
}
/**
* Handles idle state, looping or playing next track as needed.
*/
async onIdle() {
if (this.loopTrack) {
const url = this.history[this.history.length - 1];
const metadata = await this.fetchMetadata(url);
return await this.playUrl(url, metadata);
}
if (this.queue.length) {
const next = this.queue.shift();
if (this.loopQueue)
this.queue.push(next);
return await this.playUrl(next.url, next);
}
if (this.radioMode && this.radioUrls.length > 0) {
const shuffledUrls = this.shuffleArray([...this.radioUrls]);
this.queue = await Promise.all(shuffledUrls.map(async (url) => await this.fetchMetadata(url)));
if (this.queue.length > 0) {
const next = this.queue.shift();
return await this.playUrl(next.url, next);
}
}
this.playing = false;
this.emit(types_1.MusicPlayerEvent.Finish, { queue: [...this.queue], history: [...this.history] });
if (this.autoLeaveOnEmptyQueue) {
this.emit(types_1.MusicPlayerEvent.Disconnect);
this.disconnect();
}
else {
this.startIdleTimer();
}
return;
}
/**
* Skips the current track and moves to the next.
*/
skip() {
this.emit(types_1.MusicPlayerEvent.Skip, { queue: [...this.queue], history: [...this.history] });
this.player.stop();
return;
}
/**
* Plays the previous track from history.
*/
async previous() {
if (this.history.length < 2) {
this.emit(types_1.MusicPlayerEvent.Error, this.createError("No track to previous."));
return;
}
this.history.pop();
const prevUrl = this.history.pop();
const metadata = await this.fetchMetadata(prevUrl);
this.queue.unshift(metadata);
this.emit(types_1.MusicPlayerEvent.Previous, { metadata, queue: [...this.queue], history: [...this.history, prevUrl] });
await this.playUrl(prevUrl, metadata);
return;
}
/**
* Shuffles the queue and saves the previous order.
*/
shuffle() {
this.previousQueueOrder = [...this.queue];
for (let i = this.queue.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[this.queue[i], this.queue[j]] = [this.queue[j], this.queue[i]];
}
this.shuffield = true;
this.emit(types_1.MusicPlayerEvent.Shuffle, { queue: [...this.queue] });
return;
}
/**
* Restores the queue to its pre-shuffle order, excluding played tracks.
*/
undoShuffle() {
this.queue = this.previousQueueOrder.filter(meta => !this.history.includes(meta.url));
this.shuffield = false;
this.emit(types_1.MusicPlayerEvent.Shuffle, { queue: [...this.queue] });
return;
}
/**
* Toggles queue looping on or off.
*/
toggleLoopQueue() {
return this.loopQueue = !this.loopQueue;
}
/**
* Checks if queue looping is enabled.
* @returns True if enabled, false otherwise.
*/
isLoopQueue() {
return this.loopQueue;
}
/**
* Toggles track looping on or off.
*/
toggleLoopTrack() {
return this.loopTrack = !this.loopTrack;
}
/**
* Checks if track looping is enabled.
* @returns True if enabled, false otherwise.
*/
isLoopTrack() {
return this.loopTrack;
}
/**
* Disconnects from the voice channel and cleans up resources.
*/
disconnect() {
this.clearIdleTimer();
this.player?.stop();
if (this.connection) {
this.connection.destroy();
this.connection = null;
}
this.playing = false;
this.queue = [];
this.history = [];
this.emit(types_1.MusicPlayerEvent.Disconnect);
return;
}
/**
* Stops playback and optionally disconnects.
* @param noLeave - If true, stays connected to the channel.
*/
stop(noLeave = true) {
this.radioMode = false;
this.radioUrls = [];
this.player.stop();
this.playing = false;
this.queue = [];
this.history = [];
this.clearIdleTimer();
if (!noLeave)
this.disconnect();
this.emit(types_1.MusicPlayerEvent.Stop);
return;
}
/**
* Returns a copy of the current queue.
* @returns Array of track metadata.
*/
getQueue() {
return [...this.queue];
}
/**
* Gets the current volume percentage.
* @returns Volume (0–200).
*/
getVolume() {
const resource = this.player.state.resource;
if (resource && resource.volume && resource.volume.volume)
return Math.round(resource.volume.volume * 100);
return Math.round(this.volume * 100);
}
/**
* Checks if the player is currently playing.
* @returns True if playing, false otherwise.
*/
isPlaying() {
return this.playing;
}
/**
* Checks if the player is paused.
* @returns True if paused, false otherwise.
*/
isPaused() {
return this.player && this.player.state.status === voice_1.AudioPlayerStatus.Paused;
}
/**
* Checks if the queue is shuffled.
* @returns True if shuffled, false otherwise.
*/
isShuffiled() {
return this.shuffield;
}
/**
* Checks if the bot is actively connected to a voice channel.
* @param guildId - Optional guild ID; uses stored guild ID if not provided.
* @returns True if actively connected, false otherwise.
*/
isConnected(guildId) {
const targetGuildId = guildId || this.connectionData?.guildId;
if (!targetGuildId)
return false;
const connection = this.connection || (0, voice_1.getVoiceConnection)(targetGuildId);
if (!connection)
return false;
return [
voice_1.VoiceConnectionStatus.Ready,
voice_1.VoiceConnectionStatus.Connecting,
voice_1.VoiceConnectionStatus.Signalling
].includes(connection.state.status);
}
/**
* Creates a custom error for the music player.
* @param message - Error message.
* @returns Custom error instance.
*/
createError(message) {
class discordPlayerError extends Error {
constructor() {
super();
this.name = "Discord-Player";
this.message = message;
}
}
return new discordPlayerError();
}
}
exports.MusicPlayer = MusicPlayer;
/**
* @copyright
* Code by Sobhan-SRZA (mr.sinre) | https://github.com/Sobhan-SRZA
* Developed for Persian Caesar | https://github.com/Persian-Caesar | https://dsc.gg/persian-caesar
*
* If you encounter any issues or need assistance with this code,
* please make sure to credit "Persian Caesar" in your documentation or communications.
*/
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTXVzaWNQbGF5ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvTXVzaWNQbGF5ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsNENBVzBCO0FBQzFCLG1DQU1pQjtBQUNqQiwrQ0FBMEM7QUFFMUMsMEVBQWtEO0FBQ2xELG9EQUFrQztBQUNsQywwREFBa0M7QUFDbEMsc0RBQTZCO0FBQzdCLG1FQUFzQztBQUN0QyxrRkFBeUM7QUFFekM7OztHQUdHO0FBQ0gsTUFBYSxXQUFZLFNBQVEsZ0JBQTBCO0lBc0M1QztJQXJDWCxtQkFBbUI7SUFDWCxrQkFBa0IsR0FBb0IsRUFBRSxDQUFDO0lBQ3pDLFVBQVUsR0FBMkIsSUFBSSxDQUFDO0lBQzFDLE1BQU0sQ0FBYztJQUNwQixNQUFNLENBQVM7SUFDZixLQUFLLEdBQW9CLEVBQUUsQ0FBQztJQUM1QixPQUFPLEdBQWEsRUFBRSxDQUFDO0lBQ3ZCLFNBQVMsR0FBRyxLQUFLLENBQUM7SUFDbEIsU0FBUyxHQUFHLEtBQUssQ0FBQztJQUNsQixPQUFPLEdBQUcsS0FBSyxDQUFDO0lBQ2hCLHFCQUFxQixDQUFVO0lBQy9CLGlCQUFpQixDQUFTO0lBQzFCLFNBQVMsR0FBMEIsSUFBSSxDQUFDO0lBQ3hDLFNBQVMsR0FBWSxLQUFLLENBQUM7SUFFbkMsUUFBUTtJQUNBLFNBQVMsR0FBWSxLQUFLLENBQUM7SUFDM0IsU0FBUyxHQUFhLEVBQUUsQ0FBQztJQUVqQyxhQUFhO0lBQ0wsY0FBYyxHQVFYLElBQUksQ0FBQztJQUVoQjs7Ozs7T0FLRztJQUNILFlBQ1csT0FBcUIsRUFDNUIsYUFBYSxHQUFHLEdBQUcsRUFDbkIsVUFBOEIsRUFBRTtRQUVoQyxLQUFLLEVBQUUsQ0FBQztRQUpELFlBQU8sR0FBUCxPQUFPLENBQWM7UUFLNUIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFBLHlCQUFpQixHQUFFLENBQUMsQ0FBQyxpREFBaUQ7UUFDcEYsSUFBSSxDQUFDLE1BQU0sR0FBRyxJ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