karin-plugin-kkk 2.30.4 → 2.31.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,9 +1,9 @@
1
1
  import { i as __toESM } from "./rolldown-runtime.js";
2
- import { $ as zhCN, $t as Hash, A as n, An as Chip, At as Save, B as RiPieChart2Fill, Bn as require_protobufjs, Bt as Palette, C as BiImage, Cn as ChartColumn, Ct as ShoppingBag, D as AiOutlineVideoCamera, Dn as Bot, Dt as Settings2, E as AiFillStar, En as Box, Et as Share2, F as RiHeart3Fill, Fn as require_react, Ft as QrCode, G as RiTiktokFill, Gt as Menu, H as RiStarFill, Hn as Xhshow, Ht as Moon, I as RiHeart3Line, In as require_png, It as Puzzle, J as RiVerifiedBadgeFill, Jt as LoaderCircle, K as RiTrophyFill, Kt as Maximize, L as RiHeartLine, Ln as require_jsQR, Lt as Plus, M as RiArrowRightFill, Mn as clsx, Mt as RefreshCw, N as RiGroupLine, Nn as require_jsx_runtime, Nt as Radio, O as m, On as Bookmark, Ot as Search, P as RiHashtag, Pn as require_server_node, Pt as Quote, Q as SiAnthropic, Qt as Heart, R as RiLiveLine, Rn as require_jpeg_js, Rt as Play, S as FaUserGroup, Sn as Check, St as Smartphone, T as AiFillPushpin, Tn as Calendar, Tt as ShieldCheck, U as RiStarLine, Un as zod_default, Ut as Monitor, V as RiShareForwardFill, Vn as Chalk, Vt as Music, W as RiThumbUpFill, Wt as MessageCircle, X as SiGithub, Xt as Info, Y as RiVideoLine, Yt as LayoutTemplate, Z as SiBilibili, Zt as Image$1, _ as MdLocationOn, _n as CircleFadingArrowUp, _t as Sun, a as purify, an as Eye, at as Zap, b as FaMusic, bn as CircleCheck, bt as SquarePen, c as VictoryLine, cn as Download, ct as Video, d as VictoryLabel, dn as CornerDownLeft, dt as User, en as GitBranch, et as parse, f as VictoryTheme, fn as Copy, ft as UserPlus, g as MdLightbulbOutline, gn as CircleQuestionMark, gt as Terminal, h as MdInfoOutline, hn as Clapperboard, ht as Trash2, i as Window, in as FilePlay, it as differenceInSeconds, j as Markdown, jn as Button, jt as RotateCcw, k as a, kn as BellRing, kt as ScanLine, l as VictoryChart, ln as Crown, lt as Users, m as MdFitScreen, mn as Clock, mt as TriangleAlert, n as require_lib, nn as Gamepad2, nt as formatDistanceToNow, o as VictoryScatter, on as EyeOff, ot as X, p as rehypeHighlight, pn as Code, pt as Upload, q as RiUserFollowLine, qt as MapPin, r as require_qr_code_styling, rn as FileText, rt as format, s as VictoryPie, sn as ExternalLink, st as WandSparkles, t as createProxyMiddleware, tn as Gift, tt as fromUnixTime, u as VictoryAxis, un as Cpu, ut as UsersRound, v as MdSchedule, vn as CircleEllipsis, vt as Star, w as AiFillHeart, wn as Camera, wt as Shield, x as FaTiktok, xn as CircleAlert, xt as Sparkles, y as FaCommentDots, yn as CircleCheckBig, yt as Square, z as RiMessage3Fill, zn as require_heic_decode, zt as Pencil } from "./vendor.js";
2
+ import { $ as SiOppo, $n as zod_default, $t as MessageCircle, A as n, An as CircleAlert, At as Sparkles, B as RiPieChart2Fill, Bn as Chip, Bt as RotateCcw, C as BiImage, Cn as Clock, Ct as TriangleAlert, D as AiOutlineVideoCamera, Dn as CircleEllipsis, Dt as Star, E as AiFillStar, En as CircleFadingArrowUp, Et as Sun, F as RiHeart3Fill, Fn as Box, Ft as Share2, G as RiTiktokFill, Gn as require_react, Gt as Puzzle, H as RiStarFill, Hn as clsx, Ht as Radio, I as RiHeart3Line, In as Bot, It as Settings2, J as RiVerifiedBadgeFill, Jn as require_jpeg_js, Jt as Pencil, K as RiTrophyFill, Kn as require_png, Kt as Plus, L as RiHeartLine, Ln as Bookmark, Lt as Search, M as RiArrowRightFill, Mn as ChartColumn, Mt as ShoppingBag, N as RiGroupLine, Nn as Camera, Nt as Shield, O as m, On as CircleCheck, Ot as Square, P as RiHashtag, Pn as Calendar, Pt as ShieldCheck, Q as SiSamsung, Qn as Xhshow, Qt as Monitor, R as RiLiveLine, Rn as BellRing, Rt as ScanLine, S as FaUserGroup, Sn as Code, St as Upload, T as AiFillPushpin, Tn as CircleQuestionMark, Tt as Terminal, U as RiStarLine, Un as require_jsx_runtime, Ut as Quote, V as RiShareForwardFill, Vn as Button, Vt as RefreshCw, W as RiThumbUpFill, Wn as require_server_node, Wt as QrCode, X as SiXiaomi, Xn as require_protobufjs, Xt as Music, Y as RiVideoLine, Yn as require_heic_decode, Yt as Palette, Z as SiVivo, Zn as Chalk, Zt as Moon, _ as MdLocationOn, _n as Download, _t as Video, a as purify, an as Info, at as SiBilibili, b as FaMusic, bn as CornerDownLeft, bt as User, c as VictoryLine, cn as Hash, ct as zhCN, d as VictoryLabel, dn as Gamepad2, dt as formatDistanceToNow, en as Menu, et as SiOneplus, f as VictoryTheme, fn as FileText, ft as format, g as MdLightbulbOutline, gn as ExternalLink, gt as WandSparkles, h as MdInfoOutline, hn as EyeOff, ht as X, i as Window, in as LayoutTemplate, it as SiGithub, j as Markdown, jn as Check, jt as Smartphone, k as a, kn as CircleCheckBig, kt as SquarePen, l as VictoryChart, ln as GitBranch, lt as parse, m as MdFitScreen, mn as Eye, mt as Zap, n as require_lib, nn as MapPin, nt as SiHonor, o as VictoryScatter, on as Image$1, ot as SiApple, p as rehypeHighlight, pn as FilePlay, pt as differenceInSeconds, q as RiUserFollowLine, qn as require_jsQR, qt as Play, r as require_qr_code_styling, rn as LoaderCircle, rt as SiGooglephotos, s as VictoryPie, sn as Heart, st as SiAnthropic, t as createProxyMiddleware, tn as Maximize, tt as SiHuawei, u as VictoryAxis, un as Gift, ut as fromUnixTime, v as MdSchedule, vn as Crown, vt as Users, w as AiFillHeart, wn as Clapperboard, wt as Trash2, x as FaTiktok, xn as Copy, xt as UserPlus, y as FaCommentDots, yn as Cpu, yt as UsersRound, z as RiMessage3Fill, zn as ArrowDownToLine, zt as Save } 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";
6
+ import URL$2, { fileURLToPath } from "node:url";
7
7
  import os, { platform } from "node:os";
8
8
  import karin$1, { BOT_CONNECT, app, authMiddleware, checkPkgUpdate, checkPort, common, components, config, copyConfigSync, createBadRequestResponse, createNotFoundResponse, createServerErrorResponse, createSuccessResponse, db, defineConfig, ffmpeg, ffprobe, filesByExt, getBot, hooks, karin, karinPathHtml, karinPathTemp, logger, logger as logger$1, logs, mkdirSync, parseChangelog, range, render, requireFileSync, restart, segment, updatePkg, watch } from "node-karin";
9
9
  import _ from "node-karin/lodash";
@@ -18,7 +18,7 @@ import util from "node:util";
18
18
  import { Transform } from "node:stream";
19
19
  import { pipeline } from "node:stream/promises";
20
20
  import { embedWatermarkToPngBytes } from "@ikenxuan/watermark";
21
- import { snapka } from "@snapka/puppeteer";
21
+ import { snapka } from "@karinjs/plugin-puppeteer";
22
22
  import { newInjectedPage } from "fingerprint-injector";
23
23
  //#region src/index.ts
24
24
  globalThis.__kkkLoadStart ??= process.hrtime.bigint();
@@ -1613,8 +1613,8 @@ var xiaohongshuApiUrls = {
1613
1613
  keyword: data.keyword,
1614
1614
  page: data.page ?? 1,
1615
1615
  page_size: data.page_size ?? 20,
1616
- sort: SearchSortType.GENERAL,
1617
- note_type: SearchNoteType.ALL,
1616
+ sort: "general",
1617
+ note_type: 0,
1618
1618
  search_id: xiaohongshuSign.getSearchId(),
1619
1619
  image_formats: [
1620
1620
  "jpg",
@@ -2632,7 +2632,7 @@ var douoyinAPIErrorCode = /* @__PURE__ */ function(douoyinAPIErrorCode) {
2632
2632
  /** 当前用户未开播 */
2633
2633
  douoyinAPIErrorCode["NOT_LIVE"] = "USER_NOT_LIVE";
2634
2634
  /** 未知错误 */
2635
- douoyinAPIErrorCode[douoyinAPIErrorCode["UNKNOWN"] = amagiAPIErrorCode.UNKNOWN] = "UNKNOWN";
2635
+ douoyinAPIErrorCode["UNKNOWN"] = "UNKNOWN_ERROR";
2636
2636
  return douoyinAPIErrorCode;
2637
2637
  }({});
2638
2638
  /** B站平台API错误码 */
@@ -2744,7 +2744,7 @@ var kuaishouAPIErrorCode = /* @__PURE__ */ function(kuaishouAPIErrorCode) {
2744
2744
  /** Cookie无效或已过期 */
2745
2745
  kuaishouAPIErrorCode["COOKIE"] = "INVALID_COOKIE";
2746
2746
  /** 未知错误 */
2747
- kuaishouAPIErrorCode[kuaishouAPIErrorCode["UNKNOWN"] = amagiAPIErrorCode.UNKNOWN] = "UNKNOWN";
2747
+ kuaishouAPIErrorCode["UNKNOWN"] = "UNKNOWN_ERROR";
2748
2748
  return kuaishouAPIErrorCode;
2749
2749
  }({});
2750
2750
  /** 小红书平台API错误码 */
@@ -2752,7 +2752,7 @@ var xiaohongshuAPIErrorCode = /* @__PURE__ */ function(xiaohongshuAPIErrorCode)
2752
2752
  /** Cookie无效或已过期 */
2753
2753
  xiaohongshuAPIErrorCode["COOKIE"] = "INVALID_COOKIE";
2754
2754
  /** 未知错误 */
2755
- xiaohongshuAPIErrorCode[xiaohongshuAPIErrorCode["UNKNOWN"] = amagiAPIErrorCode.UNKNOWN] = "UNKNOWN";
2755
+ xiaohongshuAPIErrorCode["UNKNOWN"] = "UNKNOWN_ERROR";
2756
2756
  /** 非法请求 */
2757
2757
  xiaohongshuAPIErrorCode[xiaohongshuAPIErrorCode["ILLEGAL_REQUEST"] = 500] = "ILLEGAL_REQUEST";
2758
2758
  /** 检测到帐号异常,请稍后重试 */
@@ -3270,7 +3270,7 @@ var XBogus = class {
3270
3270
  * @returns 包含完整URL、X-Bogus值和使用的User-Agent的元组
3271
3271
  */
3272
3272
  getXBogus(url, ua) {
3273
- const parsedUrl = new URL$1.URL(url);
3273
+ const parsedUrl = new URL$2.URL(url);
3274
3274
  const urlPath = parsedUrl.pathname + parsedUrl.search;
3275
3275
  const currentUa = ua ?? this.defaultUa;
3276
3276
  const rc4EncryptedUa = this.rc4Encrypt(this.uaKey, currentUa);
@@ -10140,7 +10140,7 @@ function getApiRoute(platform, methodType) {
10140
10140
  * 构建后使用 __VERSION__,开发环境从 package.json 读取
10141
10141
  */
10142
10142
  var getVersion = () => {
10143
- return "6.1.2";
10143
+ return "6.1.3";
10144
10144
  };
10145
10145
  var VERSION = getVersion();
10146
10146
  /**
@@ -10935,6 +10935,10 @@ var QRCodeScanner = class {
10935
10935
  try {
10936
10936
  const response = await axios.get(imageUrl, { responseType: "arraybuffer" });
10937
10937
  const buffer = Buffer.from(response.data);
10938
+ if (!this.detectImageFormat(buffer)) {
10939
+ logger.debug("URL 内容不是支持的图片格式,跳过二维码扫描");
10940
+ return null;
10941
+ }
10938
10942
  return this.scanFromBuffer(buffer);
10939
10943
  } catch (error) {
10940
10944
  logger.error("识别二维码时发生错误:", error);
@@ -11254,7 +11258,7 @@ var QRCodeScanner = class {
11254
11258
  */
11255
11259
  static async parseHEIC(buffer) {
11256
11260
  try {
11257
- const decoded = await (0, import_heic_decode.default)({ buffer: buffer.buffer });
11261
+ const decoded = await (0, import_heic_decode.default)({ buffer });
11258
11262
  logger.debug(`HEIC 解析成功: ${decoded.width}x${decoded.height}`);
11259
11263
  return {
11260
11264
  width: decoded.width,
@@ -11512,23 +11516,47 @@ var Common = new class Tools {
11512
11516
  * @param e event 消息事件
11513
11517
  * @returns 被引用的消息
11514
11518
  */
11519
+ /**
11520
+ * 尝试从图片 URL 识别二维码并返回支持的平台链接
11521
+ * @param imageUrl 图片 URL
11522
+ * @param source 来源描述(用于日志)
11523
+ * @returns 识别到的平台链接,或 null
11524
+ */
11525
+ async tryScanImageQrCode(imageUrl, source) {
11526
+ try {
11527
+ logger.debug(`检测到${source}为图片,尝试识别二维码...`);
11528
+ const qrContent = await QRCodeScanner.scanFromUrl(imageUrl);
11529
+ if (qrContent && QRCodeScanner.isSupportedPlatform(qrContent)) {
11530
+ logger.debug(`从${source}二维码中识别到支持的平台链接: ${qrContent}`);
11531
+ return qrContent;
11532
+ } else if (qrContent) logger.debug(`识别到二维码内容但不是支持的平台: ${qrContent}`);
11533
+ } catch (error) {
11534
+ logger.error(`识别${source}二维码时发生错误:`, error);
11535
+ }
11536
+ return null;
11537
+ }
11515
11538
  async getReplyMessage(e) {
11516
11539
  if (e.replyId) {
11517
11540
  const reply = await e.bot.getMsg(e.contact, e.replyId);
11518
- for (const v of reply.elements) if (v.type === "text") return v.text;
11519
- else if (v.type === "json") return v.data;
11520
- else if (v.type === "image") try {
11521
- logger.debug("检测到引用消息为图片,尝试识别二维码...");
11522
- const imageUrl = v.file;
11523
- if (imageUrl) {
11524
- const qrContent = await QRCodeScanner.scanFromUrl(imageUrl);
11525
- if (qrContent && QRCodeScanner.isSupportedPlatform(qrContent)) {
11526
- logger.debug(`从图片二维码中识别到支持的平台链接: ${qrContent}`);
11527
- return qrContent;
11528
- } else if (qrContent) logger.debug(`识别到二维码内容但不是支持的平台: ${qrContent}`);
11529
- }
11530
- } catch (error) {
11531
- logger.error("识别图片二维码时发生错误:", error);
11541
+ for (const v of reply.elements) if (v.type === "text") {
11542
+ try {
11543
+ const parsed = JSON.parse(v.text);
11544
+ if (parsed.type === "markdown" && parsed.data?.content) {
11545
+ const content = parsed.data.content;
11546
+ const imageRegex = /!\[.*?\]\((.*?)\)/g;
11547
+ let match;
11548
+ while ((match = imageRegex.exec(content)) !== null) {
11549
+ const qrResult = await this.tryScanImageQrCode(match[1], "引用消息中的 markdown 图片");
11550
+ if (qrResult) return qrResult;
11551
+ }
11552
+ return content;
11553
+ }
11554
+ } catch {}
11555
+ return v.text;
11556
+ } else if (v.type === "json") return v.data;
11557
+ else if (v.type === "image") {
11558
+ const qrResult = await this.tryScanImageQrCode(v.file, "引用消息");
11559
+ if (qrResult) return qrResult;
11532
11560
  }
11533
11561
  }
11534
11562
  return "";
@@ -14561,7 +14589,7 @@ var ViteLogo = ({ className = "w-auto h-12" }) => /* @__PURE__ */ (0, import_jsx
14561
14589
  * @param props 组件属性
14562
14590
  * @returns JSX元素
14563
14591
  */
14564
- var DefaultLayout = ({ children, version, data, scale = 3, className = "", style = {} }) => {
14592
+ var DefaultLayout = ({ children, version, data, scale = 3, className = "", style = {}, watermarkTextBitSize }) => {
14565
14593
  const { useDarkTheme } = data;
14566
14594
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
14567
14595
  className: clsx("w-360 shrink-0 bg-background text-foreground font-[HarmonyOSHans-Regular]", useDarkTheme ? "dark" : "light", className),
@@ -14575,9 +14603,9 @@ var DefaultLayout = ({ children, version, data, scale = 3, className = "", style
14575
14603
  maxWidth: "1440px",
14576
14604
  ...style
14577
14605
  },
14578
- children: [children, version ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
14606
+ children: [children, version ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
14579
14607
  className: "relative z-50 pt-32 pb-20 text-foreground/80",
14580
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
14608
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
14581
14609
  className: "flex relative justify-center items-center space-x-8",
14582
14610
  children: [
14583
14611
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
@@ -14697,8 +14725,20 @@ var DefaultLayout = ({ children, version, data, scale = 3, className = "", style
14697
14725
  })]
14698
14726
  })] })
14699
14727
  ]
14728
+ }), typeof watermarkTextBitSize === "number" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
14729
+ className: "flex justify-center",
14730
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
14731
+ className: "text-xs font-mono text-foreground/30",
14732
+ children: ["Restore ID: ", watermarkTextBitSize]
14733
+ })
14734
+ })]
14735
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
14736
+ className: "flex items-center justify-center h-24",
14737
+ children: typeof watermarkTextBitSize === "number" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
14738
+ className: "text-xs font-mono text-foreground/30",
14739
+ children: ["Restore ID: ", watermarkTextBitSize]
14700
14740
  })
14701
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-24" })]
14741
+ })]
14702
14742
  });
14703
14743
  };
14704
14744
  //#endregion
@@ -16950,7 +16990,7 @@ BilibiliArticleDynamic.displayName = "BilibiliArticleDynamic";
16950
16990
  */
16951
16991
  var BilibiliVideoDynamicHeader = () => {
16952
16992
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
16953
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-20" }),
16993
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-25" }),
16954
16994
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
16955
16995
  className: "flex items-center pl-20 text-6xl text-muted",
16956
16996
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
@@ -18036,7 +18076,7 @@ var OriginalDrawContent = ({ content }) => {
18036
18076
  })
18037
18077
  })
18038
18078
  }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18039
- className: `grid gap-3 p-4 ${content.image_url?.length === 4 ? "grid-cols-2" : "grid-cols-3"}`,
18079
+ className: `grid gap-3 ${content.image_url?.length === 4 ? "grid-cols-2" : "grid-cols-3"}`,
18040
18080
  children: [content.image_url?.map((img, index) => {
18041
18081
  const total = content.image_url?.length || 0;
18042
18082
  const cols = total === 4 ? 2 : 3;
@@ -18359,7 +18399,7 @@ var BilibiliForwardDynamic = import_react.memo((props) => {
18359
18399
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18360
18400
  className: "p-4",
18361
18401
  children: [
18362
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-15" }),
18402
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-25" }),
18363
18403
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BilibiliForwardUserInfo, {
18364
18404
  avatar_url: props.data.avatar_url,
18365
18405
  frame: props.data.frame,
@@ -26913,6 +26953,13 @@ var iconRegistry = {
26913
26953
  "simple-icons:bilibili": SiBilibili,
26914
26954
  "simple-icons:openai": Sparkles,
26915
26955
  "simple-icons:anthropic": SiAnthropic,
26956
+ "simple-icons:googlephotos": SiGooglephotos,
26957
+ "simple-icons:xiaomi": SiXiaomi,
26958
+ "simple-icons:oppo": SiOppo,
26959
+ "simple-icons:huawei": SiHuawei,
26960
+ "simple-icons:honor": SiHonor,
26961
+ "simple-icons:vivo": SiVivo,
26962
+ "simple-icons:samsung": SiSamsung,
26916
26963
  "tabler:message-circle": MessageCircle,
26917
26964
  "tabler:scan": ScanLine,
26918
26965
  "ph:play-fill": n,
@@ -27184,6 +27231,435 @@ var Help = import_react.memo((props) => {
27184
27231
  });
27185
27232
  Help.displayName = "Help";
27186
27233
  //#endregion
27234
+ //#region ../template/src/components/platforms/other/LivePhotoTip.tsx
27235
+ /**
27236
+ * Google Photos 彩色官方 Logo
27237
+ */
27238
+ var GooglePhotosIcon = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
27239
+ className,
27240
+ viewBox: "0 0 32 32",
27241
+ xmlns: "http://www.w3.org/2000/svg",
27242
+ children: [
27243
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
27244
+ d: "M4,16a6,6,0,0,1,12,0Z",
27245
+ fill: "#ffba00"
27246
+ }),
27247
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
27248
+ d: "M22,10a6,6,0,0,1-6,6V4a6,6,0,0,1,6,6",
27249
+ fill: "#ea4435"
27250
+ }),
27251
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
27252
+ d: "M28,16a6,6,0,0,1-12,0Z",
27253
+ fill: "#0066da"
27254
+ }),
27255
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
27256
+ d: "M10,22a6,6,0,0,1,6-6V28a6,6,0,0,1-6-6",
27257
+ fill: "#00ac47"
27258
+ })
27259
+ ]
27260
+ });
27261
+ var statusConfig = {
27262
+ verified: {
27263
+ icon: Check,
27264
+ color: "#22c55e",
27265
+ label: "实测可用"
27266
+ },
27267
+ untested: {
27268
+ icon: CircleQuestionMark,
27269
+ color: "#f59e0b",
27270
+ label: "理论支持"
27271
+ },
27272
+ unsupported: {
27273
+ icon: X,
27274
+ color: "#ef4444",
27275
+ label: "不支持"
27276
+ }
27277
+ };
27278
+ /**
27279
+ * kkk Logo SVG
27280
+ */
27281
+ var KkkLogo = ({ className, color }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
27282
+ xmlns: "http://www.w3.org/2000/svg",
27283
+ viewBox: "0 0 230 221",
27284
+ className,
27285
+ style: { color },
27286
+ children: [
27287
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
27288
+ d: "M132.75,87.37l-53.72-53.37c-4.66-4.63-1.38-12.58,5.18-12.58h115.13c6.57,0,9.84,7.95,5.18,12.58l-53.72,53.37c-4.99,4.96-13.06,4.96-18.05,0Z",
27289
+ fill: "currentColor"
27290
+ }),
27291
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
27292
+ d: "M28.49,186.89l.03-51.42c-.02-6.57,7.92-9.87,12.56-5.23l57.02,57.02c4.64,4.64,1.34,12.41-5.23,12.39h-51.42c-7.04-.02-12.94-5.72-12.96-12.76Z",
27293
+ fill: "currentColor"
27294
+ }),
27295
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
27296
+ d: "M41.54,23.68l163.04,163.05c4.78,4.78,1.39,12.95-5.36,12.94h-47.88c-9.69,0-18.99-3.86-25.84-10.71L39.3,102.75c-6.85-6.85-10.7-16.15-10.7-25.84V29.04c0-6.76,8.16-10.14,12.94-5.36Z",
27297
+ fill: "currentColor"
27298
+ })
27299
+ ]
27300
+ });
27301
+ function BrandCard({ brand, isDark }) {
27302
+ const StatusIcon = statusConfig[brand.status].icon;
27303
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27304
+ className: "flex flex-col items-center gap-3",
27305
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27306
+ className: "relative flex items-center justify-center w-75 h-75 rounded-3xl",
27307
+ style: { background: isDark ? "radial-gradient(circle, " + brand.color + "12 0%, transparent 70%)" : "radial-gradient(circle, " + brand.color + "08 0%, transparent 70%)" },
27308
+ children: [brand.icon, /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27309
+ className: "absolute top-4 right-4 flex items-center gap-1.5 px-5 py-2.5 rounded-full",
27310
+ style: { backgroundColor: statusConfig[brand.status].color + "20" },
27311
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusIcon, {
27312
+ className: "w-5 h-auto",
27313
+ style: { color: statusConfig[brand.status].color }
27314
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
27315
+ className: "text-lg font-bold",
27316
+ style: { color: statusConfig[brand.status].color },
27317
+ children: statusConfig[brand.status].label
27318
+ })]
27319
+ })]
27320
+ })
27321
+ });
27322
+ }
27323
+ function UnsupportedBrandCard({ brand, isDark }) {
27324
+ const StatusIcon = statusConfig[brand.status].icon;
27325
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27326
+ className: "flex flex-col items-center gap-2 opacity-50",
27327
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27328
+ className: "relative flex items-center justify-center w-40 h-40 rounded-2xl",
27329
+ style: { background: isDark ? "radial-gradient(circle, " + brand.color + "08 0%, transparent 70%)" : "radial-gradient(circle, " + brand.color + "05 0%, transparent 70%)" },
27330
+ children: brand.icon
27331
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27332
+ className: "flex items-center gap-1",
27333
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusIcon, {
27334
+ className: "w-5 h-auto",
27335
+ style: { color: statusConfig[brand.status].color }
27336
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
27337
+ className: "text-md font-bold",
27338
+ style: { color: statusConfig[brand.status].color },
27339
+ children: statusConfig[brand.status].label
27340
+ })]
27341
+ })]
27342
+ });
27343
+ }
27344
+ /**
27345
+ * 实况图提示组件 - 正方形,Vercel 黑白风格
27346
+ */
27347
+ var LivePhotoTip = import_react.memo((props) => {
27348
+ const isDark = props.data.useDarkTheme ?? false;
27349
+ const bgColor = isDark ? "#000000" : "#ffffff";
27350
+ const primaryColor = isDark ? "#ffffff" : "#000000";
27351
+ const secondaryColor = isDark ? "#888888" : "#666666";
27352
+ const mutedColor = isDark ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.5)";
27353
+ const accentColor = isDark ? "#ffffff" : "#000000";
27354
+ const glow1 = "radial-gradient(ellipse at 30% 40%, " + (isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.06)") + " 0%, transparent 70%)";
27355
+ const glow2 = "radial-gradient(ellipse at 70% 60%, " + (isDark ? "rgba(128,128,128,0.1)" : "rgba(128,128,128,0.08)") + " 0%, transparent 70%)";
27356
+ const noiseOpacity = isDark ? .04 : .06;
27357
+ const appleColor = isDark ? "#ffffff" : "#000000";
27358
+ const supportedBrands = [
27359
+ {
27360
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GooglePhotosIcon, { className: "w-36 h-auto" }),
27361
+ color: "#4285F4",
27362
+ status: "verified"
27363
+ },
27364
+ {
27365
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SiXiaomi, {
27366
+ className: "w-28 h-auto",
27367
+ style: { color: "#FF6900" }
27368
+ }),
27369
+ color: "#FF6900",
27370
+ status: "verified"
27371
+ },
27372
+ {
27373
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SiSamsung, {
27374
+ className: "w-68 h-auto",
27375
+ style: { color: "#1428A0" }
27376
+ }),
27377
+ color: "#1428A0",
27378
+ status: "verified"
27379
+ },
27380
+ {
27381
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SiOppo, { className: "w-58 h-auto" }),
27382
+ color: "#009B77",
27383
+ status: "verified"
27384
+ },
27385
+ {
27386
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SiOneplus, {
27387
+ className: "w-26 h-auto",
27388
+ style: { color: "#F50514" }
27389
+ }),
27390
+ color: "#F50514",
27391
+ status: "verified"
27392
+ },
27393
+ {
27394
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SiHuawei, {
27395
+ className: "w-32 h-auto",
27396
+ style: { color: "#CF0A2C" }
27397
+ }),
27398
+ color: "#CF0A2C",
27399
+ status: "untested"
27400
+ },
27401
+ {
27402
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SiHonor, {
27403
+ className: "w-58 h-auto",
27404
+ style: { color: "#00BFFF" }
27405
+ }),
27406
+ color: "#00BFFF",
27407
+ status: "untested"
27408
+ }
27409
+ ];
27410
+ const unsupportedBrands = [{
27411
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SiApple, {
27412
+ className: "w-20 h-auto",
27413
+ style: { color: appleColor }
27414
+ }),
27415
+ color: appleColor,
27416
+ status: "unsupported"
27417
+ }, {
27418
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SiVivo, {
27419
+ className: "w-24 h-auto",
27420
+ style: { color: "#415FFF" }
27421
+ }),
27422
+ color: "#415FFF",
27423
+ status: "unsupported"
27424
+ }];
27425
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DefaultLayout, {
27426
+ ...props,
27427
+ version: void 0,
27428
+ className: "relative overflow-hidden",
27429
+ style: {
27430
+ backgroundColor: bgColor,
27431
+ minHeight: "1440px"
27432
+ },
27433
+ children: [
27434
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27435
+ className: "absolute inset-0 pointer-events-none",
27436
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27437
+ className: "absolute rounded-full w-150 h-125 top-[20%] left-[10%] blur-[150px]",
27438
+ style: { background: glow1 }
27439
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27440
+ className: "absolute rounded-full w-125 h-112.5 bottom-[15%] right-[10%] blur-[130px]",
27441
+ style: { background: glow2 }
27442
+ })]
27443
+ }),
27444
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27445
+ className: "absolute inset-0 pointer-events-none",
27446
+ style: { opacity: noiseOpacity },
27447
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
27448
+ className: "w-full h-full",
27449
+ xmlns: "http://www.w3.org/2000/svg",
27450
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("filter", {
27451
+ id: "tipNoise",
27452
+ x: "0%",
27453
+ y: "0%",
27454
+ width: "100%",
27455
+ height: "100%",
27456
+ children: [
27457
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feTurbulence", {
27458
+ type: "fractalNoise",
27459
+ baseFrequency: "0.8",
27460
+ numOctaves: "1",
27461
+ stitchTiles: "stitch",
27462
+ result: "noise"
27463
+ }),
27464
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feColorMatrix", {
27465
+ type: "saturate",
27466
+ values: "0",
27467
+ result: "gray"
27468
+ }),
27469
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("feComponentTransfer", { children: [
27470
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncR", {
27471
+ type: "discrete",
27472
+ tableValues: "0 1"
27473
+ }),
27474
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncG", {
27475
+ type: "discrete",
27476
+ tableValues: "0 1"
27477
+ }),
27478
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncB", {
27479
+ type: "discrete",
27480
+ tableValues: "0 1"
27481
+ })
27482
+ ] })
27483
+ ]
27484
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
27485
+ width: "100%",
27486
+ height: "100%",
27487
+ filter: "url(#tipNoise)"
27488
+ })]
27489
+ })
27490
+ }),
27491
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27492
+ className: "absolute inset-0 pointer-events-none overflow-hidden",
27493
+ children: [
27494
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27495
+ className: "absolute top-20 left-20 grid grid-cols-5 gap-2 opacity-30",
27496
+ children: Array.from({ length: 15 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27497
+ className: "w-2 h-2 rounded-full",
27498
+ style: { backgroundColor: primaryColor }
27499
+ }, i))
27500
+ }),
27501
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27502
+ className: "absolute top-20 right-20 flex flex-col items-end gap-2 opacity-30",
27503
+ children: [
27504
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27505
+ className: "h-0.75 rounded-full w-20",
27506
+ style: { backgroundColor: secondaryColor }
27507
+ }),
27508
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27509
+ className: "h-0.75 rounded-full w-12",
27510
+ style: { backgroundColor: secondaryColor }
27511
+ }),
27512
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27513
+ className: "h-0.75 rounded-full w-6",
27514
+ style: { backgroundColor: secondaryColor }
27515
+ })
27516
+ ]
27517
+ }),
27518
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27519
+ className: "absolute bottom-40 left-10 flex gap-2 opacity-30",
27520
+ children: [
27521
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27522
+ className: "w-2 h-2 rounded-full",
27523
+ style: { backgroundColor: primaryColor }
27524
+ }),
27525
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27526
+ className: "w-2 h-2 rounded-full",
27527
+ style: { backgroundColor: primaryColor }
27528
+ }),
27529
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27530
+ className: "w-2 h-2 rounded-full",
27531
+ style: { backgroundColor: primaryColor }
27532
+ }),
27533
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27534
+ className: "w-2 h-2 rounded-full",
27535
+ style: { backgroundColor: primaryColor }
27536
+ })
27537
+ ]
27538
+ }),
27539
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27540
+ className: "absolute bottom-10 right-10 opacity-30",
27541
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
27542
+ width: "100",
27543
+ height: "100",
27544
+ viewBox: "0 0 100 100",
27545
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
27546
+ cx: "50",
27547
+ cy: "50",
27548
+ r: "44",
27549
+ fill: "none",
27550
+ stroke: primaryColor,
27551
+ strokeWidth: "2"
27552
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
27553
+ cx: "50",
27554
+ cy: "50",
27555
+ r: "28",
27556
+ fill: "none",
27557
+ stroke: secondaryColor,
27558
+ strokeWidth: "2"
27559
+ })]
27560
+ })
27561
+ })
27562
+ ]
27563
+ }),
27564
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27565
+ className: "relative z-10 flex flex-col min-h-360 px-20 py-16",
27566
+ children: [
27567
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-20" }),
27568
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27569
+ className: "flex items-center gap-5 mb-16",
27570
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27571
+ className: "rounded-full p-5 shrink-0",
27572
+ style: { background: "radial-gradient(circle, " + (isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.06)") + " 0%, transparent 70%)" },
27573
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowDownToLine, {
27574
+ className: "w-20 h-auto",
27575
+ style: { color: primaryColor }
27576
+ })
27577
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
27578
+ className: "text-4xl font-bold leading-tight",
27579
+ style: { color: accentColor },
27580
+ children: "保存原图"
27581
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
27582
+ className: "text-2xl mt-1",
27583
+ style: { color: mutedColor },
27584
+ children: "长按选择「保存原图」即可识别为实况照片"
27585
+ })] })]
27586
+ }),
27587
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27588
+ className: "flex-1 flex flex-col justify-center items-center gap-6",
27589
+ children: [
27590
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27591
+ className: "flex flex-col gap-6",
27592
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27593
+ className: "flex justify-center gap-6",
27594
+ children: supportedBrands.slice(0, 4).map((brand, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BrandCard, {
27595
+ brand,
27596
+ isDark
27597
+ }, idx))
27598
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27599
+ className: "flex justify-center gap-6",
27600
+ children: supportedBrands.slice(4).map((brand, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BrandCard, {
27601
+ brand,
27602
+ isDark
27603
+ }, idx))
27604
+ })]
27605
+ }),
27606
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27607
+ className: "w-200 h-px",
27608
+ style: { backgroundColor: isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.06)" }
27609
+ }),
27610
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27611
+ className: "flex justify-center gap-8",
27612
+ children: unsupportedBrands.map((brand, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UnsupportedBrandCard, {
27613
+ brand,
27614
+ isDark
27615
+ }, idx))
27616
+ })
27617
+ ]
27618
+ }),
27619
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27620
+ className: "flex items-start gap-4 mt-12 px-8 py-5 rounded-2xl",
27621
+ style: { backgroundColor: isDark ? "rgba(255,255,255,0.04)" : "rgba(0,0,0,0.03)" },
27622
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Info, {
27623
+ className: "w-6 h-6 shrink-0 mt-0.5",
27624
+ style: { color: primaryColor }
27625
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
27626
+ className: "text-xl leading-relaxed",
27627
+ style: { color: mutedColor },
27628
+ children: "所有支持 Google Motion Photo 标准的相册 App 均可识别实况照片"
27629
+ })]
27630
+ }),
27631
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
27632
+ className: "flex justify-end items-end mt-auto pt-12",
27633
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27634
+ className: "flex items-end gap-6",
27635
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27636
+ className: "flex flex-col items-end",
27637
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
27638
+ className: "text-xl font-bold tracking-[0.15em] uppercase",
27639
+ style: { color: mutedColor },
27640
+ children: "KARIN-PLUGIN"
27641
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
27642
+ className: "text-5xl font-black",
27643
+ style: { color: accentColor },
27644
+ children: "kkk"
27645
+ })]
27646
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GlowImage, {
27647
+ glowStrength: 1,
27648
+ blurRadius: 25,
27649
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(KkkLogo, {
27650
+ className: "w-auto h-20",
27651
+ color: accentColor
27652
+ })
27653
+ })]
27654
+ })
27655
+ })
27656
+ ]
27657
+ })
27658
+ ]
27659
+ });
27660
+ });
27661
+ LivePhotoTip.displayName = "LivePhotoTip";
27662
+ //#endregion
27187
27663
  //#region ../template/src/components/platforms/other/qrlogin.tsx
27188
27664
  /**
27189
27665
  * APP 扫码登录组件
@@ -29020,6 +29496,14 @@ var baseComponentConfigs = [
29020
29496
  enabled: true,
29021
29497
  componentPath: "platforms/other/qrlogin",
29022
29498
  exportName: "QrLogin"
29499
+ },
29500
+ {
29501
+ id: "live-photo-tip",
29502
+ name: "实况图提示",
29503
+ description: "实况照片保存提示图片",
29504
+ enabled: true,
29505
+ componentPath: "platforms/other/LivePhotoTip",
29506
+ exportName: "LivePhotoTip"
29023
29507
  }
29024
29508
  ]
29025
29509
  },
@@ -29199,6 +29683,7 @@ var componentConfigs = baseComponentConfigs.map((basePlatform) => {
29199
29683
  case "changelog": return createComponentConfig(baseComponent, { component: Changelog });
29200
29684
  case "version_warning": return createComponentConfig(baseComponent, { component: VersionWarning });
29201
29685
  case "qrlogin": return createComponentConfig(baseComponent, { component: QrLogin });
29686
+ case "live-photo-tip": return createComponentConfig(baseComponent, { component: LivePhotoTip });
29202
29687
  default: return createComponentConfig(baseComponent);
29203
29688
  }
29204
29689
  });
@@ -29655,6 +30140,7 @@ var ComponentRendererFactory = class {
29655
30140
  data: request.data,
29656
30141
  version: request.version,
29657
30142
  scale: request.scale,
30143
+ watermarkTextBitSize: request.watermarkTextBitSize,
29658
30144
  ...extraProps
29659
30145
  };
29660
30146
  if (templateName.includes("/")) props.subType = templateName.split("/")[1];
@@ -30558,7 +31044,6 @@ var createPosterPalettePlugin = () => {
30558
31044
  */
30559
31045
  /**
30560
31046
  * 将隐水印嵌入到 PNG 图片中
30561
- *
30562
31047
  * @param pngBytes - PNG 图片的 Buffer 或 Uint8Array
30563
31048
  * @param watermarkText - 要嵌入的水印文本
30564
31049
  * @returns 嵌入水印后的 PNG Buffer,失败返回 null
@@ -30566,12 +31051,17 @@ var createPosterPalettePlugin = () => {
30566
31051
  var embedWatermark = (pngBytes, watermarkText) => {
30567
31052
  try {
30568
31053
  const result = embedWatermarkToPngBytes(pngBytes instanceof Buffer ? pngBytes : Buffer.from(pngBytes), watermarkText);
30569
- return result instanceof Buffer ? result : Buffer.from(result);
30570
- } catch (error) {
30571
- logger.error("嵌入隐水印失败:", error);
31054
+ return result instanceof Buffer ? result : Buffer.from(result.buffer);
31055
+ } catch {
30572
31056
  return null;
30573
31057
  }
30574
31058
  };
31059
+ /**
31060
+ * 从 PNG 图片中提取隐水印文本
31061
+ *
31062
+ * @param pngBytes - PNG 图片的 Buffer 或 Uint8Array
31063
+ * @returns 提取出的水印文本,失败返回 null
31064
+ */
30575
31065
  //#endregion
30576
31066
  //#region src/module/utils/Render/index.ts
30577
31067
  /**
@@ -30599,6 +31089,12 @@ var Render = async (event, path$1, data) => {
30599
31089
  const lockedVersion = await db.get("kkk:update:lock");
30600
31090
  if (typeof lockedVersion === "string" && lockedVersion.length > 0) hasUpdate = isSemverGreater(lockedVersion, Root.pluginVersion);
30601
31091
  } catch {}
31092
+ const watermarkText = JSON.stringify({
31093
+ a: Date.now(),
31094
+ b: `Generated by karin-plugin-kkk v${Root.pluginVersion}, with source code open-sourced under the GPL-3.0 license`,
31095
+ c: `Sent by ${event?.bot?.account.selfId ?? "unknown"}|${event?.bot?.account.name ?? "unknown"}`
31096
+ });
31097
+ const watermarkTextBitSize = Buffer.byteLength(watermarkText, "utf8") * 8;
30602
31098
  const result = await reactServerRender({
30603
31099
  request: {
30604
31100
  templateType,
@@ -30614,6 +31110,7 @@ var Render = async (event, path$1, data) => {
30614
31110
  frameworkVersion: Root.karinVersion,
30615
31111
  hasUpdate
30616
31112
  },
31113
+ watermarkTextBitSize,
30617
31114
  data: {
30618
31115
  ...data,
30619
31116
  useDarkTheme: Common.useDarkTheme()
@@ -30635,7 +31132,7 @@ var Render = async (event, path$1, data) => {
30635
31132
  const renderResult = await render.render({
30636
31133
  name: `${Root.pluginName}/${templateType}`,
30637
31134
  file: result.htmlPath,
30638
- multiPage: Config.app.multiPageRender ? Config.app.multiPageHeight : false,
31135
+ multiPage: Config.app.multiPageRender && event.bot.adapter.name !== "QQ Official Bot" ? Config.app.multiPageHeight : false,
30639
31136
  selector: "#container",
30640
31137
  fullPage: false,
30641
31138
  type: "png",
@@ -30650,11 +31147,7 @@ var Render = async (event, path$1, data) => {
30650
31147
  const imageStats = [];
30651
31148
  for (const image of images) {
30652
31149
  const imageBuffer = Buffer.from(image, "base64");
30653
- const finalImageBuffer = embedWatermark(imageBuffer, JSON.stringify({
30654
- a: Date.now(),
30655
- b: `Generated by karin-plugin-kkk v${Root.pluginVersion}, with source code open-sourced under the GPL-3.0 license`,
30656
- c: `Sent by ${event?.bot?.account.selfId ?? "unknown"}|${event?.bot?.account.name ?? "unknown"}`
30657
- })) ?? imageBuffer;
31150
+ const finalImageBuffer = embedWatermark(imageBuffer, watermarkText) ?? imageBuffer;
30658
31151
  const metadata = getImageMetadata(finalImageBuffer);
30659
31152
  const dimensions = metadata.width && metadata.height ? `${metadata.width}x${metadata.height}` : "unknown";
30660
31153
  imageStats.push({
@@ -36618,13 +37111,11 @@ var Bilibili = class extends Base {
36618
37111
  imgArray.push(segment.image(imageUrl));
36619
37112
  }
36620
37113
  if (hasGeneratedLivePhoto) {
36621
- const tip = {
36622
- google: "Google 相册",
36623
- xiaomi: "小米相册(支持实况照片的任何版本)、Google 相册",
36624
- oppo: "OPPO 相册、小米相册(较新版本)、Google 相册",
36625
- huawei_honor: "华为/荣耀相册(理论可行但未实测)"
36626
- }[Config.app.livePhotoSystem] || "Google 相册";
36627
- imgArray.push(segment.text(`💡 提示:保存原图到 ${tip} 即可识别为实况图`));
37114
+ const tipImg = await Render(this.e, "other/live-photo-tip", {
37115
+ title: "实况照片已生成",
37116
+ description: "保存原图到相册即可识别为实况图"
37117
+ });
37118
+ imgArray.push(...tipImg);
36628
37119
  }
36629
37120
  if (imgArray.length === 1) this.e.reply(imgArray[0]);
36630
37121
  if (imgArray.length > 1) {
@@ -38161,8 +38652,6 @@ var Bilibilipush = class extends Base {
38161
38652
  host_mid: data[dynamicId].host_mid,
38162
38653
  typeMode: "strict"
38163
38654
  });
38164
- let emojiDATA = await this.amagi.bilibili.fetcher.fetchEmojiList({ typeMode: "strict" });
38165
- emojiDATA = extractEmojisData(emojiDATA.data.data.packages);
38166
38655
  switch (data[dynamicId].dynamic_type) {
38167
38656
  /** 处理图文动态 */
38168
38657
  case DynamicType.DRAW:
@@ -38493,9 +38982,13 @@ var Bilibilipush = class extends Base {
38493
38982
  if (send_video) {
38494
38983
  let correctList;
38495
38984
  let videoSize = "";
38985
+ const videoInfo = await this.amagi.bilibili.fetcher.fetchVideoInfo({
38986
+ bvid: data[dynamicId].Dynamic_Data.modules.module_dynamic.major.archive.bvid,
38987
+ typeMode: "strict"
38988
+ });
38496
38989
  const playUrlData = await this.amagi.bilibili.fetcher.fetchVideoStreamUrl({
38497
38990
  avid: parseInt(data[dynamicId].Dynamic_Data.modules.module_dynamic.major.archive.aid),
38498
- cid: data[dynamicId].Dynamic_Data.modules.module_dynamic.major.archive.cid,
38991
+ cid: videoInfo.data.data.cid,
38499
38992
  typeMode: "strict"
38500
38993
  });
38501
38994
  /** 提取出视频流信息对象,并排除清晰度重复的视频流 */
@@ -38662,13 +39155,11 @@ var Bilibilipush = class extends Base {
38662
39155
  }
38663
39156
  }
38664
39157
  if (hasGeneratedLivePhoto) {
38665
- const tip = {
38666
- google: "Google 相册",
38667
- xiaomi: "小米相册(支持实况照片的任何版本)、Google 相册",
38668
- oppo: "OPPO 相册、小米相册(较新版本)、Google 相册",
38669
- huawei_honor: "华为/荣耀相册(理论可行但未实测)"
38670
- }[Config.app.livePhotoSystem] || "Google 相册";
38671
- imgArray.push(segment.text(`💡 提示:保存原图到 ${tip} 即可识别为实况图`));
39158
+ const tipImg = await Render(this.e, "other/live-photo-tip", {
39159
+ title: "实况照片已生成",
39160
+ description: "保存原图到相册即可识别为实况图"
39161
+ });
39162
+ imgArray.push(...tipImg);
38672
39163
  }
38673
39164
  const forwardMsg = common.makeForward(imgArray, botId, bot.account.name);
38674
39165
  try {
@@ -38952,23 +39443,6 @@ var br = (data) => {
38952
39443
  return data = data.replace(/\n/g, "<br>");
38953
39444
  };
38954
39445
  /**
38955
- * 处理并提取表情数据,返回一个包含表情名称和URL的对象数组。
38956
- * @param data 表情数据的数组,每个元素包含一个表情包的信息。
38957
- * @returns 返回一个对象数组,每个对象包含text(表情名称)和url(表情图片地址)属性。
38958
- */
38959
- var extractEmojisData = (data) => {
38960
- const emojisData = [];
38961
- data.forEach((packages) => {
38962
- packages.emote.forEach((emote) => {
38963
- emojisData.push({
38964
- text: emote.text,
38965
- url: emote.url
38966
- });
38967
- });
38968
- });
38969
- return emojisData;
38970
- };
38971
- /**
38972
39446
  * 判断标题是否有屏蔽词或屏蔽标签
38973
39447
  * @param PushItem 推送项
38974
39448
  * @returns 是否应该跳过推送
@@ -39861,13 +40335,11 @@ var DouYin = class DouYin extends Base {
39861
40335
  }
39862
40336
  }
39863
40337
  if (hasGeneratedLivePhoto) {
39864
- const tip = {
39865
- google: "Google 相册",
39866
- xiaomi: "小米相册(支持实况照片的任何版本)、Google 相册",
39867
- oppo: "OPPO 相册、小米相册(较新版本)、Google 相册",
39868
- huawei_honor: "华为/荣耀相册(理论可行但未实测)"
39869
- }[Config.app.livePhotoSystem] || "Google 相册";
39870
- processedImages.push(segment.text(`💡 提示:保存原图到 ${tip} 即可识别为实况图`));
40338
+ const tipImg = await Render(this.e, "other/live-photo-tip", {
40339
+ title: "实况照片已生成",
40340
+ description: "保存原图到相册即可识别为实况图"
40341
+ });
40342
+ processedImages.push(...tipImg);
39871
40343
  }
39872
40344
  const Element = common.makeForward(processedImages, Config.app.fakeForward ? this.e.sender.userId : this.e.bot.account.selfId, Config.app.fakeForward ? this.e.sender.nick : this.e.bot.account.name);
39873
40345
  try {
@@ -40018,13 +40490,11 @@ var DouYin = class DouYin extends Base {
40018
40490
  }
40019
40491
  }
40020
40492
  if (hasGeneratedLivePhoto) {
40021
- const tip = {
40022
- google: "Google 相册",
40023
- xiaomi: "小米相册(支持实况照片的任何版本)、Google 相册",
40024
- oppo: "OPPO 相册、小米相册(较新版本)、Google 相册",
40025
- huawei_honor: "华为/荣耀相册(理论可行但未实测)"
40026
- }[Config.app.livePhotoSystem] || "Google 相册";
40027
- images.push(segment.text(`💡 提示:保存原图到 ${tip} 即可识别为实况图`));
40493
+ const tipImg = await Render(this.e, "other/live-photo-tip", {
40494
+ title: "实况照片已生成",
40495
+ description: "保存原图到相册即可识别为实况图"
40496
+ });
40497
+ images.push(...tipImg);
40028
40498
  }
40029
40499
  const Element = common.makeForward(images, Config.app.fakeForward ? this.e.sender.userId : this.e.bot.account.selfId, Config.app.fakeForward ? this.e.sender.nick : this.e.bot.account.name);
40030
40500
  try {
@@ -40620,21 +41090,11 @@ var DouyinWorkMainType = /* @__PURE__ */ function(DouyinWorkMainType) {
40620
41090
  return DouyinWorkMainType;
40621
41091
  }({});
40622
41092
  /**
40623
- * 图文作品子类型
40624
- */
40625
- var DouyinImageSubType = /* @__PURE__ */ function(DouyinImageSubType) {
40626
- /** 图集(纯静态图片或包含 live 图) */
40627
- DouyinImageSubType["GALLERY"] = "gallery";
40628
- /** 合辑(图片+视频混合) */
40629
- DouyinImageSubType["COLLECTION"] = "collection";
40630
- return DouyinImageSubType;
40631
- }({});
40632
- /**
40633
41093
  * 从作品数据判断详细类型信息
40634
41094
  */
40635
41095
  function getWorkTypeInfo(data) {
40636
41096
  if (data.live_data) return {
40637
- mainType: DouyinWorkMainType.LIVE,
41097
+ mainType: "live",
40638
41098
  isVideo: false,
40639
41099
  isImage: false,
40640
41100
  isArticle: false,
@@ -40644,7 +41104,7 @@ function getWorkTypeInfo(data) {
40644
41104
  templatePath: "douyin/live"
40645
41105
  };
40646
41106
  if (data.aweme_type === 163 || data.article_info) return {
40647
- mainType: DouyinWorkMainType.ARTICLE,
41107
+ mainType: "article",
40648
41108
  isVideo: false,
40649
41109
  isImage: false,
40650
41110
  isArticle: true,
@@ -40654,21 +41114,21 @@ function getWorkTypeInfo(data) {
40654
41114
  templatePath: "douyin/article-work"
40655
41115
  };
40656
41116
  if (data.images && data.images.length > 0) {
40657
- const subType = data.is_slides === true ? DouyinImageSubType.COLLECTION : DouyinImageSubType.GALLERY;
41117
+ const subType = data.is_slides === true ? "collection" : "gallery";
40658
41118
  return {
40659
- mainType: DouyinWorkMainType.IMAGE,
41119
+ mainType: "image",
40660
41120
  subType,
40661
41121
  isVideo: false,
40662
41122
  isImage: true,
40663
41123
  isArticle: false,
40664
41124
  isLive: false,
40665
- isGallery: subType === DouyinImageSubType.GALLERY,
40666
- isCollection: subType === DouyinImageSubType.COLLECTION,
41125
+ isGallery: subType === "gallery",
41126
+ isCollection: subType === "collection",
40667
41127
  templatePath: "douyin/image-work"
40668
41128
  };
40669
41129
  }
40670
41130
  return {
40671
- mainType: DouyinWorkMainType.VIDEO,
41131
+ mainType: "video",
40672
41132
  isVideo: true,
40673
41133
  isImage: false,
40674
41134
  isArticle: false,
@@ -41419,13 +41879,11 @@ var DouYinpush = class extends Base {
41419
41879
  }
41420
41880
  }
41421
41881
  if (hasGeneratedLivePhoto) {
41422
- const tip = {
41423
- google: "Google 相册",
41424
- xiaomi: "小米相册(支持实况照片的任何版本)、Google 相册",
41425
- oppo: "OPPO 相册、小米相册(较新版本)、Google 相册",
41426
- huawei_honor: "华为/荣耀相册(理论可行但未实测)"
41427
- }[Config.app.livePhotoSystem] || "Google 相册";
41428
- images.push(segment.text(`💡 提示:保存原图到 ${tip} 即可识别为实况图`));
41882
+ const tipImg = await Render(this.e, "other/live-photo-tip", {
41883
+ title: "实况照片已生成",
41884
+ description: "保存原图到相册即可识别为实况图"
41885
+ });
41886
+ images.push(...tipImg);
41429
41887
  }
41430
41888
  const bot = karin$1.getBot(botId);
41431
41889
  const Element = common.makeForward(images, botId, bot.account.name);
@@ -41544,13 +42002,11 @@ var DouYinpush = class extends Base {
41544
42002
  }
41545
42003
  }
41546
42004
  if (hasGeneratedLivePhoto) {
41547
- const tip = {
41548
- google: "Google 相册",
41549
- xiaomi: "小米相册(支持实况照片的任何版本)、Google 相册",
41550
- oppo: "OPPO 相册、小米相册(较新版本)、Google 相册",
41551
- huawei_honor: "华为/荣耀相册(理论可行但未实测)"
41552
- }[Config.app.livePhotoSystem] || "Google 相册";
41553
- processedImages.push(segment.text(`💡 提示:保存原图到 ${tip} 即可识别为实况图`));
42005
+ const tipImg = await Render(this.e, "other/live-photo-tip", {
42006
+ title: "实况照片已生成",
42007
+ description: "保存原图到相册即可识别为实况图"
42008
+ });
42009
+ processedImages.push(...tipImg);
41554
42010
  }
41555
42011
  const bot = karin$1.getBot(botId);
41556
42012
  const Element = common.makeForward(processedImages, botId, bot.account.name);
@@ -42451,13 +42907,11 @@ var Xiaohongshu = class extends Base {
42451
42907
  processedImages.push(segment.image(imageUrl));
42452
42908
  }
42453
42909
  if (hasGeneratedLivePhoto) {
42454
- const tip = {
42455
- google: "Google 相册",
42456
- xiaomi: "小米相册(支持实况照片的任何版本)、Google 相册",
42457
- oppo: "OPPO 相册、小米相册(较新版本)、Google 相册",
42458
- huawei_honor: "华为/荣耀相册(理论可行但未实测)"
42459
- }[Config.app.livePhotoSystem] || "Google 相册";
42460
- processedImages.push(segment.text(`💡 提示:保存原图到 ${tip} 即可识别为实况图`));
42910
+ const tipImg = await Render(this.e, "other/live-photo-tip", {
42911
+ title: "实况照片已生成",
42912
+ description: "保存原图到相册即可识别为实况图"
42913
+ });
42914
+ processedImages.push(...tipImg);
42461
42915
  }
42462
42916
  const res = common.makeForward(processedImages, Config.app.fakeForward ? this.e.sender.userId : this.e.bot.account.selfId, Config.app.fakeForward ? this.e.sender.nick : this.e.bot.account.name);
42463
42917
  if (processedImages.length === 1) await this.e.reply(processedImages[0]);
@@ -43501,14 +43955,12 @@ var forcePush = karin$1.command(/#(抖音|B站)(全部)?强制推送/, handleFor
43501
43955
  var setdyPush = karin$1.command(/^#设置抖音推送/, handleSetDouyinPush, {
43502
43956
  name: "kkk-推送功能-设置",
43503
43957
  event: "message.group",
43504
- perm: Config.douyin.push.permission,
43505
- dsbAdapter: ["qqbot"]
43958
+ perm: Config.douyin.push.permission
43506
43959
  });
43507
43960
  var setbiliPush = karin$1.command(/^#设置[bB]站推送/, handleSetBilibiliPush, {
43508
43961
  name: "kkk-推送功能-设置",
43509
43962
  event: "message.group",
43510
- perm: Config.bilibili.push.permission,
43511
- dsbAdapter: ["qqbot"]
43963
+ perm: Config.bilibili.push.permission
43512
43964
  });
43513
43965
  var bilibiliPushList = karin$1.command(/^#?[bB]站推送列表$/, handleBilibiliPushList, {
43514
43966
  name: "kkk-推送功能-列表",
@@ -43526,7 +43978,6 @@ var testDouyinPush = karin$1.command(/^#测试抖音推送\s*(https?:\/\/[^\s]+)
43526
43978
  name: "kkk-推送功能-测试",
43527
43979
  event: "message.group",
43528
43980
  perm: Config.douyin.push.permission,
43529
- dsbAdapter: ["qqbot"],
43530
43981
  priority: -Infinity
43531
43982
  });
43532
43983
  var globalIgnore = karin$1.command(/^#kkk推送全局忽略/, handleGlobalIgnore, {