diff --git a/.eslintrc.js b/.eslintrc.js index c7012dd..62df6ab 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -16,4 +16,14 @@ module.exports = { 'plugins': [ '@typescript-eslint' ], + 'rules': { + '@typescript-eslint/no-unused-vars': [ + 'warn', + { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_', + }, + ], + } }; diff --git a/lib/plugins/libreLinks/plugin.ts b/lib/plugins/libreLinks/plugin.ts new file mode 100644 index 0000000..2d01d51 --- /dev/null +++ b/lib/plugins/libreLinks/plugin.ts @@ -0,0 +1,85 @@ +import { Message } from 'discord.js' +import { MessageHandler, Plugin } from '../pluginManager' + +// https://stackoverflow.com/a/3809435/18140793 +const URL_REGEX = + /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/g + +const getUrls = (str: string): string[] => { + const matches = Array.from(str.matchAll(URL_REGEX)) + const urls = matches.map((x) => x[0]) + return urls +} + +const isUnsignedInt = (num: string): boolean => { + for (const char of num) { + if (!(char >= '0' && char <= '9')) { + return false + } + } + + return true +} + +const getNitterLink = (link: string): string | undefined => { + const url = new URL(link) + + if (url.host != 'twitter.com') { + return + } + + const [_, ...pathSegments] = url.pathname.split('/') + const isProfile = pathSegments.length == 1 + const isStatus = + pathSegments.length == 3 && + pathSegments[1] == 'status' && + isUnsignedInt(pathSegments[2]) + + if (!isProfile && !isStatus) { + return + } + + url.search = '' + url.host = 'nitter.net' + url.protocol = 'https' + + return url.toString() +} + +const replaceUrls = (urls: string[]): string[] => { + const replaced: string[] = [] + + urls.forEach((url) => { + const transformed = getNitterLink(url) + if (transformed !== undefined) { + replaced.push(transformed) + } + }) + + return replaced +} + +const messageHandlers: MessageHandler[] = [ + { + predicate: async (_: Message) => true, + action: async (msg: Message): Promise => { + const urls = getUrls(msg.content) + const replaced = replaceUrls(urls) + + if (replaced.length == 0) { + return + } + + const response = replaced.join('\n') + await msg.channel.send(response) + }, + }, +] + +const LibreLinksPlugin: Plugin = { + name: 'libre-links', + messageHandlers, + commands: [], +} + +export default LibreLinksPlugin diff --git a/lib/plugins/pluginManager.ts b/lib/plugins/pluginManager.ts index af21c89..9d095a8 100644 --- a/lib/plugins/pluginManager.ts +++ b/lib/plugins/pluginManager.ts @@ -7,6 +7,7 @@ import config from '../config' import whoisPlugin from './whois/plugin' import { JudgementPluginFactory } from './rel/plugin' +import LibreLinksPlugin from './libreLinks/plugin' export type Command = { name: string @@ -14,6 +15,7 @@ export type Command = { handle: (interaction: CommandInteraction) => Promise } +// TODO(LiquidLemon): replace with simple middleware to prevent work duplication export type MessageHandler = { predicate: (message: Message) => Promise action: (message: Message) => Promise @@ -87,12 +89,17 @@ export default class PluginManager { } public async handleMessage(interaction: Message): Promise { + if (interaction.author.id == interaction.client.user?.id) { + return + } + const logContext = { messageContent: interaction.content, user: `${interaction.author.username}#${interaction.author.discriminator}`, userId: interaction.author.id, } + // TODO(LiquidLemon): simplify this monstrosity const messageHandler = ( await Promise.all( this.plugins @@ -111,10 +118,8 @@ export default class PluginManager { return } - logger.info('Handling message.', logContext) - try { - logger.info('Handling message.', logContext) + logger.debug('Handling message.', logContext) await messageHandler(interaction) } catch (error) { logger.error( @@ -131,6 +136,7 @@ export default class PluginManager { await JudgementPluginFactory.createPlugin( config.env.REL_DB_PATH || './sqlite.db' ), + LibreLinksPlugin, ]) } } diff --git a/lib/plugins/whois/plugin.ts b/lib/plugins/whois/plugin.ts index 7d5960f..1a7a7b9 100644 --- a/lib/plugins/whois/plugin.ts +++ b/lib/plugins/whois/plugin.ts @@ -1,4 +1,9 @@ -import { CommandInteraction, GuildMember, Message, TextChannel } from 'discord.js' +import { + CommandInteraction, + GuildMember, + Message, + TextChannel, +} from 'discord.js' import { Plugin, Command, MessageHandler } from '../pluginManager' import api from './api'