koishi-plugin-video-parser-all 1.5.1 → 1.5.3

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
@@ -38,6 +38,8 @@ export declare const Config: Schema<{
38
38
  showImageText?: boolean | null | undefined;
39
39
  showCoverImage?: boolean | null | undefined;
40
40
  showCoverFile?: boolean | null | undefined;
41
+ showCoverText?: boolean | null | undefined;
42
+ coverText?: string | null | undefined;
41
43
  showImageFileNew?: boolean | null | undefined;
42
44
  showAuthorAvatar?: boolean | null | undefined;
43
45
  showAuthorAvatarFile?: boolean | null | undefined;
@@ -45,6 +47,7 @@ export declare const Config: Schema<{
45
47
  authorAvatarText?: string | null | undefined;
46
48
  showMusicCover?: boolean | null | undefined;
47
49
  showVideoFile?: boolean | null | undefined;
50
+ sendLiveMessage?: boolean | null | undefined;
48
51
  forceDownloadCover?: boolean | null | undefined;
49
52
  forceDownloadImageNew?: boolean | null | undefined;
50
53
  forceDownloadAuthorAvatar?: boolean | null | undefined;
@@ -190,6 +193,8 @@ export declare const Config: Schema<{
190
193
  showImageText: boolean;
191
194
  showCoverImage: boolean;
192
195
  showCoverFile: boolean;
196
+ showCoverText: boolean;
197
+ coverText: string;
193
198
  showImageFileNew: boolean;
194
199
  showAuthorAvatar: boolean;
195
200
  showAuthorAvatarFile: boolean;
@@ -197,6 +202,7 @@ export declare const Config: Schema<{
197
202
  authorAvatarText: string;
198
203
  showMusicCover: boolean;
199
204
  showVideoFile: boolean;
205
+ sendLiveMessage: boolean;
200
206
  forceDownloadCover: boolean;
201
207
  forceDownloadImageNew: boolean;
202
208
  forceDownloadAuthorAvatar: boolean;
package/lib/index.js CHANGED
@@ -72,7 +72,7 @@ exports.Config = koishi_1.Schema.intersect([
72
72
  koishi_1.Schema.object({
73
73
  enable: koishi_1.Schema.boolean().default(true).description('是否启用视频解析插件'),
74
74
  botName: koishi_1.Schema.string().default('视频解析机器人').description('合并转发中显示的昵称'),
75
- showWaitingTip: koishi_1.Schema.boolean().default(true).description('解析时显示等待提示'),
75
+ showWaitingTip: koishi_1.Schema.boolean().default(true).description('显示等待提示'),
76
76
  debug: koishi_1.Schema.boolean().default(false).description('开启调试日志'),
77
77
  platformEnabled: koishi_1.Schema.object({
78
78
  bilibili: koishi_1.Schema.boolean().default(true).description('哔哩哔哩'),
@@ -109,13 +109,16 @@ exports.Config = koishi_1.Schema.intersect([
109
109
  showImageText: koishi_1.Schema.boolean().default(true).description('发送文字内容'),
110
110
  showCoverImage: koishi_1.Schema.boolean().default(true).description('发送封面图片'),
111
111
  showCoverFile: koishi_1.Schema.boolean().default(true).description('封面是否以图片形式发送(关闭则只发送链接)'),
112
+ showCoverText: koishi_1.Schema.boolean().default(true).description('发送封面前显示文字提示'),
113
+ coverText: koishi_1.Schema.string().default('封面:').description('封面前显示的文字'),
112
114
  showImageFileNew: koishi_1.Schema.boolean().default(true).description('图片是否以图片形式发送(关闭则只发送链接)'),
113
115
  showAuthorAvatar: koishi_1.Schema.boolean().default(true).description('发送作者头像图片'),
114
116
  showAuthorAvatarFile: koishi_1.Schema.boolean().default(true).description('作者头像图片是否以图片形式发送(关闭则只发送链接)'),
115
- showAuthorAvatarText: koishi_1.Schema.boolean().default(true).description('发送作者头像前显示文字提示'),
117
+ showAuthorAvatarText: koishi_1.Schema.boolean().default(true).description('作者头像前显示文字提示(将追加到文字消息末尾)'),
116
118
  authorAvatarText: koishi_1.Schema.string().default('作者头像:').description('作者头像前显示的文字'),
117
119
  showMusicCover: koishi_1.Schema.boolean().default(true).description('发送音乐封面图片'),
118
120
  showVideoFile: koishi_1.Schema.boolean().default(true).description('视频是否以视频形式发送(关闭则只发送链接)'),
121
+ sendLiveMessage: koishi_1.Schema.boolean().default(true).description('直播作品发送文字消息(不发送视频)'),
119
122
  forceDownloadCover: koishi_1.Schema.boolean().default(false).description('强制下载封面'),
120
123
  forceDownloadImageNew: koishi_1.Schema.boolean().default(false).description('强制下载图片'),
121
124
  forceDownloadAuthorAvatar: koishi_1.Schema.boolean().default(false).description('强制下载作者头像'),
@@ -135,7 +138,7 @@ exports.Config = koishi_1.Schema.intersect([
135
138
  downloadEngine: koishi_1.Schema.union([
136
139
  koishi_1.Schema.const('internal').description('内置下载'),
137
140
  koishi_1.Schema.const('aria2').description('aria2 下载(需 koishi-plugin-aria2-plus)'),
138
- koishi_1.Schema.const('downloads').description('downloads 服务下载(需 koishi-plugin-downloads)'),
141
+ koishi_1.Schema.const('downloads').description('downloads 服务下载'),
139
142
  ]).default('internal').description('下载引擎'),
140
143
  }).description('性能与限制'),
141
144
  koishi_1.Schema.object({
@@ -437,8 +440,9 @@ function cleanUrl(url) {
437
440
  try {
438
441
  url = url.replace(/&amp;/g, '&');
439
442
  const urlObj = new URL(url);
440
- if (urlObj.protocol === 'http:')
441
- urlObj.protocol = 'https:';
443
+ if (urlObj.protocol !== 'http:' && urlObj.protocol !== 'https:') {
444
+ throw new Error('非法的协议');
445
+ }
442
446
  if (urlObj.hostname.includes('douyin.com') || urlObj.hostname.includes('v.douyin.com')) {
443
447
  ['source', 'share_type', 'share_token', 'timestamp', 'from', 'isappinstalled'].forEach(p => urlObj.searchParams.delete(p));
444
448
  return urlObj.origin + urlObj.pathname;
@@ -838,23 +842,32 @@ function apply(ctx, config) {
838
842
  }) || fileExts[0];
839
843
  const fileName = `${filePrefix}_${Date.now()}_${(0, crypto_1.randomBytes)(4).toString('hex')}.${ext}`;
840
844
  const filePath = path_1.default.resolve(cacheDir, fileName);
845
+ const startTime = Date.now();
841
846
  if (downloadEngine === 'downloads' && downloadsService) {
842
- logger.info(`开始下载: ${url}`);
843
- const dest = await downloadsService.download(url, path_1.default.join(cacheDir, fileName), {
844
- headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' },
845
- timeout
846
- });
847
- const stat = await promises_1.default.stat(dest);
848
- const sizeMB = (stat.size / (1024 * 1024)).toFixed(2);
849
- logger.info(`下载完成: ${dest} (${sizeMB} MB)`);
850
- if (maxSize > 0 && stat.size > maxSize * 1024 * 1024) {
851
- await promises_1.default.unlink(dest).catch(() => { });
852
- throw new Error(`文件过大(${Math.round(stat.size / 1024 / 1024)}MB),超过限制(${maxSize}MB)`);
847
+ logger.info(`[下载] 开始 (downloads): ${url}`);
848
+ try {
849
+ const dest = await downloadsService.download(url, path_1.default.join(cacheDir, fileName), {
850
+ headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' },
851
+ timeout
852
+ });
853
+ const stat = await promises_1.default.stat(dest);
854
+ const sizeMB = (stat.size / (1024 * 1024)).toFixed(2);
855
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
856
+ logger.info(`[下载] 完成 (downloads): ${dest} (${sizeMB} MB, 耗时 ${elapsed}s)`);
857
+ if (maxSize > 0 && stat.size > maxSize * 1024 * 1024) {
858
+ await promises_1.default.unlink(dest).catch(() => { });
859
+ throw new Error(`文件过大(${Math.round(stat.size / 1024 / 1024)}MB),超过限制(${maxSize}MB)`);
860
+ }
861
+ return dest;
862
+ }
863
+ catch (e) {
864
+ debugLog('ERROR', 'downloads 下载失败,回退内置下载:', e);
865
+ throw e;
853
866
  }
854
- return dest;
855
867
  }
856
868
  if (downloadEngine === 'aria2' && aria2Service) {
857
869
  try {
870
+ logger.info(`[下载] 开始 (aria2): ${url}`);
858
871
  const gid = await aria2Service.addUri([url], {
859
872
  dir: cacheDir,
860
873
  out: fileName,
@@ -868,10 +881,10 @@ function apply(ctx, config) {
868
881
  header: [`User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36`, `Referer: https://www.baidu.com/`]
869
882
  });
870
883
  let completed = false;
871
- const startTime = Date.now();
884
+ const ariaStart = Date.now();
872
885
  let lastProgressTime = 0;
873
886
  while (!completed) {
874
- if (Date.now() - startTime > timeout) {
887
+ if (Date.now() - ariaStart > timeout) {
875
888
  await aria2Service.remove(gid).catch(() => { });
876
889
  throw new Error('aria2下载超时');
877
890
  }
@@ -897,6 +910,9 @@ function apply(ctx, config) {
897
910
  }
898
911
  }
899
912
  const stat = await promises_1.default.stat(filePath);
913
+ const sizeMB = (stat.size / (1024 * 1024)).toFixed(2);
914
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
915
+ logger.info(`[下载] 完成 (aria2): ${filePath} (${sizeMB} MB, 耗时 ${elapsed}s)`);
900
916
  if (maxSize > 0 && stat.size > maxSize * 1024 * 1024) {
901
917
  await promises_1.default.unlink(filePath).catch(() => { });
902
918
  throw new Error(`文件过大(${Math.round(stat.size / 1024 / 1024)}MB),超过限制(${maxSize}MB)`);
@@ -907,6 +923,10 @@ function apply(ctx, config) {
907
923
  debugLog('ERROR', `aria2下载失败,回退内置下载: ${getErrorMessage(e)}`);
908
924
  }
909
925
  }
926
+ const urlObj = new URL(url);
927
+ if (urlObj.protocol !== 'http:' && urlObj.protocol !== 'https:') {
928
+ throw new Error('不支持的下载协议:' + urlObj.protocol);
929
+ }
910
930
  const writer = (0, fs_1.createWriteStream)(filePath);
911
931
  let response;
912
932
  try {
@@ -932,6 +952,8 @@ function apply(ctx, config) {
932
952
  await promises_1.default.unlink(filePath).catch(() => { });
933
953
  throw new Error(`文件过大(${Math.round(contentLength / 1024 / 1024)}MB),超过限制(${maxSize}MB)`);
934
954
  }
955
+ const sizeStr = contentLength > 0 ? `${(contentLength / (1024 * 1024)).toFixed(2)}MB` : '未知大小';
956
+ logger.info(`[下载] 开始 (内置): ${url} (${sizeStr})`);
935
957
  let downloaded = 0;
936
958
  let lastProgressTime = 0;
937
959
  response.data.on('data', (chunk) => {
@@ -940,22 +962,27 @@ function apply(ctx, config) {
940
962
  lastProgressTime = Date.now();
941
963
  if (contentLength > 0) {
942
964
  const percent = Math.round((downloaded / contentLength) * 100);
943
- onProgress(percent, '');
965
+ const mb = (downloaded / (1024 * 1024)).toFixed(2);
966
+ const totalMB = (contentLength / (1024 * 1024)).toFixed(2);
967
+ onProgress(percent, `${mb}/${totalMB}MB`);
944
968
  }
945
969
  else {
946
- onProgress(-1, formatSpeed(downloaded / ((Date.now() - lastProgressTime) / 1000)));
970
+ const mb = (downloaded / (1024 * 1024)).toFixed(2);
971
+ onProgress(-1, `已下载 ${mb} MB`);
947
972
  }
948
973
  }
949
974
  });
950
975
  try {
951
976
  await (0, promises_2.pipeline)(response.data, writer);
977
+ const stat = await promises_1.default.stat(filePath);
978
+ const sizeMB = (stat.size / (1024 * 1024)).toFixed(2);
979
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
980
+ logger.info(`[下载] 完成 (内置): ${filePath} (${sizeMB} MB, 耗时 ${elapsed}s)`);
952
981
  if (onProgress) {
953
- if (contentLength > 0) {
954
- onProgress(100, '');
955
- }
956
- else {
957
- onProgress(-1, formatSpeed(downloaded / ((Date.now() - lastProgressTime) / 1000)));
958
- }
982
+ if (contentLength > 0)
983
+ onProgress(100, `${sizeMB}MB`);
984
+ else
985
+ onProgress(-1, `完成,共 ${sizeMB} MB`);
959
986
  }
960
987
  return filePath;
961
988
  }
@@ -989,15 +1016,15 @@ function apply(ctx, config) {
989
1016
  };
990
1017
  const prefixMap = { image: 'img', video: 'video', audio: 'music' };
991
1018
  const sendFunc = type === 'audio' ? koishi_1.h.audio : type === 'video' ? koishi_1.h.video : koishi_1.h.image;
992
- const onProgress = forceDownload ? (percent, speed) => {
1019
+ const onProgress = (percent, info) => {
993
1020
  if (percent === -1) {
994
- logger.info(`下载进度: 已下载 ${speed}`);
1021
+ logger.info(`[下载] ${info}`);
995
1022
  }
996
1023
  else {
997
- const text = `下载进度: ${percent}%` + (speed ? ` (${speed})` : '');
1024
+ const text = `[下载] ${percent}%` + (info ? ` (${info})` : '');
998
1025
  logger.info(text);
999
1026
  }
1000
- } : undefined;
1027
+ };
1001
1028
  if (forceDownload) {
1002
1029
  try {
1003
1030
  const localPath = await downloadFile(url, mediaDownloadTimeout, maxMediaSize, prefixMap[type], extMap[type], onProgress);
@@ -1029,7 +1056,7 @@ function apply(ctx, config) {
1029
1056
  }
1030
1057
  catch {
1031
1058
  try {
1032
- const localPath = await downloadFile(url, mediaDownloadTimeout, maxMediaSize, prefixMap[type], extMap[type]);
1059
+ const localPath = await downloadFile(url, mediaDownloadTimeout, maxMediaSize, prefixMap[type], extMap[type], onProgress);
1033
1060
  try {
1034
1061
  await sendWithTimeout(session, sendFunc(`file://${localPath}`));
1035
1062
  }
@@ -1105,16 +1132,18 @@ function apply(ctx, config) {
1105
1132
  const forwardMessages = [];
1106
1133
  for (const item of items) {
1107
1134
  const p = item.parsed;
1108
- const text = item.text;
1109
- if (text && config.showImageText)
1110
- forwardMessages.push(buildForwardNode(session, text, botName));
1135
+ let text = item.text;
1111
1136
  if (config.showAuthorAvatar && p.avatar && config.showAuthorAvatarText) {
1112
- forwardMessages.push(buildForwardNode(session, config.authorAvatarText || '作者头像:', botName));
1137
+ text = text ? text + '\n' + (config.authorAvatarText || '作者头像:') : (config.authorAvatarText || '作者头像:');
1113
1138
  }
1139
+ if (text && config.showImageText)
1140
+ forwardMessages.push(buildForwardNode(session, text, botName));
1114
1141
  if (config.showAuthorAvatar && p.avatar) {
1115
1142
  forwardMessages.push(buildForwardNode(session, koishi_1.h.image(p.avatar), botName));
1116
1143
  }
1117
- if (p.cover && config.showCoverImage && p.type !== 'live_photo' && p.type !== 'image' && !(p.type === 'live' && (p.live_photo?.length || p.images?.length))) {
1144
+ if (p.cover && config.showCoverImage && p.type !== 'live_photo' && p.type !== 'image' && p.type !== 'live') {
1145
+ if (config.showCoverText)
1146
+ forwardMessages.push(buildForwardNode(session, config.coverText || '封面:', botName));
1118
1147
  forwardMessages.push(buildForwardNode(session, koishi_1.h.image(p.cover), botName));
1119
1148
  }
1120
1149
  if (config.showMusicCover && p.music.cover) {
@@ -1125,7 +1154,7 @@ function apply(ctx, config) {
1125
1154
  for (const imgUrl of imageUrls)
1126
1155
  forwardMessages.push(buildForwardNode(session, koishi_1.h.image(imgUrl), botName));
1127
1156
  }
1128
- if (p.video)
1157
+ if (p.video && p.type !== 'live')
1129
1158
  forwardMessages.push(buildForwardNode(session, koishi_1.h.video(p.video), botName));
1130
1159
  if (config.showMusicVoice && p.music.url) {
1131
1160
  forwardMessages.push(buildForwardNode(session, koishi_1.h.audio(p.music.url), botName));
@@ -1147,20 +1176,21 @@ function apply(ctx, config) {
1147
1176
  else {
1148
1177
  for (const item of items) {
1149
1178
  const p = item.parsed;
1150
- const text = item.text;
1179
+ let text = item.text;
1180
+ if (config.showAuthorAvatar && p.avatar && config.showAuthorAvatarText) {
1181
+ text = text ? text + '\n' + (config.authorAvatarText || '作者头像:') : (config.authorAvatarText || '作者头像:');
1182
+ }
1151
1183
  if (text && config.showImageText) {
1152
1184
  await sendWithTimeout(session, text);
1153
1185
  await delay(300);
1154
1186
  }
1155
- if (config.showAuthorAvatar && p.avatar && config.showAuthorAvatarText) {
1156
- await sendWithTimeout(session, config.authorAvatarText || '作者头像:');
1157
- await delay(300);
1158
- }
1159
1187
  if (config.showAuthorAvatar && p.avatar) {
1160
1188
  await sendMedia(session, p.avatar, 'image', config.forceDownloadAuthorAvatar, config.showAuthorAvatarFile).catch(() => { });
1161
1189
  await delay(300);
1162
1190
  }
1163
- if (p.cover && config.showCoverImage && p.type !== 'live_photo' && p.type !== 'image' && !(p.type === 'live' && (p.live_photo?.length || p.images?.length))) {
1191
+ if (p.cover && config.showCoverImage && p.type !== 'live_photo' && p.type !== 'image' && p.type !== 'live') {
1192
+ if (config.showCoverText)
1193
+ await sendWithTimeout(session, config.coverText || '封面:');
1164
1194
  await sendMedia(session, p.cover, 'image', config.forceDownloadCover, config.showCoverFile).catch(() => { });
1165
1195
  await delay(300);
1166
1196
  }
@@ -1168,17 +1198,21 @@ function apply(ctx, config) {
1168
1198
  await sendMedia(session, p.music.cover, 'image', false, true).catch(() => { });
1169
1199
  await delay(300);
1170
1200
  }
1171
- if (p.video && (p.type === 'video' || (p.type === 'live' && !p.live_photo?.length && !p.images?.length))) {
1201
+ if (p.video && p.type !== 'live') {
1172
1202
  await sendMedia(session, p.video, 'video', config.forceDownloadVideo, config.showVideoFile).catch(() => { });
1173
1203
  await delay(500);
1174
1204
  }
1175
1205
  if (p.type === 'image' || p.type === 'live_photo' || (p.type === 'live' && (p.live_photo?.length || p.images?.length))) {
1176
1206
  const imageUrls = p.images?.length ? p.images : (p.live_photo?.map(lp => lp.image) ?? []);
1177
- for (const imgUrl of imageUrls) {
1178
- await sendMedia(session, imgUrl, 'image', config.forceDownloadImageNew, config.showImageFileNew).catch(() => { });
1179
- await delay(200);
1207
+ for (let i = 0; i < imageUrls.length; i++) {
1208
+ logger.info(`[发送] 图片 ${i + 1}/${imageUrls.length}`);
1209
+ await sendMedia(session, imageUrls[i], 'image', config.forceDownloadImageNew, config.showImageFileNew).catch(() => { });
1210
+ await delay(1000);
1180
1211
  }
1181
1212
  }
1213
+ if (p.type === 'live' && config.sendLiveMessage) {
1214
+ await sendWithTimeout(session, '直播进行中,无法发送视频流。').catch(() => { });
1215
+ }
1182
1216
  if (config.showMusicVoice && p.music.url) {
1183
1217
  await sendMedia(session, p.music.url, 'audio', config.forceDownloadMusicVoice, config.showMusicVoiceFile).catch(() => { });
1184
1218
  await delay(300);
@@ -1413,21 +1447,23 @@ function apply(ctx, config) {
1413
1447
  dedupCache.clear();
1414
1448
  debugLog('INFO', '插件已卸载');
1415
1449
  });
1416
- process.on('beforeExit', async () => {
1417
- try {
1418
- const files = await promises_1.default.readdir(cacheDir);
1419
- for (const file of files) {
1420
- if ((file.startsWith('video_') && file.endsWith('.mp4')) ||
1421
- (file.startsWith('img_') && file.match(/\.(png|jpg|jpeg|gif|webp)$/i)) ||
1422
- (file.startsWith('music_') && file.match(/\.(mp3|wav|ogg|flac|aac|m4a)$/i))) {
1423
- await promises_1.default.unlink(path_1.default.join(cacheDir, file)).catch(() => { });
1450
+ if (!process.listenerCount('beforeExit')) {
1451
+ process.once('beforeExit', async () => {
1452
+ try {
1453
+ const files = await promises_1.default.readdir(cacheDir);
1454
+ for (const file of files) {
1455
+ if ((file.startsWith('video_') && file.endsWith('.mp4')) ||
1456
+ (file.startsWith('img_') && file.match(/\.(png|jpg|jpeg|gif|webp)$/i)) ||
1457
+ (file.startsWith('music_') && file.match(/\.(mp3|wav|ogg|flac|aac|m4a)$/i))) {
1458
+ await promises_1.default.unlink(path_1.default.join(cacheDir, file)).catch(() => { });
1459
+ }
1424
1460
  }
1425
1461
  }
1426
- }
1427
- catch (e) {
1428
- if (e?.code !== 'ENOENT')
1429
- debugLog('WARN', '退出清理临时文件失败:', e);
1430
- }
1431
- });
1462
+ catch (e) {
1463
+ if (e?.code !== 'ENOENT')
1464
+ debugLog('WARN', '退出清理临时文件失败:', e);
1465
+ }
1466
+ });
1467
+ }
1432
1468
  debugLog('INFO', '插件初始化完成');
1433
1469
  }
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.5.1",
4
+ "version": "1.5.3",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
package/readme.md CHANGED
@@ -40,13 +40,16 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
40
40
  | `showImageText` | boolean | true | 发送文字内容 (Send text content) |
41
41
  | `showCoverImage` | boolean | true | 发送封面图片 (Send cover image) |
42
42
  | `showCoverFile` | boolean | true | 封面是否以图片形式发送(关闭则只发送链接)(Send cover as image, otherwise link only) |
43
+ | `showCoverText` | boolean | true | 发送封面前显示文字提示 (Show text hint before cover image) |
44
+ | `coverText` | string | 封面: | 封面前显示的文字 (Text displayed before cover) |
43
45
  | `showImageFileNew` | boolean | true | 图片是否以图片形式发送(关闭则只发送链接)(Send images as image, otherwise link only) |
44
46
  | `showAuthorAvatar` | boolean | true | 发送作者头像图片 (Send author avatar image) |
45
47
  | `showAuthorAvatarFile` | boolean | true | 作者头像图片是否以图片形式发送(关闭则只发送链接)(Send author avatar as image, otherwise link only) |
46
- | `showAuthorAvatarText` | boolean | true | 发送作者头像前显示文字提示 (Show text hint before author avatar) |
48
+ | `showAuthorAvatarText` | boolean | true | 作者头像前显示文字提示(将追加到文字消息末尾)(Show text hint before author avatar, appended to the text message) |
47
49
  | `authorAvatarText` | string | 作者头像: | 作者头像前显示的文字 (Text displayed before author avatar) |
48
50
  | `showMusicCover` | boolean | true | 发送音乐封面图片 (Send music cover image) |
49
51
  | `showVideoFile` | boolean | true | 视频是否以视频形式发送(关闭则只发送链接)(Send video as file, otherwise link only) |
52
+ | `sendLiveMessage` | boolean | true | 直播作品发送文字消息(不发送视频)(Send text message for live streams, no video) |
50
53
  | `forceDownloadCover` | boolean | false | 强制下载封面 (Force download cover) |
51
54
  | `forceDownloadImageNew` | boolean | false | 强制下载图片 (Force download images) |
52
55
  | `forceDownloadAuthorAvatar` | boolean | false | 强制下载作者头像 (Force download author avatar) |