diff --git a/commands/nowplaying.js b/commands/nowplaying.js new file mode 100644 index 0000000..f07cdfa --- /dev/null +++ b/commands/nowplaying.js @@ -0,0 +1,47 @@ +// Copyright 2020 Emily J. / mudkipscience and contributors. Subject to the AGPLv3 license. + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: ['np'], + permLevel: 'User', + requiredPerms: [], + cooldown: 2000 +} + +exports.help = { + name: 'nowplaying', + category: 'Music', + description: 'Gives details on the song that is currently playing', + usage: 'nowplaying', + parameters: '' +} + +const { getGuild, createTimestamp } = require('../utils/music') +const { MessageEmbed } = require('discord.js') +exports.run = async (client, message, args, level, data) => { + const guild = getGuild(message.guild.id) + + if (guild.queue.length < 1) { + return message.channel.send(client.config.emojis.error + ' Nothing is in the queue!') + } + + const s = guild.queue[0] + const elapsedTime = createTimestamp(guild.dispatcher.streamTime / 1000) + let timestamp = `\`[${createTimestamp(s.video.lengthSeconds)}]\`` + + if (timestamp !== '`[LIVE]`') { + timestamp = `\`[${elapsedTime + '/' + createTimestamp(s.video.lengthSeconds)}]\`` + } + + const embed = new MessageEmbed() + embed.setTitle('Now playing') + embed.setThumbnail(s.video.videoThumbnails[1].url) + embed.setColor(client.embedColour(message.guild)) + embed.setDescription(`**[${s.video.title}](https://www.youtube.com/watch?v=${s.video.videoId})**`) + embed.addField('Channel:', s.video.author, true) + embed.addField('Time:', timestamp, true) + embed.setFooter('Requested by ' + s.requestedBy.tag, s.requestedBy.avatarURL({ format: 'png', dynamic: true, size: 2048 })) + + message.channel.send(embed) +} diff --git a/commands/pause.js b/commands/pause.js new file mode 100644 index 0000000..9b6e8e0 --- /dev/null +++ b/commands/pause.js @@ -0,0 +1,37 @@ +// Copyright 2020 Emily J. / mudkipscience and contributors. Subject to the AGPLv3 license. + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: [], + permLevel: 'User', + requiredPerms: [], + cooldown: 2000 +} + +exports.help = { + name: 'pause', + category: 'Music', + description: 'Pauses the music that is currently playing.', + usage: 'pause', + parameters: '' +} + +const { getGuild } = require('../utils/music') +exports.run = async (client, message, args, level, data) => { + const guild = getGuild(message.guild.id) + + if (guild.paused === true) { + return message.channel.send('The music has already been paused! Run resume to start the music again.') + } + + if (guild.queue.length < 1 || guild.playing === false) { + return message.channel.send('Nothing is playing!') + } + + guild.playing = false + guild.paused = true + guild.dispatcher.pause() + + message.channel.send('Music paused!') +} diff --git a/commands/queue.js b/commands/queue.js new file mode 100644 index 0000000..1471564 --- /dev/null +++ b/commands/queue.js @@ -0,0 +1,178 @@ +// Copyright 2020 Emily J. / mudkipscience and contributors. Subject to the AGPLv3 license. + +'use strict' + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: [], + permLevel: 'User', + requiredPerms: [], + cooldown: 2000 +} + +exports.help = { + name: 'queue', + category: 'Music', + description: 'Lists all songs that have been queued.', + usage: 'queue ', + parameters: '' +} + +const { getGuild, createTimestamp } = require('../utils/music') +const Discord = require('discord.js') +exports.run = (client, message, args) => { + var queue = getGuild(message.guild.id).queue + + if (queue.length < 1) { + return message.channel.send('<:error:466995152976871434> Nothing is playing.') + } + + const lists = [] + + function generateList (start, number) { + let list = '' + let timestamp + + if (start === 1 && queue.length === 1) { + return ['There\'s nothing else waiting to be played!', 1] + } + + if (number === 1 && queue.length + 1 < start) { + return false + } + + const q = queue.slice(start) + + let i = 0 + + for (i = 0; i < q.length; i++) { + const song = q[i] + + timestamp = createTimestamp(song.video.lengthSeconds) + + const aaa = list + `\`${(i + 1) + start - 1}:\` **[${song.video.title}](https://www.youtube.com/watch?v=${song.video.videoId})** added by ${song.requestedBy} \`[${timestamp}]\`\n` + + if (aaa.length > 1024) { + return [list, start + i - 1] + } else { + list = aaa + } + + // totalDuration = totalDuration + song.duration + } + + return [list, start + i + 1] + } + + const songsInQueue = queue.length - 1 + let songsInQueueEnglish = 'song' + + function generatePage (list, page) { + if (!list || list === '') { + return false + } + + var embed = new Discord.MessageEmbed() + embed.setTitle(`Queue for: ${message.guild.name}`) + embed.setColor(client.embedColour(message.guild)) + + var elapsedTime = getGuild(message.guild.id).dispatcher.streamTime / 1000 + var totalDuration = queue[0].video.lengthSeconds - elapsedTime + + let timeRemaining = '' + + for (let i = 1; i < queue.length; i++) { + const b = queue[i] + + if (b.video.lengthSeconds === 0) { + timeRemaining = '∞' + + break + } + + totalDuration += b.video.lengthSeconds + } + + if (timeRemaining === '') { + const queueDuration = createTimestamp(totalDuration) + + timeRemaining = queueDuration + } + + let timestamp = `\`${createTimestamp(queue[0].video.lengthSeconds)}\`` + + if (timestamp !== '`[LIVE]`') { + timestamp = `\`[${createTimestamp(elapsedTime) + '/' + createTimestamp(queue[0].video.lengthSeconds)}]\`` + } + + embed.addField('Now playing:', `**[${queue[0].video.title}](https://www.youtube.com/watch?v=${queue[0].video.videoId})** added by ${queue[0].requestedBy} ${timestamp}`) + + embed.addField('Up next:', list) + + if (songsInQueue > 1 || songsInQueue === 0) { + songsInQueueEnglish = 'songs' + } + + embed.setFooter(`Page ${page}/${lists.length} | ${songsInQueue + ' ' + songsInQueueEnglish} in queue | ${timeRemaining} time remaining`) + + return embed + } + + var myMessage = null + + function displayPage (number) { + const page = generatePage(lists[number - 1], number) + + if (page) { + if (myMessage) { + myMessage.edit(page) + } else { + myMessage = message.channel.send(page) + } + + return true + } else { + return false + } + } + + function aFunction (start) { + // start - index of song, which we should start with + // end - index of song, which we ended with + + const [list, end] = generateList(start, lists.length + 1) + + if (list && list !== '') { + lists.push(list) + + if (queue[end + 1]) { + aFunction(end + 1) + } + } + } + + aFunction(1) + + let page = 1 + + if (args[0]) { + const userPage = Number(args[0]) + + if (userPage) { + page = userPage + } else { + return message.channel.send( + `<:error:466995152976871434> Invalid page. Usage: \`${client.commands.get('queue').help.usage}\`` + ) + } + } + + if (displayPage(page)) { + + } else { + return message.channel.send( + `<:error:466995152976871434> Page ${page} doesn't exist!` + ) + } +} diff --git a/commands/resume.js b/commands/resume.js new file mode 100644 index 0000000..6208e7a --- /dev/null +++ b/commands/resume.js @@ -0,0 +1,37 @@ +// Copyright 2020 Emily J. / mudkipscience and contributors. Subject to the AGPLv3 license. + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: ['unpause'], + permLevel: 'User', + requiredPerms: [], + cooldown: 2000 +} + +exports.help = { + name: 'resume', + category: 'Music', + description: 'Starts music back up if it was paused.', + usage: 'resume', + parameters: '' +} + +const { getGuild } = require('../utils/music') +exports.run = async (client, message, args, level, data) => { + const guild = getGuild(message.guild.id) + + if (guild.paused === false) { + return message.channel.send('The music is already playing, use pause to pause the music first!') + } + + if (guild.queue.length < 1) { + return message.channel.send('Nothing is playing!') + } + + guild.playing = true + guild.paused = false + guild.dispatcher.resume() + + message.channel.send('Music resumed!') +} diff --git a/configTemplate.js b/configTemplate.js index ed6b127..14c8d39 100644 --- a/configTemplate.js +++ b/configTemplate.js @@ -14,7 +14,7 @@ const config = { // Configurable API endpoints endpoints: { - invidious: "https://invidious.snopyta.org/api/" + invidious: 'https://invidious.snopyta.org/api/' }, // Users added to this embed get access to developer-level commands diff --git a/utils/music.js b/utils/music.js index 825334b..756a4e6 100644 --- a/utils/music.js +++ b/utils/music.js @@ -8,7 +8,9 @@ const { utc } = require('moment') exports.queue = {} exports.createTimestamp = function (s) { - if (s >= 3600) { + if (s < 1) { + return 'LIVE' + } else if (s >= 3600) { return utc(s * 1000).format('HH:mm:ss') } else { return utc(s * 1000).format('mm:ss') @@ -21,9 +23,11 @@ exports.getGuild = function (id) { if (!guild) { guild = {} - guild.dispatcher = null - guild.playing = false guild.queue = [] + guild.playing = false + guild.paused = false + guild.dispatcher = null + guild.skippers = [] exports.queue[id] = guild } @@ -155,7 +159,7 @@ exports.play = async function (client, message, query, ignoreQueue) { } // Add video to queue - guild.queue.push({ video: video, requestedBy: message.member.id }) + guild.queue.push({ video: video, requestedBy: message.author }) } // Figure out if the bot should add it to queue or play it right now @@ -181,7 +185,7 @@ exports.play = async function (client, message, query, ignoreQueue) { guild.playing = false if (guild.queue.length > 0) { - exports.play(message, null, true) + exports.play(client, message, null, true) } else { guild.dispatcher = null