diff --git a/CommandBase.js b/CommandBase.js new file mode 100644 index 0000000000000000000000000000000000000000..2222d7817ef30a2448fe56a97a28123a8513df86 --- /dev/null +++ b/CommandBase.js @@ -0,0 +1,7 @@ +class CommandBase { + constructor(client) { + this.client = client; + } +} + +module.exports = CommandBase; \ No newline at end of file diff --git a/README.md b/README.md index d8a9df99017206e29440a175c050d4013b310b22..5e94206b1b1c0f271ee9eba3fd2243abf383e8f7 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,13 @@ This bot listens on the Federated Timeline and follows everyone. This bot respect the #nobot tag. If you don't want to be followed by the bot anymore, -just DM "unfollow" to the bot, and it'll never follow you again. [WIP] +just DM "unfollow" to the bot, and it'll never follow you again. |Command|What is does| |---|---| -|unfollow|[WIP] The bot will unfollow and mure you so it'll never follow you again.| -|blockuser <user@domain.tld>|[WIP] The bot will mute the targeted user. If followed, it'll unfollow they too. Admin only.| -|blockdomain <domain.tld>|[WIP] The bot will mute the targeted domain. If users from this domain are followed, it'll unfollow them. Admin only.| +|unfollow|The bot will unfollow and mure you so it'll never follow you again.| +|blockuser <user@domain.tld>|The bot will mute the targeted user. If followed, it'll unfollow they too. Admin only.| +|blockdomain <domain.tld>|The bot will mute the targeted domain. If users from this domain are followed, it'll unfollow them. Admin only.| ## Running the bot diff --git a/bot.js b/bot.js index 63dab79cded1e31a2e97d2d555be823df089b216..753137b0c11ee322c94891f4dc952511e58c367b 100644 --- a/bot.js +++ b/bot.js @@ -1,9 +1,6 @@ const EventEmitter = require('events'); const MastodonAPI = require('mastodon-api'); -// Todo: Implements mute_user and block_domain -// Todo: Implements unfollow - class Bot extends EventEmitter { /** * Constructor @@ -110,6 +107,15 @@ class Bot extends EventEmitter { follow(id) { this.M.post('accounts/' + id + '/follow'); } + + /** + * Unfollow a user + * @param {int} id + */ + unfollow(id) { + this.M.post('accounts/' + id + '/unfollow'); + } + /** * Mute an user * @param {int} id @@ -118,5 +124,13 @@ class Bot extends EventEmitter { this.M.post('accounts/' + id + '/mute'); } + /** + * Block a domain + * @param {string} domain + */ + block_domain(domain) { + this.M.post('domain_blocks', { domain }); + } } + module.exports = Bot; \ No newline at end of file diff --git a/commands/BlockDomain.js b/commands/BlockDomain.js new file mode 100644 index 0000000000000000000000000000000000000000..1a9753e0c4281c330e9f9ca436799fa2cc07aca1 --- /dev/null +++ b/commands/BlockDomain.js @@ -0,0 +1,18 @@ +const CommandBase = require('../CommandBase'); + +class BlockDomain extends CommandBase { + constructor(client) { + super(client); + this.name = 'blockdomain'; + this.admin_only = true; + this.required_args = 1; + } + + execute(msg, args) { + this.client.block_domain(args[0]); + + this.client.fav(msg.status.id); + } +} + +module.exports = BlockDomain; \ No newline at end of file diff --git a/commands/MuteUser.js b/commands/MuteUser.js new file mode 100644 index 0000000000000000000000000000000000000000..116465be9057e7edd002fb61cdcc2323a5bb345a --- /dev/null +++ b/commands/MuteUser.js @@ -0,0 +1,18 @@ +const CommandBase = require('../CommandBase'); + +class MuteUser extends CommandBase { + constructor(client) { + super(client); + this.name = 'muteuser'; + this.admin_only = true; + this.required_args = 1; + } + + execute(msg, args) { + this.client.mute_user(args[0]); + + this.client.fav(msg.status.id); + } +} + +module.exports = MuteUser; \ No newline at end of file diff --git a/commands/Unfollow.js b/commands/Unfollow.js new file mode 100644 index 0000000000000000000000000000000000000000..9505c02d51384d57b9af97395d3c682472b68a6e --- /dev/null +++ b/commands/Unfollow.js @@ -0,0 +1,18 @@ +const CommandBase = require('../CommandBase'); + +class Unfollow extends CommandBase { + constructor(client) { + super(client); + this.name = 'unfollow'; + } + + execute(msg) { + this.client.unfollow(msg.account.id); + + this.client.mute_user(msg.account.id); + + this.client.fav(msg.status.id); + } +} + +module.exports = Unfollow; \ No newline at end of file diff --git a/index.js b/index.js index 7e3c39a6c24a6e83a48e6c7c75c9f66fef72c7a3..fadc7a84a9164414e114877495b70fe12240b340 100644 --- a/index.js +++ b/index.js @@ -1,10 +1,23 @@ const Bot = require("./bot"); const striptags = require('striptags'); +const fs = require('fs'); +const Dict = require('collections/dict'); const config = require('./config.json'); +// Hardcode admins since Mastodon API doesn't provide such thing... +const admins = ['tagadmin', 'Dhveszak', 'Incandescente']; + const client = new Bot(config, [{api_point: "public", events: ["update"]}, {api_point: "user", events: ["notification"]}]); +const commands = new Dict(); +const commandFiles = fs.readdirSync(__dirname + "/commands/"); +for (const file of commandFiles) { + const commandClass = require(__dirname + "/commands/" + file); + const command = new commandClass(client); + commands.set(command.name, command) +} + // Following list const following = []; @@ -16,6 +29,7 @@ client.start().then(() => { }); }); +// When a toot arrives in Federated Timeline client.on('update', (msg) => { const acct = msg.account.acct; const id = parseInt(msg.account.id); @@ -45,10 +59,43 @@ client.on('update', (msg) => { console.log("NOW FOLLOWS: " + acct); }); +// When a toto arrives in notifications (mentions) client.on("notification", (msg) => { if (msg.type !== "mention") return; - // Todo: Implement unfollow command - // Todo: Implement blockuser command - // Todo: Implement blockdomain command + if (!admins.some((e) => { return e === msg.account.acct;})) return; + + const status = striptags(msg.status.content); + + if (!status.startsWith(client.me.acct)) return; + + const args = stripped.slice(client.me.acct + 1).trim().split(/ +/); + const commandName = args.shift().toLowerCase(); + + //Check if command exists + if (!this.commands.has(commandName)) { + return; + } + const command = this.commands.get(commandName); + + //Check if command is disabled + if (command.disabled === true) return; + + //Check if command is AdminOnly + if(command.admin_only === true && !admins.some((e) => { return e === msg.account.acct;})) return; + + //Check args length + if (command.required_args > args) { + return; + } + + console.log(`CMD: ${commandName} from ${msg.account.acct}`); + + //Execute the command + try { + command.execute(msg, args); + } + catch (error) { + console.error(error); + } }); \ No newline at end of file diff --git a/package.json b/package.json index 8f668da0e0a835395877e8698e018cdbd40f81fc..cd1f73ea62ce5e47e1bd3532ae2b7b072f003c58 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "federationbot", "version": "0.0.1", "dependencies": { + "collections": "^5.1.2", "mastodon-api": "^1.3.0", "striptags": "^3.1.1" }