koishi-plugin-video-parser-all 0.4.6 → 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.
Files changed (3) hide show
  1. package/lib/index.d.ts +22 -27
  2. package/lib/index.js +437 -183
  3. package/package.json +2 -2
package/lib/index.d.ts CHANGED
@@ -16,7 +16,6 @@ export declare const Config: Schema<{
16
16
  bilibili?: boolean | null | undefined;
17
17
  douyin?: boolean | null | undefined;
18
18
  kuaishou?: boolean | null | undefined;
19
- xigua?: boolean | null | undefined;
20
19
  xiaohongshu?: boolean | null | undefined;
21
20
  weibo?: boolean | null | undefined;
22
21
  toutiao?: boolean | null | undefined;
@@ -48,21 +47,20 @@ export declare const Config: Schema<{
48
47
  } & ({
49
48
  autoClearCacheInterval?: number | null | undefined;
50
49
  } & (({
50
+ enableApiSelection?: false | null | undefined;
51
+ } & import("cosmokit").Dict) | ({
51
52
  enableApiSelection?: true | null | undefined;
52
53
  preferredApi?: ({
53
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;
54
- douyin?: "https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/douyin/" | "https://api.bugpk.com/api/douyin" | null | undefined;
55
- kuaishou?: "https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/kuaishou/" | "https://api.bugpk.com/api/ksjx" | null | undefined;
56
- xigua?: "https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/xigua/" | "https://api.bugpk.com/api/toutiao" | null | undefined;
57
- xiaohongshu?: "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/xhsjx" | null | undefined;
58
- weibo?: "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/weibo" | null | undefined;
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;
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;
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;
58
+ weibo?: "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/weibo" | "https://api.bugpk.com/api/weibo_v" | null | undefined;
59
59
  toutiao?: "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/toutiao" | null | undefined;
60
- pipigx?: "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/pipigx" | null | undefined;
60
+ pipigx?: "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/pipigx" | "https://api.suyanw.cn/api/pipigx.php" | null | undefined;
61
61
  pipixia?: "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/pipixia" | null | undefined;
62
- zuiyou?: "https://api.bugpk.com/api/short_videos" | "https://api.suyanw.cn/api/zuiyou.php" | null | undefined;
62
+ zuiyou?: "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/zuiyou" | "https://api.suyanw.cn/api/zuiyou.php" | null | undefined;
63
63
  } & import("cosmokit").Dict) | null | undefined;
64
- } & import("cosmokit").Dict) | ({
65
- enableApiSelection?: false | null | undefined;
66
64
  } & import("cosmokit").Dict))))), {
67
65
  enable: boolean;
68
66
  autoParse: boolean;
@@ -79,7 +77,6 @@ export declare const Config: Schema<{
79
77
  bilibili: Schema<boolean, boolean>;
80
78
  douyin: Schema<boolean, boolean>;
81
79
  kuaishou: Schema<boolean, boolean>;
82
- xigua: Schema<boolean, boolean>;
83
80
  xiaohongshu: Schema<boolean, boolean>;
84
81
  weibo: Schema<boolean, boolean>;
85
82
  toutiao: Schema<boolean, boolean>;
@@ -111,31 +108,29 @@ export declare const Config: Schema<{
111
108
  } & ({
112
109
  autoClearCacheInterval: number;
113
110
  } & (Schemastery.ObjectT<{
111
+ enableApiSelection: Schema<false, false>;
112
+ }> | Schemastery.ObjectT<{
114
113
  enableApiSelection: Schema<true, true>;
115
114
  preferredApi: Schema<Schemastery.ObjectS<{
116
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">;
117
- 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/short_videos" | "https://api.xingzhige.com/API/douyin/" | "https://api.bugpk.com/api/douyin">;
118
- kuaishou: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/kuaishou/" | "https://api.bugpk.com/api/ksjx", "https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/kuaishou/" | "https://api.bugpk.com/api/ksjx">;
119
- 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">;
120
- xiaohongshu: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/xhsjx", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/xhsjx">;
121
- weibo: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/weibo", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/weibo">;
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">;
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">;
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">;
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">;
122
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">;
123
- pipigx: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/pipigx", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/pipigx">;
121
+ pipigx: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/pipigx" | "https://api.suyanw.cn/api/pipigx.php", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/pipigx" | "https://api.suyanw.cn/api/pipigx.php">;
124
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">;
125
- zuiyou: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.suyanw.cn/api/zuiyou.php", "https://api.bugpk.com/api/short_videos" | "https://api.suyanw.cn/api/zuiyou.php">;
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">;
126
124
  }>, Schemastery.ObjectT<{
127
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">;
128
- 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/short_videos" | "https://api.xingzhige.com/API/douyin/" | "https://api.bugpk.com/api/douyin">;
129
- kuaishou: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/kuaishou/" | "https://api.bugpk.com/api/ksjx", "https://api.bugpk.com/api/short_videos" | "https://api.xingzhige.com/API/kuaishou/" | "https://api.bugpk.com/api/ksjx">;
130
- 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
- xiaohongshu: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/xhsjx", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/xhsjx">;
132
- weibo: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/weibo", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/weibo">;
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">;
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">;
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">;
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">;
133
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">;
134
- pipigx: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/pipigx", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/pipigx">;
131
+ pipigx: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/pipigx" | "https://api.suyanw.cn/api/pipigx.php", "https://api.bugpk.com/api/short_videos" | "https://api.bugpk.com/api/pipigx" | "https://api.suyanw.cn/api/pipigx.php">;
135
132
  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">;
136
- zuiyou: Schema<"https://api.bugpk.com/api/short_videos" | "https://api.suyanw.cn/api/zuiyou.php", "https://api.bugpk.com/api/short_videos" | "https://api.suyanw.cn/api/zuiyou.php">;
133
+ 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">;
137
134
  }>>;
138
- }> | Schemastery.ObjectT<{
139
- enableApiSelection: Schema<false, false>;
140
135
  }>))))>;
141
136
  export declare function apply(ctx: any, config: any): void;
package/lib/index.js CHANGED
@@ -12,25 +12,23 @@ const fs_1 = __importDefault(require("fs"));
12
12
  const path_1 = __importDefault(require("path"));
13
13
  const promises_1 = require("stream/promises");
14
14
  const worker_threads_1 = require("worker_threads");
15
+ const logger = new koishi_1.Logger('video-parser');
15
16
  const API_CONFIG = {
16
17
  universal: 'https://api.bugpk.com/api/short_videos',
17
18
  xingzhige: {
18
19
  bilibili: 'https://api.xingzhige.com/API/b_parse/',
19
- kuaishou: 'https://api.xingzhige.com/API/kuaishou/',
20
- douyin: 'https://api.xingzhige.com/API/douyin/',
21
- xigua: 'https://api.xingzhige.com/API/xigua/'
20
+ douyin: 'https://api.xingzhige.com/API/douyin/'
22
21
  },
23
22
  platform: {
24
- bilibili: ['https://api.bugpk.com/api/bilibili'],
23
+ bilibili: ['https://api.bugpk.com/api/bilibili', 'https://api.xingzhige.com/API/b_parse/'],
25
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'],
26
- xiaohongshu: ['https://api.bugpk.com/api/xhsjx', 'https://api.bugpk.com/api/xhsimg', 'https://api.bugpk.com/api/xhslive'],
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'],
27
26
  weibo: ['https://api.bugpk.com/api/weibo', 'https://api.bugpk.com/api/weibo_v'],
28
27
  toutiao: ['https://api.bugpk.com/api/toutiao'],
29
28
  pipigx: ['https://api.bugpk.com/api/pipigx', 'https://api.suyanw.cn/api/pipigx.php'],
30
29
  pipixia: ['https://api.bugpk.com/api/pipixia'],
31
- douyin: ['https://api.bugpk.com/api/douyin', 'https://api.bugpk.com/api/dyjx', 'https://api.bugpk.com/api/dylive'],
32
- zuiyou: ['https://api.suyanw.cn/api/zuiyou.php'],
33
- xigua: ['https://api.bugpk.com/api/toutiao']
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/'],
31
+ zuiyou: ['https://api.bugpk.com/api/zuiyou', 'https://api.suyanw.cn/api/zuiyou.php']
34
32
  }
35
33
  };
36
34
  exports.name = 'video-parser-all';
@@ -52,7 +50,6 @@ exports.Config = koishi_1.Schema.intersect([
52
50
  bilibili: koishi_1.Schema.boolean().default(true).description('B站'),
53
51
  douyin: koishi_1.Schema.boolean().default(true).description('抖音'),
54
52
  kuaishou: koishi_1.Schema.boolean().default(true).description('快手'),
55
- xigua: koishi_1.Schema.boolean().default(true).description('西瓜视频'),
56
53
  xiaohongshu: koishi_1.Schema.boolean().default(true).description('小红书'),
57
54
  weibo: koishi_1.Schema.boolean().default(true).description('微博'),
58
55
  toutiao: koishi_1.Schema.boolean().default(true).description('今日头条'),
@@ -62,7 +59,18 @@ exports.Config = koishi_1.Schema.intersect([
62
59
  }).description('平台开关')
63
60
  }).description('平台开关'),
64
61
  koishi_1.Schema.object({
65
- messageFormat: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}\n时长:${视频时长}\n点赞:${点赞数}\n投币:${投币数}\n收藏:${收藏数}\n转发:${转发数}\n播放:${播放数}\n视频大小:${视频大小}MB').description('统一消息格式(支持${变量}占位符,投币仅B站有效,其他平台自动隐藏)'),
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站平台会自动隐藏投币字段`),
66
74
  }).description('消息格式'),
67
75
  koishi_1.Schema.object({
68
76
  showImageText: koishi_1.Schema.boolean().default(true).description('显示图文内容'),
@@ -95,9 +103,9 @@ exports.Config = koishi_1.Schema.intersect([
95
103
  koishi_1.Schema.union([
96
104
  koishi_1.Schema.object({
97
105
  enableApiSelection: koishi_1.Schema.const(false).required(),
98
- }),
106
+ }).description('关闭API选择设置'),
99
107
  koishi_1.Schema.object({
100
- enableApiSelection: koishi_1.Schema.const(true),
108
+ enableApiSelection: koishi_1.Schema.const(true).required(),
101
109
  preferredApi: koishi_1.Schema.object({
102
110
  bilibili: koishi_1.Schema.union([
103
111
  'https://api.xingzhige.com/API/b_parse/',
@@ -108,25 +116,28 @@ exports.Config = koishi_1.Schema.intersect([
108
116
  douyin: koishi_1.Schema.union([
109
117
  'https://api.xingzhige.com/API/douyin/',
110
118
  'https://api.bugpk.com/api/short_videos',
111
- 'https://api.bugpk.com/api/douyin'
119
+ 'https://api.bugpk.com/api/douyin',
120
+ 'https://api.bugpk.com/api/dyjx',
121
+ 'https://api.bugpk.com/api/dylive'
112
122
  ]).default('https://api.xingzhige.com/API/douyin/').description('抖音首选解析源'),
113
123
  kuaishou: koishi_1.Schema.union([
114
- 'https://api.xingzhige.com/API/kuaishou/',
115
124
  'https://api.bugpk.com/api/short_videos',
116
- 'https://api.bugpk.com/api/ksjx'
117
- ]).default('https://api.xingzhige.com/API/kuaishou/').description('快手首选解析源'),
118
- xigua: koishi_1.Schema.union([
119
- 'https://api.xingzhige.com/API/xigua/',
120
- 'https://api.bugpk.com/api/short_videos',
121
- 'https://api.bugpk.com/api/toutiao'
122
- ]).default('https://api.xingzhige.com/API/xigua/').description('西瓜视频首选解析源'),
125
+ 'https://api.bugpk.com/api/ksjx',
126
+ 'https://api.bugpk.com/api/kuaishou',
127
+ 'https://api.bugpk.com/api/ksimg',
128
+ 'https://api.suyanw.cn/api/kuaishou.php'
129
+ ]).default('https://api.bugpk.com/api/short_videos').description('快手首选解析源'),
123
130
  xiaohongshu: koishi_1.Schema.union([
124
131
  'https://api.bugpk.com/api/short_videos',
125
- 'https://api.bugpk.com/api/xhsjx'
132
+ 'https://api.bugpk.com/api/xhsjx',
133
+ 'https://api.bugpk.com/api/xhsimg',
134
+ 'https://api.bugpk.com/api/xhslive',
135
+ 'https://api.bugpk.com/api/xhs'
126
136
  ]).default('https://api.bugpk.com/api/short_videos').description('小红书首选解析源'),
127
137
  weibo: koishi_1.Schema.union([
128
138
  'https://api.bugpk.com/api/short_videos',
129
- 'https://api.bugpk.com/api/weibo'
139
+ 'https://api.bugpk.com/api/weibo',
140
+ 'https://api.bugpk.com/api/weibo_v'
130
141
  ]).default('https://api.bugpk.com/api/short_videos').description('微博首选解析源'),
131
142
  toutiao: koishi_1.Schema.union([
132
143
  'https://api.bugpk.com/api/short_videos',
@@ -134,7 +145,8 @@ exports.Config = koishi_1.Schema.intersect([
134
145
  ]).default('https://api.bugpk.com/api/short_videos').description('今日头条首选解析源'),
135
146
  pipigx: koishi_1.Schema.union([
136
147
  'https://api.bugpk.com/api/short_videos',
137
- 'https://api.bugpk.com/api/pipigx'
148
+ 'https://api.bugpk.com/api/pipigx',
149
+ 'https://api.suyanw.cn/api/pipigx.php'
138
150
  ]).default('https://api.bugpk.com/api/short_videos').description('皮皮搞笑首选解析源'),
139
151
  pipixia: koishi_1.Schema.union([
140
152
  'https://api.bugpk.com/api/short_videos',
@@ -142,10 +154,11 @@ exports.Config = koishi_1.Schema.intersect([
142
154
  ]).default('https://api.bugpk.com/api/short_videos').description('皮皮虾首选解析源'),
143
155
  zuiyou: koishi_1.Schema.union([
144
156
  'https://api.bugpk.com/api/short_videos',
157
+ 'https://api.bugpk.com/api/zuiyou',
145
158
  'https://api.suyanw.cn/api/zuiyou.php'
146
159
  ]).default('https://api.bugpk.com/api/short_videos').description('最右首选解析源'),
147
160
  }).description('首选解析源设置(将优先尝试用户选择的API,失败后自动尝试其他)')
148
- }).description('API选择设置'),
161
+ }).description('API选择设置(启用后显示)'),
149
162
  ]),
150
163
  ]);
151
164
  function getErrorMessage(error) {
@@ -157,7 +170,7 @@ if (!worker_threads_1.isMainThread) {
157
170
  (async () => {
158
171
  try {
159
172
  if (url.endsWith('.m4a') || url.endsWith('.mp3')) {
160
- worker_threads_1.parentPort?.postMessage({ success: false, error: '不支持音频' });
173
+ worker_threads_1.parentPort?.postMessage({ success: false, error: '不支持音频', code: 3001 });
161
174
  return;
162
175
  }
163
176
  const maxSizeBytes = maxSize * 1024 * 1024;
@@ -170,8 +183,12 @@ if (!worker_threads_1.isMainThread) {
170
183
  });
171
184
  if (maxSize > 0 && response.headers['content-length']) {
172
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
+ }
173
190
  if (contentLength > maxSizeBytes) {
174
- worker_threads_1.parentPort?.postMessage({ success: false, error: `视频大小超过限制(${maxSize}MB)` });
191
+ worker_threads_1.parentPort?.postMessage({ success: false, error: `视频大小超过限制(${maxSize}MB)`, code: 3003 });
175
192
  return;
176
193
  }
177
194
  }
@@ -182,15 +199,20 @@ if (!worker_threads_1.isMainThread) {
182
199
  if (maxSize > 0 && downloadedSize > maxSizeBytes) {
183
200
  response.data.destroy();
184
201
  writeStream.destroy();
185
- fs_1.default.unlinkSync(filePath);
186
- worker_threads_1.parentPort?.postMessage({ success: false, error: `视频大小超过限制(${maxSize}MB)` });
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 });
187
209
  }
188
210
  });
189
211
  await (0, promises_1.pipeline)(response.data, writeStream);
190
212
  worker_threads_1.parentPort?.postMessage({ success: true, filePath });
191
213
  }
192
214
  catch (error) {
193
- worker_threads_1.parentPort?.postMessage({ success: false, error: getErrorMessage(error) });
215
+ worker_threads_1.parentPort?.postMessage({ success: false, error: getErrorMessage(error), code: 3004 });
194
216
  }
195
217
  })();
196
218
  }
@@ -206,7 +228,6 @@ const PLATFORM_KEYWORDS = {
206
228
  pipixia: ['pipixia', '皮皮虾', 'h5.pipix.com', 'pipix.com'],
207
229
  douyin: ['douyin', '抖音', 'v.douyin.com', 'douyin.com', 'tiktok.com'],
208
230
  zuiyou: ['zuiyou', '最右', 'xiaochuankeji.cn', 'izuiyou.com'],
209
- xigua: ['ixigua', '西瓜视频', 'xigua.com', 'ixigua.com']
210
231
  };
211
232
  function extractUrl(content, enableBvAvParse) {
212
233
  const urls = content.match(/https?:\/\/[^\s"'>]+/gi) || [];
@@ -306,30 +327,133 @@ function formatDuration(seconds) {
306
327
  return `${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
307
328
  }
308
329
  function parseData(data, maxDescLength, platform) {
309
- const type = data.images?.length && !data.video ? 'image' : 'video';
310
- const title = data.title || data.desc || '无标题';
311
- let author = data.author || data.name || '未知作者';
330
+ let type = 'unknown';
331
+ if (data.type) {
332
+ type = data.type.toLowerCase();
333
+ }
334
+ else if (data.data?.type) {
335
+ type = data.data.type.toLowerCase();
336
+ }
337
+ else if (data.images?.length && !data.url && !data.data?.url) {
338
+ type = 'image';
339
+ }
340
+ else if (data.live_photo?.length || data.data?.live_photo?.length) {
341
+ type = 'live';
342
+ }
343
+ else if (data.url || data.video || data.data?.url || data.data?.video) {
344
+ type = 'video';
345
+ }
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 || '未知作者';
312
348
  if (author && typeof author === 'object') {
313
- 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);
366
+ }
367
+ video = videoUrls.find(url => url && typeof url === 'string' && url.startsWith('http')) || '';
368
+ let video_backup;
369
+ if (data.video_backup) {
370
+ if (Array.isArray(data.video_backup)) {
371
+ video_backup = data.video_backup.map((item) => typeof item === 'object' ? item.url : item).filter(Boolean);
372
+ }
373
+ else if (typeof data.video_backup === 'string') {
374
+ video_backup = [data.video_backup];
375
+ }
376
+ }
377
+ let like = 0;
378
+ if (data.stat?.like !== undefined)
379
+ like = data.stat.like;
380
+ else if (data.like !== undefined)
381
+ like = data.like;
382
+ else if (data.likes !== undefined)
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;
388
+ let view = 0;
389
+ if (data.stat?.view !== undefined)
390
+ view = data.stat.view;
391
+ else if (data.view !== undefined)
392
+ view = data.view;
393
+ else if (data.views !== undefined)
394
+ view = data.views;
395
+ else if (data.play_count !== undefined)
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;
401
+ let share = 0;
402
+ if (data.stat?.share !== undefined)
403
+ share = data.stat.share;
404
+ else if (data.share !== undefined)
405
+ share = data.share;
406
+ else if (data.shares !== undefined)
407
+ share = data.shares;
408
+ else if (data.data?.stat?.share !== undefined)
409
+ share = data.data.stat.share;
410
+ let favorite = 0;
411
+ if (data.stat?.favorite !== undefined)
412
+ favorite = data.stat.favorite;
413
+ else if (data.favorite !== undefined)
414
+ favorite = data.favorite;
415
+ else if (data.collect !== undefined)
416
+ favorite = data.collect;
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);
314
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;
315
436
  return {
316
437
  type,
317
438
  title,
318
439
  author,
319
- desc: (data.desc || data.description || title).slice(0, maxDescLength),
320
- cover: data.cover || data.imgurl || data.pic || '',
321
- images: data.images || [],
322
- video: data.video || data.url || '',
323
- duration: data.duration || 0,
324
- durationFormatted: formatDuration(data.duration || 0),
440
+ desc,
441
+ cover,
442
+ images: Array.isArray(images) ? images : [],
443
+ video,
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,
325
449
  stat: {
326
- like: data.stat?.like || 0,
327
- coin: data.stat?.coin || 0,
328
- favorite: data.stat?.favorite || 0,
329
- share: data.stat?.share || 0,
330
- view: data.stat?.view || 0,
331
- size: data.stat?.size || 0,
332
- duration: formatDuration(data.duration || 0)
450
+ like,
451
+ coin,
452
+ favorite,
453
+ share,
454
+ view,
455
+ size,
456
+ duration: formatDuration(duration)
333
457
  }
334
458
  };
335
459
  }
@@ -340,7 +464,7 @@ function parse_xingzhige_data(resData, platform) {
340
464
  title: d.video?.title || d.title || '',
341
465
  author: d.owner?.name || d.name || '未知UP主',
342
466
  desc: d.video?.desc || d.desc || '',
343
- cover: d.video?.fm || d.fm || '',
467
+ cover: d.video?.fm || d.fm || d.cover || '',
344
468
  video: d.video?.url || d.url || '',
345
469
  images: [],
346
470
  stat: {
@@ -349,7 +473,8 @@ function parse_xingzhige_data(resData, platform) {
349
473
  coin: d.stat?.coin || 0,
350
474
  favorite: d.stat?.favorite || 0,
351
475
  share: d.stat?.share || 0,
352
- duration: d.duration || 0
476
+ duration: d.duration || 0,
477
+ size: d.size || 0
353
478
  },
354
479
  duration: d.duration || 0,
355
480
  type: 'video'
@@ -357,17 +482,38 @@ function parse_xingzhige_data(resData, platform) {
357
482
  }
358
483
  const item = resData.jx?.[0] || {};
359
484
  return {
360
- title: item.title || '',
361
- author: resData.stat?.author || '',
362
- cover: item.cover || '',
363
- video: item.url || item.video || '',
364
- images: item.images || [],
485
+ title: item.title || resData.title || '',
486
+ author: resData.stat?.author || resData.author || '',
487
+ cover: item.cover || resData.cover || '',
488
+ video: item.url || item.video || resData.url || '',
489
+ images: item.images || resData.images || [],
490
+ music: item.music || resData.music,
365
491
  stat: {
366
492
  like: resData.stat?.like || 0,
367
493
  view: resData.stat?.view || 0,
368
- share: resData.stat?.share || 0
494
+ share: resData.stat?.share || 0,
495
+ comment: resData.stat?.comment || 0,
496
+ collect: resData.stat?.collect || 0,
497
+ size: item.size || 0
498
+ },
499
+ type: item.images?.length ? 'image' : (resData.type || 'video')
500
+ };
501
+ }
502
+ function parse_suyanw_data(resData) {
503
+ return {
504
+ title: resData.data?.title || '',
505
+ author: resData.data?.author || '',
506
+ cover: resData.data?.cover || '',
507
+ video: resData.data?.video || resData.data?.url || '',
508
+ images: resData.image || [],
509
+ music: resData.music,
510
+ stat: {
511
+ like: resData.data?.likes || 0,
512
+ view: resData.data?.views || 0,
513
+ comment: resData.data?.comments || 0,
514
+ size: 0
369
515
  },
370
- type: item.images?.length ? 'image' : 'video'
516
+ type: resData.image?.length ? 'image' : 'video'
371
517
  };
372
518
  }
373
519
  function generateFormattedText(platform, parseData, config) {
@@ -384,7 +530,7 @@ function generateFormattedText(platform, parseData, config) {
384
530
  .replace(/\${播放数}/g, String(parseData.stat.view))
385
531
  .replace(/\${视频大小}/g, String(parseData.stat.size));
386
532
  if (platform !== 'bilibili') {
387
- text = text.replace(/\n投币:[0-9]+/g, '');
533
+ text = text.replace(/投币:[0-9]+\n?/g, '');
388
534
  }
389
535
  return text;
390
536
  }
@@ -401,12 +547,12 @@ async function downloadVideoWithThreads(url, filename, maxSize, threads, userAge
401
547
  if (result.success && result.filePath)
402
548
  resolve(result.filePath);
403
549
  else
404
- reject(new Error(result.error || '下载失败'));
550
+ reject(new Error(`${result.error || '下载失败'} (错误码: ${result.code || 3000})`));
405
551
  });
406
552
  worker.on('error', reject);
407
553
  worker.on('exit', (code) => {
408
554
  if (code !== 0)
409
- reject(new Error('视频下载线程异常'));
555
+ reject(new Error(`视频下载线程异常 (错误码: 3005)`));
410
556
  });
411
557
  });
412
558
  }
@@ -418,7 +564,8 @@ function clearAllCache() {
418
564
  if (fs_1.default.existsSync(tempDir)) {
419
565
  fs_1.default.readdirSync(tempDir).forEach(file => {
420
566
  try {
421
- fs_1.default.unlinkSync(path_1.default.join(tempDir, file));
567
+ const filePath = path_1.default.join(tempDir, file);
568
+ fs_1.default.unlinkSync(filePath);
422
569
  }
423
570
  catch { }
424
571
  });
@@ -445,189 +592,262 @@ function apply(ctx, config) {
445
592
  if (!worker_threads_1.isMainThread)
446
593
  return;
447
594
  clearAllCache();
595
+ logger.info('视频解析插件已加载');
448
596
  const http = axios_1.default.create({
449
597
  timeout: config.timeout,
450
- headers: { 'User-Agent': config.userAgent }
598
+ headers: { 'User-Agent': config.userAgent },
599
+ maxRedirects: 5,
600
+ validateStatus: (status) => status >= 200 && status < 500
451
601
  });
452
- async function tryAPI(apiFunc) {
602
+ async function tryAPI(apiFunc, apiName) {
453
603
  try {
454
- return await apiFunc();
604
+ const result = await apiFunc();
605
+ return result;
455
606
  }
456
- catch {
607
+ catch (error) {
457
608
  return null;
458
609
  }
459
610
  }
611
+ async function requestAPI(apiUrl, params, method = 'GET') {
612
+ try {
613
+ let response;
614
+ if (method.toUpperCase() === 'GET') {
615
+ response = await http.get(apiUrl, { params });
616
+ }
617
+ else {
618
+ response = await http.post(apiUrl, params);
619
+ }
620
+ return response.data;
621
+ }
622
+ catch (error) {
623
+ throw error;
624
+ }
625
+ }
460
626
  async function parseBilibili(realUrl) {
461
627
  const preferred = config.enableApiSelection ? config.preferredApi?.bilibili : 'https://api.xingzhige.com/API/b_parse/';
462
628
  const apis = [preferred];
463
629
  if (config.bilibiliAccessKey && preferred.includes('xingzhige')) {
464
630
  const vipResult = await tryAPI(async () => {
465
- const res = await http.get(preferred, {
466
- params: { url: realUrl, access_key: config.bilibiliAccessKey }
467
- });
468
- if (res.data?.data || res.data?.title) {
469
- return { data: parseData(parse_xingzhige_data(res.data, 'bilibili'), config.maxDescLength, 'bilibili'), msg: 'B站解析成功' };
631
+ const data = await requestAPI(preferred, {
632
+ url: realUrl,
633
+ access_key: config.bilibiliAccessKey
634
+ }, 'GET');
635
+ if (data?.data || data?.title) {
636
+ return { data: parseData(parse_xingzhige_data(data, 'bilibili'), config.maxDescLength, 'bilibili'), msg: 'B站解析成功' };
470
637
  }
471
638
  return null;
472
- });
639
+ }, `${preferred} (大会员)`);
473
640
  if (vipResult)
474
641
  return vipResult;
475
642
  }
476
643
  const otherApis = [
477
- 'https://api.xingzhige.com/API/b_parse/',
478
- 'https://api.bugpk.com/api/short_videos',
479
- 'https://api.bugpk.com/api/bilibili',
480
- 'https://api.bilibili.com/x/web-interface/view'
481
- ].filter(api => api !== preferred);
482
- apis.push(...otherApis);
483
- for (const apiUrl of apis) {
644
+ { url: 'https://api.xingzhige.com/API/b_parse/', method: 'GET' },
645
+ { url: 'https://api.bugpk.com/api/bilibili', method: 'GET' },
646
+ { url: 'https://api.bugpk.com/api/short_videos', method: 'GET' },
647
+ { url: 'https://api.bilibili.com/x/web-interface/view', method: 'GET' }
648
+ ].filter(api => api.url !== preferred);
649
+ for (const apiInfo of otherApis) {
484
650
  const result = await tryAPI(async () => {
485
651
  const params = { url: realUrl };
486
- if (config.bilibiliAccessKey && apiUrl.includes('xingzhige')) {
652
+ if (apiInfo.url.includes('bilibili.com/x/web-interface/view')) {
653
+ const vid = vid_type_parse(realUrl);
654
+ if (vid.type === 'bv') {
655
+ params.bvid = vid.id;
656
+ }
657
+ else if (vid.type === 'av') {
658
+ params.aid = vid.id;
659
+ }
660
+ }
661
+ if (config.bilibiliAccessKey && apiInfo.url.includes('xingzhige')) {
487
662
  params.access_key = config.bilibiliAccessKey;
488
663
  }
489
- const res = await http.get(apiUrl, { params });
490
- if (apiUrl.includes('xingzhige') && (res.data?.data || res.data?.title)) {
491
- return { data: parseData(parse_xingzhige_data(res.data, 'bilibili'), config.maxDescLength, 'bilibili'), msg: 'B站解析成功' };
664
+ const data = await requestAPI(apiInfo.url, params, apiInfo.method);
665
+ if (apiInfo.url.includes('xingzhige')) {
666
+ if (data?.data || data?.title) {
667
+ return { data: parseData(parse_xingzhige_data(data, 'bilibili'), config.maxDescLength, 'bilibili'), msg: 'B站解析成功' };
668
+ }
492
669
  }
493
- if ((res.data?.code === 200 || res.data?.code === 0) && res.data?.data) {
494
- return { data: parseData(res.data.data, config.maxDescLength, 'bilibili'), msg: 'B站解析成功' };
670
+ else if (apiInfo.url.includes('bugpk.com')) {
671
+ if ((data?.code === 200 || data?.code === 0) && data?.data) {
672
+ return { data: parseData(data, config.maxDescLength, 'bilibili'), msg: 'B站解析成功' };
673
+ }
495
674
  }
496
- if (apiUrl.includes('bilibili.com') && res.data?.code === 0 && res.data?.data) {
497
- const { bvid, cid } = res.data.data;
675
+ else if (apiInfo.url.includes('bilibili.com') && data?.code === 0 && data?.data) {
676
+ const { bvid, cid } = data.data;
498
677
  const playInfo = await get_bilibili_play_url(bvid, cid, config.userAgent);
499
678
  if (playInfo) {
500
679
  return {
501
- data: parseData({ ...res.data, playUrl: playInfo.url, duration: playInfo.duration }, config.maxDescLength, 'bilibili'),
680
+ data: parseData({ ...data.data, playUrl: playInfo.url, duration: playInfo.duration }, config.maxDescLength, 'bilibili'),
502
681
  msg: 'B站解析成功'
503
682
  };
504
683
  }
505
684
  }
506
685
  return null;
507
- });
686
+ }, apiInfo.url);
508
687
  if (result)
509
688
  return result;
510
689
  }
511
- ctx.logger.error(`B站解析失败 - URL: ${realUrl}, 错误码: 2001`);
512
- return { data: null, msg: 'B站解析失败' };
690
+ logger.error(`B站解析失败 - URL: ${realUrl}, 错误码: 2001`);
691
+ return { data: null, msg: 'B站解析失败 (错误码: 2001)' };
513
692
  }
514
693
  async function parseKuaishou(realUrl) {
515
- const preferred = config.enableApiSelection ? config.preferredApi?.kuaishou : 'https://api.xingzhige.com/API/kuaishou/';
516
- const apis = [preferred];
694
+ const preferred = config.enableApiSelection ? config.preferredApi?.kuaishou : 'https://api.bugpk.com/api/short_videos';
695
+ const apis = [{ url: preferred, method: 'GET' }];
517
696
  const otherApis = [
518
- 'https://api.xingzhige.com/API/kuaishou/',
519
- 'https://api.bugpk.com/api/short_videos',
520
- 'https://api.bugpk.com/api/ksjx'
521
- ].filter(api => api !== preferred);
697
+ { url: 'https://api.bugpk.com/api/kuaishou', method: 'GET' },
698
+ { url: 'https://api.bugpk.com/api/ksjx', method: 'GET' },
699
+ { url: 'https://api.bugpk.com/api/ksimg', method: 'GET' },
700
+ { url: 'https://api.suyanw.cn/api/kuaishou.php', method: 'GET' },
701
+ { url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
702
+ ].filter(api => api.url !== preferred);
522
703
  apis.push(...otherApis);
523
- for (const apiUrl of apis) {
704
+ for (const apiInfo of apis) {
524
705
  const result = await tryAPI(async () => {
525
- const res = await http.get(apiUrl, { params: { url: realUrl } });
526
- if (apiUrl.includes('xingzhige') && res.data?.jx?.length) {
527
- return { data: parseData(parse_xingzhige_data(res.data, 'kuaishou'), config.maxDescLength, 'kuaishou'), msg: '快手解析成功' };
706
+ const data = await requestAPI(apiInfo.url, { url: realUrl }, apiInfo.method);
707
+ if (apiInfo.url.includes('suyanw.cn')) {
708
+ if (data?.code === 200) {
709
+ return { data: parseData(parse_suyanw_data(data), config.maxDescLength, 'kuaishou'), msg: '快手解析成功' };
710
+ }
528
711
  }
529
- if ((res.data?.code === 200 || res.data?.code === 0) && (res.data?.data || res.data?.image)) {
530
- return { data: parseData(res.data.data || res.data, config.maxDescLength, 'kuaishou'), msg: '快手解析成功' };
712
+ else if (apiInfo.url.includes('bugpk.com')) {
713
+ if ((data?.code === 200 || data?.code === 0)) {
714
+ if (data.data) {
715
+ return { data: parseData(data, config.maxDescLength, 'kuaishou'), msg: '快手解析成功' };
716
+ }
717
+ else if (data.images) {
718
+ return {
719
+ data: parseData({
720
+ images: data.images,
721
+ title: '快手图集',
722
+ author: data.author || '未知作者',
723
+ type: 'image'
724
+ }, config.maxDescLength, 'kuaishou'),
725
+ msg: '快手图集解析成功'
726
+ };
727
+ }
728
+ }
531
729
  }
532
730
  return null;
533
- });
731
+ }, apiInfo.url);
534
732
  if (result)
535
733
  return result;
536
734
  }
537
- ctx.logger.error(`快手解析失败 - URL: ${realUrl}, 错误码: 2002`);
538
- return { data: null, msg: '快手解析失败' };
735
+ logger.error(`快手解析失败 - URL: ${realUrl}, 错误码: 2002`);
736
+ return { data: null, msg: '快手解析失败 (错误码: 2002)' };
539
737
  }
540
738
  async function parseDouyin(realUrl) {
541
739
  const preferred = config.enableApiSelection ? config.preferredApi?.douyin : 'https://api.xingzhige.com/API/douyin/';
542
- const apis = [preferred];
740
+ const apis = [{ url: preferred, method: 'GET' }];
543
741
  const otherApis = [
544
- 'https://api.xingzhige.com/API/douyin/',
545
- 'https://api.bugpk.com/api/short_videos',
546
- 'https://api.bugpk.com/api/douyin'
547
- ].filter(api => api !== preferred);
742
+ { url: 'https://api.xingzhige.com/API/douyin/', method: 'GET' },
743
+ { url: 'https://api.bugpk.com/api/douyin', method: 'GET' },
744
+ { url: 'https://api.bugpk.com/api/dyjx', method: 'GET' },
745
+ { url: 'https://api.bugpk.com/api/dylive', method: 'GET' },
746
+ { url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
747
+ ].filter(api => api.url !== preferred);
548
748
  apis.push(...otherApis);
549
- for (const apiUrl of apis) {
749
+ for (const apiInfo of apis) {
550
750
  const result = await tryAPI(async () => {
551
- const res = await http.get(apiUrl, { params: { url: realUrl } });
552
- if (apiUrl.includes('xingzhige') && res.data?.jx?.length) {
553
- return { data: parseData(parse_xingzhige_data(res.data, 'douyin'), config.maxDescLength, 'douyin'), msg: '抖音解析成功' };
554
- }
555
- if ((res.data?.code === 200 || res.data?.code === 0) && res.data?.data) {
556
- return { data: parseData(res.data.data, config.maxDescLength, 'douyin'), msg: '抖音解析成功' };
557
- }
558
- return null;
559
- });
560
- if (result)
561
- return result;
562
- }
563
- ctx.logger.error(`抖音解析失败 - URL: ${realUrl}, 错误码: 2003`);
564
- return { data: null, msg: '抖音解析失败' };
565
- }
566
- async function parseXigua(realUrl) {
567
- const preferred = config.enableApiSelection ? config.preferredApi?.xigua : 'https://api.xingzhige.com/API/xigua/';
568
- const apis = [preferred];
569
- const otherApis = [
570
- 'https://api.xingzhige.com/API/xigua/',
571
- 'https://api.bugpk.com/api/short_videos',
572
- 'https://api.bugpk.com/api/toutiao'
573
- ].filter(api => api !== preferred);
574
- apis.push(...otherApis);
575
- for (const apiUrl of apis) {
576
- const result = await tryAPI(async () => {
577
- const res = await http.get(apiUrl, { params: { url: realUrl } });
578
- if (apiUrl.includes('xingzhige') && res.data?.jx?.length) {
579
- return { data: parseData(parse_xingzhige_data(res.data, 'xigua'), config.maxDescLength, 'xigua'), msg: '西瓜视频解析成功' };
751
+ const method = apiInfo.url.includes('bugpk.com') ? 'POST' : 'GET';
752
+ const data = await requestAPI(apiInfo.url, { url: realUrl }, method);
753
+ if (apiInfo.url.includes('xingzhige')) {
754
+ if (data?.jx?.length || data?.data) {
755
+ return { data: parseData(parse_xingzhige_data(data, 'douyin'), config.maxDescLength, 'douyin'), msg: '抖音解析成功' };
756
+ }
580
757
  }
581
- if ((res.data?.code === 200 || res.data?.code === 0) && res.data?.data) {
582
- return { data: parseData(res.data.data, config.maxDescLength, 'xigua'), msg: '西瓜视频解析成功' };
758
+ else if (apiInfo.url.includes('bugpk.com')) {
759
+ if ((data?.code === 200 || data?.code === 0)) {
760
+ if (data.data) {
761
+ return { data: parseData(data, config.maxDescLength, 'douyin'), msg: '抖音解析成功' };
762
+ }
763
+ }
583
764
  }
584
765
  return null;
585
- });
766
+ }, apiInfo.url);
586
767
  if (result)
587
768
  return result;
588
769
  }
589
- ctx.logger.error(`西瓜视频解析失败 - URL: ${realUrl}, 错误码: 2004`);
590
- return { data: null, msg: '西瓜视频解析失败' };
770
+ logger.error(`抖音解析失败 - URL: ${realUrl}, 错误码: 2003`);
771
+ return { data: null, msg: '抖音解析失败 (错误码: 2003)' };
591
772
  }
592
773
  async function parseOther(realUrl, platform) {
593
774
  const preferred = config.enableApiSelection ? config.preferredApi?.[platform] : 'https://api.bugpk.com/api/short_videos';
594
- const apis = [preferred];
775
+ const apis = [{ url: preferred, method: 'GET' }];
595
776
  const platformApis = {
596
- xiaohongshu: ['https://api.bugpk.com/api/short_videos', 'https://api.bugpk.com/api/xhsjx'],
597
- weibo: ['https://api.bugpk.com/api/short_videos', 'https://api.bugpk.com/api/weibo'],
598
- toutiao: ['https://api.bugpk.com/api/short_videos', 'https://api.bugpk.com/api/toutiao'],
599
- pipigx: ['https://api.bugpk.com/api/short_videos', 'https://api.bugpk.com/api/pipigx'],
600
- pipixia: ['https://api.bugpk.com/api/short_videos', 'https://api.bugpk.com/api/pipixia'],
601
- zuiyou: ['https://api.bugpk.com/api/short_videos', 'https://api.suyanw.cn/api/zuiyou.php']
777
+ xiaohongshu: [
778
+ { url: 'https://api.bugpk.com/api/xhsjx', method: 'GET' },
779
+ { url: 'https://api.bugpk.com/api/xhsimg', method: 'GET' },
780
+ { url: 'https://api.bugpk.com/api/xhslive', method: 'GET' },
781
+ { url: 'https://api.bugpk.com/api/xhs', method: 'GET' },
782
+ { url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
783
+ ],
784
+ weibo: [
785
+ { url: 'https://api.bugpk.com/api/weibo', method: 'GET' },
786
+ { url: 'https://api.bugpk.com/api/weibo_v', method: 'GET' },
787
+ { url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
788
+ ],
789
+ toutiao: [
790
+ { url: 'https://api.bugpk.com/api/toutiao', method: 'GET' },
791
+ { url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
792
+ ],
793
+ pipigx: [
794
+ { url: 'https://api.bugpk.com/api/pipigx', method: 'GET' },
795
+ { url: 'https://api.suyanw.cn/api/pipigx.php', method: 'GET' },
796
+ { url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
797
+ ],
798
+ pipixia: [
799
+ { url: 'https://api.bugpk.com/api/pipixia', method: 'GET' },
800
+ { url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
801
+ ],
802
+ zuiyou: [
803
+ { url: 'https://api.bugpk.com/api/zuiyou', method: 'GET' },
804
+ { url: 'https://api.suyanw.cn/api/zuiyou.php', method: 'GET' },
805
+ { url: 'https://api.bugpk.com/api/short_videos', method: 'GET' }
806
+ ]
602
807
  };
603
- const otherApis = (platformApis[platform] || []).filter(api => api !== preferred);
808
+ const otherApis = (platformApis[platform] || []).filter(api => api.url !== preferred);
604
809
  apis.push(...otherApis);
605
- for (const apiUrl of apis) {
810
+ for (const apiInfo of apis) {
606
811
  const result = await tryAPI(async () => {
607
- const res = await http.get(apiUrl, { params: { url: realUrl } });
608
- if ((res.data?.code === 200 || res.data?.code === 0) && res.data?.data) {
609
- return { data: parseData(res.data.data, config.maxDescLength, platform), msg: '解析成功' };
812
+ const data = await requestAPI(apiInfo.url, { url: realUrl }, apiInfo.method);
813
+ if (apiInfo.url.includes('bugpk.com') || apiInfo.url.includes('suyanw.cn')) {
814
+ if (data?.code === 200 || data?.code === 0) {
815
+ if (data.data) {
816
+ return { data: parseData(data, config.maxDescLength, platform), msg: '解析成功' };
817
+ }
818
+ else if (data.images) {
819
+ return {
820
+ data: parseData({
821
+ images: data.images,
822
+ title: data.title || `${platform}图集`,
823
+ author: data.author || '未知作者',
824
+ type: 'image'
825
+ }, config.maxDescLength, platform),
826
+ msg: '图集解析成功'
827
+ };
828
+ }
829
+ }
610
830
  }
611
831
  return null;
612
- });
832
+ }, apiInfo.url);
613
833
  if (result)
614
834
  return result;
615
835
  }
616
- ctx.logger.error(`${platform}解析失败 - URL: ${realUrl}, 错误码: 2005`);
617
- return { data: null, msg: '解析失败,请稍后重试' };
836
+ logger.error(`${platform}解析失败 - URL: ${realUrl}, 错误码: 2005`);
837
+ return { data: null, msg: '解析失败,请稍后重试 (错误码: 2005)' };
618
838
  }
619
839
  async function parse(url) {
620
840
  const realUrl = await resolveShortUrl(url);
621
841
  const platform = getPlatformType(realUrl);
622
842
  if (!platform || !config.platformEnable[platform]) {
623
- ctx.logger.error(`解析失败 - 平台: ${platform || '未知'}, URL: ${url}, 错误码: 1001`);
624
- return { data: null, msg: platform ? '该平台解析已关闭' : '不支持该平台链接' };
843
+ const code = !platform ? 1001 : 1002;
844
+ logger.error(`解析失败 - 平台: ${platform || '未知'}, URL: ${url}, 错误码: ${code}`);
845
+ return { data: null, msg: platform ? `该平台解析已关闭 (错误码: ${code})` : `不支持该平台链接 (错误码: ${code})` };
625
846
  }
626
847
  const parsers = {
627
848
  bilibili: parseBilibili,
628
849
  kuaishou: parseKuaishou,
629
- douyin: parseDouyin,
630
- xigua: parseXigua
850
+ douyin: parseDouyin
631
851
  };
632
852
  if (parsers[platform]) {
633
853
  return parsers[platform](realUrl);
@@ -638,16 +858,17 @@ function apply(ctx, config) {
638
858
  const hash = crypto_1.default.createHash('md5').update(url).digest('hex');
639
859
  const now = Date.now();
640
860
  if (processed.get(hash) && now - processed.get(hash) < config.sameLinkInterval * 1000) {
641
- return { data: null, msg: '请勿重复解析' };
861
+ return { data: null, msg: '请勿重复解析 (错误码: 1003)' };
642
862
  }
643
863
  processed.set(hash, now);
644
864
  const result = await parse(url);
645
- if (!result.data)
865
+ if (!result.data) {
646
866
  return { data: null, msg: result.msg };
867
+ }
647
868
  const platform = getPlatformType(url);
648
869
  const text = generateFormattedText(platform || 'bilibili', result.data, config);
649
870
  return {
650
- data: { text, cover: result.data.cover, images: result.data.images, video: result.data.video, type: result.data.type },
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 },
651
872
  msg: 'ok'
652
873
  };
653
874
  }
@@ -655,7 +876,7 @@ function apply(ctx, config) {
655
876
  if (config.videoSendTimeout <= 0) {
656
877
  return session.send(content).catch((err) => {
657
878
  if (!config.ignoreSendError)
658
- ctx.logger.error('发送消息失败:', err.message);
879
+ logger.error(`发送消息失败 (错误码: 4001): ${err.message}`);
659
880
  return null;
660
881
  });
661
882
  }
@@ -664,7 +885,7 @@ function apply(ctx, config) {
664
885
  new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), config.videoSendTimeout))
665
886
  ]).catch((err) => {
666
887
  if (!config.ignoreSendError)
667
- ctx.logger.error('发送消息超时:', err.message);
888
+ logger.error(`发送消息超时 (错误码: 4002): ${err.message}`);
668
889
  return null;
669
890
  });
670
891
  }
@@ -683,9 +904,9 @@ function apply(ctx, config) {
683
904
  if (result.data) {
684
905
  items.push(result.data);
685
906
  }
686
- else if (result.msg !== '请勿重复解析') {
907
+ else if (result.msg !== '请勿重复解析 (错误码: 1003)') {
687
908
  errs.push(`【${url.slice(0, 22)}...】:${result.msg}`);
688
- ctx.logger.error(`解析失败: ${url}, 原因: ${result.msg}`);
909
+ logger.error(`解析失败: ${url}, 原因: ${result.msg}`);
689
910
  }
690
911
  }
691
912
  const enableForward = config.enableForward && session.platform === 'onebot';
@@ -723,6 +944,15 @@ function apply(ctx, config) {
723
944
  forwardMessages.push(buildForwardNode(session, koishi_1.h.image(item.images[i]), botName));
724
945
  }
725
946
  }
947
+ if (item.live_photo?.length && forwardMessages.length < 100) {
948
+ for (let i = 0; i < item.live_photo.length && forwardMessages.length < 100; i++) {
949
+ const live = item.live_photo[i];
950
+ forwardMessages.push(buildForwardNode(session, koishi_1.h.image(live.image), botName));
951
+ if (live.video && forwardMessages.length < 100) {
952
+ forwardMessages.push(buildForwardNode(session, koishi_1.h.video(live.video), botName));
953
+ }
954
+ }
955
+ }
726
956
  if (item.video && config.showVideoFile && forwardMessages.length < 100) {
727
957
  let videoElem;
728
958
  if (config.downloadVideoBeforeSend) {
@@ -732,7 +962,7 @@ function apply(ctx, config) {
732
962
  videoElem = koishi_1.h.file(filePath);
733
963
  }
734
964
  catch (error) {
735
- ctx.logger.error(`视频下载失败: ${getErrorMessage(error)}`);
965
+ logger.error(`视频下载失败 (错误码: 4003): ${getErrorMessage(error)}`);
736
966
  videoElem = koishi_1.h.video(item.video);
737
967
  }
738
968
  }
@@ -752,6 +982,16 @@ function apply(ctx, config) {
752
982
  if (item.type === 'image' && item.images?.length) {
753
983
  await sendTimeout(session, (0, koishi_1.h)('message', ...item.images.map((url) => koishi_1.h.image(url))));
754
984
  }
985
+ else if (item.live_photo?.length) {
986
+ for (const live of item.live_photo) {
987
+ await sendTimeout(session, koishi_1.h.image(live.image));
988
+ await delay(300);
989
+ if (live.video) {
990
+ await sendTimeout(session, koishi_1.h.video(live.video));
991
+ await delay(300);
992
+ }
993
+ }
994
+ }
755
995
  else {
756
996
  if (item.cover) {
757
997
  await sendTimeout(session, koishi_1.h.image(item.cover));
@@ -766,7 +1006,7 @@ function apply(ctx, config) {
766
1006
  videoElem = koishi_1.h.file(filePath);
767
1007
  }
768
1008
  catch (error) {
769
- ctx.logger.error(`视频下载失败: ${getErrorMessage(error)}`);
1009
+ logger.error(`视频下载失败 (错误码: 4003): ${getErrorMessage(error)}`);
770
1010
  videoElem = koishi_1.h.video(item.video);
771
1011
  }
772
1012
  }
@@ -780,8 +1020,8 @@ function apply(ctx, config) {
780
1020
  }
781
1021
  }
782
1022
  catch (error) {
783
- ctx.logger.error(`处理内容失败: ${getErrorMessage(error)}`);
784
- await sendTimeout(session, `❌ 处理${item.type}内容失败: ${getErrorMessage(error)}`);
1023
+ logger.error(`处理内容失败 (错误码: 4004): ${getErrorMessage(error)}`);
1024
+ await sendTimeout(session, `❌ 处理${item.type}内容失败: ${getErrorMessage(error)} (错误码: 4004)`);
785
1025
  }
786
1026
  }
787
1027
  if (enableForward && forwardMessages.length) {
@@ -789,7 +1029,7 @@ function apply(ctx, config) {
789
1029
  await sendTimeout(session, (0, koishi_1.h)('message', { forward: true }, forwardMessages.slice(0, 100)));
790
1030
  }
791
1031
  catch (error) {
792
- ctx.logger.error(`合并转发失败: ${getErrorMessage(error)}`);
1032
+ logger.error(`合并转发失败 (错误码: 4005): ${getErrorMessage(error)}`);
793
1033
  for (const node of forwardMessages) {
794
1034
  await sendTimeout(session, node.data.content);
795
1035
  await delay(500);
@@ -800,7 +1040,20 @@ function apply(ctx, config) {
800
1040
  ctx.on('message', async (session) => {
801
1041
  if (!config.enable || !config.autoParse)
802
1042
  return;
803
- const urls = extractUrl(session.content.trim(), config.enableBvAvParse);
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);
804
1057
  if (!urls.length)
805
1058
  return;
806
1059
  const key = `${session.platform}:${session.userId}:${session.channelId}`;
@@ -829,10 +1082,10 @@ function apply(ctx, config) {
829
1082
  ctx.command('parse <url>', '手动解析视频链接')
830
1083
  .action(async ({ session }, url) => {
831
1084
  if (!url)
832
- return '请输入视频链接';
1085
+ return '请输入视频链接 (错误码: 5001)';
833
1086
  const urls = extractUrl(url, config.enableBvAvParse);
834
1087
  if (!urls.length)
835
- return '不支持该链接';
1088
+ return '不支持该链接 (错误码: 1001)';
836
1089
  await flush(session, [...new Set(urls)]);
837
1090
  });
838
1091
  ctx.command('clear-cache', '清空解析缓存与临时文件')
@@ -854,12 +1107,13 @@ function apply(ctx, config) {
854
1107
  const now = Date.now();
855
1108
  fs_1.default.readdirSync(tempDir).forEach(file => {
856
1109
  try {
857
- const stat = fs_1.default.statSync(path_1.default.join(tempDir, file));
1110
+ const filePath = path_1.default.join(tempDir, file);
1111
+ const stat = fs_1.default.statSync(filePath);
858
1112
  if (now - stat.mtimeMs > 3600000)
859
- fs_1.default.unlinkSync(path_1.default.join(tempDir, file));
1113
+ fs_1.default.unlinkSync(filePath);
860
1114
  }
861
1115
  catch (error) {
862
- ctx.logger.error(`清理临时文件失败: ${file}, ${getErrorMessage(error)}`);
1116
+ logger.error(`清理临时文件失败 (错误码: 4006): ${file}, ${getErrorMessage(error)}`);
863
1117
  }
864
1118
  });
865
1119
  }, 1800000);
@@ -867,7 +1121,7 @@ function apply(ctx, config) {
867
1121
  setInterval(clearAllCache, config.autoClearCacheInterval * 60000);
868
1122
  }
869
1123
  process.on('exit', clearAllCache);
870
- ctx.logger.info('视频解析插件已加载');
1124
+ logger.info('视频解析插件已加载完成');
871
1125
  }
872
1126
  module.exports = {
873
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.6",
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": [