@anyul/koishi-plugin-rss 5.3.2 → 5.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/lib/commands/index.js +0 -2
  2. package/lib/commands/subscription-management.js +0 -2
  3. package/lib/commands/utils.d.ts +0 -5
  4. package/lib/commands/utils.js +0 -16
  5. package/lib/config.js +0 -8
  6. package/lib/core/feeder-arg.js +3 -38
  7. package/lib/core/feeder-runtime.js +0 -5
  8. package/lib/core/feeder.js +0 -10
  9. package/lib/core/item-processor-runtime.d.ts +4 -2
  10. package/lib/core/item-processor-runtime.js +4 -12
  11. package/lib/core/notification-queue-sender.js +0 -5
  12. package/lib/core/notification-queue.js +0 -7
  13. package/lib/core/telegram-video-restore.js +3 -8
  14. package/lib/index.js +3 -11
  15. package/lib/tsconfig.tsbuildinfo +1 -1
  16. package/lib/types.d.ts +0 -9
  17. package/lib/utils/common.d.ts +6 -0
  18. package/lib/utils/common.js +15 -25
  19. package/lib/utils/error-handler.d.ts +49 -0
  20. package/lib/utils/error-handler.js +111 -1
  21. package/lib/utils/fetcher.js +11 -37
  22. package/lib/utils/logger.d.ts +6 -0
  23. package/lib/utils/logger.js +82 -14
  24. package/lib/utils/proxy.d.ts +37 -0
  25. package/lib/utils/proxy.js +60 -0
  26. package/package.json +1 -1
  27. package/lib/commands/error-handler.d.ts +0 -53
  28. package/lib/commands/error-handler.js +0 -120
  29. package/lib/commands/rss-subscribe.d.ts +0 -11
  30. package/lib/commands/rss-subscribe.js +0 -323
  31. package/lib/core/feeder-old.d.ts +0 -15
  32. package/lib/core/feeder-old.js +0 -403
  33. package/lib/utils/error-tracker.d.ts +0 -127
  34. package/lib/utils/error-tracker.js +0 -352
  35. package/lib/utils/metrics.d.ts +0 -184
  36. package/lib/utils/metrics.js +0 -401
  37. package/lib/utils/structured-logger.d.ts +0 -135
  38. package/lib/utils/structured-logger.js +0 -248
@@ -1,323 +0,0 @@
1
- "use strict";
2
- /**
3
- * RSS 订阅命令
4
- * 处理 RSS 订阅的添加、删除、列表、关注等操作
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.registerRssSubscribeCommand = registerRssSubscribeCommand;
8
- const constants_1 = require("../constants");
9
- const feeder_1 = require("../core/feeder");
10
- const common_1 = require("../utils/common");
11
- const logger_1 = require("../utils/logger");
12
- const utils_1 = require("./utils");
13
- const error_handler_1 = require("./error-handler");
14
- /**
15
- * 注册 RSS 订阅命令
16
- */
17
- function registerRssSubscribeCommand(ctx, config, processor, getRssDataLocal, parseRssItem, parseQuickUrlLocal, parsePubDateLocal) {
18
- const usage = 'RSS 订阅命令\n' +
19
- '用法:\n' +
20
- ' rsso <url> - 订阅 RSS\n' +
21
- ' rsso -l - 查看订阅列表\n' +
22
- ' rsso -r <id> - 删除订阅\n' +
23
- ' rsso -p <id> - 拉取最新内容\n' +
24
- ' rsso -f <id> - 关注订阅\n';
25
- ctx.guild()
26
- .command('rssowl <url:text>', '*订阅 RSS 链接*')
27
- .alias('rsso')
28
- .usage(usage)
29
- .option('list', '-l [content] 查看订阅列表(详情)')
30
- .option('remove', '-r <content> [订阅id|关键字] *删除订阅*')
31
- .option('removeAll', '*删除全部订阅*')
32
- .option('follow', '-f <content> [订阅id|关键字] 关注订阅,在该订阅更新时提醒你')
33
- .option('followAll', '<content> [订阅id|关键字] **在该订阅更新时提醒所有人**')
34
- .option('target', '<content> [群组id] **跨群订阅**')
35
- .option('arg', '-a <content> 自定义配置')
36
- .option('template', '-i <content> 消息模板[content(文字模板)|default(图片模板)],更多见readme')
37
- .option('title', '-t <content> 自定义命名')
38
- .option('pull', '-p <content> [订阅id|关键字]拉取订阅id最后更新')
39
- .option('force', '强行写入')
40
- .option('daily', '-d <content>')
41
- .option('test', '-T 测试')
42
- .option('quick', '-q [content] 查询快速订阅列表')
43
- .example('rsso https://hub.slarker.me/qqorw')
44
- .action(async ({ session, options }, url) => {
45
- return (0, error_handler_1.executeCommand)(ctx, config, '订阅', () => handleRssCommand(ctx, config, processor, session, options, url, getRssDataLocal, parseRssItem, parseQuickUrlLocal, parsePubDateLocal));
46
- });
47
- }
48
- /**
49
- * 处理 RSS 订阅命令
50
- */
51
- async function handleRssCommand(ctx, config, processor, session, options, url, getRssDataLocal, parseRssItem, parseQuickUrlLocal, parsePubDateLocal) {
52
- const { guildId, platform, authorId, authority } = (0, utils_1.extractSessionInfo)(session);
53
- (0, logger_1.debug)(config, options, 'options', 'info');
54
- (0, logger_1.debug)(config, `${platform}:${authorId}:${guildId}`, '', 'info');
55
- // 处理快速订阅查询
56
- if (options?.quick !== undefined) {
57
- return handleQuickList(options.quick);
58
- }
59
- // 沙盒环境提示
60
- if (platform.includes('sandbox') && !options.test && url) {
61
- session.send('沙盒中无法推送更新,但RSS依然会被订阅,建议使用 -T 选项进行测试');
62
- }
63
- // 获取当前订阅列表
64
- const rssList = await ctx.database.get('rssOwl', { platform, guildId });
65
- // 处理列表选项
66
- if (options?.list !== undefined) {
67
- return handleList(rssList, options.list, parsePubDateLocal);
68
- }
69
- // 处理删除选项
70
- if (options?.remove) {
71
- return handleRemove(ctx, rssList, options.remove, authority);
72
- }
73
- // 处理删除全部选项
74
- if (options?.removeAll) {
75
- return handleRemoveAll(ctx, rssList, authority);
76
- }
77
- // 处理关注选项
78
- if (options?.follow) {
79
- return handleFollow(ctx, rssList, options.follow, authorId);
80
- }
81
- // 处理全员关注选项
82
- if (options?.followAll) {
83
- return handleFollowAll(ctx, rssList, options.followAll, authority);
84
- }
85
- // 处理拉取选项
86
- if (options?.pull) {
87
- return handlePull(ctx, config, rssList, options.pull, parseRssItem, getRssDataLocal, parseQuickUrlLocal, parsePubDateLocal, feeder_1.mixinArg);
88
- }
89
- // 处理订阅 URL
90
- if (url) {
91
- return handleSubscribe(ctx, config, session, rssList, url, options, platform, guildId, authorId, authority, getRssDataLocal, parseRssItem, parseQuickUrlLocal, parsePubDateLocal, feeder_1.formatArg);
92
- }
93
- return '用法: rsso <url> 或 rsso -l 查看订阅列表';
94
- }
95
- /**
96
- * 处理快速订阅列表查询
97
- */
98
- function handleQuickList(quick) {
99
- if (quick === '') {
100
- return '输入 rsso -q [id] 查询详情\n' +
101
- constants_1.quickList.map((v, i) => `${i + 1}.${v.name}`).join('\n');
102
- }
103
- const index = parseInt(quick) - 1;
104
- if (index < 0 || index >= constants_1.quickList.length) {
105
- return '无效的 ID';
106
- }
107
- const quickObj = constants_1.quickList[index];
108
- return `${quickObj.name}\n${quickObj.detail}\n` +
109
- `例:rsso -T ${quickObj.example}\n(${(0, common_1.parseQuickUrl)(quickObj.example, '', [])})`;
110
- }
111
- /**
112
- * 处理列表查询
113
- */
114
- function handleList(rssList, listOption, parsePubDateLocal) {
115
- (0, logger_1.debug)(config, rssList, 'rssList', 'info');
116
- if (rssList.length === 0) {
117
- return '当前没有任何订阅';
118
- }
119
- // 简单列表
120
- if (listOption === '') {
121
- return rssList.map((v, i) => `${i + 1}. ${v.title} [${v.id}]`).join('\n');
122
- }
123
- // 详细列表
124
- const rssItem = (0, feeder_1.findRssItem)(rssList, listOption);
125
- if (!rssItem) {
126
- throw (0, error_handler_1.notFound)('未找到该订阅');
127
- }
128
- const lastPubDate = rssItem.lastPubDate
129
- ? parsePubDateLocal(rssItem.lastPubDate).toLocaleString('zh-CN', { hour12: false })
130
- : '未知';
131
- return `标题: ${rssItem.title}\n` +
132
- `链接: ${rssItem.url}\n` +
133
- `更新时间: ${lastPubDate}`;
134
- }
135
- /**
136
- * 处理删除订阅
137
- */
138
- async function handleRemove(ctx, rssList, identifier, authority) {
139
- const authCheck = (0, utils_1.checkAuthority)(authority, ctx.config.basic.authority);
140
- if (!authCheck.success) {
141
- throw (0, error_handler_1.permissionDenied)();
142
- }
143
- const rssItem = (0, feeder_1.findRssItem)(rssList, identifier);
144
- if (!rssItem) {
145
- throw (0, error_handler_1.notFound)('未找到该订阅');
146
- }
147
- await ctx.database.remove('rssOwl', rssItem.id);
148
- return '删除成功';
149
- }
150
- /**
151
- * 处理删除全部订阅
152
- */
153
- async function handleRemoveAll(ctx, rssList, authority) {
154
- const authCheck = (0, utils_1.checkAuthority)(authority, ctx.config.basic.authority);
155
- if (!authCheck.success) {
156
- throw (0, error_handler_1.permissionDenied)();
157
- }
158
- await ctx.database.remove('rssOwl', { platform, guildId });
159
- return '删除成功';
160
- }
161
- /**
162
- * 处理关注订阅
163
- */
164
- async function handleFollow(ctx, rssList, identifier, authorId) {
165
- const rssItem = (0, feeder_1.findRssItem)(rssList, identifier);
166
- if (!rssItem) {
167
- throw (0, error_handler_1.notFound)('未找到该订阅');
168
- }
169
- if (!rssItem.followers) {
170
- rssItem.followers = [];
171
- }
172
- if (rssItem.followers.includes(authorId)) {
173
- return '已经关注过了';
174
- }
175
- rssItem.followers.push(authorId);
176
- await ctx.database.set('rssOwl', { id: rssItem.id }, { followers: rssItem.followers });
177
- return '关注成功';
178
- }
179
- /**
180
- * 处理全员关注
181
- */
182
- async function handleFollowAll(ctx, rssList, identifier, authority) {
183
- const authCheck = (0, utils_1.checkAuthority)(authority, ctx.config.basic.advancedAuthority);
184
- if (!authCheck.success) {
185
- throw (0, error_handler_1.permissionDenied)();
186
- }
187
- const rssItem = (0, feeder_1.findRssItem)(rssList, identifier);
188
- if (!rssItem) {
189
- throw (0, error_handler_1.notFound)('未找到该订阅');
190
- }
191
- if (!rssItem.followers) {
192
- rssItem.followers = [];
193
- }
194
- rssItem.followers.push('all');
195
- await ctx.database.set('rssOwl', { id: rssItem.id }, { followers: rssItem.followers });
196
- return '关注成功';
197
- }
198
- /**
199
- * 处理拉取最新内容
200
- */
201
- async function handlePull(ctx, config, rssList, identifier, parseRssItem, getRssDataLocal, parseQuickUrlLocal, parsePubDateLocal, mixinArg) {
202
- const rssItem = (0, feeder_1.findRssItem)(rssList, identifier);
203
- if (!rssItem) {
204
- throw (0, error_handler_1.notFound)('未找到该订阅');
205
- }
206
- const arg = mixinArg(rssItem.arg || {});
207
- const rssItemList = (await Promise.all(rssItem.url.split('|')
208
- .map((url) => parseQuickUrlLocal(url))
209
- .map(async (url) => await getRssDataLocal(url, arg)))).flat(1);
210
- let itemArray = rssItemList.sort((a, b) => parsePubDateLocal(b.pubDate).getTime() - parsePubDateLocal(a.pubDate).getTime());
211
- if (arg.reverse) {
212
- itemArray = itemArray.reverse();
213
- }
214
- const maxItem = arg.forceLength || 1;
215
- const messageList = await Promise.all(itemArray
216
- .filter((v, i) => i < maxItem)
217
- .map(i => parseRssItem(i, { ...rssItem, ...arg }, rssItem.author)));
218
- return messageList.join('');
219
- }
220
- /**
221
- * 处理新订阅
222
- */
223
- async function handleSubscribe(ctx, config, session, rssList, url, options, platform, guildId, authorId, authority, getRssDataLocal, parseRssItem, parseQuickUrlLocal, parsePubDateLocal, formatArg) {
224
- // 检查是否已存在
225
- if (rssList.find(i => i.url === url)) {
226
- throw new Error('该订阅已存在');
227
- }
228
- const arg = formatArg(options);
229
- let targetPlatform = platform;
230
- let targetGuildId = guildId;
231
- // 处理跨群订阅
232
- if (options?.target) {
233
- const authCheck = (0, utils_1.checkAuthority)(authority, config.basic.advancedAuthority);
234
- if (!authCheck.success) {
235
- throw (0, error_handler_1.permissionDenied)();
236
- }
237
- const target = (0, utils_1.parseTarget)(options.target);
238
- if (!target) {
239
- throw new Error('请输入正确的群号,格式为 platform:guildId 或 platform:guildId');
240
- }
241
- targetPlatform = target.platform;
242
- targetGuildId = target.guildId;
243
- }
244
- let title = options?.title || '';
245
- url = parseQuickUrlLocal(url);
246
- url = (0, common_1.ensureUrlProtocol)(url);
247
- // 获取 RSS 数据
248
- const rssItemList = await getRssDataLocal(url, arg);
249
- // 测试模式
250
- if (options.test) {
251
- return handleTestMode(rssItemList, arg, title, config, parseRssItem, authorId);
252
- }
253
- // 获取标题
254
- if (!title) {
255
- title = rssItemList[0]?.rss?.channel?.title;
256
- if (!title) {
257
- throw new Error('无法获取标题,请使用 -t 指定标题');
258
- }
259
- }
260
- // 检查权限(force 模式)
261
- if (options.force && authority < config.basic.authority) {
262
- throw (0, error_handler_1.permissionDenied)();
263
- }
264
- // 检查去重
265
- if (config.basic.urlDeduplication && rssList.find(i => i.rssId === title)) {
266
- throw new Error(`订阅已存在: ${title}`);
267
- }
268
- // 创建订阅项
269
- const lastPubDate = parsePubDateLocal(rssItemList[0]?.pubDate);
270
- const rssItem = {
271
- url,
272
- platform: targetPlatform,
273
- guildId: targetGuildId,
274
- author: authorId,
275
- rssId: rssItemList[0]?.rss?.channel?.title || title,
276
- arg,
277
- title,
278
- lastPubDate,
279
- lastContent: [],
280
- followers: [],
281
- firstime: lastPubDate
282
- };
283
- await ctx.database.create('rssOwl', rssItem);
284
- // 首次加载
285
- if (config.basic.firstLoad && arg.firstLoad !== false && rssItemList.length > 0) {
286
- await loadInitialItems(ctx, rssItemList, rssItem, targetPlatform, targetGuildId, parsePubDateLocal, parseRssItem);
287
- }
288
- return `订阅成功: ${title}`;
289
- }
290
- /**
291
- * 处理测试模式
292
- */
293
- async function handleTestMode(rssItemList, arg, title, config, parseRssItem, authorId) {
294
- const testItem = rssItemList[0];
295
- if (!testItem) {
296
- throw new Error('未获取到数据');
297
- }
298
- const testArg = {
299
- ...arg,
300
- url: title || testItem.rss.channel.title,
301
- title: title || testItem.rss.channel.title
302
- };
303
- if (!testArg.template) {
304
- testArg.template = config.basic.defaultTemplate;
305
- }
306
- const msg = await parseRssItem(testItem, testArg, authorId);
307
- return msg;
308
- }
309
- /**
310
- * 加载初始条目
311
- */
312
- async function loadInitialItems(ctx, rssItemList, rssItem, targetPlatform, targetGuildId, parsePubDateLocal, parseRssItem) {
313
- let itemArray = rssItemList.sort((a, b) => parsePubDateLocal(b.pubDate).getTime() - parsePubDateLocal(a.pubDate).getTime());
314
- if (rssItem.arg.reverse) {
315
- itemArray = itemArray.reverse();
316
- }
317
- const maxItem = rssItem.arg.forceLength || 1;
318
- const messageList = await Promise.all(itemArray
319
- .filter((v, i) => i < maxItem)
320
- .map(i => parseRssItem(i, { ...rssItem, ...rssItem.arg }, rssItem.author)));
321
- const message = messageList.join('');
322
- await ctx.broadcast([`${targetPlatform}:${targetGuildId}`], message);
323
- }
@@ -1,15 +0,0 @@
1
- import { Context } from 'koishi';
2
- import { Config, rssArg } from '../types';
3
- import { RssItemProcessor } from './item-processor';
4
- export interface FeederDependencies {
5
- ctx: Context;
6
- config: Config;
7
- $http: any;
8
- }
9
- export declare function findRssItem(rssList: any[], keyword: number | string): any;
10
- export declare function getLastContent(item: any, config: Config): any;
11
- export declare function formatArg(options: any, config: Config): rssArg;
12
- export declare function mixinArg(arg: any, config: Config): rssArg;
13
- export declare function feeder(deps: FeederDependencies, processor: RssItemProcessor): Promise<void>;
14
- export declare function startFeeder(ctx: Context, config: Config, $http: any, processor: RssItemProcessor): void;
15
- export declare function stopFeeder(): void;