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