diff --git a/.pnp.cjs b/.pnp.cjs index a9ed520..46613b5 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -33,17 +33,17 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["@octokit/auth-token", "npm:4.0.0"],\ ["@octokit/rest", "npm:20.0.1"],\ ["@types/ms", "npm:0.7.31"],\ - ["@types/node", "npm:20.4.8"],\ + ["@types/node", "npm:20.4.10"],\ ["axios", "npm:1.4.0"],\ ["canvas", "npm:2.11.2"],\ ["discord-player", "virtual:20c353e2d6536e37339997f03975c6a660f4d296e664d291bd43620c6162cca8eb5ef90b0998dc9db75ff6862e5da587d0530bae26805f5fadc8f17aaa4ff794#npm:6.6.2"],\ ["discord.js", "npm:14.12.1"],\ ["libsodium-wrappers", "npm:0.7.11"],\ ["moment", "npm:2.29.4"],\ - ["mongoose", "npm:7.4.2"],\ + ["mongoose", "npm:7.4.3"],\ ["ms", "npm:2.1.3"],\ ["prism-media", "virtual:20c353e2d6536e37339997f03975c6a660f4d296e664d291bd43620c6162cca8eb5ef90b0998dc9db75ff6862e5da587d0530bae26805f5fadc8f17aaa4ff794#npm:1.3.5"],\ - ["systeminformation", "npm:5.18.12"],\ + ["systeminformation", "npm:5.18.15"],\ ["typescript", "patch:typescript@npm%3A5.1.6#~builtin::version=5.1.6&hash=5da071"],\ ["xml-js", "npm:1.6.11"],\ ["youtube-sr", "npm:4.3.4"],\ @@ -513,6 +513,13 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { }]\ ]],\ ["@types/node", [\ + ["npm:20.4.10", {\ + "packageLocation": "./.yarn/cache/@types-node-npm-20.4.10-a66bd58ee3-02a1ca415d.zip/node_modules/@types/node/",\ + "packageDependencies": [\ + ["@types/node", "npm:20.4.10"]\ + ],\ + "linkType": "HARD"\ + }],\ ["npm:20.4.8", {\ "packageLocation": "./.yarn/cache/@types-node-npm-20.4.8-f8f2d8d349-86a3963c0c.zip/node_modules/@types/node/",\ "packageDependencies": [\ @@ -934,17 +941,17 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["@octokit/auth-token", "npm:4.0.0"],\ ["@octokit/rest", "npm:20.0.1"],\ ["@types/ms", "npm:0.7.31"],\ - ["@types/node", "npm:20.4.8"],\ + ["@types/node", "npm:20.4.10"],\ ["axios", "npm:1.4.0"],\ ["canvas", "npm:2.11.2"],\ ["discord-player", "virtual:20c353e2d6536e37339997f03975c6a660f4d296e664d291bd43620c6162cca8eb5ef90b0998dc9db75ff6862e5da587d0530bae26805f5fadc8f17aaa4ff794#npm:6.6.2"],\ ["discord.js", "npm:14.12.1"],\ ["libsodium-wrappers", "npm:0.7.11"],\ ["moment", "npm:2.29.4"],\ - ["mongoose", "npm:7.4.2"],\ + ["mongoose", "npm:7.4.3"],\ ["ms", "npm:2.1.3"],\ ["prism-media", "virtual:20c353e2d6536e37339997f03975c6a660f4d296e664d291bd43620c6162cca8eb5ef90b0998dc9db75ff6862e5da587d0530bae26805f5fadc8f17aaa4ff794#npm:1.3.5"],\ - ["systeminformation", "npm:5.18.12"],\ + ["systeminformation", "npm:5.18.15"],\ ["typescript", "patch:typescript@npm%3A5.1.6#~builtin::version=5.1.6&hash=5da071"],\ ["xml-js", "npm:1.6.11"],\ ["youtube-sr", "npm:4.3.4"],\ @@ -1923,10 +1930,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ],\ "linkType": "SOFT"\ }],\ - ["virtual:d0cf582de895e62953c81ce7ab1a408175da60784650b2939a6701a3e2b010f4c727d233f3f39d449e394e9ee90a709f72fd9dc5e400cff7ac78e132b6b47f51#npm:5.7.0", {\ - "packageLocation": "./.yarn/__virtual__/mongodb-virtual-7d609f886f/0/cache/mongodb-npm-5.7.0-c5e415a2e7-16357b6229.zip/node_modules/mongodb/",\ + ["virtual:de9b2a4bee48b47472569f051556d00472ad2cae24f303eab2885fcb163b9304e49630ec473487f25346e199b727589de8b538c4c4621c9a5e46486fe0dda3c9#npm:5.7.0", {\ + "packageLocation": "./.yarn/__virtual__/mongodb-virtual-3d9fb5213a/0/cache/mongodb-npm-5.7.0-c5e415a2e7-16357b6229.zip/node_modules/mongodb/",\ "packageDependencies": [\ - ["mongodb", "virtual:d0cf582de895e62953c81ce7ab1a408175da60784650b2939a6701a3e2b010f4c727d233f3f39d449e394e9ee90a709f72fd9dc5e400cff7ac78e132b6b47f51#npm:5.7.0"],\ + ["mongodb", "virtual:de9b2a4bee48b47472569f051556d00472ad2cae24f303eab2885fcb163b9304e49630ec473487f25346e199b727589de8b538c4c4621c9a5e46486fe0dda3c9#npm:5.7.0"],\ ["@aws-sdk/credential-providers", null],\ ["@mongodb-js/zstd", null],\ ["@types/aws-sdk__credential-providers", null],\ @@ -1969,13 +1976,13 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { }]\ ]],\ ["mongoose", [\ - ["npm:7.4.2", {\ - "packageLocation": "./.yarn/cache/mongoose-npm-7.4.2-d0cf582de8-2bf73cea4b.zip/node_modules/mongoose/",\ + ["npm:7.4.3", {\ + "packageLocation": "./.yarn/cache/mongoose-npm-7.4.3-de9b2a4bee-e92feec9e7.zip/node_modules/mongoose/",\ "packageDependencies": [\ - ["mongoose", "npm:7.4.2"],\ + ["mongoose", "npm:7.4.3"],\ ["bson", "npm:5.4.0"],\ ["kareem", "npm:2.5.1"],\ - ["mongodb", "virtual:d0cf582de895e62953c81ce7ab1a408175da60784650b2939a6701a3e2b010f4c727d233f3f39d449e394e9ee90a709f72fd9dc5e400cff7ac78e132b6b47f51#npm:5.7.0"],\ + ["mongodb", "virtual:de9b2a4bee48b47472569f051556d00472ad2cae24f303eab2885fcb163b9304e49630ec473487f25346e199b727589de8b538c4c4621c9a5e46486fe0dda3c9#npm:5.7.0"],\ ["mpath", "npm:0.9.0"],\ ["mquery", "npm:5.0.0"],\ ["ms", "npm:2.1.3"],\ @@ -2681,10 +2688,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { }]\ ]],\ ["systeminformation", [\ - ["npm:5.18.12", {\ - "packageLocation": "./.yarn/unplugged/systeminformation-npm-5.18.12-2a4b019257/node_modules/systeminformation/",\ + ["npm:5.18.15", {\ + "packageLocation": "./.yarn/unplugged/systeminformation-npm-5.18.15-6e7be558fc/node_modules/systeminformation/",\ "packageDependencies": [\ - ["systeminformation", "npm:5.18.12"]\ + ["systeminformation", "npm:5.18.15"]\ ],\ "linkType": "HARD"\ }]\ diff --git a/package.json b/package.json index 0f2f7e0..7d865b1 100644 --- a/package.json +++ b/package.json @@ -37,10 +37,10 @@ "discord.js": "14.12.1", "libsodium-wrappers": "0.7.11", "moment": "2.29.4", - "mongoose": "7.4.2", + "mongoose": "7.4.3", "ms": "2.1.3", "prism-media": "1.3.5", - "systeminformation": "5.18.12", + "systeminformation": "5.18.15", "typescript": "5.1.6", "xml-js": "1.6.11", "youtube-sr": "4.3.4", @@ -48,6 +48,6 @@ }, "devDependencies": { "@types/ms": "0.7.31", - "@types/node": "20.4.8" + "@types/node": "20.4.10" } } diff --git a/src/commands/dev.ts b/src/commands/dev.ts index 1e3ef09..0eed7b0 100644 --- a/src/commands/dev.ts +++ b/src/commands/dev.ts @@ -193,7 +193,7 @@ export default { .addStringOption(x=>x .setName('status') .setDescription('Set a status indicator for the bot') - .setChoices( + .addChoices( {name: 'Online', value: Discord.PresenceUpdateStatus.Online}, {name: 'Idle', value: Discord.PresenceUpdateStatus.Idle}, {name: 'Do Not Distrub', value: Discord.PresenceUpdateStatus.DoNotDisturb}, diff --git a/src/commands/music.ts b/src/commands/music.ts index d30eb76..cbe5749 100644 --- a/src/commands/music.ts +++ b/src/commands/music.ts @@ -5,12 +5,9 @@ import {SpotifyExtractor} from '@discord-player/extractor'; export default { async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ if (!client.config.botSwitches.music && !client.config.whitelist.includes(interaction.user.id)) return interaction.reply({content:'Music module is currently disabled.',ephemeral:true}); - if (!client.isStaff(interaction.member) && !client.config.whitelist.includes(interaction.member.id)) return interaction.reply('This command is in early stages of development, some parts may be missing or broken.\nIt has been restricted to staff for time-being.'); + if (!client.isStaff(interaction.member) && !client.config.whitelist.includes(interaction.member.id)) return interaction.reply('Music module is close to being completed, some parts may be incomplete or broken, so it has been restricted to staff for time-being.'); const player = Player.singleton(client); - await player.extractors.register(SpotifyExtractor, { - clientId: client.tokens.dontlookatme.client, - clientSecret: client.tokens.dontlookatme.secret - }); + await player.extractors.register(SpotifyExtractor,{clientId: client.tokens.dontlookatme.client, clientSecret: client.tokens.dontlookatme.secret}); if (!interaction.member.voice.channel) return interaction.reply('Please join a voice channel first to use the command.'); player.nodes.create(interaction.guildId, { metadata: { @@ -27,53 +24,67 @@ export default { connectionTimeout: 25000, strategy: 'FIFO' }); + const queue = useQueue(interaction.guildId); ({ play: async()=>{ const url = interaction.options.getString('url'); if (!url.includes('https://open.spotify.com/')) return interaction.reply('Sorry, I can\'t play that. I can only accept Spotify links that contains `https://open.spotify.com/`'); // Yes, I made it clear that it's intended typo. if (!(await player.search(url,{requestedBy:interaction.user})).hasTracks()) return interaction.reply(`No results found for \`${url}\`\nIt is either private, unavailable or you made a *tpyo* in your query.`) player.play(interaction.member.voice.channel, url); - await interaction.reply(`Added the ${url.includes('playlist/') ? 'playlist' : 'song'} to the queue.`); + await interaction.reply(`Added the ${url.includes('playlist/') ? 'playlist' : url.includes('album/') ? 'album' : 'song'} to the queue.`); }, stop: async()=>{ player.destroy(); await interaction.reply('Player destroyed.') }, pause: ()=>{ - const queue = useQueue(interaction.guildId); queue.node.setPaused(!queue.node.isPaused()); - if (!queue.node.isPaused) interaction.reply('Music has been paused.'); - else if (queue.node.isPaused) interaction.reply('Music has been unpaused.') + if (queue.node.isPaused()) interaction.reply('Music has been paused.'); + else interaction.reply('Music has been resumed.') }, now_playing: ()=>{ const {volume,timestamp,track} = useTimeline(interaction.guildId); - interaction.reply({embeds:[ - new client.embed().setColor(client.config.embedColor).setTitle(`${track.title} - ${track.author}`).setThumbnail(track.thumbnail).addFields( - {name: 'Timestamp', value: `**${timestamp.current.label}**/**${timestamp.total.label}**`, inline: true}, - {name: 'Volume', value: `${volume}%`, inline: true} - ) - ]}) - }, - queue: async()=>{ - const queue = useQueue(interaction.guildId); - interaction.reply({embeds:[new client.embed().setColor(client.config.embedColor).setTitle(`Songs currently in the queue: ${queue.tracks.size}`).setDescription(queue.tracks.size > 0 ? `\`\`\`${queue.tracks.map(i=>`${i.title} - ${i.author}\`\`\``).join('```\n')}`.slice(0,1017) : '*No songs currently queued.*')]}) + if (!track) return interaction.reply('There\'s nothing playing, why are you checking?'); + else { + function convertNumberToText(input:number){ + switch(input){ + case 0: return 'Off'; + case 1: return 'Track'; + case 2: return 'Queue'; + case 3: return 'Autoplay DJ'; + } + } + interaction.reply({embeds:[ + new client.embed().setColor(client.config.embedColor).setTitle(`${track.title} - ${track.author}`).setThumbnail(track.thumbnail).addFields( + {name: 'Timestamp', value: `**${timestamp.current.label}**/**${timestamp.total.label}**`, inline: true}, + {name: 'Volume', value: `${volume}%`, inline: true}, + {name: 'Loop mode', value: `${convertNumberToText(queue.repeatMode)}`, inline: true} + ) + ]}) + } }, + queue: async()=>interaction.reply({embeds:[new client.embed().setColor(client.config.embedColor).setTitle(`Songs currently in the queue: ${queue.tracks.size}`).setDescription(queue.tracks.size > 0 ? `\`\`\`${queue.tracks.map(i=>`${i.title} - ${i.author}\`\`\``).join('```\n')}`.slice(0,1017) : '*No songs currently queued.*')]}), volume: ()=>{ const vol = interaction.options.getNumber('percentage'); - useQueue(interaction.guildId).node.setVolume(vol); + queue.node.setVolume(vol); interaction.reply(`Successfully adjusted the player's volume to ${vol}%`) }, shuffle: ()=>{ - useQueue(interaction.guildId).tracks.shuffle(); + queue.tracks.shuffle(); interaction.reply('Songs in the queue has been shuffled.') }, remove: ()=>{ - useQueue(interaction.guildId).removeTrack(interaction.options.getNumber('id',true)); + queue.removeTrack(interaction.options.getNumber('id',true)); interaction.reply('Song has been removed from the queue.') }, skip: ()=>{ - useQueue(interaction.guildId).node.skip(); + queue.node.skip(); interaction.reply('Skipped the current song, now playing the next one in queue.') + }, + loop: ()=>{ + const loopMode = interaction.options.getNumber('mode',true); + queue.setRepeatMode(loopMode); + interaction.reply(`Loop mode is now ${loopMode === 0 ? 'disabled.' : loopMode === 1 ? 'set to loop current track.': loopMode === 2 ? 'looping through current queue.' : 'activating Autoplay DJ.'}`) } } as any)[interaction.options.getSubcommand()](); }, @@ -114,6 +125,19 @@ export default { .addSubcommand(x=>x .setName('shuffle') .setDescription('Shuffle the songs in a queue')) + .addSubcommand(x=>x + .setName('loop') + .setDescription('Loop through queue or current track or enable Autoplay DJ') + .addNumberOption(x=>x + .setName('mode') + .setDescription('Select the available modes to use') + .addChoices( + {name: 'Off', value: 0}, + {name: 'Current track', value: 1}, + {name: 'Queue', value: 2}, + {name: 'Autoplay DJ (Play related songs based on queue)', value: 3} + ) + .setRequired(true))) .addSubcommand(x=>x .setName('remove') .setDescription('Remove a specific song from the queue') diff --git a/src/index.ts b/src/index.ts index 648e203..5e4bcfd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,13 +30,18 @@ client.on('ready', async()=>{ // Error handler function DZ(error:Error, type:string){// Yes, I may have shiternet but I don't need to wake up to like a hundred messages or so. - if (['getaddrinfo ENOTFOUND discord.com', 'getaddrinfo EAI_AGAIN discord.com', '[Error: 30130000:error:0A000410:SSL', '[Error: F8200000:error:0A000410:SSL'].includes(error.message)) return; + if ([ + 'getaddrinfo ENOTFOUND discord.com', 'getaddrinfo EAI_AGAIN discord.com', + '[Error: 30130000:error:0A000410:SSL', '[Error: F8200000:error:0A000410:SSL', + 'HTTPError: Internal Server Error' + ].includes(error.message)) return; console.error(error); (client.channels.resolve(client.config.mainServer.channels.errors) as Discord.TextChannel | null)?.send({embeds: [new client.embed().setColor('#560000').setTitle('Error caught!').setFooter({text: 'Error type: ' + type}).setDescription(`**Error:**\n\`\`\`${error.message}\`\`\`**Stack:**\n\`\`\`${`${error.stack}`.slice(0, 2500)}\`\`\``)]}) } process.on('unhandledRejection', (error: Error)=>DZ(error, 'unhandledRejection')); process.on('uncaughtException', (error: Error)=>DZ(error, 'uncaughtException')); -process.on('error', (error: Error)=>DZ(error, 'process-error')); +process.on('error', (error: Error)=>DZ(error, 'nodeError')); +process.on('warning', (warn: Error)=>DZ(warn, 'nodeWarning')); client.on('error', (error: Error)=>DZ(error, 'client-error')); // Audio Player event handling @@ -87,7 +92,9 @@ setInterval(async()=>{ dailyMsgs.push([formattedDate, total]); writeFileSync('./src/database/dailyMsgs.json', JSON.stringify(dailyMsgs)) console.log(client.logTime(), `Pushed [${formattedDate}, ${total}] to dailyMsgs`); - client.guilds.cache.get(client.config.mainServer.id).commands.fetch().then(commands=>(client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send(`:pencil: Pushed \`[${formattedDate}, ${total}]\` to x.name === 'rank').id}>`)); - (client.channels.resolve(client.config.mainServer.channels.thismeanswar) as Discord.TextChannel).send({files:['./src/database/dailyMsgs.json']}).catch(fileErr=>console.log(fileErr)) + if (client.token != client.tokens.main){ + client.guilds.cache.get(client.config.mainServer.id).commands.fetch().then(commands=>(client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send(`:pencil: Pushed \`[${formattedDate}, ${total}]\` to x.name === 'rank').id}>`)); + (client.channels.resolve(client.config.mainServer.channels.thismeanswar) as Discord.TextChannel).send({files:['./src/database/dailyMsgs.json']}).catch(fileErr=>console.log(fileErr)) + } else console.log(client.logTime(), 'Development bot\'s token is in use, not uploading dailyMsgs.json to channel.') } }, 5000) diff --git a/yarn.lock b/yarn.lock index b6654cb..4e48323 100644 --- a/yarn.lock +++ b/yarn.lock @@ -379,13 +379,20 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:20.4.8": +"@types/node@npm:*": version: 20.4.8 resolution: "@types/node@npm:20.4.8" checksum: 86a3963c0c7af3410553d1dfa4b018a20b3cb3ab4d8e8ffe27408b6338c5de0374b0bf379bc705da2205b466daa751ccfe062f453ba9bde34fdb0e5163ca6a68 languageName: node linkType: hard +"@types/node@npm:20.4.10": + version: 20.4.10 + resolution: "@types/node@npm:20.4.10" + checksum: 02a1ca415d9cc91144c4250383aa0ef1e48241bd36067ed7d1b239d8bacc2a11139dd90e223e11ac289345eeae624cc5dcf73359e684bd2e5a6c31bdfbab4811 + languageName: node + linkType: hard + "@types/webidl-conversions@npm:*": version: 7.0.0 resolution: "@types/webidl-conversions@npm:7.0.0" @@ -750,17 +757,17 @@ __metadata: "@octokit/auth-token": 4.0.0 "@octokit/rest": 20.0.1 "@types/ms": 0.7.31 - "@types/node": 20.4.8 + "@types/node": 20.4.10 axios: 1.4.0 canvas: 2.11.2 discord-player: 6.6.2 discord.js: 14.12.1 libsodium-wrappers: 0.7.11 moment: 2.29.4 - mongoose: 7.4.2 + mongoose: 7.4.3 ms: 2.1.3 prism-media: 1.3.5 - systeminformation: 5.18.12 + systeminformation: 5.18.15 typescript: 5.1.6 xml-js: 1.6.11 youtube-sr: 4.3.4 @@ -1628,9 +1635,9 @@ __metadata: languageName: node linkType: hard -"mongoose@npm:7.4.2": - version: 7.4.2 - resolution: "mongoose@npm:7.4.2" +"mongoose@npm:7.4.3": + version: 7.4.3 + resolution: "mongoose@npm:7.4.3" dependencies: bson: ^5.4.0 kareem: 2.5.1 @@ -1639,7 +1646,7 @@ __metadata: mquery: 5.0.0 ms: 2.1.3 sift: 16.0.1 - checksum: 2bf73cea4bf72ffa553a7d024b827e50fcb4aba9a17111ece764e1644c97313d678e84e0fb63c101061e70966b19ba720524f46deedcfbc631f583da45533eb0 + checksum: e92feec9e739fd429726b6b17ad0d5c05503d2786aa9605548e2b7e999f990a59bdf950e5cd44aa10e3936277410b4880e760e9e503627fae6c16b4901bf9c49 languageName: node linkType: hard @@ -2233,12 +2240,12 @@ __metadata: languageName: node linkType: hard -"systeminformation@npm:5.18.12": - version: 5.18.12 - resolution: "systeminformation@npm:5.18.12" +"systeminformation@npm:5.18.15": + version: 5.18.15 + resolution: "systeminformation@npm:5.18.15" bin: systeminformation: lib/cli.js - checksum: 0893f61fecb0cae181c6cb37b544395263e8be1f7c53a06868c139e4fb9dfe605426850c339afe905d25427addf33e9f754c4c05ec71b0e73dbbf93c2da2247c + checksum: 15555c2c0fac29ca8146153c5b9ad146f5fe5ffe109f0cbc20d2d2b902f8b4d2cc57a1add233edc4914c13f984b96250a51ce351bd570a1ac6ba369ed3caa974 conditions: (os=darwin | os=linux | os=win32 | os=freebsd | os=openbsd | os=netbsd | os=sunos | os=android) languageName: node linkType: hard