karin-plugin-kkk 2.45.0 → 2.45.1-beta.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [2.45.1-beta.0](https://github.com/ikenxuan/karin-plugin-kkk/compare/v2.45.0...v2.45.1-beta.0) (2026-10-08)
6
+
7
+
8
+ ### 🧰 其他更新
9
+
10
+ * 优化发布脚本 ([a37069d](https://github.com/ikenxuan/karin-plugin-kkk/commit/a37069dd510b704d647f860606cccb8738547559))
11
+ * 更新 package.json 版本至 2.45.0,并优化发布脚本以稳定版本钉住 ([9b2f89e](https://github.com/ikenxuan/karin-plugin-kkk/commit/9b2f89ee5995173bdaab1a110a37d0ff1b64aed0))
12
+
13
+
14
+ ### 💄 UI 优化
15
+
16
+ * **web:** 优化网页配置订阅群组交互 ([7529a4e](https://github.com/ikenxuan/karin-plugin-kkk/commit/7529a4e802337ae1c266549afa31fbfc73edfbc4))
17
+
5
18
  ## [2.45.0](https://github.com/ikenxuan/karin-plugin-kkk/compare/v2.44.0...v2.45.0) (2026-10-07)
6
19
 
7
20
  > 本版本为测试/预览线的转正发布,自上一个 tag 以来没有新增常规提交。完整变更记录见 `2.45.0-rc.4` 及更早的各小节。
@@ -1,10 +1,10 @@
1
1
  {
2
- "version": "2.45.0",
3
- "buildTime": "2026-10-07T06:37:45.204Z",
4
- "buildTimestamp": 1791355065204,
2
+ "version": "2.45.1-beta.0",
3
+ "buildTime": "2026-10-08T06:22:01.860Z",
4
+ "buildTimestamp": 1791440521860,
5
5
  "name": "karin-plugin-kkk",
6
6
  "description": "Karin 的「抖音」「B 站」视频解析/动态推送插件",
7
7
  "homepage": "https://github.com/ikenxuan/karin-plugin-kkk",
8
- "commitHash": "4bc262974e83fc829c4a82254930910b9a390a8a",
9
- "shortCommitHash": "4bc26297"
8
+ "commitHash": "096ff3e5841b4e4a675f17b649efbf189d37eb19",
9
+ "shortCommitHash": "096ff3e5"
10
10
  }
@@ -1,6 +1,6 @@
1
1
  globalThis.__KTR_BUNDLED__ = true;
2
2
  import { o as __toESM } from "./rolldown-runtime.js";
3
- import { $r as number$1, Gr as CryptoConfig, Jr as xRapParam, Kr as FingerprintGenerator, Qr as literal, Wr as require_protobufjs, Xr as _enum, Yr as number, Zr as array, ei as object, ni as union, qr as Xhshow, ri as toJSONSchema, ti as string } from "./vendor.js";
3
+ import { $r as literal, Gr as require_protobufjs, Jr as Xhshow, Kr as CryptoConfig, Qr as array, Xr as number, Yr as xRapParam, Zr as _enum, ei as number$1, ii as toJSONSchema, ni as string, qr as FingerprintGenerator, ri as union, ti as object } from "./vendor.js";
4
4
  import crypto, { createCipheriv, createHash, randomBytes, randomUUID } from "node:crypto";
5
5
  import express, { Router } from "node-karin/express";
6
6
  import axios, { AxiosError, AxiosHeaders, mergeConfig } from "node-karin/axios";
@@ -1,7 +1,7 @@
1
1
  globalThis.__KTR_BUNDLED__ = true;
2
2
  import { o as __toESM } from "./rolldown-runtime.js";
3
3
  import { a as createBilibiliRoutes, c as createXiaohongshuRoutes, i as bilibiliApiUrls, l as wbi_sign, n as DynamicType, o as createDouyinRoutes, r as MajorType, s as createKuaishouRoutes, t as Client } from "./default.js";
4
- import { $ as RiPieChart2Fill, $n as FingerprintPattern, $t as UsersRound, A as MdFitScreen, An as Plus, Ar as BookOpenText, At as e, B as AiFillHeart, Bn as MapPin, Br as require_server_node, Bt as s$1, C as webassembly_default, Cn as RotateCcw, Cr as ChartColumn, Ct as o, D as tailwind_css_default, Dn as Quote, Dr as Box, Dt as a, E as tsdown_default, En as Radio, Er as Braces, Et as m, F as FaCommentDots, Fn as Moon, Fr as require_jsx_runtime, Ft as c$1, G as RiArrowRightFill, Gn as Info, Gt as formatDistanceToNow, H as AiFillStar, Hn as ListChecks, Hr as HtmlWrapper, Ht as zhCN, I as FaMusic, In as Monitor, Ir as twMerge, It as o$2, J as RiHeart3Fill, Jn as Hash, Jt as Zap, K as RiGroupLine, Kn as Image$1, Kt as format, L as FaTiktok, Ln as MessageCircle, Lr as clsx, Lt as c, M as MdLightbulbOutline, Mn as Pencil, Mr as ArrowRight, Mt as a$1, N as MdLocationOn, Nn as Palette, Nr as Chip, Nt as m$1, O as sqlite_default, On as QrCode, Or as Bot, Ot as n, P as MdSchedule, Pn as Music, Pr as Button, Pt as m$2, Q as RiMessage3Fill, Qn as Gamepad2, Qt as Users, R as FaUserGroup, Rn as Menu, Rr as createTemplateRenderer, Rt as p, S as rehypeHighlight, Sn as Route, Sr as Check, St as r, T as typescript_default, Tn as RefreshCw, Tr as Calendar, Tt as s, U as AiOutlineVideoCamera, Un as Link, Ur as defineTemplate, Ut as parse, V as AiFillPushpin, Vn as LoaderCircle, Vr as require_react, Vt as m$3, W as Markdown, Wn as LayoutTemplate, Wt as fromUnixTime, X as RiHeartLine, Xn as Gift, Xt as WandSparkles, Y as RiHeart3Line, Yn as GitBranch, Yt as X, Z as RiLiveLine, Zn as Gauge, Zt as Video, _ as use, _n as Share2, _r as CircleEllipsis, _t as SiGithub, a as drawDither, an as Timer, ar as ExternalLink, at as RiTrophyFill, b as install$2, bn as ScanLine, br as CircleCheckBig, bt as SiAnthropic, c as install$11, cn as Star, cr as Cpu, ct as RiVideoLine, d as install$8, dn as Sparkles, dr as Code, dt as SiSamsung, en as User, er as FileText, et as RiShareForwardFill, f as install$7, fn as Smartphone, fr as Clock, ft as SiOppo, g as install$5, gn as ShieldAlert, gr as CircleFadingArrowUp, gt as SiGooglephotos, h as install$6, hn as ShieldCheck, hr as CircleQuestionMark, ht as SiHonor, in as Trash, ir as EyeOff, it as RiTiktokFill, j as MdInfoOutline, jn as Play, jr as BellRing, jt as c$2, k as react_default, kn as Puzzle, kr as Bookmark, kt as p$1, l as install$10, ln as Square, lr as CornerDownLeft, lt as SiXiaomi, m as install$4, mn as Shield, mr as Clapperboard, mt as SiHuawei, nn as Upload, nr as FileExclamationPoint, nt as RiStarLine, o as require_jpeg_js, on as Terminal, or as Download, ot as RiUserFollowLine, p as install$3, pn as ShoppingBag, pr as Clock3, pt as SiOneplus, q as RiHashtag, qn as Heart, qt as differenceInSeconds, rn as TriangleAlert, rr as Eye, rt as RiThumbUpFill, s as require_heic_decode, sn as Sun, sr as Crown, st as RiVerifiedBadgeFill, tn as UserPlus, tr as FilePlay, tt as RiStarFill, u as install$9, un as SquarePen, ur as Copy, ut as SiVivo, v as init, vn as Settings2, vr as CircleDashed, vt as SiBilibili, w as vite_default, wn as Repeat, wr as Camera, wt as o$1, x as install$1, xn as Save, xr as CircleAlert, xt as o$3, y as install, yn as Search, yr as CircleCheck, yt as SiApple, z as BiImage, zn as Maximize, zr as resolveTemplateStyle, zt as n$1 } from "./vendor.js";
4
+ import { $ as RiPieChart2Fill, $n as Gamepad2, $t as UsersRound, A as MdFitScreen, An as Plus, Ar as Bookmark, At as e, B as AiFillHeart, Bn as Maximize, Br as resolveTemplateStyle, Bt as s$1, C as webassembly_default, Cn as RotateCcw, Cr as Check, Ct as o, D as tailwind_css_default, Dn as Quote, Dr as Braces, Dt as a, E as tsdown_default, En as Radio, Er as Calendar, Et as m, F as FaCommentDots, Fn as Music, Fr as Button, Ft as c$1, G as RiArrowRightFill, Gn as LayoutTemplate, Gt as formatDistanceToNow, H as AiFillStar, Hn as LoaderCircle, Hr as require_react, Ht as zhCN, I as FaMusic, In as Moon, Ir as require_jsx_runtime, It as o$2, J as RiHeart3Fill, Jn as Heart, Jt as Zap, K as RiGroupLine, Kn as Info, Kt as format, L as FaTiktok, Ln as Monitor, Lr as twMerge, Lt as c, M as MdLightbulbOutline, Mn as Pencil, Mr as BellRing, Mt as a$1, N as MdLocationOn, Nn as Palette, Nr as ArrowRight, Nt as m$1, O as sqlite_default, On as QrCode, Or as Box, Ot as n, P as MdSchedule, Pn as Network$1, Pr as Chip, Pt as m$2, Q as RiMessage3Fill, Qn as Gauge, Qt as Users, R as FaUserGroup, Rn as MessageCircle, Rr as clsx, Rt as p, S as rehypeHighlight, Sn as Route, Sr as CircleAlert, St as r, T as typescript_default, Tn as RefreshCw, Tr as Camera, Tt as s, U as AiOutlineVideoCamera, Un as ListChecks, Ur as HtmlWrapper, Ut as parse, V as AiFillPushpin, Vn as MapPin, Vr as require_server_node, Vt as m$3, W as Markdown, Wn as Link, Wr as defineTemplate, Wt as fromUnixTime, X as RiHeartLine, Xn as GitBranch, Xt as WandSparkles, Y as RiHeart3Line, Yn as Hash, Yt as X, Z as RiLiveLine, Zn as Gift, Zt as Video, _ as use, _n as Share2, _r as CircleFadingArrowUp, _t as SiGithub, a as drawDither, an as Timer, ar as EyeOff, at as RiTrophyFill, b as install$2, bn as ScanLine, br as CircleCheck, bt as SiAnthropic, c as install$11, cn as Star, cr as Crown, ct as RiVideoLine, d as install$8, dn as Sparkles, dr as Copy, dt as SiSamsung, en as User, er as FingerprintPattern, et as RiShareForwardFill, f as install$7, fn as Smartphone, fr as Code, ft as SiOppo, g as install$5, gn as ShieldAlert, gr as CircleQuestionMark, gt as SiGooglephotos, h as install$6, hn as ShieldCheck, hr as Clapperboard, ht as SiHonor, in as Trash, ir as Eye, it as RiTiktokFill, j as MdInfoOutline, jn as Play, jr as BookOpenText, jt as c$2, k as react_default, kn as Puzzle, kr as Bot, kt as p$1, l as install$10, ln as Square, lr as Cpu, lt as SiXiaomi, m as install$4, mn as Shield, mr as Clock3, mt as SiHuawei, nn as Upload, nr as FilePlay, nt as RiStarLine, o as require_jpeg_js, on as Terminal, or as ExternalLink, ot as RiUserFollowLine, p as install$3, pn as ShoppingBag, pr as Clock, pt as SiOneplus, q as RiHashtag, qn as Image$1, qt as differenceInSeconds, rn as TriangleAlert, rr as FileExclamationPoint, rt as RiThumbUpFill, s as require_heic_decode, sn as Sun, sr as Download, st as RiVerifiedBadgeFill, tn as UserPlus, tr as FileText, tt as RiStarFill, u as install$9, un as SquarePen, ur as CornerDownLeft, ut as SiVivo, v as init, vn as Settings2, vr as CircleEllipsis, vt as SiBilibili, w as vite_default, wn as Repeat, wr as ChartColumn, wt as o$1, x as install$1, xn as Save, xr as CircleCheckBig, xt as o$3, y as install, yn as Search, yr as CircleDashed, yt as SiApple, z as BiImage, zn as Menu, zr as createTemplateRenderer, zt as n$1 } from "./vendor.js";
5
5
  import { createRequire } from "node:module";
6
6
  import fs from "node:fs";
7
7
  import path, { resolve } from "node:path";
@@ -21632,7 +21632,8 @@ var getLogLevelTheme = (level, dark) => {
21632
21632
  };
21633
21633
  return themeMap[level] || themeMap["TRAC"];
21634
21634
  };
21635
- var ADAPTER_LOGO_MAP = {
21635
+ /** 协议实现(napcat / lagrange / …)的徽标。键按 `protocol` 的取值写,没有则落空。 */
21636
+ var PROTOCOL_LOGO_MAP = {
21636
21637
  napcat: "/image/other/handlerError/napcat.webp",
21637
21638
  lagrange: "/image/other/handlerError/lagrange.webp",
21638
21639
  chronocat: "/image/other/handlerError/chronocat.svg",
@@ -21641,19 +21642,80 @@ var ADAPTER_LOGO_MAP = {
21641
21642
  conwechat: "/image/other/handlerError/conwechat.webp",
21642
21643
  gocq: "/image/other/handlerError/gocq-http.webp"
21643
21644
  };
21644
- var getAdapterLogo = (adapterName) => {
21645
- const nameLower = adapterName.toLowerCase();
21646
- for (const [key, logoPath] of Object.entries(ADAPTER_LOGO_MAP)) if (nameLower.includes(key)) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
21647
- src: logoPath,
21648
- className: "h-20 w-auto",
21649
- alt: adapterName
21650
- });
21651
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Puzzle, {
21652
- size: 64,
21653
- className: "text-danger/80"
21645
+ /** 协议标准(onebot11 / milky / satori)的徽标。onebot 两个版本共用一张。 */
21646
+ var STANDARD_LOGO_MAP = {
21647
+ onebot: "/image/other/handlerError/onebot.png",
21648
+ milky: "/image/other/handlerError/Milky.png",
21649
+ satori: "/image/other/handlerError/satori.png"
21650
+ };
21651
+ /**
21652
+ * 在徽标表里找一张图。
21653
+ *
21654
+ * 同时拿 `protocol` 与 `name` 去匹配:Karin 的 `protocol` 是枚举(`napcat`、`lagrange`…),
21655
+ * 那是首选依据;但自建适配器常把 `protocol` 填成 `other`、真正的实现名只写在 `name` 里
21656
+ * (如 `NapCat.Onebot`),所以两者拼起来做子串匹配,保住这部分的徽标覆盖。
21657
+ * @param map - 徽标表
21658
+ * @param values - 参与匹配的字段原文
21659
+ * @returns 命中的图片路径,没有对应徽标时为 `undefined`
21660
+ */
21661
+ var findLogo = (map, ...values) => {
21662
+ const haystack = values.map(String).join(" ").toLowerCase();
21663
+ for (const [key, logoPath] of Object.entries(map)) if (haystack.includes(key)) return logoPath;
21664
+ };
21665
+ /** 徽标的透明度渐变:右上角全不透明,往左下收到一半。 */
21666
+ var LOGO_MASK = "linear-gradient(to bottom left, rgba(0,0,0,1) 0%, rgba(0,0,0,0.5) 100%)";
21667
+ /**
21668
+ * 卡片右侧的徽标。
21669
+ *
21670
+ * 是 flex 的真实兄弟节点,不是绝对定位的水印 —— 这样格子高度会把它算进去,哪怕文字只有
21671
+ * 一行也不会裁掉图;原先那版靠负偏移加 `overflow-hidden`,协议实现那格一到三行就把图切了。
21672
+ *
21673
+ * **定高不定宽**:`h-16` 固定高度、`w-auto` 让宽随图自己的比例走。徽标长宽比差得很远
21674
+ * (napcat 是 3053×4114 的竖图、onebot 是正方),锁成方框会给竖图留两条空白。
21675
+ * 反过来也不能用 `h-full`:那会让高度喂给宽度、宽度又撑开行高,格子一路涨到 600px。
21676
+ *
21677
+ * 高度**正好等于两行文字块**(标签 + 值 = 64px)。网格行是 `items-stretch`,徽标一旦更高
21678
+ * 就由它决定整行高度,同行那个没徽标的格子只能跟着空出一截 —— 96px 时四格全被拉到 120px。
21679
+ *
21680
+ * 没有对应徽标就整块不渲染,文字区照常铺满。
21681
+ */
21682
+ var CardLogo = ({ src, alt }) => {
21683
+ if (!src) return null;
21684
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
21685
+ src,
21686
+ alt,
21687
+ className: "h-16 w-auto object-contain shrink-0 self-center rounded-xl",
21688
+ style: {
21689
+ WebkitMaskImage: LOGO_MASK,
21690
+ maskImage: LOGO_MASK
21691
+ }
21654
21692
  });
21655
21693
  };
21656
21694
  /**
21695
+ * `AdapterStandard` 的中文说法。
21696
+ *
21697
+ * 适配器顶层要回答的是「这个事件源遵的是哪套标准接口」,而不是它自称什么名字 ——
21698
+ * 名字(`NapCat.Onebot` 之类)是协议实现那一格的事。
21699
+ */
21700
+ var ADAPTER_STANDARD_LABELS = {
21701
+ onebot11: "OneBot v11",
21702
+ onebot12: "OneBot v12",
21703
+ oicq: "OICQ",
21704
+ icqq: "ICQQ",
21705
+ milky: "Milky",
21706
+ satori: "Satori"
21707
+ };
21708
+ /**
21709
+ * 把 `standard` 印成一句话。
21710
+ * @param standard - Karin 适配器声明的协议标准
21711
+ * @returns 形如「符合 OneBot v11 标准」;`other` / 空值时说明它没声明通用标准
21712
+ */
21713
+ var standardSentenceOf = (standard) => {
21714
+ const key = String(standard ?? "").toLowerCase();
21715
+ if (key === "" || key === "other") return "未声明通用标准";
21716
+ return `符合 ${ADAPTER_STANDARD_LABELS[key] ?? _.upperFirst(_.camelCase(key))} 标准`;
21717
+ };
21718
+ /**
21657
21719
  * amagi 12 个错误大类的中文名与「该怎么办」。
21658
21720
  *
21659
21721
  * 印 `kind` 本身对看图的人没用 —— 有用的是它指向哪一类处置:改配置、等一会儿、
@@ -22504,25 +22566,19 @@ var handlerError = (props) => {
22504
22566
  className: "flex items-start justify-between gap-8 mb-6",
22505
22567
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
22506
22568
  className: "flex items-center gap-6 min-w-0",
22507
- children: [getAdapterLogo(data.adapterInfo.name), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
22569
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Network$1, {
22570
+ size: 64,
22571
+ className: "text-danger/80 shrink-0"
22572
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
22508
22573
  className: "min-w-0",
22509
22574
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
22510
22575
  className: "text-xl mb-1",
22511
22576
  style: { color: mutedColor },
22512
22577
  children: "Adapter / 适配器"
22513
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
22514
- className: "flex items-center gap-4 flex-wrap",
22515
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
22516
- className: "text-3xl font-bold truncate",
22517
- style: { color: accentColor },
22518
- children: data.adapterInfo.name
22519
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chip, {
22520
- size: "lg",
22521
- variant: "soft",
22522
- color: "danger",
22523
- className: "h-8 text-lg",
22524
- children: data.adapterInfo.version.startsWith("v") ? data.adapterInfo.version : `v${data.adapterInfo.version}`
22525
- })]
22578
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
22579
+ className: "text-3xl font-bold truncate",
22580
+ style: { color: accentColor },
22581
+ children: standardSentenceOf(data.adapterInfo.standard)
22526
22582
  })]
22527
22583
  })]
22528
22584
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
@@ -22531,7 +22587,7 @@ var handlerError = (props) => {
22531
22587
  children: "事件信息来源"
22532
22588
  })]
22533
22589
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
22534
- className: "grid grid-cols-4 gap-4 text-lg",
22590
+ className: "grid grid-cols-2 gap-4 text-lg",
22535
22591
  style: { color: secondaryColor },
22536
22592
  children: [
22537
22593
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
@@ -22546,67 +22602,53 @@ var handlerError = (props) => {
22546
22602
  })]
22547
22603
  }),
22548
22604
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
22549
- className: "rounded-2xl px-4 py-3 relative overflow-hidden",
22605
+ className: "rounded-2xl px-4 py-3 flex items-stretch gap-4",
22550
22606
  style: { backgroundColor: dark ? "rgba(248,113,113,0.08)" : "rgba(220,38,38,0.05)" },
22551
- children: [
22552
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
22607
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
22608
+ className: "min-w-0 flex-1",
22609
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
22553
22610
  className: "text-sm mb-1 opacity-75",
22554
22611
  children: "Standard / 协议标准"
22555
- }),
22556
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
22612
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
22557
22613
  className: "font-semibold break-all text-2xl",
22558
22614
  children: _.upperFirst(_.camelCase(String(data.adapterInfo.standard)))
22559
- }),
22560
- String(data.adapterInfo.standard).toLowerCase() === "milky" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
22561
- className: "absolute inset-0 pointer-events-none",
22562
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
22563
- src: "/image/other/handlerError/Milky.png",
22564
- alt: "Milky",
22565
- className: "absolute -right-2 -bottom-3 w-24 h-24 object-contain",
22566
- style: {
22567
- WebkitMaskImage: "linear-gradient(to top left, transparent 0%, rgba(0,0,0,1) 60%)",
22568
- maskImage: "linear-gradient(to top left, transparent 0%, rgba(0,0,0,1) 60%)",
22569
- opacity: 1
22570
- }
22571
- })
22572
- }),
22573
- String(data.adapterInfo.standard).toLowerCase() === "satori" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
22574
- className: "absolute inset-0 pointer-events-none",
22575
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
22576
- src: "/image/other/handlerError/satori.png",
22577
- alt: "Satori",
22578
- className: "absolute -right-2 -bottom-3 w-24 h-24 object-contain",
22579
- style: {
22580
- WebkitMaskImage: "linear-gradient(to top left, transparent 0%, rgba(0,0,0,1) 60%)",
22581
- maskImage: "linear-gradient(to top left, transparent 0%, rgba(0,0,0,1) 60%)",
22582
- opacity: 1
22583
- }
22584
- })
22585
- }),
22586
- String(data.adapterInfo.standard).includes("onebot") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
22587
- className: "absolute inset-0 pointer-events-none",
22588
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
22589
- src: "/image/other/handlerError/onebot.png",
22590
- alt: "OneBot",
22591
- className: "absolute -right-2 -bottom-3 w-24 h-24 object-contain",
22592
- style: {
22593
- WebkitMaskImage: "linear-gradient(to top left, transparent 0%, rgba(0,0,0,1) 60%)",
22594
- maskImage: "linear-gradient(to top left, transparent 0%, rgba(0,0,0,1) 60%)",
22595
- opacity: 1
22596
- }
22597
- })
22598
- })
22599
- ]
22615
+ })]
22616
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardLogo, {
22617
+ src: findLogo(STANDARD_LOGO_MAP, data.adapterInfo.standard),
22618
+ alt: "协议标准徽标"
22619
+ })]
22600
22620
  }),
22601
22621
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
22602
- className: "rounded-2xl px-4 py-3",
22622
+ className: "rounded-2xl px-4 py-3 flex items-stretch gap-4",
22603
22623
  style: { backgroundColor: dark ? "rgba(248,113,113,0.08)" : "rgba(220,38,38,0.05)" },
22604
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
22605
- className: "text-sm mb-1 opacity-75",
22606
- children: "Protocol / 协议实现"
22607
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
22608
- className: "font-semibold break-all text-2xl",
22609
- children: String(data.adapterInfo.protocol)
22624
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
22625
+ className: "min-w-0 flex-1",
22626
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
22627
+ className: "text-sm mb-1 opacity-75",
22628
+ children: "Protocol / 协议实现"
22629
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
22630
+ className: "flex items-center gap-3",
22631
+ children: [
22632
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
22633
+ className: "font-semibold text-2xl shrink-0",
22634
+ children: String(data.adapterInfo.protocol)
22635
+ }),
22636
+ data.adapterInfo.name.toLowerCase() !== String(data.adapterInfo.protocol).toLowerCase() && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
22637
+ className: "text-xl opacity-80 truncate min-w-0",
22638
+ children: data.adapterInfo.name
22639
+ }),
22640
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chip, {
22641
+ size: "lg",
22642
+ variant: "soft",
22643
+ color: "danger",
22644
+ className: "h-7 text-base shrink-0",
22645
+ children: data.adapterInfo.version.startsWith("v") ? data.adapterInfo.version : `v${data.adapterInfo.version}`
22646
+ })
22647
+ ]
22648
+ })]
22649
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardLogo, {
22650
+ src: findLogo(PROTOCOL_LOGO_MAP, data.adapterInfo.protocol, data.adapterInfo.name),
22651
+ alt: "协议实现徽标"
22610
22652
  })]
22611
22653
  }),
22612
22654
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
@@ -40421,6 +40463,12 @@ var UPDATE_CHANNELS = [
40421
40463
  ];
40422
40464
  /** 各渠道更新提醒锁:记录该渠道上次已推送的版本,检测到新版本推送一次后上锁 */
40423
40465
  var updateLockKey = (channel) => `kkk:update:lock:${channel}`;
40466
+ /** 推送文本用的渠道中文名(UpdateNotifyChannels 的取值 → 展示标签) */
40467
+ var UPDATE_CHANNEL_LABELS = {
40468
+ stable: "正式版",
40469
+ beta: "测试版",
40470
+ rc: "预览版"
40471
+ };
40424
40472
  var UPDATE_MSGID_KEY = "kkk:update:msgid";
40425
40473
  /** 推送图对应的安装目标版本(引用回复推送图「更新」时安装它) */
40426
40474
  var UPDATE_PUSHED_KEY = "kkk:update:pushed";
@@ -40458,7 +40506,7 @@ var Handler = async () => {
40458
40506
  }
40459
40507
  return isSemverGreater(version, Root.pluginVersion);
40460
40508
  };
40461
- const pending = /* @__PURE__ */ new Set();
40509
+ const versionChannels = /* @__PURE__ */ new Map();
40462
40510
  for (const channel of channels) {
40463
40511
  const version = tagVersions.get(tagOf(channel)) ?? null;
40464
40512
  if (!version || !isNewVersion(version)) continue;
@@ -40467,11 +40515,11 @@ var Handler = async () => {
40467
40515
  if (typeof locked === "string" && locked === version) continue;
40468
40516
  await db.set(updateLockKey(channel), version);
40469
40517
  } catch {}
40470
- pending.add(version);
40518
+ versionChannels.set(version, [...versionChannels.get(version) ?? [], channel]);
40471
40519
  }
40472
- if (pending.size === 0) return true;
40473
- const installTarget = [...pending].sort((a, b) => isSemverGreater(b, a) ? 1 : -1)[0];
40474
- const rendered = installedIsCanary && pending.size > 1 ? /* @__PURE__ */ new Set([installTarget]) : pending;
40520
+ if (versionChannels.size === 0) return true;
40521
+ const installTarget = [...versionChannels.keys()].sort((a, b) => isSemverGreater(b, a) ? 1 : -1)[0];
40522
+ const rendered = installedIsCanary && versionChannels.size > 1 ? [installTarget] : [...versionChannels.keys()];
40475
40523
  const masters = config.master().filter((id) => id !== "console");
40476
40524
  if (masters.length === 0) return true;
40477
40525
  const botItems = karin.getAllBotList().filter((b) => b.bot.account.name !== "console");
@@ -40491,7 +40539,11 @@ var Handler = async () => {
40491
40539
  const botToImage = /* @__PURE__ */ new Map();
40492
40540
  for (const item of botItems) {
40493
40541
  if (!Array.from(masterToBot.entries()).some(([, b]) => b.account.selfId === item.bot.account.selfId)) continue;
40494
- const elements = [segment.text("karin-plugin-kkk 有新的更新!")];
40542
+ const describe = (version) => {
40543
+ const labels = (versionChannels.get(version) ?? []).map((c) => UPDATE_CHANNEL_LABELS[c] ?? c).join("/");
40544
+ return labels ? `${labels} ${version}` : version;
40545
+ };
40546
+ const elements = [segment.text(`karin-plugin-kkk 更新提醒 · ${rendered.map(describe).join(" / ")}`)];
40495
40547
  for (const version of rendered) {
40496
40548
  const img = await getChangelogImage({ bot: item.bot }, {
40497
40549
  localVersion: Root.pluginVersion,