import { httpGET, sanitizeEscapedText } from '@squeebot/core/lib/common'; import { Plugin, EventListener, DependencyLoad, } from '@squeebot/core/lib/plugin'; import { IMessage, ProtocolFeatureFlag } from '@squeebot/core/lib/types'; async function mastodonResponse( msg: IMessage, url: string, type = 'Mastodon', limit = true ): Promise { let murl; if (type === 'Mastodon') { murl = url.match( /^(https?):\/\/((?:[\w\d-]+\.)*[\w\d-]+\.\w{2,16})\/(?:users\/)?@?([\w-_]+)\/(?:statuses\/)?(\d+[^&#?\s/])/i ); } else if (type === 'Pleroma') { murl = url.match( /^(https?):\/\/((?:[\w\d-]+\.)*[\w\d-]+\.\w{2,16})\/(notice)\/([^&#?\s/]+)/i ); } if (!murl) { return false; } const url2go = `${murl[1]}://${murl[2]}/api/v1/statuses/${murl[4]}`; let data; try { data = await httpGET(url2go); if (!data) { throw new Error('No API response, probably not ' + type + ' after all.'); } data = JSON.parse(data); } catch (e) { return false; } let content = data.content; if (!content) { return false; } if (data.spoiler_text) { content = '[CW] ' + data.spoiler_text; } const keys = []; let end = sanitizeEscapedText( content .replace(/<\/p>/g, '\n') // Add newlines to paragraph endings .replace(/
/g, '\n') // Add newlines instead of
.replace(/(<([^>]+)>)/gi, '') ); // Strip the rest of the HTML out if (end.length > 220 && limit) { end = end.substring(0, 220) + '…'; } keys.push(['field', type, { color: 'cyan', type: 'title' }]); keys.push([ 'field', data.favourites_count.toString(), { color: 'red', label: ['★', 'Favourites'], type: 'metric' }, ]); keys.push([ 'field', data.reblogs_count.toString(), { color: 'green', label: ['↱↲', 'Reblogs'], type: 'metric' }, ]); keys.push(['bold', '@' + data.account.acct + ':']); keys.push(['field', end, { type: 'content' }]); if (data.media_attachments?.length) { const amount = data.media_attachments.length; keys.push([ 'field', `[${amount} attachment${amount !== 1 ? 's' : ''}]`, { color: 'brown' }, ]); } msg.resolve(keys); return true; } class FediResponsePlugin extends Plugin { @EventListener('pluginUnload') public unloadEventHandler(plugin: string | Plugin): void { if (plugin === this.name || plugin === this) { this.emit('pluginUnloaded', this); } } @DependencyLoad('urlreply') addUrlReply(urlreply: any): void { urlreply.registerHandler( this.name, 'html/mastodon', async ( url: string, msg: IMessage, title: string, body: any ): Promise => { const type = url.match('/notice/') ? 'Pleroma' : 'Mastodon'; let pass = false; if (type === 'Pleroma') { pass = true; } else { const tag = body('a[href="https://joinmastodon.org"]'); const initTag = body('head > script[id="initial-state"][type="application/json"]'); if ( initTag || (tag && tag.text() && ((tag.text() as string).includes('Mastodon') || (tag.text() as string).includes('About'))) ) { pass = true; } } if (pass) { const mastodonTest = await mastodonResponse( msg, url, type, msg.source.supports(ProtocolFeatureFlag.SHORT_FORM_MESSAGING) ); if (mastodonTest) { return true; } } return false; } ); } } module.exports = FediResponsePlugin;