koishi-plugin-video-parser-all 1.4.8 → 1.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 CHANGED
@@ -1,12 +1,4 @@
1
1
  import { Context, Schema } from 'koishi';
2
- declare module 'koishi' {
3
- interface Context {
4
- downloads?: {
5
- download(url: string, dest: string, options?: Record<string, unknown>): Promise<string>;
6
- };
7
- aria2?: any;
8
- }
9
- }
10
2
  export declare const name = "video-parser-all";
11
3
  export declare const Config: Schema<{
12
4
  enable?: boolean | null | undefined;
@@ -45,10 +37,17 @@ export declare const Config: Schema<{
45
37
  } & {
46
38
  showImageText?: boolean | null | undefined;
47
39
  showCoverImage?: boolean | null | undefined;
40
+ showCoverFile?: boolean | null | undefined;
41
+ showImageFileNew?: boolean | null | undefined;
42
+ showAuthorAvatar?: boolean | null | undefined;
43
+ showAuthorAvatarFile?: boolean | null | undefined;
44
+ showAuthorAvatarText?: boolean | null | undefined;
45
+ authorAvatarText?: string | null | undefined;
48
46
  showMusicCover?: boolean | null | undefined;
49
- showImageFile?: boolean | null | undefined;
50
47
  showVideoFile?: boolean | null | undefined;
51
- forceDownloadImage?: boolean | null | undefined;
48
+ forceDownloadCover?: boolean | null | undefined;
49
+ forceDownloadImageNew?: boolean | null | undefined;
50
+ forceDownloadAuthorAvatar?: boolean | null | undefined;
52
51
  forceDownloadVideo?: boolean | null | undefined;
53
52
  } & {
54
53
  showMusicVoice?: boolean | null | undefined;
@@ -190,10 +189,17 @@ export declare const Config: Schema<{
190
189
  } & {
191
190
  showImageText: boolean;
192
191
  showCoverImage: boolean;
192
+ showCoverFile: boolean;
193
+ showImageFileNew: boolean;
194
+ showAuthorAvatar: boolean;
195
+ showAuthorAvatarFile: boolean;
196
+ showAuthorAvatarText: boolean;
197
+ authorAvatarText: string;
193
198
  showMusicCover: boolean;
194
- showImageFile: boolean;
195
199
  showVideoFile: boolean;
196
- forceDownloadImage: boolean;
200
+ forceDownloadCover: boolean;
201
+ forceDownloadImageNew: boolean;
202
+ forceDownloadAuthorAvatar: boolean;
197
203
  forceDownloadVideo: boolean;
198
204
  } & {
199
205
  showMusicVoice: boolean;
package/lib/index.js CHANGED
@@ -103,15 +103,22 @@ exports.Config = koishi_1.Schema.intersect([
103
103
  }).description('各平台解析开关'),
104
104
  }).description('基本设置'),
105
105
  koishi_1.Schema.object({
106
- unifiedMessageFormat: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}\n音乐标题:${音乐标题}\n音乐作者:${音乐作者}\n点赞:${点赞数}\n收藏:${收藏数}\n转发:${转发数}\n播放:${播放数}\n评论:${评论数}\n图片数量:${图片数量}').description('文字格式,支持变量,空行自动隐藏'),
106
+ unifiedMessageFormat: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}\n音乐标题:${音乐标题}\n音乐作者:${音乐作者}\n点赞:${点赞数}\n收藏:${收藏数}\n转发:${转发数}\n播放:${播放数}\n评论:${评论数}\n图片数量:${图片数量}').description('文字格式,支持变量:${标题} ${作者} ${author-name} ${简介} ${视频时长} ${点赞数} ${收藏数} ${转发数} ${播放数} ${评论数} ${发布时间} ${图片数量} ${作者ID} ${author-id} ${音乐标题} ${music-title} ${音乐作者} ${music-author},空行自动隐藏'),
107
107
  }).description('消息格式'),
108
108
  koishi_1.Schema.object({
109
109
  showImageText: koishi_1.Schema.boolean().default(true).description('发送文字内容'),
110
110
  showCoverImage: koishi_1.Schema.boolean().default(true).description('发送封面图片'),
111
+ showCoverFile: koishi_1.Schema.boolean().default(true).description('封面是否以图片形式发送(关闭则只发送链接)'),
112
+ showImageFileNew: koishi_1.Schema.boolean().default(true).description('图片是否以图片形式发送(关闭则只发送链接)'),
113
+ showAuthorAvatar: koishi_1.Schema.boolean().default(true).description('发送作者头像图片'),
114
+ showAuthorAvatarFile: koishi_1.Schema.boolean().default(true).description('作者头像图片是否以图片形式发送(关闭则只发送链接)'),
115
+ showAuthorAvatarText: koishi_1.Schema.boolean().default(true).description('发送作者头像前显示文字提示'),
116
+ authorAvatarText: koishi_1.Schema.string().default('作者头像:').description('作者头像前显示的文字'),
111
117
  showMusicCover: koishi_1.Schema.boolean().default(true).description('发送音乐封面图片'),
112
- showImageFile: koishi_1.Schema.boolean().default(true).description('封面/图片是否以图片形式发送(关闭则只发送链接)'),
113
118
  showVideoFile: koishi_1.Schema.boolean().default(true).description('视频是否以视频形式发送(关闭则只发送链接)'),
114
- forceDownloadImage: koishi_1.Schema.boolean().default(false).description('强制下载封面/图片'),
119
+ forceDownloadCover: koishi_1.Schema.boolean().default(false).description('强制下载封面'),
120
+ forceDownloadImageNew: koishi_1.Schema.boolean().default(false).description('强制下载图片'),
121
+ forceDownloadAuthorAvatar: koishi_1.Schema.boolean().default(false).description('强制下载作者头像'),
115
122
  forceDownloadVideo: koishi_1.Schema.boolean().default(false).description('强制下载视频'),
116
123
  }).description('媒体发送'),
117
124
  koishi_1.Schema.object({
@@ -623,17 +630,6 @@ function parseApiResponse(raw, maxDescLen, fieldMapping) {
623
630
  const author_followers = parseCount(mapField('author_followers', () => extra.author_extra?.follower_count ?? data.author_extra?.follower_count ?? 0));
624
631
  const author_signature = String(mapField('author_signature', () => extra.author_extra?.signature ?? data.author_extra?.signature ?? ''));
625
632
  const admire = parseCount(mapField('admire', () => extra.statistics?.admire_count ?? data.statistics?.admire_count ?? 0));
626
- let hashtags = '';
627
- const tagsArray = mapField('hashtags', () => extra.hashtags ?? data.hashtags);
628
- if (Array.isArray(tagsArray) && tagsArray.length > 0) {
629
- const tagNames = tagsArray.map((t) => t?.name ? t.name : '').filter(Boolean);
630
- hashtags = tagNames.map(name => `#${name}`).join(' ');
631
- if (tagNames.length > 0 && desc) {
632
- const escapedTags = tagNames.map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
633
- const tagRegex = new RegExp(`[##](${escapedTags.join('|')})\\b`, 'gi');
634
- desc = desc.replace(tagRegex, '').replace(/\s{2,}/g, ' ').trim();
635
- }
636
- }
637
633
  title = title.replace(/\[话题\]/g, '');
638
634
  desc = desc.replace(/\[话题\]/g, '');
639
635
  if (title && desc && title.trim() === desc.trim()) {
@@ -643,7 +639,7 @@ function parseApiResponse(raw, maxDescLen, fieldMapping) {
643
639
  title = '';
644
640
  if (desc.trim().startsWith('#'))
645
641
  desc = '';
646
- return { type, title, desc, author, uid, avatar, cover, video, videos, images, live_photo, music, like, comment, collect, share, play, duration, publishTime, author_followers, author_signature, admire, hashtags };
642
+ return { type, title, desc, author, uid, avatar, cover, video, videos, images, live_photo, music, like, comment, collect, share, play, duration, publishTime, author_followers, author_signature, admire };
647
643
  }
648
644
  const formatVarRegex = /\$\{([^}]+)\}/g;
649
645
  function generateFormattedText(p, format) {
@@ -651,7 +647,6 @@ function generateFormattedText(p, format) {
651
647
  const vars = {
652
648
  '标题': p.title,
653
649
  '作者': p.author,
654
- '作者名称': p.author,
655
650
  'author-name': p.author,
656
651
  '简介': p.desc,
657
652
  '视频时长': p.duration > 0 ? formatDuration(p.duration) : '',
@@ -664,21 +659,10 @@ function generateFormattedText(p, format) {
664
659
  '图片数量': String(imageCount),
665
660
  '作者ID': p.uid,
666
661
  'author-id': p.uid,
667
- '视频链接': p.video,
668
662
  '音乐标题': p.music.title || '',
669
663
  'music-title': p.music.title || '',
670
664
  '音乐作者': p.music.author || '',
671
665
  'music-author': p.music.author || '',
672
- '音乐封面': p.music.cover || '',
673
- 'author-avatar': p.avatar,
674
- '作者粉丝数': String(p.author_followers),
675
- 'author-followers': String(p.author_followers),
676
- '作者签名': p.author_signature,
677
- 'author-signature': p.author_signature,
678
- '赞赏数': String(p.admire),
679
- 'admire-count': String(p.admire),
680
- '话题标签': p.hashtags,
681
- 'hashtags': p.hashtags,
682
666
  };
683
667
  const varReplacements = Object.entries(vars).map(([key, val]) => ({
684
668
  regex: new RegExp(`\\$\\{${key}\\}`, 'g'),
@@ -773,9 +757,14 @@ function apply(ctx, config) {
773
757
  const mediaDownloadTimeout = config.mediaDownloadTimeout ?? 120000;
774
758
  const maxMediaSize = config.maxMediaSize ?? 0;
775
759
  const downloadEngine = config.downloadEngine || 'internal';
776
- if (downloadEngine === 'aria2' && !ctx.aria2) {
760
+ const aria2Service = ctx.get('aria2');
761
+ const downloadsService = ctx.get('downloads');
762
+ if (downloadEngine === 'aria2' && !aria2Service) {
777
763
  logger.warn('选择了 aria2 下载引擎,但未检测到 koishi-plugin-aria2-plus 服务,将回退到内置下载');
778
764
  }
765
+ if (downloadEngine === 'downloads' && !downloadsService) {
766
+ logger.warn('选择了 downloads 下载引擎,但未检测到 koishi-plugin-downloads 服务,将回退到内置下载');
767
+ }
779
768
  function getPlatformConfig(type) {
780
769
  if (type.startsWith('custom_')) {
781
770
  const name = type.slice(7);
@@ -853,9 +842,9 @@ function apply(ctx, config) {
853
842
  }) || fileExts[0];
854
843
  const fileName = `${filePrefix}_${Date.now()}_${(0, crypto_1.randomBytes)(4).toString('hex')}.${ext}`;
855
844
  const filePath = path_1.default.resolve(cacheDir, fileName);
856
- if (downloadEngine === 'downloads' && ctx.downloads) {
845
+ if (downloadEngine === 'downloads' && downloadsService) {
857
846
  logger.info(`开始下载: ${url}`);
858
- const dest = await ctx.downloads.download(url, path_1.default.join(cacheDir, fileName), {
847
+ const dest = await downloadsService.download(url, path_1.default.join(cacheDir, fileName), {
859
848
  headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' },
860
849
  timeout
861
850
  });
@@ -868,9 +857,9 @@ function apply(ctx, config) {
868
857
  }
869
858
  return dest;
870
859
  }
871
- if (downloadEngine === 'aria2' && ctx.aria2) {
860
+ if (downloadEngine === 'aria2' && aria2Service) {
872
861
  try {
873
- const gid = await ctx.aria2.addUri([url], {
862
+ const gid = await aria2Service.addUri([url], {
874
863
  dir: cacheDir,
875
864
  out: fileName,
876
865
  split: 4,
@@ -887,10 +876,10 @@ function apply(ctx, config) {
887
876
  let lastProgressTime = 0;
888
877
  while (!completed) {
889
878
  if (Date.now() - startTime > timeout) {
890
- await ctx.aria2.remove(gid).catch(() => { });
879
+ await aria2Service.remove(gid).catch(() => { });
891
880
  throw new Error('aria2下载超时');
892
881
  }
893
- const status = await ctx.aria2.tellStatus(gid);
882
+ const status = await aria2Service.tellStatus(gid);
894
883
  if (status.status === 'complete') {
895
884
  completed = true;
896
885
  if (onProgress)
@@ -1107,6 +1096,11 @@ function apply(ctx, config) {
1107
1096
  const text = item.text;
1108
1097
  if (text && config.showImageText)
1109
1098
  forwardMessages.push(buildForwardNode(session, text, botName));
1099
+ if (config.showAuthorAvatar && p.avatar) {
1100
+ if (config.showAuthorAvatarText)
1101
+ forwardMessages.push(buildForwardNode(session, config.authorAvatarText || '作者头像:', botName));
1102
+ forwardMessages.push(buildForwardNode(session, koishi_1.h.image(p.avatar), botName));
1103
+ }
1110
1104
  if (p.cover && config.showCoverImage && p.type !== 'live_photo' && p.type !== 'image' && !(p.type === 'live' && (p.live_photo?.length || p.images?.length))) {
1111
1105
  forwardMessages.push(buildForwardNode(session, koishi_1.h.image(p.cover), botName));
1112
1106
  }
@@ -1145,12 +1139,18 @@ function apply(ctx, config) {
1145
1139
  await sendWithTimeout(session, text);
1146
1140
  await delay(300);
1147
1141
  }
1142
+ if (config.showAuthorAvatar && p.avatar) {
1143
+ if (config.showAuthorAvatarText)
1144
+ await sendWithTimeout(session, config.authorAvatarText || '作者头像:');
1145
+ await sendMedia(session, p.avatar, 'image', config.forceDownloadAuthorAvatar, config.showAuthorAvatarFile).catch(() => { });
1146
+ await delay(300);
1147
+ }
1148
1148
  if (p.cover && config.showCoverImage && p.type !== 'live_photo' && p.type !== 'image' && !(p.type === 'live' && (p.live_photo?.length || p.images?.length))) {
1149
- await sendMedia(session, p.cover, 'image', config.forceDownloadImage, config.showImageFile).catch(() => { });
1149
+ await sendMedia(session, p.cover, 'image', config.forceDownloadCover, config.showCoverFile).catch(() => { });
1150
1150
  await delay(300);
1151
1151
  }
1152
1152
  if (config.showMusicCover && p.music.cover) {
1153
- await sendMedia(session, p.music.cover, 'image', config.forceDownloadImage, config.showImageFile).catch(() => { });
1153
+ await sendMedia(session, p.music.cover, 'image', false, true).catch(() => { });
1154
1154
  await delay(300);
1155
1155
  }
1156
1156
  if (p.video && (p.type === 'video' || (p.type === 'live' && !p.live_photo?.length && !p.images?.length))) {
@@ -1160,7 +1160,7 @@ function apply(ctx, config) {
1160
1160
  if (p.type === 'image' || p.type === 'live_photo' || (p.type === 'live' && (p.live_photo?.length || p.images?.length))) {
1161
1161
  const imageUrls = p.images?.length ? p.images : (p.live_photo?.map(lp => lp.image) ?? []);
1162
1162
  for (const imgUrl of imageUrls) {
1163
- await sendMedia(session, imgUrl, 'image', config.forceDownloadImage, config.showImageFile).catch(() => { });
1163
+ await sendMedia(session, imgUrl, 'image', config.forceDownloadImageNew, config.showImageFileNew).catch(() => { });
1164
1164
  await delay(200);
1165
1165
  }
1166
1166
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-video-parser-all",
3
3
  "description": "Koishi 全平台视频/图集解析插件,支持抖音/快手/B站/微博/小红书/剪映/YouTube/TikTok等20+平台",
4
- "version": "1.4.8",
4
+ "version": "1.4.9",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
package/readme.md CHANGED
@@ -39,11 +39,20 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
39
39
  |--------|------|--------|------|
40
40
  | `showImageText` | boolean | true | 发送文字内容 |
41
41
  | `showCoverImage` | boolean | true | 发送封面图片 |
42
- | `showMusicCover` | boolean | true | 发送音乐封面 |
43
- | `showImageFile` | boolean | true | 封面/图片是否以图片形式发送(关闭则只发送链接) |
42
+ | `showCoverFile` | boolean | true | 封面是否以图片形式发送(关闭则只发送链接) |
43
+ | `showImageFileNew` | boolean | true | 图片是否以图片形式发送(关闭则只发送链接) |
44
+ | `showAuthorAvatar` | boolean | true | 发送作者头像图片 |
45
+ | `showAuthorAvatarFile` | boolean | true | 作者头像图片是否以图片形式发送(关闭则只发送链接) |
46
+ | `showMusicCover` | boolean | true | 发送音乐封面图片 |
44
47
  | `showVideoFile` | boolean | true | 视频是否以视频形式发送(关闭则只发送链接) |
45
- | `forceDownloadImage` | boolean | false | 强制下载封面/图片 |
48
+ | `forceDownloadCover` | boolean | false | 强制下载封面 |
49
+ | `forceDownloadImageNew` | boolean | false | 强制下载图片 |
50
+ | `forceDownloadAuthorAvatar` | boolean | false | 强制下载作者头像 |
46
51
  | `forceDownloadVideo` | boolean | false | 强制下载视频 |
52
+ | `forceDownloadAuthorAvatar` | boolean | false | 强制下载作者头像 |
53
+ | `forceDownloadVideo` | boolean | false | 强制下载视频 |
54
+ | `showAuthorAvatarText` | boolean | true | 发送作者头像前显示文字提示 |
55
+ | `authorAvatarText` | string | 作者头像: | 作者头像前显示的文字 |
47
56
 
48
57
  ### 音乐语音(需 silk 和 ffmpeg)
49
58
  | 配置项 | 类型 | 默认值 | 说明 |
@@ -109,7 +118,7 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
109
118
  | 变量名 | 说明 |
110
119
  |--------|------|
111
120
  | `${标题}` | 视频/图集标题 |
112
- | `${作者}` | 作者名称 |
121
+ | `${作者}` 或 `${author-name}` | 作者名称 |
113
122
  | `${简介}` | 内容简介 |
114
123
  | `${视频时长}` | 视频时长(时:分:秒) |
115
124
  | `${点赞数}` | 点赞数量 |
@@ -119,10 +128,9 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
119
128
  | `${评论数}` | 评论数量 |
120
129
  | `${发布时间}` | 发布时间(格式化) |
121
130
  | `${图片数量}` | 图集/实况图片数量 |
122
- | `${作者ID}` | 作者唯一标识ID |
123
- | `${视频链接}` | 视频原始链接 |
124
- | `${音乐标题}` | 音乐标题 |
125
- | `${音乐作者}` | 音乐作者 |
131
+ | `${作者ID}` 或 `${author-id}` | 作者唯一标识ID |
132
+ | `${音乐标题}` 或 `${music-title}` | 音乐标题 |
133
+ | `${音乐作者}` 或 `${music-author}` | 音乐作者 |
126
134
 
127
135
  ## 依赖说明 (Dependencies)
128
136
  ### 音乐语音(可选)
@@ -166,7 +174,7 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
166
174
  | 皮皮搞笑 | `h5.pipigx.com/pp/post/`, `ippzone.com` | 短视频 |
167
175
  | 皮皮虾 | `pipix.com`, `pipixia.com` | 短视频 |
168
176
  | 最右 | `share.xiaochuankeji.cn/hybrid/share/post`, `izuiyou.com` | 短视频 |
169
- | 🔧 自定义平台 | 通过 `customPlatforms` 配置添加 | 取决于提供的 API |
177
+ | 自定义平台 | 通过 `customPlatforms` 配置添加 | 取决于提供的 API |
170
178
 
171
179
  ## 项目贡献者 (Contributors)
172
180
 
@@ -179,6 +187,7 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
179
187
  | dzt2008 + Apricityx | 提交Bug-会对非支持视频平台URL进行误解析-已修复 |
180
188
  | JH-Ahua | BugPk-Api 支持 |
181
189
  | shangxue | 灵感来源 |
190
+ | linyves | 提交Bug-小红书图集重复发送封面-已修复<br>提交Bug-话题显示异常 #**[话题]#-已修复<br>提交建议-Live Photo 全部按普通图片处理-已采纳<br>提交Bug-解析后会把作者头像一起发送-已修复 |
182
191
 
183
192
  (欢迎通过 Issues 或 PR 加入贡献者列表)
184
193