Skip to content

Commit

Permalink
3.7.0-dev-5
Browse files Browse the repository at this point in the history
Added songs size to playlist schema.
Added songs size to playlist name autocomplete.
Added button "favorite" to audioplayer.
  • Loading branch information
AlexInCube committed Aug 21, 2024
1 parent 67c95c1 commit 6e6150a
Show file tree
Hide file tree
Showing 22 changed files with 198 additions and 83 deletions.
2 changes: 2 additions & 0 deletions src/CommandTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,5 @@ interface IGuildData {
voice_required?: boolean;
voice_with_bot_only?: boolean; // Property enabled only if voice_required is true
}

export type ICommandContext = Message | ChatInputCommandInteraction;
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export enum AudioPlayerIcons {
skip = '<:skipbutton:1092107438234275900>',
shuffle = '<:shufflebutton:1092107651384614912>',
list = '<:songlistwhite:1014551771705782405>',
lyrics = '<:lyrics:1260156581794811974>'
lyrics = '<:lyrics:1260156581794811974>',
favorite = '<:favorite:1275199463631093860>'
}

export enum AudioSourceIcons {
Expand Down
8 changes: 4 additions & 4 deletions src/audioplayer/AudioPlayersManager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DisTube, PlayOptions, Queue, RepeatMode, Song, Events as DistubeEvents, Playlist } from 'distube';
import { DisTube, Events as DistubeEvents, Playlist, PlayOptions, Queue, RepeatMode, Song } from 'distube';
import { AudioPlayersStore } from './AudioPlayersStore.js';
import { pagination } from '../utilities/pagination/pagination.js';
import { ButtonStyles, ButtonTypes } from '../utilities/pagination/paginationTypes.js';
Expand Down Expand Up @@ -52,11 +52,11 @@ export class AudioPlayersManager {
async play(
voiceChannel: VoiceBasedChannel,
textChannel: TextChannel,
song: string | Song | Playlist,
query: string | Song | Playlist,
options?: PlayOptions
) {
try {
const playableThing: Song | Playlist = await this.distube.handler.resolve(song);
const playableThing: Song | Playlist = await this.distube.handler.resolve(query);

// I am need manual connect user to a voice channel, because when I am using only Distube "play"
// method, getVoiceConnection in @discordjs/voice is not working
Expand All @@ -70,7 +70,7 @@ export class AudioPlayersManager {
} catch (e) {
if (ENV.BOT_VERBOSE_LOGGING) loggerError(e);
await textChannel.send({
embeds: [generateErrorEmbed(`${song}\n${e.message}`, i18next.t('audioplayer:play_error') as string)]
embeds: [generateErrorEmbed(`${query}\n${e.message}`, i18next.t('audioplayer:play_error') as string)]
});

const queue = this.distube.getQueue(voiceChannel.guildId);
Expand Down
56 changes: 48 additions & 8 deletions src/audioplayer/PlayerButtons.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import {
ActionRowBuilder,
ButtonBuilder,
ButtonInteraction,
ButtonStyle,
InteractionCollector,
ComponentType,
Client,
GuildMember,
ButtonInteraction,
ComponentType,
Guild,
GuildTextBasedChannel
GuildMember,
GuildTextBasedChannel,
InteractionCollector
} from 'discord.js';
import { checkMemberInVoiceWithBot } from '../utilities/checkMemberInVoiceWithBot.js';
import { generateErrorEmbed } from '../utilities/generateErrorEmbed.js';
Expand All @@ -18,13 +18,16 @@ import {
generateEmbedAudioPlayerShuffle,
generateEmbedAudioPlayerShuffleFailure
} from '../commands/audio/shuffle.command.js';
import { AudioPlayerIcons, AudioPlayerState } from './AudioPlayerTypes.js';
import { AudioPlayerIcons, AudioPlayerState } from './AudioPlayerIcons.js';
import { generateEmbedAudioPlayerStop } from '../commands/audio/stop.command.js';
import {
generateEmbedAudioPlayerPrevious,
generateEmbedAudioPlayerPreviousFailure
} from '../commands/audio/previous.command.js';
import { ENV } from '../EnvironmentVariables.js';
import { UserPlaylistAddFavoriteSong } from '../schemas/SchemaPlaylist.js';
import { generateSimpleEmbed } from '../utilities/generateSimpleEmbed.js';
import i18next from 'i18next';

enum ButtonIDs {
stopMusic = 'stopMusic',
Expand All @@ -35,7 +38,8 @@ enum ButtonIDs {
//downloadSong = 'downloadSong',
shuffle = 'shuffle',
showQueue = 'showQueue',
lyrics = 'lyrics'
lyrics = 'lyrics',
favorite = 'favorite'
}

const rowPrimary = new ActionRowBuilder<ButtonBuilder>().addComponents(
Expand Down Expand Up @@ -69,7 +73,11 @@ const rowPrimaryPaused = new ActionRowBuilder<ButtonBuilder>().addComponents(
const rowSecondary = new ActionRowBuilder<ButtonBuilder>().addComponents(
//new ButtonBuilder().setCustomId(ButtonIDs.downloadSong).setStyle(ButtonStyle.Success).setEmoji('<:downloadwhite:1014553027614617650>'),
new ButtonBuilder().setCustomId(ButtonIDs.shuffle).setStyle(ButtonStyle.Primary).setEmoji(AudioPlayerIcons.shuffle),
new ButtonBuilder().setCustomId(ButtonIDs.showQueue).setStyle(ButtonStyle.Secondary).setEmoji(AudioPlayerIcons.list)
new ButtonBuilder().setCustomId(ButtonIDs.showQueue).setStyle(ButtonStyle.Secondary).setEmoji(AudioPlayerIcons.list),
new ButtonBuilder()
.setCustomId(ButtonIDs.favorite)
.setStyle(ButtonStyle.Secondary)
.setEmoji(AudioPlayerIcons.favorite)
);

if (ENV.BOT_GENIUS_TOKEN) {
Expand Down Expand Up @@ -192,6 +200,38 @@ export class PlayerButtons {

case ButtonIDs.lyrics: {
await this.client.audioPlayer.showLyrics(ButtonInteraction);
break;
}

case ButtonIDs.favorite: {
try {
const queue = ButtonInteraction.client.audioPlayer.distube.getQueue(ButtonInteraction.guild as Guild);

if (!queue || queue.songs.length === 0) {
await ButtonInteraction.deferUpdate();
return;
}

await UserPlaylistAddFavoriteSong(ButtonInteraction.user.id, queue.songs[0]);

await ButtonInteraction.reply({
embeds: [
generateSimpleEmbed(
i18next.t('audioplayer:song_added_to_favorite', {
name: queue.songs[0].name!,
interpolation: { escapeValue: false }
})
)
],
ephemeral: true
});
} catch (e) {
await ButtonInteraction.reply({
embeds: [generateErrorEmbed(e.message, e.name)],
ephemeral: true
});
}
break;
}
}
} catch (e) {
Expand Down
11 changes: 3 additions & 8 deletions src/audioplayer/PlayerEmbed.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { EmbedBuilder, User } from 'discord.js';
import { AudioPlayerLoopMode, AudioPlayerState, AudioSourceIcons } from './AudioPlayerTypes.js';
import { getNoun } from '../utilities/getNoun.js';
import { AudioPlayerLoopMode, AudioPlayerState, AudioSourceIcons } from './AudioPlayerIcons.js';
import { formatSecondsToTime } from '../utilities/formatSecondsToTime.js';
import i18next from 'i18next';
import { Playlist, Song } from 'distube';
import { getIconFromSource } from './util/getIconFromSource.js';
import { getSongsNoun } from './util/getSongsNoun.js';

export class PlayerEmbed extends EmbedBuilder {
private playerState: AudioPlayerState = 'loading';
Expand Down Expand Up @@ -51,12 +51,7 @@ export class PlayerEmbed extends EmbedBuilder {
this.addFields({
name: i18next.t('audioplayer:player_embed_queue'),
value: `
\`${this.songsCount} ${getNoun(
this.songsCount,
i18next.t('audioplayer:player_embed_queue_noun_one'),
i18next.t('audioplayer:player_embed_queue_noun_two'),
i18next.t('audioplayer:player_embed_queue_noun_five')
)}\`
\`${this.songsCount} ${getSongsNoun(this.songsCount)}\`
\`${this.queueDuration}\`
`,
inline: true
Expand Down
2 changes: 1 addition & 1 deletion src/audioplayer/PlayerInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Client, GuildTextBasedChannel, Message } from 'discord.js';
import { PlayerEmbed } from './PlayerEmbed.js';
import { Queue, Song } from 'distube';
import { PlayerButtons } from './PlayerButtons.js';
import { AudioPlayerState } from './AudioPlayerTypes.js';
import { AudioPlayerState } from './AudioPlayerIcons.js';
import { checkBotInVoice } from '../utilities/checkBotInVoice.js';
import i18next from 'i18next';
import { ENV } from '../EnvironmentVariables.js';
Expand Down
2 changes: 1 addition & 1 deletion src/audioplayer/util/getIconFromSource.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AudioSourceIcons } from '../AudioPlayerTypes.js';
import { AudioSourceIcons } from '../AudioPlayerIcons.js';

export function getIconFromSource(source: string): AudioSourceIcons {
switch (source) {
Expand Down
11 changes: 11 additions & 0 deletions src/audioplayer/util/getSongsNoun.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { getNoun } from '../../utilities/getNoun.js';
import i18next from 'i18next';

export function getSongsNoun(songsSize: number) {
return getNoun(
songsSize,
i18next.t('audioplayer:player_embed_queue_noun_one'),
i18next.t('audioplayer:player_embed_queue_noun_two'),
i18next.t('audioplayer:player_embed_queue_noun_five')
);
}
26 changes: 16 additions & 10 deletions src/commands/audio/pl-add.command.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CommandArgument, ICommand } from '../../CommandTypes.js';
import { CommandArgument, ICommand, ICommandContext } from '../../CommandTypes.js';
import { GroupAudio } from './AudioTypes.js';
import { ChatInputCommandInteraction, Message, PermissionsBitField, SlashCommandBuilder, User } from 'discord.js';
import { Message, PermissionsBitField, SlashCommandBuilder, User } from 'discord.js';
import i18next from 'i18next';
import {
PlaylistIsNotExists,
Expand Down Expand Up @@ -40,7 +40,7 @@ export default function (): ICommand {
.addStringOption((option) =>
option
.setName('playlist_name')
.setDescription(i18next.t('commands:pl-add_link'))
.setDescription(i18next.t('commands:pl_arg_name'))
.setAutocomplete(true)
.setRequired(true)
)
Expand All @@ -60,12 +60,7 @@ export default function (): ICommand {
};
}

async function plAddAndReply(
playlistName: string,
url: string,
ctx: Message | ChatInputCommandInteraction,
user: User
) {
async function plAddAndReply(playlistName: string, url: string, ctx: ICommandContext, user: User) {
try {
if (!isValidURL(url)) {
await ctx.reply({
Expand All @@ -75,7 +70,18 @@ async function plAddAndReply(
return;
}

const song = await ctx.client.audioPlayer.distube.handler.resolve(url);
const song = await ctx.client.audioPlayer.distube.handler
.resolve(url)
.then((result) => result)
.catch((err) => loggerError(err));

if (!song) {
await ctx.reply({
embeds: [generateErrorEmbed(i18next.t('commands:pl-add_error_song_must_be_support_in_bot_player'))],
ephemeral: true
});
return;
}

if (song instanceof Playlist) {
await ctx.reply({
Expand Down
6 changes: 3 additions & 3 deletions src/commands/audio/pl-create.command.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CommandArgument, ICommand } from '../../CommandTypes.js';
import { CommandArgument, ICommand, ICommandContext } from '../../CommandTypes.js';
import { GroupAudio } from './AudioTypes.js';
import { ChatInputCommandInteraction, Message, PermissionsBitField, SlashCommandBuilder } from 'discord.js';
import { Message, PermissionsBitField, SlashCommandBuilder } from 'discord.js';
import i18next from 'i18next';
import {
PlaylistAlreadyExists,
Expand Down Expand Up @@ -49,7 +49,7 @@ export default function (): ICommand {
};
}

async function plCreateAndReply(playlistName: string, ctx: Message | ChatInputCommandInteraction, userID: string) {
async function plCreateAndReply(playlistName: string, ctx: ICommandContext, userID: string) {
try {
await UserPlaylistCreate(userID, playlistName);

Expand Down
6 changes: 3 additions & 3 deletions src/commands/audio/pl-delete.command.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CommandArgument, ICommand } from '../../CommandTypes.js';
import { CommandArgument, ICommand, ICommandContext } from '../../CommandTypes.js';
import { GroupAudio } from './AudioTypes.js';
import { ChatInputCommandInteraction, Message, PermissionsBitField, SlashCommandBuilder } from 'discord.js';
import { Message, PermissionsBitField, SlashCommandBuilder } from 'discord.js';
import i18next from 'i18next';
import {
PlaylistIsNotExists,
Expand Down Expand Up @@ -47,7 +47,7 @@ export default function (): ICommand {
};
}

async function plDeleteAndReply(ctx: Message | ChatInputCommandInteraction, userID: string, playlistName: string) {
async function plDeleteAndReply(ctx: ICommandContext, userID: string, playlistName: string) {
try {
await UserPlaylistDelete(userID, playlistName);

Expand Down
13 changes: 3 additions & 10 deletions src/commands/audio/pl-display.command.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
import { CommandArgument, ICommand } from '../../CommandTypes.js';
import { CommandArgument, ICommand, ICommandContext } from '../../CommandTypes.js';
import { GroupAudio } from './AudioTypes.js';
import {
ChatInputCommandInteraction,
EmbedBuilder,
Message,
PermissionsBitField,
SlashCommandBuilder,
User
} from 'discord.js';
import { EmbedBuilder, Message, PermissionsBitField, SlashCommandBuilder, User } from 'discord.js';
import i18next from 'i18next';
import {
PlaylistNameMaxLength,
Expand Down Expand Up @@ -54,7 +47,7 @@ export default function (): ICommand {
};
}

async function plDisplayAndReply(playlistName: string, ctx: Message | ChatInputCommandInteraction, user: User) {
async function plDisplayAndReply(playlistName: string, ctx: ICommandContext, user: User) {
const playlist = await UserPlaylistGet(user.id, playlistName, true);

if (!playlist) {
Expand Down
12 changes: 3 additions & 9 deletions src/commands/audio/pl-my.command.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import { ICommand } from '../../CommandTypes.js';
import { ICommand, ICommandContext } from '../../CommandTypes.js';
import { GroupAudio } from './AudioTypes.js';
import {
ChatInputCommandInteraction,
EmbedBuilder,
Message,
PermissionsBitField,
SlashCommandBuilder
} from 'discord.js';
import { EmbedBuilder, Message, PermissionsBitField, SlashCommandBuilder } from 'discord.js';
import i18next from 'i18next';
import { UserPlaylistGetPlaylists } from '../../schemas/SchemaPlaylist.js';
import { generateErrorEmbed } from '../../utilities/generateErrorEmbed.js';
Expand All @@ -31,7 +25,7 @@ export default function (): ICommand {
};
}

async function plMyAndReply(ctx: Message | ChatInputCommandInteraction, userID: string) {
async function plMyAndReply(ctx: ICommandContext, userID: string) {
const playlists = await UserPlaylistGetPlaylists(userID);

if (playlists && playlists.length > 0) {
Expand Down
25 changes: 21 additions & 4 deletions src/commands/audio/pl-play.command.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { CommandArgument, ICommand } from '../../CommandTypes.js';
import { CommandArgument, ICommand, ICommandContext } from '../../CommandTypes.js';
import { GroupAudio } from './AudioTypes.js';
import {
ChatInputCommandInteraction,
Guild,
GuildMember,
Message,
Expand All @@ -18,6 +17,7 @@ import { ENV } from '../../EnvironmentVariables.js';
import { Song } from 'distube';
import { generateErrorEmbed } from '../../utilities/generateErrorEmbed.js';
import { loggerError } from '../../utilities/logger.js';
import { commandEmptyReply } from '../../utilities/commandEmptyReply.js';

export default function (): ICommand {
return {
Expand Down Expand Up @@ -64,7 +64,7 @@ export default function (): ICommand {
};
}

async function plPlayAndReply(ctx: Message | ChatInputCommandInteraction, playlistName: string, userID: string) {
async function plPlayAndReply(ctx: ICommandContext, playlistName: string, userID: string) {
try {
if (queueSongsIsFull(ctx.client, ctx.guild as Guild)) {
await ctx.reply({
Expand All @@ -88,6 +88,23 @@ async function plPlayAndReply(ctx: Message | ChatInputCommandInteraction, playli
})
);

if (songs.length === 0) {
await ctx.reply({
embeds: [
generateErrorEmbed(
i18next.t('commands:pl-play_error_empty_playlist', {
name: playlistName,
interpolation: { escapeValue: false }
})
)
],
ephemeral: true
});
return;
}

await commandEmptyReply(ctx);

const member = ctx.member as GuildMember;

const DistubePlaylist = await ctx.client.audioPlayer.distube.createCustomPlaylist(songs, {
Expand Down Expand Up @@ -120,7 +137,7 @@ async function plPlayAndReply(ctx: Message | ChatInputCommandInteraction, playli
return;
}

await ctx.reply({ embeds: [generateErrorEmbed(i18next.t('commands:pl-add_error_unknown'))], ephemeral: true });
await ctx.reply({ embeds: [generateErrorEmbed(i18next.t('commands:pl-play_error_unknown'))], ephemeral: true });
if (ENV.BOT_VERBOSE_LOGGING) loggerError(e);
}
}
Loading

0 comments on commit 6e6150a

Please sign in to comment.