|
@@ -46,7 +46,7 @@ export class ScreenNameNormalizer {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-export let sendTweet = (id: string, receiver: IChat): void => {
|
|
|
+export let sendTweet = (id: string, receiver: IChat, forceRefresh: boolean): void => {
|
|
|
throw Error();
|
|
|
};
|
|
|
|
|
@@ -141,15 +141,29 @@ export default class {
|
|
|
this.wsUrl = opt.wsUrl;
|
|
|
if (opt.redis) this.redis = new RedisSvc(opt.redis);
|
|
|
ScreenNameNormalizer._queryUser = this.queryUser;
|
|
|
- sendTweet = (id, receiver) => {
|
|
|
- this.getTweet(id, this.sendTweets({sourceInfo: `tweet ${id}`, reportOnSkip: true}, receiver))
|
|
|
+ sendTweet = (idOrQuery, receiver, forceRefresh) => {
|
|
|
+ const send = (id: string) => this.getTweet(
|
|
|
+ id,
|
|
|
+ this.sendTweets({sourceInfo: `tweet ${id}`, reportOnSkip: true, force: forceRefresh}, receiver),
|
|
|
+ forceRefresh
|
|
|
+ )
|
|
|
.catch((err: {code: number, message: string}[]) => {
|
|
|
+ if (err[0]?.code === 34)
|
|
|
+ return this.bot.sendTo(receiver, `找不到用户 ${match[2].replace(/^@?(.*)$/, '@$1')}。`);
|
|
|
if (err[0].code !== 144) {
|
|
|
logger.warn(`error retrieving tweet: ${err[0].message}`);
|
|
|
this.bot.sendTo(receiver, `获取推文时出现错误:${err[0].message}`);
|
|
|
}
|
|
|
this.bot.sendTo(receiver, '找不到请求的推文,它可能已被删除。');
|
|
|
});
|
|
|
+ const match = /^last(|-\d+)@([^\/?#,]+)((?:,no.*?=[^,]*)*)$/.exec(idOrQuery);
|
|
|
+ const query = () => this.queryTimeline({
|
|
|
+ username: match[2],
|
|
|
+ count: 0 - Number(match[1] || -1),
|
|
|
+ noreps: {on: true, off: false}[match[3].replace(/.*,noreps=([^,]*).*/, '$1')],
|
|
|
+ norts: {on: true, off: false}[match[3].replace(/.*,norts=([^,]*).*/, '$1')],
|
|
|
+ }).then(tweets => tweets.slice(-1)[0].id_str);
|
|
|
+ (match ? query() : Promise.resolve(idOrQuery)).then(send);
|
|
|
};
|
|
|
sendTimeline = ({username, count, since, until, noreps, norts}, receiver) => {
|
|
|
const countNum = Number(count) || 10;
|
|
@@ -262,9 +276,10 @@ export default class {
|
|
|
|
|
|
private workOnTweets = (
|
|
|
tweets: Tweets,
|
|
|
- sendTweets: (id: string, msg: string, text: string, author: string) => void
|
|
|
+ sendTweets: (id: string, msg: string, text: string, author: string) => void,
|
|
|
+ refresh = false
|
|
|
) => Promise.all(tweets.map(tweet =>
|
|
|
- (this.redis ? this.redis.getContent(`webshot/${tweet.id_str}`) : Promise.reject())
|
|
|
+ ((this.redis && !refresh) ? this.redis.getContent(`webshot/${tweet.id_str}`) : Promise.reject())
|
|
|
.then(content => {
|
|
|
if (content === null) throw Error();
|
|
|
logger.info(`retrieved cached webshot of tweet ${tweet.id_str} from redis database`);
|
|
@@ -283,7 +298,7 @@ export default class {
|
|
|
)
|
|
|
));
|
|
|
|
|
|
- public getTweet = (id: string, sender: (id: string, msg: string, text: string, author: string) => void) => {
|
|
|
+ public getTweet = (id: string, sender: (id: string, msg: string, text: string, author: string) => void, refresh = false) => {
|
|
|
const endpoint = 'statuses/show';
|
|
|
const config = {
|
|
|
id,
|
|
@@ -292,15 +307,16 @@ export default class {
|
|
|
return this.client.get(endpoint, config)
|
|
|
.then((tweet: Tweet) => {
|
|
|
logger.debug(`api returned tweet ${JSON.stringify(tweet)} for query id=${id}`);
|
|
|
- return this.workOnTweets([tweet], sender);
|
|
|
+ return this.workOnTweets([tweet], sender, refresh);
|
|
|
});
|
|
|
};
|
|
|
|
|
|
private sendTweets = (
|
|
|
- config: {sourceInfo?: string, reportOnSkip?: boolean} = {reportOnSkip: false}, ...to: IChat[]
|
|
|
+ config: {sourceInfo?: string, reportOnSkip?: boolean, force?: boolean} = {reportOnSkip: false, force: false},
|
|
|
+ ...to: IChat[]
|
|
|
) => (id: string, msg: string, text: string, author: string) => {
|
|
|
to.forEach(subscriber => {
|
|
|
- const {sourceInfo: source, reportOnSkip} = config;
|
|
|
+ const {sourceInfo: source, reportOnSkip, force} = config;
|
|
|
const targetStr = JSON.stringify(subscriber);
|
|
|
const send = () => retryOnError(
|
|
|
() => this.bot.sendTo(subscriber, msg),
|
|
@@ -318,7 +334,7 @@ export default class {
|
|
|
return this.redis.cacheForChat(id, subscriber);
|
|
|
}
|
|
|
});
|
|
|
- (this.redis ? this.redis.isCachedForChat(id, subscriber) : Promise.resolve(false))
|
|
|
+ ((this.redis && !force) ? this.redis.isCachedForChat(id, subscriber) : Promise.resolve(false))
|
|
|
.then(isCached => {
|
|
|
if (isCached) {
|
|
|
logger.info(`skipped subscriber ${targetStr} as this tweet or the origin of this retweet has been sent already`);
|