crystelf-plugin/apps/rssPush.js
2025-05-17 10:58:10 +08:00

153 lines
4.2 KiB
JavaScript

import configControl from '../lib/config/configControl.js';
import rssTools from '../models/rss/rss.js';
import path from 'path';
import screenshot from '../lib/rss/screenshot.js';
import fs from 'fs';
import rssCache from '../lib/rss/rssCache.js';
export default class RssPlugin extends plugin {
constructor() {
super({
name: 'crystelf RSS订阅',
dsc: '定时推送rss解析流',
rule: [
{
reg: '^#rss添加(.+)$',
fnc: 'addFeed',
permission: 'master',
},
{
reg: '^#rss移除(\\d+)$',
fnc: 'removeFeed',
permission: 'master',
},
{
reg: /(https?:\/\/[^\s]+(?:\.atom|\/feed))/i,
fnc: 'autoAddFeed',
permission: 'master',
},
{
reg: '^#rss拉取 (https?:\/\/[^\s]+)$',
fnc: 'pullFeedNow',
permission: 'master',
},
],
task: [
{
name: 'RSS定时推送',
corn: '*/10 * * * *',
fnc: () => this.pushFeeds(),
},
],
});
}
/**
* 添加rss
* @param e
* @returns {Promise<*>}
*/
async addFeed(e) {
const url = e.msg.replace(/^#rss添加/, '').trim();
const feeds = configControl.get('feeds') || [];
const groupId = e.group_id;
const exists = feeds.find((f) => f.url === url);
if (exists) {
if (!exists.targetGroups.includes(groupId)) {
exists.targetGroups.push(groupId);
await configControl.set('feeds', feeds);
return e.reply(`群已添加到该rss订阅中..`, true);
}
return e.reply(`该rss已存在并包含在该群聊..`, true);
}
feeds.push({ url, targetGroups: [groupId], screenshot: true });
await configControl.set('feeds', feeds);
return e.reply(`rss解析流设置成功..`, true);
}
/**
* 自动添加
* @param e
* @returns {Promise<*|boolean>}
*/
async autoAddFeed(e) {
const url = e.msg.match(/(https?:\/\/[^\s]+(?:\.atom|\/feed))/i)?.[1];
if (!url) return false;
e.msg = `#rss添加 ${url}`;
return await this.addFeed(e);
}
/**
* 移除rss
* @param e
* @returns {Promise<*>}
*/
async removeFeed(e) {
const index = parseInt(e.msg.replace(/^#rss移除/, '').trim(), 10);
const feeds = configControl.get('feeds') || [];
const groupId = e.group_id;
if (index < 0 || index >= feeds.length) return e.reply('索引无效..', true);
feeds[index].targetGroups = feeds[index].targetGroups.filter((id) => id !== groupId);
await configControl.set('feeds', feeds);
return e.reply('群已移除该订阅');
}
/**
* 手动拉取
* @param e
* @returns {Promise<*>}
*/
async pullFeedNow(e) {
const url = e.msg.replace(/^#rss拉取\s*/, '').trim();
const latest = await rssTools.fetchFeed(url);
if (!latest || !latest.length) {
return e.reply('拉取失败或无内容..', true);
}
const post = latest[0];
const tempPath = path.join(process.cwd(), 'data', `rss-test-${Date.now()}.png`);
await screenshot.generateScreenshot(post, tempPath);
await e.reply([segment.image(tempPath)]);
fs.unlinkSync(tempPath);
}
/**
* 检查rss更新
* @param e
* @returns {Promise<void>}
*/
async pushFeeds(e) {
const feeds = configControl.get('feeds') || [];
for (const feed of feeds) {
const latest = await rssTools.fetchFeed(feed.url);
if (!latest || !latest.length) continue;
const lastLink = await rssCache.get(feed.url);
const newItems = lastLink ? latest.filter((i) => i.link !== lastLink) : latest;
if (newItems.length) {
await rssCache.set(feed.url, newItems[0].link);
for (const groupId of feed.targetGroups) {
const post = newItems[0];
const tempPath = path.join(process.cwd(), 'data', `rss-${Date.now()}.png`);
if (feed.screenshot) {
await screenshot.generateScreenshot(post, tempPath);
await Bot.pickGroup(groupId)?.sendMsg([segment.image(tempPath)]);
fs.unlinkSync(tempPath);
} else {
await Bot.pickGroup(groupId)?.sendMsg(`[RSS推送]\n${post.title}\n${post.link}`);
}
}
}
}
}
}