Skip to content

Commit

Permalink
3.7.0-dev-3
Browse files Browse the repository at this point in the history
Added command /pl-play
UserPlaylistGet now throwing error when playlist is not found.
Refactored /play command.
  • Loading branch information
AlexInCube committed Aug 19, 2024
1 parent 464f488 commit 6162056
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 68 deletions.
7 changes: 6 additions & 1 deletion src/audioplayer/AudioPlayersManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ export class AudioPlayersManager {
this.setupEvents();
}

async play(voiceChannel: VoiceBasedChannel, textChannel: TextChannel, song: string | Song, options?: PlayOptions) {
async play(
voiceChannel: VoiceBasedChannel,
textChannel: TextChannel,
song: string | Song | Playlist,
options?: PlayOptions
) {
try {
const playableThing: Song | Playlist = await this.distube.handler.resolve(song);

Expand Down
96 changes: 90 additions & 6 deletions src/commands/audio/pl-play.command.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
import { CommandArgument, ICommand } from '../../CommandTypes.js';
import { GroupAudio } from './AudioTypes.js';
import { Message, PermissionsBitField, SlashCommandBuilder } from 'discord.js';
import {
ChatInputCommandInteraction,
Guild,
GuildMember,
Message,
PermissionsBitField,
SlashCommandBuilder,
TextChannel,
VoiceChannel
} from 'discord.js';
import i18next from 'i18next';
import { UserPlaylistNamesAutocomplete } from '../../schemas/SchemaPlaylist.js';
import { PlaylistIsNotExists, UserPlaylistGet, UserPlaylistNamesAutocomplete } from '../../schemas/SchemaPlaylist.js';
import { queueSongsIsFull } from '../../audioplayer/util/queueSongsIsFull.js';
import { generateWarningEmbed } from '../../utilities/generateWarningEmbed.js';
import { ENV } from '../../EnvironmentVariables.js';
import { Song } from 'distube';
import { generateErrorEmbed } from '../../utilities/generateErrorEmbed.js';
import { loggerError } from '../../utilities/logger.js';

export default function (): ICommand {
return {
text_data: {
name: 'pl-play',
description: i18next.t('commands:pl-play_desc'),
arguments: [new CommandArgument(i18next.t('commands:pl-play_arg'), true)],
execute: async (message: Message) => {}
arguments: [new CommandArgument(i18next.t('commands:pl_arg_name'), true)],
execute: async (message: Message, args: Array<string>) => {
const playlistName = args.join(' ');

await plPlayAndReply(message, playlistName, message.author.id);
}
},
slash_data: {
slash_builder: new SlashCommandBuilder()
Expand All @@ -19,11 +38,15 @@ export default function (): ICommand {
.addStringOption((option) =>
option
.setName('playlist_name')
.setDescription(i18next.t('commands:pl-play_arg'))
.setDescription(i18next.t('commands:pl_arg_name'))
.setAutocomplete(true)
.setRequired(true)
),
execute: async (interaction) => {},
execute: async (interaction) => {
const playlistName = interaction.options.getString('playlist_name')!;

await plPlayAndReply(interaction, playlistName, interaction.user.id);
},
autocomplete: UserPlaylistNamesAutocomplete
},
group: GroupAudio,
Expand All @@ -40,3 +63,64 @@ export default function (): ICommand {
]
};
}

async function plPlayAndReply(ctx: Message | ChatInputCommandInteraction, playlistName: string, userID: string) {
try {
if (queueSongsIsFull(ctx.client, ctx.guild as Guild)) {
await ctx.reply({
embeds: [
generateWarningEmbed(
i18next.t('commands:play_error_songs_limit', {
queueLimit: ENV.BOT_MAX_SONGS_IN_QUEUE
}) as string
)
],
ephemeral: true
});
return;
}

const userPlaylist = await UserPlaylistGet(userID, playlistName, true);

const songs: Array<Song> = await Promise.all(
userPlaylist.songs.map(async (userSong) => {
return (await ctx.client.audioPlayer.distube.handler.resolve(userSong.url)) as Song;
})
);

const member = ctx.member as GuildMember;

const DistubePlaylist = await ctx.client.audioPlayer.distube.createCustomPlaylist(songs, {
member,
name: playlistName
});

await ctx.client.audioPlayer.play(
member.voice.channel as VoiceChannel,
ctx.channel as TextChannel,
DistubePlaylist,
{
member,
textChannel: ctx.channel as TextChannel
}
);
} catch (e) {
if (e instanceof PlaylistIsNotExists) {
await ctx.reply({
embeds: [
generateErrorEmbed(
i18next.t('commands:pl_error_playlist_not_exists', {
name: playlistName,
interpolation: { escapeValue: false }
})
)
],
ephemeral: true
});
return;
}

await ctx.reply({ embeds: [generateErrorEmbed(i18next.t('commands:pl-add_error_unknown'))], ephemeral: true });
if (ENV.BOT_VERBOSE_LOGGING) loggerError(e);
}
}
83 changes: 27 additions & 56 deletions src/commands/audio/play.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { CommandArgument, ICommand } from '../../CommandTypes.js';
import {
ApplicationCommandOptionChoiceData,
AutocompleteInteraction,
ChatInputCommandInteraction,
Guild,
GuildMember,
Message,
PermissionsBitField,
SlashCommandBuilder,
TextChannel,
VoiceBasedChannel,
VoiceChannel
} from 'discord.js';
import { GroupAudio } from './AudioTypes.js';
Expand All @@ -32,28 +32,7 @@ export default function (): ICommand {
// In text command system we need to merge all words for request in one string
const songQuery = args.join(' ');

const member = message.member as GuildMember;
const channel = message.channel as TextChannel;

if (queueSongsIsFull(message.client, message.guild as Guild)) {
await message.reply({
embeds: [
generateWarningEmbed(
i18next.t('commands:play_error_songs_limit', {
queueLimit: ENV.BOT_MAX_SONGS_IN_QUEUE
}) as string
)
]
});
return;
}

await message.client.audioPlayer.play(member.voice.channel as VoiceBasedChannel, channel, songQuery, {
member: member,
textChannel: channel
});

await message.delete();
await playAndReply(message, songQuery);
}
},
slash_data: {
Expand All @@ -69,40 +48,9 @@ export default function (): ICommand {
),
autocomplete: songSearchAutocomplete,
execute: async (interaction) => {
if (queueSongsIsFull(interaction.client, interaction.guild as Guild)) {
await interaction.reply({
embeds: [
generateWarningEmbed(
i18next.t('commands:play_error_songs_limit', {
queueLimit: ENV.BOT_MAX_SONGS_IN_QUEUE
}) as string
)
],
ephemeral: true
});
return;
}

const songQuery = interaction.options.getString('request');
const songQuery = interaction.options.getString('request')!;

await interaction.reply({
content: i18next.t('general:thinking') as string
});
await interaction.deleteReply();

const member = interaction.member as GuildMember;

if (songQuery) {
await interaction.client.audioPlayer.play(
member.voice.channel as VoiceChannel,
interaction.channel as TextChannel,
songQuery,
{
member: interaction.member as GuildMember,
textChannel: interaction.channel as TextChannel
}
);
}
await playAndReply(interaction, songQuery);
}
},
group: GroupAudio,
Expand Down Expand Up @@ -148,3 +96,26 @@ export async function songSearchAutocomplete(interaction: AutocompleteInteractio

await interaction.respond([]);
}

async function playAndReply(ctx: Message | ChatInputCommandInteraction, songQuery: string) {
if (queueSongsIsFull(ctx.client, ctx.guild as Guild)) {
await ctx.reply({
embeds: [
generateWarningEmbed(
i18next.t('commands:play_error_songs_limit', {
queueLimit: ENV.BOT_MAX_SONGS_IN_QUEUE
}) as string
)
],
ephemeral: true
});
return;
}

const member = ctx.member as GuildMember;

await ctx.client.audioPlayer.play(member.voice.channel as VoiceChannel, ctx.channel as TextChannel, songQuery, {
member,
textChannel: ctx.channel as TextChannel
});
}
4 changes: 3 additions & 1 deletion src/locales/en/commands.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,7 @@
"pl-add_success": "The song ``{{song}}`` has been successfully added to the playlist ``{{playlist}}``",
"pl-remove_desc": "Removes a song from a playlist",
"pl-remove_success": "The song ``{{song}}`` has been successfully removed from the playlist ``{{playlist}}``",
"pl-remove_error_unknown": "Unknown error when deleting a song from a playlist"
"pl-remove_error_unknown": "Unknown error when deleting a song from a playlist",
"pl-play_desc": "Adds a custom playlist to the play queue",
"pl-play_error_unknown": "Unknown error while adding a playlist to the queue"
}
4 changes: 3 additions & 1 deletion src/locales/ru/commands.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,7 @@
"pl-add_success": "Песня ``{{song}}`` успешно добавлена в плейлист ``{{playlist}}``",
"pl-remove_desc": "Удаляет песню из плейлиста",
"pl-remove_success": "Песня ``{{song}}`` успешно удалена из плейлиста ``{{playlist}}``",
"pl-remove_error_unknown": "Неизвестная ошибка во время удаление песни из плейлиста"
"pl-remove_error_unknown": "Неизвестная ошибка во время удаление песни из плейлиста",
"pl-play_desc": "Добавляет пользовательский плейлист в очередь на воспроизведение",
"pl-play_error_unknown": "Неизвестная ошибка во время добавления плейлиста в очередь"
}
9 changes: 6 additions & 3 deletions src/schemas/SchemaPlaylist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,18 @@ export async function UserPlaylistGet(
userID: string,
name: string,
withSongs: boolean = false
): Promise<PlaylistModelClass | null | undefined> {
): Promise<PlaylistModelClass> {
const user = await getOrCreateUser(userID);
const userWithPlaylists = await user.populate({
path: 'playlists',
select: withSongs ? ['name', 'songs', 'createdAt'] : undefined
});

if (!userWithPlaylists.playlists) return null;
return userWithPlaylists.playlists.find((playlist) => playlist.name === name);
if (!userWithPlaylists.playlists) throw new PlaylistIsNotExists(name);

const playlist = userWithPlaylists.playlists.find((playlist) => playlist.name === name);
if (!playlist) throw new PlaylistIsNotExists(name);
return playlist;
}

export async function UserPlaylistGetPlaylists(userID: string): Promise<Array<PlaylistModelClass> | null> {
Expand Down
1 change: 1 addition & 0 deletions src/schemas/SchemaSongsHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export async function addSongToGuildSongsHistory(guildID: string, resource: Song

if (!history) return;

// Users' playlists cannot be added to history, because they don't have url
if (resource.name && resource.member?.id && resource.url) {
history.songsHistory.push({
name: resource.name ?? 'unknown',
Expand Down

0 comments on commit 6162056

Please sign in to comment.