Skip to content

Commit

Permalink
3.7.0-dev-6
Browse files Browse the repository at this point in the history
Refactored pagination.
Added pagination to /pl-display.
Added playlist name and songs count in /pl-display.
Added info about /pl-* commands to wiki.
  • Loading branch information
AlexInCube committed Aug 23, 2024
1 parent 6e6150a commit ed5ef9d
Show file tree
Hide file tree
Showing 17 changed files with 255 additions and 221 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "aicbot",
"version": "3.7.0-dev",
"version": "3.7.0",
"description": "Discord Bot for playing music",
"main": "build/main.js",
"scripts": {
Expand Down Expand Up @@ -61,7 +61,7 @@
"@typescript-eslint/eslint-plugin": "^8.0.1",
"@typescript-eslint/parser": "^8.0.1",
"@eslint/js": "^9.9.0",
"typescript-eslint": "7.18.0",
"typescript-eslint": "^8.2.0",
"eslint": "^9.9.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
Expand Down
210 changes: 104 additions & 106 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion src/CommandTypes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
AutocompleteInteraction,
ChatInputCommandInteraction,
CommandInteraction,
Message,
PermissionResolvable,
SlashCommandBuilder,
Expand Down Expand Up @@ -66,4 +67,5 @@ interface IGuildData {
voice_with_bot_only?: boolean; // Property enabled only if voice_required is true
}

export type ICommandContext = Message | ChatInputCommandInteraction;
export type InteractionReplyContext = ChatInputCommandInteraction | CommandInteraction;
export type ReplyContext = Message | InteractionReplyContext;
35 changes: 2 additions & 33 deletions src/audioplayer/AudioPlayersManager.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
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';
import { clamp } from '../utilities/clamp.js';
import { generateErrorEmbed } from '../utilities/generateErrorEmbed.js';
import i18next from 'i18next';
Expand All @@ -14,7 +12,6 @@ import {
ButtonInteraction,
Client,
CommandInteraction,
Embed,
EmbedBuilder,
Guild,
Interaction,
Expand All @@ -26,6 +23,7 @@ import { generateWarningEmbed } from '../utilities/generateWarningEmbed.js';
import { generateLyricsEmbed } from './Lyrics.js';
import { getGuildOptionLeaveOnEmpty, setGuildOptionLeaveOnEmpty } from '../schemas/SchemaGuild.js';
import { addSongToGuildSongsHistory } from '../schemas/SchemaSongsHistory.js';
import { PaginationList } from './PaginationList.js';

export const loggerPrefixAudioplayer = `Audioplayer`;

Expand Down Expand Up @@ -276,36 +274,7 @@ export class AudioPlayersManager {
arrayEmbeds.push(buildPage(queue, i, entriesPerPage));
}

await pagination({
embeds: arrayEmbeds as unknown as Embed[],
author: interaction.user,
interaction: interaction as CommandInteraction,
ephemeral: true,
fastSkip: true,
pageTravel: false,
buttons: [
{
type: ButtonTypes.first,
emoji: '⬅️',
style: ButtonStyles.Secondary
},
{
type: ButtonTypes.previous,
emoji: '◀️',
style: ButtonStyles.Secondary
},
{
type: ButtonTypes.next,
emoji: '▶️',
style: ButtonStyles.Secondary
},
{
type: ButtonTypes.last,
emoji: '➡️',
style: ButtonStyles.Secondary
}
]
});
await PaginationList(interaction as CommandInteraction, arrayEmbeds, interaction.user);
}

async setLeaveOnEmpty(guild: Guild, mode: boolean) {
Expand Down
38 changes: 38 additions & 0 deletions src/audioplayer/PaginationList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { pagination } from '../utilities/pagination/pagination.js';
import { Embed, EmbedBuilder, Message, User } from 'discord.js';
import { ButtonStyles, ButtonTypes } from '../utilities/pagination/paginationTypes.js';
import { ReplyContext } from '../CommandTypes.js';

export async function PaginationList(ctx: ReplyContext, pages: Array<Embed | EmbedBuilder>, user: User) {
await pagination({
embeds: pages as unknown as Array<Embed>,
author: user,
message: ctx instanceof Message ? ctx : undefined,
interaction: ctx instanceof Message ? undefined : ctx,
ephemeral: true,
fastSkip: true,
pageTravel: false,
buttons: [
{
type: ButtonTypes.first,
emoji: '⬅️',
style: ButtonStyles.Secondary
},
{
type: ButtonTypes.previous,
emoji: '◀️',
style: ButtonStyles.Secondary
},
{
type: ButtonTypes.next,
emoji: '▶️',
style: ButtonStyles.Secondary
},
{
type: ButtonTypes.last,
emoji: '➡️',
style: ButtonStyles.Secondary
}
]
});
}
59 changes: 8 additions & 51 deletions src/commands/audio/history.command.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
import { ICommand } from '../../CommandTypes.js';
import { ReplyContext, ICommand } from '../../CommandTypes.js';
import i18next from 'i18next';
import {
CommandInteraction,
Embed,
EmbedBuilder,
Guild,
Message,
PermissionsBitField,
SlashCommandBuilder
} from 'discord.js';
import { EmbedBuilder, Guild, PermissionsBitField, SlashCommandBuilder, User } from 'discord.js';
import { GroupAudio } from './AudioTypes.js';
import { getOrCreateGuildSongsHistory, ISchemaSongsHistory } from '../../schemas/SchemaSongsHistory.js';
import { pagination } from '../../utilities/pagination/pagination.js';
import { ButtonStyles, ButtonTypes } from '../../utilities/pagination/paginationTypes.js';
import { ENV } from '../../EnvironmentVariables.js';
import { PaginationList } from '../../audioplayer/PaginationList.js';

export default function (): ICommand {
return {
Expand All @@ -22,13 +13,13 @@ export default function (): ICommand {
name: 'history',
description: i18next.t('commands:history_desc'),
execute: async (message) => {
await replyWithSongHistory(message.guild as Guild, undefined, message);
await replyWithSongHistory(message.guild as Guild, message, message.author);
}
},
slash_data: {
slash_builder: new SlashCommandBuilder().setName('history').setDescription(i18next.t('commands:history_desc')),
execute: async (interaction) => {
await replyWithSongHistory(interaction.guild as Guild, interaction);
await replyWithSongHistory(interaction.guild as Guild, interaction, interaction.user);
}
},
guild_data: {
Expand All @@ -39,16 +30,13 @@ export default function (): ICommand {
};
}

async function replyWithSongHistory(guild: Guild, interaction?: CommandInteraction, message?: Message): Promise<void> {
async function replyWithSongHistory(guild: Guild, ctx: ReplyContext, user: User): Promise<void> {
const history: ISchemaSongsHistory | null = await getOrCreateGuildSongsHistory(guild.id);

if (!history) throw Error(`Can't find guild songs history: ${guild.id}`);

if (history.songsHistory.length === 0) {
await interaction?.reply({
embeds: [new EmbedBuilder().setTitle(i18next.t('commands:history_embed_no_songs'))]
});
await message?.reply({
await ctx.reply({
embeds: [new EmbedBuilder().setTitle(i18next.t('commands:history_embed_no_songs'))]
});
}
Expand Down Expand Up @@ -79,36 +67,5 @@ async function replyWithSongHistory(guild: Guild, interaction?: CommandInteracti
arrayEmbeds.push(buildPage(history, i, entriesPerPage));
}

await pagination({
embeds: arrayEmbeds as unknown as Embed[],
// @ts-expect-error I need to provide Interaction or Message for different command systems.
author: interaction?.user ?? message?.author,
message: message,
interaction: interaction,
ephemeral: true,
fastSkip: true,
pageTravel: false,
buttons: [
{
type: ButtonTypes.first,
emoji: '⬅️',
style: ButtonStyles.Secondary
},
{
type: ButtonTypes.previous,
emoji: '◀️',
style: ButtonStyles.Secondary
},
{
type: ButtonTypes.next,
emoji: '▶️',
style: ButtonStyles.Secondary
},
{
type: ButtonTypes.last,
emoji: '➡️',
style: ButtonStyles.Secondary
}
]
});
await PaginationList(ctx, arrayEmbeds, user);
}
4 changes: 2 additions & 2 deletions src/commands/audio/pl-add.command.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CommandArgument, ICommand, ICommandContext } from '../../CommandTypes.js';
import { CommandArgument, ICommand, ReplyContext } from '../../CommandTypes.js';
import { GroupAudio } from './AudioTypes.js';
import { Message, PermissionsBitField, SlashCommandBuilder, User } from 'discord.js';
import i18next from 'i18next';
Expand Down Expand Up @@ -60,7 +60,7 @@ export default function (): ICommand {
};
}

async function plAddAndReply(playlistName: string, url: string, ctx: ICommandContext, user: User) {
async function plAddAndReply(playlistName: string, url: string, ctx: ReplyContext, user: User) {
try {
if (!isValidURL(url)) {
await ctx.reply({
Expand Down
4 changes: 2 additions & 2 deletions src/commands/audio/pl-create.command.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CommandArgument, ICommand, ICommandContext } from '../../CommandTypes.js';
import { CommandArgument, ICommand, ReplyContext } from '../../CommandTypes.js';
import { GroupAudio } from './AudioTypes.js';
import { Message, PermissionsBitField, SlashCommandBuilder } from 'discord.js';
import i18next from 'i18next';
Expand Down Expand Up @@ -49,7 +49,7 @@ export default function (): ICommand {
};
}

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

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

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

Expand Down
48 changes: 37 additions & 11 deletions src/commands/audio/pl-display.command.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { CommandArgument, ICommand, ICommandContext } from '../../CommandTypes.js';
import { CommandArgument, ICommand, ReplyContext } from '../../CommandTypes.js';
import { GroupAudio } from './AudioTypes.js';
import { EmbedBuilder, Message, PermissionsBitField, SlashCommandBuilder, User } from 'discord.js';
import i18next from 'i18next';
import {
ISchemaPlaylist,
PlaylistNameMaxLength,
PlaylistNameMinLength,
UserPlaylistGet,
UserPlaylistNamesAutocomplete
} from '../../schemas/SchemaPlaylist.js';
import { generateErrorEmbed } from '../../utilities/generateErrorEmbed.js';
import { PaginationList } from '../../audioplayer/PaginationList.js';
import { getSongsNoun } from '../../audioplayer/util/getSongsNoun.js';

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

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

if (!playlist) {
Expand All @@ -60,19 +63,42 @@ async function plDisplayAndReply(playlistName: string, ctx: ICommandContext, use

const playlistEmbed = new EmbedBuilder().setAuthor({ name: user.displayName, iconURL: user.displayAvatarURL() });

let songs = ``;
function buildPage(playlist: ISchemaPlaylist, pageNumber: number, entriesPerPage: number) {
let songsList = '';

playlist.songs.forEach((song, index) => {
const songDate = song.createdAt ? `<t:${Math.round(song.createdAt.getTime() / 1000)}:f>` : '<t:0:f>';
const startingIndex = pageNumber * entriesPerPage;

songs += `${index + 1}. [${song.name}](${song.url}) - ${songDate} \n`;
});
for (let i = startingIndex; i < Math.min(startingIndex + entriesPerPage, playlist.songs.length); i++) {
const song = playlist.songs[i];

if (songs === '') {
const songDate = song.createdAt ? `<t:${Math.round(song.createdAt.getTime() / 1000)}:f>` : '<t:0:f>';

songsList += `${i + 1}. [${song.name}](${song.url}) - ${songDate} \n`;
}

return (
new EmbedBuilder()
.setAuthor({
name: `${user.displayName} - ${playlist.name} - ${playlist.songs.length} ${getSongsNoun(playlist.songs.length)}`,
iconURL: user.displayAvatarURL()
})
//.setTitle(`${i18next.t('commands:history_embed_title')} ${guild.name}`)
.setDescription(`${songsList}`.slice(0, 4096))
);
}

if (playlist.songsSize === 0) {
playlistEmbed.setDescription(i18next.t('commands:pl-display_embed_no_songs'));
await ctx.reply({ embeds: [playlistEmbed], ephemeral: true });
} else {
playlistEmbed.setDescription(songs);
}
const arrayEmbeds: Array<EmbedBuilder> = [];
const entriesPerPage = 20;
const pages = Math.ceil(playlist.songs.length / entriesPerPage);

for (let i = 0; i < pages; i++) {
arrayEmbeds.push(buildPage(playlist, i, entriesPerPage));
}

await ctx.reply({ embeds: [playlistEmbed], ephemeral: true });
await PaginationList(ctx, arrayEmbeds, user);
}
}
4 changes: 2 additions & 2 deletions src/commands/audio/pl-my.command.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ICommand, ICommandContext } from '../../CommandTypes.js';
import { ICommand, ReplyContext } from '../../CommandTypes.js';
import { GroupAudio } from './AudioTypes.js';
import { EmbedBuilder, Message, PermissionsBitField, SlashCommandBuilder } from 'discord.js';
import i18next from 'i18next';
Expand All @@ -25,7 +25,7 @@ export default function (): ICommand {
};
}

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

if (playlists && playlists.length > 0) {
Expand Down
4 changes: 2 additions & 2 deletions src/commands/audio/pl-play.command.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CommandArgument, ICommand, ICommandContext } from '../../CommandTypes.js';
import { CommandArgument, ICommand, ReplyContext } from '../../CommandTypes.js';
import { GroupAudio } from './AudioTypes.js';
import {
Guild,
Expand Down Expand Up @@ -64,7 +64,7 @@ export default function (): ICommand {
};
}

async function plPlayAndReply(ctx: ICommandContext, playlistName: string, userID: string) {
async function plPlayAndReply(ctx: ReplyContext, playlistName: string, userID: string) {
try {
if (queueSongsIsFull(ctx.client, ctx.guild as Guild)) {
await ctx.reply({
Expand Down
4 changes: 2 additions & 2 deletions src/commands/audio/pl-remove.command.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CommandArgument, ICommand, ICommandContext } from '../../CommandTypes.js';
import { CommandArgument, ICommand, ReplyContext } from '../../CommandTypes.js';
import { GroupAudio } from './AudioTypes.js';
import { Message, PermissionsBitField, SlashCommandBuilder } from 'discord.js';
import i18next from 'i18next';
Expand Down Expand Up @@ -58,7 +58,7 @@ export default function (): ICommand {
};
}

async function plRemoveAndReply(playlistName: string, songID: number, ctx: ICommandContext, userID: string) {
async function plRemoveAndReply(playlistName: string, songID: number, ctx: ReplyContext, userID: string) {
try {
const playlistSong = await UserPlaylistRemoveSong(userID, playlistName, Number(songID));

Expand Down
Loading

0 comments on commit ed5ef9d

Please sign in to comment.