koishi-plugin-video-parser-all 0.4.7 → 0.4.8
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/lib/index.d.ts +6 -13
- package/lib/index.js +177 -212
- package/package.json +2 -2
package/lib/index.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { Schema } from 'koishi';
|
|
|
2
2
|
export declare const name = "video-parser-all";
|
|
3
3
|
export declare const Config: Schema<{
|
|
4
4
|
enable?: boolean | null | undefined;
|
|
5
|
-
debug?: boolean | null | undefined;
|
|
6
5
|
autoParse?: boolean | null | undefined;
|
|
7
6
|
enableBvAvParse?: boolean | null | undefined;
|
|
8
7
|
botName?: string | null | undefined;
|
|
@@ -17,7 +16,6 @@ export declare const Config: Schema<{
|
|
|
17
16
|
bilibili?: boolean | null | undefined;
|
|
18
17
|
douyin?: boolean | null | undefined;
|
|
19
18
|
kuaishou?: boolean | null | undefined;
|
|
20
|
-
xigua?: boolean | null | undefined;
|
|
21
19
|
xiaohongshu?: boolean | null | undefined;
|
|
22
20
|
weibo?: boolean | null | undefined;
|
|
23
21
|
toutiao?: boolean | null | undefined;
|
|
@@ -53,10 +51,9 @@ export declare const Config: Schema<{
|
|
|
53
51
|
} & import("cosmokit").Dict) | ({
|
|
54
52
|
enableApiSelection?: true | null | undefined;
|
|
55
53
|
preferredApi?: ({
|
|
56
|
-
bilibili?: "https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/b_parse/" | "https://api.bugpk.com/api/bilibili" | "https://api.
|
|
54
|
+
bilibili?: "https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/b_parse/" | "https://api.bugpk.com/api/bilibili" | "https://api.bilibili.com/x/web-interface/view" | null | undefined;
|
|
57
55
|
douyin?: "https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/douyin/" | "https://api.bugpk.com/api/douyin" | "https://api.bugpk.com/api/dyjx" | "https://api.bugpk.com/api/dylive" | null | undefined;
|
|
58
|
-
kuaishou?: "https://api.bugpk.com/api/short_videos" | "https://api.
|
|
59
|
-
xigua?: "https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/xigua/" | "https://api.bugpk.com/api/toutiao" | null | undefined;
|
|
56
|
+
kuaishou?: "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/ksjx" | "https://api.bugpk.com/api/kuaishou" | "https://api.bugpk.com/api/ksimg" | "https://api.suyanw.cn/api/kuaishou.php" | null | undefined;
|
|
60
57
|
xiaohongshu?: "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/xhsjx" | "https://api.bugpk.com/api/xhsimg" | "https://api.bugpk.com/api/xhslive" | "https://api.bugpk.com/api/xhs" | null | undefined;
|
|
61
58
|
weibo?: "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/weibo" | "https://api.bugpk.com/api/weibo_v" | null | undefined;
|
|
62
59
|
toutiao?: "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/toutiao" | null | undefined;
|
|
@@ -66,7 +63,6 @@ export declare const Config: Schema<{
|
|
|
66
63
|
} & import("cosmokit").Dict) | null | undefined;
|
|
67
64
|
} & import("cosmokit").Dict))))), {
|
|
68
65
|
enable: boolean;
|
|
69
|
-
debug: boolean;
|
|
70
66
|
autoParse: boolean;
|
|
71
67
|
enableBvAvParse: boolean;
|
|
72
68
|
botName: string;
|
|
@@ -81,7 +77,6 @@ export declare const Config: Schema<{
|
|
|
81
77
|
bilibili: Schema<boolean, boolean>;
|
|
82
78
|
douyin: Schema<boolean, boolean>;
|
|
83
79
|
kuaishou: Schema<boolean, boolean>;
|
|
84
|
-
xigua: Schema<boolean, boolean>;
|
|
85
80
|
xiaohongshu: Schema<boolean, boolean>;
|
|
86
81
|
weibo: Schema<boolean, boolean>;
|
|
87
82
|
toutiao: Schema<boolean, boolean>;
|
|
@@ -117,10 +112,9 @@ export declare const Config: Schema<{
|
|
|
117
112
|
}> | Schemastery.ObjectT<{
|
|
118
113
|
enableApiSelection: Schema<true, true>;
|
|
119
114
|
preferredApi: Schema<Schemastery.ObjectS<{
|
|
120
|
-
bilibili: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/b_parse/" | "https://api.bugpk.com/api/bilibili" | "https://api.
|
|
115
|
+
bilibili: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/b_parse/" | "https://api.bugpk.com/api/bilibili" | "https://api.bilibili.com/x/web-interface/view", "https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/b_parse/" | "https://api.bugpk.com/api/bilibili" | "https://api.bilibili.com/x/web-interface/view">;
|
|
121
116
|
douyin: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/douyin/" | "https://api.bugpk.com/api/douyin" | "https://api.bugpk.com/api/dyjx" | "https://api.bugpk.com/api/dylive", "https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/douyin/" | "https://api.bugpk.com/api/douyin" | "https://api.bugpk.com/api/dyjx" | "https://api.bugpk.com/api/dylive">;
|
|
122
|
-
kuaishou: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.
|
|
123
|
-
xigua: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/xigua/" | "https://api.bugpk.com/api/toutiao", "https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/xigua/" | "https://api.bugpk.com/api/toutiao">;
|
|
117
|
+
kuaishou: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/ksjx" | "https://api.bugpk.com/api/kuaishou" | "https://api.bugpk.com/api/ksimg" | "https://api.suyanw.cn/api/kuaishou.php", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/ksjx" | "https://api.bugpk.com/api/kuaishou" | "https://api.bugpk.com/api/ksimg" | "https://api.suyanw.cn/api/kuaishou.php">;
|
|
124
118
|
xiaohongshu: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/xhsjx" | "https://api.bugpk.com/api/xhsimg" | "https://api.bugpk.com/api/xhslive" | "https://api.bugpk.com/api/xhs", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/xhsjx" | "https://api.bugpk.com/api/xhsimg" | "https://api.bugpk.com/api/xhslive" | "https://api.bugpk.com/api/xhs">;
|
|
125
119
|
weibo: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/weibo" | "https://api.bugpk.com/api/weibo_v", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/weibo" | "https://api.bugpk.com/api/weibo_v">;
|
|
126
120
|
toutiao: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/toutiao", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/toutiao">;
|
|
@@ -128,10 +122,9 @@ export declare const Config: Schema<{
|
|
|
128
122
|
pipixia: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/pipixia", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/pipixia">;
|
|
129
123
|
zuiyou: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/zuiyou" | "https://api.suyanw.cn/api/zuiyou.php", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/zuiyou" | "https://api.suyanw.cn/api/zuiyou.php">;
|
|
130
124
|
}>, Schemastery.ObjectT<{
|
|
131
|
-
bilibili: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/b_parse/" | "https://api.bugpk.com/api/bilibili" | "https://api.
|
|
125
|
+
bilibili: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/b_parse/" | "https://api.bugpk.com/api/bilibili" | "https://api.bilibili.com/x/web-interface/view", "https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/b_parse/" | "https://api.bugpk.com/api/bilibili" | "https://api.bilibili.com/x/web-interface/view">;
|
|
132
126
|
douyin: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/douyin/" | "https://api.bugpk.com/api/douyin" | "https://api.bugpk.com/api/dyjx" | "https://api.bugpk.com/api/dylive", "https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/douyin/" | "https://api.bugpk.com/api/douyin" | "https://api.bugpk.com/api/dyjx" | "https://api.bugpk.com/api/dylive">;
|
|
133
|
-
kuaishou: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.
|
|
134
|
-
xigua: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/xigua/" | "https://api.bugpk.com/api/toutiao", "https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/xigua/" | "https://api.bugpk.com/api/toutiao">;
|
|
127
|
+
kuaishou: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/ksjx" | "https://api.bugpk.com/api/kuaishou" | "https://api.bugpk.com/api/ksimg" | "https://api.suyanw.cn/api/kuaishou.php", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/ksjx" | "https://api.bugpk.com/api/kuaishou" | "https://api.bugpk.com/api/ksimg" | "https://api.suyanw.cn/api/kuaishou.php">;
|
|
135
128
|
xiaohongshu: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/xhsjx" | "https://api.bugpk.com/api/xhsimg" | "https://api.bugpk.com/api/xhslive" | "https://api.bugpk.com/api/xhs", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/xhsjx" | "https://api.bugpk.com/api/xhsimg" | "https://api.bugpk.com/api/xhslive" | "https://api.bugpk.com/api/xhs">;
|
|
136
129
|
weibo: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/weibo" | "https://api.bugpk.com/api/weibo_v", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/weibo" | "https://api.bugpk.com/api/weibo_v">;
|
|
137
130
|
toutiao: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/toutiao", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/toutiao">;
|
package/lib/index.js
CHANGED
|
@@ -17,28 +17,24 @@ const API_CONFIG = {
|
|
|
17
17
|
universal: 'https://api.bugpk.com/api/short_videos',
|
|
18
18
|
xingzhige: {
|
|
19
19
|
bilibili: 'https://api.xingzhige.com/API/b_parse/',
|
|
20
|
-
|
|
21
|
-
douyin: 'https://api.xingzhige.com/API/douyin/',
|
|
22
|
-
xigua: 'https://api.xingzhige.com/API/xigua/'
|
|
20
|
+
douyin: 'https://api.xingzhige.com/API/douyin/'
|
|
23
21
|
},
|
|
24
22
|
platform: {
|
|
25
|
-
bilibili: ['https://api.bugpk.com/api/bilibili', 'https://api.xingzhige.com/API/b_parse/'
|
|
26
|
-
kuaishou: ['https://api.bugpk.com/api/ksjx', 'https://api.bugpk.com/api/kuaishou', 'https://api.bugpk.com/api/ksimg', 'https://api.suyanw.cn/api/kuaishou.php'
|
|
23
|
+
bilibili: ['https://api.bugpk.com/api/bilibili', 'https://api.xingzhige.com/API/b_parse/'],
|
|
24
|
+
kuaishou: ['https://api.bugpk.com/api/ksjx', 'https://api.bugpk.com/api/kuaishou', 'https://api.bugpk.com/api/ksimg', 'https://api.suyanw.cn/api/kuaishou.php'],
|
|
27
25
|
xiaohongshu: ['https://api.bugpk.com/api/xhsjx', 'https://api.bugpk.com/api/xhsimg', 'https://api.bugpk.com/api/xhslive', 'https://api.bugpk.com/api/xhs'],
|
|
28
26
|
weibo: ['https://api.bugpk.com/api/weibo', 'https://api.bugpk.com/api/weibo_v'],
|
|
29
27
|
toutiao: ['https://api.bugpk.com/api/toutiao'],
|
|
30
28
|
pipigx: ['https://api.bugpk.com/api/pipigx', 'https://api.suyanw.cn/api/pipigx.php'],
|
|
31
29
|
pipixia: ['https://api.bugpk.com/api/pipixia'],
|
|
32
30
|
douyin: ['https://api.bugpk.com/api/douyin', 'https://api.bugpk.com/api/dyjx', 'https://api.bugpk.com/api/dylive', 'https://api.xingzhige.com/API/douyin/'],
|
|
33
|
-
zuiyou: ['https://api.bugpk.com/api/zuiyou', 'https://api.suyanw.cn/api/zuiyou.php']
|
|
34
|
-
xigua: ['https://api.bugpk.com/api/toutiao', 'https://api.xingzhige.com/API/xigua/']
|
|
31
|
+
zuiyou: ['https://api.bugpk.com/api/zuiyou', 'https://api.suyanw.cn/api/zuiyou.php']
|
|
35
32
|
}
|
|
36
33
|
};
|
|
37
34
|
exports.name = 'video-parser-all';
|
|
38
35
|
exports.Config = koishi_1.Schema.intersect([
|
|
39
36
|
koishi_1.Schema.object({
|
|
40
37
|
enable: koishi_1.Schema.boolean().default(true).description('是否启用视频解析插件'),
|
|
41
|
-
debug: koishi_1.Schema.boolean().default(false).description('开启调试模式,输出详细日志'),
|
|
42
38
|
autoParse: koishi_1.Schema.boolean().default(true).description('是否自动解析消息中的视频链接'),
|
|
43
39
|
enableBvAvParse: koishi_1.Schema.boolean().default(true).description('是否解析独立的BV/AV号(如:BV1xx411c7mD)'),
|
|
44
40
|
botName: koishi_1.Schema.string().default('视频解析机器人').description('机器人显示名称'),
|
|
@@ -54,7 +50,6 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
54
50
|
bilibili: koishi_1.Schema.boolean().default(true).description('B站'),
|
|
55
51
|
douyin: koishi_1.Schema.boolean().default(true).description('抖音'),
|
|
56
52
|
kuaishou: koishi_1.Schema.boolean().default(true).description('快手'),
|
|
57
|
-
xigua: koishi_1.Schema.boolean().default(true).description('西瓜视频'),
|
|
58
53
|
xiaohongshu: koishi_1.Schema.boolean().default(true).description('小红书'),
|
|
59
54
|
weibo: koishi_1.Schema.boolean().default(true).description('微博'),
|
|
60
55
|
toutiao: koishi_1.Schema.boolean().default(true).description('今日头条'),
|
|
@@ -64,7 +59,18 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
64
59
|
}).description('平台开关')
|
|
65
60
|
}).description('平台开关'),
|
|
66
61
|
koishi_1.Schema.object({
|
|
67
|
-
messageFormat: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}\n时长:${视频时长}\n点赞:${点赞数}\n投币:${投币数}\n收藏:${收藏数}\n转发:${转发数}\n播放:${播放数}\n视频大小:${视频大小}MB').description(
|
|
62
|
+
messageFormat: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}\n时长:${视频时长}\n点赞:${点赞数}\n投币:${投币数}\n收藏:${收藏数}\n转发:${转发数}\n播放:${播放数}\n视频大小:${视频大小}MB').description(`消息格式,可用变量:
|
|
63
|
+
${'${标题}'} - 视频/图文标题
|
|
64
|
+
${'${作者}'} - 作者名称
|
|
65
|
+
${'${简介}'} - 作品简介/描述
|
|
66
|
+
${'${视频时长}'} - 视频时长(格式化)
|
|
67
|
+
${'${点赞数}'} - 点赞数量
|
|
68
|
+
${'${投币数}'} - 投币数量(仅B站有效)
|
|
69
|
+
${'${收藏数}'} - 收藏数量
|
|
70
|
+
${'${转发数}'} - 转发/分享数量
|
|
71
|
+
${'${播放数}'} - 播放/浏览数量
|
|
72
|
+
${'${视频大小}'} - 视频文件大小(MB)
|
|
73
|
+
注:非B站平台会自动隐藏投币字段`),
|
|
68
74
|
}).description('消息格式'),
|
|
69
75
|
koishi_1.Schema.object({
|
|
70
76
|
showImageText: koishi_1.Schema.boolean().default(true).description('显示图文内容'),
|
|
@@ -99,13 +105,12 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
99
105
|
enableApiSelection: koishi_1.Schema.const(false).required(),
|
|
100
106
|
}).description('关闭API选择设置'),
|
|
101
107
|
koishi_1.Schema.object({
|
|
102
|
-
enableApiSelection: koishi_1.Schema.const(true),
|
|
108
|
+
enableApiSelection: koishi_1.Schema.const(true).required(),
|
|
103
109
|
preferredApi: koishi_1.Schema.object({
|
|
104
110
|
bilibili: koishi_1.Schema.union([
|
|
105
111
|
'https://api.xingzhige.com/API/b_parse/',
|
|
106
112
|
'https://api.bugpk.com/api/short_videos',
|
|
107
113
|
'https://api.bugpk.com/api/bilibili',
|
|
108
|
-
'https://api.xingzhige.com/API/b_video/',
|
|
109
114
|
'https://api.bilibili.com/x/web-interface/view'
|
|
110
115
|
]).default('https://api.xingzhige.com/API/b_parse/').description('B站首选解析源'),
|
|
111
116
|
douyin: koishi_1.Schema.union([
|
|
@@ -116,18 +121,12 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
116
121
|
'https://api.bugpk.com/api/dylive'
|
|
117
122
|
]).default('https://api.xingzhige.com/API/douyin/').description('抖音首选解析源'),
|
|
118
123
|
kuaishou: koishi_1.Schema.union([
|
|
119
|
-
'https://api.xingzhige.com/API/kuaishou/',
|
|
120
124
|
'https://api.bugpk.com/api/short_videos',
|
|
121
125
|
'https://api.bugpk.com/api/ksjx',
|
|
122
126
|
'https://api.bugpk.com/api/kuaishou',
|
|
123
127
|
'https://api.bugpk.com/api/ksimg',
|
|
124
128
|
'https://api.suyanw.cn/api/kuaishou.php'
|
|
125
|
-
]).default('https://api.
|
|
126
|
-
xigua: koishi_1.Schema.union([
|
|
127
|
-
'https://api.xingzhige.com/API/xigua/',
|
|
128
|
-
'https://api.bugpk.com/api/short_videos',
|
|
129
|
-
'https://api.bugpk.com/api/toutiao'
|
|
130
|
-
]).default('https://api.xingzhige.com/API/xigua/').description('西瓜视频首选解析源'),
|
|
129
|
+
]).default('https://api.bugpk.com/api/short_videos').description('快手首选解析源'),
|
|
131
130
|
xiaohongshu: koishi_1.Schema.union([
|
|
132
131
|
'https://api.bugpk.com/api/short_videos',
|
|
133
132
|
'https://api.bugpk.com/api/xhsjx',
|
|
@@ -171,7 +170,7 @@ if (!worker_threads_1.isMainThread) {
|
|
|
171
170
|
(async () => {
|
|
172
171
|
try {
|
|
173
172
|
if (url.endsWith('.m4a') || url.endsWith('.mp3')) {
|
|
174
|
-
worker_threads_1.parentPort?.postMessage({ success: false, error: '不支持音频' });
|
|
173
|
+
worker_threads_1.parentPort?.postMessage({ success: false, error: '不支持音频', code: 3001 });
|
|
175
174
|
return;
|
|
176
175
|
}
|
|
177
176
|
const maxSizeBytes = maxSize * 1024 * 1024;
|
|
@@ -184,8 +183,12 @@ if (!worker_threads_1.isMainThread) {
|
|
|
184
183
|
});
|
|
185
184
|
if (maxSize > 0 && response.headers['content-length']) {
|
|
186
185
|
const contentLength = parseInt(response.headers['content-length']);
|
|
186
|
+
if (isNaN(contentLength)) {
|
|
187
|
+
worker_threads_1.parentPort?.postMessage({ success: false, error: '无法获取视频大小', code: 3002 });
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
187
190
|
if (contentLength > maxSizeBytes) {
|
|
188
|
-
worker_threads_1.parentPort?.postMessage({ success: false, error: `视频大小超过限制(${maxSize}MB
|
|
191
|
+
worker_threads_1.parentPort?.postMessage({ success: false, error: `视频大小超过限制(${maxSize}MB)`, code: 3003 });
|
|
189
192
|
return;
|
|
190
193
|
}
|
|
191
194
|
}
|
|
@@ -196,15 +199,20 @@ if (!worker_threads_1.isMainThread) {
|
|
|
196
199
|
if (maxSize > 0 && downloadedSize > maxSizeBytes) {
|
|
197
200
|
response.data.destroy();
|
|
198
201
|
writeStream.destroy();
|
|
199
|
-
|
|
200
|
-
|
|
202
|
+
try {
|
|
203
|
+
fs_1.default.unlinkSync(filePath);
|
|
204
|
+
}
|
|
205
|
+
catch (err) {
|
|
206
|
+
logger.error(`删除文件失败: ${getErrorMessage(err)}`);
|
|
207
|
+
}
|
|
208
|
+
worker_threads_1.parentPort?.postMessage({ success: false, error: `视频大小超过限制(${maxSize}MB)`, code: 3003 });
|
|
201
209
|
}
|
|
202
210
|
});
|
|
203
211
|
await (0, promises_1.pipeline)(response.data, writeStream);
|
|
204
212
|
worker_threads_1.parentPort?.postMessage({ success: true, filePath });
|
|
205
213
|
}
|
|
206
214
|
catch (error) {
|
|
207
|
-
worker_threads_1.parentPort?.postMessage({ success: false, error: getErrorMessage(error) });
|
|
215
|
+
worker_threads_1.parentPort?.postMessage({ success: false, error: getErrorMessage(error), code: 3004 });
|
|
208
216
|
}
|
|
209
217
|
})();
|
|
210
218
|
}
|
|
@@ -220,7 +228,6 @@ const PLATFORM_KEYWORDS = {
|
|
|
220
228
|
pipixia: ['pipixia', '皮皮虾', 'h5.pipix.com', 'pipix.com'],
|
|
221
229
|
douyin: ['douyin', '抖音', 'v.douyin.com', 'douyin.com', 'tiktok.com'],
|
|
222
230
|
zuiyou: ['zuiyou', '最右', 'xiaochuankeji.cn', 'izuiyou.com'],
|
|
223
|
-
xigua: ['ixigua', '西瓜视频', 'xigua.com', 'ixigua.com']
|
|
224
231
|
};
|
|
225
232
|
function extractUrl(content, enableBvAvParse) {
|
|
226
233
|
const urls = content.match(/https?:\/\/[^\s"'>]+/gi) || [];
|
|
@@ -322,29 +329,49 @@ function formatDuration(seconds) {
|
|
|
322
329
|
function parseData(data, maxDescLength, platform) {
|
|
323
330
|
let type = 'unknown';
|
|
324
331
|
if (data.type) {
|
|
325
|
-
type = data.type;
|
|
332
|
+
type = data.type.toLowerCase();
|
|
333
|
+
}
|
|
334
|
+
else if (data.data?.type) {
|
|
335
|
+
type = data.data.type.toLowerCase();
|
|
326
336
|
}
|
|
327
|
-
else if (data.images?.length && !data.url) {
|
|
337
|
+
else if (data.images?.length && !data.url && !data.data?.url) {
|
|
328
338
|
type = 'image';
|
|
329
339
|
}
|
|
330
|
-
else if (data.live_photo?.length) {
|
|
340
|
+
else if (data.live_photo?.length || data.data?.live_photo?.length) {
|
|
331
341
|
type = 'live';
|
|
332
342
|
}
|
|
333
|
-
else if (data.url || data.video) {
|
|
343
|
+
else if (data.url || data.video || data.data?.url || data.data?.video) {
|
|
334
344
|
type = 'video';
|
|
335
345
|
}
|
|
336
|
-
|
|
337
|
-
let author = data.author || data.name || '未知作者';
|
|
346
|
+
let title = data.title || data.data?.title || data.desc || data.data?.desc || '无标题';
|
|
347
|
+
let author = data.author || data.data?.author || data.name || data.data?.name || '未知作者';
|
|
338
348
|
if (author && typeof author === 'object') {
|
|
339
|
-
author = author.name || author.nickname || author.username || '未知作者';
|
|
349
|
+
author = author.name || author.nickname || author.username || author.uid || '未知作者';
|
|
350
|
+
}
|
|
351
|
+
let video = '';
|
|
352
|
+
const videoUrls = [];
|
|
353
|
+
if (data.url)
|
|
354
|
+
videoUrls.push(data.url);
|
|
355
|
+
if (data.video)
|
|
356
|
+
videoUrls.push(data.video);
|
|
357
|
+
if (data.data?.url)
|
|
358
|
+
videoUrls.push(data.data.url);
|
|
359
|
+
if (data.data?.video)
|
|
360
|
+
videoUrls.push(data.data.video);
|
|
361
|
+
if (data.data?.videos && Array.isArray(data.data.videos) && data.data.videos.length > 0) {
|
|
362
|
+
videoUrls.push(data.data.videos[0].url);
|
|
363
|
+
}
|
|
364
|
+
if (data.data?.live_photo && Array.isArray(data.data.live_photo) && data.data.live_photo.length > 0) {
|
|
365
|
+
videoUrls.push(data.data.live_photo[0].video);
|
|
340
366
|
}
|
|
341
|
-
|
|
367
|
+
video = videoUrls.find(url => url && typeof url === 'string' && url.startsWith('http')) || '';
|
|
368
|
+
let video_backup;
|
|
342
369
|
if (data.video_backup) {
|
|
343
370
|
if (Array.isArray(data.video_backup)) {
|
|
344
|
-
|
|
371
|
+
video_backup = data.video_backup.map((item) => typeof item === 'object' ? item.url : item).filter(Boolean);
|
|
345
372
|
}
|
|
346
373
|
else if (typeof data.video_backup === 'string') {
|
|
347
|
-
|
|
374
|
+
video_backup = [data.video_backup];
|
|
348
375
|
}
|
|
349
376
|
}
|
|
350
377
|
let like = 0;
|
|
@@ -354,6 +381,10 @@ function parseData(data, maxDescLength, platform) {
|
|
|
354
381
|
like = data.like;
|
|
355
382
|
else if (data.likes !== undefined)
|
|
356
383
|
like = data.likes;
|
|
384
|
+
else if (data.data?.stat?.like !== undefined)
|
|
385
|
+
like = data.data.stat.like;
|
|
386
|
+
else if (data.data?.like !== undefined)
|
|
387
|
+
like = data.data.like;
|
|
357
388
|
let view = 0;
|
|
358
389
|
if (data.stat?.view !== undefined)
|
|
359
390
|
view = data.stat.view;
|
|
@@ -363,6 +394,10 @@ function parseData(data, maxDescLength, platform) {
|
|
|
363
394
|
view = data.views;
|
|
364
395
|
else if (data.play_count !== undefined)
|
|
365
396
|
view = data.play_count;
|
|
397
|
+
else if (data.data?.stat?.view !== undefined)
|
|
398
|
+
view = data.data.stat.view;
|
|
399
|
+
else if (data.data?.play_count !== undefined)
|
|
400
|
+
view = data.data.play_count;
|
|
366
401
|
let share = 0;
|
|
367
402
|
if (data.stat?.share !== undefined)
|
|
368
403
|
share = data.stat.share;
|
|
@@ -370,6 +405,8 @@ function parseData(data, maxDescLength, platform) {
|
|
|
370
405
|
share = data.share;
|
|
371
406
|
else if (data.shares !== undefined)
|
|
372
407
|
share = data.shares;
|
|
408
|
+
else if (data.data?.stat?.share !== undefined)
|
|
409
|
+
share = data.data.stat.share;
|
|
373
410
|
let favorite = 0;
|
|
374
411
|
if (data.stat?.favorite !== undefined)
|
|
375
412
|
favorite = data.stat.favorite;
|
|
@@ -377,23 +414,38 @@ function parseData(data, maxDescLength, platform) {
|
|
|
377
414
|
favorite = data.favorite;
|
|
378
415
|
else if (data.collect !== undefined)
|
|
379
416
|
favorite = data.collect;
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
417
|
+
else if (data.data?.stat?.favorite !== undefined)
|
|
418
|
+
favorite = data.data.stat.favorite;
|
|
419
|
+
let coin = data.stat?.coin || data.data?.stat?.coin || 0;
|
|
420
|
+
let size = data.stat?.size || data.size || data.data?.stat?.size || data.data?.size || 0;
|
|
421
|
+
if (size && typeof size === 'string' && size.endsWith('MB')) {
|
|
422
|
+
size = parseFloat(size);
|
|
423
|
+
}
|
|
424
|
+
let duration = data.duration || data.data?.duration || 0;
|
|
425
|
+
if (typeof duration === 'string') {
|
|
426
|
+
duration = parseFloat(duration);
|
|
427
|
+
}
|
|
428
|
+
let cover = data.cover || data.imgurl || data.pic || data.data?.cover || data.data?.imgurl || '';
|
|
429
|
+
let images = data.images || data.data?.images || [];
|
|
430
|
+
if (data.imgurl && Array.isArray(data.imgurl)) {
|
|
431
|
+
images = [...images, ...data.imgurl];
|
|
432
|
+
}
|
|
433
|
+
let live_photo = data.live_photo || data.data?.live_photo;
|
|
434
|
+
let desc = (data.desc || data.description || data.data?.desc || data.data?.description || title || '').slice(0, maxDescLength);
|
|
435
|
+
let music = data.music || data.data?.music;
|
|
384
436
|
return {
|
|
385
437
|
type,
|
|
386
438
|
title,
|
|
387
439
|
author,
|
|
388
|
-
desc
|
|
389
|
-
cover
|
|
390
|
-
images:
|
|
440
|
+
desc,
|
|
441
|
+
cover,
|
|
442
|
+
images: Array.isArray(images) ? images : [],
|
|
391
443
|
video,
|
|
392
|
-
video_backup:
|
|
393
|
-
live_photo:
|
|
394
|
-
duration
|
|
395
|
-
durationFormatted: formatDuration(
|
|
396
|
-
music
|
|
444
|
+
video_backup: video_backup?.filter(url => url !== video),
|
|
445
|
+
live_photo: Array.isArray(live_photo) ? live_photo : undefined,
|
|
446
|
+
duration,
|
|
447
|
+
durationFormatted: formatDuration(duration),
|
|
448
|
+
music,
|
|
397
449
|
stat: {
|
|
398
450
|
like,
|
|
399
451
|
coin,
|
|
@@ -401,7 +453,7 @@ function parseData(data, maxDescLength, platform) {
|
|
|
401
453
|
share,
|
|
402
454
|
view,
|
|
403
455
|
size,
|
|
404
|
-
duration: formatDuration(
|
|
456
|
+
duration: formatDuration(duration)
|
|
405
457
|
}
|
|
406
458
|
};
|
|
407
459
|
}
|
|
@@ -478,7 +530,7 @@ function generateFormattedText(platform, parseData, config) {
|
|
|
478
530
|
.replace(/\${播放数}/g, String(parseData.stat.view))
|
|
479
531
|
.replace(/\${视频大小}/g, String(parseData.stat.size));
|
|
480
532
|
if (platform !== 'bilibili') {
|
|
481
|
-
text = text.replace(
|
|
533
|
+
text = text.replace(/投币:[0-9]+\n?/g, '');
|
|
482
534
|
}
|
|
483
535
|
return text;
|
|
484
536
|
}
|
|
@@ -495,12 +547,12 @@ async function downloadVideoWithThreads(url, filename, maxSize, threads, userAge
|
|
|
495
547
|
if (result.success && result.filePath)
|
|
496
548
|
resolve(result.filePath);
|
|
497
549
|
else
|
|
498
|
-
reject(new Error(result.error || '下载失败'));
|
|
550
|
+
reject(new Error(`${result.error || '下载失败'} (错误码: ${result.code || 3000})`));
|
|
499
551
|
});
|
|
500
552
|
worker.on('error', reject);
|
|
501
553
|
worker.on('exit', (code) => {
|
|
502
554
|
if (code !== 0)
|
|
503
|
-
reject(new Error(
|
|
555
|
+
reject(new Error(`视频下载线程异常 (错误码: 3005)`));
|
|
504
556
|
});
|
|
505
557
|
});
|
|
506
558
|
}
|
|
@@ -512,7 +564,8 @@ function clearAllCache() {
|
|
|
512
564
|
if (fs_1.default.existsSync(tempDir)) {
|
|
513
565
|
fs_1.default.readdirSync(tempDir).forEach(file => {
|
|
514
566
|
try {
|
|
515
|
-
|
|
567
|
+
const filePath = path_1.default.join(tempDir, file);
|
|
568
|
+
fs_1.default.unlinkSync(filePath);
|
|
516
569
|
}
|
|
517
570
|
catch { }
|
|
518
571
|
});
|
|
@@ -539,36 +592,24 @@ function apply(ctx, config) {
|
|
|
539
592
|
if (!worker_threads_1.isMainThread)
|
|
540
593
|
return;
|
|
541
594
|
clearAllCache();
|
|
542
|
-
|
|
543
|
-
logger.info('视频解析插件已加载,调试模式已开启');
|
|
544
|
-
}
|
|
595
|
+
logger.info('视频解析插件已加载');
|
|
545
596
|
const http = axios_1.default.create({
|
|
546
597
|
timeout: config.timeout,
|
|
547
|
-
headers: { 'User-Agent': config.userAgent }
|
|
598
|
+
headers: { 'User-Agent': config.userAgent },
|
|
599
|
+
maxRedirects: 5,
|
|
600
|
+
validateStatus: (status) => status >= 200 && status < 500
|
|
548
601
|
});
|
|
549
602
|
async function tryAPI(apiFunc, apiName) {
|
|
550
603
|
try {
|
|
551
|
-
if (config.debug) {
|
|
552
|
-
logger.debug(`尝试调用API: ${apiName}`);
|
|
553
|
-
}
|
|
554
604
|
const result = await apiFunc();
|
|
555
|
-
if (config.debug && result) {
|
|
556
|
-
logger.debug(`API ${apiName} 调用成功`);
|
|
557
|
-
}
|
|
558
605
|
return result;
|
|
559
606
|
}
|
|
560
607
|
catch (error) {
|
|
561
|
-
if (config.debug) {
|
|
562
|
-
logger.debug(`API ${apiName} 调用失败: ${getErrorMessage(error)}`);
|
|
563
|
-
}
|
|
564
608
|
return null;
|
|
565
609
|
}
|
|
566
610
|
}
|
|
567
611
|
async function requestAPI(apiUrl, params, method = 'GET') {
|
|
568
612
|
try {
|
|
569
|
-
if (config.debug) {
|
|
570
|
-
logger.debug(`请求API: ${apiUrl}, 方法: ${method}, 参数:`, params);
|
|
571
|
-
}
|
|
572
613
|
let response;
|
|
573
614
|
if (method.toUpperCase() === 'GET') {
|
|
574
615
|
response = await http.get(apiUrl, { params });
|
|
@@ -576,22 +617,13 @@ function apply(ctx, config) {
|
|
|
576
617
|
else {
|
|
577
618
|
response = await http.post(apiUrl, params);
|
|
578
619
|
}
|
|
579
|
-
if (config.debug) {
|
|
580
|
-
logger.debug(`API响应: ${apiUrl}, 状态码: ${response.status}`);
|
|
581
|
-
}
|
|
582
620
|
return response.data;
|
|
583
621
|
}
|
|
584
622
|
catch (error) {
|
|
585
|
-
if (config.debug) {
|
|
586
|
-
logger.debug(`API请求失败 ${apiUrl}: ${getErrorMessage(error)}`);
|
|
587
|
-
}
|
|
588
623
|
throw error;
|
|
589
624
|
}
|
|
590
625
|
}
|
|
591
626
|
async function parseBilibili(realUrl) {
|
|
592
|
-
if (config.debug) {
|
|
593
|
-
logger.debug(`开始解析B站链接: ${realUrl}`);
|
|
594
|
-
}
|
|
595
627
|
const preferred = config.enableApiSelection ? config.preferredApi?.bilibili : 'https://api.xingzhige.com/API/b_parse/';
|
|
596
628
|
const apis = [preferred];
|
|
597
629
|
if (config.bilibiliAccessKey && preferred.includes('xingzhige')) {
|
|
@@ -610,15 +642,14 @@ function apply(ctx, config) {
|
|
|
610
642
|
}
|
|
611
643
|
const otherApis = [
|
|
612
644
|
{ url: 'https://api.xingzhige.com/API/b_parse/', method: 'GET' },
|
|
613
|
-
{ url: 'https://api.xingzhige.com/API/b_video/', method: 'GET' },
|
|
614
|
-
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' },
|
|
615
645
|
{ url: 'https://api.bugpk.com/api/bilibili', method: 'GET' },
|
|
646
|
+
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' },
|
|
616
647
|
{ url: 'https://api.bilibili.com/x/web-interface/view', method: 'GET' }
|
|
617
648
|
].filter(api => api.url !== preferred);
|
|
618
649
|
for (const apiInfo of otherApis) {
|
|
619
650
|
const result = await tryAPI(async () => {
|
|
620
651
|
const params = { url: realUrl };
|
|
621
|
-
if (apiInfo.url.includes('
|
|
652
|
+
if (apiInfo.url.includes('bilibili.com/x/web-interface/view')) {
|
|
622
653
|
const vid = vid_type_parse(realUrl);
|
|
623
654
|
if (vid.type === 'bv') {
|
|
624
655
|
params.bvid = vid.id;
|
|
@@ -638,7 +669,7 @@ function apply(ctx, config) {
|
|
|
638
669
|
}
|
|
639
670
|
else if (apiInfo.url.includes('bugpk.com')) {
|
|
640
671
|
if ((data?.code === 200 || data?.code === 0) && data?.data) {
|
|
641
|
-
return { data: parseData(data
|
|
672
|
+
return { data: parseData(data, config.maxDescLength, 'bilibili'), msg: 'B站解析成功' };
|
|
642
673
|
}
|
|
643
674
|
}
|
|
644
675
|
else if (apiInfo.url.includes('bilibili.com') && data?.code === 0 && data?.data) {
|
|
@@ -657,35 +688,31 @@ function apply(ctx, config) {
|
|
|
657
688
|
return result;
|
|
658
689
|
}
|
|
659
690
|
logger.error(`B站解析失败 - URL: ${realUrl}, 错误码: 2001`);
|
|
660
|
-
return { data: null, msg: 'B站解析失败' };
|
|
691
|
+
return { data: null, msg: 'B站解析失败 (错误码: 2001)' };
|
|
661
692
|
}
|
|
662
693
|
async function parseKuaishou(realUrl) {
|
|
663
|
-
|
|
664
|
-
logger.debug(`开始解析快手链接: ${realUrl}`);
|
|
665
|
-
}
|
|
666
|
-
const preferred = config.enableApiSelection ? config.preferredApi?.kuaishou : 'https://api.xingzhige.com/API/kuaishou/';
|
|
694
|
+
const preferred = config.enableApiSelection ? config.preferredApi?.kuaishou : 'https://api.bugpk.com/api/short_videos';
|
|
667
695
|
const apis = [{ url: preferred, method: 'GET' }];
|
|
668
696
|
const otherApis = [
|
|
669
|
-
{ url: 'https://api.xingzhige.com/API/kuaishou/', method: 'GET' },
|
|
670
|
-
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' },
|
|
671
|
-
{ url: 'https://api.bugpk.com/api/ksjx', method: 'GET' },
|
|
672
697
|
{ url: 'https://api.bugpk.com/api/kuaishou', method: 'GET' },
|
|
698
|
+
{ url: 'https://api.bugpk.com/api/ksjx', method: 'GET' },
|
|
673
699
|
{ url: 'https://api.bugpk.com/api/ksimg', method: 'GET' },
|
|
674
|
-
{ url: 'https://api.suyanw.cn/api/kuaishou.php', method: 'GET' }
|
|
700
|
+
{ url: 'https://api.suyanw.cn/api/kuaishou.php', method: 'GET' },
|
|
701
|
+
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
|
|
675
702
|
].filter(api => api.url !== preferred);
|
|
676
703
|
apis.push(...otherApis);
|
|
677
704
|
for (const apiInfo of apis) {
|
|
678
705
|
const result = await tryAPI(async () => {
|
|
679
706
|
const data = await requestAPI(apiInfo.url, { url: realUrl }, apiInfo.method);
|
|
680
|
-
if (apiInfo.url.includes('
|
|
681
|
-
if (data?.
|
|
682
|
-
return { data: parseData(
|
|
707
|
+
if (apiInfo.url.includes('suyanw.cn')) {
|
|
708
|
+
if (data?.code === 200) {
|
|
709
|
+
return { data: parseData(parse_suyanw_data(data), config.maxDescLength, 'kuaishou'), msg: '快手解析成功' };
|
|
683
710
|
}
|
|
684
711
|
}
|
|
685
712
|
else if (apiInfo.url.includes('bugpk.com')) {
|
|
686
713
|
if ((data?.code === 200 || data?.code === 0)) {
|
|
687
714
|
if (data.data) {
|
|
688
|
-
return { data: parseData(data
|
|
715
|
+
return { data: parseData(data, config.maxDescLength, 'kuaishou'), msg: '快手解析成功' };
|
|
689
716
|
}
|
|
690
717
|
else if (data.images) {
|
|
691
718
|
return {
|
|
@@ -700,45 +727,38 @@ function apply(ctx, config) {
|
|
|
700
727
|
}
|
|
701
728
|
}
|
|
702
729
|
}
|
|
703
|
-
else if (apiInfo.url.includes('suyanw.cn')) {
|
|
704
|
-
if (data?.code === 200) {
|
|
705
|
-
return { data: parseData(parse_suyanw_data(data), config.maxDescLength, 'kuaishou'), msg: '快手解析成功' };
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
730
|
return null;
|
|
709
731
|
}, apiInfo.url);
|
|
710
732
|
if (result)
|
|
711
733
|
return result;
|
|
712
734
|
}
|
|
713
735
|
logger.error(`快手解析失败 - URL: ${realUrl}, 错误码: 2002`);
|
|
714
|
-
return { data: null, msg: '快手解析失败' };
|
|
736
|
+
return { data: null, msg: '快手解析失败 (错误码: 2002)' };
|
|
715
737
|
}
|
|
716
738
|
async function parseDouyin(realUrl) {
|
|
717
|
-
if (config.debug) {
|
|
718
|
-
logger.debug(`开始解析抖音链接: ${realUrl}`);
|
|
719
|
-
}
|
|
720
739
|
const preferred = config.enableApiSelection ? config.preferredApi?.douyin : 'https://api.xingzhige.com/API/douyin/';
|
|
721
740
|
const apis = [{ url: preferred, method: 'GET' }];
|
|
722
741
|
const otherApis = [
|
|
723
742
|
{ url: 'https://api.xingzhige.com/API/douyin/', method: 'GET' },
|
|
724
|
-
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' },
|
|
725
743
|
{ url: 'https://api.bugpk.com/api/douyin', method: 'GET' },
|
|
726
744
|
{ url: 'https://api.bugpk.com/api/dyjx', method: 'GET' },
|
|
727
|
-
{ url: 'https://api.bugpk.com/api/dylive', method: 'GET' }
|
|
745
|
+
{ url: 'https://api.bugpk.com/api/dylive', method: 'GET' },
|
|
746
|
+
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
|
|
728
747
|
].filter(api => api.url !== preferred);
|
|
729
748
|
apis.push(...otherApis);
|
|
730
749
|
for (const apiInfo of apis) {
|
|
731
750
|
const result = await tryAPI(async () => {
|
|
732
|
-
const
|
|
751
|
+
const method = apiInfo.url.includes('bugpk.com') ? 'POST' : 'GET';
|
|
752
|
+
const data = await requestAPI(apiInfo.url, { url: realUrl }, method);
|
|
733
753
|
if (apiInfo.url.includes('xingzhige')) {
|
|
734
|
-
if (data?.jx?.length) {
|
|
754
|
+
if (data?.jx?.length || data?.data) {
|
|
735
755
|
return { data: parseData(parse_xingzhige_data(data, 'douyin'), config.maxDescLength, 'douyin'), msg: '抖音解析成功' };
|
|
736
756
|
}
|
|
737
757
|
}
|
|
738
758
|
else if (apiInfo.url.includes('bugpk.com')) {
|
|
739
759
|
if ((data?.code === 200 || data?.code === 0)) {
|
|
740
760
|
if (data.data) {
|
|
741
|
-
return { data: parseData(data
|
|
761
|
+
return { data: parseData(data, config.maxDescLength, 'douyin'), msg: '抖音解析成功' };
|
|
742
762
|
}
|
|
743
763
|
}
|
|
744
764
|
}
|
|
@@ -748,77 +768,41 @@ function apply(ctx, config) {
|
|
|
748
768
|
return result;
|
|
749
769
|
}
|
|
750
770
|
logger.error(`抖音解析失败 - URL: ${realUrl}, 错误码: 2003`);
|
|
751
|
-
return { data: null, msg: '抖音解析失败' };
|
|
752
|
-
}
|
|
753
|
-
async function parseXigua(realUrl) {
|
|
754
|
-
if (config.debug) {
|
|
755
|
-
logger.debug(`开始解析西瓜视频链接: ${realUrl}`);
|
|
756
|
-
}
|
|
757
|
-
const preferred = config.enableApiSelection ? config.preferredApi?.xigua : 'https://api.xingzhige.com/API/xigua/';
|
|
758
|
-
const apis = [{ url: preferred, method: 'GET' }];
|
|
759
|
-
const otherApis = [
|
|
760
|
-
{ url: 'https://api.xingzhige.com/API/xigua/', method: 'GET' },
|
|
761
|
-
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' },
|
|
762
|
-
{ url: 'https://api.bugpk.com/api/toutiao', method: 'GET' }
|
|
763
|
-
].filter(api => api.url !== preferred);
|
|
764
|
-
apis.push(...otherApis);
|
|
765
|
-
for (const apiInfo of apis) {
|
|
766
|
-
const result = await tryAPI(async () => {
|
|
767
|
-
const data = await requestAPI(apiInfo.url, { url: realUrl }, apiInfo.method);
|
|
768
|
-
if (apiInfo.url.includes('xingzhige')) {
|
|
769
|
-
if (data?.jx?.length) {
|
|
770
|
-
return { data: parseData(parse_xingzhige_data(data, 'xigua'), config.maxDescLength, 'xigua'), msg: '西瓜视频解析成功' };
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
else if (apiInfo.url.includes('bugpk.com')) {
|
|
774
|
-
if ((data?.code === 200 || data?.code === 0) && data?.data) {
|
|
775
|
-
return { data: parseData(data.data, config.maxDescLength, 'xigua'), msg: '西瓜视频解析成功' };
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
return null;
|
|
779
|
-
}, apiInfo.url);
|
|
780
|
-
if (result)
|
|
781
|
-
return result;
|
|
782
|
-
}
|
|
783
|
-
logger.error(`西瓜视频解析失败 - URL: ${realUrl}, 错误码: 2004`);
|
|
784
|
-
return { data: null, msg: '西瓜视频解析失败' };
|
|
771
|
+
return { data: null, msg: '抖音解析失败 (错误码: 2003)' };
|
|
785
772
|
}
|
|
786
773
|
async function parseOther(realUrl, platform) {
|
|
787
|
-
if (config.debug) {
|
|
788
|
-
logger.debug(`开始解析${platform}链接: ${realUrl}`);
|
|
789
|
-
}
|
|
790
774
|
const preferred = config.enableApiSelection ? config.preferredApi?.[platform] : 'https://api.bugpk.com/api/short_videos';
|
|
791
775
|
const apis = [{ url: preferred, method: 'GET' }];
|
|
792
776
|
const platformApis = {
|
|
793
777
|
xiaohongshu: [
|
|
794
|
-
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' },
|
|
795
778
|
{ url: 'https://api.bugpk.com/api/xhsjx', method: 'GET' },
|
|
796
779
|
{ url: 'https://api.bugpk.com/api/xhsimg', method: 'GET' },
|
|
797
780
|
{ url: 'https://api.bugpk.com/api/xhslive', method: 'GET' },
|
|
798
|
-
{ url: 'https://api.bugpk.com/api/xhs', method: 'GET' }
|
|
781
|
+
{ url: 'https://api.bugpk.com/api/xhs', method: 'GET' },
|
|
782
|
+
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
|
|
799
783
|
],
|
|
800
784
|
weibo: [
|
|
801
|
-
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' },
|
|
802
785
|
{ url: 'https://api.bugpk.com/api/weibo', method: 'GET' },
|
|
803
|
-
{ url: 'https://api.bugpk.com/api/weibo_v', method: 'GET' }
|
|
786
|
+
{ url: 'https://api.bugpk.com/api/weibo_v', method: 'GET' },
|
|
787
|
+
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
|
|
804
788
|
],
|
|
805
789
|
toutiao: [
|
|
806
|
-
{ url: 'https://api.bugpk.com/api/
|
|
807
|
-
{ url: 'https://api.bugpk.com/api/
|
|
790
|
+
{ url: 'https://api.bugpk.com/api/toutiao', method: 'GET' },
|
|
791
|
+
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
|
|
808
792
|
],
|
|
809
793
|
pipigx: [
|
|
810
|
-
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' },
|
|
811
794
|
{ url: 'https://api.bugpk.com/api/pipigx', method: 'GET' },
|
|
812
|
-
{ url: 'https://api.suyanw.cn/api/pipigx.php', method: 'GET' }
|
|
795
|
+
{ url: 'https://api.suyanw.cn/api/pipigx.php', method: 'GET' },
|
|
796
|
+
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
|
|
813
797
|
],
|
|
814
798
|
pipixia: [
|
|
815
|
-
{ url: 'https://api.bugpk.com/api/
|
|
816
|
-
{ url: 'https://api.bugpk.com/api/
|
|
799
|
+
{ url: 'https://api.bugpk.com/api/pipixia', method: 'GET' },
|
|
800
|
+
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
|
|
817
801
|
],
|
|
818
802
|
zuiyou: [
|
|
819
|
-
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' },
|
|
820
803
|
{ url: 'https://api.bugpk.com/api/zuiyou', method: 'GET' },
|
|
821
|
-
{ url: 'https://api.suyanw.cn/api/zuiyou.php', method: 'GET' }
|
|
804
|
+
{ url: 'https://api.suyanw.cn/api/zuiyou.php', method: 'GET' },
|
|
805
|
+
{ url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
|
|
822
806
|
]
|
|
823
807
|
};
|
|
824
808
|
const otherApis = (platformApis[platform] || []).filter(api => api.url !== preferred);
|
|
@@ -829,7 +813,7 @@ function apply(ctx, config) {
|
|
|
829
813
|
if (apiInfo.url.includes('bugpk.com') || apiInfo.url.includes('suyanw.cn')) {
|
|
830
814
|
if (data?.code === 200 || data?.code === 0) {
|
|
831
815
|
if (data.data) {
|
|
832
|
-
return { data: parseData(data
|
|
816
|
+
return { data: parseData(data, config.maxDescLength, platform), msg: '解析成功' };
|
|
833
817
|
}
|
|
834
818
|
else if (data.images) {
|
|
835
819
|
return {
|
|
@@ -850,26 +834,20 @@ function apply(ctx, config) {
|
|
|
850
834
|
return result;
|
|
851
835
|
}
|
|
852
836
|
logger.error(`${platform}解析失败 - URL: ${realUrl}, 错误码: 2005`);
|
|
853
|
-
return { data: null, msg: '解析失败,请稍后重试' };
|
|
837
|
+
return { data: null, msg: '解析失败,请稍后重试 (错误码: 2005)' };
|
|
854
838
|
}
|
|
855
839
|
async function parse(url) {
|
|
856
|
-
if (config.debug) {
|
|
857
|
-
logger.debug(`开始解析URL: ${url}`);
|
|
858
|
-
}
|
|
859
840
|
const realUrl = await resolveShortUrl(url);
|
|
860
|
-
if (config.debug) {
|
|
861
|
-
logger.debug(`解析后URL: ${realUrl}`);
|
|
862
|
-
}
|
|
863
841
|
const platform = getPlatformType(realUrl);
|
|
864
842
|
if (!platform || !config.platformEnable[platform]) {
|
|
865
|
-
|
|
866
|
-
|
|
843
|
+
const code = !platform ? 1001 : 1002;
|
|
844
|
+
logger.error(`解析失败 - 平台: ${platform || '未知'}, URL: ${url}, 错误码: ${code}`);
|
|
845
|
+
return { data: null, msg: platform ? `该平台解析已关闭 (错误码: ${code})` : `不支持该平台链接 (错误码: ${code})` };
|
|
867
846
|
}
|
|
868
847
|
const parsers = {
|
|
869
848
|
bilibili: parseBilibili,
|
|
870
849
|
kuaishou: parseKuaishou,
|
|
871
|
-
douyin: parseDouyin
|
|
872
|
-
xigua: parseXigua
|
|
850
|
+
douyin: parseDouyin
|
|
873
851
|
};
|
|
874
852
|
if (parsers[platform]) {
|
|
875
853
|
return parsers[platform](realUrl);
|
|
@@ -880,27 +858,15 @@ function apply(ctx, config) {
|
|
|
880
858
|
const hash = crypto_1.default.createHash('md5').update(url).digest('hex');
|
|
881
859
|
const now = Date.now();
|
|
882
860
|
if (processed.get(hash) && now - processed.get(hash) < config.sameLinkInterval * 1000) {
|
|
883
|
-
|
|
884
|
-
logger.debug(`重复解析,跳过: ${url}`);
|
|
885
|
-
}
|
|
886
|
-
return { data: null, msg: '请勿重复解析' };
|
|
861
|
+
return { data: null, msg: '请勿重复解析 (错误码: 1003)' };
|
|
887
862
|
}
|
|
888
863
|
processed.set(hash, now);
|
|
889
|
-
if (config.debug) {
|
|
890
|
-
logger.debug(`开始处理URL: ${url}`);
|
|
891
|
-
}
|
|
892
864
|
const result = await parse(url);
|
|
893
865
|
if (!result.data) {
|
|
894
|
-
if (config.debug) {
|
|
895
|
-
logger.debug(`解析失败: ${url}, 原因: ${result.msg}`);
|
|
896
|
-
}
|
|
897
866
|
return { data: null, msg: result.msg };
|
|
898
867
|
}
|
|
899
868
|
const platform = getPlatformType(url);
|
|
900
869
|
const text = generateFormattedText(platform || 'bilibili', result.data, config);
|
|
901
|
-
if (config.debug) {
|
|
902
|
-
logger.debug(`解析成功: ${url}, 标题: ${result.data.title}`);
|
|
903
|
-
}
|
|
904
870
|
return {
|
|
905
871
|
data: { text, cover: result.data.cover, images: result.data.images, video: result.data.video, type: result.data.type, live_photo: result.data.live_photo },
|
|
906
872
|
msg: 'ok'
|
|
@@ -910,7 +876,7 @@ function apply(ctx, config) {
|
|
|
910
876
|
if (config.videoSendTimeout <= 0) {
|
|
911
877
|
return session.send(content).catch((err) => {
|
|
912
878
|
if (!config.ignoreSendError)
|
|
913
|
-
logger.error(
|
|
879
|
+
logger.error(`发送消息失败 (错误码: 4001): ${err.message}`);
|
|
914
880
|
return null;
|
|
915
881
|
});
|
|
916
882
|
}
|
|
@@ -919,7 +885,7 @@ function apply(ctx, config) {
|
|
|
919
885
|
new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), config.videoSendTimeout))
|
|
920
886
|
]).catch((err) => {
|
|
921
887
|
if (!config.ignoreSendError)
|
|
922
|
-
logger.error(
|
|
888
|
+
logger.error(`发送消息超时 (错误码: 4002): ${err.message}`);
|
|
923
889
|
return null;
|
|
924
890
|
});
|
|
925
891
|
}
|
|
@@ -931,9 +897,6 @@ function apply(ctx, config) {
|
|
|
931
897
|
clearTimeout(buffer.timer);
|
|
932
898
|
linkBuffer.delete(key);
|
|
933
899
|
}
|
|
934
|
-
if (config.debug) {
|
|
935
|
-
logger.debug(`开始处理批量URL: ${urls.length}个`);
|
|
936
|
-
}
|
|
937
900
|
const items = [];
|
|
938
901
|
const errs = [];
|
|
939
902
|
for (const url of urls) {
|
|
@@ -941,7 +904,7 @@ function apply(ctx, config) {
|
|
|
941
904
|
if (result.data) {
|
|
942
905
|
items.push(result.data);
|
|
943
906
|
}
|
|
944
|
-
else if (result.msg !== '请勿重复解析') {
|
|
907
|
+
else if (result.msg !== '请勿重复解析 (错误码: 1003)') {
|
|
945
908
|
errs.push(`【${url.slice(0, 22)}...】:${result.msg}`);
|
|
946
909
|
logger.error(`解析失败: ${url}, 原因: ${result.msg}`);
|
|
947
910
|
}
|
|
@@ -969,9 +932,6 @@ function apply(ctx, config) {
|
|
|
969
932
|
}
|
|
970
933
|
return;
|
|
971
934
|
}
|
|
972
|
-
if (config.debug) {
|
|
973
|
-
logger.debug(`成功解析: ${items.length}个`);
|
|
974
|
-
}
|
|
975
935
|
for (const item of items) {
|
|
976
936
|
try {
|
|
977
937
|
if (enableForward) {
|
|
@@ -1002,7 +962,7 @@ function apply(ctx, config) {
|
|
|
1002
962
|
videoElem = koishi_1.h.file(filePath);
|
|
1003
963
|
}
|
|
1004
964
|
catch (error) {
|
|
1005
|
-
logger.error(
|
|
965
|
+
logger.error(`视频下载失败 (错误码: 4003): ${getErrorMessage(error)}`);
|
|
1006
966
|
videoElem = koishi_1.h.video(item.video);
|
|
1007
967
|
}
|
|
1008
968
|
}
|
|
@@ -1046,7 +1006,7 @@ function apply(ctx, config) {
|
|
|
1046
1006
|
videoElem = koishi_1.h.file(filePath);
|
|
1047
1007
|
}
|
|
1048
1008
|
catch (error) {
|
|
1049
|
-
logger.error(
|
|
1009
|
+
logger.error(`视频下载失败 (错误码: 4003): ${getErrorMessage(error)}`);
|
|
1050
1010
|
videoElem = koishi_1.h.video(item.video);
|
|
1051
1011
|
}
|
|
1052
1012
|
}
|
|
@@ -1060,8 +1020,8 @@ function apply(ctx, config) {
|
|
|
1060
1020
|
}
|
|
1061
1021
|
}
|
|
1062
1022
|
catch (error) {
|
|
1063
|
-
logger.error(
|
|
1064
|
-
await sendTimeout(session, `❌ 处理${item.type}内容失败: ${getErrorMessage(error)}`);
|
|
1023
|
+
logger.error(`处理内容失败 (错误码: 4004): ${getErrorMessage(error)}`);
|
|
1024
|
+
await sendTimeout(session, `❌ 处理${item.type}内容失败: ${getErrorMessage(error)} (错误码: 4004)`);
|
|
1065
1025
|
}
|
|
1066
1026
|
}
|
|
1067
1027
|
if (enableForward && forwardMessages.length) {
|
|
@@ -1069,7 +1029,7 @@ function apply(ctx, config) {
|
|
|
1069
1029
|
await sendTimeout(session, (0, koishi_1.h)('message', { forward: true }, forwardMessages.slice(0, 100)));
|
|
1070
1030
|
}
|
|
1071
1031
|
catch (error) {
|
|
1072
|
-
logger.error(
|
|
1032
|
+
logger.error(`合并转发失败 (错误码: 4005): ${getErrorMessage(error)}`);
|
|
1073
1033
|
for (const node of forwardMessages) {
|
|
1074
1034
|
await sendTimeout(session, node.data.content);
|
|
1075
1035
|
await delay(500);
|
|
@@ -1080,12 +1040,22 @@ function apply(ctx, config) {
|
|
|
1080
1040
|
ctx.on('message', async (session) => {
|
|
1081
1041
|
if (!config.enable || !config.autoParse)
|
|
1082
1042
|
return;
|
|
1083
|
-
|
|
1043
|
+
let textContent = '';
|
|
1044
|
+
if (Array.isArray(session.elements)) {
|
|
1045
|
+
session.elements.forEach((element) => {
|
|
1046
|
+
if (element.type === 'text') {
|
|
1047
|
+
textContent += element.content;
|
|
1048
|
+
}
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
else {
|
|
1052
|
+
textContent = session.content || '';
|
|
1053
|
+
}
|
|
1054
|
+
if (!textContent.trim())
|
|
1055
|
+
return;
|
|
1056
|
+
const urls = extractUrl(textContent.trim(), config.enableBvAvParse);
|
|
1084
1057
|
if (!urls.length)
|
|
1085
1058
|
return;
|
|
1086
|
-
if (config.debug) {
|
|
1087
|
-
logger.debug(`收到消息,提取到URL: ${urls.length}个`);
|
|
1088
|
-
}
|
|
1089
1059
|
const key = `${session.platform}:${session.userId}:${session.channelId}`;
|
|
1090
1060
|
const uniqueUrls = [...new Set(urls)];
|
|
1091
1061
|
if (linkBuffer.has(key)) {
|
|
@@ -1095,9 +1065,6 @@ function apply(ctx, config) {
|
|
|
1095
1065
|
buffer.urls.push(...newUrls);
|
|
1096
1066
|
clearTimeout(buffer.timer);
|
|
1097
1067
|
buffer.timer = setTimeout(() => flush(session), config.messageBufferDelay * 1000);
|
|
1098
|
-
if (config.debug) {
|
|
1099
|
-
logger.debug(`缓冲中添加新URL: ${newUrls.length}个`);
|
|
1100
|
-
}
|
|
1101
1068
|
}
|
|
1102
1069
|
return;
|
|
1103
1070
|
}
|
|
@@ -1111,17 +1078,14 @@ function apply(ctx, config) {
|
|
|
1111
1078
|
timer: setTimeout(() => flush(session), config.messageBufferDelay * 1000),
|
|
1112
1079
|
tipMsgId
|
|
1113
1080
|
});
|
|
1114
|
-
if (config.debug) {
|
|
1115
|
-
logger.debug(`创建新缓冲,等待处理: ${uniqueUrls.length}个`);
|
|
1116
|
-
}
|
|
1117
1081
|
});
|
|
1118
1082
|
ctx.command('parse <url>', '手动解析视频链接')
|
|
1119
1083
|
.action(async ({ session }, url) => {
|
|
1120
1084
|
if (!url)
|
|
1121
|
-
return '请输入视频链接';
|
|
1085
|
+
return '请输入视频链接 (错误码: 5001)';
|
|
1122
1086
|
const urls = extractUrl(url, config.enableBvAvParse);
|
|
1123
1087
|
if (!urls.length)
|
|
1124
|
-
return '不支持该链接';
|
|
1088
|
+
return '不支持该链接 (错误码: 1001)';
|
|
1125
1089
|
await flush(session, [...new Set(urls)]);
|
|
1126
1090
|
});
|
|
1127
1091
|
ctx.command('clear-cache', '清空解析缓存与临时文件')
|
|
@@ -1143,12 +1107,13 @@ function apply(ctx, config) {
|
|
|
1143
1107
|
const now = Date.now();
|
|
1144
1108
|
fs_1.default.readdirSync(tempDir).forEach(file => {
|
|
1145
1109
|
try {
|
|
1146
|
-
const
|
|
1110
|
+
const filePath = path_1.default.join(tempDir, file);
|
|
1111
|
+
const stat = fs_1.default.statSync(filePath);
|
|
1147
1112
|
if (now - stat.mtimeMs > 3600000)
|
|
1148
|
-
fs_1.default.unlinkSync(
|
|
1113
|
+
fs_1.default.unlinkSync(filePath);
|
|
1149
1114
|
}
|
|
1150
1115
|
catch (error) {
|
|
1151
|
-
logger.error(
|
|
1116
|
+
logger.error(`清理临时文件失败 (错误码: 4006): ${file}, ${getErrorMessage(error)}`);
|
|
1152
1117
|
}
|
|
1153
1118
|
});
|
|
1154
1119
|
}, 1800000);
|
|
@@ -1156,7 +1121,7 @@ function apply(ctx, config) {
|
|
|
1156
1121
|
setInterval(clearAllCache, config.autoClearCacheInterval * 60000);
|
|
1157
1122
|
}
|
|
1158
1123
|
process.on('exit', clearAllCache);
|
|
1159
|
-
logger.info('
|
|
1124
|
+
logger.info('视频解析插件已加载完成');
|
|
1160
1125
|
}
|
|
1161
1126
|
module.exports = {
|
|
1162
1127
|
name: exports.name,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-video-parser-all",
|
|
3
|
-
"description": "Koishi 全平台视频解析插件,支持抖音/快手/B
|
|
4
|
-
"version": "0.4.
|
|
3
|
+
"description": "Koishi 全平台视频解析插件,支持抖音/快手/B站/小红书/微博/今日头条/皮皮搞笑/皮皮虾/右视频链接解析",
|
|
4
|
+
"version": "0.4.8",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|