Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6d4866e
feat: Integrate Spotify extractor and enhance player functionality wi…
Maaato Apr 11, 2025
ad53cc0
refactor: enhance logging for track player events
Maaato Apr 11, 2025
713e8ea
refactor: replace player.types.ts with player.service.types.ts for im…
Maaato Apr 11, 2025
389bd5f
refactor: streamline player provider methods and enhance related trac…
Maaato Apr 15, 2025
69fea4c
feat: Add Spotify configuration and integrate client credentials into…
Maaato Apr 15, 2025
c65a700
feat: Implement link validation for music search and enhance error ha…
Maaato Apr 15, 2025
d78c00d
refactor: Remove unused QueueEmbedProps type and update getQueuedEmbe…
Maaato Apr 15, 2025
4cad32f
refactor: Simplify SpotifyExtractor registration by removing unused c…
Maaato Apr 15, 2025
d5af6b0
test: Enhance PlayerProvider and PlayerService tests with additional …
Maaato Apr 16, 2025
999f2c1
style: Add comment to ignore formatting for prettier in getRelatedTracks
Maaato Apr 16, 2025
5b74d5d
feat: Add Deezer and Spotify credentials to deployment gh action work…
Maaato Apr 16, 2025
201772f
refactor: Update SpotifyExtractor registration to include client cred…
Maaato Apr 16, 2025
418ab04
refactor: Enhance customAutoPlay track handling by removing duplicate…
Maaato Apr 16, 2025
511df5c
refactor: Update handlePlayerFinish to always update finished track c…
Maaato Apr 16, 2025
8f6400e
chore: Update .gitignore to include .cursor and .vscode directories
Maaato Apr 18, 2025
1604676
refactor: Revamp embed utility functions to improve structure and rea…
Maaato Apr 18, 2025
e65be71
feat: Add cache deletion for now playing message in handlePlayerFinish
Maaato Apr 19, 2025
e9ae68f
feat: Add DEBUG_MODE to configuration and update PlayerProvider to ut…
Maaato Apr 21, 2025
e7a0537
feat: Add DEBUG_MODE environment variable to deployment workflow
Maaato Apr 22, 2025
4a95a7f
refactor: Update PlayerProvider to improve event handling and cache m…
Maaato Apr 22, 2025
ce62433
refactor: Update ttl cache management for last now playing message
Maaato Apr 22, 2025
52bb01f
refactor: Simplify SpotifyExtractor registration by removing client c…
Maaato Apr 24, 2025
e71d28a
refactor: Add numeric check for DEBUG_MODE in event handling
Maaato Apr 24, 2025
54b9655
refactor: Enhance track description in embed utility to include track…
Maaato Apr 25, 2025
abf6c69
refactor: Consolidate embed options and improve readability
Maaato Apr 25, 2025
54cb044
feat: Enhance customAutoPlay embeds handling
Maaato Apr 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .env.sample
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# [ENV] Application
NODE_PORT
NODE_ENV
DEBUG_MODE
# [ENV] Discord App
DISCORD_APP_LOGIN_TOKEN
# [ENV] Discord Bot
Expand All @@ -9,4 +10,10 @@ DISCORD_BOT_LOGIN_TOKEN
# [ENV] AWS
AWS_ALEXA_SKILL_ID
# [ENV] MongoDB
MONGODB_URI
MONGODB_URI
# [ENV] Deezer
DEEZER_DECRYPTION_KEY
DEEZER_ARL
# [ENV] Spotify
SPOTIFY_CLIENT_ID
SPOTIFY_CLIENT_SECRET
5 changes: 5 additions & 0 deletions .github/workflows/deploy-to-oci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,17 @@ jobs:
echo "DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }}" >> $workdir/.env
echo "NODE_ENV=${{ secrets.NODE_ENV }}" >> $workdir/.env
echo "NODE_PORT=${{ secrets.NODE_PORT }}" >> $workdir/.env
echo "DEBUG_MODE=${{ secrets.DEBUG_MODE }}" >> $workdir/.env
echo "DISCORD_APP_LOGIN_TOKEN=${{ secrets.DISCORD_APP_LOGIN_TOKEN }}" >> $workdir/.env
echo "DISCORD_BOT_LOGIN_TOKEN=${{ secrets.DISCORD_BOT_LOGIN_TOKEN }}" >> $workdir/.env
echo "DISCORD_BOT_OWNER_USER_ID=${{ secrets.DISCORD_BOT_OWNER_USER_ID }}" >> $workdir/.env
echo "DISCORD_BOT_PREFIX=°" >> $workdir/.env
echo "AWS_ALEXA_SKILL_ID=${{ secrets.AWS_ALEXA_SKILL_ID }}" >> $workdir/.env
echo "MONGODB_URI=${{ secrets.MONGODB_URI }}" >> $workdir/.env
echo "DEEZER_DECRYPTION_KEY=${{ secrets.DEEZER_DECRYPTION_KEY }}" >> $workdir/.env
echo "DEEZER_ARL=${{ secrets.DEEZER_ARL }}" >> $workdir/.env
echo "SPOTIFY_CLIENT_ID=${{ secrets.SPOTIFY_CLIENT_ID }}" >> $workdir/.env
echo "SPOTIFY_CLIENT_SECRET=${{ secrets.SPOTIFY_CLIENT_SECRET }}" >> $workdir/.env
existing_container=$(docker ps -q -f name=$container_name)
if [ ! -z "$existing_container" ]; then
echo "Stopping and removing the existing $container_name..."
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

# Enviroments
.env
.env.*

# npm
package-lock.json
Expand Down Expand Up @@ -35,6 +36,8 @@ lerna-debug.log*
*.launch
.settings/
*.sublime-workspace
.cursor
.vscode

# IDE - VSCode
.vscode/*
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "amzbot",
"version": "2.1.0",
"version": "2.2.5",
"description": "",
"author": "",
"private": true,
Expand All @@ -9,7 +9,7 @@
"build": "nest build",
"start": "nest start",
"start:dev": "set NODE_OPTIONS=--openssl-legacy-provider && nest start --watch",
"start:debug": "nest start --debug --watch",
"start:debug": "set NODE_OPTIONS=--openssl-legacy-provider && nest start --debug --watch",
"start:prod": "node --openssl-legacy-provider dist/main",
"test": "jest --runInBand",
"test:watch": "jest --watch --coverage --runInBand",
Expand Down Expand Up @@ -40,6 +40,7 @@
"cache-manager": "5.7.6",
"discord-player": "7.1.0",
"discord-player-deezer": "2.5.0",
"discord-player-spotify": "1.1.2",
"discord-player-youtubei": "1.4.3",
"discord.js": "14.18.0",
"mongoose": "^8.7.3",
Expand Down
5 changes: 2 additions & 3 deletions src/bot/bot.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { InjectDiscordClient, InteractionEvent, On, Once } from '@discord-nestjs
import { Injectable, Logger } from '@nestjs/common';
import { IMemberVoiceState } from '@shared/interfaces/memberVoiceState.interface';
import { ActivityType, ButtonInteraction, Client, MessageFlags, VoiceState } from 'discord.js';
import { VALIDATOR_MESSAGES } from './constants/messages.constant';
import { FRIENDLY_ERROR_MESSAGES } from './constants/messages.constant';
import { getNowPlayingButtons } from './utils/player.utils';

@Injectable()
Expand Down Expand Up @@ -61,7 +61,6 @@ export class BotGateway {
}
case PlayerButtonActionId.SKIP: {
await channel.sendTyping();
await this.disableButtonInteraction(interaction);
this._playerService.skip({ guildId });
await interaction.deferUpdate();
return;
Expand All @@ -77,7 +76,7 @@ export class BotGateway {

private async handleInvalidButtonInteraction(interaction: ButtonInteraction): Promise<void> {
await this.disableButtonInteraction(interaction);
await interaction.reply({ content: VALIDATOR_MESSAGES.NO_ACTIVE_QUEUE, flags: MessageFlags.Ephemeral });
await interaction.reply({ content: FRIENDLY_ERROR_MESSAGES.NO_ACTIVE_QUEUE, flags: MessageFlags.Ephemeral });
}

private async initPresence(): Promise<void> {
Expand Down
4 changes: 2 additions & 2 deletions src/bot/commands/misc/help.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Prefixcommand } from '@bot/decorators/prefix-command.decorator';
import { CommandValidationType } from '@bot/enums/command-validation.enum';
import { MessageFromUserGuard } from '@bot/guards/message-from-user.guard';
import { CommandService } from '@bot/services/command/command.service';
import { getDescriptionEmbed } from '@bot/utils/embed.utils';
import { createInfoEmbed } from '@bot/utils/embed.utils';
import { PrefixCommandInterceptor } from '@discord-nestjs/common';
import { On } from '@discord-nestjs/core';
import { Injectable, Logger, UseGuards, UseInterceptors } from '@nestjs/common';
Expand Down Expand Up @@ -39,7 +39,7 @@ export class HelpCommand extends BaseCommand {
const embed = this.createHelpEmbed(message.guild, commands);
await message.reply({ embeds: [embed] });
} catch (error) {
await message.reply({ embeds: [getDescriptionEmbed({ description: FRIENDLY_ERROR_MESSAGES.UNEXPECTED_ERROR })] });
await message.reply({ embeds: [createInfoEmbed(FRIENDLY_ERROR_MESSAGES.UNEXPECTED_ERROR)] });
this.logger.error(`[onMessageCreate] Error: ${error.message}`);
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/bot/commands/music/clear.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { CommandValidationType } from '@bot/enums/command-validation.enum';
import { GuildQueueGuard } from '@bot/guards/guild-queue.guard';
import { MessageFromUserGuard } from '@bot/guards/message-from-user.guard';
import { PlayerService } from '@bot/services/player/player.service';
import { getDescriptionEmbed } from '@bot/utils/embed.utils';
import { createInfoEmbed } from '@bot/utils/embed.utils';
import { PrefixCommandInterceptor } from '@discord-nestjs/common';
import { MessageEvent, On } from '@discord-nestjs/core';
import { Injectable, Logger, UseGuards, UseInterceptors } from '@nestjs/common';
Expand Down Expand Up @@ -37,9 +37,9 @@ export class ClearCommand extends BaseCommand {
try {
await message.channel.sendTyping();
this._playerService.clear({ guildId });
await message.reply({ embeds: [getDescriptionEmbed({ description: FRIENDLY_OK_MESSAGES.QUEUE_CLEARED })] });
await message.reply({ embeds: [createInfoEmbed(FRIENDLY_OK_MESSAGES.QUEUE_CLEARED)] });
} catch (error) {
await message.reply({ embeds: [getDescriptionEmbed({ description: FRIENDLY_ERROR_MESSAGES.UNEXPECTED_ERROR })] });
await message.reply({ embeds: [createInfoEmbed(FRIENDLY_ERROR_MESSAGES.UNEXPECTED_ERROR)] });
this.logger.error(`[onMessageCreate] Error: ${error.message}`);
}
}
Expand Down
25 changes: 19 additions & 6 deletions src/bot/commands/music/play.command.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FRIENDLY_ERROR_MESSAGES, VALIDATOR_MESSAGES } from '@bot/constants/messages.constant';
import { FRIENDLY_ERROR_MESSAGES } from '@bot/constants/messages.constant';
import { RequireValidation } from '@bot/decorators/command-validation.decorator';
import { Prefixcommand } from '@bot/decorators/prefix-command.decorator';
import { CommandValidationType } from '@bot/enums/command-validation.enum';
Expand All @@ -10,10 +10,12 @@ import {
getMemberVoiceChannel,
getTextchannelFromCache,
} from '@bot/utils/discord.utils';
import { getDescriptionEmbed } from '@bot/utils/embed.utils';
import { createErrorEmbed, createWarningEmbed } from '@bot/utils/embed.utils';
import { isAllowedLinkSearch } from '@bot/utils/player.utils';
import { PrefixCommandInterceptor } from '@discord-nestjs/common';
import { InjectDiscordClient, MessageEvent, On } from '@discord-nestjs/core';
import { Injectable, Logger, UseGuards, UseInterceptors } from '@nestjs/common';
import { HTTP_PREFIX } from '@shared/constants/misc.constants';
import { BaseCommand } from '@shared/interfaces/command.interface';
import { Client, Message } from 'discord.js';

Expand Down Expand Up @@ -41,6 +43,8 @@ export class PlayCommand extends BaseCommand {
@UseGuards(MessageFromUserGuard)
@UseInterceptors(new PrefixCommandInterceptor('play'))
async onMessageCreate(@MessageEvent() message: Message<true>): Promise<void> {
this.logger.log(`[onMessageCreate] Searching for '${message.content}'`);
const query = message.content.trim();
try {
await message.channel.sendTyping();
const { guildId, author: requester, channelId } = message;
Expand All @@ -49,19 +53,28 @@ export class PlayCommand extends BaseCommand {
const textChannel = getTextchannelFromCache(guild, channelId);
const voiceChannel = getMemberVoiceChannel(member);
if (!voiceChannel) {
await message.reply({ embeds: [getDescriptionEmbed({ description: VALIDATOR_MESSAGES.NOT_IN_VOICE_CHANNEL })] }); // biome-ignore format: prettier
await message.reply({ embeds: [createErrorEmbed(FRIENDLY_ERROR_MESSAGES.NOT_IN_VOICE_CHANNEL)] });
return;
}

const { isEmpty, tracks, isPlaylist } = await this._playerService.search({ query: message.content, requester }); // biome-ignore format: prettier
if (query.toLocaleLowerCase().startsWith(HTTP_PREFIX)) {
const { isValid, host } = isAllowedLinkSearch(query);
if (!isValid) {
this.logger.error(`[onMessageCreate] Invalid URL: ${query}`);
await message.reply({ embeds: [createErrorEmbed(FRIENDLY_ERROR_MESSAGES[`${host}_LINK_NOT_SUPPORTED_YET`])] }); // biome-ignore format: prettier
return;
}
}

const { isEmpty, tracks, isPlaylist } = await this._playerService.search({ query, requester }); // biome-ignore format: prettier
if (isEmpty) {
await message.reply({ embeds: [getDescriptionEmbed({ description: FRIENDLY_ERROR_MESSAGES.NO_TRACKS_FOUND })] }); // biome-ignore format: prettier
await message.reply({ embeds: [createWarningEmbed(FRIENDLY_ERROR_MESSAGES.NO_TRACKS_FOUND)] }); // biome-ignore format: prettier
return;
}

await this._playerService.play({ tracks, isPlaylist, requester, textChannel, voiceChannel }); // biome-ignore format: prettier
} catch (error) {
await message.reply({ embeds: [getDescriptionEmbed({ description: FRIENDLY_ERROR_MESSAGES.UNEXPECTED_ERROR })] });
await message.reply({ embeds: [createErrorEmbed(FRIENDLY_ERROR_MESSAGES.UNEXPECTED_ERROR)] });
this.logger.error(`[onMessageCreate] Error: ${error.message}`);
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/bot/commands/music/shuffle.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { CommandValidationType } from '@bot/enums/command-validation.enum';
import { GuildQueueGuard } from '@bot/guards/guild-queue.guard';
import { MessageFromUserGuard } from '@bot/guards/message-from-user.guard';
import { PlayerService } from '@bot/services/player/player.service';
import { getDescriptionEmbed } from '@bot/utils/embed.utils';
import { createInfoEmbed } from '@bot/utils/embed.utils';
import { PrefixCommandInterceptor } from '@discord-nestjs/common';
import { On } from '@discord-nestjs/core';
import { Injectable, Logger, UseGuards, UseInterceptors } from '@nestjs/common';
Expand Down Expand Up @@ -37,10 +37,10 @@ export class ShuffleCommand extends BaseCommand {
try {
await message.channel.sendTyping();
const { isEnabled } = this._playerService.shuffle({ guildId });
const description = isEnabled ? FRIENDLY_OK_MESSAGES.QUEUE_SHUFFLED : FRIENDLY_OK_MESSAGES.QUEUE_UNSHUFFLED;
await message.reply({ embeds: [getDescriptionEmbed({ description })] });
const embedDescription = isEnabled ? FRIENDLY_OK_MESSAGES.QUEUE_SHUFFLED : FRIENDLY_OK_MESSAGES.QUEUE_UNSHUFFLED;
await message.reply({ embeds: [createInfoEmbed(embedDescription)] });
} catch (error) {
await message.reply({ embeds: [getDescriptionEmbed({ description: FRIENDLY_ERROR_MESSAGES.UNEXPECTED_ERROR })] });
await message.reply({ embeds: [createInfoEmbed(FRIENDLY_ERROR_MESSAGES.UNEXPECTED_ERROR)] });
this.logger.error(`[onMessageCreate] Error: ${error.message}`);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/bot/commands/music/skip.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { CommandValidationType } from '@bot/enums/command-validation.enum';
import { GuildQueueGuard } from '@bot/guards/guild-queue.guard';
import { MessageFromUserGuard } from '@bot/guards/message-from-user.guard';
import { PlayerService } from '@bot/services/player/player.service';
import { getDescriptionEmbed } from '@bot/utils/embed.utils';
import { createInfoEmbed } from '@bot/utils/embed.utils';
import { PrefixCommandInterceptor } from '@discord-nestjs/common';
import { On } from '@discord-nestjs/core';
import { Injectable, Logger, UseGuards, UseInterceptors } from '@nestjs/common';
Expand Down Expand Up @@ -38,7 +38,7 @@ export class SkipCommand extends BaseCommand {
await message.channel.sendTyping();
this._playerService.skip({ guildId });
} catch (error) {
await message.reply({ embeds: [getDescriptionEmbed({ description: FRIENDLY_ERROR_MESSAGES.UNEXPECTED_ERROR })] });
await message.reply({ embeds: [createInfoEmbed(FRIENDLY_ERROR_MESSAGES.UNEXPECTED_ERROR)] });
this.logger.error(`[onMessageCreate] Error: ${error.message}`);
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/bot/constants/embeds-props.constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,10 @@ export const USAGE_FIELD_NAME = 'Usage:';

/* Misc */
export const EMPTY_SPACE = '\u200B';

export const EMBED_COLORS = {
PRIMARY: 0xf9e30b,
ERROR: 0xff4c4c,
INFO: 0x00b0f4,
WARNING: 0xffa500,
} as const;
10 changes: 7 additions & 3 deletions src/bot/constants/messages.constant.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
export const FRIENDLY_ERROR_MESSAGES = {
NO_TRACKS_FOUND: 'Oops! I could not find any tracks!',
UNEXPECTED_ERROR: 'Oops! a unexpected error occurred!',
} as const;

export const VALIDATOR_MESSAGES = {
NO_RELATED_TRACKS_FOUND: 'Oops! I could not find any related tracks, try adding a new track to the queue!',
NOT_IN_VOICE_CHANNEL: 'Oops! connect to a voice channel first!',
NO_ACTIVE_QUEUE: 'Oops! there is no active queue!',
UNKNOWN_LINK_NOT_SUPPORTED_YET: 'Oops! this provider is not supported for now!',
SPOTIFY_LINK_NOT_SUPPORTED_YET: 'Oops! Spotify links are not supported for now!',
DEEZER_LINK_NOT_SUPPORTED_YET: 'Oops! Deezer links are not supported for now!',
YOUTUBE_LINK_NOT_SUPPORTED_YET: 'Oops! Youtube links are not supported for now!',
} as const;

export const FRIENDLY_OK_MESSAGES = {
QUEUE_CLEARED: 'The queue has been cleared!',
QUEUE_SHUFFLED: 'The queue has been shuffled!',
QUEUE_UNSHUFFLED: 'shuffled has been removed!',
FETCHING_RELATED_TRACKS: 'Oops! Queue is empty, fetching related tracks...',
RELATED_TRACKS_FETCHED: (count: number) => `${count} related tracks fetched! Adding to queue...`,
} as const;
2 changes: 1 addition & 1 deletion src/bot/constants/player.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const PLAYER_INIT_OPTIONS: PlayerInitOptions = {

export const DEFAULT_PLAYER_OPTIONS: GuildNodeCreateOptions = {
volume: 80,
repeatMode: QueueRepeatMode.AUTOPLAY,
repeatMode: QueueRepeatMode.OFF,
noEmitInsert: true,
leaveOnStop: false,
leaveOnEnd: false,
Expand Down
6 changes: 3 additions & 3 deletions src/bot/guards/guild-queue.guard.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { VALIDATOR_MESSAGES } from '@bot/constants/messages.constant';
import { FRIENDLY_ERROR_MESSAGES } from '@bot/constants/messages.constant';
import { COMMAND_VALIDATION_KEY } from '@bot/decorators/command-validation.decorator';
import { CommandValidationType } from '@bot/enums/command-validation.enum';
import { BaseCommandGuard } from '@bot/guards/base-command.guard';
import { PlayerService } from '@bot/services/player/player.service';
import { getDescriptionEmbed } from '@bot/utils/embed.utils';
import { createInfoEmbed } from '@bot/utils/embed.utils';
import { ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';

Expand All @@ -24,7 +24,7 @@ export class GuildQueueGuard extends BaseCommandGuard {
const queue = this._playerService.getGuildQueue(message.guildId);

if (queue) return true;
await message.reply({ embeds: [getDescriptionEmbed({ description: VALIDATOR_MESSAGES.NO_ACTIVE_QUEUE })] });
await message.reply({ embeds: [createInfoEmbed(FRIENDLY_ERROR_MESSAGES.NO_ACTIVE_QUEUE)] });
return false;
}
}
24 changes: 24 additions & 0 deletions src/bot/providers/player/player.provider.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { PlayerProvider } from '@bot/providers/player/player.provider';
import { PlayerService } from '@bot/services/player/player.service';
import { createPlayerServiceMock } from '@bot/services/player/player.service.mocks';
import { ConfigService } from '@config/config.service';
import { createConfigServiceMock } from '@config/config.service.mocks';
import { INJECT_DISCORD_CLIENT } from '@discord-nestjs/core';
Expand All @@ -7,8 +9,29 @@ import { CacheManagerService } from '@services/cache-manager/cache-manager.servi
import { createCacheManagerServiceMock } from '@services/cache-manager/cache-manager.service.mocks';
import { createDiscordClientMock } from '@shared/mocks/discord-client.mocks';

jest.mock('discord.js', () => ({
...jest.createMockFromModule<any>('discord.js'),
User: jest.fn().mockImplementation(() => ({
id: '123456789',
username: 'mockUser',
discriminator: '0000',
bot: false,
system: false,
})),
}));

jest.mock('discord-player', () => ({
...jest.createMockFromModule<any>('discord-player'),
GuildQueue: jest.fn().mockImplementation(() => ({
clear: jest.fn(),
toggleShuffle: jest.fn(),
addTrack: jest.fn(),
node: {
setPaused: jest.fn(),
isPaused: jest.fn(),
skip: jest.fn(),
},
})),
}));

describe('PlayerProvider', () => {
Expand All @@ -21,6 +44,7 @@ describe('PlayerProvider', () => {
{ provide: INJECT_DISCORD_CLIENT, useValue: createDiscordClientMock() },
{ provide: CacheManagerService, useValue: createCacheManagerServiceMock() },
{ provide: ConfigService, useValue: createConfigServiceMock() },
{ provide: PlayerService, useValue: createPlayerServiceMock() },
],
}).compile();

Expand Down
Loading