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解析流', priority: 114, rule: [ { reg: '^#rss添加(.+)$', fnc: 'addFeed', permission: 'master', }, { reg: '^#rss移除(\\d+)$', fnc: 'removeFeed', permission: 'master', }, { reg: '^#rss拉取(.+)$', fnc: 'pullFeedNow', permission: 'master', priority: 100, }, { reg: /(https?:\/\/[^\s]+(?:\.atom|\/feed))/i, fnc: 'autoAddFeed', permission: 'master', priority: 500, }, ], 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) { //if (/^#rss/i.test(e.msg.trim())) return false; 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拉取/, '').trim(); const latest = await rssTools.fetchFeed(url); //logger.info(latest); if (!latest || !latest.length) { return e.reply('拉取失败或无内容..', true); } const post = latest[0]; //console.log(post); 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} */ 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}`); } } } } } }