@karinjs/adapter-qqbot 3.3.1 → 3.4.0

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,4 +1,81 @@
1
+ import { i as Scene, r as MediaType } from "../base-Dw5yfdft.js";
2
+ import { ElementTypes } from "node-karin";
3
+ //#region src/core/adapter/media-source.d.ts
4
+ /**
5
+ * 本次发送归属的上传会话。
6
+ *
7
+ * QQ 的 openid 按 bot 隔离,上传接口的路径参数只接受该 bot 可见的
8
+ * group_openid / user_openid。因此把真实发送目标一并交给 fileToUrl 处理器,
9
+ * 需要借 QQ 通道上传的处理器才能用对会话,而不是猜一个。
10
+ */
11
+ interface UploadOrigin {
12
+ /** 会话类型。 */
13
+ scene: Scene;
14
+ /** 目标 group_openid 或 user_openid。 */
15
+ peer: string;
16
+ }
17
+ /**
18
+ * 拿到 URL 之后的用途。
19
+ *
20
+ * - markdown:URL 会被写进 markdown 正文,必须是公网可访问地址;
21
+ * - media:URL 只是交给 QQ 富媒体接口去下载转存,本地路径同样可用。
22
+ */
23
+ type UploadPurpose = 'markdown' | 'media';
24
+ /**
25
+ * 传给 fileToUrl 处理器的附加信息。
26
+ *
27
+ * 处理器通过 `args.args` 读取。对不认识这些字段的第三方处理器没有影响,
28
+ * 行为与之前一致。
29
+ */
30
+ interface FileToUrlExtra {
31
+ /** 正在执行本次发送的 bot,用于让上传走同一个 bot。 */
32
+ selfId: string;
33
+ /** 本次转换的用途。 */
34
+ purpose: UploadPurpose;
35
+ /** 本次发送归属的上传会话;频道场景没有可用 openid 时为 undefined。 */
36
+ origin?: UploadOrigin;
37
+ /**
38
+ * 是否允许适配器内置的 fileToUrl 处理器接手。
39
+ *
40
+ * 发送链路会先传 false,让用户处理器和 QQ 素材管理依次尝试;两者都失败后
41
+ * 再传 true 调用内置图床。用户处理器可以忽略该字段。
42
+ */
43
+ allowBuiltinFileToUrl?: boolean;
44
+ }
45
+ //#endregion
1
46
  //#region src/apps/qqbot-file-to-url.d.ts
47
+ /**
48
+ * 内置 `fileToUrl` 处理器:用 QQ 官方分片上传充当临时图床。
49
+ *
50
+ * 发送链路会先尝试用户自己的 `fileToUrl` 和 QQ 素材管理;两者都失败后才把
51
+ * `allowBuiltinFileToUrl` 设为 true,允许本处理器接手。这样图片优先得到
52
+ * `qqbot-media://`,临时直链只作为 Markdown 内嵌的最后手段,再失败才降级为
53
+ * 独立的 `msg_type=7` 富媒体消息。
54
+ *
55
+ * 只在以下条件全部满足时接手,其余情况一律放行给链路上的其他处理器:
56
+ * - 资源要被写进 markdown 正文(富媒体上传不需要先换成 URL);
57
+ * - 类型是图片 / 视频 / 语音(QQ 不为文件类型返回直链);
58
+ * - 允许内置图床接手;
59
+ * - 能确定执行上传的 bot 与归属会话(频道场景没有可用 openid)。
60
+ */
61
+ /** 内置 fileToUrl 处理器的接手条件。 */
62
+ interface BuiltinFileToUrlInput {
63
+ type: MediaType;
64
+ purpose?: FileToUrlExtra['purpose'];
65
+ selfId?: string;
66
+ origin?: FileToUrlExtra['origin'];
67
+ allowBuiltinFileToUrl?: boolean;
68
+ }
69
+ /**
70
+ * 判断内置处理器是否应接手本次 fileToUrl 请求。
71
+ *
72
+ * 发送链路在用户处理器和素材管理阶段会传 `allowBuiltinFileToUrl: false`,
73
+ * 此时内置图床必须放行;只有最后兜底阶段才允许接手图片。
74
+ *
75
+ * @param input 当前 fileToUrl 请求的媒体类型与上下文。
76
+ * @returns 是否由内置处理器处理。
77
+ */
78
+ declare const shouldHandleBuiltinFileToUrl: (input: BuiltinFileToUrlInput) => boolean;
2
79
  declare const qqbotFileToUrl: import("node-karin").Handler;
3
80
  //#endregion
4
- export { qqbotFileToUrl };
81
+ export { BuiltinFileToUrlInput, qqbotFileToUrl, shouldHandleBuiltinFileToUrl };
@@ -1,23 +1,19 @@
1
- import { n as getImageSize } from "../common-DwVsAvIo.js";
1
+ import { n as getImageSize } from "../common-D4MDcmOI.js";
2
2
  import karin, { getAllBot } from "node-karin";
3
3
 
4
4
  //#region src/apps/qqbot-file-to-url.ts
5
5
  /**
6
- * 内置 `fileToUrl` 处理器:用 QQ 官方分片上传充当临时图床。
6
+ * 判断内置处理器是否应接手本次 fileToUrl 请求。
7
7
  *
8
- * 分片上传完成后,合并响应会带上资源的下载直链。有了这个地址,本地图片、截图、
9
- * base64 图片就能以 markdown 图片语法进入消息正文,和文本、按钮合并成一条消息,
10
- * 而不是退化成一条独立的富媒体消息。
8
+ * 发送链路在用户处理器和素材管理阶段会传 `allowBuiltinFileToUrl: false`,
9
+ * 此时内置图床必须放行;只有最后兜底阶段才允许接手图片。
11
10
  *
12
- * 无需任何配置:适配器发送消息时会把执行发送的 bot 和真实发送目标一并交给本
13
- * 处理器,上传因此总是发生在同一个 bot、同一个会话下。QQ 的 openid 按 bot
14
- * 隔离,这一点不能靠猜。上传只借用会话的上传通道,不会往会话里发任何消息。
15
- *
16
- * 只在以下条件全部满足时接手,其余情况一律放行给链路上的其他处理器:
17
- * - 资源要被写进 markdown 正文(富媒体上传不需要先换成 URL);
18
- * - 类型是图片 / 视频 / 语音(QQ 不为文件类型返回直链);
19
- * - 能确定执行上传的 bot 与归属会话(频道场景没有可用 openid)。
11
+ * @param input 当前 fileToUrl 请求的媒体类型与上下文。
12
+ * @returns 是否由内置处理器处理。
20
13
  */
14
+ const shouldHandleBuiltinFileToUrl = (input) => {
15
+ return input.purpose === "markdown" && input.type !== "file" && input.allowBuiltinFileToUrl !== false && !!input.selfId && !!input.origin;
16
+ };
21
17
  /**
22
18
  * 判断已注册的 bot 是否由本插件提供。
23
19
  *
@@ -53,23 +49,23 @@ const toUploadSource = (file) => {
53
49
  const qqbotFileToUrl = karin.handler("fileToUrl", async (payload, next) => {
54
50
  /** fileToUrl 把第四个参数原样放在 args 字段下。 */
55
51
  const { file, type, filename, args: extra } = payload;
56
- /**
57
- * 富媒体上传接受本地文件与 base64,先换成 URL 再交给 QQ 反而多一次往返,
58
- * 而且那次往返仍然是 QQ 自己下载转存,没有收益。
59
- */
60
- if (extra?.purpose !== "markdown") return next();
61
- /** QQ 只对图片 / 视频 / 语音返回下载直链。 */
62
- if (type === "file") return next();
63
- /** 频道场景用 channel_id,没有上传接口要求的 openid。 */
64
- const origin = extra.origin;
65
- if (!extra.selfId || !origin) return next();
66
- const bot = findBot(extra.selfId);
52
+ const selfId = extra?.selfId;
53
+ const origin = extra?.origin;
54
+ if (!selfId || !origin) return next();
55
+ if (!shouldHandleBuiltinFileToUrl({
56
+ type,
57
+ purpose: extra?.purpose,
58
+ selfId,
59
+ origin,
60
+ allowBuiltinFileToUrl: extra?.allowBuiltinFileToUrl
61
+ })) return next();
62
+ const bot = findBot(selfId);
67
63
  if (!bot) return next();
68
64
  try {
69
65
  const { url, response } = await bot.super.media.uploadForUrl(origin.scene, origin.peer, type, toUploadSource(file), filename);
70
66
  bot.logger("debug", `[内置图床] 已取得直链,有效期 ${response.ttl}s: ${url}`);
71
67
  if (type !== "image") return { url };
72
- /** markdown 图片语法需要宽高;解析不出来时 getImageSize 会给出保守默认值。 */
68
+ /** Markdown 图片必须携带宽高,否则 QQ 客户端会使用极小的默认尺寸。 */
73
69
  const { width, height } = await getImageSize(file);
74
70
  return {
75
71
  url,
@@ -91,4 +87,4 @@ const qqbotFileToUrl = karin.handler("fileToUrl", async (payload, next) => {
91
87
  });
92
88
 
93
89
  //#endregion
94
- export { qqbotFileToUrl };
90
+ export { qqbotFileToUrl, shouldHandleBuiltinFileToUrl };