koishi-plugin-forward-hime 1.4.2-alpha.1 → 1.4.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.
@@ -1,10 +1,10 @@
1
- import { Session, Element } from "koishi";
1
+ import { Context, Session, Element } from "koishi";
2
2
  import { ConfigSet, ForwardNode } from "./config";
3
3
  interface ForwardMsg {
4
4
  head: Element[];
5
5
  content: Element[];
6
6
  }
7
- export declare function decoratorInit(cfg: ConfigSet): void;
7
+ export declare function decoratorInit(ctx: Context, cfg: ConfigSet): void;
8
8
  export declare function defaultDecorator({ head, content }: ForwardMsg): Element[];
9
9
  export declare function defaultMiddleware(session: Session): ForwardMsg;
10
10
  export declare function MsgMiddlewareCache(session: Session): Promise<void>;
package/lib/index.js CHANGED
@@ -362,8 +362,21 @@ var MediaRelayError = class extends Error {
362
362
  this.userMessage = userMessage;
363
363
  }
364
364
  };
365
- function relayInit(cfg) {
365
+ function relayInit(ctx2, cfg) {
366
366
  relayConfig = cfg.MediaRelay;
367
+ ctx2.on("http/file", (url, options) => {
368
+ const { filename, file } = options;
369
+ if (typeof filename !== "string" || file !== filename) return;
370
+ const match = /^data:([\w.+/-]+);base64,(.*)$/.exec(url);
371
+ if (match) {
372
+ return {
373
+ data: Buffer.from(match[2], "base64"),
374
+ type: match[1],
375
+ mime: match[1],
376
+ filename
377
+ };
378
+ }
379
+ });
367
380
  }
368
381
  function cleanupExpiredRelayCache() {
369
382
  const now = Date.now();
@@ -425,16 +438,26 @@ function getCacheKey(element) {
425
438
  const src = mediaUrlFromElement(element);
426
439
  return `${mediaType}:${src}`;
427
440
  }
428
- function relayElementFromCache(item) {
429
- return createRelayElement(item.kind, item.mime, item.buffer, item.filename);
441
+ function relayElementFromCache(item, targetPlatform) {
442
+ return createRelayElement(
443
+ item.kind,
444
+ item.mime,
445
+ item.buffer,
446
+ item.filename,
447
+ targetPlatform
448
+ );
430
449
  }
431
- function createRelayElement(kind, mime, buffer, filename) {
450
+ function createRelayElement(kind, mime, buffer, filename, targetPlatform) {
432
451
  const helperMap = import_koishi5.h;
433
452
  if (kind === "img") {
434
453
  return import_koishi5.h.image(buffer, mime);
435
454
  }
455
+ if (kind === "audio") {
456
+ return import_koishi5.h.audio(buffer, mime, { file: filename });
457
+ }
436
458
  if (kind === "file") {
437
- return helperMap.file(buffer, mime, { filename });
459
+ const attrs = { file: filename, filename, title: filename };
460
+ return targetPlatform === "discord" ? import_koishi5.h.image(buffer, mime, attrs) : helperMap.file(buffer, mime, attrs);
438
461
  }
439
462
  if (helperMap[kind]) {
440
463
  return helperMap[kind](buffer, mime);
@@ -495,7 +518,7 @@ async function downloadAndRelay(element, traceId, session, node) {
495
518
  ...context
496
519
  });
497
520
  }
498
- return relayElementFromCache(cacheItem);
521
+ return relayElementFromCache(cacheItem, node?.Platform);
499
522
  }
500
523
  const timeoutSignal = typeof AbortSignal.timeout === "function" ? AbortSignal.timeout(relayConfig.RequestTimeoutSec * 1e3) : void 0;
501
524
  const response = await fetch(src, { signal: timeoutSignal });
@@ -546,9 +569,9 @@ async function downloadAndRelay(element, traceId, session, node) {
546
569
  `\u5A92\u4F53\u6587\u4EF6\u8FC7\u5927\uFF08>${relayConfig.MaxFileSizeMB} MB\uFF09\uFF0C\u65E0\u6CD5\u4E2D\u8F6C\u53D1\u9001\u3002`
547
570
  );
548
571
  }
549
- const mime = response.headers.get("content-type") || pickDefaultMime(kind);
550
- const filename = kind === "file" ? pickFilename(element, src) : void 0;
551
- const relayed = createRelayElement(kind, mime, buffer, filename);
572
+ const mime = response.headers.get("content-type")?.split(";")[0].trim() || pickDefaultMime(kind);
573
+ const filename = kind === "file" || kind === "audio" ? pickFilename(element, src) : void 0;
574
+ const relayed = createRelayElement(kind, mime, buffer, filename, node?.Platform);
552
575
  relayCache.set(cacheKey, {
553
576
  expiresAt: Date.now() + relayConfig.CacheMinutes * 60 * 1e3,
554
577
  kind,
@@ -608,9 +631,15 @@ async function relayForwardContent(content, traceId, session, node) {
608
631
  }
609
632
 
610
633
  // src/message.ts
634
+ var DeliveryUncertainError = class extends Error {
635
+ constructor(cause) {
636
+ super("message delivery status unknown", { cause });
637
+ }
638
+ };
611
639
  async function MessageSendWithDecorator(ctx2, node, session, Deco, traceId, attempt) {
612
640
  const startedAt = Date.now();
613
641
  const uuid = session.channelId + ":" + session.messageId;
642
+ let submitted = false;
614
643
  writeDiagnostic({
615
644
  traceId,
616
645
  phase: "send-attempt",
@@ -621,6 +650,7 @@ async function MessageSendWithDecorator(ctx2, node, session, Deco, traceId, atte
621
650
  });
622
651
  try {
623
652
  const content = await Deco(session, node, traceId);
653
+ submitted = true;
624
654
  const res = await ctx2.bots[`${node.Platform}:${node.BotID}`].sendMessage(
625
655
  node.Guild,
626
656
  content
@@ -663,7 +693,7 @@ async function MessageSendWithDecorator(ctx2, node, session, Deco, traceId, atte
663
693
  logger.error(
664
694
  `ERROR:<MessageSendWithDecorator ${node.Platform}> ctx=${ctx2} ${error}`
665
695
  );
666
- throw error;
696
+ throw submitted ? new DeliveryUncertainError(error) : error;
667
697
  }
668
698
  }
669
699
  function sessionTypeArray(session) {
@@ -748,6 +778,10 @@ async function MessageForward(ctx2, node, session, timeoutSec, relayEnabled) {
748
778
  logger.error(
749
779
  `ERROR:<MessageSend ${node.Platform}> ctx=${ctx2} ${sessionTypeArray(session)} ${firstError}`
750
780
  );
781
+ if (firstError instanceof DeliveryUncertainError) {
782
+ writeDiagnostic({ traceId, phase: "forward-uncertain", source, target });
783
+ return;
784
+ }
751
785
  if (relayEnabled !== false && firstError instanceof MediaRelayError) {
752
786
  logger.info(
753
787
  `[MessageForward] relay failed, retrying without relay: ${node.Platform}`
@@ -765,6 +799,15 @@ async function MessageForward(ctx2, node, session, timeoutSec, relayEnabled) {
765
799
  logger.error(
766
800
  `ERROR:<MessageSendDirect ${node.Platform}> ctx=${ctx2} ${sessionTypeArray(session)} ${secondError}`
767
801
  );
802
+ if (secondError instanceof DeliveryUncertainError) {
803
+ writeDiagnostic({
804
+ traceId,
805
+ phase: "forward-uncertain",
806
+ source,
807
+ target
808
+ });
809
+ return;
810
+ }
768
811
  sendDegraded(reasonFromError(secondError));
769
812
  });
770
813
  } else {
@@ -795,11 +838,11 @@ function MsgUUIDFromSession(session) {
795
838
  var defaultPrefix = "";
796
839
  var defaultFallback = "";
797
840
  var defaultPrefixNewline = true;
798
- function decoratorInit(cfg) {
841
+ function decoratorInit(ctx2, cfg) {
799
842
  defaultPrefix = cfg.DefaultDecorator.Prefix;
800
843
  defaultPrefixNewline = cfg.DefaultDecorator.Newline;
801
844
  defaultFallback = cfg.DefaultFallbackMsgPrefix;
802
- relayInit(cfg);
845
+ relayInit(ctx2, cfg);
803
846
  }
804
847
  function renderTemplate(template, data) {
805
848
  return template.replace(/\$\{(\w+)\}/g, (_, key) => {
@@ -816,7 +859,10 @@ function defaultMiddleware(session) {
816
859
  if (defaultPrefixNewline) {
817
860
  head.push((0, import_koishi6.h)("br"));
818
861
  }
819
- return { head, content: session.elements };
862
+ const content = session.platform === "discord" ? session.elements.map(
863
+ (element) => element.type === "record" ? (0, import_koishi6.h)("audio", element.attrs, element.children) : element
864
+ ) : session.elements;
865
+ return { head, content };
820
866
  }
821
867
  var localDecorators = [atTranslator, quoteTranslator];
822
868
  var msgMiddleCache = [];
@@ -842,6 +888,19 @@ function MsgToMiddleware(session) {
842
888
  }
843
889
  return defaultMiddleware(session);
844
890
  }
891
+ function discordAudioAttachments(session, node, content) {
892
+ if (session.platform !== "onebot" || node.Platform !== "discord") {
893
+ return content;
894
+ }
895
+ return content.map((element) => {
896
+ if (element.type !== "audio") return element;
897
+ const src = element.attrs.src || element.attrs.url;
898
+ if (typeof src !== "string") return element;
899
+ const name2 = element.attrs.filename || element.attrs.file;
900
+ const filename = typeof name2 === "string" && /^[^/\\:]+\.[a-z\d]+$/i.test(name2) ? name2 : "voice.bin";
901
+ return import_koishi6.h.image(src, { file: filename, mode: "download" });
902
+ });
903
+ }
845
904
  async function MsgMiddlewareCache(session) {
846
905
  const elems = MsgToMiddleware(session);
847
906
  msgMiddleCacheAppend({ UUID: MsgUUIDFromSession(session), msg: elems });
@@ -863,7 +922,11 @@ async function MsgDecorator(session, node, traceId) {
863
922
  }
864
923
  elems = {
865
924
  head: elems.head,
866
- content: await relayForwardContent(elems.content, traceId, session, node)
925
+ content: discordAudioAttachments(
926
+ session,
927
+ node,
928
+ await relayForwardContent(elems.content, traceId, session, node)
929
+ )
867
930
  };
868
931
  if (_platform_out && typeof _platform_out.Decorator === "function") {
869
932
  return _platform_out.Decorator(elems);
@@ -884,6 +947,10 @@ async function MsgDecoratorNoRelay(session, node) {
884
947
  elems = await fn(session, node, elems);
885
948
  }
886
949
  logger.debug(`[MsgDecoratorNoRelay] fallback to direct forward`);
950
+ elems = {
951
+ head: elems.head,
952
+ content: discordAudioAttachments(session, node, elems.content)
953
+ };
887
954
  if (_platform_out && typeof _platform_out.Decorator === "function") {
888
955
  return _platform_out.Decorator(elems);
889
956
  } else {
@@ -993,7 +1060,7 @@ function apply(ctx2, cfg) {
993
1060
  diagnosticsInit(ctx2);
994
1061
  consoleInit(ctx2);
995
1062
  msgCacheInit(ctx2, cfg);
996
- decoratorInit(cfg);
1063
+ decoratorInit(ctx2, cfg);
997
1064
  ctx2.on("message-created", async (session) => {
998
1065
  const hitGroup = [];
999
1066
  for (const g in cfg.ForwardGroups) {
package/lib/relay.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Element } from "koishi";
1
+ import { Context, Element } from "koishi";
2
2
  import { ConfigSet } from "./config";
3
3
  import { Session } from "koishi";
4
4
  import { ForwardNode } from "./config";
@@ -6,5 +6,5 @@ export declare class MediaRelayError extends Error {
6
6
  userMessage: string;
7
7
  constructor(message: string, userMessage: string);
8
8
  }
9
- export declare function relayInit(cfg: ConfigSet): void;
9
+ export declare function relayInit(ctx: Context, cfg: ConfigSet): void;
10
10
  export declare function relayForwardContent(content: Element[], traceId?: string, session?: Session, node?: ForwardNode): Promise<Element[]>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-forward-hime",
3
3
  "description": "多群组消息互通",
4
- "version": "1.4.2-alpha.1",
4
+ "version": "1.4.3",
5
5
  "author": {
6
6
  "name": "xianii",
7
7
  "email": "jiyucheng007@gmail.com"