1
0
mirror of https://github.com/musix-org/musix-oss synced 2024-12-22 14:53:17 +00:00
This commit is contained in:
MatteZ02 2020-02-05 22:02:53 +02:00
commit d343af3b14
49 changed files with 1248 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
node_modules/
dev/
.env
.vscode/
package-lock.json
src/struct/config/.env
src/struct/config/serviceAccount.json

37
package.json Normal file
View File

@ -0,0 +1,37 @@
{
"name": "musix",
"version": "1.0.0",
"description": "V3 for Musix the discord music bot",
"main": "./src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/MatteZ02/Musix-V3.git"
},
"author": "Matte",
"license": "ISC",
"bugs": {
"url": "https://github.com/MatteZ02/Musix-V3/issues"
},
"homepage": "https://github.com/MatteZ02/Musix-V3#readme",
"dependencies": {
"dblapi.js": "^2.3.1",
"discord.js": "github:discordjs/discord.js",
"dotenv": "^8.2.0",
"ffmpeg": "0.0.4",
"firebase": "^7.8.0",
"firebase-admin": "^8.9.2",
"fs": "0.0.1-security",
"he": "^1.2.0",
"ms": "^2.1.2",
"node-opus": "^0.3.3",
"prism-media": "github:hydrabolt/prism-media",
"request": "^2.88.0",
"simple-youtube-api": "^5.2.1",
"video-thumbnail-url": "^1.0.1",
"ytdl-core": "^1.0.7",
"ytdl-core-discord": "^1.1.0"
}
}

16
src/commands/bug.js Normal file
View File

@ -0,0 +1,16 @@
module.exports = {
name: 'bug',
alias: 'none',
usage: 'bug',
description: 'Report a bug',
onlyDev: false,
permission: 'none',
category: 'info',
async execute(msg, args, client, Discord, prefix) {
const embed = new Discord.MessageEmbed()
.setTitle(`Found a bug with ${client.user.username}?\nDM the core developer:`)
.setDescription(`Matte#0002\nOr join the support server: https://discord.gg/rvHuJtB`)
.setColor(client.config.embedColor);
msg.channel.send(embed);
},
};

31
src/commands/cmduses.js Normal file
View File

@ -0,0 +1,31 @@
module.exports = {
name: 'cmduses',
alias: 'none',
usage: 'cmduses',
description: 'list all commands and how many times they\'ve been used',
onlyDev: true,
permission: 'dev',
category: 'info',
async execute(msg, args, client, Discord) {
const cmduses = [];
client.commands.forEach((value, key) => {
cmduses.push([key, value.uses]);
});
cmduses.sort((a, b) => {
return b[1] - a[1];
});
const cmdnamelength = Math.max(...cmduses.map(x => x[0].length)) + 4;
const numberlength = Math.max(...cmduses.map(x => x[1].toString().length), 4);
const markdownrows = ['Command' + ' '.repeat(cmdnamelength - 'command'.length) + ' '.repeat(numberlength - 'uses'.length) + 'Uses'];
cmduses.forEach(x => {
if (x[1] > 0) markdownrows.push(x[0] + '.'.repeat(cmdnamelength - x[0].length) + ' '.repeat(numberlength - x[1].toString().length) + x[1].toString());
});
const embed = new Discord.MessageEmbed();
embed
.setTitle('Musix Command Usage During Current Uptime')
.setDescription('```ml\n' + markdownrows.join('\n') + '\n```')
.setFooter('These statistics are from the current uptime.')
.setColor(client.config.embedColor);
msg.channel.send(embed);
},
};

View File

@ -0,0 +1,16 @@
module.exports = {
name: 'disconnect',
alias: 'dc',
usage: 'disconnect',
description: 'Disconnect the bot from a voice channel.',
onlyDev: false,
permission: 'MANAGE_CHANNELS',
category: 'util',
async execute(msg, args, client, Discord, prefix, command) {
const serverQueue = client.queue.get(msg.guild.id);
if (client.funcs.check(client, msg, command)) {
serverQueue.voiceChannel.leave();
msg.channel.send('<:green_check_mark:674265384777416705> Left the voice channel!');
}
}
};

29
src/commands/eval.js Normal file
View File

@ -0,0 +1,29 @@
module.exports = {
name: 'eval',
alias: 'e',
usage: 'eval <code>',
description: 'Evaluation command. DEV ONLY!',
onlyDev: true,
permission: 'dev',
category: 'util',
async execute(msg, args, client, Discord, prefix) {
const ytdl = require('ytdl-core');
const serverQueue = client.queue.get(msg.guild.id);
let data;
if (serverQueue) {
data = await Promise.resolve(ytdl.getInfo(serverQueue.songs[0].url));
}
const input = msg.content.slice(prefix.length + 4);
let output;
try {
output = await eval(input);
} catch (error) {
output = error.toString();
}
const embed = new Discord.MessageEmbed()
.setTitle('Evaluation Command')
.setColor(client.config.embedColor)
.setDescription(`Input: \`\`\`js\n${input.replace(/; /g, ';').replace(/;/g, ';\n')}\n\`\`\`\nOutput: \`\`\`\n${output}\n\`\`\``);
return msg.channel.send(embed);
},
};

36
src/commands/help.js Normal file
View File

@ -0,0 +1,36 @@
module.exports = {
name: 'help',
alias: 'h',
usage: 'help <command(opt)>',
description: 'See the help for Musix.',
onlyDev: false,
permission: 'none',
category: 'info',
execute(msg, args, client, Discord, prefix, command) {
if (args[1]) {
if (!client.commands.has(args[1]) || (client.commands.has(args[1]) && client.commands.get(args[1]).omitFromHelp === true && msg.guild.id !== '489083836240494593')) return msg.channel.send('That command does not exist');
const command = client.commands.get(args[1]);
const embed = new Discord.MessageEmbed()
.setTitle(`${client.global.db.guilds[msg.guild.id].prefix}${command.name} ${command.usage}`)
.setDescription(command.description)
.setFooter(`Command Alias: \`${command.alias}\``)
.setColor(client.config.embedColor)
msg.channel.send(embed);
} else {
const categories = [];
for (let i = 0; i < client.commands.size; i++) {
if (!categories.includes(client.commands.array()[i].category)) categories.push(client.commands.array()[i].category);
}
let commands = '';
for (let i = 0; i < categories.length; i++) {
commands += `**» ${categories[i].toUpperCase()}**\n${client.commands.filter(x => x.category === categories[i] && !x.omitFromHelp).map(x => `\`${x.name}\``).join(', ')}\n`;
}
const embed = new Discord.MessageEmbed()
.setTitle(`${client.user.username} help:`)
.setDescription(commands)
.setFooter(`"${client.global.db.guilds[msg.guild.id].prefix}help <command>" to see more information about a command.`)
.setColor(client.config.embedColor)
msg.channel.send(embed);
}
}
};

16
src/commands/invite.js Normal file
View File

@ -0,0 +1,16 @@
module.exports = {
name: 'invite',
alias: 'i',
usage: 'invite',
description: 'Invite Musix.',
onlyDev: false,
permission: 'none',
category: 'info',
execute(msg, args, client, Discord, prefix) {
const embed = new Discord.MessageEmbed()
.setTitle(`Invite ${client.user.username} to your Discord server!`)
.setURL(client.config.invite)
.setColor(client.config.embedColor)
return msg.channel.send(embed);
}
};

24
src/commands/join.js Normal file
View File

@ -0,0 +1,24 @@
module.exports = {
name: 'join',
alias: 'j',
usage: 'join',
description: 'Make Musix join the channel your channel',
onlyDev: false,
permission: 'none',
category: 'util',
async execute(msg, args, client, Discord, prefix) {
try {
const serverQueue = client.queue.get(msg.guild.id);
const voiceChannel = msg.member.voice.channel;
const connection = await voiceChannel.join();
if (serverQueue) {
serverQueue.connection = connection;
}
msg.channel.send(`<:green_check_mark:674265384777416705> Joined ${voiceChannel.name}!`);
} catch (error) {
client.queue.delete(msg.guild.id);
client.channels.get(client.config.debug_channel).send("Error with connecting to voice channel: " + error);
return msg.channel.send(`<:redx:674263474704220182> An error occured: ${error}`);
}
}
};

21
src/commands/loop.js Normal file
View File

@ -0,0 +1,21 @@
module.exports = {
name: 'loop',
alias: 'none',
usage: 'loop',
description: 'loop the queue.',
onlyDev: false,
permission: 'MANAGE_MESSAGES',
category: 'music',
async execute(msg, args, client, Discord, prefix, command) {
const serverQueue = client.queue.get(msg.guild.id);
if (client.funcs.check(client, msg, command)) {
if (!serverQueue.looping) {
serverQueue.looping = true;
msg.channel.send('<:repeat1:674685561377914892> Looping the queue now!');
} else {
serverQueue.looping = false;
msg.channel.send('<:repeat1:674685561377914892> No longer looping the queue!');
}
}
}
};

21
src/commands/loopsong.js Normal file
View File

@ -0,0 +1,21 @@
module.exports = {
name: 'loopsong',
alias: 'loops',
usage: 'loopsong',
description: 'loop the currently playing song.',
onlyDev: false,
permission: 'MANAGE_MESSAGES',
category: 'music',
async execute(msg, args, client, Discord, prefix, command) {
const serverQueue = client.queue.get(msg.guild.id);
if (client.funcs.check(client, msg, command)) {
if (!serverQueue.songLooping) {
serverQueue.songLooping = true;
msg.channel.send(`<:repeatsong:674685573419761716> Looping **${serverQueue.songs[0].title}** now!`);
} else {
serverQueue.songLooping = false;
msg.channel.send('<:repeatsong:674685573419761716> No longer looping the song!');
}
}
}
};

View File

@ -0,0 +1,33 @@
module.exports = {
name: 'nowplaying',
alias: 'np',
usage: 'nowplaying',
description: 'See the currently playing song position and length.',
onlyDev: false,
permission: 'none',
category: 'music',
async execute(msg, args, client, Discord, prefix) {
const getThumb = require('video-thumbnail-url');
const ytdl = require('ytdl-core');
const serverQueue = client.queue.get(msg.guild.id);
if (!serverQueue) return msg.channel.send('<:redx:674263474704220182> There is nothing playing.');
if (!serverQueue.playing) return msg.channel.send('<:redx:674263474704220182> There is nothing playing.');
let data = await Promise.resolve(ytdl.getInfo(serverQueue.songs[0].url));
let songtime = (data.length_seconds * 1000).toFixed(0);
serverQueue.time = serverQueue.connection.dispatcher.streamTime;
let completed = (serverQueue.time.toFixed(0));
let barlength = 30;
let completedpercent = ((completed / songtime) * barlength).toFixed(0);
let array = []; for (let i = 0; i < completedpercent - 1; i++) { array.push('⎯'); } array.push('⭗'); for (let i = 0; i < barlength - completedpercent - 1; i++) { array.push('⎯'); }
const thumbnail = getThumb(serverQueue.songs[0].url);
const embed = new Discord.MessageEmbed()
.setTitle("__Now playing__")
.setDescription(`<a:aNotes:674602408105476106>**Now playing:** ${serverQueue.songs[0].title}\n${array.join('')} | \`${client.funcs.msToTime(completed)} / ${client.funcs.msToTime(songtime)}\``)
.setFooter(`Queued by ${serverQueue.songs[0].author.tag}`)
.setURL(serverQueue.songs[0].url)
.setThumbnail(thumbnail._rejectionHandler0)
.setColor(client.config.embedColor)
return msg.channel.send(embed);
}
};

18
src/commands/pause.js Normal file
View File

@ -0,0 +1,18 @@
module.exports = {
name: 'pause',
alias: 'none',
usage: 'pause',
description: 'Pause the currently playing music.',
onlyDev: false,
permission: 'MANAGE_MESSAGES',
category: 'music',
execute(msg, args, client, Discord, prefix, command) {
const serverQueue = client.queue.get(msg.guild.id);
if (client.funcs.check(client, msg, command)) {
if (serverQueue.paused) return msg.channel.send('<:redx:674263474704220182> The music is already paused!');
serverQueue.paused = true;
serverQueue.connection.dispatcher.pause(true);
return msg.channel.send('<:pause:674685548610322462> Paused the music!');
}
}
};

58
src/commands/play.js Normal file
View File

@ -0,0 +1,58 @@
const YouTube = require("simple-youtube-api");
module.exports = {
name: 'play',
alias: 'p',
usage: 'play <song name>',
description: 'Play some music.',
onlyDev: false,
permission: 'none',
category: 'music',
async execute(msg, args, client, Discord, prefix) {
const youtube = new YouTube(client.config.api_key);
const searchString = args.slice(1).join(" ");
const url = args[1] ? args[1].replace(/<(.+)>/g, "$1") : "";
const serverQueue = client.queue.get(msg.guild.id);
const voiceChannel = msg.member.voice.channel;
if (!serverQueue) {
if (!msg.member.voice.channel) return msg.channel.send('<:redx:674263474704220182> I\'m sorry but you need to be in a voice channel to play music!');
} else {
if (voiceChannel !== serverQueue.voiceChannel) return msg.channel.send('<:redx:674263474704220182> I\'m sorry but you need to be in the same voice channel as Musix to play music!');
}
if (!args[1]) return msg.channel.send('<:redx:674263474704220182> You need to use a link or search for a song!');
const permissions = voiceChannel.permissionsFor(msg.client.user);
if (!permissions.has('CONNECT')) {
return msg.channel.send('<:redx:674263474704220182> I cannot connect to your voice channel, make sure I have the proper permissions!');
}
if (!permissions.has('SPEAK')) {
return msg.channel.send('<:redx:674263474704220182> I cannot speak in your voice channel, make sure I have the proper permissions!');
}
if (url.match(/^https?:\/\/(www.youtube.com|youtube.com)\/playlist(.*)$/)) {
const lmsg = await msg.channel.send('<a:loading:674284196700618783> Loading song(s)');
const playlist = await youtube.getPlaylist(url);
const videos = await playlist.getVideos();
for (const video of Object.values(videos)) {
const video2 = await youtube.getVideoByID(video.id)
.catch(err => {
console.error(err);
return lmsg.edit(`<:redx:674263474704220182> Error loading songs!\nNot all songs we're loaded! This may have been caused by the playlist containing privated/deleted videos!`);
});
await client.funcs.handleVideo(video2, msg, voiceChannel, client, true);
}
return lmsg.edit(`<:green_check_mark:674265384777416705> Playlist: **${playlist.title}** has been added to the queue!`);
} else {
try {
var video = await youtube.getVideo(url);
} catch (error) {
try {
const videos = await youtube.searchVideos(searchString, 1);
var video = await youtube.getVideoByID(videos[0].id);
} catch (err) {
console.error(err);
return msg.channel.send('<:redx:674263474704220182> I could not obtain any search results!');
}
}
return client.funcs.handleVideo(video, msg, voiceChannel, client, false);
}
}
};

40
src/commands/queue.js Normal file
View File

@ -0,0 +1,40 @@
module.exports = {
name: 'queue',
alias: 'q',
usage: 'queue <page(opt)>',
description: 'See the queue.',
onlyDev: false,
permission: 'none',
category: 'music',
async execute(msg, args, client, Discord, prefix) {
const serverQueue = client.queue.get(msg.guild.id);
if (!serverQueue) return msg.channel.send('<:redx:674263474704220182> There is nothing playing.');
if (args[1]) {
if (isNaN(args[1])) return msg.channel.send('<:redx:674263474704220182> I\'m sorry, But you need to enter a valid __number__.');
}
let page = parseInt(args[1]);
if (!page) page = 1;
let pagetext = `:page_facing_up: Page: ${page} :page_facing_up:`
if (page === 1) pagetext = ':arrow_down: Next in queue :arrow_down:'
let queuesongs = serverQueue.songs.slice((page - 1) * 20 + 1, page * 20 + 1);
let queuemessage = `${queuesongs.map(song => `**#** ${song.title}`).join('\n')}`
const hashs = queuemessage.split('**#**').length;
for (let i = 0; i < hashs; i++) {
queuemessage = queuemessage.replace('**#**', `**${i + 1}**`);
}
if (!serverQueue.looping) {
const embed = new Discord.MessageEmbed()
.setTitle("__Song queue__")
.setDescription(`**Now playing:** ${serverQueue.songs[0].title}<a:aNotes:674602408105476106>\n${pagetext}\n${queuemessage}`)
.setColor(client.config.embedColor)
return msg.channel.send(embed);
} else {
const embed = new Discord.MessageEmbed()
.setTitle("__Song queue__")
.setDescription(`**Now playing:** ${serverQueue.songs[0].title}<a:aNotes:674602408105476106>\n${pagetext}\n${queuemessage}`)
.setFooter('<:repeat1:674685561377914892> Currently looping the queue!')
.setColor(client.config.embedColor)
return msg.channel.send(embed);
}
}
};

21
src/commands/remove.js Normal file
View File

@ -0,0 +1,21 @@
module.exports = {
name: 'remove',
alias: 'rm',
usage: 'remove <song pos>',
description: 'Remove a song from the queue',
onlyDev: false,
permission: 'MANAGE_MESSAGES',
category: 'music',
execute(msg, args, client, Discord, prefix, command) {
const serverQueue = client.queue.get(msg.guild.id);
if (client.funcs.check(client, msg, command)) {
if (!args[1]) return msg.channel.send('<:redx:674263474704220182> Please provide a song position in queue for me to remove!');
const pos = parseInt(args[1]);
if (isNaN(pos)) return msg.channel.send('<:redx:674263474704220182> You need to enter a number!');
if (pos === 0) return msg.channel.send('<:redx:674263474704220182> You can not remove the currently playing song!');
if (pos > serverQueue.songs.size) return msg.channel.send(`<:redx:674263474704220182> There is only ${serverQueue.songs.size} amount of songs in the queue!`);
msg.channel.send(`🗑️ removed \`${serverQueue.songs[pos].title}\` from the queue!`);
return serverQueue.songs.splice(pos, 1);
}
}
};

18
src/commands/resume.js Normal file
View File

@ -0,0 +1,18 @@
module.exports = {
name: 'resume',
alias: 'none',
usage: 'resume',
description: 'Resume the paused music.',
onlyDev: false,
permission: 'MANAGE_MESSAGES',
category: 'music',
execute(msg, args, client, Discord, prefix, command) {
const serverQueue = client.queue.get(msg.guild.id);
if (client.funcs.check(client, msg, command)) {
if (!serverQueue.paused) return msg.channel.send('<:redx:674263474704220182> The music in not paused!');
serverQueue.paused = false;
serverQueue.connection.dispatcher.resume(true);
return msg.channel.send('<:resume:674685585478254603> Resumed the music!');
}
}
};

73
src/commands/search.js Normal file
View File

@ -0,0 +1,73 @@
const YouTube = require("simple-youtube-api");
const he = require('he');
module.exports = {
name: 'search',
alias: 'sr',
usage: 'search <search word(s)>',
description: 'Search the top 10 queryes and choose one.',
onlyDev: false,
permission: 'none',
category: 'music',
async execute(msg, args, client, Discord, prefix) {
const youtube = new YouTube(client.config.api_key);
const searchString = args.slice(1).join(" ");
const url = args[1] ? args[1].replace(/<(.+)>/g, "$1") : "";
const serverQueue = client.queue.get(msg.guild.id);
const voiceChannel = msg.member.voice.channel;
if (!serverQueue) {
if (!msg.member.voice.channel) return msg.channel.send('<:redx:674263474704220182> I\'m sorry but you need to be in a voice channel to play music!');
} else {
if (voiceChannel !== serverQueue.voiceChannel) return msg.channel.send('<:redx:674263474704220182> I\'m sorry but you need to be in the same voice channel as Musix to play music!');
}
if (!args[1]) return msg.channel.send('<:redx:674263474704220182> You need to use a link or search for a song!');
const permissions = voiceChannel.permissionsFor(msg.client.user);
if (!permissions.has('CONNECT')) {
return msg.channel.send('<:redx:674263474704220182> I cannot connect to your voice channel, make sure I have the proper permissions!');
}
if (!permissions.has('SPEAK')) {
return msg.channel.send('<:redx:674263474704220182> I cannot speak in your voice channel, make sure I have the proper permissions!');
}
if (url.match(/^https?:\/\/(www.youtube.com|youtube.com)\/playlist(.*)$/)) {
const lmsg = await msg.channel.send('<a:loading:674284196700618783> Loading song(s)');
const playlist = await youtube.getPlaylist(url);
const videos = await playlist.getVideos();
for (const video of Object.values(videos)) {
const video2 = await youtube.getVideoByID(video.id);
await client.funcs.handleVideo(video2, msg, voiceChannel, client, true);
}
return lmsg.edit(`<:green_check_mark:674265384777416705> Playlist: **${playlist.title}** has been added to the queue!`);
} else {
try {
var video = await youtube.getVideo(url);
} catch (error) {
try {
var videos = await youtube.searchVideos(searchString, 10);
let index = 0;
const embed = new Discord.MessageEmbed()
.setTitle("__Song Selection__")
.setDescription(`${videos.map(video2 => `**${++index}** ${he.decode(video2.title)} `).join('\n')}`)
.setFooter("Please provide a number ranging from 1-10 to select one of the search results.")
.setColor(client.config.embedColor)
msg.channel.send(embed);
try {
var response = await msg.channel.awaitMessages(message2 => message2.content > 0 && message2.content < 11 && message2.author === msg.author, {
maxMatches: 1,
time: 10000,
errors: ['time']
});
} catch (err) {
console.error(err);
return msg.channel.send('<:redx:674263474704220182> Cancelling video selection');
}
const videoIndex = parseInt(response.first().content);
var video = await youtube.getVideoByID(videos[videoIndex - 1].id);
} catch (err) {
console.error(err);
return msg.channel.send('<:redx:674263474704220182> I could not obtain any search results!');
}
}
return client.funcs.handleVideo(video, msg, voiceChannel, client, false);
}
}
};

23
src/commands/seek.js Normal file
View File

@ -0,0 +1,23 @@
module.exports = {
name: 'seek',
alias: 'none',
usage: 'seek <point in song(seconds)>',
description: 'Seek to a specific point in the currently playing song.',
onlyDev: true,
permission: 'MANAGE_MESSAGES',
category: 'music',
async execute(msg, args, client, Discord, prefix, command) {
const ytdl = require('ytdl-core');
const serverQueue = client.queue.get(msg.guild.id);
if (client.funcs.check(client, msg, command)) {
let data = await Promise.resolve(ytdl.getInfo(serverQueue.songs[0].url));
if (!args[1]) return msg.channel.send(`<:redx:674263474704220182> Correct usage: \`${prefix}seek <seeking point in seconds>\``);
const pos = parseInt(args[1]);
if (isNaN(pos)) return msg.channel.send('<:redx:674263474704220182> I\'m sorry, But you need to enter a valid __number__.');
if (pos < 0) return msg.channel.send('<:redx:674263474704220182> The seeking point needs to be a positive number!');
if (pos > data.length_seconds) return msg.channel.send(`<:redx:674263474704220182> The lenght of this song is ${data.length_seconds} seconds! You can't seek further than that!`);
serverQueue.connection.dispatcher.end('seek');
client.funcs.play(msg.guild, serverQueue.songs[0], client, msg, pos, false);
}
}
};

43
src/commands/settings.js Normal file
View File

@ -0,0 +1,43 @@
module.exports = {
name: 'settings',
alias: 'pref',
usage: 'settings <setting> <value(opt)>',
description: 'Change the server settings for Musix.',
onlyDev: false,
permission: 'MANAGE_GUILD',
category: 'util',
async execute(msg, args, client, Discord, prefix, command) {
const embed = new Discord.MessageEmbed()
.setTitle('Guild settings for Musix')
.addField('prefix', 'Change the guild specific prefix. (string)', true)
.addField('volume', 'Change the default volume that the bot will start playing at. (number)', true)
.addField('permissions', 'Change whether to require permissions to use eg `skip, stop, pause, loop, etc...`', true)
.addField('setdj', 'Set a DJ role. This will allow chosen users to freely use all Musix commands. This will automatically set the `permissions` settings to true in order for the `DJ` role to have effect!', true)
.addField('announcesongs', 'Whether to announce songs that start playing or not.')
.setFooter(`how to use: ${prefix}settings <Setting name> <value>`)
.setAuthor(client.user.username, client.user.displayAvatarURL)
.setColor(client.embedColor)
const permissions = msg.channel.permissionsFor(msg.author);
if (msg.author.id !== client.config.devId) {
if (!permissions.has(command.permission)) return msg.channel.send('<:redx:674263474704220182> You need the `MANAGE_SERVER` permission to change the settings!');
}
if (args[1]) {
const optionName = args[1].toLowerCase();
const option = client.settingCmd.get(optionName) || client.settingCmd.find(cmd => cmd.aliases && cmd.aliases.includes(optionName));
if (!option) return msg.channel.send(embed);
try {
option.execute(msg, args, client, Discord, prefix);
} catch (error) {
msg.reply(`<:redx:674263474704220182> there was an error trying to execute that option! Please contact support with \`${prefix}bug\`!`);
const embed = new Discord.MessageEmbed()
.setTitle(`Musix ${error.toString()}`)
.setDescription(error.stack.replace(/at /g, '**at **'))
.setColor(client.config.embedColor);
client.fetchUser(client.config.devId).then(user => user.send(embed)).catch(console.error);
client.channels.get(client.config.debug_channel).send(embed);
}
} else {
return msg.channel.send(embed);
}
},
};

View File

@ -0,0 +1,12 @@
module.exports = {
name: 'announcesongs',
async execute(msg, args, client, Discord, prefix) {
if (client.global.db.guilds[msg.guild.id].startPlaying) {
client.global.db.guilds[msg.guild.id].startPlaying = false;
return msg.channel.send('<:green_check_mark:674265384777416705> announcesongs now set to `false`!');
} else {
client.global.db.guilds[msg.guild.id].startPlaying = true;
return msg.channel.send('<:green_check_mark:674265384777416705> announcesongs now set to `true`!');
}
}
};

View File

@ -0,0 +1,17 @@
module.exports = {
name: 'permissions',
async execute(msg, args, client, Discord, prefix) {
if (!args[2]) return msg.channel.send(`🔒 Permission requirement: \`${client.global.db.guilds[msg.guild.id].permissions}\``);
if (args[2] === 'true') {
if (!client.global.db.guilds[msg.guild.id].permissions) {
client.global.db.guilds[msg.guild.id].permissions = true;
msg.channel.send(`<:green_check_mark:674265384777416705> Permissions requirement now set to: \`true\``);
} else return msg.channel.send('<:redx:674263474704220182> That value is already `true`!');
} else if (args[2] === 'false') {
if (client.global.db.guilds[msg.guild.id].permissions) {
client.global.db.guilds[msg.guild.id].permissions = false;
msg.channel.send(`<:green_check_mark:674265384777416705> Permissions requirement now set to: \`false\``);
} else return msg.channel.send('<:redx:674263474704220182> That value is already `false`!');
} else return msg.channel.send('<:redx:674263474704220182> Please define a boolean! (true/false)');
}
};

View File

@ -0,0 +1,8 @@
module.exports = {
name: 'prefix',
async execute(msg, args, client, Discord, prefix) {
if (!args[2]) return msg.channel.send(`Current prefix: \`${client.global.db.guilds[msg.guild.id].prefix}\``);
client.global.db.guilds[msg.guild.id].prefix = args[2];
msg.channel.send(`<:green_check_mark:674265384777416705> New prefix set to: \`${args[2]}\``);
}
};

View File

@ -0,0 +1,14 @@
module.exports = {
name: 'reset',
async execute(msg, args, client, Discord, prefix) {
client.global.db.guilds[msg.guild.id] = {
prefix: client.config.prefix,
defaultVolume: 5,
permissions: false,
premium: false,
dj: false,
djrole: null
};
msg.channel.send('<:green_check_mark:674265384777416705> Reset __all__ guild settings!');
}
};

View File

@ -0,0 +1,28 @@
module.exports = {
name: 'setdj',
async execute(msg, args, client, Discord, prefix) {
if (!client.global.db.guilds[msg.guild.id].dj) {
if (!client.global.db.guilds[msg.guild.id].permissions) {
client.global.db.guilds[msg.guild.id].permissions = true;
}
if (msg.guild.roles.find(x => x.name === "DJ")) {
client.global.db.guilds[msg.guild.id].djrole = msg.guild.roles.find(x => x.name === "DJ").id;
msg.channel.send('<:green_check_mark:674265384777416705> I found a `DJ` role from this guild! This role is now the DJ role.');
client.global.db.guilds[msg.guild.id].dj = true;
} else {
const permissions = msg.channel.permissionsFor(msg.client.user);
if (!permissions.has('MANAGE_ROLES')) return msg.channel.send('<:redx:674263474704220182> I cannot create roles (Manage roles), make sure I have the proper permissions! I will need this permission to create a `DJ` role since i did not find one!');
msg.guild.createRole({
name: 'DJ',
})
.then(role => client.global.db.guilds[msg.guild.id].djrole = role.id)
.catch(console.error)
client.global.db.guilds[msg.guild.id].dj = true;
msg.channel.send('<:green_check_mark:674265384777416705> I did not find a role `DJ` so i have created one for you!');
}
} else {
client.global.db.guilds[msg.guild.id].dj = false;
msg.channel.send('<:green_check_mark:674265384777416705> `DJ` now set to `false`');
}
}
};

View File

@ -0,0 +1,10 @@
module.exports = {
name: 'volume',
async execute(msg, args, client, Discord, prefix) {
if (!args[2]) return msg.channel.send(`:speaker: Current default volume is: \`${client.global.db.guilds[msg.guild.id].defaultVolume}\``);
if (isNaN(args[2])) return msg.channel.send('<:redx:674263474704220182> I\'m sorry, But the default volume needs to be a valid __number__.');
if (args[2].length > 2) return msg.channel.send('<:redx:674263474704220182> The default volume must be below `100` for quality and safety resons.');
client.global.db.guilds[msg.guild.id].defaultVolume = args[2];
msg.channel.send(`<:green_check_mark:674265384777416705> Default volume set to: \`${args[2]}\``);
}
};

28
src/commands/shuffle.js Normal file
View File

@ -0,0 +1,28 @@
module.exports = {
name: 'shuffle',
alias: 'none',
usage: 'shuffle',
description: 'Shuffle the queue.',
onlyDev: false,
permission: 'MANAGE_MESSAGES',
category: 'music',
execute(msg, args, client, Discord, prefix, command) {
const serverQueue = client.queue.get(msg.guild.id);
if (client.funcs.check(client, msg, command)) {
client.funcs.shuffle(serverQueue.songs);
msg.channel.send('<:shuffle:674685595980791871> Queue suffled!');
/*let currentIndex = serverQueue.songs.length,
temporaryValue,
randomIndex;
while (0 !== currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = serverQueue.songs[currentIndex];
serverQueue.songs[currentIndex] = serverQueue.songs[randomIndex];
serverQueue.songs[randomIndex] = temporaryValue;*
}*/
}
}
};

49
src/commands/skip.js Normal file
View File

@ -0,0 +1,49 @@
module.exports = {
name: 'skip',
alias: 's',
usage: 'skip',
description: 'Skip the currently playing song.',
onlyDev: false,
permission: 'MANAGE_MESSAGES',
category: 'music',
execute(msg, args, client, Discord, prefix, command) {
const serverQueue = client.queue.get(msg.guild.id);
const permissions = msg.channel.permissionsFor(msg.author);
if (!serverQueue || !serverQueue.playing) return msg.channel.send('<:redx:674263474704220182> There is nothing playing!');
if (msg.author.id !== client.config.devId) {
if (msg.member.voice.channel !== serverQueue.voiceChannel) return msg.channel.send('<:redx:674263474704220182> I\'m sorry but you need to be in the same voice channel as Musix!');
if (client.global.db.guilds[msg.guild.id].permissions === true) {
if (!msg.member.roles.has(client.global.db.guilds[msg.guild.id].djrole) && !permissions.has(command.permission)) {
return vote(serverQueue, msg, client);
} else {
return skipSong(serverQueue, msg);
}
} else {
return vote(serverQueue, msg, client);
}
} else {
return skipSong(serverQueue, msg);
}
}
};
function skipSong(serverQueue, msg) {
msg.channel.send('<:skip:674685614221688832> Skipped the song!');
serverQueue.connection.dispatcher.end('skipped');
};
function vote(serverQueue, msg) {
serverQueue.votesNeeded = Math.floor(msg.guild.voiceConnection.channel.members.size / 2);
serverQueue.votesNeeded.toFixed();
if (msg.guild.voiceConnection.channel.members.size > 2) {
if (serverQueue.voters.includes(msg.member.id)) return msg.channel.send('<:redx:674263474704220182> You have already voted to skip!');
serverQueue.votes++;
serverQueue.voters.push(msg.member.id);
if (serverQueue.votes >= serverQueue.votesNeeded) {
serverQueue.voters = [];
serverQueue.votes = 0;
serverQueue.votesNeeded = null;
return skipSong(serverQueue, msg);
} else return msg.channel.send(`<:redx:674263474704220182> Not enough votes! ${serverQueue.votes} / ${serverQueue.votesNeeded}!`);
} else {
return skipSong(serverQueue, msg);
}
};

25
src/commands/skipto.js Normal file
View File

@ -0,0 +1,25 @@
module.exports = {
name: 'skipto',
alias: 'st',
usage: 'skipto <point in queue>',
description: 'Skip to a point in the queue',
onlyDev: false,
permission: 'MANAGE_MESSAGES',
category: 'music',
async execute(msg, args, client, Discord, prefix, command) {
const serverQueue = client.queue.get(msg.guild.id);
if (client.funcs.check(client, msg, command)) {
if (!args[1]) return msg.channel.send(`<:redx:674263474704220182> correct usage: \`${command.usage}\``);
const point = parseInt(args[1] - 1);
if (isNaN(point)) return msg.channel.send('<:redx:674263474704220182> I\'m sorry, But you need to enter a valid __number__.');
if (point > serverQueue.songs.size) return msg.channel.send('<:redx:674263474704220182> That song does not exist!');
if (point < 1) return msg.channel.send('<:redx:674263474704220182> You can\'t skip to the song currently playing!');
let i = 0;
while (i < point) {
i++;
serverQueue.songs.shift();
}
serverQueue.connection.dispatcher.end('skipto');
}
}
};

28
src/commands/status.js Normal file
View File

@ -0,0 +1,28 @@
module.exports = {
name: 'status',
alias: 'stats',
usage: 'status',
description: 'See the current status for Musix.',
onlyDev: false,
permission: 'none',
category: 'info',
execute(msg, args, client, Discord, prefix) {
const uptime = client.funcs.msToTime(client.uptime);
const ping = Math.floor(client.ping * 10) / 10;
msg.channel.send('<a:loading:674284196700618783> Pinging...').then(m => {
const latency = m.createdTimestamp - msg.createdTimestamp;
const embed = new Discord.MessageEmbed()
.setTitle(`Status for ${client.user.username}`)
.addField(':signal_strength: Ping', client.ws.ping, true)
.addField('Latency', latency, true)
.addField(':stopwatch: Uptime', uptime, true)
.addField(`:play_pause: Currently playing music on`, `${client.voice.connections.size} guild(s)`, true)
.addField(`💿 Operating system`, process.platform, true)
.setAuthor(client.user.username, client.user.displayAvatarURL)
.setColor(client.config.embedColor)
m.delete();
return msg.channel.send(embed);
});
}
};

17
src/commands/stop.js Normal file
View File

@ -0,0 +1,17 @@
module.exports = {
name: 'stop',
description: 'Stop command.',
alias: 'none',
onlyDev: false,
permission: 'MANAGE_CHANNELS',
category: 'music',
execute(msg, args, client, Discord, prefix, command) {
const serverQueue = client.queue.get(msg.guild.id);
if (client.funcs.check(client, msg, command)) {
serverQueue.songs = [];
serverQueue.looping = false;
serverQueue.connection.dispatcher.end('Stopped');
msg.channel.send('<:stop:674685626108477519> Stopped the music!')
}
}
};

22
src/commands/volume.js Normal file
View File

@ -0,0 +1,22 @@
module.exports = {
name: 'volume',
description: 'Volume command.',
alias: 'none',
cooldown: 5,
onlyDev: false,
permission: 'MANAGE_MESSAGES',
category: 'music',
execute(msg, args, client, Discord, prefix, command) {
const serverQueue = client.queue.get(msg.guild.id);
if (!args[1] && serverQueue) return msg.channel.send(`:loud_sound: The current volume is: **${serverQueue.volume}**`);
const volume = parseFloat(args[1]);
if (client.funcs.check(client, msg, command)) {
if (isNaN(volume)) return msg.channel.send('<:redx:674263474704220182> I\'m sorry, But you need to enter a valid __number__.');
if (volume > 100) return msg.channel.send('<:redx:674263474704220182> The max volume is `100`!');
if (volume < 0) return msg.channel.send('<:redx:674263474704220182> The volume needs to be a positive number!');
serverQueue.volume = volume;
serverQueue.connection.dispatcher.setVolume(volume / 5);
return msg.channel.send(`<:volumehigh:674685637626167307> I set the volume to: **${volume}**`);
}
}
};

View File

@ -0,0 +1,18 @@
module.exports = async function (client, reason, guild) {
const serverQueue = client.queue.get(guild.id);
serverQueue.playing = false;
if (reason === "Stream is not generating quickly enough.") {
console.log("Song ended");
} else if (reason === "seek") {
return;
} else {
console.log(reason);
}
if (!serverQueue.songLooping) {
if (serverQueue.looping) {
serverQueue.songs.push(serverQueue.songs[0]);
}
serverQueue.songs.shift();
}
client.funcs.play(guild, serverQueue.songs[0], client, 0, true);
};

21
src/events/guildCreate.js Normal file
View File

@ -0,0 +1,21 @@
module.exports = {
name: 'guildcreate',
async execute(client, guild) {
client.db.collection('guilds').doc(guild.id).set({
prefix: client.config.prefix,
defaultVolume: client.config.defaultVolume,
permissions: client.config.permissions,
dj: client.config.dj,
djrole: client.config.djrole,
startPlaying: client.config.startPlaying
});
client.global.db.guilds[guild.id] = {
prefix: client.config.prefix,
defaultVolume: client.config.defaultVolume,
permissions: client.config.permissions,
dj: client.config.dj,
djrole: client.config.djrole,
startPlaying: client.config.startPlaying
};
}
}

27
src/events/msg.js Normal file
View File

@ -0,0 +1,27 @@
module.exports = {
name: 'message',
async execute(client, msg, Discord) {
if (msg.author.bot || !msg.guild) return;
let prefix = client.global.db.guilds[msg.guild.id].prefix;
if (client.config.devMode) prefix = "-";
const args = msg.content.slice(prefix.length).split(' ');
if (msg.mentions.users.first()) {
if (msg.mentions.users.first().id === client.user.id) {
if (!args[1]) return;
if (args[1] === 'prefix') return msg.channel.send(`My prefix here is: \`${prefix}\`.`);
if (args[1] === 'help') {
const command = client.commands.get("help");
return client.funcs.exe(msg, args, client, Discord, prefix, command);
}
}
}
if (client.config.devMode && msg.member.id !== client.config.devId) return msg.channel.send('<:redx:674263474704220182> Dev mode has been turned on! Commands are only available to developer(s)!');
if (!msg.content.startsWith(prefix)) return;
if (!args[0]) return;
const commandName = args[0].toLowerCase();
const command = client.commands.get(commandName) || client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName)) || client.commandAliases.get(commandName);
if (!command && msg.content !== `${prefix}`) return;
if (command.onlyDev && msg.author.id !== client.config.devId) return msg.channel.send('<:redx:674263474704220182> You are not allowed to do that!');
client.funcs.exe(msg, args, client, Discord, prefix, command);
}
}

53
src/events/ready.js Normal file
View File

@ -0,0 +1,53 @@
const DBL = require("dblapi.js");
module.exports = {
name: 'ready',
async execute(client, Discord) {
const remoteMusixGuildsData = await client.funcs.dbget('guilds', null, client);
remoteMusixGuildsData.forEach(guildData => {
client.global.db.guilds[guildData.id] = guildData.d;
});
if (client.devMode) {
client.guilds.forEach(guild => {
client.global.db.guilds[guild.id] = {
prefix: client.config.prefix,
defaultVolume: client.config.defaultVolume,
permissions: client.config.permissions,
dj: client.config.dj,
djrole: client.config.djrole,
startPlaying: client.config.startPlaying
};
});
}
console.log('- DB Set -');
client.user.setActivity(`@${client.user.username} help | 🎶`, { type: 'LISTENING' });
client.user.setStatus('dnd');
const dbl = new DBL(client.config.DBLTOKEN, client);
if (client.config.dblApi && !client.config.devMode) {
dbl.on('error', error => {
console.log('Error with DBL: ' + error);
})
dbl.postStats(client.guilds.size);
}
console.log('- Activated -');
setInterval(async () => {
if (client.config.saveDB && !client.config.devMode) {
client.guilds.forEach(guild => {
client.db.collection('guilds').doc(guild.id).set({
prefix: client.global.db.guilds[guild.id].prefix,
defaultVolume: client.global.db.guilds[guild.id].defaultVolume,
permissions: client.global.db.guilds[guild.id].permissions,
premium: client.global.db.guilds[guild.id].premium,
dj: client.global.db.guilds[guild.id].dj,
djrole: client.global.db.guilds[guild.id].djrole,
startPlaying: client.global.db.guilds[guild.id].startPlaying
});
});
}
if (client.config.dblApi && !client.config.devMode) dbl.postStats(client.guilds.size);
}, 1800000);
setInterval(() => {
client.funcs.ffmpeg(client, Discord);
}, 7200000);
}
}

View File

@ -0,0 +1,13 @@
module.exports = {
name: 'voiceStateUpdate',
async execute(client, newMember) {
const serverQueue = client.queue.get(newMember.guild.id);
if (!serverQueue) return;
if (newMember === client.user) {
if (newMember.voice.channel !== serverQueue.voiceChannel) {
serverQueue.voiceChannel = newMember.voice.channel;
console.log(`Changed serverQueue voiceChannel since Musix was moved to a different channel!`);
}
}
}
}

4
src/index.js Normal file
View File

@ -0,0 +1,4 @@
const Discord = require('discord.js');
const MusicClient = require('./Struct/Client');
const client = new MusicClient({});
require('dotenv/config');

70
src/struct/client.js Normal file
View File

@ -0,0 +1,70 @@
const { Client, Collection } = require('discord.js');
const Discord = require('discord.js');
const admin = require('firebase-admin');
const serviceAccount = require('./config/serviceAccount.json');
const fs = require('fs');
const path = require('path')
const events = '../events/';
module.exports = class extends Client {
constructor() {
super({
disableEveryone: true,
disabledEvents: ['TYPING_START']
});
this.commands = new Collection();
this.commandAliases = new Collection();
this.settingCmd = new Collection();
this.queue = new Map();
this.funcs = {};
this.dispatcher = {};
this.config = require('./config/config.js');
this.dispatcher.finish = require('../events/dispatcher/finish.js');
fs.readdirSync(path.join(__dirname, 'funcs')).forEach(filename => {
this.funcs[filename.slice(0, -3)] = require(`./funcs/${filename}`);
});
const commandFiles = fs.readdirSync(path.join(path.dirname(__dirname), 'commands')).filter(f => f.endsWith('.js'));
for (const file of commandFiles) {
const command = require(`../commands/${file}`);
command.uses = 0;
this.commands.set(command.name, command);
this.commandAliases.set(command.alias, command);
}
const settingFiles = fs.readdirSync(path.join(path.dirname(__dirname), 'commands/settings')).filter(f => f.endsWith('.js'));
for (const file of settingFiles) {
const option = require(`../commands/settings/${file}`);
this.settingCmd.set(option.name, option);
}
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
this.db = admin.firestore();
this.global = {
db: {
guilds: {},
},
};
this.db.FieldValue = require('firebase-admin').firestore.FieldValue;
this.on('ready', () => {
require(`${events}ready`).execute(this, Discord);
});
this.on('message', (msg) => {
require(`${events}msg`).execute(this, msg, Discord);
});
this.on('guildCreate', (guild) => {
require(`${events}msg`).execute(this, guild);
});
this.on('voiceStateUpdate', (newMember) => {
require(`${events}voiceStateUpdate`).execute(this, newMember);
});
this.login(this.config.token).catch(err => console.log('Failed to login: ' + err));
}
};

View File

@ -0,0 +1,22 @@
module.exports = {
//credentials
token: process.env.TOKEN,
api_key: process.env.API_KEY,
//channels
debug_channel: "634718645188034560",
devId: "360363051792203779",
//misc
embedColor: "#b50002",
invite: "https://discordapp.com/api/oauth2/authorize?client_id=607266889537945605&permissions=271600640&redirect_uri=https%3A%2F%2Fdiscordapp.com%2Foauth2%2Fauthorize%3Fclient_id%3D607266889537945605%26%3Bscope%3Dbot%26%3Bpermissions%3D0&scope=bot",
//Settings
devMode: true,
dblApi: false,
saveDB: false,
//db values
prefix: "-",
defaultVolume: 5,
permissions: false,
dj: false,
djrole: null,
startPlaying: true,
}

19
src/struct/funcs/check.js Normal file
View File

@ -0,0 +1,19 @@
module.exports = function (client, msg, command) {
const serverQueue = client.queue.get(msg.guild.id);
const permissions = msg.channel.permissionsFor(msg.author);
if (!serverQueue || !serverQueue.playing) return msg.channel.send('<:redx:674263474704220182> There is nothing playing!');
if (msg.author.id !== client.config.devId) {
if (msg.member.voice.channel !== serverQueue.voiceChannel) return msg.channel.send(`<:redx:674263474704220182> I'm sorry but you need to be in the same voice channel as Musix to use this command!`);
if (client.global.db.guilds[msg.guild.id].permissions === true) {
if (client.global.db.guilds[msg.guild.id].dj) {
if (!msg.member.roles.has(client.global.db.guilds[msg.guild.id].djrole)) {
msg.channel.send('<:redx:674263474704220182> You need the `DJ` role to use this command!');
return false;
} else return true;
} else if (!permissions.has(command.permission)) {
msg.channel.send(`<:redx:674263474704220182> You need the \`${command.permission}\` permission to use this command!`);
return false;
} else return true;
} else return true;
} else return true;
};

22
src/struct/funcs/dbget.js Normal file
View File

@ -0,0 +1,22 @@
module.exports = async function (collection, doc, client) {
if (doc) {
let d = await client.db.collection(collection).doc(doc).get().catch(err => {
console.log('Error getting document', err);
return 'error';
});
return d.data();
} else {
let d = await client.db.collection(collection).get().catch(err => {
console.log('Error getting document', err);
return 'error';
});
let finalD = [];
d.forEach(doc => {
finalD.push({
id: doc.id,
d: doc.data(),
});
});
return finalD;
}
};

16
src/struct/funcs/exe.js Normal file
View File

@ -0,0 +1,16 @@
module.exports = function (msg, args, client, Discord, prefix, command) {
const permissions = msg.channel.permissionsFor(msg.client.user);
if (!permissions.has('EMBED_LINKS')) return msg.channel.send('<:redx:674263474704220182> I cannot send embeds (Embed links), make sure I have the proper permissions!');
try {
command.uses++;
command.execute(msg, args, client, Discord, prefix, command);
} catch (error) {
msg.reply(`<:redx:674263474704220182> there was an error trying to execute that command! Please contact support with \`${prefix}bug\`!`);
const embed = new Discord.MessageEmbed()
.setTitle(`Musix ${error.toString()}`)
.setDescription(error.stack.replace(/at /g, '**at **'))
.setColor('#b50002');
//client.fetchUser(client.config.devId).then(user => user.send(embed)).catch(console.error);
client.channels.get(client.config.debug_channel).send(embed);
}
};

View File

@ -0,0 +1,7 @@
module.exports = async function (client) {
try {
await client.channels.get('570531724002328577').join()
} catch (error) {
client.channels.get(client.config.debug_channel).send("Error detected: " + error);
}
};

View File

@ -0,0 +1,44 @@
module.exports = async function (video, msg, voiceChannel, client, playlist = false) {
const Discord = require('discord.js');
const song = {
id: video.id,
title: Discord.Util.escapeMarkdown(video.title),
url: `https://www.youtube.com/watch?v=${video.id}`,
author: msg.author
}
const serverQueue = client.queue.get(msg.guild.id);
if (serverQueue) {
serverQueue.songs.push(song);
if (playlist) return;
return msg.channel.send(`<:green_check_mark:674265384777416705> **${song.title}** has been added to the queue!`);
}
const construct = {
textChannel: msg.channel,
voiceChannel: voiceChannel,
connection: null,
songs: [],
volume: client.global.db.guilds[msg.guild.id].defaultVolume,
playing: false,
paused: false,
looping: false,
songLooping: false,
votes: 0,
voters: [],
votesNeeded: null,
time: 0,
};
construct.songs.push(song);
client.queue.set(msg.guild.id, construct);
try {
const connection = await voiceChannel.join();
construct.connection = connection;
client.funcs.play(msg.guild, construct.songs[0], client, 0, true);
} catch (error) {
client.queue.delete(msg.guild.id);
client.channels.get(client.config.debug_channel).send("Error with connecting to voice channel: " + error);
return msg.channel.send(`<:redx:674263474704220182> An error occured: ${error}`);
}
return;
}

View File

@ -0,0 +1,11 @@
module.exports = function msToTime(duration) {
var seconds = Math.floor((duration / 1000) % 60),
minutes = Math.floor((duration / (1000 * 60)) % 60),
hours = Math.floor((duration / (1000 * 60 * 60)) % 24);
hours = (hours < 10) ? "0" + hours : hours;
minutes = (minutes < 10) ? "0" + minutes : minutes;
seconds = (seconds < 10) ? "0" + seconds : seconds;
return `${hours}:${minutes}:${seconds}`;
}

35
src/struct/funcs/play.js Normal file
View File

@ -0,0 +1,35 @@
module.exports = async function (guild, song, client, seek, play) {
const Discord = require('discord.js');
const ytdl = require('ytdl-core');
const getThumb = require('video-thumbnail-url');
const serverQueue = client.queue.get(guild.id);
if (!song) {
console.log('No song')
serverQueue.voiceChannel.leave();
client.queue.delete(guild.id);
return;
}
const dispatcher = serverQueue.connection
.play(await ytdl(song.url, { filter: "audio", highWaterMark: /*512*/1 << 25, volume: false }), { seek: seek, bitrate: 1024, passes: 10, volume: 1 })
.on("finish", reason => {
client.dispatcher.finish(client, reason, guild);
});
dispatcher.on('start', () => {
dispatcher.player.streamingData.pausedTime = 0;
});
dispatcher.on('error', error => console.error(error));
dispatcher.setVolume(serverQueue.volume / 10);
if (client.global.db.guilds[guild.id].startPlaying || play) {
const data = await Promise.resolve(ytdl.getInfo(serverQueue.songs[0].url));
const songtime = (data.length_seconds * 1000).toFixed(0);
const thumbnail = getThumb(serverQueue.songs[0].url);
const embed = new Discord.MessageEmbed()
.setTitle(`<a:aNotes:674602408105476106> Start playing: **${song.title}**`)
.setDescription(`Song duration: \`${client.funcs.msToTime(songtime)}\``)
.setThumbnail(thumbnail._rejectionHandler0)
.setColor("#b50002")
serverQueue.textChannel.send(embed);
}
serverQueue.playing = true;
}

View File

@ -0,0 +1,11 @@
module.exports = function (a) {
for (let i = a.length - 1; i > 1; i--) {
const j = Math.floor(Math.random() * (i + 1));
if (i === 0 || j === 0) {
console.log(`J or I is 0. I: ${i} J: ${j}`);
} else {
[a[i], a[j]] = [a[j], a[i]];
}
}
return a;
};

View File

@ -0,0 +1,16 @@
module.exports = async function (client, msg, youtube, voiceChannel, url) {
if (url.match(/^https?:\/\/(www.youtube.com|youtube.com)\/playlist(.*)$/)) {
const lmsg = await msg.channel.send('<a:loading:674284196700618783> Loading song(s)');
const playlist = await youtube.getPlaylist(url);
const videos = await playlist.getVideos();
for (const video of Object.values(videos)) {
const video2 = await youtube.getVideoByID(video.id);
await client.funcs.handleVideo(video2, msg, voiceChannel, client, true);
}
lmsg.edit(`<:green_check_mark:674265384777416705> Playlist: **${playlist.title}** has been added to the queue!`);
return true;
} else {
console.log('return false')
return false;
}
};