koishi-plugin-video-parser-all 1.5.7 → 1.5.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 (2) hide show
  1. package/lib/index.js +126 -111
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -283,68 +283,76 @@ let debugEnabled = false;
283
283
  function debugLog(level, ...args) {
284
284
  if (!debugEnabled)
285
285
  return;
286
- logger.info(`[${new Date().toISOString()}] [${level}] ${args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)).join(' ')}`);
286
+ const safe = args.map(a => {
287
+ try {
288
+ return typeof a === 'object' ? JSON.stringify(a) : String(a);
289
+ }
290
+ catch {
291
+ return '[unserializable]';
292
+ }
293
+ });
294
+ logger.info(`[${new Date().toISOString()}] [${level}] ${safe.join(' ')}`);
287
295
  }
288
296
  const BUILTIN_LINK_RULES = [
289
- { pattern: /https?:\/\/(?:www\.)?bilibili\.com\/video\/([ab]v[0-9a-zA-Z_-]+)[^\s]*/gi, type: 'bilibili' },
290
- { pattern: /https?:\/\/b23\.tv\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'bilibili' },
291
- { pattern: /https?:\/\/bili\d+\.cn\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'bilibili' },
292
- { pattern: /https?:\/\/b23\.wtf\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'bilibili' },
293
- { pattern: /https?:\/\/bili2233\.cn\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'bilibili' },
294
- { pattern: /https?:\/\/(?:www\.)?douyin\.com\/video\/\d{10,}[^\s]*/gi, type: 'douyin' },
295
- { pattern: /https?:\/\/v\.douyin\.com\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'douyin' },
296
- { pattern: /https?:\/\/(?:www\.)?kuaishou\.com\/short-video\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'kuaishou' },
297
- { pattern: /https?:\/\/v\.kuaishou\.com\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'kuaishou' },
298
- { pattern: /https?:\/\/(?:www\.)?kuaishou\.com\/f\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'kuaishou' },
299
- { pattern: /https?:\/\/(?:www\.)?xiaohongshu\.com\/discovery\/item\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'xiaohongshu' },
300
- { pattern: /https?:\/\/xhslink\.com\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'xiaohongshu' },
301
- { pattern: /https?:\/\/(?:www\.)?xiaohongshu\.com\/explore\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'xiaohongshu' },
302
- { pattern: /https?:\/\/(?:www\.)?xiaohongshu\.com\/board\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'xiaohongshu' },
303
- { pattern: /https?:\/\/weibo\.com\/\d+\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'weibo' },
304
- { pattern: /https?:\/\/video\.weibo\.com\/show\?fid=[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'weibo' },
305
- { pattern: /https?:\/\/t\.cn\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'weibo' },
306
- { pattern: /https?:\/\/m\.weibo\.cn\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'weibo' },
307
- { pattern: /https?:\/\/(?:www\.)?ixigua\.com\/\d{10,}[^\s]*/gi, type: 'xigua' },
308
- { pattern: /https?:\/\/(?:www\.)?youtube\.com\/watch\?v=[a-zA-Z0-9_-]{11}[^\s]*/gi, type: 'youtube' },
309
- { pattern: /https?:\/\/youtu\.be\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'youtube' },
310
- { pattern: /https?:\/\/(?:www\.)?youtube\.com\/shorts\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'youtube' },
311
- { pattern: /https?:\/\/(?:www\.)?tiktok\.com\/@[\w.]+\/video\/\d{10,}[^\s]*/gi, type: 'tiktok' },
312
- { pattern: /https?:\/\/vm\.tiktok\.com\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'tiktok' },
313
- { pattern: /https?:\/\/vt\.tiktok\.com\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'tiktok' },
314
- { pattern: /https?:\/\/(?:www\.)?acfun\.cn\/v\/ac\d{10,}[^\s]*/gi, type: 'acfun' },
315
- { pattern: /https?:\/\/(?:www\.)?zhihu\.com\/video\/\d{10,}[^\s]*/gi, type: 'zhihu' },
316
- { pattern: /https?:\/\/(?:www\.|m\.)?zhihu\.com\/question\/\d+\/answer\/\d+[^\s]*/gi, type: 'zhihu' },
317
- { pattern: /https?:\/\/zhuanlan\.zhihu\.com\/p\/\d+[^\s]*/gi, type: 'zhihu' },
318
- { pattern: /https?:\/\/(?:www\.|m\.)?zhihu\.com\/zvideo\/\d+[^\s]*/gi, type: 'zhihu' },
319
- { pattern: /https?:\/\/weishi\.qq\.com\/weishi\/feed\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'weishi' },
320
- { pattern: /https?:\/\/(?:www\.)?huya\.com\/video\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'huya' },
321
- { pattern: /https?:\/\/haokan\.baidu\.com\/v\?vid=[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'haokan' },
322
- { pattern: /https?:\/\/(?:www\.)?meipai\.com\/media\/\d{10,}[^\s]*/gi, type: 'meipai' },
323
- { pattern: /https?:\/\/twitter\.com\/\w+\/status\/\d{10,}[^\s]*/gi, type: 'twitter' },
324
- { pattern: /https?:\/\/x\.com\/\w+\/status\/\d{10,}[^\s]*/gi, type: 'twitter' },
325
- { pattern: /https?:\/\/(?:www\.)?instagram\.com\/p\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'instagram' },
326
- { pattern: /https?:\/\/(?:www\.)?instagram\.com\/reel\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'instagram' },
327
- { pattern: /https?:\/\/(?:www\.)?instagram\.com\/share\/(?:reel|p)\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'instagram' },
328
- { pattern: /https?:\/\/(?:www\.)?doubao\.com\/video\/\d{10,}[^\s]*/gi, type: 'doubao' },
329
- { pattern: /https?:\/\/(?:www\.)?doubao\.com\/video-sharing\?[^\s]*/gi, type: 'doubao' },
330
- { pattern: /https?:\/\/(?:www\.)?doubao\.com\/thread\/[^\s]+/gi, type: 'doubao_image' },
331
- { pattern: /https?:\/\/(?:www\.)?jimeng\.jianying\.com\/[^\s]*/gi, type: 'jimeng' },
332
- { pattern: /https?:\/\/(?:www\.)?jimeng\.cn\/[^\s]*/gi, type: 'jimeng' },
333
- { pattern: /https?:\/\/(?:www\.)?dreamina\.jianying\.com\/[^\s]*/gi, type: 'jimeng' },
334
- { pattern: /https?:\/\/(?:www\.)?dreamina\.capcut\.com\/[^\s]*/gi, type: 'jimeng' },
335
- { pattern: /https?:\/\/(?:www\.)?oasis\.weibo\.com\/v\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'oasis' },
336
- { pattern: /https?:\/\/channels\.weixin\.qq\.com\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'wechat_channel' },
337
- { pattern: /https?:\/\/weixin\.qq\.com\/sph\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'wechat_channel' },
338
- { pattern: /https?:\/\/(?:www\.)?pearvideo\.com\/video_\d+[^\s]*/gi, type: 'lishi' },
339
- { pattern: /https?:\/\/video\.li\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'lishi' },
340
- { pattern: /https?:\/\/(?:www\.)?quanmin\.tv\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'quanmin' },
341
- { pattern: /https?:\/\/(?:www\.)?quanmintv\.cn\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'quanmin' },
342
- { pattern: /https?:\/\/h5\.pipigx\.com\/pp\/post\/\d+[^\s]*/gi, type: 'pipigx' },
343
- { pattern: /https?:\/\/(?:www\.)?ippzone\.com\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'pipigx' },
344
- { pattern: /https?:\/\/(?:h5|www)\.pipix\.com\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'pipixia' },
345
- { pattern: /https?:\/\/(?:www\.)?pipixia\.com\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'pipixia' },
346
- { pattern: /https?:\/\/share\.xiaochuankeji\.cn\/hybrid\/share\/post\?pid=\d+[^\s]*/gi, type: 'zuiyou' },
347
- { pattern: /https?:\/\/(?:h5|www)\.izuiyou\.com\/[0-9a-zA-Z_\/-]+[^\s]*/gi, type: 'zuiyou' },
297
+ { pattern: /https?:\/\/(?:www\.)?bilibili\.com\/video\/([ab]v[0-9a-zA-Z_-]+)(?:\?[^\s'"“”‘’]*)?/gi, type: 'bilibili' },
298
+ { pattern: /https?:\/\/b23\.tv\/[0-9a-zA-Z_\/-]+/gi, type: 'bilibili' },
299
+ { pattern: /https?:\/\/bili\d+\.cn\/[0-9a-zA-Z_\/-]+/gi, type: 'bilibili' },
300
+ { pattern: /https?:\/\/b23\.wtf\/[0-9a-zA-Z_\/-]+/gi, type: 'bilibili' },
301
+ { pattern: /https?:\/\/bili2233\.cn\/[0-9a-zA-Z_\/-]+/gi, type: 'bilibili' },
302
+ { pattern: /https?:\/\/(?:www\.)?douyin\.com\/video\/\d{10,}/gi, type: 'douyin' },
303
+ { pattern: /https?:\/\/v\.douyin\.com\/[0-9a-zA-Z_\/-]+/gi, type: 'douyin' },
304
+ { pattern: /https?:\/\/(?:www\.)?kuaishou\.com\/short-video\/[0-9a-zA-Z_\/-]+/gi, type: 'kuaishou' },
305
+ { pattern: /https?:\/\/v\.kuaishou\.com\/[0-9a-zA-Z_\/-]+/gi, type: 'kuaishou' },
306
+ { pattern: /https?:\/\/(?:www\.)?kuaishou\.com\/f\/[0-9a-zA-Z_\/-]+/gi, type: 'kuaishou' },
307
+ { pattern: /https?:\/\/(?:www\.)?xiaohongshu\.com\/discovery\/item\/[0-9a-zA-Z_\/-]+/gi, type: 'xiaohongshu' },
308
+ { pattern: /https?:\/\/xhslink\.com\/[0-9a-zA-Z_\/-]+/gi, type: 'xiaohongshu' },
309
+ { pattern: /https?:\/\/(?:www\.)?xiaohongshu\.com\/explore\/[0-9a-zA-Z_\/-]+/gi, type: 'xiaohongshu' },
310
+ { pattern: /https?:\/\/(?:www\.)?xiaohongshu\.com\/board\/[0-9a-zA-Z_\/-]+/gi, type: 'xiaohongshu' },
311
+ { pattern: /https?:\/\/weibo\.com\/\d+\/[0-9a-zA-Z_\/-]+/gi, type: 'weibo' },
312
+ { pattern: /https?:\/\/video\.weibo\.com\/show\?fid=[0-9a-zA-Z_\/-]+/gi, type: 'weibo' },
313
+ { pattern: /https?:\/\/t\.cn\/[0-9a-zA-Z_\/-]+/gi, type: 'weibo' },
314
+ { pattern: /https?:\/\/m\.weibo\.cn\/[0-9a-zA-Z_\/-]+/gi, type: 'weibo' },
315
+ { pattern: /https?:\/\/(?:www\.)?ixigua\.com\/\d{10,}/gi, type: 'xigua' },
316
+ { pattern: /https?:\/\/(?:www\.)?youtube\.com\/watch\?v=[a-zA-Z0-9_-]{11}/gi, type: 'youtube' },
317
+ { pattern: /https?:\/\/youtu\.be\/[0-9a-zA-Z_\/-]+/gi, type: 'youtube' },
318
+ { pattern: /https?:\/\/(?:www\.)?youtube\.com\/shorts\/[0-9a-zA-Z_\/-]+/gi, type: 'youtube' },
319
+ { pattern: /https?:\/\/(?:www\.)?tiktok\.com\/@[\w.]+\/video\/\d{10,}/gi, type: 'tiktok' },
320
+ { pattern: /https?:\/\/vm\.tiktok\.com\/[0-9a-zA-Z_\/-]+/gi, type: 'tiktok' },
321
+ { pattern: /https?:\/\/vt\.tiktok\.com\/[0-9a-zA-Z_\/-]+/gi, type: 'tiktok' },
322
+ { pattern: /https?:\/\/(?:www\.)?acfun\.cn\/v\/ac\d{10,}/gi, type: 'acfun' },
323
+ { pattern: /https?:\/\/(?:www\.)?zhihu\.com\/video\/\d{10,}/gi, type: 'zhihu' },
324
+ { pattern: /https?:\/\/(?:www\.|m\.)?zhihu\.com\/question\/\d+\/answer\/\d+/gi, type: 'zhihu' },
325
+ { pattern: /https?:\/\/zhuanlan\.zhihu\.com\/p\/\d+/gi, type: 'zhihu' },
326
+ { pattern: /https?:\/\/(?:www\.|m\.)?zhihu\.com\/zvideo\/\d+/gi, type: 'zhihu' },
327
+ { pattern: /https?:\/\/weishi\.qq\.com\/weishi\/feed\/[0-9a-zA-Z_\/-]+/gi, type: 'weishi' },
328
+ { pattern: /https?:\/\/(?:www\.)?huya\.com\/video\/[0-9a-zA-Z_\/-]+/gi, type: 'huya' },
329
+ { pattern: /https?:\/\/haokan\.baidu\.com\/v\?vid=[0-9a-zA-Z_\/-]+/gi, type: 'haokan' },
330
+ { pattern: /https?:\/\/(?:www\.)?meipai\.com\/media\/\d{10,}/gi, type: 'meipai' },
331
+ { pattern: /https?:\/\/twitter\.com\/\w+\/status\/\d{10,}/gi, type: 'twitter' },
332
+ { pattern: /https?:\/\/x\.com\/\w+\/status\/\d{10,}/gi, type: 'twitter' },
333
+ { pattern: /https?:\/\/(?:www\.)?instagram\.com\/p\/[0-9a-zA-Z_\/-]+/gi, type: 'instagram' },
334
+ { pattern: /https?:\/\/(?:www\.)?instagram\.com\/reel\/[0-9a-zA-Z_\/-]+/gi, type: 'instagram' },
335
+ { pattern: /https?:\/\/(?:www\.)?instagram\.com\/share\/(?:reel|p)\/[0-9a-zA-Z_\/-]+/gi, type: 'instagram' },
336
+ { pattern: /https?:\/\/(?:www\.)?doubao\.com\/video\/\d{10,}/gi, type: 'doubao' },
337
+ { pattern: /https?:\/\/(?:www\.)?doubao\.com\/video-sharing\?[^\s'"“”‘’]*/gi, type: 'doubao' },
338
+ { pattern: /https?:\/\/(?:www\.)?doubao\.com\/thread\/[^\s'"“”‘’]+/gi, type: 'doubao_image' },
339
+ { pattern: /https?:\/\/(?:www\.)?jimeng\.jianying\.com\/[^\s'"“”‘’]*/gi, type: 'jimeng' },
340
+ { pattern: /https?:\/\/(?:www\.)?jimeng\.cn\/[^\s'"“”‘’]*/gi, type: 'jimeng' },
341
+ { pattern: /https?:\/\/(?:www\.)?dreamina\.jianying\.com\/[^\s'"“”‘’]*/gi, type: 'jimeng' },
342
+ { pattern: /https?:\/\/(?:www\.)?dreamina\.capcut\.com\/[^\s'"“”‘’]*/gi, type: 'jimeng' },
343
+ { pattern: /https?:\/\/(?:www\.)?oasis\.weibo\.com\/v\/[0-9a-zA-Z_\/-]+/gi, type: 'oasis' },
344
+ { pattern: /https?:\/\/channels\.weixin\.qq\.com\/[0-9a-zA-Z_\/-]+/gi, type: 'wechat_channel' },
345
+ { pattern: /https?:\/\/weixin\.qq\.com\/sph\/[0-9a-zA-Z_\/-]+/gi, type: 'wechat_channel' },
346
+ { pattern: /https?:\/\/(?:www\.)?pearvideo\.com\/video_\d+/gi, type: 'lishi' },
347
+ { pattern: /https?:\/\/video\.li\/[0-9a-zA-Z_\/-]+/gi, type: 'lishi' },
348
+ { pattern: /https?:\/\/(?:www\.)?quanmin\.tv\/[0-9a-zA-Z_\/-]+/gi, type: 'quanmin' },
349
+ { pattern: /https?:\/\/(?:www\.)?quanmintv\.cn\/[0-9a-zA-Z_\/-]+/gi, type: 'quanmin' },
350
+ { pattern: /https?:\/\/h5\.pipigx\.com\/pp\/post\/\d+/gi, type: 'pipigx' },
351
+ { pattern: /https?:\/\/(?:www\.)?ippzone\.com\/[0-9a-zA-Z_\/-]+/gi, type: 'pipigx' },
352
+ { pattern: /https?:\/\/(?:h5|www)\.pipix\.com\/[0-9a-zA-Z_\/-]+/gi, type: 'pipixia' },
353
+ { pattern: /https?:\/\/(?:www\.)?pipixia\.com\/[0-9a-zA-Z_\/-]+/gi, type: 'pipixia' },
354
+ { pattern: /https?:\/\/share\.xiaochuankeji\.cn\/hybrid\/share\/post\?pid=\d+/gi, type: 'zuiyou' },
355
+ { pattern: /https?:\/\/(?:h5|www)\.izuiyou\.com\/[0-9a-zA-Z_\/-]+/gi, type: 'zuiyou' },
348
356
  ];
349
357
  function buildCustomLinkRules(customPlatforms) {
350
358
  if (!Array.isArray(customPlatforms) || customPlatforms.length === 0)
@@ -356,7 +364,7 @@ function buildCustomLinkRules(customPlatforms) {
356
364
  if (keywords.length === 0)
357
365
  return null;
358
366
  const escaped = keywords.map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
359
- const pattern = new RegExp('https?://[^/\\s]*(' + escaped.join('|') + ')[^\\s]*', 'gi');
367
+ const pattern = new RegExp(`https?://[^/\\s"'“”‘’]*(${escaped.join('|')})[^\\s"'“”‘’]*`, 'gi');
360
368
  return { pattern, type: `custom_${p.name}` };
361
369
  })
362
370
  .filter(Boolean);
@@ -370,7 +378,10 @@ function linkTypeParser(content, customRules) {
370
378
  let match;
371
379
  rule.pattern.lastIndex = 0;
372
380
  while ((match = rule.pattern.exec(content)) !== null) {
373
- const url = match[0];
381
+ let url = match[0];
382
+ url = cleanUrl(url);
383
+ if (!url)
384
+ continue;
374
385
  if (seen.has(url))
375
386
  continue;
376
387
  seen.add(url);
@@ -385,8 +396,8 @@ function cleanUrl(url) {
385
396
  .replace(/&lt;/g, '<')
386
397
  .replace(/&gt;/g, '>')
387
398
  .replace(/\\\//g, '/');
388
- url = url.replace(/^[\s"'<]+/, '');
389
- url = url.replace(/[\s"'<>\{\}\[\]`,;]+$/, '');
399
+ url = url.replace(/^[\s"'<“”‘’]+/, '');
400
+ url = url.replace(/[\s"'<>\{\}\[\]`,;,。!?:;“”‘’…—~]+$/, '');
390
401
  if (!/^https?:\/\//i.test(url)) {
391
402
  if (/^\/\//.test(url))
392
403
  url = 'https:' + url;
@@ -630,7 +641,7 @@ function parseApiResponse(raw, maxDescLen, fieldMapping) {
630
641
  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 };
631
642
  }
632
643
  const formatVarRegex = /\$\{([^}]+)\}/g;
633
- function generateFormattedText(p, format) {
644
+ function generateFormattedText(p, format, index, total) {
634
645
  const imageCount = p.images.length || p.live_photo.length;
635
646
  const vars = {
636
647
  '标题': p.title,
@@ -648,10 +659,6 @@ function generateFormattedText(p, format) {
648
659
  '音乐标题': p.music.title || '',
649
660
  '音乐作者': p.music.author || '',
650
661
  };
651
- const varReplacements = Object.entries(vars).map(([key, val]) => ({
652
- regex: new RegExp(`\\$\\{${key}\\}`, 'g'),
653
- value: val,
654
- }));
655
662
  const lines = format.split('\n');
656
663
  const resultLines = [];
657
664
  for (const line of lines) {
@@ -670,12 +677,16 @@ function generateFormattedText(p, format) {
670
677
  continue;
671
678
  }
672
679
  let newLine = line;
673
- for (const { regex, value } of varReplacements) {
674
- newLine = newLine.replace(regex, value);
680
+ for (const [key, val] of Object.entries(vars)) {
681
+ newLine = newLine.replace(new RegExp(`\\$\\{${key}\\}`, 'g'), val);
675
682
  }
676
683
  resultLines.push(newLine);
677
684
  }
678
- return resultLines.join('\n').trim();
685
+ let text = resultLines.join('\n').trim();
686
+ if (index !== undefined && total !== undefined && total > 1) {
687
+ text = `【${index}/${total}】\n${text}`;
688
+ }
689
+ return text;
679
690
  }
680
691
  const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
681
692
  function buildForwardNode(session, content, botName) {
@@ -806,6 +817,31 @@ function apply(ctx, config) {
806
817
  return { [customHeaderName]: apiKey };
807
818
  return {};
808
819
  }
820
+ async function sendWithTimeout(session, content, customRetries) {
821
+ const maxRetries = customRetries ?? config.retryTimes ?? 3;
822
+ const retryDelay = config.retryInterval || 1000;
823
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
824
+ try {
825
+ let sendPromise = session.send(content);
826
+ if (config.videoSendTimeout > 0) {
827
+ const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('发送超时')), config.videoSendTimeout));
828
+ return await Promise.race([sendPromise, timeoutPromise]);
829
+ }
830
+ else {
831
+ return await sendPromise;
832
+ }
833
+ }
834
+ catch (err) {
835
+ const errMsg = getErrorMessage(err);
836
+ debugLog('ERROR', `发送失败尝试 ${attempt + 1}: ${errMsg}`);
837
+ if (attempt < maxRetries)
838
+ await delay(retryDelay);
839
+ else if (!config.ignoreSendError)
840
+ throw err;
841
+ }
842
+ }
843
+ return null;
844
+ }
809
845
  async function sendMedia(session, url, type, showFile) {
810
846
  if (!url)
811
847
  return;
@@ -875,13 +911,16 @@ function apply(ctx, config) {
875
911
  await sendWithTimeout(session, `${getText('parseErrorPrefix')}\n${errors.join('\n')}`);
876
912
  if (!items.length)
877
913
  return;
914
+ const totalItems = items.length;
878
915
  const enableForward = config.enableForward && (session.platform === 'onebot' || session.platform === 'satori');
879
916
  const botName = config.botName || '视频解析机器人';
880
917
  if (enableForward) {
881
918
  const forwardMessages = [];
882
- for (const item of items) {
919
+ for (let i = 0; i < items.length; i++) {
920
+ const item = items[i];
883
921
  const p = item.parsed;
884
- let text = item.text;
922
+ const textWithIndex = (totalItems > 1) ? `【${i + 1}/${totalItems}】\n${item.text}` : item.text;
923
+ let text = textWithIndex;
885
924
  if (config.showAuthorAvatar && p.avatar && config.showAuthorAvatarText) {
886
925
  text = text ? text + '\n' + (config.authorAvatarText || '作者头像:') : (config.authorAvatarText || '作者头像:');
887
926
  }
@@ -934,9 +973,11 @@ function apply(ctx, config) {
934
973
  }
935
974
  }
936
975
  else {
937
- for (const item of items) {
976
+ for (let i = 0; i < items.length; i++) {
977
+ const item = items[i];
938
978
  const p = item.parsed;
939
- let text = item.text;
979
+ const textWithIndex = (totalItems > 1) ? `【${i + 1}/${totalItems}】\n${item.text}` : item.text;
980
+ let text = textWithIndex;
940
981
  if (config.showAuthorAvatar && p.avatar && config.showAuthorAvatarText) {
941
982
  text = text ? text + '\n' + (config.authorAvatarText || '作者头像:') : (config.authorAvatarText || '作者头像:');
942
983
  }
@@ -966,9 +1007,9 @@ function apply(ctx, config) {
966
1007
  }
967
1008
  else if (p.type === 'image' || (p.type === 'live' && (p.live_photo?.length || p.images?.length))) {
968
1009
  const imageUrls = p.images?.length ? p.images : (p.live_photo?.map(lp => lp.image) ?? []);
969
- for (let i = 0; i < imageUrls.length; i++) {
970
- logger.info(`[发送] 图片 ${i + 1}/${imageUrls.length}`);
971
- await sendMedia(session, imageUrls[i], 'image', config.showImageFileNew).catch(() => { });
1010
+ for (let j = 0; j < imageUrls.length; j++) {
1011
+ logger.info(`[发送] 图片 ${j + 1}/${imageUrls.length}`);
1012
+ await sendMedia(session, imageUrls[j], 'image', config.showImageFileNew).catch(() => { });
972
1013
  await delay(1000);
973
1014
  }
974
1015
  }
@@ -1073,18 +1114,17 @@ function apply(ctx, config) {
1073
1114
  throw lastError || new Error('所有API请求全部失败');
1074
1115
  }
1075
1116
  async function parseUrl(url, type, fieldMapping, platformConf) {
1076
- const cleanedUrl = cleanUrl(url);
1077
1117
  try {
1078
- const info = await fetchApi(cleanedUrl, type, fieldMapping, platformConf);
1118
+ const info = await fetchApi(url, type, fieldMapping, platformConf);
1079
1119
  if (info.video || info.images.length > 0 || info.live_photo.length > 0)
1080
1120
  return { success: true, data: info };
1081
- debugLog('WARN', `解析成功但无内容: ${cleanedUrl}`);
1121
+ debugLog('WARN', `解析成功但无内容: ${url}`);
1122
+ return { success: false, msg: '解析接口返回空内容' };
1082
1123
  }
1083
1124
  catch (error) {
1084
- debugLog('ERROR', `解析失败: ${cleanedUrl}`, getErrorMessage(error));
1125
+ debugLog('ERROR', `解析失败: ${url}`, getErrorMessage(error));
1085
1126
  return { success: false, msg: getErrorMessage(error) };
1086
1127
  }
1087
- return { success: false, msg: getText('unsupportedPlatformText') };
1088
1128
  }
1089
1129
  async function processSingleUrl(url, type, fieldMapping, platformConf) {
1090
1130
  const result = await parseUrl(url, type, fieldMapping, platformConf);
@@ -1093,31 +1133,6 @@ function apply(ctx, config) {
1093
1133
  const text = generateFormattedText(result.data, config.unifiedMessageFormat);
1094
1134
  return { success: true, data: { text, parsed: result.data } };
1095
1135
  }
1096
- async function sendWithTimeout(session, content, customRetries) {
1097
- const maxRetries = customRetries ?? config.retryTimes ?? 3;
1098
- const retryDelay = config.retryInterval || 1000;
1099
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
1100
- try {
1101
- let sendPromise = session.send(content);
1102
- if (config.videoSendTimeout > 0) {
1103
- const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('发送超时')), config.videoSendTimeout));
1104
- return await Promise.race([sendPromise, timeoutPromise]);
1105
- }
1106
- else {
1107
- return await sendPromise;
1108
- }
1109
- }
1110
- catch (err) {
1111
- const errMsg = getErrorMessage(err);
1112
- debugLog('ERROR', `发送失败尝试 ${attempt + 1}: ${errMsg}`);
1113
- if (attempt < maxRetries)
1114
- await delay(retryDelay);
1115
- else if (!config.ignoreSendError)
1116
- throw err;
1117
- }
1118
- }
1119
- return null;
1120
- }
1121
1136
  const customRules = buildCustomLinkRules(config.customPlatforms || []);
1122
1137
  const axiosConfig = {
1123
1138
  timeout: config.timeout,
@@ -1156,7 +1171,7 @@ function apply(ctx, config) {
1156
1171
  debugLog('INFO', `检测到 ${matches.length} 个链接`);
1157
1172
  if (config.showWaitingTip) {
1158
1173
  try {
1159
- await sendWithTimeout(session, getText('waitingTipText'));
1174
+ await sendWithTimeout(session, koishi_1.h.quote(session.messageId) + getText('waitingTipText'));
1160
1175
  }
1161
1176
  catch (e) {
1162
1177
  debugLog('WARN', '等待提示发送失败:', e);
@@ -1176,7 +1191,7 @@ function apply(ctx, config) {
1176
1191
  }
1177
1192
  if (config.showWaitingTip) {
1178
1193
  try {
1179
- await sendWithTimeout(session, getText('waitingTipText'));
1194
+ await sendWithTimeout(session, koishi_1.h.quote(session?.messageId) + getText('waitingTipText'));
1180
1195
  }
1181
1196
  catch { }
1182
1197
  }
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.7",
4
+ "version": "1.5.8",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": ["lib"],