126 lines
3.5 KiB
TypeScript
126 lines
3.5 KiB
TypeScript
import {
|
|
Plugin,
|
|
Configurable,
|
|
EventListener,
|
|
DependencyLoad
|
|
} from '@squeebot/core/lib/plugin';
|
|
|
|
import { logger } from '@squeebot/core/lib/core';
|
|
|
|
import Twitter from 'twitter-lite';
|
|
import { IMessage } from '@squeebot/core/lib/types';
|
|
import { sanitizeEscapedText } from '@squeebot/core/lib/common';
|
|
|
|
interface TwitterUser {
|
|
id: number;
|
|
name: string;
|
|
screen_name: string;
|
|
description: string;
|
|
followers_count: number;
|
|
statuses_count: number;
|
|
}
|
|
|
|
interface TwitterTweet {
|
|
id: number;
|
|
full_text: string;
|
|
text?: string;
|
|
user: TwitterUser;
|
|
retweet_count: number;
|
|
favorite_count: number;
|
|
}
|
|
|
|
@Configurable({
|
|
consumer_key: null,
|
|
consumer_secret: null,
|
|
access_token_key: null,
|
|
access_token_secret: null,
|
|
})
|
|
class TwitterURLPlugin extends Plugin {
|
|
public twitter: Twitter | null = null;
|
|
public me: TwitterUser | null = null;
|
|
|
|
@EventListener('pluginUnload')
|
|
public unloadEventHandler(plugin: string | Plugin): void {
|
|
if (plugin === this.name || plugin === this) {
|
|
this.config.save().then(() =>
|
|
this.emit('pluginUnloaded', this));
|
|
}
|
|
}
|
|
|
|
async handleTweet(data: TwitterTweet, msg: IMessage): Promise<boolean> {
|
|
const keys = [];
|
|
const end = sanitizeEscapedText(data.text || data.full_text);
|
|
|
|
keys.push(['field', 'Twitter', { color: 'cyan', type: 'title' }]);
|
|
keys.push(['field', data.favorite_count.toString(), { color: 'red', label: ['♥', 'Likes'], type: 'metric' }]);
|
|
keys.push(['field', data.retweet_count.toString(), { color: 'green', label: ['↱↲', 'Retweets'], type: 'metric' }]);
|
|
keys.push(['bold', '@' + data.user.screen_name + ':']);
|
|
keys.push(['field', end, { type: 'content' }]);
|
|
|
|
msg.resolve(keys);
|
|
return true;
|
|
}
|
|
|
|
async getStatusById(id: string): Promise<any> {
|
|
if (!this.twitter) {
|
|
return null;
|
|
}
|
|
return this.twitter.get('statuses/show', {id, tweet_mode: 'extended'});
|
|
}
|
|
|
|
async twitterURLHandler(url: URL, msg: IMessage): Promise<boolean> {
|
|
const det = url.href.match(/\/\w+\/status\/(\d+[^&#?\s/])/i);
|
|
if (!det) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
const tweet = await this.getStatusById(det[1]);
|
|
if (tweet) {
|
|
return this.handleTweet(tweet as TwitterTweet, msg);
|
|
}
|
|
} catch (e) {
|
|
msg.resolve('No such tweet!');
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@DependencyLoad('urlreply')
|
|
addURLHandler(urlreply: any): void {
|
|
urlreply.registerHandler(this.name, 'twitter.com/', (url: URL, msg: IMessage) => {
|
|
return this.twitterURLHandler(url, msg);
|
|
});
|
|
|
|
urlreply.registerHandler(this.name, 'nitter.net/', (url: URL, msg: IMessage) => {
|
|
return this.twitterURLHandler(url, msg);
|
|
});
|
|
}
|
|
|
|
initialize(): void {
|
|
const consumerKey = this.config.get('consumer_key');
|
|
const consumerSecret = this.config.get('consumer_secret');
|
|
const accessToken = this.config.get('access_token_key');
|
|
const accessTokenSecret = this.config.get('access_token_secret');
|
|
|
|
if (!consumerKey || !consumerSecret || !accessToken || !accessTokenSecret) {
|
|
logger.error('[%s] Twitter credentials missing!', this.name);
|
|
return;
|
|
}
|
|
|
|
this.twitter = new Twitter({
|
|
consumer_key: consumerKey,
|
|
consumer_secret: consumerSecret,
|
|
access_token_key: accessToken,
|
|
access_token_secret: accessTokenSecret,
|
|
});
|
|
|
|
this.twitter.get('account/verify_credentials').then((data: TwitterUser) => {
|
|
this.me = data;
|
|
}, (err) => {
|
|
logger.error('[%s] Twitter threw an error!', this.name, err.stack);
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = TwitterURLPlugin;
|