Start of rewrite
This commit is contained in:
commit
97e46f6447
12 changed files with 1448 additions and 0 deletions
14
.eslintignore
Normal file
14
.eslintignore
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
pnpm-debug.log
|
||||||
|
dist
|
||||||
|
.cache
|
||||||
|
.tern-port
|
||||||
|
config.json
|
||||||
|
package-lock.json
|
||||||
|
README.html
|
||||||
|
*~
|
||||||
|
\#*\#
|
||||||
|
node_modules
|
||||||
|
yarn-error.log
|
||||||
|
npm-error.log
|
||||||
|
/.vscode
|
||||||
|
/.idea
|
31
.eslintrc.js
Normal file
31
.eslintrc.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
const OFF = 0;
|
||||||
|
// const WARN = 1;
|
||||||
|
const ERROR = 2;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
extends: ["eslint:recommended"],
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 2020,
|
||||||
|
},
|
||||||
|
env: {
|
||||||
|
es6: true,
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
indent: OFF,
|
||||||
|
semi: ERROR,
|
||||||
|
quotes: [ERROR, "double", {avoidEscape: true, allowTemplateLiterals: true}],
|
||||||
|
"no-empty": ERROR,
|
||||||
|
"array-callback-return": ERROR,
|
||||||
|
"consistent-return": ERROR,
|
||||||
|
eqeqeq: OFF,
|
||||||
|
"prefer-const": ERROR,
|
||||||
|
"no-unused-vars": [ERROR, {args: "none", varsIgnorePattern: "^_"}],
|
||||||
|
"no-console": OFF,
|
||||||
|
"no-debugger": OFF,
|
||||||
|
"require-atomic-updates": OFF,
|
||||||
|
},
|
||||||
|
globals: {
|
||||||
|
hf: true,
|
||||||
|
},
|
||||||
|
};
|
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
config.json
|
||||||
|
config.prod.json
|
||||||
|
config.testing.json
|
||||||
|
apikeys.json
|
5
.prettierrc
Normal file
5
.prettierrc
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"semi": true,
|
||||||
|
"bracketSpacing": false,
|
||||||
|
"endOfLine": "lf"
|
||||||
|
}
|
2
README.md
Normal file
2
README.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# HiddenPhox
|
||||||
|
**This is the rewrite branch. For the main branch go [here](https://gitlab.com/Cynosphere/HiddenPhox/-/tree/master)**
|
30
package.json
Normal file
30
package.json
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"name": "hiddenphox",
|
||||||
|
"version": "10.0.0",
|
||||||
|
"description": "Discord bot",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://gitlab.com/Cynosphere/HiddenPhox.git"
|
||||||
|
},
|
||||||
|
"author": "Cynosphere",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://gitlab.com/Cynosphere/HiddenPhox/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://gitlab.com/Cynosphere/HiddenPhox#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"colorcolor": "^1.1.1",
|
||||||
|
"eris": "github:abalabahaha/eris#dev",
|
||||||
|
"murmurhash": "^2.0.0",
|
||||||
|
"node-fetch": "^2.6.1",
|
||||||
|
"npmlog": "^4.1.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"eslint": "^7.22.0",
|
||||||
|
"prettier": "^2.2.1"
|
||||||
|
}
|
||||||
|
}
|
1001
pnpm-lock.yaml
Normal file
1001
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load diff
66
src/index.js
Normal file
66
src/index.js
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
const Eris = require("eris");
|
||||||
|
const logger = require("npmlog");
|
||||||
|
const fs = require("fs");
|
||||||
|
const {resolve} = require("path");
|
||||||
|
|
||||||
|
const config = require("../config.json");
|
||||||
|
const Command = require("./lib/command.js");
|
||||||
|
const CommandDispatcher = require("./lib/commandDispatcher.js");
|
||||||
|
|
||||||
|
const bot = new Eris(config.token, {
|
||||||
|
defaultImageFormat: "png",
|
||||||
|
defaultImageSize: 1024,
|
||||||
|
});
|
||||||
|
|
||||||
|
const commands = new Eris.Collection();
|
||||||
|
|
||||||
|
function registerCommand(cmdObj) {
|
||||||
|
if (cmdObj instanceof Command) {
|
||||||
|
commands.set(cmdObj.name, cmdObj);
|
||||||
|
const aliases = cmdObj.getAliases();
|
||||||
|
logger.info(
|
||||||
|
"hf:cmd",
|
||||||
|
"Registered command '%s'%s",
|
||||||
|
cmdObj.name,
|
||||||
|
aliases.length > 0 ? ` (aliases: ${aliases.join(", ")})` : ""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global.hf = {
|
||||||
|
bot,
|
||||||
|
config,
|
||||||
|
commands,
|
||||||
|
registerCommand,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const file of fs.readdirSync(resolve(__dirname, "modules"))) {
|
||||||
|
require(resolve(__dirname, "modules", file));
|
||||||
|
logger.info("hf:modules", "Loaded module: '%s'", file);
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.on("messageCreate", CommandDispatcher);
|
||||||
|
bot.on("messageUpdate", (msg) => {
|
||||||
|
const oneDay = Date.now() - 86400000;
|
||||||
|
if (msg.timestamp > oneDay && !msg.hasRan) {
|
||||||
|
CommandDispatcher(msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bot.on("ready", async () => {
|
||||||
|
logger.info("hf:main", "Connected to Discord.");
|
||||||
|
logger.info(
|
||||||
|
"hf:main",
|
||||||
|
"Logged in as: %s#%s (%s)",
|
||||||
|
bot.user.username,
|
||||||
|
bot.user.discriminator,
|
||||||
|
bot.user.id
|
||||||
|
);
|
||||||
|
|
||||||
|
const channel = await bot.getDMChannel(config.owner_id);
|
||||||
|
if (channel) {
|
||||||
|
channel.createMessage(":white_check_mark: Loaded HiddenPhox.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bot.connect();
|
39
src/lib/command.js
Normal file
39
src/lib/command.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
const {Permissions} = require("eris/lib/Constants");
|
||||||
|
|
||||||
|
class Command {
|
||||||
|
constructor(name) {
|
||||||
|
this.name = name;
|
||||||
|
this.aliases = [];
|
||||||
|
this.permissions = {};
|
||||||
|
this.helpText = "No description provided.";
|
||||||
|
this.category = "unsorted";
|
||||||
|
}
|
||||||
|
|
||||||
|
addAlias(alias) {
|
||||||
|
this.aliases.push(alias);
|
||||||
|
}
|
||||||
|
getAliases() {
|
||||||
|
return this.aliases;
|
||||||
|
}
|
||||||
|
hasAlias(alias) {
|
||||||
|
return this.aliases.includes(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
addPermission(permission) {
|
||||||
|
if (Permissions[permission]) {
|
||||||
|
this.permissions[permission] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removePermission(permission) {
|
||||||
|
delete this.permissions[permission];
|
||||||
|
}
|
||||||
|
getPermissions() {
|
||||||
|
return this.permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback() {
|
||||||
|
return "Callback not overwritten.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Command;
|
94
src/lib/commandDispatcher.js
Normal file
94
src/lib/commandDispatcher.js
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
const logger = require("npmlog");
|
||||||
|
|
||||||
|
function parseArguments(str) {
|
||||||
|
return str.match(/\\?.|^$/g).reduce(
|
||||||
|
(p, c) => {
|
||||||
|
if (c === '"') {
|
||||||
|
p.quote ^= 1;
|
||||||
|
} else if (!p.quote && c === " ") {
|
||||||
|
p.a.push("");
|
||||||
|
} else {
|
||||||
|
p.a[p.a.length - 1] += c.replace(/\\(.)/, "$1");
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
},
|
||||||
|
{a: [""]}
|
||||||
|
).a;
|
||||||
|
}
|
||||||
|
|
||||||
|
function runCommand(msg, cmd, line, args) {
|
||||||
|
let cmdObj = hf.commands.get(cmd);
|
||||||
|
if (!cmdObj) {
|
||||||
|
for (const c of hf.commands.values()) {
|
||||||
|
if (c.hasAlias(cmd)) {
|
||||||
|
cmdObj = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!cmdObj) return null;
|
||||||
|
|
||||||
|
if (cmdObj.ownerOnly && msg.author.id != hf.config.owner_id) {
|
||||||
|
return "No\n\nSent from my iPhone.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdObj.elevatedOnly && !hf.config.elevated.includes(msg.author.id)) {
|
||||||
|
return "No\n\nSent from my iPhone.";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return cmdObj.callback(msg, line, ...args);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error("hf:cmd:" + cmd, err);
|
||||||
|
return ":warning: An internal error occurred.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function CommandDispatcher(msg) {
|
||||||
|
let str = msg.content;
|
||||||
|
let inCommand = false;
|
||||||
|
|
||||||
|
const prefix1 = hf.config.prefix;
|
||||||
|
const prefix2 = `<@${hf.bot.user.id}> `;
|
||||||
|
const prefix3 = `<@!${hf.bot.user.id}> `;
|
||||||
|
|
||||||
|
if (str.startsWith(prefix1)) {
|
||||||
|
str = str.substring(prefix1.length);
|
||||||
|
inCommand = true;
|
||||||
|
} else if (str.startsWith(prefix2)) {
|
||||||
|
str = str.substring(prefix2.length);
|
||||||
|
inCommand = true;
|
||||||
|
} else if (str.startsWith(prefix3)) {
|
||||||
|
str = str.substring(prefix3.length);
|
||||||
|
inCommand = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inCommand) {
|
||||||
|
let line = str.split(" ");
|
||||||
|
let [cmd] = line.splice(0, 1);
|
||||||
|
cmd = cmd.toLowerCase();
|
||||||
|
line = line.join(" ");
|
||||||
|
|
||||||
|
const args = parseArguments(line);
|
||||||
|
|
||||||
|
const response = runCommand(msg, cmd, line, args);
|
||||||
|
if (response) {
|
||||||
|
msg.channel.createMessage(
|
||||||
|
Object.assign(
|
||||||
|
typeof response === "string" ? {content: response} : response,
|
||||||
|
{
|
||||||
|
allowedMentions: {
|
||||||
|
repliedUser: false,
|
||||||
|
},
|
||||||
|
messageReferenceID: msg.id,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
response.file
|
||||||
|
);
|
||||||
|
}
|
||||||
|
msg.hasRan = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = CommandDispatcher;
|
25
src/lib/misc.js
Normal file
25
src/lib/misc.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
const {v3} = require("murmurhash");
|
||||||
|
const colorcolor = require("colorcolor");
|
||||||
|
|
||||||
|
function pastelize(id) {
|
||||||
|
const hue = v3(id) % 360;
|
||||||
|
const hex = colorcolor(`hsl(${hue},75%,60%)`, "hex");
|
||||||
|
return parseInt(hex.substring(1), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTopColor(msg, id, fallback = 0x7289da) {
|
||||||
|
if (!msg.channel.guild) return fallback;
|
||||||
|
|
||||||
|
const roles = msg.channel.guild.members
|
||||||
|
.get(id)
|
||||||
|
.roles.map((role) => msg.channel.guild.roles.get(role))
|
||||||
|
.filter((role) => role.color);
|
||||||
|
roles.sort((a, b) => b.position - a.position);
|
||||||
|
|
||||||
|
return roles[0]?.color || fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
pastelize,
|
||||||
|
getTopColor,
|
||||||
|
};
|
135
src/modules/general.js
Normal file
135
src/modules/general.js
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
const Command = require("../lib/command.js");
|
||||||
|
const CATEGORY = "general";
|
||||||
|
const {pastelize, getTopColor} = require("../lib/misc.js");
|
||||||
|
|
||||||
|
const help = new Command("help");
|
||||||
|
help.category = CATEGORY;
|
||||||
|
help.helpText = "Lists all commands";
|
||||||
|
help.usage = "[command] or [--category]";
|
||||||
|
help.callback = function (msg, line) {
|
||||||
|
const color = getTopColor(msg, hf.bot.user.id, pastelize(hf.bot.user.id));
|
||||||
|
const sorted = {};
|
||||||
|
|
||||||
|
for (const cmd of hf.commands.values()) {
|
||||||
|
const cat = cmd.category.toLowerCase();
|
||||||
|
if (!sorted[cat]) {
|
||||||
|
sorted[cat] = [];
|
||||||
|
}
|
||||||
|
sorted[cat].push(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line == "") {
|
||||||
|
const embed = {
|
||||||
|
title: "HiddenPhox Help",
|
||||||
|
color,
|
||||||
|
fields: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const cat in sorted) {
|
||||||
|
embed.fields.push({
|
||||||
|
name: cat.toUpperCase().charAt(0) + cat.toLowerCase().substring(1),
|
||||||
|
value: `${sorted[cat].length} Commands\n\`${
|
||||||
|
hf.config.prefix
|
||||||
|
}help --${cat.toLowerCase()}\``,
|
||||||
|
inline: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {embed};
|
||||||
|
} else if (line.startsWith("--")) {
|
||||||
|
const cat = line.replace("--", "").toLowerCase().trim();
|
||||||
|
|
||||||
|
if (sorted[cat]) {
|
||||||
|
const embed = {
|
||||||
|
title: `HiddenPhox Help: Category > ${
|
||||||
|
cat.toUpperCase().charAt(0) + cat.toLowerCase().substring(1)
|
||||||
|
}`,
|
||||||
|
color,
|
||||||
|
fields: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const cmd of sorted[cat]) {
|
||||||
|
embed.fields.push({
|
||||||
|
name: hf.config.prefix + cmd.name,
|
||||||
|
value: cmd.helpText,
|
||||||
|
inline: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {embed};
|
||||||
|
} else {
|
||||||
|
return "Category not found.";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let cmd = hf.commands.get(line.toLowerCase().trim());
|
||||||
|
if (!cmd) {
|
||||||
|
for (const c of hf.commands.values()) {
|
||||||
|
if (c.hasAlias(line.toLowerCase().trim())) {
|
||||||
|
cmd = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd) {
|
||||||
|
const aliases = cmd.getAliases();
|
||||||
|
|
||||||
|
const embed = {
|
||||||
|
title: `HiddenPhox Help: Command > \`${hf.config.prefix}${cmd.name}\``,
|
||||||
|
color,
|
||||||
|
description: cmd.helpText,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "Category",
|
||||||
|
value:
|
||||||
|
cmd.category.toUpperCase().charAt(0) +
|
||||||
|
cmd.category.toLowerCase().substring(1),
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
if (aliases.length > 0) {
|
||||||
|
embed.fields.push({
|
||||||
|
name: "Aliases",
|
||||||
|
value: aliases.join(", "),
|
||||||
|
inline: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (cmd.usage) {
|
||||||
|
embed.fields.push({
|
||||||
|
name: "Usage",
|
||||||
|
value: `${hf.config.prefix}${cmd.name} ${cmd.usage}`,
|
||||||
|
inline: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd.description) {
|
||||||
|
embed.fields.push({
|
||||||
|
name: "Full Description",
|
||||||
|
value: cmd.description,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {embed};
|
||||||
|
} else {
|
||||||
|
return "Command not found.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
hf.registerCommand(help);
|
||||||
|
|
||||||
|
const ping = new Command("ping");
|
||||||
|
ping.category = CATEGORY;
|
||||||
|
ping.helpText = "Pong";
|
||||||
|
ping.description = "Measures response times to Discord.";
|
||||||
|
ping.addAlias("p");
|
||||||
|
ping.callback = async function (msg) {
|
||||||
|
const newMsg = await msg.channel.createMessage("Pong.");
|
||||||
|
const rtt = Math.floor(newMsg.timestamp - msg.timestamp);
|
||||||
|
const gateway = hf.bot.shards.get(
|
||||||
|
hf.bot.guildShardMap[hf.bot.channelGuildMap[msg.channel.id]] || 0
|
||||||
|
).latency;
|
||||||
|
|
||||||
|
newMsg.edit(`Pong. RTT: \`${rtt}ms\`, Gateway: \`${gateway}ms\``);
|
||||||
|
};
|
||||||
|
hf.registerCommand(ping);
|
Loading…
Reference in a new issue