karin-plugin-kkk 2.45.0-beta.3 → 2.45.0-beta.5

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,21 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [2.45.0-beta.5](https://github.com/ikenxuan/karin-plugin-kkk/compare/v2.45.0-beta.4...v2.45.0-beta.5) (2026-10-06)
6
+
7
+
8
+ ### 🐛 错误修复
9
+
10
+ * 更新 node-karin 依赖版本至 1.18.0 ([42ef2e2](https://github.com/ikenxuan/karin-plugin-kkk/commit/42ef2e2729556b7a4c75c68f7ee1714b6581ced2))
11
+
12
+ ## [2.45.0-beta.4](https://github.com/ikenxuan/karin-plugin-kkk/compare/v2.45.0-beta.3...v2.45.0-beta.4) (2026-10-06)
13
+
14
+
15
+ ### 🐛 错误修复
16
+
17
+ * 优化更新检测逻辑,支持逐渠道版本锁定与提醒 ([ddfd011](https://github.com/ikenxuan/karin-plugin-kkk/commit/ddfd011ac3bcd49789870a2e154003973c52cea9))
18
+ * 优化更新逻辑以支持金丝雀用户的版本解锁和范围起点解析 ([4a28ce5](https://github.com/ikenxuan/karin-plugin-kkk/commit/4a28ce55b82115683713ad6985d456751f151c23))
19
+
5
20
  ## [2.45.0-beta.3](https://github.com/ikenxuan/karin-plugin-kkk/compare/v2.45.0-beta.2...v2.45.0-beta.3) (2026-10-06)
6
21
 
7
22
 
@@ -1,10 +1,10 @@
1
1
  {
2
- "version": "2.45.0-beta.3",
3
- "buildTime": "2026-10-06T06:00:56.704Z",
4
- "buildTimestamp": 1791266456705,
2
+ "version": "2.45.0-beta.5",
3
+ "buildTime": "2026-10-06T08:25:30.584Z",
4
+ "buildTimestamp": 1791275130584,
5
5
  "name": "karin-plugin-kkk",
6
6
  "description": "Karin 的「抖音」「B 站」视频解析/动态推送插件",
7
7
  "homepage": "https://github.com/ikenxuan/karin-plugin-kkk",
8
- "commitHash": "030579c9a3c0615a5bb50526953874b9109ba9ad",
9
- "shortCommitHash": "030579c9"
8
+ "commitHash": "29a1c8b38919021e5788a3ab88067b20104e9d96",
9
+ "shortCommitHash": "29a1c8b3"
10
10
  }
@@ -7841,8 +7841,17 @@ var Render = async (event, path, data) => {
7841
7841
  const templateType = path.split("/")[0];
7842
7842
  let hasUpdate = false;
7843
7843
  try {
7844
- const lockedVersion = await db.get("kkk:update:lock");
7845
- if (typeof lockedVersion === "string" && lockedVersion.length > 0) hasUpdate = isSemverGreater(lockedVersion, Root.pluginVersion);
7844
+ for (const channel of [
7845
+ "stable",
7846
+ "beta",
7847
+ "rc"
7848
+ ]) {
7849
+ const lockedVersion = await db.get(`kkk:update:lock:${channel}`);
7850
+ if (typeof lockedVersion === "string" && lockedVersion.length > 0 && isSemverGreater(lockedVersion, Root.pluginVersion)) {
7851
+ hasUpdate = true;
7852
+ break;
7853
+ }
7854
+ }
7846
7855
  } catch {}
7847
7856
  const useDarkTheme = await resolveUseDarkTheme(path, data);
7848
7857
  const result = await renderTemplate(path, data, {
@@ -24561,6 +24570,15 @@ var updateHelp_default = defineTemplate({
24561
24570
  active: true
24562
24571
  };
24563
24572
  const order = semverCompare(channel.version ?? "0.0.0", data.currentVersion);
24573
+ if (channel.hasUpdate !== void 0) return channel.hasUpdate ? {
24574
+ dot: palette.success,
24575
+ text: "有更新可升级",
24576
+ active: true
24577
+ } : {
24578
+ dot: palette.faint,
24579
+ text: order < 0 ? "低于当前版本" : "已是最新",
24580
+ active: false
24581
+ };
24564
24582
  if (order > 0) return {
24565
24583
  dot: palette.success,
24566
24584
  text: "有更新可升级",
@@ -40321,6 +40339,23 @@ var getLagVersionCount = (changelog, localVersion, remoteVersion) => {
40321
40339
  }).length;
40322
40340
  };
40323
40341
  /**
40342
+ * 金丝雀用户的 range 起点解析:semver 的 ASCII 序(beta < canary)无法表达
40343
+ * 「发布晚于本机构建」——改按 pkg.pr.new 发布历史的时间线,取本机构建时间
40344
+ * 之前的最后一个发布版本作为 range 起点。失败返回 undefined(回退 semver)。
40345
+ */
40346
+ var resolveCanaryRangeStart = async (buildTimestamp) => {
40347
+ if (!buildTimestamp) return void 0;
40348
+ try {
40349
+ const nodes = (await axios.get("https://pkg.pr.new/api/repo/commits?owner=ikenxuan&repo=karin-plugin-kkk", { timeout: 1e4 })).data?.target?.history?.nodes;
40350
+ if (!Array.isArray(nodes)) return void 0;
40351
+ for (const n of nodes) {
40352
+ const t = n.authoredDate ? new Date(n.authoredDate).getTime() : 0;
40353
+ const v = /v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)/.exec(n.message ?? "")?.[1];
40354
+ if (t > 0 && t <= buildTimestamp && v) return v;
40355
+ }
40356
+ } catch {}
40357
+ };
40358
+ /**
40324
40359
  * 获取远程构建元数据
40325
40360
  * @param version 远程版本号
40326
40361
  * @returns 构建元数据对象,如果获取失败则返回 null
@@ -40393,9 +40428,10 @@ var getChangelogImage = async (ctx, props) => {
40393
40428
  lagVersionCount = getLagVersionCount(changelog, props.localVersion, props.remoteVersion);
40394
40429
  const remoteMeta = await getRemoteBuildMetadata(props.remoteVersion);
40395
40430
  if (remoteMeta?.buildTime) buildTime = formatBuildTime(remoteMeta.buildTime);
40431
+ const rangeStart = parseReleaseChannel(props.localVersion) === "Canary" ? await resolveCanaryRangeStart(getBuildMetadata()?.buildTimestamp) ?? props.localVersion : props.localVersion;
40396
40432
  changelog = range({
40397
40433
  data: changelog,
40398
- startVersion: props.localVersion,
40434
+ startVersion: rangeStart,
40399
40435
  endVersion: versionCore(props.remoteVersion),
40400
40436
  compare: "semver"
40401
40437
  });
@@ -40403,9 +40439,10 @@ var getChangelogImage = async (ctx, props) => {
40403
40439
  try {
40404
40440
  changelog = fs.readFileSync(Root.pluginPath + "/CHANGELOG.md", "utf8");
40405
40441
  lagVersionCount = getLagVersionCount(changelog, props.localVersion, props.remoteVersion);
40442
+ const rangeStart = parseReleaseChannel(props.localVersion) === "Canary" ? await resolveCanaryRangeStart(getBuildMetadata()?.buildTimestamp) ?? props.localVersion : props.localVersion;
40406
40443
  changelog = range({
40407
40444
  data: changelog,
40408
- startVersion: props.localVersion,
40445
+ startVersion: rangeStart,
40409
40446
  endVersion: versionCore(props.remoteVersion),
40410
40447
  compare: "semver"
40411
40448
  });
@@ -40428,45 +40465,64 @@ var getChangelogImage = async (ctx, props) => {
40428
40465
  };
40429
40466
  //#endregion
40430
40467
  //#region src/apps/update.ts
40431
- var UPDATE_LOCK_KEY = "kkk:update:lock";
40468
+ /** 更新提醒的订阅渠道(与面板 UpdateNotifyChannels 可选项一致) */
40469
+ var UPDATE_CHANNELS = [
40470
+ "stable",
40471
+ "beta",
40472
+ "rc"
40473
+ ];
40474
+ /** 各渠道更新提醒锁:记录该渠道上次已推送的版本,检测到新版本推送一次后上锁 */
40475
+ var updateLockKey = (channel) => `kkk:update:lock:${channel}`;
40432
40476
  var UPDATE_MSGID_KEY = "kkk:update:msgid";
40477
+ /** 推送图对应的安装目标版本(引用回复推送图「更新」时安装它) */
40478
+ var UPDATE_PUSHED_KEY = "kkk:update:pushed";
40433
40479
  /**
40434
40480
  * 定时更新检测处理器
40435
- * 按订阅渠道检查远程版本(latest 恒参与 —— 装 prerelease 的用户也要收到转正提醒),
40436
- * 候选取 semver 最大且大于本地者,渲染变更日志并私聊通知所有主人。
40481
+ * 逐渠道检查远程 dist-tag 版本:检测到该渠道有新版本就推送一次然后上锁,
40482
+ * 各渠道锁相互独立、互不挤占;金丝雀安装按构建时间线判定新版本。
40437
40483
  *
40438
40484
  * @returns 是否继续后续任务
40439
40485
  */
40440
40486
  var Handler = async () => {
40441
- const tags = ["latest", ...(Config.app.UpdateNotifyChannels?.length ? Config.app.UpdateNotifyChannels : ["stable"]).filter((c) => c !== "stable")];
40487
+ const channels = Config.app.UpdateNotifyChannels?.length ? Config.app.UpdateNotifyChannels : ["stable"];
40488
+ const tagOf = (c) => c === "stable" ? "latest" : c;
40442
40489
  const installedIsCanary = parseReleaseChannel(Root.pluginVersion) === "Canary";
40443
40490
  const installedBuildTime = getBuildMetadata()?.buildTimestamp;
40444
- const remotes = await Promise.all(tags.map(async (tag) => {
40491
+ const tagVersions = /* @__PURE__ */ new Map();
40492
+ await Promise.all([...new Set(channels.map(tagOf))].map(async (tag) => {
40445
40493
  try {
40446
- return await getRemotePkgVersion(Root.pluginName, tag) || null;
40494
+ if (!installedIsCanary) {
40495
+ const upd = await checkPkgUpdate(Root.pluginName, {
40496
+ tag,
40497
+ compare: "semver"
40498
+ });
40499
+ tagVersions.set(tag, upd.status === "yes" ? upd.remote : null);
40500
+ } else tagVersions.set(tag, await getRemotePkgVersion(Root.pluginName, tag) || null);
40447
40501
  } catch {
40448
- return null;
40502
+ tagVersions.set(tag, null);
40449
40503
  }
40450
40504
  }));
40451
40505
  const canaryInfo = installedIsCanary ? await fetchCanaryInfo() : null;
40452
- const remote = [...new Set(remotes.filter((v) => !!v))].filter((version) => {
40506
+ const isNewVersion = (version) => {
40453
40507
  if (installedIsCanary && installedBuildTime !== void 0) {
40454
40508
  const releaseNode = canaryInfo?.nodes.find((n) => n.message.includes(version));
40455
40509
  if (releaseNode) return releaseNode.time > installedBuildTime;
40456
40510
  }
40457
40511
  return isSemverGreater(version, Root.pluginVersion);
40458
- }).sort((a, b) => isSemverGreater(b, a) ? 1 : -1)[0];
40459
- if (!remote) return true;
40460
- try {
40461
- const lockedVersion = await db.get(UPDATE_LOCK_KEY);
40462
- if (typeof lockedVersion === "string" && lockedVersion.length > 0) {
40463
- if (!isSemverGreater(lockedVersion, Root.pluginVersion)) await db.del(UPDATE_LOCK_KEY);
40464
- else if (!isSemverGreater(remote, lockedVersion)) return true;
40465
- }
40466
- } catch {}
40467
- try {
40468
- await db.set(UPDATE_LOCK_KEY, remote);
40469
- } catch {}
40512
+ };
40513
+ const pending = /* @__PURE__ */ new Set();
40514
+ for (const channel of channels) {
40515
+ const version = tagVersions.get(tagOf(channel)) ?? null;
40516
+ if (!version || !isNewVersion(version)) continue;
40517
+ try {
40518
+ const locked = await db.get(updateLockKey(channel));
40519
+ if (typeof locked === "string" && locked === version) continue;
40520
+ await db.set(updateLockKey(channel), version);
40521
+ } catch {}
40522
+ pending.add(version);
40523
+ }
40524
+ if (pending.size === 0) return true;
40525
+ const installTarget = [...pending].sort((a, b) => isSemverGreater(b, a) ? 1 : -1)[0];
40470
40526
  const masters = config.master().filter((id) => id !== "console");
40471
40527
  if (masters.length === 0) return true;
40472
40528
  const botItems = karin.getAllBotList().filter((b) => b.bot.account.name !== "console");
@@ -40486,12 +40542,16 @@ var Handler = async () => {
40486
40542
  const botToImage = /* @__PURE__ */ new Map();
40487
40543
  for (const item of botItems) {
40488
40544
  if (!Array.from(masterToBot.entries()).some(([, b]) => b.account.selfId === item.bot.account.selfId)) continue;
40489
- const img = await getChangelogImage({ bot: item.bot }, {
40490
- localVersion: Root.pluginVersion,
40491
- remoteVersion: remote,
40492
- Tip: true
40493
- });
40494
- if (img && img.length > 0) botToImage.set(item.bot.account.selfId, [segment.text("karin-plugin-kkk 有新的更新!"), ...img]);
40545
+ const elements = [segment.text("karin-plugin-kkk 有新的更新!")];
40546
+ for (const version of pending) {
40547
+ const img = await getChangelogImage({ bot: item.bot }, {
40548
+ localVersion: Root.pluginVersion,
40549
+ remoteVersion: version,
40550
+ Tip: true
40551
+ });
40552
+ if (img && img.length > 0) elements.push(...img);
40553
+ }
40554
+ if (elements.length > 1) botToImage.set(item.bot.account.selfId, elements);
40495
40555
  }
40496
40556
  let storedMsgId;
40497
40557
  for (const owner of masters) {
@@ -40504,10 +40564,16 @@ var Handler = async () => {
40504
40564
  }
40505
40565
  if (storedMsgId) try {
40506
40566
  await db.set(UPDATE_MSGID_KEY, storedMsgId);
40567
+ await db.set(UPDATE_PUSHED_KEY, installTarget);
40507
40568
  } catch {}
40508
40569
  return true;
40509
40570
  };
40510
40571
  var handleUpdateHook = wrapWithErrorHandler(async (e) => {
40572
+ const pushedVersion = await db.get(UPDATE_PUSHED_KEY);
40573
+ if (typeof pushedVersion === "string" && pushedVersion) {
40574
+ await installAndRestart(e, pushedVersion);
40575
+ return;
40576
+ }
40511
40577
  e.reply("开始更新 karin-plugin-kkk ...", { reply: true });
40512
40578
  const upd = await checkPkgUpdate(Root.pluginName, { compare: "semver" });
40513
40579
  if (upd.status === "yes") {
@@ -40516,7 +40582,8 @@ var handleUpdateHook = wrapWithErrorHandler(async (e) => {
40516
40582
  const msgResult = await e.reply(`${Root.pluginName} 更新成功!\n${result.local} -> ${result.remote}\n开始执行重启......`);
40517
40583
  if (msgResult.messageId) try {
40518
40584
  await db.del(UPDATE_MSGID_KEY);
40519
- await db.del(UPDATE_LOCK_KEY);
40585
+ await db.del(UPDATE_PUSHED_KEY);
40586
+ for (const ch of UPDATE_CHANNELS) await db.del(updateLockKey(ch));
40520
40587
  } catch {}
40521
40588
  await restart(e.selfId, e.contact, msgResult.messageId);
40522
40589
  } else e.reply(`${Root.pluginName} 更新失败: ${result.data ?? "更新执行失败"}`);
@@ -40586,7 +40653,8 @@ var installAndRestart = async (e, version) => {
40586
40653
  const msgResult = await e.reply(`${Root.pluginName} 更新成功!→ ${version}\n开始执行重启......`);
40587
40654
  if (msgResult.messageId) try {
40588
40655
  await db.del(UPDATE_MSGID_KEY);
40589
- await db.del(UPDATE_LOCK_KEY);
40656
+ await db.del(UPDATE_PUSHED_KEY);
40657
+ for (const ch of UPDATE_CHANNELS) await db.del(updateLockKey(ch));
40590
40658
  } catch {}
40591
40659
  await restart(e.selfId, e.contact, msgResult.messageId);
40592
40660
  };
@@ -40743,7 +40811,8 @@ var kkkUpdateCommand = karin.command(/^#?kkk更新(?:\s*(\S+))?$/, handleKkkUpda
40743
40811
  });
40744
40812
  var kkkUpdateTest = process.env.NODE_ENV === "development" && karin.command("test", async (_e, next) => {
40745
40813
  await db.del(UPDATE_MSGID_KEY);
40746
- await db.del(UPDATE_LOCK_KEY);
40814
+ await db.del(UPDATE_PUSHED_KEY);
40815
+ for (const ch of UPDATE_CHANNELS) await db.del(updateLockKey(ch));
40747
40816
  await Handler();
40748
40817
  next();
40749
40818
  }, { name: "kkk-更新检测-测试" });
@@ -41716,7 +41785,7 @@ app$1.use(ASSETS_PREFIX, staticRouter);
41716
41785
  app.use(KKK_PREFIX, app$1);
41717
41786
  //#endregion
41718
41787
  //#region src/setup.ts
41719
- var requireVersion = "1.16.3";
41788
+ var requireVersion = "1.18.0";
41720
41789
  if (process.env.NODE_ENV !== "development" && isSemverGreater(requireVersion, Root.karinVersion)) {
41721
41790
  const msg = `插件构建时的 karin 版本 (${requireVersion}) 高于当前运行版本 (${Root.karinVersion}),可能会出现兼容性问题!`;
41722
41791
  logger$1.warn(msg);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "karin-plugin-kkk",
3
- "version": "2.45.0-beta.3",
3
+ "version": "2.45.0-beta.5",
4
4
  "description": "Karin 的「抖音」「B 站」视频解析/动态推送插件",
5
5
  "keywords": [
6
6
  "karin",
@@ -83,7 +83,7 @@
83
83
  "@lobehub/webfont-harmony-sans-sc": "^1.0.0",
84
84
  "emoji-datasource-apple": "16.0.0"
85
85
  },
86
- "timestamp": "2026-10-06T05:59:30.186Z",
86
+ "timestamp": "2026-10-06T08:24:09.485Z",
87
87
  "engines": {
88
88
  "node": ">=18.0.0"
89
89
  }