@anyul/koishi-plugin-rss 5.2.4 → 5.2.42
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.
- package/README.md +51 -0
- package/lib/config.js +8 -1
- package/lib/core/item-processor-runtime.js +1 -1
- package/lib/core/item-processor.js +10 -0
- package/lib/core/telegram-video-restore.d.ts +31 -0
- package/lib/core/telegram-video-restore.js +168 -0
- package/lib/index.js +12 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types.d.ts +18 -0
- package/lib/utils/media.js +35 -9
- package/lib/utils/tdl.d.ts +80 -0
- package/lib/utils/tdl.js +276 -0
- package/lib/utils/video-compress.d.ts +44 -0
- package/lib/utils/video-compress.js +191 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -529,6 +529,47 @@ basic:
|
|
|
529
529
|
usePoster: true # 使用视频封面
|
|
530
530
|
```
|
|
531
531
|
|
|
532
|
+
### Telegram 大视频兼容(tdl 兜底)
|
|
533
|
+
|
|
534
|
+
订阅 Telegram 频道时,RSSHub 对超大视频会返回 `Video is too big` 占位(仅一张封面图),插件原本拿不到视频链接。开启 tdl 兜底后,插件会用外部工具 [iyear/tdl](https://github.com/iyear/tdl) 直接从 Telegram 拉取原始视频,超过阈值再用 ffmpeg 压缩后发送。
|
|
535
|
+
|
|
536
|
+
**前置准备(宿主机一次性操作):**
|
|
537
|
+
|
|
538
|
+
1. 安装 tdl(Go 编写的独立 CLI,**不是 npm 包**):
|
|
539
|
+
```bash
|
|
540
|
+
# 方式一:Go 安装
|
|
541
|
+
go install github.com/iyear/tdl@latest
|
|
542
|
+
# 方式二:下载 Release 二进制
|
|
543
|
+
# https://github.com/iyear/tdl/releases
|
|
544
|
+
```
|
|
545
|
+
2. 安装 ffmpeg(用于压缩,缺失则大视频会被跳过):
|
|
546
|
+
```bash
|
|
547
|
+
# Windows: scoop install ffmpeg 或 choco install ffmpeg
|
|
548
|
+
# macOS: brew install ffmpeg
|
|
549
|
+
# Linux: apt install ffmpeg
|
|
550
|
+
```
|
|
551
|
+
3. 完成 tdl 登录(二维码或手机号):
|
|
552
|
+
```bash
|
|
553
|
+
tdl login
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
**配置:**
|
|
557
|
+
|
|
558
|
+
```yaml
|
|
559
|
+
tdl:
|
|
560
|
+
enabled: true # 启用兜底下载(默认 false)
|
|
561
|
+
timeout: 180 # 单次下载超时(秒)
|
|
562
|
+
compressThreshold: 30 # 触发压缩的体积阈值(MB)
|
|
563
|
+
crf: 30 # ffmpeg 质量 18-32,越小越清晰体积越大
|
|
564
|
+
proxyByEnv: true # 把订阅级代理透传给 tdl 子进程
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
**行为说明:**
|
|
568
|
+
- tdl / ffmpeg **缺失时自动跳过**,不报错、不阻塞其它订阅推送。
|
|
569
|
+
- 下载与压缩产物落在插件缓存目录(`basic.cacheDir`),随定时器统一清理。
|
|
570
|
+
- 发送方式复用 `basic.videoMode`,与普通视频一致。
|
|
571
|
+
- 开启后启动日志会打印 tdl/ffmpeg 探测结果(`✓`/`✗`),便于排查。
|
|
572
|
+
|
|
532
573
|
## 🔐 权限说明
|
|
533
574
|
|
|
534
575
|
### 权限等级
|
|
@@ -679,6 +720,16 @@ debug: "details" # 显示所有调试信息
|
|
|
679
720
|
|
|
680
721
|
## 📜 更新日志
|
|
681
722
|
|
|
723
|
+
### 5.2.42 (2026-06-18)
|
|
724
|
+
|
|
725
|
+
#### Telegram 大视频 tdl 兜底
|
|
726
|
+
|
|
727
|
+
- 🎬 **Telegram 大视频兼容** - 订阅 Telegram 频道时,RSSHub 对超大视频返回的 `Video is too big` 占位,现可通过外部 [iyear/tdl](https://github.com/iyear/tdl) 直接从 Telegram 拉取原始视频
|
|
728
|
+
- 📦 **ffmpeg 自动压缩** - 下载产物超阈值(默认 30MB)自动用 ffmpeg 压缩后再发送,降低带宽占用
|
|
729
|
+
- 🔌 **外部二进制探测** - tdl/ffmpeg 为外部 CLI(非 npm 包),运行时探测 PATH,缺失自动跳过、不阻塞主流程
|
|
730
|
+
- ♻️ **videoMode 复用** - 兜底视频走既有 `videoMode` 链路(base64/File/assets),行为与普通视频一致
|
|
731
|
+
- 🧪 **新增单元测试** - 覆盖 `parseTelegramLink`、`detectVideoTooBig`、`shouldCompress` 等纯函数
|
|
732
|
+
|
|
682
733
|
### 5.2.3 (2026-03-10)
|
|
683
734
|
|
|
684
735
|
#### 结构收敛与文档同步
|
package/lib/config.js
CHANGED
|
@@ -195,8 +195,15 @@ exports.Config = koishi_1.Schema.object({
|
|
|
195
195
|
enabled: koishi_1.Schema.boolean().description('启用错误追踪').default(false),
|
|
196
196
|
dsn: koishi_1.Schema.string().role('secret').description('Sentry DSN').default(''),
|
|
197
197
|
environment: koishi_1.Schema.string().description('错误追踪环境').default('production'),
|
|
198
|
-
release: koishi_1.Schema.string().description('错误追踪版本号').default('5.2.
|
|
198
|
+
release: koishi_1.Schema.string().description('错误追踪版本号').default('5.2.42'),
|
|
199
199
|
tracesSampleRate: koishi_1.Schema.number().min(0).max(1).description('性能追踪采样率').default(0.1),
|
|
200
200
|
profilesSampleRate: koishi_1.Schema.number().min(0).max(1).description('性能分析采样率').default(0.1),
|
|
201
201
|
}).description('错误追踪设置'),
|
|
202
|
+
tdl: koishi_1.Schema.object({
|
|
203
|
+
enabled: koishi_1.Schema.boolean().description('启用 Telegram 大视频 tdl 兜底下载<br>当 RSSHub 返回 "Video is too big" 占位时,调用外部 tdl 直接从 Telegram 拉取原始视频。<br><b>需宿主机自行安装</b>: `go install github.com/iyear/tdl@latest` 或下载 [Release](https://github.com/iyear/tdl/releases),并执行 `tdl login` 完成登录。<br>插件运行时探测 PATH,缺失则跳过、不阻塞主流程。').default(false),
|
|
204
|
+
timeout: koishi_1.Schema.number().min(30).max(1800).description('tdl 单次下载超时(秒)').default(180),
|
|
205
|
+
compressThreshold: koishi_1.Schema.number().min(1).description('触发 ffmpeg 压缩的体积阈值(MB),默认沿用基础设置中的视频最大体积').default(30),
|
|
206
|
+
crf: koishi_1.Schema.number().min(18).max(32).description('ffmpeg 压缩质量 CRF(18 接近无损体积大,32 体积小质量差),需宿主机安装 ffmpeg').default(30),
|
|
207
|
+
proxyByEnv: koishi_1.Schema.boolean().description('是否把订阅级代理通过 HTTPS_PROXY 环境变量透传给 tdl 子进程').default(true),
|
|
208
|
+
}).description('Telegram 大视频(tdl)设置'),
|
|
202
209
|
});
|
|
@@ -96,7 +96,7 @@ async function prepareHtmlForRender(deps, html, arg, useXml = false) {
|
|
|
96
96
|
element.attribs.src = await (0, media_1.getImageUrl)(deps.ctx, deps.config, deps.$http, src, arg, true);
|
|
97
97
|
}).get());
|
|
98
98
|
}
|
|
99
|
-
html('img').attr('style', 'object-fit:scale-down;max-width:100%;');
|
|
99
|
+
html('img').attr('style', 'object-fit:scale-down;max-width:100%;height:auto;');
|
|
100
100
|
return useXml ? html.xml() : html.html();
|
|
101
101
|
}
|
|
102
102
|
/**
|
|
@@ -40,6 +40,7 @@ const sanitizer_1 = require("../utils/sanitizer");
|
|
|
40
40
|
const ai_1 = require("./ai");
|
|
41
41
|
const item_processor_template_1 = require("./item-processor-template");
|
|
42
42
|
const item_processor_runtime_1 = require("./item-processor-runtime");
|
|
43
|
+
const telegram_video_restore_1 = require("./telegram-video-restore");
|
|
43
44
|
class RssItemProcessor {
|
|
44
45
|
ctx;
|
|
45
46
|
config;
|
|
@@ -83,6 +84,15 @@ class RssItemProcessor {
|
|
|
83
84
|
item.title = (0, item_processor_runtime_1.normalizeText)(item.title).replace(new RegExp(blockWord, 'gim'), matched => Array(matched.length).fill(this.config.msg?.blockString || '*').join(''));
|
|
84
85
|
});
|
|
85
86
|
const html = cheerio.load(item.description);
|
|
87
|
+
// Telegram 大视频占位恢复:检测 "Video is too big" 并用 tdl 兜底下载
|
|
88
|
+
// 任何失败都静默跳过,等价于现状;成功则把占位 blockquote 改写为真 <video>
|
|
89
|
+
// 产物落到插件缓存目录,由 feeder 定时器统一清理,无需此处管理生命周期
|
|
90
|
+
try {
|
|
91
|
+
await (0, telegram_video_restore_1.restoreTelegramVideos)(html, item, arg, this.config);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
(0, logger_1.debug)(this.config, `restoreTelegramVideos 异常(已忽略): ${err?.message || err}`, 'tg-restore', 'error');
|
|
95
|
+
}
|
|
86
96
|
if (this.config.basic?.videoMode === 'filter' && html('video').length > 0) {
|
|
87
97
|
return '';
|
|
88
98
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram 大视频占位恢复
|
|
3
|
+
*
|
|
4
|
+
* RSSHub 对 Telegram 超大视频会渲染:
|
|
5
|
+
* <blockquote><b>Video is too big</b><br><img src="...poster..."></blockquote>
|
|
6
|
+
* 此时条目内没有任何 <video> 元素,processVideos() 会静默跳过。
|
|
7
|
+
*
|
|
8
|
+
* 本模块在模板渲染前介入:
|
|
9
|
+
* 1. 检测到 "Video is too big" 占位
|
|
10
|
+
* 2. 从 item.link 解析 Telegram 频道+消息ID
|
|
11
|
+
* 3. 用 tdl 下载原始视频
|
|
12
|
+
* 4. 超阈值则用 ffmpeg 压缩
|
|
13
|
+
* 5. 把产物移动到插件缓存目录(避免发送队列异步消费时被清理)
|
|
14
|
+
* 6. 把占位 blockquote 替换为真正的 <video src="file:///缓存路径">
|
|
15
|
+
*
|
|
16
|
+
* 任何环节失败都静默返回(不抛错、不阻塞),等价于"无视频"现状。
|
|
17
|
+
*
|
|
18
|
+
* 文件生命周期:产物落在 getCacheDir() 下,随 File 模式缓存清理周期
|
|
19
|
+
* (feeder 定时器内 delCache)一起被回收,无需此处单独删。
|
|
20
|
+
*/
|
|
21
|
+
import { Config, rssArg } from '../types';
|
|
22
|
+
/**
|
|
23
|
+
* 尝试用 tdl 恢复 Telegram 大视频,原地改写 cheerio 文档。
|
|
24
|
+
*
|
|
25
|
+
* @param html cheerio 实例(会被原地修改)
|
|
26
|
+
* @param item RSS 条目(读取 item.link)
|
|
27
|
+
* @param arg 订阅级参数(含代理)
|
|
28
|
+
* @param config 全局配置
|
|
29
|
+
* @returns 是否成功注入视频(true 表示 html 已被改写)
|
|
30
|
+
*/
|
|
31
|
+
export declare function restoreTelegramVideos(html: any, item: any, arg: rssArg, config: Config): Promise<boolean>;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Telegram 大视频占位恢复
|
|
4
|
+
*
|
|
5
|
+
* RSSHub 对 Telegram 超大视频会渲染:
|
|
6
|
+
* <blockquote><b>Video is too big</b><br><img src="...poster..."></blockquote>
|
|
7
|
+
* 此时条目内没有任何 <video> 元素,processVideos() 会静默跳过。
|
|
8
|
+
*
|
|
9
|
+
* 本模块在模板渲染前介入:
|
|
10
|
+
* 1. 检测到 "Video is too big" 占位
|
|
11
|
+
* 2. 从 item.link 解析 Telegram 频道+消息ID
|
|
12
|
+
* 3. 用 tdl 下载原始视频
|
|
13
|
+
* 4. 超阈值则用 ffmpeg 压缩
|
|
14
|
+
* 5. 把产物移动到插件缓存目录(避免发送队列异步消费时被清理)
|
|
15
|
+
* 6. 把占位 blockquote 替换为真正的 <video src="file:///缓存路径">
|
|
16
|
+
*
|
|
17
|
+
* 任何环节失败都静默返回(不抛错、不阻塞),等价于"无视频"现状。
|
|
18
|
+
*
|
|
19
|
+
* 文件生命周期:产物落在 getCacheDir() 下,随 File 模式缓存清理周期
|
|
20
|
+
* (feeder 定时器内 delCache)一起被回收,无需此处单独删。
|
|
21
|
+
*/
|
|
22
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
23
|
+
if (k2 === undefined) k2 = k;
|
|
24
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
25
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
26
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
27
|
+
}
|
|
28
|
+
Object.defineProperty(o, k2, desc);
|
|
29
|
+
}) : (function(o, m, k, k2) {
|
|
30
|
+
if (k2 === undefined) k2 = k;
|
|
31
|
+
o[k2] = m[k];
|
|
32
|
+
}));
|
|
33
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
34
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
35
|
+
}) : function(o, v) {
|
|
36
|
+
o["default"] = v;
|
|
37
|
+
});
|
|
38
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
39
|
+
var ownKeys = function(o) {
|
|
40
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
41
|
+
var ar = [];
|
|
42
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
43
|
+
return ar;
|
|
44
|
+
};
|
|
45
|
+
return ownKeys(o);
|
|
46
|
+
};
|
|
47
|
+
return function (mod) {
|
|
48
|
+
if (mod && mod.__esModule) return mod;
|
|
49
|
+
var result = {};
|
|
50
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
51
|
+
__setModuleDefault(result, mod);
|
|
52
|
+
return result;
|
|
53
|
+
};
|
|
54
|
+
})();
|
|
55
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
56
|
+
exports.restoreTelegramVideos = restoreTelegramVideos;
|
|
57
|
+
const logger_1 = require("../utils/logger");
|
|
58
|
+
const media_1 = require("../utils/media");
|
|
59
|
+
const tdl_1 = require("../utils/tdl");
|
|
60
|
+
const video_compress_1 = require("../utils/video-compress");
|
|
61
|
+
const fs = __importStar(require("fs"));
|
|
62
|
+
const path = __importStar(require("path"));
|
|
63
|
+
const url_1 = require("url");
|
|
64
|
+
/**
|
|
65
|
+
* 尝试用 tdl 恢复 Telegram 大视频,原地改写 cheerio 文档。
|
|
66
|
+
*
|
|
67
|
+
* @param html cheerio 实例(会被原地修改)
|
|
68
|
+
* @param item RSS 条目(读取 item.link)
|
|
69
|
+
* @param arg 订阅级参数(含代理)
|
|
70
|
+
* @param config 全局配置
|
|
71
|
+
* @returns 是否成功注入视频(true 表示 html 已被改写)
|
|
72
|
+
*/
|
|
73
|
+
async function restoreTelegramVideos(html, item, arg, config) {
|
|
74
|
+
if (!config.tdl?.enabled)
|
|
75
|
+
return false;
|
|
76
|
+
if (!(0, tdl_1.detectVideoTooBig)(html))
|
|
77
|
+
return false;
|
|
78
|
+
const link = normalizeText(item?.link);
|
|
79
|
+
const linkInfo = (0, tdl_1.parseTelegramLink)(link);
|
|
80
|
+
if (!linkInfo) {
|
|
81
|
+
(0, logger_1.debug)(config, `检测到 Video is too big 但 link 非 Telegram 消息链接,跳过: ${link}`, 'tg-restore', 'info');
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
const poster = (0, tdl_1.extractTooBigPoster)(html);
|
|
85
|
+
(0, logger_1.debug)(config, `检测到 Telegram 大视频占位,尝试 tdl 下载: ${link}(channel=${linkInfo.channel}, msgId=${linkInfo.messageId})`, 'tg-restore', 'info');
|
|
86
|
+
const downloaded = await (0, tdl_1.downloadWithTdl)({
|
|
87
|
+
config,
|
|
88
|
+
link,
|
|
89
|
+
proxyAgent: arg?.proxyAgent,
|
|
90
|
+
});
|
|
91
|
+
if (!downloaded) {
|
|
92
|
+
(0, logger_1.debug)(config, `tdl 未取回视频,保持占位现状: ${link}`, 'tg-restore', 'info');
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
const compressResult = await (0, video_compress_1.compressVideoIfNeeded)(downloaded, config);
|
|
96
|
+
if (!compressResult) {
|
|
97
|
+
(0, logger_1.debug)(config, `视频压缩环节返回 null(ffmpeg 缺失或失败),按策略跳过该视频: ${link}`, 'tg-restore', 'info');
|
|
98
|
+
// 清理 tdl 下载目录
|
|
99
|
+
await (0, tdl_1.safeRemoveDir)(path.dirname(downloaded));
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
// 把最终产物移动到插件缓存目录,避免被异步发送队列提前清理
|
|
103
|
+
let finalPath = compressResult.path;
|
|
104
|
+
try {
|
|
105
|
+
finalPath = await moveToCacheDir(finalPath, config);
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
(0, logger_1.debug)(config, `视频迁移到缓存目录失败,沿用 tdl 临时路径: ${err?.message || err}`, 'tg-restore', 'error');
|
|
109
|
+
// 沿用临时路径(风险:发送前被清理),但仍尝试发送
|
|
110
|
+
}
|
|
111
|
+
const fileUrl = (0, url_1.pathToFileURL)(finalPath).href;
|
|
112
|
+
(0, logger_1.debug)(config, `Telegram 大视频已恢复,注入 <video src="${fileUrl}">(最终大小 ${(compressResult.finalSize / 1024 / 1024).toFixed(2)} MB)`, 'tg-restore', 'info');
|
|
113
|
+
// 把 "Video is too big" blockquote 替换为真 <video>
|
|
114
|
+
// 保留 poster(若有),便于 usePoster 模式显示封面
|
|
115
|
+
const posterAttr = poster ? ` poster="${escapeAttr(poster)}"` : '';
|
|
116
|
+
const replacement = `<video src="${escapeAttr(fileUrl)}"${posterAttr} controls="controls" style="width:100%"></video>`;
|
|
117
|
+
replaceTooBigBlockquotes(html, replacement);
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* 把文件移动到插件缓存目录(与 File 模式共用),返回新路径。
|
|
122
|
+
*
|
|
123
|
+
* 缓存目录由 getCacheDir 决定,会被 feeder 定时器统一清理。
|
|
124
|
+
*/
|
|
125
|
+
async function moveToCacheDir(srcPath, config) {
|
|
126
|
+
const cacheDir = (0, media_1.getCacheDir)(config);
|
|
127
|
+
const ext = path.extname(srcPath) || '.mp4';
|
|
128
|
+
const dest = path.join(cacheDir, `tg-tdl-${Date.now()}-${Math.random().toString(36).slice(2, 9)}${ext}`);
|
|
129
|
+
// 优先尝试 rename(同卷快),失败则复制+删除
|
|
130
|
+
try {
|
|
131
|
+
await fs.promises.rename(srcPath, dest);
|
|
132
|
+
return dest;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
await fs.promises.copyFile(srcPath, dest);
|
|
136
|
+
await fs.promises.unlink(srcPath).catch(() => { });
|
|
137
|
+
return dest;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 把所有 "Video is too big" blockquote 替换为给定 HTML 字符串。
|
|
142
|
+
*/
|
|
143
|
+
function replaceTooBigBlockquotes(html, replacement) {
|
|
144
|
+
if (!html)
|
|
145
|
+
return;
|
|
146
|
+
try {
|
|
147
|
+
html('blockquote').each((_, el) => {
|
|
148
|
+
const $el = html(el);
|
|
149
|
+
const text = $el.text() || '';
|
|
150
|
+
if (/video\s+is\s+too\s+big/i.test(text)) {
|
|
151
|
+
$el.replaceWith(replacement);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// ignore
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function escapeAttr(s) {
|
|
160
|
+
return String(s || '').replace(/"/g, '"');
|
|
161
|
+
}
|
|
162
|
+
function normalizeText(v) {
|
|
163
|
+
if (Array.isArray(v))
|
|
164
|
+
return v.join('');
|
|
165
|
+
if (v === undefined || v === null)
|
|
166
|
+
return '';
|
|
167
|
+
return String(v);
|
|
168
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -26,6 +26,8 @@ exports.name = '@anyul/koishi-plugin-rss';
|
|
|
26
26
|
const fetcher_1 = require("./utils/fetcher");
|
|
27
27
|
const media_1 = require("./utils/media");
|
|
28
28
|
const error_tracker_1 = require("./utils/error-tracker");
|
|
29
|
+
const tdl_1 = require("./utils/tdl");
|
|
30
|
+
const logger_1 = require("./utils/logger");
|
|
29
31
|
const commands_1 = require("./commands");
|
|
30
32
|
// Import core modules
|
|
31
33
|
const item_processor_1 = require("./core/item-processor");
|
|
@@ -40,6 +42,16 @@ exports.inject = { required: ["database"], optional: ["puppeteer", "censor", "as
|
|
|
40
42
|
function apply(ctx, config) {
|
|
41
43
|
// Setup database
|
|
42
44
|
(0, database_1.setupDatabase)(ctx);
|
|
45
|
+
// 启用时探测 tdl / ffmpeg 外部二进制可用性,便于用户排查
|
|
46
|
+
// 探测异步进行、失败仅打日志,不阻塞插件加载
|
|
47
|
+
if (config.tdl?.enabled) {
|
|
48
|
+
Promise.all([
|
|
49
|
+
(0, tdl_1.detectBinary)('tdl', ['-v']),
|
|
50
|
+
(0, tdl_1.detectBinary)('ffmpeg', ['-version']),
|
|
51
|
+
]).then(([hasTdl, hasFfmpeg]) => {
|
|
52
|
+
(0, logger_1.debug)(config, `Telegram 大视频工具探测:tdl=${hasTdl ? '✓' : '✗(请安装 iyear/tdl 并 tdl login)'},ffmpeg=${hasFfmpeg ? '✓' : '✗(缺失时大视频将被跳过)'}`, 'tdl', 'info');
|
|
53
|
+
}).catch(() => { });
|
|
54
|
+
}
|
|
43
55
|
if (config.errorTracking?.enabled) {
|
|
44
56
|
(0, error_tracker_1.initErrorTracker)({
|
|
45
57
|
enabled: config.errorTracking.enabled ?? false,
|