diff --git a/.eslintrc.json b/.eslintrc.json index c2218ab..3fd4e62 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -6,17 +6,7 @@ "es6": true, "node": true }, - "overrides": [ - // { - // "files": [ - // "tests/*" - // ], - // "env": { - // "jest": true, - // "jest/globals": true - // } - // } - ], + "overrides": [], "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended" @@ -109,7 +99,13 @@ "warn", 4, { - "SwitchCase": 1 + "SwitchCase": 1, + "VariableDeclarator": "first", + "FunctionDeclaration": {"parameters": "first"}, + "CallExpression": {"arguments": "first"}, + "ArrayExpression": "first", + "ObjectExpression": "first", + "ImportDeclaration": "first" } ], "init-declarations": "warn", @@ -118,14 +114,15 @@ "single" ], "jsx-quotes": [ - "warn", + "error", "prefer-single" ], "key-spacing": [ "warn", { "beforeColon": false, - "afterColon": true + "afterColon": true, + "align": "value" } ], "keyword-spacing": [ @@ -164,7 +161,6 @@ "new-parens": "warn", "no-alert": "warn", "no-array-constructor": "warn", - // "no-bitwise": "warn", "no-buffer-constructor": "warn", "no-caller": "warn", "no-console": "warn", @@ -192,7 +188,7 @@ "no-loop-func": "warn", "no-mixed-requires": "warn", "no-multi-assign": "warn", - "no-multi-spaces": "warn", + "no-multi-spaces": ["warn", {"ignoreEOLComments": true, "exceptions": {"ImportDeclaration": true}}], "no-multi-str": "warn", "no-multiple-empty-lines": "warn", "no-native-reassign": "warn", @@ -224,7 +220,7 @@ "no-setter-return": "warn", "no-spaced-func": "warn", "@typescript-eslint/no-shadow": "error", - "no-tabs": "warn", + "no-tabs": "error", "no-template-curly-in-string": "error", "no-throw-literal": "warn", "no-trailing-spaces": "warn", @@ -241,7 +237,6 @@ "no-useless-rename": "warn", "no-useless-return": "warn", "no-var": "warn", - // "no-void": "warn", "no-whitespace-before-property": "error", "nonblock-statement-body-position": [ "warn", diff --git a/src/client/components/MusicLibrary.ts b/src/client/components/MusicLibrary.ts index 09bf968..4242b22 100644 --- a/src/client/components/MusicLibrary.ts +++ b/src/client/components/MusicLibrary.ts @@ -16,7 +16,7 @@ import { inspect } from 'node:util'; const linkReg = /(https?:\/\/(www\.)?)?(?([a-z0-9-]{1,63}\.)?([a-z0-9-]{1,63})(\.[a-z0-9-]{2,63})(\.[a-z0-9-]{2,63})?)(\/[^()\s]*)?/iu; const defaultStats: MusicStatsEntry = { - name: '', + name: '', plays: 0, skips: 0 }; @@ -267,14 +267,14 @@ class MusicLibrary implements Initialisable const title = segmets[segmets.length - 1].replace((/\..+$/u), ''); const entry = { - id: this.#currentId++, + id: this.#currentId++, artist: common.artist ?? artist, - title: common.title ?? title, - album: common.album, - year: common.year, - genre: common.genre ?? [], - file: fp, - stats: { + title: common.title ?? title, + album: common.album, + year: common.year, + genre: common.genre ?? [], + file: fp, + stats: { plays: 0, skips: 0 } diff --git a/src/client/components/MusicPlayer.ts b/src/client/components/MusicPlayer.ts index f4491d7..cc6d08d 100644 --- a/src/client/components/MusicPlayer.ts +++ b/src/client/components/MusicPlayer.ts @@ -98,7 +98,7 @@ class MusicPlayer implements Initialisable const config = { volume: this.#volume, - queue: this.#queue + queue: this.#queue }; fs.writeFileSync(cachePath, JSON.stringify(config)); } @@ -149,7 +149,7 @@ class MusicPlayer implements Initialisable this.#currentSong = info; this.#currentResource = createAudioResource(info.file, { inlineVolume: true, - metadata: { + metadata: { title: info.title } }); @@ -183,9 +183,9 @@ class MusicPlayer implements Initialisable return; const payload = { embeds: [{ - title: 'Now playing :notes:', + title: 'Now playing :notes:', description: `**${info.title}** by ${info.artist}`, - color: 0xffafff + color: 0xffafff }] }; const messages = await channel.messages.fetch({ limit: 100 }); @@ -236,8 +236,8 @@ class MusicPlayer implements Initialisable } const connection = joinVoiceChannel({ - channelId: channel.id, - guildId: guild.id, + channelId: channel.id, + guildId: guild.id, adapterCreator: guild.voiceAdapterCreator }); connection.removeAllListeners(); diff --git a/src/client/components/SpotifyAPI.ts b/src/client/components/SpotifyAPI.ts index 68f32c6..ec7bac6 100644 --- a/src/client/components/SpotifyAPI.ts +++ b/src/client/components/SpotifyAPI.ts @@ -33,10 +33,10 @@ class SpotifyAPI const response = await fetch( 'https://accounts.spotify.com/api/token', { - method: 'POST', + method: 'POST', headers: { 'Authorization': `Basic ${Buffer.from(`${this.#id}:${this.#secret}`).toString('base64')}`, - 'Content-Type': 'application/x-www-form-urlencoded' + 'Content-Type': 'application/x-www-form-urlencoded' }, body: `${encodeURI('grant_type')}=${encodeURI('client_credentials')}` } @@ -55,7 +55,10 @@ class SpotifyAPI this.#token = token; this.#tokenType = type; - setTimeout(this.login.bind(this), expires * 1000); + setTimeout(() => + { + this.#ready = false; + }, expires * 1000); this.#ready = true; } @@ -70,10 +73,10 @@ class SpotifyAPI const { album, artists, name } = data as { album: { name: string }, artists: { name: string, genres: string[] }[], name: string }; const [ artist ] = artists; return { - album: album.name, + album: album.name, artist: artist.name, genres: artist.genres, - title: name + title: name }; } diff --git a/src/client/components/commands/List.ts b/src/client/components/commands/List.ts index ccd574d..74cdb0b 100644 --- a/src/client/components/commands/List.ts +++ b/src/client/components/commands/List.ts @@ -8,17 +8,17 @@ class ListCommand extends Command constructor (client: DiscordClient) { super(client, { - name: 'list', + name: 'list', description: 'Display a list of things on the bot.', - options: [{ - name: 'commands', - type: OptionType.SUB_COMMAND, + options: [{ + name: 'commands', + type: OptionType.SUB_COMMAND, options: [{ - name: 'all', - type: OptionType.BOOLEAN, + name: 'all', + type: OptionType.BOOLEAN, valueOptional: true, - defaultValue: true, - flag: true + defaultValue: true, + flag: true }] }] }); diff --git a/src/client/components/commands/Ping.ts b/src/client/components/commands/Ping.ts index c4e19a8..48683e7 100644 --- a/src/client/components/commands/Ping.ts +++ b/src/client/components/commands/Ping.ts @@ -6,7 +6,7 @@ class PingCommand extends Command constructor (client: DiscordClient) { super(client, { - name: 'ping', + name: 'ping', description: 'pong' }); } diff --git a/src/client/components/commands/Queue.ts b/src/client/components/commands/Queue.ts index d5884a2..1aba1dc 100644 --- a/src/client/components/commands/Queue.ts +++ b/src/client/components/commands/Queue.ts @@ -8,10 +8,10 @@ class QueueCommand extends Command constructor (client: DiscordClient) { super(client, { - name: 'queue', - aliases: [ 'q' ], + name: 'queue', + aliases: [ 'q' ], description: 'Queue a song (must be already downloaded, use search to look up songs), or display the current queue.', - options: [{ + options: [{ name: 'artist', flag: true }, { @@ -45,9 +45,9 @@ class QueueCommand extends Command const [ artist ]= map.get('artist') ?? []; const [ id ]= map.get('id') ?? []; const query = { - title: song?.value as string | undefined, + title: song?.value as string | undefined, artist: artist?.value as string | undefined, - id: id?.value as number | undefined + id: id?.value as number | undefined }; const result = this.client.musicPlayer.queueSong(query); diff --git a/src/client/components/commands/Request.ts b/src/client/components/commands/Request.ts index 400a9cf..c9760a0 100644 --- a/src/client/components/commands/Request.ts +++ b/src/client/components/commands/Request.ts @@ -10,14 +10,14 @@ class RequestCommand extends Command constructor (client: DiscordClient) { super(client, { - name: 'request', - aliases: [ 'r', 'req' ], + name: 'request', + aliases: [ 'r', 'req' ], description: 'Request a song to be downloaded and queued.', - guildOnly: true, - sameVc: true, - showUsage: true, - options: [{ - name: 'link', + guildOnly: true, + sameVc: true, + showUsage: true, + options: [{ + name: 'link', required: true }] }); diff --git a/src/client/components/commands/Rescan.ts b/src/client/components/commands/Rescan.ts index 130444c..c54c2bb 100644 --- a/src/client/components/commands/Rescan.ts +++ b/src/client/components/commands/Rescan.ts @@ -8,15 +8,15 @@ class PingCommand extends Command constructor (client: DiscordClient) { super(client, { - name: 'rescan', - restricted: true, + name: 'rescan', + restricted: true, description: 'Rescan the library and add to index.', - options: [{ - name: 'rebuild', - type: OptionType.BOOLEAN, - flag: true, + options: [{ + name: 'rebuild', + type: OptionType.BOOLEAN, + flag: true, valueOptional: true, - defaultValue: true + defaultValue: true }] }); } diff --git a/src/client/components/commands/Reshuffle.ts b/src/client/components/commands/Reshuffle.ts index 41d500e..44893fe 100644 --- a/src/client/components/commands/Reshuffle.ts +++ b/src/client/components/commands/Reshuffle.ts @@ -6,10 +6,10 @@ class ReshuffleCommand extends Command constructor (client: DiscordClient) { super(client, { - name: 'reshuffle', + name: 'reshuffle', description: 'Reshuffles the playlist (does not apply to queue).', - sameVc: true, - guildOnly: true, + sameVc: true, + guildOnly: true, }); } diff --git a/src/client/components/commands/Search.ts b/src/client/components/commands/Search.ts index 6b5311a..7ef9e44 100644 --- a/src/client/components/commands/Search.ts +++ b/src/client/components/commands/Search.ts @@ -8,11 +8,11 @@ class SearchCommand extends Command constructor (client: DiscordClient) { super(client, { - name: 'search', - aliases: [ 's', 'query' ], + name: 'search', + aliases: [ 's', 'query' ], description: 'Search the index for an already downloaded song.', - showUsage: true, - options: [{ + showUsage: true, + options: [{ name: 'keyword', }, { name: 'artist', @@ -30,8 +30,8 @@ class SearchCommand extends Command const [ artist ] = map.get('artist') ?? []; const [ keyword ] = map.get('keyword') ?? []; const query = { - title: song?.value as string | undefined, - artist: artist?.value as string | undefined, + title: song?.value as string | undefined, + artist: artist?.value as string | undefined, keyword: keyword?.value as string | undefined }; const results = this.client.musicPlayer.library.search(query); diff --git a/src/client/components/commands/SetAvatar.ts b/src/client/components/commands/SetAvatar.ts index b65492f..eccfc2b 100644 --- a/src/client/components/commands/SetAvatar.ts +++ b/src/client/components/commands/SetAvatar.ts @@ -8,13 +8,13 @@ class SetAvatarCommand extends Command constructor (client: DiscordClient) { super(client, { - name: 'set', + name: 'set', description: 'Sets various things on the bot.', - options: [{ - name: 'avatar', - type: OptionType.SUB_COMMAND, + options: [{ + name: 'avatar', + type: OptionType.SUB_COMMAND, options: [{ - name: 'asset', + name: 'asset', required: true }] }], diff --git a/src/client/components/commands/Skip.ts b/src/client/components/commands/Skip.ts index f337787..ca33c60 100644 --- a/src/client/components/commands/Skip.ts +++ b/src/client/components/commands/Skip.ts @@ -7,12 +7,12 @@ class SkipCommand extends Command constructor (client: DiscordClient) { super(client, { - name: 'skip', + name: 'skip', description: 'Skips the current song.', - guildOnly: true, + guildOnly: true, // restricted: true, - sameVc: true, - limited: [ '1076274430520594514' ] + sameVc: true, + limited: [ '1076274430520594514' ] }); } diff --git a/src/client/components/commands/Stats.ts b/src/client/components/commands/Stats.ts index b9a9205..0a7b977 100644 --- a/src/client/components/commands/Stats.ts +++ b/src/client/components/commands/Stats.ts @@ -9,15 +9,15 @@ class StatsCommand extends Command constructor (client: DiscordClient) { super(client, { - name: 'stats', + name: 'stats', description: 'Display statistics about the songs played', - options: [{ - name: 'reset', - type: OptionType.BOOLEAN, - defaultValue: true, + options: [{ + name: 'reset', + type: OptionType.BOOLEAN, + defaultValue: true, valueOptional: true, - flag: true, - restricted: true + flag: true, + restricted: true }], guildOnly: true }); diff --git a/src/client/components/commands/Volume.ts b/src/client/components/commands/Volume.ts index df0278b..d339384 100644 --- a/src/client/components/commands/Volume.ts +++ b/src/client/components/commands/Volume.ts @@ -8,13 +8,13 @@ class VolumeCommand extends Command constructor (client: DiscordClient) { super(client, { - name: 'volume', - aliases: [ 'v', 'vol' ], + name: 'volume', + aliases: [ 'v', 'vol' ], description: 'Display or set the volume.', - options: [ + options: [ { - name: 'volume', - type: OptionType.INTEGER, + name: 'volume', + type: OptionType.INTEGER, // required: true, minimum: 0, maximum: 100 @@ -22,8 +22,8 @@ class VolumeCommand extends Command ], guildOnly: true, // restricted: true, - sameVc: true, - limited: [ '1076274430520594514' ], + sameVc: true, + limited: [ '1076274430520594514' ], }); } diff --git a/src/client/components/downloaders/Spotify.ts b/src/client/components/downloaders/Spotify.ts index fa17086..3bd06b7 100644 --- a/src/client/components/downloaders/Spotify.ts +++ b/src/client/components/downloaders/Spotify.ts @@ -121,9 +121,9 @@ class SpotifyDownloader extends Downloader const ext = elems[elems.length - 1]; return Promise.resolve({ existing: true, - artist: existingData.artist, - song: existingData.title, - album: data.album, + artist: existingData.artist, + song: existingData.title, + album: data.album, ext }); } diff --git a/src/client/components/inhibitors/DMOnly.ts b/src/client/components/inhibitors/DMOnly.ts index 308f70d..ae215f8 100644 --- a/src/client/components/inhibitors/DMOnly.ts +++ b/src/client/components/inhibitors/DMOnly.ts @@ -9,7 +9,7 @@ class DMOnlyInhibitor extends Inhibitor constructor (client: DiscordClient) { super(client, { - name: 'DMOnly', + name: 'DMOnly', priority: 4 }); } diff --git a/src/client/components/inhibitors/GuildOnly.ts b/src/client/components/inhibitors/GuildOnly.ts index d24af5c..c5c254b 100644 --- a/src/client/components/inhibitors/GuildOnly.ts +++ b/src/client/components/inhibitors/GuildOnly.ts @@ -9,7 +9,7 @@ class GuildOnlyInhibitor extends Inhibitor constructor (client: DiscordClient) { super(client, { - name: 'GuildOnly', + name: 'GuildOnly', priority: 4 }); } diff --git a/src/client/components/inhibitors/Limited.ts b/src/client/components/inhibitors/Limited.ts index e8a945f..bbc6025 100644 --- a/src/client/components/inhibitors/Limited.ts +++ b/src/client/components/inhibitors/Limited.ts @@ -10,7 +10,7 @@ class LimitedInhibitor extends Inhibitor constructor (client: DiscordClient) { super(client, { - name: 'Limited', + name: 'Limited', priority: 5 }); } diff --git a/src/client/components/observers/CommandHandler.ts b/src/client/components/observers/CommandHandler.ts index e87f960..bb3bf51 100644 --- a/src/client/components/observers/CommandHandler.ts +++ b/src/client/components/observers/CommandHandler.ts @@ -20,7 +20,7 @@ class CommandHandler extends Observer constructor (client: DiscordClient) { super(client, { - name: 'commandHandler', + name: 'commandHandler', priority: 10, }); @@ -29,16 +29,16 @@ class CommandHandler extends Observer ]; this.#parser = new Parser({ - commands: this.client.commands.values(), - prefix: client.prefix, - resolver: client.resolver, + commands: this.client.commands.values(), + prefix: client.prefix, + resolver: client.resolver, allowIncompleteReturn: true, - globalFlags: [{ - name: 'help', - flag: true, + globalFlags: [{ + name: 'help', + flag: true, valueOptional: true, - defaultValue: true, - type: OptionType.BOOLEAN + defaultValue: true, + type: OptionType.BOOLEAN }], debug: false }); @@ -56,7 +56,7 @@ class CommandHandler extends Observer try { result = await this.#parser.parseMessage(message.content, { - guild: message.guild, + guild: message.guild, commandFilter: (cmd) => { const command = cmd as Command; @@ -81,9 +81,9 @@ class CommandHandler extends Observer if (err instanceof ParserError) return void message.reply({ embeds: [{ - title: 'Command parse error', + title: 'Command parse error', description: err.message, - color: 0xbf2d30 + color: 0xbf2d30 }], allowedMentions }); @@ -91,9 +91,9 @@ class CommandHandler extends Observer this.logger.error(error); return void message.reply({ embeds: [{ - title: 'Command parse error', + title: 'Command parse error', description: this.client.isDeveloper(author) ? `\`\`\`js\n${error.stack ?? error.message}\n\`\`\`` : 'An internal error occurred...\n\nThis has been logged, please try again at a later point.', - color: 0xbf2d30 + color: 0xbf2d30 }], allowedMentions }); @@ -123,9 +123,9 @@ class CommandHandler extends Observer const [ first ] = inhibitions; return void message.reply({ embeds: [{ - title: 'Command execution inhibited', + title: 'Command execution inhibited', description: first.reason ?? '', - color: 0xd88c49 + color: 0xd88c49 }], allowedMentions }); @@ -138,9 +138,9 @@ class CommandHandler extends Observer this.logger.info(`${author.username} (${author.id}) ran into ${restrictedArgs.length} restricted arguments`); return void message.reply({ embeds: [{ - title: 'Restricted arguments', + title: 'Restricted arguments', description: `${Util.plural(restrictedArgs.length, 'Argument')} ${restrictedArgs.map(flag => flag?.name).join(', ')} are restricted`, - color: 0xd88c49 + color: 0xd88c49 }], allowedMentions }); @@ -197,9 +197,9 @@ class CommandHandler extends Observer const error = err as Error; await message.reply({ embeds: [{ - title: 'Command execution error', + title: 'Command execution error', description: this.client.isDeveloper(message.author) ? `\`\`\`js\n${error.stack ?? error.message}\n\`\`\`` : 'An internal error occurred, this has been logged.\nTry again later.\n\nIf your issue is truly urgent contact staff directly.', - color: 0xbf2d30 + color: 0xbf2d30 }], allowedMentions: { repliedUser: false }, failIfNotExists: false diff --git a/src/errors/CommandError.ts b/src/errors/CommandError.ts index 62e28f8..a9a72ed 100644 --- a/src/errors/CommandError.ts +++ b/src/errors/CommandError.ts @@ -58,9 +58,9 @@ class CommandError extends Error get embed () { return { - title: 'Command Error', + title: 'Command Error', description: this.reason, - color: 15120384 + color: 15120384 }; } diff --git a/src/interfaces/Component.ts b/src/interfaces/Component.ts index 06c26fe..a7ce69d 100644 --- a/src/interfaces/Component.ts +++ b/src/interfaces/Component.ts @@ -89,7 +89,7 @@ abstract class Component this.client.emit('componentUpdate', { component: this, - type: 'UNLOAD' + type: 'UNLOAD' }); return { error: false }; diff --git a/src/middleware/Controller.ts b/src/middleware/Controller.ts index 84635ef..5a74c7a 100644 --- a/src/middleware/Controller.ts +++ b/src/middleware/Controller.ts @@ -37,13 +37,13 @@ class Controller options.discord.logger = options.logger; options.discord.version = version; this.#shardingOptions = { - path: clientPath, + path: clientPath, totalShards, shardList, respawn, - shardArgs: [], + shardArgs: [], execArgv, - token: process.env.DISCORD_TOKEN, + token: process.env.DISCORD_TOKEN, clientOptions: options.discord, debug }; diff --git a/src/middleware/Shard.ts b/src/middleware/Shard.ts index 22d690d..9695ce6 100644 --- a/src/middleware/Shard.ts +++ b/src/middleware/Shard.ts @@ -57,12 +57,12 @@ class Shard extends EventEmitter this.#env = { ...process.env, - SHARDING_MANAGER: true, // IMPORTANT, SHARD IPC WILL BREAK IF MISSING + SHARDING_MANAGER: true, // IMPORTANT, SHARD IPC WILL BREAK IF MISSING SHARDING_MANAGER_MODE: 'process', // IMPORTANT, SHARD IPC WILL BREAK IF MISSING - SHARDS: this.#id, - SHARD_ID: this.#id, - SHARD_COUNT: options.totalShards, - DISCORD_TOKEN: options.token + SHARDS: this.#id, + SHARD_ID: this.#id, + SHARD_COUNT: options.totalShards, + DISCORD_TOKEN: options.token }; if (!options.clientOptions?.libraryOptions) throw new Error('Missing library options, must provide intents'); @@ -111,7 +111,7 @@ class Shard extends EventEmitter this.#process = childProcess .fork(path.resolve(this.#file), this.#args, { - env: this.#env as NodeJS.ProcessEnv, + env: this.#env as NodeJS.ProcessEnv, execArgv: this.#execArgv }) .on('message', this.#handleMessage.bind(this)) diff --git a/src/utilities/Util.ts b/src/utilities/Util.ts index 822e8a9..9753348 100644 --- a/src/utilities/Util.ts +++ b/src/utilities/Util.ts @@ -22,10 +22,10 @@ const Constants: { QuotePairs: StringIndexable } = { QuotePairs: { - '"': '"', // regular double + '"': '"', // regular double '\'': '\'', // regular single - '‘': '’', // smart single - '“': '”' // smart double + '‘': '’', // smart single + '“': '”' // smart double } }; @@ -357,7 +357,7 @@ class Util word = ''; const words: [string, boolean][] = [], - chars = string.split(''); + chars = string.split(''); chars.forEach((char: string) => { @@ -506,9 +506,9 @@ class Util static makePlainError (err: Error): PlainError { return { - name: err.name, + name: err.name, message: err.message, - stack: err.stack + stack: err.stack }; } @@ -544,7 +544,7 @@ class Util if (!token) throw new Error('[util] Token missing.'); return fetch('https://discord.com/api/v7/gateway/bot', { - method: 'GET', + method: 'GET', headers: { Authorization: `Bot ${token.replace(/^Bot\s*/iu, '')}` } }).then((res) => {