karin-plugin-kkk 2.36.1 → 2.36.2

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
1
  import { i as __toESM } from "./rolldown-runtime.js";
2
- import { $ as SiGooglephotos, $n as require_jsx_runtime, $t as Puzzle, A as RiHashtag, An as Copy, At as Upload, B as RiThumbUpFill, Bn as CircleAlert, Bt as ShoppingBag, C as AiFillHeart, Cn as Eye, Ct as X, D as Markdown, Dn as Crown, Dt as UsersRound, E as AiOutlineVideoCamera, En as Download, Et as Users, F as RiMessage3Fill, Fn as CircleQuestionMark, Ft as Star, G as RiVideoLine, Gn as Box, Gt as Search, H as RiTrophyFill, Hn as ChartColumn, Ht as ShieldCheck, I as RiPieChart2Fill, In as CircleFadingArrowUp, It as Square, J as SiSamsung, Jn as BellRing, Jt as RotateCcw, K as SiXiaomi, Kn as Bot, Kt as ScanLine, L as RiShareForwardFill, Ln as CircleEllipsis, Lt as SquarePen, M as RiHeart3Line, Mn as Clock, Mt as Trash2, N as RiHeartLine, Nn as Clock3, Nt as Terminal, O as RiArrowRightFill, On as Cpu, Ot as User, P as RiLiveLine, Pn as Clapperboard, Pt as Sun, Q as SiHonor, Qn as clsx, Qt as QrCode, R as RiStarFill, Rn as CircleCheck, Rt as Sparkles, S as BiImage, Sn as FilePlay, St as Zap, T as AiFillStar, Tn as ExternalLink, Tt as Video, U as RiUserFollowLine, Un as Camera, Ut as Share2, V as RiTiktokFill, Vn as Check, Vt as Shield, W as RiVerifiedBadgeFill, Wn as Calendar, Wt as Settings2, X as SiOneplus, Xn as Chip, Xt as Radio, Y as SiOppo, Yn as ArrowDownToLine, Yt as RefreshCw, Z as SiHuawei, Zn as Button, Zt as Quote, _ as MdSchedule, _n as Hash, _t as fromUnixTime, a as VictoryScatter, an as Moon, ar as FingerprintGenerator, at as r, b as FaTiktok, bn as Gamepad2, bt as differenceInSeconds, c as VictoryChart, cn as Menu, ct as m, d as VictoryTheme, dn as LoaderCircle, dt as e, en as Plus, er as require_server_node, et as SiGithub, f as rehypeHighlight, fn as Link, ft as a$1, g as MdLocationOn, gn as Heart, gt as parse, h as MdLightbulbOutline, hn as Image$1, ht as zhCN, i as require_heic_decode, in as Music, ir as CryptoConfig, it as o$2, j as RiHeart3Fill, jn as Code, jt as TriangleAlert, k as RiGroupLine, kn as CornerDownLeft, kt as UserPlus, l as VictoryAxis, ln as Maximize, lt as a, m as MdInfoOutline, mn as Info, mt as c, n as require_lib, nn as Pencil, nr as require_protobufjs, nt as SiApple, o as VictoryPie, on as Monitor, or as Xhshow, ot as o, p as MdFitScreen, pn as LayoutTemplate, pt as o$1, q as SiVivo, qn as Bookmark, qt as Save, r as require_jpeg_js, rn as Palette, rr as Chalk, rt as SiAnthropic, s as VictoryLine, sn as MessageCircle, sr as zod_default, st as o$3, t as createProxyMiddleware, tn as Play, tr as require_react, tt as SiBilibili, u as VictoryLabel, un as MapPin, ut as n, v as FaCommentDots, vn as GitBranch, vt as formatDistanceToNow, w as AiFillPushpin, wn as EyeOff, wt as WandSparkles, x as FaUserGroup, xn as FileText, xt as twMerge, y as FaMusic, yn as Gift, yt as format, z as RiStarLine, zn as CircleCheckBig, zt as Smartphone } from "./vendor.js";
2
+ import { $ as SiXiaomi, $n as CircleCheckBig, $t as Quote, A as AiFillHeart, An as Copy, At as X, B as RiHeartLine, Bn as Box, Bt as Square, C as MdLocationOn, Cn as Eye, Ct as parse, D as FaTiktok, Dn as Crown, Dt as differenceInSeconds, E as FaMusic, En as Download, Et as format, F as RiArrowRightFill, Fn as CircleFadingArrowUp, Ft as Upload, G as RiStarFill, Gn as WandSparkles, Gt as Share2, H as RiMessage3Fill, Hn as Bookmark, Ht as ShoppingBag, I as RiGroupLine, In as CircleEllipsis, It as Trash2, J as RiTiktokFill, Jn as SquarePen, Jt as ScanLine, K as RiStarLine, Kn as UsersRound, Kt as Settings2, L as RiHashtag, Ln as Check, Lt as Terminal, M as AiFillStar, Mn as Clock, Mt as Users, N as AiOutlineVideoCamera, Nn as Clock3, Nt as User, O as FaUserGroup, On as Cpu, Ot as twMerge, P as Markdown, Pn as Clapperboard, Pt as UserPlus, Q as RiVideoLine, Qn as CircleQuestionMark, Qt as Radio, R as RiHeart3Fill, Rn as Camera, Rt as Sun, S as MdLightbulbOutline, Sn as FileText, St as zhCN, T as FaCommentDots, Tn as ExternalLink, Tt as formatDistanceToNow, U as RiPieChart2Fill, Un as BellRing, Ut as Shield, V as RiLiveLine, Vn as Bot, Vt as Smartphone, W as RiShareForwardFill, Wn as ArrowDownToLine, Wt as ShieldCheck, X as RiUserFollowLine, Xn as LoaderCircle, Xt as RotateCcw, Y as RiTrophyFill, Yn as Sparkles, Yt as Save, Z as RiVerifiedBadgeFill, Zn as FilePlay, Zt as RefreshCw, _ as tailwind_css, _n as Heart, _t as n, a as VictoryScatter, an as Palette, ar as clsx, at as SiHonor, b as MdFitScreen, bn as Gift, bt as o$1, c as VictoryChart, cn as Monitor, cr as require_react, ct as SiBilibili, d as VictoryTheme, dn as Maximize, dr as CryptoConfig, dt as o$2, en as QrCode, er as CircleCheck, et as SiVivo, f as rehypeHighlight, fn as MapPin, fr as FingerprintGenerator, ft as r, g as tsdown, gn as Image$1, gt as a, h as typescript, hn as Info, ht as m, i as require_heic_decode, in as Pencil, ir as Button, it as SiHuawei, j as AiFillPushpin, jn as Code, jt as Video, k as BiImage, kn as CornerDownLeft, kt as Zap, l as VictoryAxis, ln as MessageCircle, lr as require_protobufjs, lt as SiApple, m as vite, mn as LayoutTemplate, mr as zod_default, mt as o$3, n as require_lib, nn as Plus, nr as ChartColumn, nt as SiOppo, o as VictoryPie, on as Music, or as require_jsx_runtime, ot as SiGooglephotos, p as webassembly, pn as Link, pr as Xhshow, pt as o, q as RiThumbUpFill, qn as TriangleAlert, qt as Search, r as require_jpeg_js, rn as Play, rr as Chip, rt as SiOneplus, s as VictoryLine, sn as Moon, sr as require_server_node, st as SiGithub, t as createProxyMiddleware, tn as Puzzle, tr as CircleAlert, tt as SiSamsung, u as VictoryLabel, un as Menu, ur as Chalk, ut as SiAnthropic, v as sqlite, vn as Hash, vt as e, w as MdSchedule, wn as EyeOff, wt as fromUnixTime, x as MdInfoOutline, xn as Gamepad2, xt as c, y as react, yn as GitBranch, yt as a$1, z as RiHeart3Line, zn as Calendar, zt as Star } from "./vendor.js";
3
3
  import "node:module";
4
4
  import fs from "node:fs";
5
5
  import path, { resolve } from "node:path";
6
- import URL$1, { fileURLToPath } from "node:url";
7
- import karin$1, { BOT_CONNECT, app, authMiddleware, checkPkgUpdate, checkPort, common, config, createBadRequestResponse, createNotFoundResponse, createServerErrorResponse, createSuccessResponse, db, defineConfig, ffmpeg, ffprobe, hooks, karin, karinPathHtml, karinPathTemp, logger, logger as logger$1, logs, mkdirSync, parseChangelog, range, render, restart, segment, updatePkg, watch } from "node-karin";
6
+ import URL$2, { fileURLToPath } from "node:url";
7
+ import karin, { BOT_CONNECT, app, authMiddleware, checkPkgUpdate, checkPort, common, config, createBadRequestResponse, createNotFoundResponse, createServerErrorResponse, createSuccessResponse, db, defineConfig, ffmpeg, ffprobe, hooks, karin as karin$1, karinPathHtml, karinPathTemp, logger, logger as logger$1, logs, mkdirSync, parseChangelog, range, render, restart, segment, updatePkg, watch } from "node-karin";
8
8
  import { EventEmitter } from "node:events";
9
9
  import crypto, { createCipheriv, createHash, randomBytes, randomUUID } from "node:crypto";
10
10
  import axios, { AxiosError } from "node-karin/axios";
@@ -3470,7 +3470,7 @@ var XBogus = class {
3470
3470
  * @returns 包含完整URL、X-Bogus值和使用的User-Agent的元组
3471
3471
  */
3472
3472
  getXBogus(url, ua) {
3473
- const parsedUrl = new URL$1.URL(url);
3473
+ const parsedUrl = new URL$2.URL(url);
3474
3474
  const urlPath = parsedUrl.pathname + parsedUrl.search;
3475
3475
  const currentUa = ua ?? this.defaultUa;
3476
3476
  const rc4EncryptedUa = this.rc4Encrypt(this.uaKey, currentUa);
@@ -7619,13 +7619,6 @@ function createBoundKuaishouFetcher(cookie, requestConfig) {
7619
7619
  }
7620
7620
  //#endregion
7621
7621
  //#region ../amagi/packages/core/src/platform/xiaohongshu/getdata.ts
7622
- /** 小红书返回 code=-100,表示当前登录 Cookie 已失效。 */
7623
- var XiaohongshuLoginExpiredError = class extends Error {
7624
- constructor() {
7625
- super("小红书登录 Cookie 已过期");
7626
- this.name = "XiaohongshuLoginExpiredError";
7627
- }
7628
- };
7629
7622
  /**
7630
7623
  * 小红书数据获取函数
7631
7624
  * @param data - 请求数据参数
@@ -7763,15 +7756,7 @@ var XiaohongshuData = async (data, cookie, requestConfig) => {
7763
7756
  default: throw new Error(`Unknown Xiaohongshu API method: "${data.methodType}"`);
7764
7757
  }
7765
7758
  };
7766
- const userCookie = cookie?.trim();
7767
- if (!userCookie) return requestWithCookie(await xiaohongshuSign.createGuestCookie(requestConfig));
7768
- try {
7769
- return await requestWithCookie(userCookie);
7770
- } catch (error) {
7771
- if (!(error instanceof XiaohongshuLoginExpiredError)) throw error;
7772
- emitLogWarn("小红书用户 Cookie 已过期,切换游客 Cookie 后重试请求");
7773
- return requestWithCookie(await xiaohongshuSign.createGuestCookie(requestConfig));
7774
- }
7759
+ return requestWithCookie(cookie?.trim() ?? "");
7775
7760
  };
7776
7761
  /**
7777
7762
  * 全局数据获取函数
@@ -7792,11 +7777,9 @@ var GlobalGetData$1 = async (methodType, config) => {
7792
7777
  throw networkError;
7793
7778
  }
7794
7779
  if (typeof response === "string" && response.includes("<html>")) return response;
7795
- if (response.code === -100) throw new XiaohongshuLoginExpiredError();
7796
7780
  if (response.code !== 0) throw new Error(`API request failed: ${response.data?.msg ?? response.msg ?? "Unknown error"}, code: ${response.code}`);
7797
7781
  return response;
7798
7782
  } catch (error) {
7799
- if (error instanceof XiaohongshuLoginExpiredError) throw error;
7800
7783
  emitLogError(`Xiaohongshu API request failed [${methodType}]:`, error.message);
7801
7784
  return {
7802
7785
  code: 500,
@@ -10350,7 +10333,7 @@ function getApiRoute(platform, methodType) {
10350
10333
  * 构建后使用 __VERSION__,开发环境从 package.json 读取
10351
10334
  */
10352
10335
  var getVersion = () => {
10353
- return "6.1.3";
10336
+ return "6.2.0";
10354
10337
  };
10355
10338
  var VERSION = getVersion();
10356
10339
  /**
@@ -10906,7 +10889,7 @@ var uploadFile = async (event, file, videoUrl, options) => {
10906
10889
  let contact;
10907
10890
  if (options?.active) {
10908
10891
  selfId = options?.activeOption?.uin;
10909
- contact = karin$1.contactGroup(options?.activeOption?.group_id);
10892
+ contact = karin.contactGroup(options?.activeOption?.group_id);
10910
10893
  } else {
10911
10894
  selfId = event.selfId;
10912
10895
  contact = event.contact;
@@ -10915,7 +10898,7 @@ var uploadFile = async (event, file, videoUrl, options) => {
10915
10898
  const Duration = await getMediaDuration(file.filepath);
10916
10899
  logger.warn(logger.yellow(`视频大小 (${file.totalBytes} MB) 触发压缩条件(设定值:${Config.app.compresstrigger} MB),正在进行压缩至${Config.app.compressvalue} MB...`));
10917
10900
  const message = [segment.text(`视频大小 (${file.totalBytes} MB) 触发压缩条件(设定值:${Config.app.compresstrigger} MB),正在进行压缩至${Config.app.compressvalue} MB...`), options?.message_id ? segment.reply(options.message_id) : segment.text("")];
10918
- const msg1 = await karin$1.sendMsg(selfId, contact, message);
10901
+ const msg1 = await karin.sendMsg(selfId, contact, message);
10919
10902
  const targetBitrate = Common.calculateBitrate(Config.app.compresstrigger, Duration) * .75;
10920
10903
  const startTime = Date.now();
10921
10904
  const outputPath = `${Common.tempDri.video}tmp_${Date.now()}.mp4`;
@@ -10929,7 +10912,7 @@ var uploadFile = async (event, file, videoUrl, options) => {
10929
10912
  newFileSize = await Common.getVideoFileSize(file.filepath);
10930
10913
  logger.debug(`原始视频大小为: ${file.totalBytes.toFixed(1)} MB, ${logger.green(`经 FFmpeg 压缩后最终视频大小为: ${newFileSize.toFixed(1)} MB,原视频文件已删除`)}`);
10931
10914
  const message2 = [segment.text(`压缩后最终视频大小为: ${newFileSize.toFixed(1)} MB,压缩耗时:${((endTime - startTime) / 1e3).toFixed(1)} 秒`), segment.reply(msg1.messageId)];
10932
- await karin$1.sendMsg(selfId, contact, message2);
10915
+ await karin.sendMsg(selfId, contact, message2);
10933
10916
  }
10934
10917
  if (options) options.useGroupFile = Config.app.usegroupfile && newFileSize > Config.app.groupfilevalue;
10935
10918
  if (Config.app.videoSendMode === "base64" && !options?.useGroupFile) {
@@ -10938,12 +10921,12 @@ var uploadFile = async (event, file, videoUrl, options) => {
10938
10921
  } else File = options?.useGroupFile ? file.filepath : `file://${file.filepath}`;
10939
10922
  try {
10940
10923
  if (options?.active) if (options.useGroupFile) {
10941
- const bot = karin$1.getBot(String(options.activeOption?.uin));
10924
+ const bot = karin.getBot(String(options.activeOption?.uin));
10942
10925
  logger.mark(`${logger.blue("主动消息:")} 视频大小: ${newFileSize.toFixed(1)}MB 正在通过${logger.yellow("bot.uploadFile")}回复...`);
10943
10926
  await bot.uploadFile(contact, File, file.originTitle ? `${file.originTitle}.mp4` : `${File.split("/").pop()}`);
10944
10927
  } else {
10945
10928
  logger.mark(`${logger.blue("主动消息:")} 视频大小: ${newFileSize.toFixed(1)}MB 正在通过${logger.yellow("karin.sendMsg")}回复...`);
10946
- sendStatus = (await karin$1.sendMsg(selfId, contact, [segment.video(File)])).messageId ? true : false;
10929
+ sendStatus = (await karin.sendMsg(selfId, contact, [segment.video(File)])).messageId ? true : false;
10947
10930
  }
10948
10931
  else if (options?.useGroupFile) {
10949
10932
  logger.mark(`${logger.blue("被动消息:")} 视频大小: ${newFileSize.toFixed(1)}MB 正在通过${logger.yellow("e.bot.uploadFile")}回复...`);
@@ -10984,8 +10967,8 @@ var downloadVideo = async (event, downloadOpt, uploadOpt) => {
10984
10967
  if (fileSizeContent > 0 && Config.app.usefilelimit && fileSize > Config.app.filelimit) {
10985
10968
  const message = segment.text(`视频:「${downloadOpt.title.originTitle ?? "Error: 文件名获取失败"}」大小 (${fileSizeInMB} MB) 超出最大限制(设定值:${Config.app.filelimit} MB),已取消上传`);
10986
10969
  const selfId = event.selfId || uploadOpt?.activeOption?.uin;
10987
- const contact = event.contact || karin$1.contactGroup(uploadOpt?.activeOption?.group_id) || karin$1.contactFriend(selfId);
10988
- await karin$1.sendMsg(selfId, contact, message);
10970
+ const contact = event.contact || karin.contactGroup(uploadOpt?.activeOption?.group_id) || karin.contactFriend(selfId);
10971
+ await karin.sendMsg(selfId, contact, message);
10989
10972
  return false;
10990
10973
  }
10991
10974
  let res = await downloadFile(downloadOpt.video_url, {
@@ -12533,6 +12516,7 @@ var ImageDownloader = class {
12533
12516
  * @returns 处理后的图片路径(HTTP URL / file:// 协议 / base64://)
12534
12517
  */
12535
12518
  async processImage(imageUrl, title, index) {
12519
+ if (!/^https?:\/\//i.test(imageUrl)) return imageUrl;
12536
12520
  switch (Config.app.imageSendMode) {
12537
12521
  case "base64": try {
12538
12522
  return await this.downloadAndConvertToBase64(imageUrl);
@@ -12979,6 +12963,20 @@ function getImageDownloader() {
12979
12963
  async function processImageUrl(imageUrl, title, index) {
12980
12964
  return await getImageDownloader().processImage(imageUrl, title, index);
12981
12965
  }
12966
+ /**
12967
+ * 处理本地生成的图片文件。
12968
+ *
12969
+ * imageSendMode 的 url 只适用于已有 HTTP 图片;本地合成图没有可直接发送的公网 URL,
12970
+ * 因此在 url 模式下回退到 base64,避免依赖 file 协议。
12971
+ */
12972
+ function processLocalImageFile(filePath) {
12973
+ const normalizedPath = filePath.replace(/\\/g, "/");
12974
+ if (Config.app.imageSendMode !== "file") {
12975
+ if (Config.app.imageSendMode === "url") logger.debug(`本地生成图片不支持 imageSendMode=url,已回退到 base64 发送: ${normalizedPath}`);
12976
+ return `base64://${fs.readFileSync(normalizedPath).toString("base64")}`;
12977
+ }
12978
+ return `file://${normalizedPath}`;
12979
+ }
12982
12980
  //#endregion
12983
12981
  //#region ../template/src/dev/preview/utils/time.ts
12984
12982
  var import_react = /* @__PURE__ */ __toESM(require_react(), 1);
@@ -23818,6 +23816,37 @@ var InlineCalloutCode = ({ children, className }) => /* @__PURE__ */ (0, import_
23818
23816
  },
23819
23817
  children
23820
23818
  });
23819
+ var toSvgDataUri = (svg) => `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
23820
+ var techStackItems = [
23821
+ {
23822
+ label: "TypeScript",
23823
+ iconSrc: toSvgDataUri(typescript.svg)
23824
+ },
23825
+ {
23826
+ label: "SQLite",
23827
+ iconSrc: toSvgDataUri(sqlite.svg)
23828
+ },
23829
+ {
23830
+ label: "React",
23831
+ iconSrc: toSvgDataUri(react.svg)
23832
+ },
23833
+ {
23834
+ label: "Tailwind CSS",
23835
+ iconSrc: toSvgDataUri(tailwind_css.svg)
23836
+ },
23837
+ {
23838
+ label: "WebAssembly",
23839
+ iconSrc: toSvgDataUri(webassembly.svg)
23840
+ },
23841
+ {
23842
+ label: "Vite",
23843
+ iconSrc: toSvgDataUri(vite.svg)
23844
+ },
23845
+ {
23846
+ label: "tsdown",
23847
+ iconSrc: toSvgDataUri(tsdown.svg)
23848
+ }
23849
+ ];
23821
23850
  /**
23822
23851
  * 更新日志组件
23823
23852
  * @param props 组件属性
@@ -23825,6 +23854,7 @@ var InlineCalloutCode = ({ children, className }) => /* @__PURE__ */ (0, import_
23825
23854
  */
23826
23855
  var Changelog = import_react.memo((props) => {
23827
23856
  const isDark = props.data.useDarkTheme ?? false;
23857
+ const isUpdateTip = props.data.Tip === true;
23828
23858
  const share_url = props.data?.share_url || "";
23829
23859
  const backgroundColors = isDark ? {
23830
23860
  base: "#0a0a0a",
@@ -23943,7 +23973,7 @@ var Changelog = import_react.memo((props) => {
23943
23973
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
23944
23974
  className: "relative px-16 pt-5 pb-0 w-full max-w-none prose prose-lg prose-invert from-surface to-surface",
23945
23975
  children: [
23946
- props.data.Tip === true ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
23976
+ isUpdateTip ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
23947
23977
  className: "pt-32",
23948
23978
  children: [
23949
23979
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
@@ -24108,7 +24138,7 @@ var Changelog = import_react.memo((props) => {
24108
24138
  a: ({ children, href, ...props }) => {
24109
24139
  const isVersionLink = href?.includes("/compare/");
24110
24140
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
24111
- className: `inline-flex gap-3 items-baseline cursor-pointer font-medium hover:underline ${isVersionLink ? "text-success" : "text-foreground/50"}`,
24141
+ className: `inline-flex gap-3 items-baseline cursor-pointer font-medium hover:underline ${isVersionLink ? "text-foreground" : "text-foreground/50"}`,
24112
24142
  onClick: (e) => e.preventDefault(),
24113
24143
  ...props,
24114
24144
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children })
@@ -24137,8 +24167,81 @@ var Changelog = import_react.memo((props) => {
24137
24167
  children: props.data?.markdown ?? ""
24138
24168
  })
24139
24169
  }),
24140
- share_url && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
24141
- className: "flex flex-col items-center gap-12 py-8",
24170
+ share_url && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: isUpdateTip ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
24171
+ className: "py-10",
24172
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
24173
+ className: "relative flex flex-col gap-8 overflow-hidden border-y border-muted/70 py-10",
24174
+ children: [
24175
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-x-0 top-0 h-px bg-linear-to-r from-transparent via-foreground/20 to-transparent" }),
24176
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-x-0 bottom-0 h-px bg-linear-to-r from-transparent via-foreground/20 to-transparent" }),
24177
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
24178
+ className: "relative flex items-stretch gap-12",
24179
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
24180
+ className: "relative w-[36%] shrink-0",
24181
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
24182
+ className: "inline-flex items-center gap-4 rounded-full border border-border/60 bg-surface/40 px-5 py-2 text-[1.75em] font-semibold text-foreground/60",
24183
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "h-3 w-3 rounded-full bg-foreground/50" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "DIFF SCAN" })]
24184
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
24185
+ className: "mt-4 w-100 rounded-3xl p-1",
24186
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
24187
+ src: generateQRCode(share_url, isDark),
24188
+ alt: "二维码",
24189
+ className: "w-full h-full rounded-2xl object-contain"
24190
+ })
24191
+ })]
24192
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
24193
+ className: "relative flex-1 py-2",
24194
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
24195
+ className: "flex items-end justify-between gap-8",
24196
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
24197
+ className: "text-[1.65em] font-semibold tracking-[0.22em] text-foreground/45",
24198
+ children: "PROJECT STACK"
24199
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
24200
+ className: "mt-2 text-[3.3em] font-black leading-none text-foreground/85",
24201
+ children: "技术栈"
24202
+ })] }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-16 w-px bg-border/80" })]
24203
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
24204
+ className: "mt-8 grid grid-cols-4 gap-4",
24205
+ children: techStackItems.map(({ iconSrc, label }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
24206
+ className: "flex min-h-40 flex-col items-center justify-center gap-3 rounded-2xl border border-border/60 bg-surface/45 px-4 py-5 backdrop-blur-xs",
24207
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GlowImage, {
24208
+ glowStrength: isDark ? 1 : 0,
24209
+ blurRadius: 20,
24210
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
24211
+ "aria-hidden": true,
24212
+ src: iconSrc,
24213
+ alt: "",
24214
+ draggable: false,
24215
+ className: "h-16 w-16 object-contain drop-shadow-lg"
24216
+ })
24217
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
24218
+ className: "text-center text-[1.35em] font-bold leading-tight text-foreground/75",
24219
+ children: label
24220
+ })]
24221
+ }, label))
24222
+ })]
24223
+ })]
24224
+ }),
24225
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
24226
+ className: "text-4xl leading-relaxed text-foreground/60",
24227
+ children: [
24228
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "扫码查看实际运行代码从" }),
24229
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
24230
+ className: "font-bold text-foreground/80",
24231
+ children: [" v", props.data.localVersion]
24232
+ }),
24233
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: " 到 " }),
24234
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
24235
+ className: "font-bold text-foreground/80",
24236
+ children: [" v", props.data.remoteVersion]
24237
+ }),
24238
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: " 的差异" })
24239
+ ]
24240
+ })
24241
+ ]
24242
+ })
24243
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
24244
+ className: "flex flex-col gap-12 py-8",
24142
24245
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
24143
24246
  className: "w-120 h-auto",
24144
24247
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
@@ -24162,8 +24265,8 @@ var Changelog = import_react.memo((props) => {
24162
24265
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: " 的差异" })
24163
24266
  ]
24164
24267
  })]
24165
- }),
24166
- props.data.Tip === true && props.data.buildTime && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
24268
+ }) }),
24269
+ isUpdateTip && props.data.buildTime && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
24167
24270
  className: "flex gap-8 justify-center text-foreground/60",
24168
24271
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
24169
24272
  className: "text-4xl",
@@ -32947,7 +33050,7 @@ var renderErrorImage = async (ctx, opts = {}) => {
32947
33050
  * @returns
32948
33051
  */
32949
33052
  var getCandidateBots = () => {
32950
- return karin$1.getAllBotList().map((item) => item.bot).filter((bot) => bot.account.name !== "console");
33053
+ return karin.getAllBotList().map((item) => item.bot).filter((bot) => bot.account.name !== "console");
32951
33054
  };
32952
33055
  /**
32953
33056
  * 获取非console主机器人ID列表
@@ -32995,7 +33098,7 @@ var getReachableMasterBots = async (masters = config.master()) => {
32995
33098
  */
32996
33099
  var resolveUsableBot = async (selfId) => {
32997
33100
  if (selfId) {
32998
- const matchedBot = karin$1.getBot(selfId);
33101
+ const matchedBot = karin.getBot(selfId);
32999
33102
  if (matchedBot) return matchedBot;
33000
33103
  }
33001
33104
  const reachable = await getReachableMasterBots();
@@ -33003,12 +33106,12 @@ var resolveUsableBot = async (selfId) => {
33003
33106
  const { douyin, bilibili } = statBotId$1(Config.pushlist);
33004
33107
  const preferredBotId = douyin.botId || bilibili.botId;
33005
33108
  if (preferredBotId) {
33006
- const matchedBot = karin$1.getBot(preferredBotId);
33109
+ const matchedBot = karin.getBot(preferredBotId);
33007
33110
  if (matchedBot) return matchedBot;
33008
33111
  }
33009
- const fallbackBotId = karin$1.getAllBotID()[0];
33112
+ const fallbackBotId = karin.getAllBotID()[0];
33010
33113
  if (!fallbackBotId) return void 0;
33011
- return karin$1.getBot(fallbackBotId);
33114
+ return karin.getBot(fallbackBotId);
33012
33115
  };
33013
33116
  //#endregion
33014
33117
  //#region src/module/utils/ErrorHandler/utils.ts
@@ -33093,7 +33196,7 @@ var injectBotToEventForPushTask = async (event, businessName) => {
33093
33196
  if (!isPushTask(event, businessName)) return event;
33094
33197
  if (event?.bot) return event;
33095
33198
  const preferredBotId = typeof event?.selfId === "string" ? event.selfId : getPushTaskBotId();
33096
- const bot = (preferredBotId ? karin$1.getBot(preferredBotId) : void 0) ?? await resolveUsableBot(preferredBotId);
33199
+ const bot = (preferredBotId ? karin.getBot(preferredBotId) : void 0) ?? await resolveUsableBot(preferredBotId);
33097
33200
  if (!bot) throw new Error(`[ErrorHandler] push 任务缺少可用 bot 实例: ${businessName}`);
33098
33201
  const normalizedEvent = event ?? {};
33099
33202
  normalizedEvent.bot = bot;
@@ -33147,7 +33250,7 @@ var sendErrorToMaster = async (ctx, img, customPrefix) => {
33147
33250
  if (!target) return;
33148
33251
  try {
33149
33252
  const prefix = customPrefix || await buildErrorPrefix(ctx, isPush, target.botId);
33150
- await karin$1.sendMaster(target.botId, target.master, [segment.text(prefix), ...img]);
33253
+ await karin.sendMaster(target.botId, target.master, [segment.text(prefix), ...img]);
33151
33254
  } catch (err) {
33152
33255
  logger.error(`[ErrorHandler] 发送错误消息给主人失败: ${err}`);
33153
33256
  }
@@ -33182,7 +33285,7 @@ var sendErrorToAllMasters = async (ctx, img, customPrefix) => {
33182
33285
  const key = `${target.botId}:${target.master}`;
33183
33286
  if (notifiedSet.has(key)) continue;
33184
33287
  try {
33185
- await karin$1.sendMaster(target.botId, target.master, [segment.text(prefix), ...img]);
33288
+ await karin.sendMaster(target.botId, target.master, [segment.text(prefix), ...img]);
33186
33289
  notifiedSet.add(key);
33187
33290
  logger.debug(`[ErrorHandler] 已发送错误消息给主人: ${target.master} (via ${target.botId})`);
33188
33291
  } catch (err) {
@@ -33233,7 +33336,7 @@ var buildErrorPrefix = async (ctx, isPush, botId) => {
33233
33336
  const { options, event } = ctx;
33234
33337
  if (isPush) return `${options.businessName} 任务执行出错\n请尽快解决以消除警告`;
33235
33338
  const groupId = event && "groupId" in event ? event.groupId : "";
33236
- return `群:${(await karin$1.getBot(botId)?.getGroupInfo(groupId))?.groupName || "未知"}(${groupId})\n${options.businessName} 任务执行出错\n请尽快解决以消除警告`;
33339
+ return `群:${(await karin.getBot(botId)?.getGroupInfo(groupId))?.groupName || "未知"}(${groupId})\n${options.businessName} 任务执行出错\n请尽快解决以消除警告`;
33237
33340
  };
33238
33341
  //#endregion
33239
33342
  //#region src/module/utils/ErrorHandler/handler.ts
@@ -34199,6 +34302,139 @@ var buildBilibiliArticleRichText = (opus, content, useDarkTheme) => {
34199
34302
  if (content) return parseHtmlContentToRichText(content);
34200
34303
  return createRichTextDocument([], { platform: "bilibili" });
34201
34304
  };
34305
+ var MAX_FORWARD_TEXT_LENGTH = 1800;
34306
+ var normalizeForwardText = (text) => {
34307
+ return text.replace(/\r\n/g, "\n").replace(/[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
34308
+ };
34309
+ var splitForwardText = (text) => {
34310
+ const chunks = [];
34311
+ let rest = text;
34312
+ while (rest.length > MAX_FORWARD_TEXT_LENGTH) {
34313
+ let splitAt = rest.lastIndexOf("\n\n", MAX_FORWARD_TEXT_LENGTH);
34314
+ if (splitAt < MAX_FORWARD_TEXT_LENGTH / 2) splitAt = rest.lastIndexOf("\n", MAX_FORWARD_TEXT_LENGTH);
34315
+ if (splitAt < MAX_FORWARD_TEXT_LENGTH / 2) splitAt = MAX_FORWARD_TEXT_LENGTH;
34316
+ const chunk = rest.slice(0, splitAt).trim();
34317
+ if (chunk) chunks.push(chunk);
34318
+ rest = rest.slice(splitAt).trim();
34319
+ }
34320
+ if (rest) chunks.push(rest);
34321
+ return chunks;
34322
+ };
34323
+ var formatRichTextLink = (text, url) => {
34324
+ if (!url || url === text) return text;
34325
+ return `${text} (${url})`;
34326
+ };
34327
+ var inlineRichTextNodeToText = (node) => {
34328
+ switch (node.type) {
34329
+ case "text":
34330
+ case "mention":
34331
+ case "searchKeyword":
34332
+ case "topic":
34333
+ case "at":
34334
+ case "lottery":
34335
+ case "vote":
34336
+ case "viewPicture":
34337
+ case "hashtag": return node.text;
34338
+ case "emoji": return node.name;
34339
+ case "webLink": return formatRichTextLink(node.text, node.jumpUrl);
34340
+ case "lineBreak": return "\n";
34341
+ default: return "";
34342
+ }
34343
+ };
34344
+ /**
34345
+ * 将共享富文本文档转换为 Karin 消息段。
34346
+ *
34347
+ * 这里用于专栏正文的合并转发:文本节点保留为 text,图片节点保留为 image,
34348
+ * 让用户在客户端里能按原文顺序查看图文内容,而不是只能看渲染长图。
34349
+ */
34350
+ var buildBilibiliRichTextForwardMessage = async (document, options = {}) => {
34351
+ const elements = [];
34352
+ let textBuffer = "";
34353
+ let imageIndex = 0;
34354
+ const appendText = (text) => {
34355
+ if (!text) return;
34356
+ textBuffer += text;
34357
+ };
34358
+ const ensureBlockBreak = () => {
34359
+ if (!textBuffer) return;
34360
+ if (textBuffer.endsWith("\n\n")) return;
34361
+ textBuffer += textBuffer.endsWith("\n") ? "\n" : "\n\n";
34362
+ };
34363
+ const flushText = () => {
34364
+ const text = normalizeForwardText(textBuffer);
34365
+ textBuffer = "";
34366
+ for (const chunk of splitForwardText(text)) elements.push(segment.text(chunk));
34367
+ };
34368
+ const appendChildren = async (nodes) => {
34369
+ for (const node of nodes) await appendNode(node);
34370
+ };
34371
+ const appendImage = async (src, caption) => {
34372
+ flushText();
34373
+ const imageUrl = options.imageResolver ? await options.imageResolver(src, imageIndex) : src;
34374
+ imageIndex += 1;
34375
+ elements.push(segment.image(imageUrl));
34376
+ if (caption) {
34377
+ appendText(caption);
34378
+ ensureBlockBreak();
34379
+ }
34380
+ };
34381
+ const appendNode = async (node) => {
34382
+ const inlineText = inlineRichTextNodeToText(node);
34383
+ if (inlineText) {
34384
+ appendText(inlineText);
34385
+ return;
34386
+ }
34387
+ switch (node.type) {
34388
+ case "heading":
34389
+ case "paragraph":
34390
+ case "blockquote":
34391
+ case "listItem":
34392
+ ensureBlockBreak();
34393
+ await appendChildren(node.nodes);
34394
+ ensureBlockBreak();
34395
+ break;
34396
+ case "image":
34397
+ if (node.src) await appendImage(node.src, node.caption);
34398
+ break;
34399
+ case "list":
34400
+ ensureBlockBreak();
34401
+ for (const [index, item] of node.items.entries()) {
34402
+ appendText(node.ordered ? `${index + 1}. ` : "- ");
34403
+ await appendChildren(item.nodes);
34404
+ appendText("\n");
34405
+ }
34406
+ ensureBlockBreak();
34407
+ break;
34408
+ case "codeBlock":
34409
+ ensureBlockBreak();
34410
+ appendText(node.content);
34411
+ ensureBlockBreak();
34412
+ break;
34413
+ case "linkCard":
34414
+ ensureBlockBreak();
34415
+ appendText(formatRichTextLink(node.title, node.url));
34416
+ ensureBlockBreak();
34417
+ break;
34418
+ case "horizontalRule":
34419
+ ensureBlockBreak();
34420
+ appendText("---");
34421
+ ensureBlockBreak();
34422
+ break;
34423
+ default: break;
34424
+ }
34425
+ };
34426
+ const headerLines = [];
34427
+ if (options.title) headerLines.push(`标题:${options.title}`);
34428
+ if (options.summary) headerLines.push(`简介:${options.summary}`);
34429
+ if (options.shareUrl) headerLines.push(`链接:${options.shareUrl}`);
34430
+ if (headerLines.length > 0) {
34431
+ appendText(headerLines.join("\n"));
34432
+ ensureBlockBreak();
34433
+ }
34434
+ await appendChildren(document.nodes);
34435
+ flushText();
34436
+ return elements;
34437
+ };
34202
34438
  //#endregion
34203
34439
  //#region src/platform/bilibili/bilibili.ts
34204
34440
  var img$1;
@@ -34414,7 +34650,7 @@ var Bilibili = class extends Base {
34414
34650
  length: videoInfo.data.result.episodes.length
34415
34651
  });
34416
34652
  this.e.reply([...img$1, segment.text("请在120秒内输入 第?集 选择集数")]);
34417
- const context = await karin$1.ctx(this.e, {
34653
+ const context = await karin.ctx(this.e, {
34418
34654
  reply: true,
34419
34655
  throwOnTimeout: false
34420
34656
  });
@@ -34541,7 +34777,7 @@ var Bilibili = class extends Base {
34541
34777
  filepath: motionPhotoCoverPath,
34542
34778
  totalBytes: 0
34543
34779
  });
34544
- const motionPhotoCover = Config.app.imageSendMode === "base64" ? `base64://${fs.readFileSync(motionPhotoCoverPath).toString("base64")}` : `file://${motionPhotoCoverPath}`;
34780
+ const motionPhotoCover = processLocalImageFile(motionPhotoCoverPath);
34545
34781
  imgArray.push(segment.image(motionPhotoCover));
34546
34782
  hasPushedMotionPhotoCover = true;
34547
34783
  }
@@ -34901,28 +35137,19 @@ var Bilibili = class extends Base {
34901
35137
  const articleData = articleInfoBase.data.data;
34902
35138
  const articleContent = articleInfo.data.data;
34903
35139
  const body = buildBilibiliArticleRichText(articleContent.opus, articleContent.content, Common.useDarkTheme());
34904
- const extractImagesFromBody = (nodes) => {
34905
- const images = [];
34906
- for (const node of nodes) {
34907
- if (node.type === "image" && node.src) images.push(node.src);
34908
- if (node.nodes) images.push(...extractImagesFromBody(node.nodes));
34909
- if (node.items) images.push(...extractImagesFromBody(node.items));
34910
- }
34911
- return images;
34912
- };
34913
- const messageElements = [];
34914
- const articleImages = extractImagesFromBody(body.nodes);
34915
35140
  const title = articleData.title || "bilibili_article";
34916
- for (const [index, item] of articleImages.entries()) {
34917
- const imageUrl = await processImageUrl(item, title, index);
34918
- messageElements.push(segment.image(imageUrl));
34919
- }
34920
- if (messageElements.length === 1) this.e.reply(messageElements[0]);
34921
- if (messageElements.length > 1) {
35141
+ const shareUrl = articleContent.dyn_id_str ? `https://www.bilibili.com/opus/${articleContent.dyn_id_str}` : `https://www.bilibili.com/read/cv${articleContent.id}`;
35142
+ const messageElements = await buildBilibiliRichTextForwardMessage(body, {
35143
+ title: articleData.title,
35144
+ summary: articleData.summary,
35145
+ shareUrl,
35146
+ imageResolver: (src, index) => processImageUrl(src, title, index)
35147
+ });
35148
+ if (messageElements.length > 0) {
34922
35149
  const forwardMsg = common.makeForward(messageElements, Config.app.fakeForward ? this.e.sender.userId : this.e.bot.account.selfId, Config.app.fakeForward ? this.e.sender.nick : this.e.bot.account.name);
34923
35150
  await this.e.bot.sendForwardMsg(this.e.contact, forwardMsg, {
34924
- source: "图片合集",
34925
- summary: `查看${messageElements.length}张图片消息`,
35151
+ source: "专栏内容",
35152
+ summary: `查看${messageElements.length}条专栏内容`,
34926
35153
  prompt: "B站专栏动态解析结果",
34927
35154
  news: [{ text: "点击查看解析结果" }]
34928
35155
  });
@@ -34940,7 +35167,7 @@ var Bilibili = class extends Base {
34940
35167
  body,
34941
35168
  stats: articleData.stats,
34942
35169
  render_time: TimeFormatter.now(),
34943
- share_url: articleContent.dyn_id_str ? `https://www.bilibili.com/opus/${articleContent.dyn_id_str}` : `https://www.bilibili.com/read/cv${articleContent.id}`,
35170
+ share_url: shareUrl,
34944
35171
  dynamicTYPE: "专栏动态解析",
34945
35172
  user_shortid: userProfileData.data.data.card.mid,
34946
35173
  total_favorited: Count(userProfileData.data.data.like_num),
@@ -35141,9 +35368,9 @@ var Bilibili = class extends Base {
35141
35368
  }
35142
35369
  case false:
35143
35370
  /** 没登录(没配置ck)情况下直接发直链,传直链在DownLoadVideo()处理 */
35144
- logger.debug("视频 URL:", playUrlData.durl[0].url);
35371
+ logger.debug("视频 URL:", playUrlData.data.durl[0].url);
35145
35372
  if ((this.forceBurnDanmaku || Config.bilibili.burnDanmaku) && danmakuList.length > 0) {
35146
- const videoFile = await downloadFile(playUrlData.durl[0].url, {
35373
+ const videoFile = await downloadFile(playUrlData.data.durl[0].url, {
35147
35374
  title: `Bil_V_tmp_${Date.now()}.mp4`,
35148
35375
  headers: this.headers
35149
35376
  });
@@ -35175,7 +35402,7 @@ var Bilibili = class extends Base {
35175
35402
  } else await Common.removeFile(videoFile.filepath, true);
35176
35403
  }
35177
35404
  } else await downloadVideo(this.e, {
35178
- video_url: playUrlData.durl[0].url,
35405
+ video_url: playUrlData.data.durl[0].url,
35179
35406
  title: {
35180
35407
  timestampTitle: `tmp_${Date.now()}.mp4`,
35181
35408
  originTitle: `${this.downloadfilename}.mp4`
@@ -35507,32 +35734,6 @@ var getStringDisplayWidth$1 = (str) => {
35507
35734
  }
35508
35735
  return width;
35509
35736
  };
35510
- /**
35511
- * 提取专栏中的所有图片URL
35512
- * @param content
35513
- * @returns
35514
- */
35515
- var extractArticleImages = (content) => {
35516
- const images = [];
35517
- if (content.opus?.content?.paragraphs) {
35518
- for (const paragraph of content.opus.content.paragraphs) if (paragraph.para_type === 2 && paragraph.pic?.pics) {
35519
- for (const pic of paragraph.pic.pics) if (pic.url) {
35520
- const url = pic.url.startsWith("//") ? `https:${pic.url}` : pic.url;
35521
- images.push(url);
35522
- }
35523
- }
35524
- }
35525
- if (content.content && typeof content.content === "string") {
35526
- const imgRegex = /<img[^>]+src="([^"]+)"/gi;
35527
- let match;
35528
- while ((match = imgRegex.exec(content.content)) !== null) {
35529
- let url = match[1];
35530
- if (url.startsWith("//")) url = `https:${url}`;
35531
- images.push(url);
35532
- }
35533
- }
35534
- return images;
35535
- };
35536
35737
  //#endregion
35537
35738
  //#region src/platform/bilibili/comments.ts
35538
35739
  /**
@@ -36057,7 +36258,7 @@ var Bilibilipush = class extends Base {
36057
36258
  injectBotToEventForRender(targets) {
36058
36259
  const targetBotId = targets.find((item) => item.botId)?.botId;
36059
36260
  if (!targetBotId) return;
36060
- const bot = karin$1.getBot(targetBotId);
36261
+ const bot = karin.getBot(targetBotId);
36061
36262
  if (!bot) return;
36062
36263
  const eventWithBot = this.e;
36063
36264
  eventWithBot.bot = bot;
@@ -36094,7 +36295,7 @@ var Bilibilipush = class extends Base {
36094
36295
  this.ensureConfigFields(Config.pushlist.bilibili);
36095
36296
  const deletedCount = await cleanOldDynamicCache("bilibili");
36096
36297
  if (deletedCount > 0) logger.info(`已清理 ${deletedCount} 条过期的B站动态缓存记录`);
36097
- const registeredBotIds = karin$1.getAllBotID();
36298
+ const registeredBotIds = karin.getAllBotID();
36098
36299
  const filteredPushList = this.filterPushListByRegisteredBots(Config.pushlist.bilibili, registeredBotIds);
36099
36300
  if (filteredPushList.length === 0) {
36100
36301
  logger.warn("没有已注册的 bot 可用于B站推送");
@@ -36153,6 +36354,7 @@ var Bilibilipush = class extends Base {
36153
36354
  if (skip) logger.warn(`动态 https://t.bilibili.com/${dynamicId} 已被处理,跳过`);
36154
36355
  let send_video = true;
36155
36356
  let img = [];
36357
+ let articleForwardPayload = null;
36156
36358
  this.injectBotToEventForRender(data[dynamicId].targets);
36157
36359
  if (!skip) {
36158
36360
  const userINFO = await this.amagi.bilibili.fetcher.fetchUserCard({
@@ -36481,6 +36683,14 @@ var Bilibilipush = class extends Base {
36481
36683
  });
36482
36684
  const articleData = articleInfoBase.data.data;
36483
36685
  const articleContent = articleInfo.data.data;
36686
+ const body = buildBilibiliArticleRichText(articleContent.opus, articleContent.content, Common.useDarkTheme());
36687
+ const shareUrl = articleContent.dyn_id_str ? `https://www.bilibili.com/opus/${articleContent.dyn_id_str}` : `https://www.bilibili.com/read/cv${articleContent.id}`;
36688
+ articleForwardPayload = {
36689
+ body,
36690
+ title: articleData.title,
36691
+ summary: articleData.summary,
36692
+ shareUrl
36693
+ };
36484
36694
  img = await Render(this.e, "bilibili/dynamic/DYNAMIC_TYPE_ARTICLE", {
36485
36695
  usernameMeta: getUsernameMetadata(data[dynamicId].Dynamic_Data.modules.module_author),
36486
36696
  avatar_url: data[dynamicId].Dynamic_Data.modules.module_author.face,
@@ -36495,10 +36705,10 @@ var Bilibilipush = class extends Base {
36495
36705
  banner_url: articleData.banner_url || articleData.image_urls && articleData.image_urls[0] || "",
36496
36706
  categories: articleData.categories || [],
36497
36707
  words: articleData.words || 0,
36498
- body: buildBilibiliArticleRichText(articleContent.opus, articleContent.content, Common.useDarkTheme()),
36708
+ body,
36499
36709
  stats: articleData.stats,
36500
36710
  render_time: TimeFormatter.now(),
36501
- share_url: articleContent.dyn_id_str ? `https://www.bilibili.com/opus/${articleContent.dyn_id_str}` : `https://www.bilibili.com/read/cv${articleContent.id}`,
36711
+ share_url: shareUrl,
36502
36712
  dynamicTYPE: "专栏动态推送"
36503
36713
  }, { skipWatermark: true });
36504
36714
  break;
@@ -36516,13 +36726,23 @@ var Bilibilipush = class extends Base {
36516
36726
  let status = null;
36517
36727
  if (!skip) {
36518
36728
  const { groupId, botId } = target;
36519
- const bot = karin$1.getBot(botId);
36520
- const Contact = karin$1.contactGroup(groupId);
36729
+ const bot = karin.getBot(botId);
36730
+ const Contact = karin.contactGroup(groupId);
36521
36731
  const eventWithBot = this.e;
36522
36732
  eventWithBot.bot = bot;
36523
36733
  eventWithBot.selfId = botId;
36524
36734
  const watermarkedImg = img ? applyWatermarkToImages(img, this.e) : [];
36525
- status = await karin$1.sendMsg(botId, Contact, [...watermarkedImg]);
36735
+ const parseUrl = buildParseUrl(data[dynamicId]);
36736
+ const parseButton = bot?.adapter?.name === "QQ Official Bot" && parseUrl ? [segment.button([{
36737
+ text: "解析",
36738
+ callback: true,
36739
+ data: `#解析${parseUrl}`
36740
+ }, {
36741
+ text: "帮助",
36742
+ callback: true,
36743
+ data: `#kkk帮助`
36744
+ }])] : [];
36745
+ status = await karin.sendMsg(botId, Contact, [...watermarkedImg, ...parseButton]);
36526
36746
  if (Config.bilibili.push.parsedynamic && status.messageId) switch (data[dynamicId].dynamic_type) {
36527
36747
  case "DYNAMIC_TYPE_AV":
36528
36748
  if (send_video) {
@@ -36557,7 +36777,7 @@ var Bilibilipush = class extends Base {
36557
36777
  /** 获取第一个视频流的大小 */
36558
36778
  videoSize = await getvideosize(correctList.videoList[0].base_url, playUrlData.data.data.dash.audio[0].base_url, data[dynamicId].Dynamic_Data.modules.module_dynamic.major.archive.bvid);
36559
36779
  if (Config.app.usefilelimit && Number(videoSize) > Number(Config.app.filelimit) && !Config.app.compress) {
36560
- await karin$1.sendMsg(botId, Contact, [segment.text(`设定的最大上传大小为 ${Config.app.filelimit}MB\n当前解析到的视频大小为 ${Number(videoSize)}MB\n视频太大了,还是去B站看吧~`), segment.reply(status.messageId)]);
36780
+ await karin.sendMsg(botId, Contact, [segment.text(`设定的最大上传大小为 ${Config.app.filelimit}MB\n当前解析到的视频大小为 ${Number(videoSize)}MB\n视频太大了,还是去B站看吧~`), segment.reply(status.messageId)]);
36561
36781
  break;
36562
36782
  }
36563
36783
  logger.mark(`当前处于自动推送状态,解析到的视频大小为 ${logger.yellow(Number(videoSize))} MB`);
@@ -36680,7 +36900,7 @@ var Bilibilipush = class extends Base {
36680
36900
  filepath: motionPhotoCoverPath,
36681
36901
  totalBytes: 0
36682
36902
  });
36683
- const motionPhotoCover = Config.app.imageSendMode === "base64" ? `base64://${fs.readFileSync(motionPhotoCoverPath).toString("base64")}` : `file://${motionPhotoCoverPath}`;
36903
+ const motionPhotoCover = processLocalImageFile(motionPhotoCoverPath);
36684
36904
  imgArray.push(segment.image(motionPhotoCover));
36685
36905
  hasPushedMotionPhotoCover = true;
36686
36906
  }
@@ -36721,23 +36941,35 @@ var Bilibilipush = class extends Base {
36721
36941
  break;
36722
36942
  }
36723
36943
  case "DYNAMIC_TYPE_ARTICLE": {
36724
- const articleInfo = await this.amagi.bilibili.fetcher.fetchArticleContent({
36725
- id: data[dynamicId].Dynamic_Data.basic.rid_str,
36726
- typeMode: "strict"
36727
- });
36728
- const messageElements = [];
36729
- const articleImages = extractArticleImages(articleInfo.data.data);
36730
- const title = articleInfo.data.data.title || "bilibili_article";
36731
- for (const [index, item] of articleImages.entries()) {
36732
- const imageUrl = await processImageUrl(item, title, index);
36733
- messageElements.push(segment.image(imageUrl));
36944
+ let payload = articleForwardPayload;
36945
+ if (!payload) {
36946
+ const articleInfoBase = await this.amagi.bilibili.fetcher.fetchArticleInfo({
36947
+ id: data[dynamicId].Dynamic_Data.basic.rid_str,
36948
+ typeMode: "strict"
36949
+ });
36950
+ const articleContent = (await this.amagi.bilibili.fetcher.fetchArticleContent({
36951
+ id: data[dynamicId].Dynamic_Data.basic.rid_str,
36952
+ typeMode: "strict"
36953
+ })).data.data;
36954
+ payload = {
36955
+ body: buildBilibiliArticleRichText(articleContent.opus, articleContent.content, Common.useDarkTheme()),
36956
+ title: articleInfoBase.data.data.title,
36957
+ summary: articleInfoBase.data.data.summary,
36958
+ shareUrl: articleContent.dyn_id_str ? `https://www.bilibili.com/opus/${articleContent.dyn_id_str}` : `https://www.bilibili.com/read/cv${articleContent.id}`
36959
+ };
36734
36960
  }
36735
- if (messageElements.length === 1) bot.sendMsg(Contact, messageElements);
36736
- if (messageElements.length > 1) {
36961
+ const title = payload.title || "bilibili_article";
36962
+ const messageElements = await buildBilibiliRichTextForwardMessage(payload.body, {
36963
+ title: payload.title,
36964
+ summary: payload.summary,
36965
+ shareUrl: payload.shareUrl,
36966
+ imageResolver: (src, index) => processImageUrl(src, title, index)
36967
+ });
36968
+ if (messageElements.length > 0) {
36737
36969
  const forwardMsg = common.makeForward(messageElements, botId, bot.account.name);
36738
36970
  await bot.sendForwardMsg(Contact, forwardMsg, {
36739
- source: "图片合集",
36740
- summary: `查看${messageElements.length}张图片消息`,
36971
+ source: "专栏内容",
36972
+ summary: `查看${messageElements.length}条专栏内容`,
36741
36973
  prompt: "B站专栏动态解析结果",
36742
36974
  news: [{ text: "点击查看解析结果" }]
36743
36975
  });
@@ -36868,6 +37100,7 @@ var Bilibilipush = class extends Base {
36868
37100
  } else {
36869
37101
  await bilibiliDBInstance.subscribeBilibiliUser(groupId, botId, host_mid, data.data.card.name);
36870
37102
  existingItem.group_id.push(`${groupId}:${botId}`);
37103
+ if (!existingItem.pushTypes || existingItem.pushTypes.length === 0) existingItem.pushTypes = [...allBilibiliPushTypes];
36871
37104
  Config.Modify("pushlist", "bilibili", config.bilibili);
36872
37105
  await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${data.data.card.name}\nUID:${host_mid}`);
36873
37106
  if (Config.bilibili.push.switch === false) await this.e.reply("请发送「#设置B站推送开启」以进行推送");
@@ -36879,7 +37112,8 @@ var Bilibilipush = class extends Base {
36879
37112
  switch: true,
36880
37113
  host_mid,
36881
37114
  group_id: [`${groupId}:${botId}`],
36882
- remark: data.data.card.name
37115
+ remark: data.data.card.name,
37116
+ pushTypes: [...allBilibiliPushTypes]
36883
37117
  });
36884
37118
  Config.Modify("pushlist", "bilibili", config.bilibili);
36885
37119
  await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${data.data.card.name}\nUID:${host_mid}`);
@@ -36989,6 +37223,22 @@ var br = (data) => {
36989
37223
  return data = data.replace(/\n/g, "<br>");
36990
37224
  };
36991
37225
  /**
37226
+ * 根据动态类型构造用于「解析」按钮的地址。
37227
+ * 视频动态使用 BV 视频地址,其余动态使用动态地址;直播动态返回空字符串(不追加按钮)。
37228
+ * @param PushItem 推送项
37229
+ * @returns 解析地址,无法解析时返回空字符串
37230
+ */
37231
+ var buildParseUrl = (PushItem) => {
37232
+ switch (PushItem.dynamic_type) {
37233
+ case DynamicType.AV: {
37234
+ const bvid = PushItem.Dynamic_Data.modules.module_dynamic.major?.archive?.bvid;
37235
+ return bvid ? `https://www.bilibili.com/video/${bvid}` : "";
37236
+ }
37237
+ case DynamicType.LIVE_RCMD: return "";
37238
+ default: return `https://t.bilibili.com/${PushItem.Dynamic_Data.id_str}`;
37239
+ }
37240
+ };
37241
+ /**
36992
37242
  * 判断标题是否有屏蔽词或屏蔽标签
36993
37243
  * @param PushItem 推送项
36994
37244
  * @returns 是否应该跳过推送
@@ -37045,7 +37295,7 @@ registerErrorStrategy({
37045
37295
  await event.reply([segment.text("检测到B站风控,请在「120 秒内」扫描二维码完成验证后发送验证结果\n"), ...img]);
37046
37296
  await sendErrorToMaster(ctx, img);
37047
37297
  await sendErrorToAllMasters(ctx, img);
37048
- const resultCtx = await karin$1.ctx(event);
37298
+ const resultCtx = await karin.ctx(event);
37049
37299
  if (!resultCtx) return "continue";
37050
37300
  const params = new URLSearchParams(resultCtx.msg);
37051
37301
  const validate = params.get("validate");
@@ -37868,7 +38118,7 @@ var DouYin = class DouYin extends Base {
37868
38118
  filepath: motionPhotoCoverPath,
37869
38119
  totalBytes: 0
37870
38120
  });
37871
- const motionPhotoCover = Config.app.imageSendMode === "base64" ? `base64://${fs.readFileSync(motionPhotoCoverPath).toString("base64")}` : `file://${motionPhotoCoverPath}`;
38121
+ const motionPhotoCover = processLocalImageFile(motionPhotoCoverPath);
37872
38122
  processedImages.push(segment.image(motionPhotoCover));
37873
38123
  hasPushedMotionPhotoCover = true;
37874
38124
  }
@@ -38023,7 +38273,7 @@ var DouYin = class DouYin extends Base {
38023
38273
  filepath: motionPhotoCoverPath,
38024
38274
  totalBytes: 0
38025
38275
  });
38026
- const motionPhotoCover = Config.app.imageSendMode === "base64" ? `base64://${fs.readFileSync(motionPhotoCoverPath).toString("base64")}` : `file://${motionPhotoCoverPath}`;
38276
+ const motionPhotoCover = processLocalImageFile(motionPhotoCoverPath);
38027
38277
  images.push(segment.image(motionPhotoCover));
38028
38278
  hasPushedMotionPhotoCover = true;
38029
38279
  }
@@ -38339,7 +38589,7 @@ var DouYin = class DouYin extends Base {
38339
38589
  });
38340
38590
  await this.e.reply(img);
38341
38591
  logger.debug(`等待用户选择视频,开始计时,${timeoutSeconds}秒后终止等待...`);
38342
- const context = await karin$1.ctx(this.e, {
38592
+ const context = await karin.ctx(this.e, {
38343
38593
  throwOnTimeout: false,
38344
38594
  time: timeoutSeconds
38345
38595
  });
@@ -39523,7 +39773,7 @@ var DouYinpush = class extends Base {
39523
39773
  injectBotToEventForRender(targets) {
39524
39774
  const targetBotId = targets.find((item) => item.botId)?.botId;
39525
39775
  if (!targetBotId) return;
39526
- const bot = karin$1.getBot(targetBotId);
39776
+ const bot = karin.getBot(targetBotId);
39527
39777
  if (!bot) return;
39528
39778
  const eventWithBot = this.e;
39529
39779
  eventWithBot.bot = bot;
@@ -39538,7 +39788,7 @@ var DouYinpush = class extends Base {
39538
39788
  if (deletedCount > 0) logger.info(`已清理 ${deletedCount} 条过期的抖音作品缓存记录`);
39539
39789
  if (await this.checkremark()) return true;
39540
39790
  await this.ensureConfigFields(Config.pushlist.douyin);
39541
- const registeredBotIds = karin$1.getAllBotID();
39791
+ const registeredBotIds = karin.getAllBotID();
39542
39792
  const filteredPushList = this.filterPushListByRegisteredBots(Config.pushlist.douyin, registeredBotIds);
39543
39793
  if (filteredPushList.length === 0) {
39544
39794
  logger.warn("没有已注册的 bot 可用于抖音推送");
@@ -39726,13 +39976,22 @@ var DouYinpush = class extends Base {
39726
39976
  let status = { message_id: "" };
39727
39977
  const { groupId, botId } = target;
39728
39978
  if (!skip) {
39729
- const Contact = karin$1.contactGroup(groupId);
39730
- const bot = karin$1.getBot(botId);
39979
+ const Contact = karin.contactGroup(groupId);
39980
+ const bot = karin.getBot(botId);
39731
39981
  const eventWithBot = this.e;
39732
39982
  eventWithBot.bot = bot;
39733
39983
  eventWithBot.selfId = botId;
39734
39984
  const watermarkedImg = img ? applyWatermarkToImages(img, this.e) : [];
39735
- status = await karin$1.sendMsg(botId, Contact, [...watermarkedImg]);
39985
+ const parseButton = bot?.adapter?.name === "QQ Official Bot" && pushItem.pushType !== "live" && Detail_Data.share_url ? [segment.button([{
39986
+ text: "解析",
39987
+ callback: true,
39988
+ data: `#解析${Detail_Data.share_url}`
39989
+ }, {
39990
+ text: "帮助",
39991
+ callback: true,
39992
+ data: `#kkk帮助`
39993
+ }])] : [];
39994
+ status = await karin.sendMsg(botId, Contact, [...watermarkedImg, ...parseButton]);
39736
39995
  if (pushItem.pushType === "live" && "room_data" in pushItem.Detail_Data && status.message_id) await douyinDBInstance.updateLiveStatus(pushItem.sec_uid, true);
39737
39996
  if (Config.douyin.push.parsedynamic && status.message_id) {
39738
39997
  const workTypeInfo = getWorkTypeInfo(Detail_Data);
@@ -39858,7 +40117,7 @@ var DouYinpush = class extends Base {
39858
40117
  filepath: motionPhotoCoverPath,
39859
40118
  totalBytes: 0
39860
40119
  });
39861
- const motionPhotoCover = Config.app.imageSendMode === "base64" ? `base64://${fs.readFileSync(motionPhotoCoverPath).toString("base64")}` : `file://${motionPhotoCoverPath}`;
40120
+ const motionPhotoCover = processLocalImageFile(motionPhotoCoverPath);
39862
40121
  images.push(segment.image(motionPhotoCover));
39863
40122
  hasPushedMotionPhotoCover = true;
39864
40123
  }
@@ -39879,7 +40138,7 @@ var DouYinpush = class extends Base {
39879
40138
  });
39880
40139
  images.push(...tipImg);
39881
40140
  }
39882
- const bot = karin$1.getBot(botId);
40141
+ const bot = karin.getBot(botId);
39883
40142
  const Element = common.makeForward(images, botId, bot.account.name);
39884
40143
  try {
39885
40144
  await bot.sendForwardMsg(Contact, Element, {
@@ -39981,7 +40240,7 @@ var DouYinpush = class extends Base {
39981
40240
  filepath: motionPhotoCoverPath,
39982
40241
  totalBytes: 0
39983
40242
  });
39984
- const motionPhotoCover = Config.app.imageSendMode === "base64" ? `base64://${fs.readFileSync(motionPhotoCoverPath).toString("base64")}` : `file://${motionPhotoCoverPath}`;
40243
+ const motionPhotoCover = processLocalImageFile(motionPhotoCoverPath);
39985
40244
  processedImages.push(segment.image(motionPhotoCover));
39986
40245
  hasPushedMotionPhotoCover = true;
39987
40246
  }
@@ -40002,7 +40261,7 @@ var DouYinpush = class extends Base {
40002
40261
  });
40003
40262
  processedImages.push(...tipImg);
40004
40263
  }
40005
- const bot = karin$1.getBot(botId);
40264
+ const bot = karin.getBot(botId);
40006
40265
  const Element = common.makeForward(processedImages, botId, bot.account.name);
40007
40266
  try {
40008
40267
  await bot.sendForwardMsg(Contact, Element, {
@@ -40024,7 +40283,7 @@ var DouYinpush = class extends Base {
40024
40283
  const imageUrl = await processImageUrl(image_url, Detail_Data.desc, index);
40025
40284
  imageres.push(segment.image(imageUrl));
40026
40285
  }
40027
- const bot = karin$1.getBot(botId);
40286
+ const bot = karin.getBot(botId);
40028
40287
  if (imageres.length === 1) {
40029
40288
  const imageUrl = await processImageUrl(image_url, Detail_Data.desc);
40030
40289
  await bot.sendMsg(Contact, [segment.image(imageUrl)]);
@@ -40754,6 +41013,42 @@ var Xiaohongshu = class extends Base {
40754
41013
  this.e = e;
40755
41014
  this.type = iddata?.type;
40756
41015
  }
41016
+ async fetchConfiguredNoteComments(data) {
41017
+ const targetCount = Math.max(1, Config.xiaohongshu.numcomment);
41018
+ const firstPage = await this.amagi.xiaohongshu.fetcher.fetchNoteComments({
41019
+ typeMode: "strict",
41020
+ note_id: data.note_id,
41021
+ xsec_token: data.xsec_token
41022
+ });
41023
+ const comments = [...firstPage.data.data.comments ?? []];
41024
+ let cursor = firstPage.data.data.cursor;
41025
+ let hasMore = firstPage.data.data.has_more;
41026
+ const seenCursors = /* @__PURE__ */ new Set();
41027
+ while (comments.length < targetCount && hasMore && cursor && !seenCursors.has(cursor)) {
41028
+ seenCursors.add(cursor);
41029
+ const nextPage = await this.amagi.xiaohongshu.fetcher.fetchNoteComments({
41030
+ typeMode: "strict",
41031
+ note_id: data.note_id,
41032
+ cursor,
41033
+ xsec_token: data.xsec_token
41034
+ });
41035
+ comments.push(...nextPage.data.data.comments ?? []);
41036
+ cursor = nextPage.data.data.cursor;
41037
+ hasMore = nextPage.data.data.has_more;
41038
+ }
41039
+ return {
41040
+ ...firstPage,
41041
+ data: {
41042
+ ...firstPage.data,
41043
+ data: {
41044
+ ...firstPage.data.data,
41045
+ comments,
41046
+ cursor,
41047
+ has_more: hasMore
41048
+ }
41049
+ }
41050
+ };
41051
+ }
40757
41052
  async XiaohongshuHandler(data) {
40758
41053
  if (Config.amagi.cookies.xiaohongshu === "") throw new Error("我还没有小红书的 Cookies,暂时无法解析呢 ~");
40759
41054
  if (Config.app.parseTip) await this.e.reply("检测到小红书链接,开始解析");
@@ -40777,11 +41072,7 @@ var Xiaohongshu = class extends Base {
40777
41072
  this.e.reply(noteInfoImg);
40778
41073
  }
40779
41074
  if (Config.xiaohongshu.sendContent.some((item) => item === "comment")) {
40780
- const CommentData = await this.amagi.xiaohongshu.fetcher.fetchNoteComments({
40781
- typeMode: "strict",
40782
- note_id: data.note_id,
40783
- xsec_token: data.xsec_token
40784
- });
41075
+ const CommentData = await this.fetchConfiguredNoteComments(data);
40785
41076
  if (!CommentData.data.data.comments || CommentData.data.data.comments.length === 0) await this.e.reply("这个笔记没有评论 ~");
40786
41077
  else {
40787
41078
  const processedComments = await xiaohongshuComments(CommentData.data, formattedEmojis);
@@ -40873,7 +41164,7 @@ var Xiaohongshu = class extends Base {
40873
41164
  filepath: motionPhotoCoverPath,
40874
41165
  totalBytes: 0
40875
41166
  });
40876
- const motionPhotoCover = Config.app.imageSendMode === "base64" ? `base64://${fs.readFileSync(motionPhotoCoverPath).toString("base64")}` : `file://${motionPhotoCoverPath}`;
41167
+ const motionPhotoCover = processLocalImageFile(motionPhotoCoverPath);
40877
41168
  processedImages.push(segment.image(motionPhotoCover));
40878
41169
  hasPushedMotionPhotoCover = true;
40879
41170
  hasGeneratedLivePhoto = true;
@@ -41299,7 +41590,7 @@ var douyinLogin = async (e) => {
41299
41590
  while (verifyAttempts < maxAttempts && !verifySuccess) {
41300
41591
  verifyAttempts++;
41301
41592
  logger.debug(`验证码输入尝试 ${verifyAttempts}/${maxAttempts}`);
41302
- const ctx = await Promise.race([karin.ctx(e, { reply: true }), new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("2FA_TIMEOUT")), 6e4))]).catch(async (error) => {
41593
+ const ctx = await Promise.race([karin$1.ctx(e, { reply: true }), new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("2FA_TIMEOUT")), 6e4))]).catch(async (error) => {
41303
41594
  if (error.message === "2FA_TIMEOUT") {
41304
41595
  logger.warn("2FA验证码输入超时");
41305
41596
  clearTimeout(timer);
@@ -41456,12 +41747,12 @@ var handleCacheCleanup = wrapWithErrorHandler(async () => {
41456
41747
  const twoHoursAgo = Date.now() - 7200 * 1e3;
41457
41748
  const videoDeleted = removeOldFiles(Common.tempDri.video, twoHoursAgo);
41458
41749
  logger.debug(`${Common.tempDri.video} 目录下已删除 ${videoDeleted} 个文件`);
41459
- if (Config.app.imageSendMode === "file") {
41750
+ if (Config.app.imageSendMode !== "url") {
41460
41751
  const imageDeleted = removeOldFiles(Common.tempDri.images, twoHoursAgo);
41461
41752
  logger.debug(`${Common.tempDri.images} 目录下已删除 ${imageDeleted} 个文件`);
41462
41753
  }
41463
41754
  }, { businessName: "缓存自动删除" });
41464
- var task = Config.app.removeCache && karin$1.task("[kkk-缓存自动删除]", "*/30 * * * *", handleCacheCleanup, { log: false });
41755
+ var task = Config.app.removeCache && karin.task("[kkk-缓存自动删除]", "*/30 * * * *", handleCacheCleanup, { log: false });
41465
41756
  var handleBilibiliLogin = wrapWithErrorHandler(async (e) => {
41466
41757
  await bilibiliLogin(e);
41467
41758
  return true;
@@ -41480,15 +41771,15 @@ var handlTestWrapWithErrorHandler = wrapWithErrorHandler(async (_e) => {
41480
41771
  logger.fatal("测试致命日志");
41481
41772
  throw Error("测试异常");
41482
41773
  }, { businessName: "测试命令-错误捕获" });
41483
- var biLogin = karin$1.command(/^#?(kkk)?\s*B站\s*(扫码)?\s*登录$/i, handleBilibiliLogin, {
41774
+ var biLogin = karin.command(/^#?(kkk)?\s*B站\s*(扫码)?\s*登录$/i, handleBilibiliLogin, {
41484
41775
  perm: Config.bilibili.loginPerm,
41485
41776
  name: "kkk-ck管理"
41486
41777
  });
41487
- var dylogin = karin$1.command(/^#?(kkk)?抖音(扫码)?登录$/, handleDouyinLogin, {
41778
+ var dylogin = karin.command(/^#?(kkk)?抖音(扫码)?登录$/, handleDouyinLogin, {
41488
41779
  perm: Config.douyin.loginPerm,
41489
41780
  name: "kkk-ck管理"
41490
41781
  });
41491
- var testWrapWithErrorHandler = process.env.NODE_ENV === "development" ? karin$1.command(/^#?(kkk)?\s*测试\s*错误捕获$/i, handlTestWrapWithErrorHandler, {
41782
+ var testWrapWithErrorHandler = process.env.NODE_ENV === "development" ? karin.command(/^#?(kkk)?\s*测试\s*错误捕获$/i, handlTestWrapWithErrorHandler, {
41492
41783
  perm: Config.bilibili.loginPerm,
41493
41784
  name: "kkk-测试命令-错误捕获"
41494
41785
  }) : null;
@@ -41677,8 +41968,8 @@ var handleVersion = wrapWithErrorHandler(async (e) => {
41677
41968
  e.reply(img);
41678
41969
  return true;
41679
41970
  }, { businessName: "KKK版本" });
41680
- var help = karin$1.command(/^#?kkk帮助$/, handleHelp, { name: "kkk-帮助" });
41681
- var version = karin$1.command(/^#?kkk(版本|更新日志)$/, handleVersion, { name: "kkk-版本" });
41971
+ var help = karin.command(/^#?kkk帮助$/, handleHelp, { name: "kkk-帮助" });
41972
+ var version = karin.command(/^#?kkk(版本|更新日志)$/, handleVersion, { name: "kkk-版本" });
41682
41973
  //#endregion
41683
41974
  //#region src/apps/push.ts
41684
41975
  var handleDouyinPush = wrapWithErrorHandler(async () => {
@@ -41844,42 +42135,42 @@ var handleGlobalIgnore = wrapWithErrorHandler(async (e) => {
41844
42135
  }
41845
42136
  return true;
41846
42137
  }, { businessName: "推送全局忽略" });
41847
- var douyinPush = Config.douyin.push.switch && karin$1.task("抖音推送", Config.douyin.push.cron, handleDouyinPush, {
42138
+ var douyinPush = Config.douyin.push.switch && karin.task("抖音推送", Config.douyin.push.cron, handleDouyinPush, {
41848
42139
  log: true,
41849
42140
  type: "skip"
41850
42141
  });
41851
- var bilibiliPush = Config.bilibili.push.switch && karin$1.task("B站推送", Config.bilibili.push.cron, handleBilibiliPush, {
42142
+ var bilibiliPush = Config.bilibili.push.switch && karin.task("B站推送", Config.bilibili.push.cron, handleBilibiliPush, {
41852
42143
  log: true,
41853
42144
  type: "skip"
41854
42145
  });
41855
- var forcePush = karin$1.command(/#(抖音|B站)(全部)?强制推送/, handleForcePush, {
42146
+ var forcePush = karin.command(/#(抖音|B站)(全部)?强制推送/, handleForcePush, {
41856
42147
  name: "𝑪𝒊𝒂𝒍𝒍𝒐~(∠・ω< )⌒★",
41857
42148
  perm: "master",
41858
42149
  event: "message.group"
41859
42150
  });
41860
- var setdyPush = karin$1.command(/^#设置抖音推送/, handleSetDouyinPush, {
42151
+ var setdyPush = karin.command(/^#设置抖音推送/, handleSetDouyinPush, {
41861
42152
  name: "kkk-推送功能-设置",
41862
42153
  event: "message.group",
41863
42154
  perm: Config.douyin.push.permission
41864
42155
  });
41865
- var setbiliPush = karin$1.command(/^#设置[bB]站推送/, handleSetBilibiliPush, {
42156
+ var setbiliPush = karin.command(/^#设置[bB]站推送/, handleSetBilibiliPush, {
41866
42157
  name: "kkk-推送功能-设置",
41867
42158
  event: "message.group",
41868
42159
  perm: Config.bilibili.push.permission
41869
42160
  });
41870
- var bilibiliPushList = karin$1.command(/^#?[bB]站推送列表$/, handleBilibiliPushList, {
42161
+ var bilibiliPushList = karin.command(/^#?[bB]站推送列表$/, handleBilibiliPushList, {
41871
42162
  name: "kkk-推送功能-列表",
41872
42163
  event: "message.group"
41873
42164
  });
41874
- var douyinPushList = karin$1.command(/^#?抖音推送列表$/, handleDouyinPushList, {
42165
+ var douyinPushList = karin.command(/^#?抖音推送列表$/, handleDouyinPushList, {
41875
42166
  name: "kkk-推送功能-列表",
41876
42167
  event: "message.group"
41877
42168
  });
41878
- var changeBotID = karin$1.command(/^#kkk设置推送机器人/, handleChangeBotID, {
42169
+ var changeBotID = karin.command(/^#kkk设置推送机器人/, handleChangeBotID, {
41879
42170
  name: "kkk-推送功能-设置",
41880
42171
  perm: "master"
41881
42172
  });
41882
- var globalIgnore = karin$1.command(/^#kkk推送全局忽略/, handleGlobalIgnore, {
42173
+ var globalIgnore = karin.command(/^#kkk推送全局忽略/, handleGlobalIgnore, {
41883
42174
  name: "kkk-推送功能-全局忽略",
41884
42175
  perm: "master",
41885
42176
  event: "message.group",
@@ -41954,7 +42245,7 @@ async function getHostByConfig() {
41954
42245
  * 生成登录二维码(仅私发给主人)
41955
42246
  */
41956
42247
  var handleQrLogin = wrapWithErrorHandler(async (e) => {
41957
- const bot = karin$1.getBot(e.selfId);
42248
+ const bot = karin.getBot(e.selfId);
41958
42249
  const userId = e.userId;
41959
42250
  if (e.isGroup) {
41960
42251
  if (!(await bot?.getFriendList())?.some((f) => f.userId === userId)) {
@@ -41979,11 +42270,11 @@ var handleQrLogin = wrapWithErrorHandler(async (e) => {
41979
42270
  }),
41980
42271
  serverUrl: `${protocol}://${host}:${port}`
41981
42272
  });
41982
- await karin$1.sendMaster(e.selfId, userId, images);
42273
+ await karin.sendMaster(e.selfId, userId, images);
41983
42274
  if (e.isGroup) await e.reply("登录二维码已私聊发送,请查收~");
41984
42275
  return true;
41985
42276
  }, { businessName: "APP扫码登录" });
41986
- var qrLogin = karin$1.command(/^#?(kkk)?登录$/i, handleQrLogin, {
42277
+ var qrLogin = karin.command(/^#?(kkk)?登录$/i, handleQrLogin, {
41987
42278
  perm: "master",
41988
42279
  name: "kkk-APP扫码登录"
41989
42280
  });
@@ -42035,7 +42326,7 @@ var handleGroupStatistics = wrapWithErrorHandler(async (e) => {
42035
42326
  await e.reply(img);
42036
42327
  return true;
42037
42328
  }, { businessName: "群组解析统计" });
42038
- var groupStatistics = karin$1.command(/^#?kkk解析统计$/, handleGroupStatistics, { name: "kkk-解析统计" });
42329
+ var groupStatistics = karin.command(/^#?kkk解析统计$/, handleGroupStatistics, { name: "kkk-解析统计" });
42039
42330
  /**
42040
42331
  * #kkk全局解析统计 命令
42041
42332
  * 获取整个插件的全局解析统计数据
@@ -42063,7 +42354,7 @@ var handleGlobalStatistics = wrapWithErrorHandler(async (e) => {
42063
42354
  await e.reply(img);
42064
42355
  return true;
42065
42356
  }, { businessName: "全局解析统计" });
42066
- var globalStatistics = karin$1.command(/^#?kkk全局解析统计$/, handleGlobalStatistics, {
42357
+ var globalStatistics = karin.command(/^#?kkk全局解析统计$/, handleGlobalStatistics, {
42067
42358
  name: "kkk-全局解析统计",
42068
42359
  perm: "master"
42069
42360
  });
@@ -42273,7 +42564,7 @@ var handleTestPush = wrapWithErrorHandler(async (e) => {
42273
42564
  return true;
42274
42565
  }, { businessName: "测试抖音推送" });
42275
42566
  /** 注册测试推送命令 */
42276
- var testPush = Config.douyin.switch && karin$1.command(/^#测试抖音(作品|喜欢列表|推荐列表|直播状态)推送/, handleTestPush, {
42567
+ var testPush = Config.douyin.switch && karin.command(/^#测试抖音(作品|喜欢列表|推荐列表|直播状态)推送/, handleTestPush, {
42277
42568
  name: "kkk-测试抖音推送",
42278
42569
  perm: "master"
42279
42570
  });
@@ -42360,7 +42651,7 @@ var handleXiaohongshu = wrapWithErrorHandler(async (e, next) => {
42360
42651
  }, { businessName: "小红书视频解析" });
42361
42652
  var handlePrefix = wrapWithErrorHandler(async (e, next) => {
42362
42653
  const originalMsg = e.msg;
42363
- e.msg = await Common.getReplyMessage(e);
42654
+ e.msg = await Common.getReplyMessage(e) || originalMsg.replace(/^#?(解析|kkk解析|弹幕解析)\s*/, "");
42364
42655
  if (/^#?弹幕解析/.test(originalMsg)) e.msg = "#弹幕解析 " + e.msg;
42365
42656
  if (reg.douyinCDN.test(e.msg)) {
42366
42657
  logger.debug("检测到抖音 CDN 下载链接,直接下载视频");
@@ -42379,23 +42670,23 @@ var handlePrefix = wrapWithErrorHandler(async (e, next) => {
42379
42670
  else if (reg.kuaishou.test(e.msg)) return await handleKuaishou(e, next);
42380
42671
  else if (reg.xiaohongshu.test(e.msg)) return await handleXiaohongshu(e, next);
42381
42672
  }, { businessName: "引用解析" });
42382
- var douyin = karin$1.command(reg.douyin, handleDouyin, {
42673
+ var douyin = karin.command(reg.douyin, handleDouyin, {
42383
42674
  name: "kkk-视频功能-抖音",
42384
42675
  priority: Config.app.videoTool ? -Infinity : 800
42385
42676
  });
42386
- var bilibili = karin$1.command(reg.bilibili, handleBilibili, {
42677
+ var bilibili = karin.command(reg.bilibili, handleBilibili, {
42387
42678
  name: "kkk-视频功能-B站",
42388
42679
  priority: Config.app.videoTool ? -Infinity : 800
42389
42680
  });
42390
- var kuaishou = karin$1.command(reg.kuaishou, handleKuaishou, {
42681
+ var kuaishou = karin.command(reg.kuaishou, handleKuaishou, {
42391
42682
  name: "kkk-视频功能-快手",
42392
42683
  priority: Config.app.videoTool ? -Infinity : 800
42393
42684
  });
42394
- var xiaohongshu = karin$1.command(reg.xiaohongshu, handleXiaohongshu, {
42685
+ var xiaohongshu = karin.command(reg.xiaohongshu, handleXiaohongshu, {
42395
42686
  name: "kkk-视频功能-小红书",
42396
42687
  priority: Config.app.videoTool ? -Infinity : 800
42397
42688
  });
42398
- var prefix = karin$1.command(/^#?(解析|kkk解析|弹幕解析)/, handlePrefix, { name: "kkk-视频功能-引用解析" });
42689
+ var prefix = karin.command(/^#?(解析|kkk解析|弹幕解析)/, handlePrefix, { name: "kkk-视频功能-引用解析" });
42399
42690
  var douyinAPP = Config.douyin.switch && douyin;
42400
42691
  var bilibiliAPP = Config.bilibili.switch && bilibili;
42401
42692
  var kuaishouAPP = Config.kuaishou.switch && kuaishou;
@@ -42562,7 +42853,7 @@ var Handler = async () => {
42562
42853
  } catch {}
42563
42854
  const masters = config.master().filter((id) => id !== "console");
42564
42855
  if (masters.length === 0) return true;
42565
- const botItems = karin$1.getAllBotList().filter((b) => b.bot.account.name !== "console");
42856
+ const botItems = karin.getAllBotList().filter((b) => b.bot.account.name !== "console");
42566
42857
  if (botItems.length === 0) return true;
42567
42858
  const friendsMap = /* @__PURE__ */ new Map();
42568
42859
  await Promise.all(botItems.map(async (item) => {
@@ -42594,7 +42885,7 @@ var Handler = async () => {
42594
42885
  if (!bot) continue;
42595
42886
  const elements = botToImage.get(bot.account.selfId);
42596
42887
  if (!elements) continue;
42597
- const msg = await karin$1.sendMaster(bot.account.selfId, owner, elements);
42888
+ const msg = await karin.sendMaster(bot.account.selfId, owner, elements);
42598
42889
  if (!storedMsgId && msg?.messageId) storedMsgId = msg.messageId;
42599
42890
  }
42600
42891
  if (storedMsgId) try {
@@ -42657,14 +42948,14 @@ var handleKkkUpdate = wrapWithErrorHandler(async (e) => {
42657
42948
  await restart(e.selfId, e.contact, msgResult.messageId);
42658
42949
  } else e.reply(`${Root.pluginName} 更新失败: ${result.data ?? "更新执行失败"}`);
42659
42950
  }, { businessName: "KKK更新" });
42660
- var kkkUpdateCommand = karin$1.command(/^#?kkk更新$/, handleKkkUpdate, { name: "kkk-更新" });
42661
- var kkkUpdateTest = process.env.NODE_ENV === "development" && karin$1.command("test", async (_e, next) => {
42951
+ var kkkUpdateCommand = karin.command(/^#?kkk更新$/, handleKkkUpdate, { name: "kkk-更新" });
42952
+ var kkkUpdateTest = process.env.NODE_ENV === "development" && karin.command("test", async (_e, next) => {
42662
42953
  await db.del(UPDATE_MSGID_KEY);
42663
42954
  await db.del(UPDATE_LOCK_KEY);
42664
42955
  await Handler();
42665
42956
  next();
42666
42957
  }, { name: "kkk-更新检测-测试" });
42667
- var update = karin$1.task("kkk-更新检测", "*/3 * * * *", Handler, {
42958
+ var update = karin.task("kkk-更新检测", "*/3 * * * *", Handler, {
42668
42959
  name: "kkk-更新检测",
42669
42960
  log: false
42670
42961
  });
@@ -42707,7 +42998,7 @@ var ROUTES = {
42707
42998
  * Bot 管理 API
42708
42999
  */
42709
43000
  var getOnlineBotById = (botId) => {
42710
- return karin.getAllBotList().find((item) => item.bot.account.selfId === botId)?.bot;
43001
+ return karin$1.getAllBotList().find((item) => item.bot.account.selfId === botId)?.bot;
42711
43002
  };
42712
43003
  var getBotAvatar = async (bot, botId) => {
42713
43004
  if (!bot) return "";
@@ -42724,7 +43015,7 @@ var getBotAvatar = async (bot, botId) => {
42724
43015
  */
42725
43016
  var getBots = async (_req, res) => {
42726
43017
  try {
42727
- const botList = karin.getAllBotList();
43018
+ const botList = karin$1.getAllBotList();
42728
43019
  const bots = [];
42729
43020
  for (const item of botList) {
42730
43021
  const bot = item.bot;
@@ -42777,7 +43068,7 @@ var getBotGroups = async (req, res) => {
42777
43068
  try {
42778
43069
  const botId = Array.isArray(req.params.botId) ? req.params.botId[0] : req.params.botId;
42779
43070
  if (!botId) return createServerErrorResponse(res, "缺少 botId 参数");
42780
- const botItem = karin.getAllBotList().find((item) => item.bot.account.selfId === botId);
43071
+ const botItem = karin$1.getAllBotList().find((item) => item.bot.account.selfId === botId);
42781
43072
  if (!botItem) return createServerErrorResponse(res, "Bot 不存在或不在线");
42782
43073
  const bot = botItem.bot;
42783
43074
  const groupList = await bot.getGroupList();
@@ -42846,7 +43137,7 @@ var getGroupsBatch = async (req, res) => {
42846
43137
  const { groups } = req.body;
42847
43138
  if (!groups || !Array.isArray(groups)) return createServerErrorResponse(res, "缺少 groups 参数");
42848
43139
  const result = [];
42849
- const botList = karin.getAllBotList();
43140
+ const botList = karin$1.getAllBotList();
42850
43141
  for (const item of groups) {
42851
43142
  const botItem = botList.find((b) => b.bot.account.selfId === item.botId);
42852
43143
  if (!botItem) {
@@ -43323,7 +43614,7 @@ if (process.env.NODE_ENV !== "development" && isSemverGreater(requireVersion, Ro
43323
43614
  logger.warn(msg);
43324
43615
  /** 已发送通知的 Bot ID 和主人 ID 组合,格式:`${botId}:${master}` */
43325
43616
  const notifiedSet = /* @__PURE__ */ new Set();
43326
- karin$1.on(BOT_CONNECT, async (bot) => {
43617
+ karin.on(BOT_CONNECT, async (bot) => {
43327
43618
  const botId = bot.selfId;
43328
43619
  if (botId === "console") return;
43329
43620
  await new Promise((resolve) => setTimeout(resolve, 2e3));
@@ -43333,7 +43624,7 @@ if (process.env.NODE_ENV !== "development" && isSemverGreater(requireVersion, Ro
43333
43624
  for (const master of masters) {
43334
43625
  if (master === "console") continue;
43335
43626
  try {
43336
- warningImage = await Render({ bot: karin$1.getBot(botId) }, "other/version_warning", {
43627
+ warningImage = await Render({ bot: karin.getBot(botId) }, "other/version_warning", {
43337
43628
  requireVersion,
43338
43629
  currentVersion: Root.karinVersion
43339
43630
  });
@@ -43345,7 +43636,7 @@ if (process.env.NODE_ENV !== "development" && isSemverGreater(requireVersion, Ro
43345
43636
  try {
43346
43637
  const elements = [];
43347
43638
  if (warningImage) elements.push(...warningImage);
43348
- await karin$1.sendMaster(botId, master, elements);
43639
+ await karin.sendMaster(botId, master, elements);
43349
43640
  notifiedSet.add(key);
43350
43641
  logger.info(`[karin-plugin-kkk] 已发送版本警告给主人: ${master} (via ${botId})`);
43351
43642
  } catch (error) {