Initial gitea commit
This commit is contained in:
commit
d647273993
|
@ -0,0 +1,4 @@
|
|||
node_modules
|
||||
npm-debug.log
|
||||
Dockerfile
|
||||
.dockerignore
|
|
@ -0,0 +1,9 @@
|
|||
node_modules
|
||||
backups
|
||||
secret.js
|
||||
lavalink/logs
|
||||
lavalink/application.yml
|
||||
lavalink/Lavalink.jar.old
|
||||
npm-debug.log
|
||||
config.json
|
||||
utils/Utils.js.old
|
|
@ -0,0 +1,165 @@
|
|||
module.exports = class App
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
var secret = require("./secret.js");
|
||||
this.bot = new Eris(secret.discord, { maxShards: 'auto' });
|
||||
this.commands = new Commands(this);
|
||||
this.version = require('./package.json').version;
|
||||
this.config = JSON.parse(fs.readFileSync("./config.json"));
|
||||
|
||||
if(this.config.disableDBL == false)
|
||||
{
|
||||
setInterval(() => {
|
||||
DLA.postGuilds(this.bot, secret.tokens);
|
||||
}, 1800000);
|
||||
}
|
||||
|
||||
this.db = new Database(this);
|
||||
|
||||
this.bot.on("ready", this.onReady.bind(this));
|
||||
this.bot.on("guildCreate", this.onJoin.bind(this));
|
||||
this.bot.on("guildMemberAdd", this.onMemberJoined.bind(this));
|
||||
this.bot.on("messageCreate", this.onMessage.bind(this));
|
||||
this.bot.on("error", this.onDisconnect.bind(this));
|
||||
|
||||
this.bot.connect();
|
||||
}
|
||||
|
||||
onReady()
|
||||
{
|
||||
console.log("Vertbot is now online.");
|
||||
this.bot.editStatus("online", {name: "v-help for info", type: 0})
|
||||
var secret = require("./secret.js");
|
||||
if(this.config.disableDBL == false) { DLA.postGuilds(this.bot, secret.tokens); } //Post the guild stats to bot list apon launch
|
||||
//TODO: init function?
|
||||
this.lavalink = new Lavalink(this);
|
||||
|
||||
//this.settings = new Settings(this);
|
||||
}
|
||||
|
||||
onPosted()
|
||||
{
|
||||
console.log("Server count posted!");
|
||||
}
|
||||
|
||||
onDBLError()
|
||||
{
|
||||
console.error("Server count could not be posted. This may be because of the fact there is no token");
|
||||
}
|
||||
|
||||
onDisconnect(err, id)
|
||||
{
|
||||
//this.bot.disconnect();
|
||||
//console.log("Lost connection to discord, trying to reconnect...");
|
||||
//this.bot.connect();
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
onJoin(guild)
|
||||
{
|
||||
var channel = U.getLogicalChannel(this, guild);
|
||||
|
||||
if(channel != null)
|
||||
{
|
||||
this.bot.createMessage(channel.id, U.createWelcomeEmbed(this));
|
||||
}
|
||||
}
|
||||
|
||||
onMemberJoined(guild, member)
|
||||
{
|
||||
if(member.username.toLowerCase().includes("h0nd"))
|
||||
{
|
||||
member.ban(7, "Shitty fucking spammer");
|
||||
}
|
||||
}
|
||||
|
||||
async onMessage(msg)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(!msg.channel.type == 1)
|
||||
{
|
||||
//var prefix = (await this.db.getGuildSettings(msg.channel.guild.id)).prefix || this.config.prefix;
|
||||
var prefix = (this.bot.user.id == "430118450795380736") ? "[=" : (await this.db.getGuildSettings(msg.channel.guild.id)).prefix || this.config.prefix;
|
||||
|
||||
var mention = msg.content.startsWith(this.bot.user.mention) ? "<@" + this.bot.user.id + ">" : "<@!" + this.bot.user.id + ">"
|
||||
|
||||
if((msg.content.startsWith(prefix) || msg.content.startsWith(mention)) && !msg.author.bot)
|
||||
{
|
||||
//the command
|
||||
var text = msg.content.startsWith(prefix) ? msg.content.slice(prefix.length).trim() : msg.content.slice((mention).length).trim(); //TODO: trim?
|
||||
|
||||
this.commands.doCommand(msg, this, text); //Command system
|
||||
}
|
||||
|
||||
if(msg.author.bot && msg.author.id == "817790099823525909")
|
||||
{
|
||||
//Scramble!
|
||||
if(msg.embeds.length > 0)
|
||||
{
|
||||
if(msg.embeds[0].title == "Scramble!")
|
||||
{
|
||||
var word = msg.embeds[0].description.split("\n")[1];
|
||||
console.log(word);
|
||||
var words = ["bell","jail","heart","Mickey Mouse","bus","butterfly","elephant","flower","turtle","snowflake","candy","key","sun","starfish","button","leg","table","ghost","orange","house","nail","apple","football","love","ants","beak","feet","river","lemon","daisy","jar","clock","flag","snail","smile","island","inchworm","mitten","king","bench","dog","knee","horse","music","square","hair","doll","sea turtle","book","whale","arm","seashell","shirt","purse","stairs","oval","camera","truck","motorcycle","moon","fly","pillow","coat","helicopter","bowl","mouth","chicken","light","hippo","woman","chimney","grapes","jacket","float","rock","snowman","bread","snake","corn","cup","baseball","pizza","beach","bug","sunglasses","rain","robot","cherry","bunny","lamp","popsicle","ears","lollipop","socks","ladybug","triangle","zebra","broom","mouse","caterpillar","dragon","bone","door","desk","grass","car","curl","cat","ring","worm","banana","mountain","water","ball","roly poly/pill bug/doodle bug","legs","sheep","rocket","man","coin","ant","night","crayon","ocean","swimming pool","bumblebee","swing","person","blanket","bark","slide","boy","hat","star","mountains","diamond","tree","bow","computer","zigzag","dinosaur","balloon","cow","boat","bunk bed","giraffe","eyes","bird","chair","comb","circle","nose","hook","feather","bear","bee","ear","leaf","pig","drum","pie","milk","suitcase","fire","window","wheel","glasses","kite","box","cupcake","zoo","girl","pants","bed","rainbow","hamburger","jellyfish","bracelet","baby","octopus","ship","eye","lips","alive","face","dream","spider web","angel","train","egg","tail","alligator","finger","pen","bike","fish","cheese","bounce","blocks","kitten","bathroom","crack","skateboard","fork","bridge","plant","owl","branch","ice cream cone","monkey","spoon","shoe","duck","crab","lizard","lion","backpack","sea","hand","head","frog","carrot","cloud","candle","line","bat","neck","cube","family","airplane","Earth","spider","basketball","monster","pencil","cookie","rabbit"];
|
||||
var scram = await unscramble(word, words);
|
||||
console.log(scram);
|
||||
this.bot.createMessage(msg.channel.id, U.createQuickEmbed("Word Unscrambled!", "Try: `" + scram.join(", ") + "`"));
|
||||
}
|
||||
|
||||
//Translate!
|
||||
|
||||
if(msg.embeds[0].title == "Translate!")
|
||||
{
|
||||
var word = msg.embeds[0].description.split("\n")[1];
|
||||
console.log(word);
|
||||
const res = await fetch("https://libretranslate.de/translate", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
q: word,
|
||||
source: "es",
|
||||
target: "en",
|
||||
format: "text",
|
||||
api_key: ""
|
||||
}),
|
||||
headers: { "Content-Type": "application/json" }
|
||||
});
|
||||
var json = await res.json();
|
||||
var tran = json.translatedText;
|
||||
console.log(json);
|
||||
console.log(tran);
|
||||
this.bot.createMessage(msg.channel.id, U.createQuickEmbed("Word Translated!", "The word is: `" + tran + "`"));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(!msg.author.bot && !msg.author.id == "817790099823525909")
|
||||
{
|
||||
this.bot.createMessage(msg.channel.id, U.createErrorEmbed("This is a DM chat", "I can't do anything in dms. If you need a gf that bad go outside"));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
console.log(e);
|
||||
//this.bot.createMessage(msg.channel.id, "" + (typeof e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//var YouTube = require('youtube-node');
|
||||
var Eris = require('eris');
|
||||
var assert = require("assert");
|
||||
//var unscramble = require('unscramble');
|
||||
const unscramble = require('word-unscrambler');
|
||||
//const { translate } = require('free-translate');
|
||||
const fetch = require('node-fetch');
|
||||
var U = require('./utils/Utils.js');
|
||||
var DLA = require('./utils/Discord-List-api.js');
|
||||
var Commands = require("./commands/Commands.js");
|
||||
var Lavalink = require("./utils/Lavalink.js");
|
||||
var Database = require("./utils/Database.js");
|
||||
var Settings = require("./utils/Settings.js");
|
||||
//var RestartHandler = require("./utils/RestartHandler.js");
|
||||
var fs = require("fs");
|
|
@ -0,0 +1,16 @@
|
|||
FROM node:19-alpine
|
||||
|
||||
# Create app directory
|
||||
WORKDIR /app
|
||||
#copy package(lock).json
|
||||
COPY package*.json ./
|
||||
#install git (needed in alpine for git repos)
|
||||
#RUN apk add git
|
||||
#install packages
|
||||
RUN npm ci --only=production
|
||||
# Bundle app source
|
||||
COPY . .
|
||||
#ports and env
|
||||
#EXPOSE 80
|
||||
|
||||
CMD [ "node", "main.js" ]
|
|
@ -0,0 +1,26 @@
|
|||
# DON'T BE A DICK PUBLIC LICENSE
|
||||
|
||||
> Version 1.1, December 2016
|
||||
|
||||
> Copyright (C) 2019 Kaydax & tehZevo
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document.
|
||||
|
||||
> DON'T BE A DICK PUBLIC LICENSE
|
||||
> TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
1. Do whatever you like with the original work, just don't be a dick.
|
||||
|
||||
Being a dick includes - but is not limited to - the following instances:
|
||||
|
||||
1a. Outright copyright infringement - Don't just copy this and change the name.
|
||||
1b. Selling the unmodified original with no work done what-so-ever, that's REALLY being a dick.
|
||||
1c. Modifying the original work to contain hidden harmful content. That would make you a PROPER dick.
|
||||
|
||||
2. If you become rich through modifications, related works/services, or supporting the original work,
|
||||
share the love. Only a dick would make loads off this work and not buy the original work's
|
||||
creator(s) a pint.
|
||||
|
||||
3. Code is provided with no warranty. Using somebody else's code and bitching when it goes wrong makes
|
||||
you a DONKEY dick. Fix the problem yourself. A non-dick would submit the fix back.
|
|
@ -0,0 +1,2 @@
|
|||
# Vertbot
|
||||
Vertbot - A lightweight lag free music bot
|
|
@ -0,0 +1,212 @@
|
|||
module.exports = class Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
this.name = "";
|
||||
this.aliases = [];
|
||||
this.usage = "";
|
||||
this.description = "";
|
||||
this.commandFiles = [];
|
||||
this.commands = [];
|
||||
//required permissions (must have all; except for hierarchy)
|
||||
this.permissions = [];
|
||||
this.parent = null;
|
||||
//TODO: guild/dm commands?
|
||||
}
|
||||
|
||||
setParent(parent)
|
||||
{
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/** returns the root of the command tree */
|
||||
getRoot()
|
||||
{
|
||||
var parent = this.parent;
|
||||
|
||||
while(parent.parent != null)
|
||||
{
|
||||
parent = parent.parent;
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
init()
|
||||
{
|
||||
//TODO: other init stuff
|
||||
this.reload();
|
||||
}
|
||||
|
||||
reload()
|
||||
{
|
||||
this.commands = this.commandFiles.map((e) =>
|
||||
{
|
||||
//console.log("loading " + e + " in " + this.constructor.name);
|
||||
var sub = new (require(e))();
|
||||
sub.setParent(this);
|
||||
return sub;
|
||||
});
|
||||
}
|
||||
|
||||
async doCommand(message, app, text)
|
||||
{
|
||||
text = text || message.content;
|
||||
|
||||
//Get the playlist settings for dj mode when checking permissions
|
||||
var pl = await app.db.getPlaylist(message.channel.guild.id);
|
||||
//grab permissions for user that sent the message
|
||||
var perms = await P.getPerms(app, message);
|
||||
|
||||
var ret = this.findCommand(text);
|
||||
|
||||
if(ret != null && ret.sub != this)
|
||||
{
|
||||
if(perms.includes("banned") && !perms.includes("dev"))
|
||||
{
|
||||
app.bot.createMessage(message.channel.id, U.createErrorEmbed("You seem to be banned", "You seem to be banned from using the bot by a developer, sorry about that..."));
|
||||
return;
|
||||
}
|
||||
|
||||
if(!U.canUseCommand(perms, ret.sub, pl))
|
||||
{
|
||||
//app.bot.createMessage(message.channel.id, U.wrapCode("ur perms here: " + Array.from(perms).join(" ")));
|
||||
app.bot.createMessage(message.channel.id, U.createErrorEmbed("You don't have permissions", "You seem to not have `" + ret.sub.permissions.join(", ") + "`"));
|
||||
return;
|
||||
}
|
||||
|
||||
ret.sub.doCommand(message, app, ret.text);
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO: display help, but not on root level
|
||||
//TODO: we can use this != root check for that
|
||||
if(this.parent != null)
|
||||
{
|
||||
app.bot.createMessage(message.channel.id, U.wrapMention(message, U.wrapCode(this.getHelp())));
|
||||
}
|
||||
}
|
||||
|
||||
/** pass a command FILENAME not an object */
|
||||
addCommand(commandFile)
|
||||
{
|
||||
if(this.commandFiles.includes(commandFile))
|
||||
{
|
||||
console.log("REEEEEEE YOU ALREADY ADDED THIS COMMAND");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.commandFiles.push(commandFile);
|
||||
|
||||
this.reload();
|
||||
}
|
||||
|
||||
findCommand(text)
|
||||
{
|
||||
var ret = {};
|
||||
ret.text = null;
|
||||
ret.sub = null;
|
||||
|
||||
text = text.trim(); //TODO: hmm
|
||||
|
||||
var token = text.split(/\s+/)[0]; //grab the first token in text
|
||||
token = token.toLowerCase() //just to be safe
|
||||
|
||||
var matches = this.findMatchingCommands(token);
|
||||
|
||||
//no matches found
|
||||
if(matches.length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//TODO: filter out commands user cant access?
|
||||
//matches = matches.filter((e) => U.canUseCommand(perms, e));
|
||||
|
||||
return {sub: matches[0], text: text.slice(token.length).trim()}; //TODO: trim?
|
||||
}
|
||||
|
||||
/** pass it a single command token, if perms is passed, performs permission checks, returns {cmd, canUse} */
|
||||
findMatchingCommands(token)
|
||||
{
|
||||
token = token.toLowerCase(); //just to be safe
|
||||
|
||||
var commands = [];
|
||||
for(var i = 0; i < this.commands.length; i++)
|
||||
{
|
||||
var sub = this.commands[i];
|
||||
|
||||
if(sub.name.toLowerCase().startsWith(token) || sub.aliases.some((e) => e.toLowerCase().startsWith(token)))
|
||||
{
|
||||
//var canUse = perms == null ? true : U.canUseCommand(perms, e);
|
||||
//TODO: command visibility based on "hidden" and permissions (recursively?)
|
||||
commands.push(sub);
|
||||
}
|
||||
|
||||
//grab subcommand's matches too
|
||||
commands = commands.concat(sub.findMatchingCommands(token));
|
||||
}
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
/** padLength = how much to pad name+usage by */
|
||||
formatHelp(name, usage, desc, padLength)
|
||||
{
|
||||
var nameUsage = name + " " + usage;
|
||||
padLength = padLength == null ? nameUsage.length - 1 : padLength;
|
||||
|
||||
nameUsage = pad(Array(padLength + 2).join(" "), nameUsage);
|
||||
|
||||
return nameUsage + " | " + desc; //TODO: OwO
|
||||
}
|
||||
|
||||
/** if self, then print command's own help line, otherwise, print help for all subcommands */
|
||||
getHelp(self)
|
||||
{
|
||||
if(self)
|
||||
{
|
||||
return this.formatHelp(this.name, this.usage, this.description);
|
||||
}
|
||||
|
||||
var str = "";
|
||||
var nameUsageLen = 0;
|
||||
var data = [];
|
||||
|
||||
//iterate over each subcommand, gather data, get max length of name + usage
|
||||
this.commands.forEach((e) =>
|
||||
{
|
||||
nameUsageLen = Math.max(nameUsageLen, e.name.length + e.usage.length);
|
||||
|
||||
data.push([e.name, e.usage, e.description]);
|
||||
});
|
||||
|
||||
//create help return string (pad name + usage to max length)
|
||||
data.forEach((e) =>
|
||||
{
|
||||
str += this.formatHelp(e[0], e[1], e[2], nameUsageLen);
|
||||
str += "\n";
|
||||
});
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
||||
var P = require.main.require("./utils/Permissions.js");
|
||||
|
||||
function pad(pad, str, padLeft)
|
||||
{
|
||||
if (typeof str === 'undefined')
|
||||
return pad;
|
||||
if (padLeft)
|
||||
{
|
||||
return (pad + str).slice(-pad.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (str + pad).substring(0, pad.length);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
var Command = require("./Command.js");
|
||||
|
||||
module.exports = class Commands extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.addCommand("./HelpCommand.js");
|
||||
this.addCommand("./PingCommand.js");
|
||||
this.addCommand("./DonateCommand.js");
|
||||
this.addCommand("./SettingsCommand.js");
|
||||
this.addCommand("./InfoCommand.js");
|
||||
this.addCommand("./MusicCommand.js");
|
||||
this.addCommand("./FunCommand.js");
|
||||
this.addCommand("./DevCommand.js");
|
||||
|
||||
this.init();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
var Command = require("./Command.js");
|
||||
|
||||
module.exports = class DevCommand extends Command
|
||||
{
|
||||
//TODO: shuffle, loop, silent, volume (auto?), autoremove (queue mode?)
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "dev";
|
||||
this.description = "Commands for only my developer";
|
||||
this.usage = "<subcommand>";
|
||||
this.permissions = ["dev"];
|
||||
|
||||
this.addCommand("./dev/PermCommand.js");
|
||||
this.addCommand("./dev/PermsCommand.js");
|
||||
this.addCommand("./dev/AvatarCommand.js");
|
||||
this.addCommand("./dev/SayCommand.js");
|
||||
this.addCommand("./dev/TestCommand.js");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
var Command = require("./Command.js");
|
||||
|
||||
module.exports = class DonateCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "donate";
|
||||
this.description = "Help me run this bot!";
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createDonateEmbed());
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,18 @@
|
|||
var Command = require("./Command.js");
|
||||
|
||||
module.exports = class FunCommand extends Command
|
||||
{
|
||||
//TODO: shuffle, loop, silent, volume (auto?), autoremove (queue mode?)
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "fun";
|
||||
this.description = "Commands for some random fun things";
|
||||
this.usage = "<subcommand>";
|
||||
|
||||
this.addCommand("./fun/AsciiCommand.js");
|
||||
this.addCommand("./fun/BooruCommand.js");
|
||||
this.addCommand("./fun/VideoCommand.js");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
var Command = require("./Command.js");
|
||||
|
||||
module.exports = class HelpCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "help";
|
||||
this.description = "shows you the help menu";
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var command;
|
||||
var self = false;
|
||||
//if empty, use root
|
||||
if(text.trim() == "")
|
||||
{
|
||||
command = this.getRoot();
|
||||
}
|
||||
else
|
||||
{
|
||||
//grab subcommand
|
||||
command = this.getRoot().findCommand(text);
|
||||
//if not found, use root
|
||||
command = command == null ? this.getRoot() : command.sub
|
||||
//Check if the command has sub commands or not, and if none are found then display just that command
|
||||
self = command.commands.length == 0 ? true : false
|
||||
}
|
||||
|
||||
U.sendHelp(app, msg, command, self);
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,20 @@
|
|||
var Command = require("./Command.js");
|
||||
|
||||
module.exports = class InfoCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "info";
|
||||
this.description = "Gives you important info about me";
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var prefix = (await app.db.getGuildSettings(msg.channel.guild.id)).prefix || app.config.prefix;
|
||||
app.bot.createMessage(msg.channel.id, U.createInfoEmbed(app, msg.channel.guild.id, prefix, msg));
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,26 @@
|
|||
var Command = require("./Command.js");
|
||||
|
||||
module.exports = class MusicCommand extends Command
|
||||
{
|
||||
//TODO: shuffle, loop, silent, volume (auto?), autoremove (queue mode?)
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "music";
|
||||
this.description = "Commands for music related things";
|
||||
this.usage = "<subcommand>";
|
||||
|
||||
this.addCommand("./music/PlayCommand.js");
|
||||
this.addCommand("./music/AddCommand.js");
|
||||
this.addCommand("./music/StopCommand.js");
|
||||
this.addCommand("./music/ClearCommand.js");
|
||||
this.addCommand("./music/RemoveCommand.js");
|
||||
this.addCommand("./music/SkipCommand.js");
|
||||
this.addCommand("./music/GotoCommand.js");
|
||||
this.addCommand("./music/VolumeCommand.js");
|
||||
this.addCommand("./music/BassCommand.js");
|
||||
this.addCommand("./music/PlaylistCommand.js");
|
||||
this.addCommand("./music/ControlCommand.js");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
var Command = require("./Command.js");
|
||||
|
||||
module.exports = class PingCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "ping";
|
||||
this.description = "pong";
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, 'Here is my current shard latency: ' + msg.channel.guild.shard.latency + "ms");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
var Command = require("./Command.js");
|
||||
|
||||
module.exports = class SettingsCommand extends Command
|
||||
{
|
||||
//TODO: shuffle, loop, silent, volume (auto?), autoremove (queue mode?)
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "settings";
|
||||
this.description = "Commands for bot settings";
|
||||
this.usage = "<subcommand>";
|
||||
|
||||
this.addCommand("./settings/PrefixCommand.js");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class AvatarCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "avatar";
|
||||
this.usage = "<url>";
|
||||
this.description = "Sets the avatar to what ever url you put in";
|
||||
this.permissions = ["dev"];
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var url = text.trim();
|
||||
const res = await require('snekfetch').get(url);
|
||||
app.bot.editSelf({ avatar: `data:image/jpg;base64,${res.body.toString('base64')}` });
|
||||
app.bot.createMessage(msg.channel.id, "Avatar Set!")
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,75 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class PermCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "perm";
|
||||
this.usage = "<user> <add/remove> <permission>";
|
||||
this.description = "Add and remove permissions from users";
|
||||
this.permissions = ["dev"];
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var tokens = text.toLowerCase().split(/\s+/);
|
||||
|
||||
//not enough tokens
|
||||
if(tokens.length < 3)
|
||||
{
|
||||
U.sendHelp(app, msg, this, true);
|
||||
return;
|
||||
}
|
||||
|
||||
var mention = tokens[0];
|
||||
|
||||
//grab id
|
||||
var id = U.str2id(mention);
|
||||
//fail, no user id provided
|
||||
if(id == null)
|
||||
{
|
||||
U.sendHelp(app, msg, this, true);
|
||||
return;
|
||||
}
|
||||
|
||||
//grab user settings
|
||||
var us = await app.db.getUserSettings(id);
|
||||
var command = tokens[1];
|
||||
var perm = tokens[2];
|
||||
|
||||
if(command == "add")
|
||||
{
|
||||
if(us.hasPermission(perm))
|
||||
{
|
||||
U.reply(app, msg, mention + " already has '" + perm + "'");
|
||||
}
|
||||
else
|
||||
{
|
||||
await us.addPermission(perm);
|
||||
U.reply(app, msg, "Gave '" + perm + "' to " + mention);
|
||||
}
|
||||
}
|
||||
else if(command == "remove")
|
||||
{
|
||||
if(!us.hasPermission(perm))
|
||||
{
|
||||
U.reply(app, msg, mention + " doesn't have '" + perm + "'");
|
||||
}
|
||||
else
|
||||
{
|
||||
await us.removePermission(perm);
|
||||
U.reply(app, msg, "Removed '" + perm + "' from " + mention);
|
||||
}
|
||||
}
|
||||
else if(command == "get")
|
||||
{
|
||||
var perms = us.getPermissions().join(", ");
|
||||
|
||||
U.reply(app, msg, mention + " has: " + perms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,63 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class PermsCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "perms";
|
||||
this.usage = "<user>";
|
||||
this.description = "get the perms of a user";
|
||||
this.permissions = ["dev"];
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
text = text.trim();
|
||||
if(text == "")
|
||||
{
|
||||
//TODO: help?
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("No user mentioned", "Please mention a user."))
|
||||
return;
|
||||
}
|
||||
|
||||
var id = U.str2id(text);
|
||||
var member = U.getMemberById(msg.channel.guild, id);
|
||||
|
||||
if(member == null)
|
||||
{
|
||||
//TODO: help member not found
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("Invalid user mentioned", "Please mention a valid user."))
|
||||
return;
|
||||
}
|
||||
|
||||
var dbp = Array.from(await P.getDBPerms(app, member));
|
||||
var gp = Array.from(await P.getGuildPerms(app, member));
|
||||
var rp = Array.from(await P.getRolePerms(app, member));
|
||||
var cp = Array.from(await P.getConfigPerms(app, member));
|
||||
|
||||
var str = "";
|
||||
if(dbp.length > 0)
|
||||
{
|
||||
str += "Database: " + dbp.join(", ") + "\n";
|
||||
}
|
||||
if(gp.length > 0)
|
||||
{
|
||||
str += "Guild: " + gp.join(", ") + "\n";
|
||||
}
|
||||
if(rp.length > 0)
|
||||
{
|
||||
str += "Role: " + rp.join(", ") + "\n";
|
||||
}
|
||||
if(cp.length > 0)
|
||||
{
|
||||
str += "Config: " + cp.join(", ") + "\n";
|
||||
}
|
||||
|
||||
U.reply(app, msg, "Permissions for: " + text + U.wrapCode(str));
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
||||
var P = require.main.require("./utils/Permissions.js");
|
|
@ -0,0 +1,20 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class SayCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "dsay";
|
||||
this.usage = "<words>";
|
||||
this.description = "Makes me say something";
|
||||
this.permissions = ["dev"];
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
msg.delete("Vertbot tts message (dsay)");
|
||||
app.bot.createMessage(msg.channel.id, text);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class TestCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "test";
|
||||
this.usage = "";
|
||||
this.description = "A command that is used for anything I need it for";
|
||||
this.permissions = ["dev"];
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
app.bot.createMessage(U.getLogicalChannel(app, msg.channel.guild).id, U.createWelcomeEmbed(app));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
NOTE:
|
||||
This command is nothing important, as it has no use at all. It just exist for the purpose of debugging
|
||||
the bot itself during development and should be ignored.
|
||||
*/
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,34 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class AsciiCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "ascii";
|
||||
this.description = "Make some fun ascii text art!";
|
||||
this.usage = "<text>"
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
if(text == "")
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("No text", "You put no text in, so I can't create the ascii art..."));
|
||||
return;
|
||||
}
|
||||
|
||||
figlet(text, function(err, data) {
|
||||
if (err) {
|
||||
console.log('Something went wrong...');
|
||||
console.dir(err);
|
||||
return;
|
||||
}
|
||||
app.bot.createMessage(msg.channel.id, U.wrapCode(data));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
||||
var figlet = require("figlet");
|
|
@ -0,0 +1,48 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class BooruCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "booru";
|
||||
this.description = "NSFW commands are the best";
|
||||
this.usage = "<site> <tags>"
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var sites = ["danbooru","konachan","konachannet","yandere","gelbooru","rule34","safebooru","tbib","xbooru","youhateus"]
|
||||
if(text <= 0)
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createQuickEmbed("Here are the sites that are supported:","```" + sites.join("\n") + "```"));
|
||||
} else if(text.split(' ')[0] == "help") {
|
||||
app.bot.createMessage(msg.channel.id, U.createQuickEmbed("Here are the sites that are supported:","```" + sites.join("\n") + "```"));
|
||||
} else {
|
||||
var array = text.split(' ');
|
||||
var site = array[0];
|
||||
var tag = array.splice(1, text.length);
|
||||
if(msg.channel.nsfw == true)
|
||||
{
|
||||
if(sites.indexOf(site) > -1)
|
||||
{
|
||||
const images = kaori.search(site, { tags: tag, random: true }).then((images) =>
|
||||
{
|
||||
images.map(image => {
|
||||
console.log();
|
||||
app.bot.createMessage(msg.channel.id, U.createBooruEmbed(msg.author.username, image.fileURL, image.tags.join(" "), image.fileURL))
|
||||
});
|
||||
}).catch(err => app.bot.createMessage(msg.channel.id, U.createErrorEmbed("Something went wrong", "```" + err + "```")));
|
||||
} else {
|
||||
app.bot.createMessage(msg.channel.id, U.createQuickEmbed("Here are the sites that are supported:","```" + sites.join("\n") + "```"));
|
||||
}
|
||||
} else {
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("This channel is not NSFW", "This command can only be used in channels that are marked as NSFW"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
||||
var kaori = require('kaori');
|
|
@ -0,0 +1,24 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class VideoCommand extends Command {
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "videochat";
|
||||
this.description = "Creates a link to allow video chat in your current voice channel";
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var vc = U.msg2vc(msg);
|
||||
if(vc != undefined || vc != null)
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Created video chat link", "[Click Here](https://discordapp.com/channels/" + msg.channel.guild.id + "/" + vc.id + ")"));
|
||||
} else {
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("No Voice Channel", "You seem to not be connected to any voice channel"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,32 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class AddCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "add";
|
||||
this.description = "add music to playlist";
|
||||
this.usage = "<url / query>";
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var pl = await app.db.getPlaylist(msg.channel.guild.id);
|
||||
var perms = await P.getPerms(app, msg);
|
||||
|
||||
//if query doesnt begin with http(s)://, prepend ytsearch:
|
||||
if(text.match(/^https?:\/\//i) == null)
|
||||
{
|
||||
text = "ytsearch:" + text;
|
||||
}
|
||||
|
||||
//app.bot.createMessage(msg.channel.id, text);
|
||||
|
||||
await app.lavalink.add(msg, text, false);
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
||||
var P = require.main.require("./utils/Permissions.js");
|
|
@ -0,0 +1,75 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class BassCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "bassboost";
|
||||
this.aliases = ["boost"];
|
||||
this.description = "crank that bass up to 11 (well actually 100)";
|
||||
this.usage = "<#>";
|
||||
}
|
||||
|
||||
async bassBoost(msg, app, cmd, pl, perms)
|
||||
{
|
||||
var vc = U.msg2vc(msg);
|
||||
var hasNumber = /\d/;
|
||||
var player = await app.lavalink.getPlayer(vc, true);
|
||||
var boost = U.getVal(msg.content, 0, 100) / 100;
|
||||
|
||||
if(hasNumber.test(cmd))
|
||||
{
|
||||
if(cmd != "")
|
||||
{
|
||||
//Bands: 0-15, Gain: -0.25-1.0
|
||||
pl.setBoost(boost);
|
||||
if(player != null)
|
||||
{
|
||||
var bands = [{"band": 0,"gain": boost},{"band": 1,"gain": boost},{"band": 2,"gain": boost}]
|
||||
player.setEQ(bands);
|
||||
}
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Bass boost has been changed", "The bass boost has been set to " + (pl.boost * 100) + "%"));
|
||||
}
|
||||
} else {
|
||||
if(cmd != "")
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("Could not change bass boost", "You seem to have not put any numbers or something broke..."));
|
||||
} else {
|
||||
app.bot.createMessage(msg.channel.id, U.createQuickEmbed("Bass boost:", "Currently " + (pl.boost * 100) + "%"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var cmd = text.trim().toLowerCase();
|
||||
var hasNumber = /\d/;
|
||||
var pl = await app.db.getPlaylist(msg.channel.guild.id);
|
||||
var perms = await P.getPerms(app, msg);
|
||||
|
||||
//Getto permission check to have less code and to make it so the command can still be used in some ways
|
||||
if(pl.djmode == true && U.canUseCommand(perms, {permissions: ["dj"]}, pl))
|
||||
{
|
||||
await this.bassBoost(msg, app, cmd, pl, perms);
|
||||
} else {
|
||||
if(pl.djmode == false || pl.djmode == undefined) { await this.bassBoost(msg, app, cmd, pl, perms); }
|
||||
|
||||
if(pl.djmode == true)
|
||||
{
|
||||
if(hasNumber.test(cmd))
|
||||
{
|
||||
//The person failed the getto permission check and we display the fact they don't have the role we want
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("You don't have permissions", "You seem to not have `dj`"));
|
||||
} else {
|
||||
//Cool the person has the role we want
|
||||
app.bot.createMessage(msg.channel.id, U.createQuickEmbed("Bass boost:", "Currently " + (pl.boost * 100) + "%"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
||||
var P = require.main.require("./utils/Permissions.js");
|
|
@ -0,0 +1,26 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class ClearCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "clear";
|
||||
this.description = "clear the playlist";
|
||||
this.permissions = ["dj"];
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var pl = await app.db.getPlaylist(msg.channel.guild.id);
|
||||
pl.clear();
|
||||
if(U.currentVC(app, msg.channel.guild.id) != null)
|
||||
{
|
||||
app.lavalink.stop(msg, app);
|
||||
}
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Playlist cleared", "The playlist has been completely cleared"));
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,19 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class ControlCommand extends Command
|
||||
{
|
||||
//TODO: shuffle, loop, silent, volume (auto?), autoremove (queue mode?)
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "control";
|
||||
this.description = "Commands for music control related things";
|
||||
this.usage = "<subcommand>";
|
||||
|
||||
this.addCommand("./music/control/RepeatCommand.js");
|
||||
this.addCommand("./music/control/SilentCommand.js");
|
||||
this.addCommand("./music/control/ShuffleCommand.js");
|
||||
this.addCommand("./music/control/DJModeCommand.js");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class GotoCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "goto";
|
||||
this.description = "Goto a song in the playlist";
|
||||
this.usage = "<# for video>"
|
||||
this.permission = ["dj"]
|
||||
}
|
||||
|
||||
async findSong(songNum, pl)
|
||||
{
|
||||
//This is prob the best way to make this command work with shuffle turned on... but this may change
|
||||
return pl.indexes.indexOf(songNum, 0);
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var vc = U.msg2vc(msg);
|
||||
var pl = await app.db.getPlaylist(msg.channel.guild.id);
|
||||
var gid = U.msg2gid(msg);
|
||||
var hasNumber = /\d/;
|
||||
var num = parseInt(text) - 1;
|
||||
|
||||
if(text.match(/^\d+$/) && (text.match(/^\d+$/) != 0))
|
||||
{
|
||||
if(pl.tracks[num] == undefined)
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("Invalid number", "Please put a valid number"));
|
||||
return;
|
||||
} else {
|
||||
await pl.setPosition(pl.shuffle ? await this.findSong(num, pl) : num); //advance playlist (wait for save confirmation to prevent glitch)
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Set new track", "Set track to: `" + pl.tracks[num].info.title + "`"));
|
||||
|
||||
if(U.currentVC(app, gid) != null)
|
||||
{
|
||||
app.lavalink.play(vc, msg, app);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("Invalid number", "Please put a valid number"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
[=add https://www.youtube.com/watch?v=dJaVI7jzc8s
|
||||
[=add https://www.youtube.com/watch?v=WNxZiBexDM8
|
||||
[=add https://www.youtube.com/watch?v=IUun0CWrvT0
|
||||
*/
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,41 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class PlayCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "play";
|
||||
this.aliases = ["join"];
|
||||
this.description = "play music";
|
||||
this.usage = "<url / query>";
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var vc = U.msg2vc(msg);
|
||||
var pl = await app.db.getPlaylist(msg.channel.guild.id);
|
||||
var perms = await P.getPerms(app, msg);
|
||||
if(msg.member.voiceState.channelID != null)
|
||||
{
|
||||
if(text.length > 0)
|
||||
{
|
||||
if(text.match(/^https?:\/\//i) == null)
|
||||
{
|
||||
text = "ytsearch:" + text;
|
||||
}
|
||||
//app.bot.createMessage(msg.channel.id, text);
|
||||
|
||||
await app.lavalink.add(msg, text, true, vc, app);
|
||||
} else {
|
||||
app.lavalink.play(vc, msg, app, true);
|
||||
}
|
||||
} else {
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("No Voice Channel", "You seem to not be connected to any voice channel"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
||||
var P = require.main.require("./utils/Permissions.js");
|
|
@ -0,0 +1,24 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class PlaylistCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "list";
|
||||
this.aliases = ["playlist", "np", "nowplaying"];
|
||||
this.description = "show the playlist";
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var pl = await app.db.getPlaylist(msg.channel.guild.id);
|
||||
var vc = U.currentVC(app, msg.channel.guild.id);
|
||||
var player = app.lavalink.getPlayer(vc, true); //jeebus
|
||||
|
||||
app.bot.createMessage(msg.channel.id, U.createPlaylistEmbed(pl, player, vc));
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,42 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class ClearCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "remove";
|
||||
this.description = "remove an item from the playlist";
|
||||
this.usage = "<# for video>";
|
||||
this.permissions = ["dj"];
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var cmd = text.trim().toLowerCase();
|
||||
var pl = await app.db.getPlaylist(msg.channel.guild.id);
|
||||
var hasNumber = /\d/;
|
||||
var number = U.getVal(cmd, 1, pl.tracks.length) - 1;
|
||||
|
||||
if(pl.tracks.length == 0)
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("The playlist is empty", "You can't remove something that isn't there ya know..."));
|
||||
return;
|
||||
}
|
||||
|
||||
if(hasNumber.test(cmd))
|
||||
{
|
||||
if(cmd != "")
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Removed track", "`" + (number + 1 + ": ") + pl.tracks[number].info.title + "` has been removed from the playlist"));
|
||||
await pl.removeTrack(number);
|
||||
}
|
||||
} else {
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("Could not remove track", "You seem to have not put any numbers or something broke..."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,81 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class SkipCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "skip";
|
||||
this.description = "skip the current playlist item";
|
||||
this.votes = [];
|
||||
}
|
||||
|
||||
async voteSkip(msg, app, vc)
|
||||
{
|
||||
var user = msg.author.id;
|
||||
|
||||
if(this.votes.includes(user))
|
||||
{
|
||||
return;
|
||||
} else {
|
||||
this.votes.push(user);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
async skip(msg, app, text, pl, vc)
|
||||
{
|
||||
//glitch likely caused by lavalink grabbing its own (slightly outdated) copy of the playlist
|
||||
await pl.next(); //advance playlist (wait for save confirmation to prevent glitch)
|
||||
|
||||
app.lavalink.play(vc, msg, app, true);
|
||||
return;
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var pl = await app.db.getPlaylist(msg.channel.guild.id);
|
||||
var vc = U.msg2vc(msg);
|
||||
var beforeVotes = this.votes;
|
||||
var perms = await P.getPerms(app, msg);
|
||||
var gid = U.msg2gid(msg);
|
||||
|
||||
//Getto permission check to have less code and to make it so the command can still be used in some ways
|
||||
if(pl.djmode == true && U.canUseCommand(perms, {permissions: ["dj"]}, pl))
|
||||
{
|
||||
this.skip(msg, app, text, pl, vc)
|
||||
} else {
|
||||
if(pl.djmode == false || pl.djmode == undefined) { await this.skip(msg, app, text, pl, vc); }
|
||||
|
||||
if(pl.djmode == true)
|
||||
{
|
||||
await this.voteSkip(msg, app, vc);
|
||||
|
||||
var currentVotes = this.votes.length;
|
||||
var quota = U.getUsersInVc(msg, vc) / 2;
|
||||
var voteString = currentVotes + "/" + Math.round(quota);
|
||||
|
||||
console.log(voteString);
|
||||
|
||||
if(currentVotes >= quota)
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Vote Passed", voteString + " voted"));
|
||||
await this.skip(msg, app, text, pl, vc);
|
||||
this.votes = [];
|
||||
} else {
|
||||
app.bot.createMessage(msg.channel.id, U.createQuickEmbed("Vote Skip:", voteString + " voted"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
[=add https://www.youtube.com/watch?v=dJaVI7jzc8s
|
||||
[=add https://www.youtube.com/watch?v=WNxZiBexDM8
|
||||
[=add https://www.youtube.com/watch?v=IUun0CWrvT0
|
||||
*/
|
||||
var U = require.main.require("./utils/Utils.js");
|
||||
var P = require.main.require("./utils/Permissions.js");
|
|
@ -0,0 +1,21 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class StopCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "stop";
|
||||
this.aliases = ["leave"];
|
||||
this.description = "stop playing music";
|
||||
this.permissions = ["dj"];
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
app.lavalink.stop(msg, app);
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,81 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class VolumeCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "volume";
|
||||
this.usage = "<#>"
|
||||
this.description = "Sets the volume of the playback";
|
||||
}
|
||||
|
||||
async volume(msg, app, cmd, pl, perms)
|
||||
{
|
||||
var vc = U.msg2vc(msg);
|
||||
var hasNumber = /\d/;
|
||||
var player = await app.lavalink.getPlayer(vc, true);
|
||||
var volume = U.canUseCommand(perms, {permissions: ["admin"]}, pl) ? U.getVal(cmd, 0, 1000) : U.getVal(cmd, 0, 100);
|
||||
|
||||
if(hasNumber.test(cmd))
|
||||
{
|
||||
if(cmd != "")
|
||||
{
|
||||
pl.setVolume(volume);
|
||||
if(player != null)
|
||||
{
|
||||
player.setVolume(volume);
|
||||
}
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Volume has been changed", "The volume has been set to " + pl.volume + "%"));
|
||||
}
|
||||
} else {
|
||||
if(cmd != "")
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("Could not change volume", "You seem to have not put any numbers or something broke..."));
|
||||
return;
|
||||
} else {
|
||||
app.bot.createMessage(msg.channel.id, U.createQuickEmbed("Volume:", "Currently " + pl.volume + "%"));
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var cmd = text.trim().toLowerCase();
|
||||
var hasNumber = /\d/;
|
||||
var pl = await app.db.getPlaylist(msg.channel.guild.id);
|
||||
var perms = await P.getPerms(app, msg);
|
||||
|
||||
|
||||
//Getto permission check to have less code and to make it so the command can still be used in some ways
|
||||
if(pl.djmode == true && U.canUseCommand(perms, {permissions: ["dj"]}, pl))
|
||||
{
|
||||
await this.volume(msg, app, cmd, pl, perms);
|
||||
} else {
|
||||
if(pl.djmode == false || pl.djmode == undefined) { await this.volume(msg, app, cmd, pl, perms); }
|
||||
|
||||
if(pl.djmode == true)
|
||||
{
|
||||
if(hasNumber.test(cmd))
|
||||
{
|
||||
//The person failed the getto permission check and we display the fact they don't have the role we want
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("You don't have permissions", "You seem to not have `dj`"));
|
||||
} else {
|
||||
//Cool the person has the role we want
|
||||
app.bot.createMessage(msg.channel.id, U.createQuickEmbed("Volume:", "Currently " + pl.volume + "%"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
[=add https://www.youtube.com/watch?v=dJaVI7jzc8s
|
||||
[=add https://www.youtube.com/watch?v=WNxZiBexDM8
|
||||
[=add https://www.youtube.com/watch?v=IUun0CWrvT0
|
||||
*/
|
||||
var U = require.main.require("./utils/Utils.js");
|
||||
var P = require.main.require("./utils/Permissions.js");
|
|
@ -0,0 +1,41 @@
|
|||
var Command = require("../../Command.js");
|
||||
|
||||
module.exports = class DJModeCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "djmode";
|
||||
this.description = "Turn on or off the requirement for the dj role";
|
||||
this.usage = "<on/off>"
|
||||
this.permissions = ["admin"];
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var cmd = text.trim().toLowerCase();
|
||||
var pl = await app.db.getPlaylist(msg.channel.guild.id);
|
||||
|
||||
if(cmd == "on")
|
||||
{
|
||||
await pl.setDJMode(true);
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("DJ Mode is now on", "DJ Mode is now turned on"));
|
||||
}
|
||||
else if(cmd == "off")
|
||||
{
|
||||
await pl.setDJMode(false);
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("DJ Mode is now off", "DJ Mode is now turned off"));
|
||||
}
|
||||
else if(cmd == "")
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createQuickEmbed("DJ Mode is currently:", (pl.djmode ? "on" : "off")));
|
||||
}
|
||||
else
|
||||
{
|
||||
U.sendHelp(app, msg, this, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,41 @@
|
|||
var Command = require("../../Command.js");
|
||||
|
||||
module.exports = class RepeatCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "repeat";
|
||||
this.description = "Toggle Repeat for the Playlist";
|
||||
this.usage = "<on/off>"
|
||||
this.permissions = ["dj"];
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var cmd = text.trim().toLowerCase();
|
||||
var pl = await app.db.getPlaylist(msg.channel.guild.id);
|
||||
|
||||
if(cmd == "on")
|
||||
{
|
||||
await pl.setRepeat(true);
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Repeat is now on", "Repeat is now turned on"));
|
||||
}
|
||||
else if(cmd == "off")
|
||||
{
|
||||
await pl.setRepeat(false);
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Repeat is now off", "Repeat is now turned off"));
|
||||
}
|
||||
else if(cmd == "")
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createQuickEmbed("Repeat is currently:", (pl.repeat ? "on" : "off")));
|
||||
}
|
||||
else
|
||||
{
|
||||
U.sendHelp(app, msg, this, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,42 @@
|
|||
var Command = require("../../Command.js");
|
||||
|
||||
module.exports = class ShuffleCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "shuffle";
|
||||
this.description = "toggle shuffle";
|
||||
this.usage = "<on/off>"
|
||||
this.permissions = ["dj"];
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var cmd = text.trim().toLowerCase();
|
||||
var pl = await app.db.getPlaylist(msg.channel.guild.id);
|
||||
|
||||
if(cmd == "on")
|
||||
{
|
||||
await pl.setShuffle(true);
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Shuffle is now on", "Shuffle is now turned on"));
|
||||
}
|
||||
else if(cmd == "off")
|
||||
{
|
||||
await pl.setShuffle(false);
|
||||
await pl.setPosition(pl.indexes[pl.position]); //This makes sure that when shuffle is turned off, it will stay on the song in the normal playlist so it will continue on
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Shuffle is now off", "Shuffle is now turned off"));
|
||||
}
|
||||
else if(cmd == "")
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createQuickEmbed("Shuffle is currently:", (pl.shuffle ? "on" : "off")));
|
||||
}
|
||||
else
|
||||
{
|
||||
U.sendHelp(app, msg, this, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,41 @@
|
|||
var Command = require("../../Command.js");
|
||||
|
||||
module.exports = class SilentCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "silent";
|
||||
this.description = "toggle silent";
|
||||
this.usage = "<on/off>"
|
||||
this.permissions = ["admin"];
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
var cmd = text.trim().toLowerCase();
|
||||
var pl = await app.db.getPlaylist(msg.channel.guild.id);
|
||||
|
||||
if(cmd == "on")
|
||||
{
|
||||
await pl.setSilent(true);
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Silent is now on", "Silent is now turned on"));
|
||||
}
|
||||
else if(cmd == "off")
|
||||
{
|
||||
await pl.setSilent(false);
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Silent is now off", "Silent is now turned off"));
|
||||
}
|
||||
else if(cmd == "")
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createQuickEmbed("Silent is currently:", (pl.silent ? "on" : "off")));
|
||||
}
|
||||
else
|
||||
{
|
||||
U.sendHelp(app, msg, this, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,42 @@
|
|||
var Command = require("../Command.js");
|
||||
|
||||
module.exports = class PrefixCommand extends Command
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "prefix";
|
||||
this.description = "Sets my prefix";
|
||||
this.permissions = ["admin"];
|
||||
}
|
||||
|
||||
async doCommand(msg, app, text)
|
||||
{
|
||||
/*var prefix = (await app.db.getGuildSettings(msg.channel.guild.id)).prefix || this.config.prefix;
|
||||
var newPrefix = msg.content.slice(prefix.length).trim().split(/\s+/)[1];
|
||||
//await this.settings.set(msg.channel.guild.id, "prefix", newPrefix);
|
||||
(await app.db.getGuildSettings(msg.channel.guild.id)).setPrefix(newPrefix);
|
||||
|
||||
app.bot.createMessage(msg.channel.id, "set prefix to " + newPrefix);
|
||||
|
||||
return;*/
|
||||
|
||||
var prefix = (await app.db.getGuildSettings(msg.channel.guild.id)).prefix || app.config.prefix;
|
||||
|
||||
text = text.trim();
|
||||
|
||||
if(text.length != 0)
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Prefix has been set", "The prefix has been set to: `" + text + "`"));
|
||||
(await app.db.getGuildSettings(msg.channel.guild.id)).setPrefix(text);
|
||||
return;
|
||||
} else
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.createQuickEmbed("The prefix is currently:", "`" + prefix + "`"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"dbUrl": "mongodb://127.0.0.1:27017",
|
||||
"dbName": "vertbot",
|
||||
"autoSave": true,
|
||||
"perms": {
|
||||
"<your id>": ["dev"]
|
||||
},
|
||||
"autoSaveInterval": 60000,
|
||||
"disableDBL": true,
|
||||
"prefix": "v-",
|
||||
"nodes": [
|
||||
{ "host": "localhost", "port": 2333, "restport": 2333, "region": "us", "password": "youshallnotpass" }
|
||||
]
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
services:
|
||||
vertbot:
|
||||
image: "kaydax/vertbot"
|
||||
depends_on:
|
||||
- lavalink
|
||||
- mongo
|
||||
restart: "unless-stopped"
|
||||
lavalink:
|
||||
image: "kaydax/lavalink"
|
||||
restart: "unless-stopped"
|
||||
#ports:
|
||||
# - 2333:2333
|
||||
mongo:
|
||||
image: mongo
|
||||
restart: always
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: vertbot
|
||||
MONGO_INITDB_ROOT_PASSWORD: ZYc34mqE
|
|
@ -0,0 +1,6 @@
|
|||
FROM eclipse-temurin:17
|
||||
WORKDIR /usr/app
|
||||
COPY . .
|
||||
#RUN java Lavalink.java
|
||||
#CMD ["java", "Main"]
|
||||
CMD ["java", "-Xmx1G", "-jar", "Lavalink.jar"]
|
Binary file not shown.
|
@ -0,0 +1,42 @@
|
|||
server: # REST server
|
||||
port: 2333
|
||||
address: 0.0.0.0
|
||||
spring:
|
||||
main:
|
||||
banner-mode: log
|
||||
lavalink:
|
||||
server:
|
||||
password: "youshallnotpass"
|
||||
sources:
|
||||
youtube: true
|
||||
bandcamp: true
|
||||
soundcloud: true
|
||||
twitch: true
|
||||
vimeo: true
|
||||
mixer: true
|
||||
http: true
|
||||
local: false
|
||||
bufferDurationMs: 400
|
||||
youtubePlaylistLoadLimit: 2147483647
|
||||
gc-warnings: true
|
||||
|
||||
metrics:
|
||||
prometheus:
|
||||
enabled: false
|
||||
endpoint: /metrics
|
||||
|
||||
sentry:
|
||||
dsn: ""
|
||||
# tags:
|
||||
# some_key: some_value
|
||||
# another_key: another_value
|
||||
|
||||
logging:
|
||||
file:
|
||||
max-history: 30
|
||||
max-size: 1GB
|
||||
path: ./logs/
|
||||
|
||||
level:
|
||||
root: INFO
|
||||
lavalink: INFO
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
java -jar Lavalink.jar
|
|
@ -0,0 +1,2 @@
|
|||
#!/bin/bash
|
||||
screen -S Lavalink java -jar Lavalink.jar
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"name": "vertbot",
|
||||
"version": "2.5.3",
|
||||
"description": "Vertbot - A lightweight multi purpose, lag free music bot",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "node main.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@gitlab.com:Kaydax/Vertbot.git"
|
||||
},
|
||||
"keywords": [
|
||||
"Discord",
|
||||
"Bot",
|
||||
"Music"
|
||||
],
|
||||
"author": "Kaydax",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Kaydax/Vertbot/issues"
|
||||
},
|
||||
"homepage": "https://github.com/Kaydax/Vertbot#readme",
|
||||
"dependencies": {
|
||||
"assert": "^2.0.0",
|
||||
"dblapi.js": "^2.3.0",
|
||||
"deepl-scraper": "^1.0.8",
|
||||
"deepl-translator": "^1.2.1",
|
||||
"eris": "^0.15.1",
|
||||
"extend": "^3.0.2",
|
||||
"figlet": "^1.2.4",
|
||||
"format-duration": "^1.3.1",
|
||||
"free-translate": "^0.1.1",
|
||||
"install": "^0.13.0",
|
||||
"jsonpath": "^1.1.1",
|
||||
"kaori": "^2.0.0",
|
||||
"mongodb": "^3.3.3",
|
||||
"mongoose": "^5.12.13",
|
||||
"node-fetch": "2.0",
|
||||
"number-format.js": "^2.0.9",
|
||||
"request": "^2.88.0",
|
||||
"request-promise": "^4.2.4",
|
||||
"shuffle-array": "^1.0.1",
|
||||
"snekfetch": "^4.0.4",
|
||||
"split2": "^3.1.1",
|
||||
"spotify-web-api-node": "git+https://github.com/thelinmichael/spotify-web-api-node.git",
|
||||
"unscramble": "^0.0.1-v",
|
||||
"vertbot-eris-lavalink": "^1.0.1",
|
||||
"word-unscrambler": "^1.1.1",
|
||||
"ws": "^7.4.6"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
//Put your bot token and youtube api key in here, and rename the file to secret.js
|
||||
module.exports = {
|
||||
discord: "<bot token>",
|
||||
youtube: "<youtube api token>",
|
||||
spotify: "<spotify access token>",
|
||||
dbl: "<Your discord bot list token>",
|
||||
dbots: "<Your discord bots auth token>"
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/** mongoose database io stuff */
|
||||
module.exports = class Database
|
||||
{
|
||||
constructor(app)
|
||||
{
|
||||
this.app = app;
|
||||
this.dbUrl = this.app.config.dbUrl;
|
||||
this.dbName = this.app.config.dbName; //"vertbot"; //TODO: putin config
|
||||
|
||||
this.db = mongoose.createConnection(this.dbUrl + "/" + this.dbName, { useUnifiedTopology: true });
|
||||
this.GuildSetting = this.db.model("guildSetting", schema.guildSetting, "settings");
|
||||
this.Playlist = this.db.model("playlist", schema.playlist, "settings");
|
||||
this.User = this.db.model("user", schema.user, "settings");
|
||||
//TODO: create other settings likewise
|
||||
|
||||
//TODO: autosave?
|
||||
}
|
||||
|
||||
//TODO: inter-shard communication
|
||||
|
||||
async getGuildSettings(gid)
|
||||
{
|
||||
var gs = await this.GuildSetting.findOne({id: gid, type: "guild"}).exec();
|
||||
|
||||
if(gs == null)
|
||||
{
|
||||
return new this.GuildSetting({id: gid});
|
||||
}
|
||||
|
||||
return gs;
|
||||
}
|
||||
|
||||
async getPlaylist(gid)
|
||||
{
|
||||
var pl = await this.Playlist.findOne({id: gid, type: "playlist"}).exec();
|
||||
|
||||
if(pl == null)
|
||||
{
|
||||
return new this.Playlist({id: gid});
|
||||
}
|
||||
|
||||
return pl;
|
||||
}
|
||||
|
||||
async getUserSettings(uid)
|
||||
{
|
||||
var user = await this.User.findOne({id: uid, type: "user"}).exec();
|
||||
|
||||
if(user == null)
|
||||
{
|
||||
return new this.User({id: uid});
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var mongoose = require("mongoose");
|
||||
var schema = require("./Schema.js");
|
|
@ -0,0 +1,31 @@
|
|||
//Basically discord-bots-api on npm but for only posting the guild count
|
||||
|
||||
var DLA = {};
|
||||
module.exports = DLA;
|
||||
|
||||
DLA.postGuilds = async function(bot, tokens)
|
||||
{
|
||||
var url = "https://botblock.org/api/count";
|
||||
var options =
|
||||
{
|
||||
method: 'POST',
|
||||
uri: url,
|
||||
body: {
|
||||
"server_count": bot.guilds.size,
|
||||
"bot_id": bot.user.id,
|
||||
"shard_count": bot.shards.size,
|
||||
"bots.ondiscord.xyz": tokens.bod,
|
||||
"discord.bots.gg": tokens.dbots,
|
||||
"discordapps.dev": tokens.dapps,
|
||||
"top.gg": tokens.topgg
|
||||
},
|
||||
json: true
|
||||
};
|
||||
rp(options).catch(function (err) {
|
||||
console.log(err);
|
||||
});
|
||||
|
||||
console.log("[DLA] Server Count Posted!");
|
||||
}
|
||||
|
||||
var rp = require('request-promise');
|
|
@ -0,0 +1,336 @@
|
|||
module.exports = class Lavalink
|
||||
{
|
||||
//TODO: store voice channel or something because uhhhhh if the user moves or d/cs what happens to msg2vc
|
||||
//TODO: playlist control with left/right + 0-9
|
||||
//TODO: add checks for user (so they cant stop other peoples music)
|
||||
constructor(app)
|
||||
{
|
||||
this.app = app;
|
||||
|
||||
//NOTE: As of 3.1.X and up, the WS and Rest Ports are the same
|
||||
this.nodes = this.app.config.nodes //[{ host: 'localhost', port: 80, region: 'us', password: 'youshallnotpass' }];
|
||||
this.regions = {
|
||||
asia: ['hongkong', 'singapore', 'sydney'],
|
||||
eu: ['eu', 'amsterdam', 'frankfurt', 'russia'],
|
||||
us: ['us', 'brazil'],
|
||||
};
|
||||
|
||||
this.shardCount = app.bot.shards.size; //lol size instead of length
|
||||
this.userId = app.bot.user.id;
|
||||
|
||||
//TODO: currently assuming single lavalink node...
|
||||
this.node = this.nodes[0];
|
||||
//console.log(this.nodes[0]);
|
||||
|
||||
this.playerManager = new PlayerManager(this.app.bot, this.nodes,
|
||||
{
|
||||
numShards: this.shardCount, // number of shards
|
||||
userId: this.userId, // the user id of the bot
|
||||
regions: this.regions,
|
||||
client_name: "Vertbot",
|
||||
defaultRegion: 'us',
|
||||
});
|
||||
|
||||
this.app.bot.voiceConnections = this.playerManager;
|
||||
}
|
||||
|
||||
/** pass voice channel and the message that caused the command, if play is called with an OOB position, position will be reset to 0 */
|
||||
async play(vc, msg, app, doMessage)
|
||||
{
|
||||
//get next track to play
|
||||
var pl = await this.app.db.getPlaylist(vc.guild.id);
|
||||
|
||||
if(pl.tracks.length == 0)
|
||||
{
|
||||
this.app.bot.createMessage(msg.channel.id, U.createErrorEmbed("No tracks in playlist", "There seems to be no tracks in the playlist, please add some and try again"));
|
||||
return;
|
||||
}
|
||||
|
||||
if(pl.position < 0 || pl.position >= pl.tracks.length)
|
||||
{
|
||||
await pl.restart();
|
||||
}
|
||||
|
||||
var track = pl.currentTrack();
|
||||
|
||||
if(track == null)
|
||||
{
|
||||
if(msg != null)
|
||||
{
|
||||
this.app.bot.createMessage(msg.channel.id, U.createErrorEmbed("Track is null", "The track really shouldn't be null here..."));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!vc.permissionsOf(this.app.bot.user.id).has("voiceConnect"))
|
||||
{
|
||||
if(msg != null)
|
||||
{
|
||||
this.app.bot.createMessage(msg.channel.id, U.createErrorEmbed("Invalid permissions", "It seems that I don't have permission to join that voice channel"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//grab player
|
||||
var player = this.getPlayer(vc);
|
||||
//if its null, join voice channel
|
||||
if(player == null)
|
||||
{
|
||||
player = await this.join(vc);
|
||||
this.registerPlayerEvents(player, msg);
|
||||
}
|
||||
|
||||
player.setVolume(pl.volume);
|
||||
var bands = [{"band": 0,"gain": pl.boost},{"band": 1,"gain": pl.boost},{"band": 2,"gain": pl.boost}];
|
||||
player.setEQ(bands);
|
||||
player.play(track.track); // track is the base64 track we get from Lavalink
|
||||
if(!pl.silent || doMessage)
|
||||
{
|
||||
var position = pl.shuffle ? pl.indexes[pl.position] + 1 : pl.position + 1;
|
||||
if(msg.channel != null)
|
||||
{
|
||||
this.app.bot.createMessage(msg.channel.id, U.createNowPlayingEmbed(position + " / " + pl.tracks.length, "**" + track.info.title + "**"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async stop(msg, app)
|
||||
{
|
||||
var vc = U.currentVC(this.app, msg.channel.guild.id);
|
||||
if(vc == null)
|
||||
{
|
||||
//throw "Bot is not in a vc";
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("No Voice Channel", "You seem to not be connected to any voice channel"));
|
||||
}
|
||||
|
||||
var player = await this.getPlayer(vc);
|
||||
if(player == null)
|
||||
{
|
||||
this.app.bot.leaveVoiceChannel(vc.id);
|
||||
app.bot.createMessage(msg.channel.id, U.createErrorEmbed("Player stuck in vc?", "I seem to have encountered an error, I will try to disconnect from the voice channel to avoid any more issues"));
|
||||
}
|
||||
|
||||
player.stop();
|
||||
this.unregisterPlayerEvents(player);
|
||||
|
||||
this.app.bot.leaveVoiceChannel(vc.id);
|
||||
}
|
||||
|
||||
async add(msg, search, play, vc, app)
|
||||
{
|
||||
var tracks = await this.resolveTracks(this.node, search);
|
||||
|
||||
if(tracks.tracks.length == 0)
|
||||
{
|
||||
this.app.bot.createMessage(msg.channel.id, U.createErrorEmbed("No tracks to add", "There seems to be nothing found that I can add. Try to make your search more clear"));
|
||||
return;
|
||||
}
|
||||
|
||||
//Show the video info from text search
|
||||
if(search.startsWith("ytsearch:"))
|
||||
{
|
||||
var info = tracks.tracks[0].info;
|
||||
var title = info.title;
|
||||
var id = info.identifier;
|
||||
var author = info.author;
|
||||
|
||||
//This used to be using the youtube api until I figured out how the thumbnail's worked
|
||||
|
||||
this.app.bot.createMessage(msg.channel.id, U.createSearchEmbed(title, id, author));
|
||||
}
|
||||
|
||||
var pl = await this.app.db.getPlaylist(msg.channel.guild.id);
|
||||
|
||||
//pl.addAll(tracks);
|
||||
//pl.add(tracks[0]);
|
||||
|
||||
//Lavalink 3 uses tracks.tracks[0] and not tracks[0] to add playlist info support
|
||||
|
||||
if(msg.content.match(/https?:/) != null)
|
||||
{
|
||||
await pl.addAll(tracks.tracks)
|
||||
} else {
|
||||
await pl.add(tracks.tracks[0]);
|
||||
}
|
||||
//this.app.bot.createMessage(msg.channel.id, "Adding " + tracks.length + " tracks");
|
||||
|
||||
if(tracks.loadType == "PLAYLIST_LOADED")
|
||||
{
|
||||
this.app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Added new playlist", "Added all of `" + tracks.playlistInfo.name + "` to the playlist"))
|
||||
} else {
|
||||
this.app.bot.createMessage(msg.channel.id, U.createSuccessEmbed("Added new track", "Added `" + tracks.tracks[0].info.title + "` to the playlist"));
|
||||
}
|
||||
|
||||
await pl.createShuffleArray(); //Creates an index array used to randomize playback when shuffle is enabled
|
||||
|
||||
if(play)
|
||||
{
|
||||
//if(!pl.shuffle) { await pl.setPosition(pl.tracks.length - 1); }; //Outdated code, don't use. Allows for bypass of vote skip when dj mode is enabled
|
||||
//this.play(vc, msg, app, true);
|
||||
|
||||
if(pl.djmode == false || pl.djmode == undefined)
|
||||
{
|
||||
if(!pl.shuffle) { await pl.setPosition(pl.tracks.length - 1); };
|
||||
this.play(vc, msg, app, true);
|
||||
}
|
||||
|
||||
//TODO: Add support for people with DJ perms to do a bypass skip with the play command.
|
||||
|
||||
//If DJMode is enabled just do nothing as it will just add the track like normal.
|
||||
//Too lazy to actually implement a DJ perm bypass to this as it will slow down the add command more then it needs to be
|
||||
}
|
||||
|
||||
//This is for debuging track info:
|
||||
//console.log(tracks);
|
||||
|
||||
//var res = await U.youtube(this.app, tracks[0].info.identifier);
|
||||
//console.log(JSON.stringify(res.items[0].snippet.thumbnails.maxres.url, null, 2));
|
||||
}
|
||||
|
||||
async onDisconnect(err)
|
||||
{
|
||||
if(err)
|
||||
{
|
||||
throw "player disconnected: " + err;
|
||||
}
|
||||
|
||||
console.log("player disconnected");
|
||||
}
|
||||
|
||||
async onError(err)
|
||||
{
|
||||
throw "player error: " + err;
|
||||
}
|
||||
|
||||
async onStuck(info)
|
||||
{
|
||||
console.log("player stuck player stuck please i beg you: " + info);
|
||||
}
|
||||
|
||||
async onEnd(data, msg)
|
||||
{
|
||||
// REPLACED reason is emitted when playing without stopping, I ignore these to prevent skip loops
|
||||
if(data.reason && data.reason === 'REPLACED')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//advance playlist
|
||||
var pl = await this.app.db.getPlaylist(msg.channel.guild.id);
|
||||
await pl.next();
|
||||
var vc = U.currentVC(this.app, msg.channel.guild.id);
|
||||
|
||||
//playlist ended
|
||||
if(pl.position >= pl.tracks.length)
|
||||
{
|
||||
if(pl.repeat)
|
||||
{
|
||||
//do repeat
|
||||
await pl.restart();
|
||||
} else {
|
||||
setTimeout(() => this.stop(msg), 1000);
|
||||
this.app.bot.createMessage(msg.channel.id, U.createQuickEmbed("Finished playing", "Playlist over"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//play next song
|
||||
this.play(vc, msg);
|
||||
}
|
||||
|
||||
unregisterPlayerEvents(player)
|
||||
{
|
||||
player.removeAllListeners("disconnect");
|
||||
player.removeAllListeners("error");
|
||||
player.removeAllListeners("stuck");
|
||||
player.removeAllListeners("end");
|
||||
}
|
||||
|
||||
registerPlayerEvents(player, msg)
|
||||
{
|
||||
//remove listeners to prevent memory leaks
|
||||
this.unregisterPlayerEvents(player);
|
||||
|
||||
player.on("disconnect", (e) => this.onDisconnect(e, msg));
|
||||
player.on("error", (e) => this.onError(e, msg));
|
||||
player.on("stuck", (e) => this.onStuck(e, msg));
|
||||
player.on("end", (e) => this.onEnd(e, msg));
|
||||
}
|
||||
|
||||
getPlayer(channel, unsafe)
|
||||
{
|
||||
if(!channel || !channel.guild)
|
||||
{
|
||||
if(unsafe)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
throw "channel is null or not a guild channel";
|
||||
}
|
||||
|
||||
return this.playerManager.get(channel.guild.id);
|
||||
}
|
||||
|
||||
join(channel)
|
||||
{
|
||||
if(!channel || !channel.guild)
|
||||
{
|
||||
return Promise.reject('Not a guild channel.');
|
||||
}
|
||||
|
||||
return this.app.bot.joinVoiceChannel(channel.id);
|
||||
}
|
||||
|
||||
getPlayerOld(channel)
|
||||
{
|
||||
if(!channel || !channel.guild)
|
||||
{
|
||||
return Promise.reject('Not a guild channel.');
|
||||
}
|
||||
//let player = this.app.bot.voiceConnections.get(channel.guild.id);
|
||||
let player = this.playerManager.get(channel.guild.id);
|
||||
if(player)
|
||||
{
|
||||
return Promise.resolve(player);
|
||||
}
|
||||
|
||||
let options = {}; //create a variable called "options", and store an empty object in it.
|
||||
if(channel.guild.region)
|
||||
{
|
||||
options.region = channel.guild.region; //put "channel.guild.region"'s info in options.region
|
||||
}
|
||||
|
||||
//return this.app.bot.voiceConnections.join(channel.guild.id, channel.id, options);
|
||||
//return this.playerManager.join(channel.guild.id, channel.id, options);
|
||||
//return this.app.bot.voiceConnections.join(channel.guild.id, channel.id, null);
|
||||
var conn = this.app.bot.joinVoiceChannel(channel.id);
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
async resolveTracks(node, search)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await superagent.get(`http://${node.host}:${node.restport}/loadtracks?identifier=${search}`)
|
||||
.set('Authorization', node.password)
|
||||
.set('Accept', 'application/json');
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if(!result)
|
||||
{
|
||||
throw 'Unable play that video.';
|
||||
}
|
||||
|
||||
return result.body; // array of tracks resolved from lavalink
|
||||
}
|
||||
}
|
||||
|
||||
var {PlayerManager} = require("vertbot-eris-lavalink");
|
||||
var superagent = require("superagent");
|
||||
//var SpotifyWebApi = require('spotify-web-api-node');
|
||||
//var spotifyApi = new SpotifyWebApi();
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,89 @@
|
|||
var Eris = require("eris");
|
||||
|
||||
var P = {}
|
||||
|
||||
module.exports = P;
|
||||
|
||||
//dev
|
||||
//donor
|
||||
//owner, admin
|
||||
|
||||
//dev > owner > admin > donor
|
||||
|
||||
/** returns all permissions of user that sent the given message */
|
||||
P.getPerms = async function(app, msg)
|
||||
{
|
||||
var member = msg.member;
|
||||
var dbp = await P.getDBPerms(app, member);
|
||||
var gp = await P.getGuildPerms(app, member);
|
||||
var rp = await P.getRolePerms(app, member);
|
||||
var cp = await P.getConfigPerms(app, member);
|
||||
|
||||
return Array.from(new Set([...dbp,...gp, ...cp,...rp]));
|
||||
}
|
||||
|
||||
P.getDBPerms = async function(app, member)
|
||||
{
|
||||
//TODO: get from database (donor?)
|
||||
var uid = member.id;
|
||||
var us = await app.db.getUserSettings(uid);
|
||||
var perms = us.getPermissions();
|
||||
|
||||
return new Set(perms);
|
||||
}
|
||||
|
||||
P.getGuildPerms = async function(app, member)
|
||||
{
|
||||
var perms = new Set();
|
||||
|
||||
var userPerms = member.permission
|
||||
if(userPerms.has("administrator"))
|
||||
{
|
||||
perms.add("admin");
|
||||
}
|
||||
|
||||
if(member.guild.ownerID == member.id)
|
||||
{
|
||||
perms.add("owner");
|
||||
}
|
||||
|
||||
//guild.ownerID
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
P.getRolePerms = async function(app, member)
|
||||
{
|
||||
//role name: permission name
|
||||
var mappings = {
|
||||
"dj": "dj"
|
||||
};
|
||||
|
||||
var perms = new Set();
|
||||
|
||||
for(var key in mappings)
|
||||
{
|
||||
if(U.hasRoleWithName(member, key))
|
||||
{
|
||||
perms.add(mappings[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
P.getConfigPerms = async function(app, member)
|
||||
{
|
||||
//dev, etc
|
||||
var uid = member.id;
|
||||
var perms = (app.config.perms || {})[uid];
|
||||
|
||||
if(perms == null)
|
||||
{
|
||||
return new Set();
|
||||
}
|
||||
|
||||
return new Set(perms);
|
||||
}
|
||||
|
||||
var U = require.main.require("./utils/Utils.js");
|
|
@ -0,0 +1,192 @@
|
|||
var mongoose = require("mongoose");
|
||||
var shuffle = require('shuffle-array');
|
||||
var Schema = mongoose.Schema;
|
||||
//oh boy here we go...
|
||||
|
||||
var S = {};
|
||||
module.exports = S;
|
||||
|
||||
/*----------Guild Data----------*/
|
||||
|
||||
var guildSetting = Schema({
|
||||
id: String, //guild id
|
||||
type: {type: String, default: "guild"},
|
||||
prefix: String,
|
||||
});
|
||||
|
||||
S.guildSetting = guildSetting;
|
||||
|
||||
guildSetting.methods.setPrefix = function(prefix)
|
||||
{
|
||||
this.prefix = prefix;
|
||||
//console.log("new prefix: " + prefix)
|
||||
this.save();
|
||||
}
|
||||
|
||||
/*----------Playlist Data----------*/
|
||||
|
||||
var playlist = Schema({
|
||||
id: String, //guild id
|
||||
type: {type: String, default: "playlist"},
|
||||
tracks: [],
|
||||
indexes: [],
|
||||
position: {type: Number, default: 0},
|
||||
volume: {type: Number, default: 100},
|
||||
boost: {type: Number, default: 0},
|
||||
shuffle: Boolean,
|
||||
repeat: Boolean,
|
||||
autoRemove: Boolean,
|
||||
silent: Boolean,
|
||||
djmode: Boolean
|
||||
});
|
||||
|
||||
S.playlist = playlist;
|
||||
|
||||
playlist.methods.currentTrack = function()
|
||||
{
|
||||
return this.shuffle ? this.tracks[this.indexes[this.position || 0]] : this.tracks[this.position || 0];
|
||||
}
|
||||
|
||||
playlist.methods.clear = async function()
|
||||
{
|
||||
//clear
|
||||
this.tracks.splice(0, this.tracks.length);
|
||||
this.indexes.splice(0, this.tracks.length);
|
||||
this.position = 0;
|
||||
return await this.save();
|
||||
}
|
||||
|
||||
playlist.methods.removeTrack = async function(index)
|
||||
{
|
||||
//remove
|
||||
this.tracks.splice(index, 1);
|
||||
return await this.save();
|
||||
}
|
||||
|
||||
playlist.methods.next = async function()
|
||||
{
|
||||
//increment, null safe
|
||||
this.position = this.position == null ? 0 : this.position;
|
||||
|
||||
this.position = this.position + 1;
|
||||
|
||||
return await this.save();
|
||||
}
|
||||
|
||||
playlist.methods.restart = async function()
|
||||
{
|
||||
this.position = 0;
|
||||
return await this.save();
|
||||
}
|
||||
|
||||
//TODO: make add/addall cleaner?
|
||||
playlist.methods.add = async function(track)
|
||||
{
|
||||
this.tracks.push(track);
|
||||
return await this.save();
|
||||
}
|
||||
|
||||
playlist.methods.addAll = async function(tracks)
|
||||
{
|
||||
for(var track of tracks)
|
||||
{
|
||||
await this.add(track);
|
||||
}
|
||||
}
|
||||
|
||||
playlist.methods.createShuffleArray = async function()
|
||||
{
|
||||
var indexes = this.tracks.map((e, i) => i);
|
||||
this.indexes = shuffle(indexes);
|
||||
return await this.save();
|
||||
}
|
||||
|
||||
playlist.methods.setPosition = async function(pos)
|
||||
{
|
||||
this.position = pos
|
||||
return await this.save();
|
||||
}
|
||||
|
||||
playlist.methods.setRepeat = async function(repeat)
|
||||
{
|
||||
this.repeat = repeat;
|
||||
|
||||
return await this.save();
|
||||
}
|
||||
|
||||
playlist.methods.setShuffle = async function(shuffle)
|
||||
{
|
||||
this.shuffle = shuffle;
|
||||
|
||||
return await this.save();
|
||||
}
|
||||
|
||||
playlist.methods.setSilent = async function(silent)
|
||||
{
|
||||
this.silent = silent;
|
||||
|
||||
return await this.save();
|
||||
}
|
||||
|
||||
playlist.methods.setDJMode = async function(djmode)
|
||||
{
|
||||
this.djmode = djmode;
|
||||
|
||||
return await this.save();
|
||||
}
|
||||
|
||||
playlist.methods.setVolume = async function(volume)
|
||||
{
|
||||
this.volume = volume;
|
||||
return await this.save();
|
||||
}
|
||||
|
||||
playlist.methods.setBoost = async function(boost)
|
||||
{
|
||||
this.boost = boost;
|
||||
return await this.save();
|
||||
}
|
||||
|
||||
/*----------User Data----------*/
|
||||
|
||||
var user = Schema({
|
||||
id: String, //user id
|
||||
type: {type: String, default: "user"},
|
||||
permissions: [String], //this should be a set but whatever
|
||||
});
|
||||
|
||||
S.user = user;
|
||||
|
||||
user.methods.addPermission = async function(perm)
|
||||
{
|
||||
perm = perm.trim().toLowerCase();
|
||||
|
||||
if(this.permissions.includes(perm))
|
||||
{
|
||||
//already has perm
|
||||
return;
|
||||
}
|
||||
|
||||
this.permissions.push(perm);
|
||||
|
||||
return await this.save();
|
||||
}
|
||||
|
||||
user.methods.removePermission = async function(perm)
|
||||
{
|
||||
perm = perm.trim().toLowerCase();
|
||||
|
||||
this.permissions = this.permissions.filter((e) => e != perm);
|
||||
|
||||
return await this.save();
|
||||
}
|
||||
|
||||
user.methods.hasPermission = function(perm)
|
||||
{
|
||||
return this.permissions.includes(perm);
|
||||
}
|
||||
|
||||
user.methods.getPermissions = function(perm)
|
||||
{
|
||||
return this.permissions;
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/** read from database on load, periodically save back to database */
|
||||
|
||||
module.exports = class Settings
|
||||
{
|
||||
constructor(app)
|
||||
{
|
||||
this.app = app;
|
||||
|
||||
//global settings
|
||||
//per-guild settings (maps ids to mongodb documents)
|
||||
this.guildSettings = {};
|
||||
//per-channel settings?
|
||||
//per-user settings?
|
||||
|
||||
//map of guild ids to "dirty" (upload to mongo) flags
|
||||
this.guildDirtyFlags = new Set();
|
||||
|
||||
this.load();
|
||||
|
||||
setTimeout(this.doAutoSave.bind(this), this.app.config.autoSaveInterval);
|
||||
}
|
||||
|
||||
/** uses jsonpath */
|
||||
guildGet(gid, query)
|
||||
{
|
||||
console.log(query);
|
||||
var gs = this.getGuildSettings(gid, true);
|
||||
|
||||
return jp.value(gs, query);
|
||||
}
|
||||
|
||||
guildSet(gid, query, value)
|
||||
{
|
||||
console.log(query);
|
||||
var gs = this.getGuildSettings(gid, true);
|
||||
|
||||
jp.value(gs, query, value);
|
||||
this.markGuildDirty();
|
||||
}
|
||||
|
||||
doAutoSave()
|
||||
{
|
||||
if(this.app.config.autoSave)
|
||||
{
|
||||
this.save();
|
||||
}
|
||||
|
||||
setTimeout(this.doAutoSave.bind(this), this.app.config.autoSaveInterval);
|
||||
}
|
||||
|
||||
markGuildDirty(gid)
|
||||
{
|
||||
this.guildDirtyFlags.add(gid);
|
||||
}
|
||||
|
||||
async load()
|
||||
{
|
||||
//load all guild settings for this shard
|
||||
var ids = Array.from(this.app.bot.guilds).map(([k, v]) => v.id);
|
||||
//grab guild settings from database
|
||||
var gs = await this.app.db.getGuildSettings(ids);
|
||||
//store in local cache (mapped by id)
|
||||
gs.forEach((e) => this.guildSettings[e.id] = e);
|
||||
|
||||
gs.forEach((e) => console.log(e.id + ": " + e.prefix));
|
||||
}
|
||||
|
||||
/** creates object if create is true, not null-safe */
|
||||
getGuildSettings(gid, create)
|
||||
{
|
||||
if(!this.guildSettings[gid] && create)
|
||||
{
|
||||
this.guildSettings[gid] = this.createNewGS(gid);
|
||||
this.setDirty(gid);
|
||||
}
|
||||
|
||||
return this.guildSettings[gid];
|
||||
}
|
||||
|
||||
createNewGS(gid)
|
||||
{
|
||||
var gs = {};
|
||||
gs.type = "guild";
|
||||
gs.id = gid;
|
||||
|
||||
return gs;
|
||||
}
|
||||
|
||||
save()
|
||||
{
|
||||
//for each guild with dirty flag set
|
||||
this.guildDirtyFlags.forEach(async (id, flag) =>
|
||||
{
|
||||
if(flag)
|
||||
{
|
||||
//grab guild settings
|
||||
var gs = this.getGuildSettings(id);
|
||||
//replace in mongodb
|
||||
var res = await this.app.db.updateGuildSettings(gs);
|
||||
//console.log("updated settings for guild " + id);
|
||||
}
|
||||
});
|
||||
|
||||
console.log("...Saved Settings..."); //ocd
|
||||
this.guildDirtyFlags.clear();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,481 @@
|
|||
var U = {};
|
||||
|
||||
var fd = require("format-duration");
|
||||
var format = require("number-format.js");
|
||||
|
||||
module.exports = U;
|
||||
|
||||
U.getUsersInVc = function(msg, vc)
|
||||
{
|
||||
var members = Array.from(vc.voiceMembers.keys());
|
||||
var users = 0;
|
||||
var guild = msg.channel.guild;
|
||||
|
||||
for(var i = 0; i < members.length; i++)
|
||||
{
|
||||
if(!U.getMemberById(guild, members[i]).bot)
|
||||
{
|
||||
users++
|
||||
}
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
|
||||
U.hasRoleWithName = function(member, role)
|
||||
{
|
||||
role = role.toLowerCase();
|
||||
|
||||
//get roles from guild
|
||||
var rolesWithName = member.guild.roles;
|
||||
|
||||
//filter roles that have the same name as "role"
|
||||
rolesWithName = rolesWithName.filter((e) => e.name.toLowerCase() == role);
|
||||
|
||||
//map to ids
|
||||
rolesWithName = rolesWithName.map((e) => parseInt(e.id));
|
||||
//console.log("role we want: " + rolesWithName)
|
||||
//get roles of member
|
||||
var userRoles = member.roles;
|
||||
|
||||
for(var i = 0; i < userRoles.length; i++)
|
||||
{
|
||||
var id = parseInt(userRoles[i]);
|
||||
|
||||
if(rolesWithName.includes(id))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
U.getMemberById = function(guild, id)
|
||||
{
|
||||
return guild.members.filter((e) => e.id == id)[0];
|
||||
}
|
||||
|
||||
/** finds the voice channel of the user that sent the given message */
|
||||
U.msg2vc = function(msg)
|
||||
{
|
||||
var vcid = msg.member.voiceState.channelID;
|
||||
var vc = msg.channel.guild.channels.get(vcid);
|
||||
|
||||
return vc;
|
||||
}
|
||||
|
||||
U.msg2gid = function(msg)
|
||||
{
|
||||
var gid = msg.channel.guild.id;
|
||||
|
||||
return gid;
|
||||
}
|
||||
|
||||
U.currentVC = function(app, gid)
|
||||
{
|
||||
var guild = app.bot.guilds.get(gid);
|
||||
var member = guild.members.get(app.bot.user.id);
|
||||
var vcid = member.voiceState.channelID;
|
||||
var vc = guild.channels.get(vcid);
|
||||
|
||||
return vc;
|
||||
}
|
||||
|
||||
/*U.sharedVc = function(app, msg, gid)
|
||||
{
|
||||
if()
|
||||
{
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
}*/
|
||||
|
||||
U.onOff = function(onOff)
|
||||
{
|
||||
return onOff ? "on" : "off";
|
||||
}
|
||||
|
||||
U.wrapMention = function(msg, text)
|
||||
{
|
||||
return msg.author.mention + " " + text;
|
||||
}
|
||||
|
||||
U.wrapCode = function(text)
|
||||
{
|
||||
return "```\n" + text + "```";
|
||||
}
|
||||
|
||||
/** convert milliseconds to string */
|
||||
//TODO: optional minutes/hours based on a second input (total time)
|
||||
U.ms2str = function(ms, total)
|
||||
{
|
||||
return fd(ms); //:^)
|
||||
}
|
||||
|
||||
U.sendHelp = function(app, msg, command, self)
|
||||
{
|
||||
//console.log("extra large penis", command, command.constructor.name, command.getHelp)
|
||||
U.reply(app, msg, U.wrapCode(command.getHelp(self)));
|
||||
}
|
||||
|
||||
U.reply = function(app, msg, text)
|
||||
{
|
||||
app.bot.createMessage(msg.channel.id, U.wrapMention(msg, text));
|
||||
}
|
||||
|
||||
U.getVal = function(v, min, max)
|
||||
{
|
||||
var val = v.replace( /^\D+/g, '');
|
||||
return (val > min) ? ((val < max) ? val : max) : min;
|
||||
}
|
||||
|
||||
U.str2id = function(str)
|
||||
{
|
||||
str = str.trim();
|
||||
var id = str.match(/<@!?(\d+)>|(\d+)/);
|
||||
if(id == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//id = id[0];
|
||||
id = id[1];
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/** returns true if the permission set has access to the command */
|
||||
U.canUseCommand = function(userPerms, command, pl)
|
||||
{
|
||||
if(command.permissions.length == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//if we have all permissions
|
||||
//REEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEturn
|
||||
return command.permissions.every((reqPerm) => {
|
||||
|
||||
if(userPerms.includes("dev"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//if require permission is in user perms
|
||||
if(userPerms.includes(reqPerm))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//override owner -> admin
|
||||
if(reqPerm == "admin" && ["owner"].some((e) => userPerms.includes(e)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//override owner & admin -> dj
|
||||
if(reqPerm == "dj" && ["owner", "admin"].some((e) => userPerms.includes(e)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//override the dj permission check if dj mode is turned on
|
||||
if((reqPerm == "dj" && pl.djmode == false) || (reqPerm == "dj" && pl.djmode == undefined))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; //User does not have the permissions to use the command
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
U.hexToColour = function(hex)
|
||||
{
|
||||
return parseInt(hex, 16);
|
||||
}
|
||||
|
||||
U.getCurrentShard = function(app, gid)
|
||||
{
|
||||
return (app.bot.guilds.get(gid).shard.id + 1) + " / " + ((app.bot.shards.size != undefined || app.bot.shards.size != null) ? app.bot.shards.size : "1");
|
||||
}
|
||||
|
||||
U.getLogicalChannel = function(app, guild)
|
||||
{
|
||||
var chans = guild.channels.filter(c => !c.type);
|
||||
var channels = Array.from(chans);
|
||||
|
||||
channels.sort((a,b) => a.position - b.position);
|
||||
|
||||
//Bot channel check
|
||||
for(var i = 0; i < channels.length; i++)
|
||||
{
|
||||
if(channels[i].name.match(/(-bot)|(bot-)|^bot$/gi))
|
||||
{
|
||||
return channels[i];
|
||||
}
|
||||
}
|
||||
|
||||
//General Channel Check
|
||||
for(var i = 0; i < channels.length; i++)
|
||||
{
|
||||
if(channels[i].name.match(/(-general)|(general-)|^general$/gi))
|
||||
{
|
||||
return channels[i];
|
||||
}
|
||||
}
|
||||
|
||||
//If the general and bot channel cannot be found, use the first channel the bot can speak in
|
||||
for(var i = 0; i < channels.length; i++)
|
||||
{
|
||||
if(U.canSpeak(app, channels[i]))
|
||||
{
|
||||
return channels[i];
|
||||
}
|
||||
}
|
||||
|
||||
//If all else fails return null
|
||||
return null;
|
||||
}
|
||||
|
||||
U.canSpeak = function(app, chan)
|
||||
{
|
||||
var id = app.bot.user.id;
|
||||
|
||||
return chan.permissionsOf(id).has("sendMessages");
|
||||
}
|
||||
|
||||
//------------Embeds------------
|
||||
U.embedField = function(name, value, inline)
|
||||
{
|
||||
return {
|
||||
name: name,
|
||||
value: value,
|
||||
inline: inline
|
||||
}
|
||||
}
|
||||
|
||||
U.thumbnail = function(url, width, height)
|
||||
{
|
||||
return {
|
||||
url: url,
|
||||
proxy_url: url,
|
||||
width: width,
|
||||
height: height
|
||||
}
|
||||
}
|
||||
|
||||
U.author = function(name, url, icon)
|
||||
{
|
||||
return {
|
||||
name: name,
|
||||
url: url,
|
||||
icon_url: icon,
|
||||
proxy_icon_url: icon
|
||||
}
|
||||
}
|
||||
|
||||
U.createSearchEmbed = function(title, id, author)
|
||||
{
|
||||
var url = "https://youtube.com/watch?v=" + id; //This is the link back to the video... you should understand how this works already
|
||||
var thumbnail = "https://i.ytimg.com/vi/" + id + "/hqdefault.jpg"; //This is pretty much how the api gets the thumbnail, but without the api
|
||||
return {
|
||||
embed:
|
||||
{
|
||||
color: U.hexToColour("00C4B1"),
|
||||
description: "[" + title + "](" + url + ")",
|
||||
author:
|
||||
{
|
||||
name: author
|
||||
},
|
||||
image:
|
||||
{
|
||||
url: thumbnail
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U.createPlaylistEmbed = function(pl, player, vc)
|
||||
{
|
||||
//TODO: fill these in
|
||||
var curTrack = pl.shuffle ? pl.tracks[pl.indexes[pl.position]] : pl.tracks[pl.position];
|
||||
var position = pl.shuffle ? pl.indexes[pl.position] : pl.position;
|
||||
var nowPlaying = vc == undefined ? "Nothing" : curTrack.info.title;
|
||||
//TODO: player null check
|
||||
var time = player == null || curTrack == null ? "0:00 / 0:00" : U.ms2str(player.state.position) + " / " + U.ms2str(curTrack.info.length);
|
||||
var modes = U.wrapCode("Repeat: " + U.onOff(pl.repeat) + ", Shuffle: " + U.onOff(pl.shuffle) + ", Silent: " + U.onOff(pl.silent) + ", DJ Mode: " + U.onOff(pl.djmode));
|
||||
|
||||
//var trackNames = pl.tracks.map((e) => e.info.title);
|
||||
|
||||
//find start, end centered around current position (pl.position)
|
||||
var beforeAfter = 7;
|
||||
var start = position - beforeAfter;
|
||||
var end = position + beforeAfter;
|
||||
|
||||
var str = "```markdown\n";
|
||||
for(var i = start; i < end; i++)
|
||||
{
|
||||
if(i >= 0 && i < pl.tracks.length)
|
||||
{
|
||||
var t = pl.tracks[i];
|
||||
str += i == position ? "> " : " ";
|
||||
str += position <= 992 ? (i + 1 + ": ").padEnd(5, " ") : (i + 1 + ": ").padEnd(6, " ");
|
||||
str += position <= 992 ? (t.info.title.length > 50 ? (t.info.title.substring(0, 50) + "...") : t.info.title) : (t.info.title.length > 48 ? (t.info.title.substring(0, 48) + "...") : t.info.title);
|
||||
str += "\n";
|
||||
}
|
||||
}
|
||||
str += "\n{" + pl.tracks.length + " videos in total}```\n"
|
||||
|
||||
return {
|
||||
embed:
|
||||
{
|
||||
color: U.hexToColour("00C4B1"),
|
||||
fields:
|
||||
[
|
||||
U.embedField("Playlist:", str, false),
|
||||
U.embedField("Now Playing:", nowPlaying, false),
|
||||
U.embedField("Time:", time, false),
|
||||
U.embedField("Modes:", modes, false)
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
U.createInfoEmbed = function(app, gid, prefix, msg)
|
||||
{
|
||||
return {
|
||||
embed:
|
||||
{
|
||||
author: U.author("Vertbot", "https://kaydax.xyz/", app.bot.user.avatarURL),
|
||||
description: "I'm Vertbot, a Discord bot built with Eris and Lavalink. My main purpose is to be one of the only Discord bots that give people the power to play music with little lag and very few limitations.",
|
||||
color: U.hexToColour("00C4B1"),
|
||||
fields:
|
||||
[
|
||||
U.embedField("Current prefix:", prefix, true),
|
||||
U.embedField("Current Build:", app.version, true),
|
||||
U.embedField("Uptime:", U.ms2str(app.bot.uptime), true),
|
||||
U.embedField("Servers:", format("#,###.", app.bot.guilds.size), true),
|
||||
U.embedField("Users:", format("#,###.", app.bot.users.size), true),
|
||||
U.embedField("Shard:", U.getCurrentShard(app, gid), true),
|
||||
U.embedField("My Discord:", "[Join Now](https://discord.gg/WPUU2dF)", true),
|
||||
U.embedField("Servers using music:", app.bot.voiceConnections.size, true),
|
||||
U.embedField("Ping:", msg.channel.guild.shard.latency, true)
|
||||
],
|
||||
footer:
|
||||
{
|
||||
text: "Developed by: Kaydax#0001 & tehZevo#0321."
|
||||
}
|
||||
}
|
||||
} //U.embedField("", "", true)
|
||||
}
|
||||
|
||||
U.createWelcomeEmbed = function(app)
|
||||
{
|
||||
return {
|
||||
embed:
|
||||
{
|
||||
author: U.author("Vertbot", "https://kaydax.xyz/", app.bot.user.avatarURL),
|
||||
description: "Hello, I'm Vertbot! Thank you for adding me to your server. To get started just do `v-help` and look through the list of commands. If you don't understand how to use the commands, join my support server.",
|
||||
color: U.hexToColour("00C4B1"),
|
||||
fields:
|
||||
[
|
||||
U.embedField("My Support Server:", "[Join Now](https://discord.gg/WPUU2dF)", true),
|
||||
U.embedField("Vote For Me:", "[Please Vote](https://discordbots.org/bot/316520238835433482/vote)", true),
|
||||
U.embedField("Donate Now:", "Please help me continue to run by [clicking here](https://donatebot.io/checkout/317570975908495361) else do `v-donate`", true),
|
||||
],
|
||||
footer:
|
||||
{
|
||||
text: "Developed by: Kaydax#0001 & tehZevo#0321"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U.createDonateEmbed = function()
|
||||
{
|
||||
return {
|
||||
embed:
|
||||
{
|
||||
title: "Help me continue to run by donating!",
|
||||
description: "If you want to help me continue to run, just donate to either [Kaydax](https://donatebot.io/checkout/317570975908495361) or [tehZevo](https://zevo.me/)",
|
||||
color: U.hexToColour("00C4B1"),
|
||||
fields:
|
||||
[
|
||||
U.embedField("I also support crypto:", "```\nBitcoin: 12gzEmGsNtqPpaJQG4dKGAFcgvu7aP6q47\nEthereum: 0xCC4050FF70008D3D9875CeEFbDCbCe27F5bc61bd\nXRP: r4TQWdYrpiibCwmXWZhajbnUcwHZvKRebn\nBAT: 0xCC4050FF70008D3D9875CeEFbDCbCe27F5bc61bd\nDogecoin: DKvXdxNAGLPAob2yEDoZPNr8cp31oSjKWD\nStellar: GBCVXJJQDIT2WJYRVN23DBC635VPZDRGCBG3A3ILMGJWZOCWK4GSKAEF\nBitcoin Cash: qpytmmpm8an6cfds3t8mqyxnn4pcmqderscv6dgtar\nBinance Coin: bnb1pf4mwyh76g5y4gqjh9khlsagqxy8trjhnel0mq\nBitcoin SV: 1DXqBUUXUwiEjSJy4zFg7Hsn455iCxBwCi\nDash: XxB815XHAMGdv5PECfWtnx6oyHmP4FW2pv\nLitecoin: LdCHqHD4ggWdRQF84TSBU5BahJAn7LvF2q\nNEO: AR1piF14vZfesSmERGbsyJ1b5cct6SYqUL\nTron: TULZsQj4539DHi9mA9Df7RFBmjAeQeSkoV\nTUSD: 0xCC4050FF70008D3D9875CeEFbDCbCe27F5bc61bd\nUSDC: 0xCC4050FF70008D3D9875CeEFbDCbCe27F5bc61bd\nZcash: t1f951Yv8UddswqNreAgiojwcGBBMVzd7wE```", false),
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U.createBooruEmbed = function(user, image, tags, url)
|
||||
{
|
||||
return {
|
||||
embed:
|
||||
{
|
||||
title: "Booru command requested by " + user,
|
||||
color: U.hexToColour("00C4B1"),
|
||||
image:
|
||||
{
|
||||
url: image,
|
||||
proxy_url: image
|
||||
},
|
||||
fields:
|
||||
[
|
||||
U.embedField("Tags:", "```" + tags + "```", false),
|
||||
U.embedField("Post URL:", url, false)
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U.createSuccessEmbed = function(reason, desc)
|
||||
{
|
||||
return {
|
||||
embed:
|
||||
{
|
||||
title: "Success: " + reason,
|
||||
description: desc,
|
||||
color: U.hexToColour("009b19")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U.createNowPlayingEmbed = function(pos, desc)
|
||||
{
|
||||
return {
|
||||
embed:
|
||||
{
|
||||
title: "Now Playing " + pos + ":",
|
||||
description: desc,
|
||||
color: U.hexToColour("00C4B1")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U.createErrorEmbed = function(reason, desc)
|
||||
{
|
||||
return {
|
||||
embed:
|
||||
{
|
||||
title: "Error: " + reason,
|
||||
description: desc,
|
||||
color: U.hexToColour("c04040")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U.createQuickEmbed = function(title, desc)
|
||||
{
|
||||
return {
|
||||
embed:
|
||||
{
|
||||
title: title,
|
||||
description: desc,
|
||||
color: U.hexToColour("00C4B1")
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------------
|
Loading…
Reference in New Issue