muse/src/utils/build-embed.ts
2024-01-16 19:44:44 -06:00

136 lines
4.5 KiB
TypeScript

import getYouTubeID from 'get-youtube-id';
import {EmbedBuilder} from 'discord.js';
import Player, {MediaSource, QueuedSong, STATUS} from '../services/player.js';
import getProgressBar from './get-progress-bar.js';
import {prettyTime} from './time.js';
import {truncate} from './string.js';
const PAGE_SIZE = 10;
const getMaxSongTitleLength = (title: string) => {
// eslint-disable-next-line no-control-regex
const nonASCII = /[^\x00-\x7F]+/;
return nonASCII.test(title) ? 28 : 48;
};
const getSongTitle = ({title, url, offset, source}: QueuedSong, shouldTruncate = false) => {
if (source === MediaSource.HLS) {
return `[${title}](${url})`;
}
const cleanSongTitle = title.replace(/\[.*\]/, '').trim();
const songTitle = shouldTruncate ? truncate(cleanSongTitle, getMaxSongTitleLength(cleanSongTitle)) : cleanSongTitle;
const youtubeId = url.length === 11 ? url : getYouTubeID(url) ?? '';
return `[${songTitle}](https://www.youtube.com/watch?v=${youtubeId}${offset === 0 ? '' : '&t=' + String(offset)})`;
};
const getQueueInfo = (player: Player) => {
const queueSize = player.queueSize();
if (queueSize === 0) {
return '-';
}
return queueSize === 1 ? '1 song' : `${queueSize} songs`;
};
const getPlayerUI = (player: Player) => {
const song = player.getCurrent();
if (!song) {
return '';
}
const position = player.getPosition();
const button = player.status === STATUS.PLAYING ? '⏹️' : '▶️';
const progressBar = getProgressBar(15, position / song.length);
const elapsedTime = song.isLive ? 'live' : `${prettyTime(position)}/${prettyTime(song.length)}`;
const loop = player.loopCurrentSong ? '🔂' : player.loopCurrentQueue ? '🔁' : '';
return `${button} ${progressBar} \`[${elapsedTime}]\` 🔉 ${loop}`;
};
export const buildPlayingMessageEmbed = (player: Player): EmbedBuilder => {
const currentlyPlaying = player.getCurrent();
if (!currentlyPlaying) {
throw new Error('No playing song found');
}
const {artist, thumbnailUrl, requestedBy} = currentlyPlaying;
const message = new EmbedBuilder();
message
.setColor(player.status === STATUS.PLAYING ? 'DarkGreen' : 'DarkRed')
.setTitle(player.status === STATUS.PLAYING ? 'Now Playing' : 'Paused')
.setDescription(`
**${getSongTitle(currentlyPlaying)}**
Requested by: <@${requestedBy}>\n
${getPlayerUI(player)}
`)
.setFooter({text: `Source: ${artist}`});
if (thumbnailUrl) {
message.setThumbnail(thumbnailUrl);
}
return message;
};
export const buildQueueEmbed = (player: Player, page: number): EmbedBuilder => {
const currentlyPlaying = player.getCurrent();
if (!currentlyPlaying) {
throw new Error('queue is empty');
}
const queueSize = player.queueSize();
const maxQueuePage = Math.ceil((queueSize + 1) / PAGE_SIZE);
if (page > maxQueuePage) {
throw new Error('the queue isn\'t that big');
}
const queuePageBegin = (page - 1) * PAGE_SIZE;
const queuePageEnd = queuePageBegin + PAGE_SIZE;
const queuedSongs = player
.getQueue()
.slice(queuePageBegin, queuePageEnd)
.map((song, index) => {
const songNumber = index + 1 + queuePageBegin;
const duration = song.isLive ? 'live' : prettyTime(song.length);
return `\`${songNumber}.\` ${getSongTitle(song, true)} \`[${duration}]\``;
})
.join('\n');
const {artist, thumbnailUrl, playlist, requestedBy} = currentlyPlaying;
const playlistTitle = playlist ? `(${playlist.title})` : '';
const totalLength = player.getQueue().reduce((accumulator, current) => accumulator + current.length, 0);
const message = new EmbedBuilder();
let description = `**${getSongTitle(currentlyPlaying)}**\n`;
description += `Requested by: <@${requestedBy}>\n\n`;
description += `${getPlayerUI(player)}\n\n`;
if (player.getQueue().length > 0) {
description += '**Up next:**\n';
description += queuedSongs;
}
message
.setTitle(player.status === STATUS.PLAYING ? `Now Playing ${player.loopCurrentSong ? '(loop on)' : ''}` : 'Queued songs')
.setColor(player.status === STATUS.PLAYING ? 'DarkGreen' : 'NotQuiteBlack')
.setDescription(description)
.addFields([{name: 'In queue', value: getQueueInfo(player), inline: true}, {
name: 'Total length', value: `${totalLength > 0 ? prettyTime(totalLength) : '-'}`, inline: true,
}, {name: 'Page', value: `${page} out of ${maxQueuePage}`, inline: true}])
.setFooter({text: `Source: ${artist} ${playlistTitle}`});
if (thumbnailUrl) {
message.setThumbnail(thumbnailUrl);
}
return message;
};