karin-plugin-kkk 2.45.2-beta.0 → 2.45.2-beta.1

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,23 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [2.45.2-beta.1](https://github.com/ikenxuan/karin-plugin-kkk/compare/v2.45.2-beta.0...v2.45.2-beta.1) (2026-10-26)
6
+
7
+
8
+ ### ✨ 新功能
9
+
10
+ * 初步支持抖音合集、短剧解析 ([0fc91a2](https://github.com/ikenxuan/karin-plugin-kkk/commit/0fc91a2258fd2d1c6fe59defa28883845f51fbba))
11
+
12
+
13
+ ### 🐛 错误修复
14
+
15
+ * **douyin:** 设置推送时改用游客接口转换sec_uid ([6ee68fa](https://github.com/ikenxuan/karin-plugin-kkk/commit/6ee68faae634447114721cc4ada5524f074d1663))
16
+
17
+
18
+ ### 🧰 其他更新
19
+
20
+ * 优化发版脚本 ([6175b0c](https://github.com/ikenxuan/karin-plugin-kkk/commit/6175b0c4f0815058db0559c22651a943921a846f))
21
+
5
22
  ## [2.45.2-beta.0](https://github.com/ikenxuan/karin-plugin-kkk/compare/v2.45.1...v2.45.2-beta.0) (2026-10-24)
6
23
 
7
24
 
@@ -1,10 +1,10 @@
1
1
  {
2
- "version": "2.45.2-beta.0",
3
- "buildTime": "2026-10-23T19:30:08.731Z",
4
- "buildTimestamp": 1792783808732,
2
+ "version": "2.45.2-beta.1",
3
+ "buildTime": "2026-10-26T06:10:25.889Z",
4
+ "buildTimestamp": 1792995025889,
5
5
  "name": "karin-plugin-kkk",
6
6
  "description": "Karin 的「抖音」「B 站」视频解析/动态推送插件",
7
7
  "homepage": "https://github.com/ikenxuan/karin-plugin-kkk",
8
- "commitHash": "f7656b43d22b833c3388975bb9fd03e2d2892be6",
9
- "shortCommitHash": "f7656b43"
8
+ "commitHash": "db1a3fc234b0dae7da5f86d8f16964c76447fd93",
9
+ "shortCommitHash": "db1a3fc2"
10
10
  }
@@ -1113,6 +1113,7 @@ var Common = new class Tools {
1113
1113
  unit = 1;
1114
1114
  }
1115
1115
  }
1116
+ if (unit > 1) temp += unit;
1116
1117
  return result + temp;
1117
1118
  }
1118
1119
  /**
@@ -7644,6 +7645,7 @@ var templateFonts = (() => {
7644
7645
  var SMART_THEME_PATHS = /* @__PURE__ */ new Set([
7645
7646
  "douyin/video-work",
7646
7647
  "douyin/image-work",
7648
+ "douyin/mix",
7647
7649
  "bilibili/dynamic/DYNAMIC_TYPE_LIVE_RCMD"
7648
7650
  ]);
7649
7651
  /**
@@ -7653,7 +7655,7 @@ var SMART_THEME_PATHS = /* @__PURE__ */ new Set([
7653
7655
  */
7654
7656
  var getCoverUrl$1 = (path, data) => {
7655
7657
  if (!data || typeof data !== "object") return "";
7656
- if (path === "douyin/video-work" || path === "bilibili/dynamic/DYNAMIC_TYPE_LIVE_RCMD") {
7658
+ if (path === "douyin/video-work" || path === "douyin/mix" || path === "bilibili/dynamic/DYNAMIC_TYPE_LIVE_RCMD") {
7657
7659
  const imageUrl = data.image_url;
7658
7660
  return typeof imageUrl === "string" ? imageUrl : "";
7659
7661
  }
@@ -16112,7 +16114,7 @@ var DouyinMoreIcon = ({ size = 36, ...props }) => /* @__PURE__ */ (0, import_jsx
16112
16114
  });
16113
16115
  //#endregion
16114
16116
  //#region ktr/template/douyin/article-work/components/ArticleWork.tsx
16115
- var getTitleClassName$2 = (titleLength) => {
16117
+ var getTitleClassName$3 = (titleLength) => {
16116
16118
  if (titleLength > 96) return "text-[42px] leading-[1.34]";
16117
16119
  if (titleLength > 72) return "text-[48px] leading-[1.3]";
16118
16120
  if (titleLength > 48) return "text-[54px] leading-[1.26]";
@@ -16271,7 +16273,7 @@ var DouyinPosterHeader$2 = ({ data, ctx }) => {
16271
16273
  var DouyinArticleTitle = ({ data }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", {
16272
16274
  className: "mt-13",
16273
16275
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
16274
- className: `${getTitleClassName$2(data.title.length)} font-bold text-foreground select-text`,
16276
+ className: `${getTitleClassName$3(data.title.length)} font-bold text-foreground select-text`,
16275
16277
  style: {
16276
16278
  wordBreak: "break-word",
16277
16279
  overflowWrap: "break-word"
@@ -17749,7 +17751,7 @@ var imageMediaTypeMeta = {
17749
17751
  icon: o$3
17750
17752
  }
17751
17753
  };
17752
- var getTitleClassName$1 = (titleLength) => {
17754
+ var getTitleClassName$2 = (titleLength) => {
17753
17755
  if (titleLength > 96) return "text-[42px] leading-[1.34]";
17754
17756
  if (titleLength > 72) return "text-[48px] leading-[1.3]";
17755
17757
  if (titleLength > 48) return "text-[54px] leading-[1.26]";
@@ -17871,7 +17873,7 @@ var DouyinPosterTitle$1 = ({ data }) => {
17871
17873
  const { title, desc } = data;
17872
17874
  const hasTitle = Boolean(title?.nodes.length);
17873
17875
  const hasDesc = Boolean(desc?.nodes.length);
17874
- const titleClassName = getTitleClassName$1(title ? extractRichTextPlainText(title).length : 0);
17876
+ const titleClassName = getTitleClassName$2(title ? extractRichTextPlainText(title).length : 0);
17875
17877
  const richTextOptions = {
17876
17878
  hashtag: { className: cn("text-inherit opacity-60", !hasTitle && "text-6xl") },
17877
17879
  mention: { className: "text-inherit" }
@@ -18597,6 +18599,415 @@ var live_default = defineTemplate({
18597
18599
  validate: (data) => typeof data === "object" && data !== null && typeof data.share_url === "string"
18598
18600
  });
18599
18601
  //#endregion
18602
+ //#region ktr/template/douyin/mix/components/Mix.tsx
18603
+ /** 万/亿 计数,数值与单位分开返回:数字用大号等宽,单位用小号 */
18604
+ var splitCount = (count) => {
18605
+ if (count >= 1e8) return {
18606
+ value: (count / 1e8).toFixed(1),
18607
+ unit: "亿"
18608
+ };
18609
+ if (count >= 1e4) return {
18610
+ value: (count / 1e4).toFixed(1),
18611
+ unit: "万"
18612
+ };
18613
+ return {
18614
+ value: count.toString(),
18615
+ unit: ""
18616
+ };
18617
+ };
18618
+ /** 总时长:不到一小时按分钟,否则按小时保留一位 */
18619
+ var splitRuntime = (milliseconds) => {
18620
+ const minutes = Math.round(milliseconds / 6e4);
18621
+ if (minutes < 60) return {
18622
+ value: minutes.toString(),
18623
+ unit: "分钟"
18624
+ };
18625
+ return {
18626
+ value: (minutes / 60).toFixed(1),
18627
+ unit: "小时"
18628
+ };
18629
+ };
18630
+ /** 单集时长 mm:ss */
18631
+ var formatDuration$4 = (milliseconds) => {
18632
+ const totalSeconds = Math.round(milliseconds / 1e3);
18633
+ const minutes = Math.floor(totalSeconds / 60);
18634
+ const seconds = totalSeconds % 60;
18635
+ return `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
18636
+ };
18637
+ /** 标题按字数分档:短标题撑满,长标题收小并最多三行 */
18638
+ var getTitleClassName$1 = (titleLength) => {
18639
+ if (titleLength <= 8) return "text-[112px] leading-[1.05]";
18640
+ if (titleLength <= 14) return "text-[96px] leading-[1.08]";
18641
+ if (titleLength <= 22) return "text-[76px] leading-[1.12]";
18642
+ return "text-[60px] leading-[1.18]";
18643
+ };
18644
+ /** 弥散背景:海报模糊铺底 + 单色离散杂色 */
18645
+ var MixBackground = ({ data, ctx }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18646
+ className: "pointer-events-none absolute inset-0 overflow-hidden select-none",
18647
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AmbientCover, {
18648
+ src: data.image_url,
18649
+ ctx
18650
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
18651
+ className: "absolute inset-0 opacity-[0.35] mix-blend-overlay dark:mix-blend-soft-light",
18652
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
18653
+ className: "h-full w-full",
18654
+ xmlns: "http://www.w3.org/2000/svg",
18655
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("filter", {
18656
+ id: "douyinMixNoise",
18657
+ children: [
18658
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feTurbulence", {
18659
+ type: "fractalNoise",
18660
+ baseFrequency: "0.8",
18661
+ numOctaves: "2",
18662
+ stitchTiles: "stitch"
18663
+ }),
18664
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feColorMatrix", {
18665
+ type: "saturate",
18666
+ values: "0"
18667
+ }),
18668
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("feComponentTransfer", { children: [
18669
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncR", {
18670
+ type: "discrete",
18671
+ tableValues: "0 1"
18672
+ }),
18673
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncG", {
18674
+ type: "discrete",
18675
+ tableValues: "0 1"
18676
+ }),
18677
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncB", {
18678
+ type: "discrete",
18679
+ tableValues: "0 1"
18680
+ })
18681
+ ] }),
18682
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feComponentTransfer", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncA", {
18683
+ type: "linear",
18684
+ slope: "2",
18685
+ intercept: "-0.5"
18686
+ }) })
18687
+ ]
18688
+ }) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
18689
+ width: "100%",
18690
+ height: "100%",
18691
+ filter: "url(#douyinMixNoise)",
18692
+ fill: "white"
18693
+ })]
18694
+ })
18695
+ })]
18696
+ });
18697
+ var MixHeader = ({ ctx }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
18698
+ className: "flex items-center justify-between",
18699
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18700
+ className: "flex items-center gap-4",
18701
+ children: [
18702
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "h-4 w-4 rounded-full bg-foreground/80" }),
18703
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
18704
+ className: "text-[26px] font-bold uppercase tracking-[0.24em] text-muted",
18705
+ children: "Douyin Mix"
18706
+ }),
18707
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
18708
+ className: "text-[26px] font-bold text-muted",
18709
+ children: "· 合集选集"
18710
+ })
18711
+ ]
18712
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
18713
+ src: isDark(ctx) ? "/image/douyin/dylogo-light.svg" : "/image/douyin/dylogo-dark.svg",
18714
+ alt: "抖音",
18715
+ className: "h-17 w-auto shrink-0 object-contain opacity-90"
18716
+ })]
18717
+ });
18718
+ var MixHero = ({ data }) => {
18719
+ const { kind, image_url, mix_name, author, statistics, episodes, total_episode, updated_to_episode } = data;
18720
+ const countUnit = kind === "collection" ? "个视频" : "集";
18721
+ const runtime = splitRuntime(episodes.reduce((sum, item) => sum + item.duration, 0));
18722
+ const stats = [
18723
+ {
18724
+ icon: a,
18725
+ label: "总播放",
18726
+ ...splitCount(statistics.play_count)
18727
+ },
18728
+ {
18729
+ icon: DouyinLikeIcon,
18730
+ label: "总点赞",
18731
+ ...splitCount(statistics.digg_count)
18732
+ },
18733
+ {
18734
+ icon: DouyinFavoriteIcon,
18735
+ label: "总收藏",
18736
+ ...splitCount(statistics.collect_count)
18737
+ },
18738
+ {
18739
+ icon: c,
18740
+ label: "总时长",
18741
+ ...runtime
18742
+ }
18743
+ ];
18744
+ const follower = splitCount(author.follower_count);
18745
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
18746
+ className: "mt-14 flex gap-14",
18747
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18748
+ className: `relative ${kind === "collection" ? "h-120" : "h-180"} w-120 shrink-0`,
18749
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
18750
+ src: image_url,
18751
+ alt: "",
18752
+ "aria-hidden": "true",
18753
+ className: "absolute inset-0 h-full w-full scale-[1.06] rounded-[40px] object-cover opacity-55 blur-[36px] saturate-[1.2]",
18754
+ referrerPolicy: "no-referrer",
18755
+ crossOrigin: "anonymous"
18756
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
18757
+ src: image_url,
18758
+ alt: "合集海报",
18759
+ className: "relative h-full w-full rounded-[40px] object-cover shadow-2xl",
18760
+ referrerPolicy: "no-referrer",
18761
+ crossOrigin: "anonymous"
18762
+ })]
18763
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18764
+ className: "flex min-w-0 flex-1 flex-col justify-between gap-10",
18765
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
18766
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
18767
+ className: `${getTitleClassName$1(mix_name.length)} line-clamp-3 font-bold text-balance text-foreground select-text`,
18768
+ style: {
18769
+ wordBreak: "break-word",
18770
+ overflowWrap: "break-word"
18771
+ },
18772
+ children: mix_name
18773
+ }),
18774
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18775
+ className: "mt-8 flex flex-wrap items-center gap-4",
18776
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
18777
+ className: "rounded-full bg-foreground px-7 py-3 text-[30px] font-bold leading-none text-background",
18778
+ children: [
18779
+ "共 ",
18780
+ total_episode,
18781
+ " ",
18782
+ countUnit
18783
+ ]
18784
+ }), updated_to_episode < total_episode && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
18785
+ className: "rounded-full border border-foreground/20 px-7 py-3 text-[30px] font-semibold leading-none text-foreground/80",
18786
+ children: [
18787
+ "更新至第 ",
18788
+ updated_to_episode,
18789
+ " 集"
18790
+ ]
18791
+ })]
18792
+ }),
18793
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18794
+ className: "mt-10 flex min-w-0 items-center gap-5",
18795
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
18796
+ src: author.avatar,
18797
+ alt: "头像",
18798
+ className: "h-20 w-20 shrink-0 rounded-full object-cover shadow-xl",
18799
+ referrerPolicy: "no-referrer",
18800
+ crossOrigin: "anonymous"
18801
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18802
+ className: "min-w-0",
18803
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18804
+ className: "flex min-w-0 items-center gap-2",
18805
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
18806
+ className: "truncate text-[38px] font-bold leading-tight text-foreground select-text",
18807
+ children: author.nickname
18808
+ }), author.verified && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RiVerifiedBadgeFill, {
18809
+ size: 34,
18810
+ className: "shrink-0 text-foreground/70"
18811
+ })]
18812
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18813
+ className: "mt-1 truncate text-[26px] text-muted select-text",
18814
+ children: [
18815
+ "抖音号 ",
18816
+ author.short_id,
18817
+ " · 粉丝 ",
18818
+ follower.value,
18819
+ follower.unit
18820
+ ]
18821
+ })]
18822
+ })]
18823
+ })
18824
+ ] }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
18825
+ className: "grid grid-cols-2 gap-x-10 gap-y-8",
18826
+ children: stats.map((stat) => {
18827
+ const Icon = stat.icon;
18828
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18829
+ className: "min-w-0",
18830
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18831
+ className: "flex items-center gap-3 text-[28px] font-semibold text-muted",
18832
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, {
18833
+ size: 32,
18834
+ weight: "fill",
18835
+ className: "text-foreground/80"
18836
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: stat.label })]
18837
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18838
+ className: "mt-2 flex items-baseline gap-2 text-foreground select-text",
18839
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
18840
+ className: "text-[64px] font-semibold leading-none tabular-nums",
18841
+ children: stat.value
18842
+ }), stat.unit && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
18843
+ className: "text-[28px] font-bold",
18844
+ children: stat.unit
18845
+ })]
18846
+ })]
18847
+ }, stat.label);
18848
+ })
18849
+ })]
18850
+ })]
18851
+ });
18852
+ };
18853
+ /** 区块标题:竖条 + 标题 */
18854
+ var SectionTitle$1 = ({ children, extra }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18855
+ className: "flex items-end justify-between gap-8",
18856
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18857
+ className: "flex items-center gap-4",
18858
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "h-10 w-2 rounded-full bg-foreground/80" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
18859
+ className: "text-[44px] font-bold leading-none text-foreground",
18860
+ children
18861
+ })]
18862
+ }), extra]
18863
+ });
18864
+ var MixSynopsis = ({ data }) => {
18865
+ if (!data.desc) return null;
18866
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
18867
+ className: "mt-16",
18868
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionTitle$1, { children: "简介" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
18869
+ className: "mt-6 line-clamp-5 text-[40px] leading-[1.6] text-foreground/85 select-text",
18870
+ style: { overflowWrap: "break-word" },
18871
+ children: data.desc
18872
+ })]
18873
+ });
18874
+ };
18875
+ var MixEpisodes = ({ data }) => {
18876
+ const { kind, episodes, total_episode, updated_to_episode, timeoutSeconds } = data;
18877
+ const episodeMap = new Map(episodes.map((item) => [item.episode, item]));
18878
+ const lastEpisode = episodes.reduce((max, item) => Math.max(max, item.episode), 0);
18879
+ const cells = Array.from({ length: lastEpisode }, (_, index) => ({
18880
+ episode: index + 1,
18881
+ item: episodeMap.get(index + 1)
18882
+ }));
18883
+ const missingCount = cells.filter((cell) => cell.item === void 0).length;
18884
+ const padLength = String(lastEpisode).length;
18885
+ const listedRange = lastEpisode < updated_to_episode;
18886
+ const unit = kind === "collection" ? "视频" : "剧集";
18887
+ const countUnit = kind === "collection" ? "个视频" : "集";
18888
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
18889
+ className: "mt-16",
18890
+ children: [
18891
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionTitle$1, {
18892
+ extra: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
18893
+ className: "text-[30px] font-semibold text-muted",
18894
+ children: [
18895
+ "已列出 ",
18896
+ episodes.length,
18897
+ " / ",
18898
+ total_episode,
18899
+ " ",
18900
+ countUnit
18901
+ ]
18902
+ }),
18903
+ children: "选集"
18904
+ }),
18905
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18906
+ className: "mt-8 flex items-center justify-between gap-10 rounded-4xl border border-foreground/10 bg-foreground/6 px-10 py-8",
18907
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18908
+ className: "flex min-w-0 flex-wrap items-center gap-x-4 gap-y-3 text-[36px] font-semibold leading-tight text-foreground",
18909
+ children: [
18910
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "发送" }),
18911
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
18912
+ className: "rounded-2xl bg-foreground px-5 py-2 font-bold text-background",
18913
+ children: "第?集"
18914
+ }),
18915
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: ["或直接发送集数,解析对应", unit] })
18916
+ ]
18917
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18918
+ className: "shrink-0 text-right",
18919
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18920
+ className: "text-[64px] font-semibold leading-none text-foreground tabular-nums",
18921
+ children: [timeoutSeconds, "s"]
18922
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
18923
+ className: "mt-2 text-[24px] font-semibold text-muted",
18924
+ children: "内有效"
18925
+ })]
18926
+ })]
18927
+ }),
18928
+ kind === "collection" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
18929
+ className: "mt-8 grid grid-cols-2 gap-4",
18930
+ children: cells.map((cell) => cell.item === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18931
+ className: "flex items-center gap-6 rounded-3xl border-2 border-dashed border-foreground/20 px-7 py-6",
18932
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
18933
+ className: "shrink-0 text-[40px] font-semibold leading-none text-foreground/25 tabular-nums",
18934
+ children: String(cell.episode).padStart(padLength, "0")
18935
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
18936
+ className: "text-[30px] font-semibold text-foreground/25",
18937
+ children: "缺失"
18938
+ })]
18939
+ }, cell.episode) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18940
+ className: "flex items-center gap-6 rounded-3xl border border-foreground/10 bg-foreground/6 px-7 py-6",
18941
+ children: [
18942
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
18943
+ className: "shrink-0 text-[40px] font-semibold leading-none text-foreground tabular-nums select-text",
18944
+ children: String(cell.episode).padStart(padLength, "0")
18945
+ }),
18946
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
18947
+ className: "line-clamp-2 min-w-0 flex-1 text-[30px] font-semibold leading-[1.35] text-foreground select-text",
18948
+ style: { overflowWrap: "break-word" },
18949
+ children: cell.item.title || "无标题"
18950
+ }),
18951
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
18952
+ className: "shrink-0 text-[24px] text-muted tabular-nums",
18953
+ children: formatDuration$4(cell.item.duration)
18954
+ })
18955
+ ]
18956
+ }, cell.episode))
18957
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
18958
+ className: "mt-8 grid grid-cols-10 gap-4",
18959
+ children: cells.map((cell) => cell.item === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18960
+ className: "flex aspect-square flex-col items-center justify-center rounded-3xl border-2 border-dashed border-foreground/20",
18961
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
18962
+ className: "text-[44px] font-semibold leading-none text-foreground/25 tabular-nums",
18963
+ children: String(cell.episode).padStart(padLength, "0")
18964
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
18965
+ className: "mt-2 text-[22px] font-semibold text-foreground/25",
18966
+ children: "缺失"
18967
+ })]
18968
+ }, cell.episode) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18969
+ className: "flex aspect-square flex-col items-center justify-center rounded-3xl border border-foreground/10 bg-foreground/6",
18970
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
18971
+ className: "text-[44px] font-semibold leading-none text-foreground tabular-nums select-text",
18972
+ children: String(cell.episode).padStart(padLength, "0")
18973
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
18974
+ className: "mt-2 text-[22px] text-muted tabular-nums",
18975
+ children: formatDuration$4(cell.item.duration)
18976
+ })]
18977
+ }, cell.episode))
18978
+ }),
18979
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
18980
+ className: "mt-8 flex flex-wrap items-center justify-between gap-6 text-[26px] text-muted",
18981
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [missingCount > 0 && `虚线格为接口未返回的${unit}(${missingCount} ${kind === "collection" ? "个" : "集"}),暂不能解析。`, listedRange && `已列出第 1–${lastEpisode} 集,共更新 ${updated_to_episode} 集。`] }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
18982
+ className: "select-text",
18983
+ children: ["图片生成于: ", format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss")]
18984
+ })]
18985
+ })
18986
+ ]
18987
+ });
18988
+ };
18989
+ var DouyinMix = import_react.memo((props) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DefaultLayout, {
18990
+ ...props,
18991
+ className: "relative overflow-hidden",
18992
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MixBackground, { ...props }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
18993
+ className: "relative z-10 px-20 pt-18",
18994
+ children: [
18995
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MixHeader, { ...props }),
18996
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MixHero, { ...props }),
18997
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MixSynopsis, { ...props }),
18998
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MixEpisodes, { ...props })
18999
+ ]
19000
+ })]
19001
+ }));
19002
+ DouyinMix.displayName = "DouyinMix";
19003
+ //#endregion
19004
+ //#region ktr/template/douyin/mix/index.tsx
19005
+ var mix_default = defineTemplate({
19006
+ name: "合集选集",
19007
+ description: "抖音合集(短剧 / 普通合集)选集列表模板",
19008
+ component: DouyinMix
19009
+ });
19010
+ //#endregion
18600
19011
  //#region ktr/template/douyin/musicinfo/components/MusicInfo.tsx
18601
19012
  /**
18602
19013
  * 抖音Logo头部组件
@@ -29428,6 +29839,7 @@ var templates = {
29428
29839
  "douyin/favorite-list": favorite_list_default,
29429
29840
  "douyin/image-work": image_work_default,
29430
29841
  "douyin/live": live_default,
29842
+ "douyin/mix": mix_default,
29431
29843
  "douyin/musicinfo": musicinfo_default,
29432
29844
  "douyin/qrcodeImg": qrcodeImg_default$2,
29433
29845
  "douyin/recommend-list": recommend_list_default,
@@ -35530,6 +35942,24 @@ async function burnDouyinDanmaku(videoPath, danmakuList, outputPath, options = {
35530
35942
  return result.status;
35531
35943
  }
35532
35944
  //#endregion
35945
+ //#region src/platform/douyin/mix.ts
35946
+ /** 句中的「第N集」,集数可以是阿拉伯数字或中文数字,数字两侧允许空格(模板里写的就是「第 N 集」) */
35947
+ var EPISODE_IN_TEXT = /第\s*([0-9]+|[零一二三四五六七八九十百千]+)\s*集/;
35948
+ /** 整条回复只有集数:「12」「12集」「十二」 */
35949
+ var EPISODE_ONLY = /^([0-9]+|[零一二三四五六七八九十百千]+)\s*集?$/;
35950
+ /**
35951
+ * 从用户回复里解析要看的集数。
35952
+ * @param msg 用户回复的文本
35953
+ * @returns 集数(从 1 开始);没解析出来返回 null
35954
+ */
35955
+ var parseMixEpisode = (msg) => {
35956
+ const text = msg.trim();
35957
+ const raw = (EPISODE_IN_TEXT.exec(text) ?? EPISODE_ONLY.exec(text))?.[1];
35958
+ if (!raw) return null;
35959
+ const episode = /^[0-9]+$/.test(raw) ? Number(raw) : Common.chineseToArabic(raw);
35960
+ return Number.isInteger(episode) && episode > 0 ? episode : null;
35961
+ };
35962
+ //#endregion
35533
35963
  //#region src/platform/douyin/videoQuality.ts
35534
35964
  /** 档位优先级,从高到低 */
35535
35965
  var QUALITY_PRIORITY = [
@@ -37019,6 +37449,69 @@ var DouYin = class DouYin extends Base {
37019
37449
  }
37020
37450
  return true;
37021
37451
  }
37452
+ case "mix_work": {
37453
+ this.workType = "bangumi";
37454
+ /** 单次最多拉取的集数,超出部分不展示 */
37455
+ const episodeLimit = 200;
37456
+ const timeoutSeconds = 120;
37457
+ const awemeList = (await this.amagi.douyin.fetcher.fetchMixAweme({
37458
+ mix_id: data.mix_id,
37459
+ number: episodeLimit
37460
+ })).data.aweme_list;
37461
+ const first = awemeList[0];
37462
+ if (!first) throw new Error("获取合集作品列表失败,可能是因为该合集已被删除或设置为私密。");
37463
+ const mixInfo = first.mix_info;
37464
+ const author = first.author;
37465
+ const isPlaylet = typeof mixInfo.statis.total_episode === "number";
37466
+ const episodes = awemeList.map((aweme) => ({
37467
+ episode: aweme.mix_info.statis.current_episode,
37468
+ aweme_id: aweme.aweme_id,
37469
+ title: aweme.desc.replace(/#\S+/g, "").trim(),
37470
+ duration: aweme.video.duration
37471
+ }));
37472
+ const img = await Render(this.e, "douyin/mix", {
37473
+ kind: isPlaylet ? "playlet" : "collection",
37474
+ mix_name: mixInfo.mix_name,
37475
+ image_url: mixInfo.cover_url.url_list[0],
37476
+ desc: isPlaylet ? episodes[0].title : "",
37477
+ total_episode: isPlaylet ? mixInfo.statis.total_episode : mixInfo.statis.updated_to_episode,
37478
+ updated_to_episode: mixInfo.statis.updated_to_episode,
37479
+ author: {
37480
+ nickname: author.nickname,
37481
+ avatar: author.avatar_thumb.url_list[0],
37482
+ short_id: author.unique_id === "" ? author.short_id : author.unique_id,
37483
+ follower_count: author.follower_count,
37484
+ verified: !!author.custom_verify || !!author.enterprise_verify_reason
37485
+ },
37486
+ statistics: {
37487
+ play_count: awemeList.reduce((sum, aweme) => sum + aweme.statistics.play_count, 0),
37488
+ digg_count: awemeList.reduce((sum, aweme) => sum + aweme.statistics.digg_count, 0),
37489
+ collect_count: awemeList.reduce((sum, aweme) => sum + aweme.statistics.collect_count, 0)
37490
+ },
37491
+ episodes,
37492
+ timeoutSeconds
37493
+ });
37494
+ await this.e.reply([...img, segment.text(`请在${timeoutSeconds}秒内输入 第?集 选择集数`)]);
37495
+ const context = await karin.ctx(this.e, {
37496
+ reply: true,
37497
+ throwOnTimeout: false,
37498
+ time: timeoutSeconds
37499
+ });
37500
+ if (!context) return true;
37501
+ const episode = parseMixEpisode(context.msg);
37502
+ const target = episode === null ? void 0 : episodes.find((item) => item.episode === episode);
37503
+ if (!target) {
37504
+ await this.e.reply(episode === null ? "匹配内容失败,请重新发送链接再次解析" : `第${episode}集不在可解析的剧集里,请重新发送链接再次解析`);
37505
+ return true;
37506
+ }
37507
+ await this.e.reply(`收到请求,第${episode}集\n${mixInfo.mix_name}\n正在解析中`);
37508
+ const targetData = {
37509
+ type: "one_work",
37510
+ aweme_id: target.aweme_id
37511
+ };
37512
+ await new DouYin(context, targetData, { forceBurnDanmaku: this.forceBurnDanmaku }).DouyinHandler(targetData);
37513
+ return true;
37514
+ }
37022
37515
  case "music_work": {
37023
37516
  this.workType = "music";
37024
37517
  const musicInfo = (await this.amagi.douyin.fetcher.fetchMusicInfo({ music_id: data.music_id })).data.music_info;
@@ -37214,6 +37707,14 @@ var getDouyinID = async (event, url, log = true) => {
37214
37707
  room_id: longLink.split("/").pop()
37215
37708
  };
37216
37709
  break;
37710
+ case /\/(?:share\/(?:playlet|mix)\/detail|collection)\/(\d+)/.test(longLink): {
37711
+ const mixMatch = /\/(?:share\/(?:playlet|mix)\/detail|collection)\/(\d+)/.exec(longLink);
37712
+ result = {
37713
+ type: "mix_work",
37714
+ mix_id: mixMatch ? mixMatch[1] : void 0
37715
+ };
37716
+ break;
37717
+ }
37217
37718
  case /video\/(\d+)/.test(longLink):
37218
37719
  case /article\/(\d+)/.test(longLink):
37219
37720
  case /note\/(\d+)/.test(longLink): {
@@ -38164,23 +38665,10 @@ var DouYinpush = class extends Base {
38164
38665
  const botId = this.e.selfId;
38165
38666
  try {
38166
38667
  const inputDouyinId = this.e.msg.replace(/^#设置抖音推送/, "").trim();
38167
- /**
38168
- * 搜索结果按响应形态自述(判别式 `__search_type`,由 amagi 的 normalize 按响应结构 +
38169
- * 请求类型写入)。订阅只认「用户搜索」那一支:抖音把 user 请求回成别的形态时在这里说清楚,
38170
- * 而不是拿一个 undefined 去遍历。
38171
- */
38172
- if (data.__search_type !== "user") throw new Error(`抖音没有返回用户搜索结果(返回形态:${data.__search_type ?? "未知"})`);
38173
- let matchedUser = null;
38174
- for (const userItem of data.user_list) if ((userItem.user_info.unique_id === "" ? userItem.user_info.short_id : userItem.user_info.unique_id) === inputDouyinId) {
38175
- matchedUser = userItem.user_info;
38176
- break;
38177
- }
38178
- if (!matchedUser) throw new Error(`未找到抖音号为 ${inputDouyinId} 的用户`);
38179
- const sec_uid = matchedUser.sec_uid;
38180
- const UserInfoData = await this.amagi.douyin.fetcher.fetchUserProfile({ sec_uid });
38181
38668
  /** 处理抖音号 */
38182
- let user_shortid;
38183
- user_shortid = UserInfoData.data.user.unique_id === "" ? UserInfoData.data.user.short_id : UserInfoData.data.user.unique_id;
38669
+ const user_shortid = data.user_info.unique_id === "" ? data.user_info.short_id : data.user_info.unique_id;
38670
+ const sec_uid = data.user_info.sec_uid;
38671
+ if (inputDouyinId !== user_shortid) throw new Error(`未找到抖音号为 ${inputDouyinId} 的用户`);
38184
38672
  config.douyin ??= [];
38185
38673
  const existingItem = config.douyin.find((item) => item.sec_uid === sec_uid);
38186
38674
  const isSubscribed = await douyinDBInstance.isSubscribed(sec_uid, groupId);
@@ -38200,31 +38688,31 @@ var DouYinpush = class extends Base {
38200
38688
  config.douyin.splice(index, 1);
38201
38689
  }
38202
38690
  Config.Modify("pushlist", "douyin", config.douyin);
38203
- await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n删除成功!${UserInfoData.data.user.nickname}\n抖音号:${user_shortid}`);
38204
- logger$1.info(`\n删除成功!${UserInfoData.data.user.nickname}\n抖音号:${user_shortid}\nsec_uid${UserInfoData.data.user.sec_uid}`);
38691
+ await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n删除成功!${data.user_info.nickname}\n抖音号:${user_shortid}`);
38692
+ logger$1.info(`\n删除成功!${data.user_info.nickname}\n抖音号:${user_shortid}\nsec_uid${data.user_info.sec_uid}`);
38205
38693
  } else {
38206
38694
  existingItem.group_id.push(`${groupId}:${botId}`);
38207
38695
  if (!existingItem.pushTypes || existingItem.pushTypes.length === 0) existingItem.pushTypes = ["post", "live"];
38208
- if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid, UserInfoData.data.user.nickname);
38696
+ if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid, data.user_info.nickname);
38209
38697
  Config.Modify("pushlist", "douyin", config.douyin);
38210
- await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${UserInfoData.data.user.nickname}\n抖音号:${user_shortid}`);
38698
+ await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${data.user_info.nickname}\n抖音号:${user_shortid}`);
38211
38699
  if (Config.douyin.push.switch === false) await this.e.reply("请发送「#设置抖音推送开启」以进行推送");
38212
- logger$1.info(`\n设置成功!${UserInfoData.data.user.nickname}\n抖音号:${user_shortid}\nsec_uid${UserInfoData.data.user.sec_uid}`);
38700
+ logger$1.info(`\n设置成功!${data.user_info.nickname}\n抖音号:${user_shortid}\nsec_uid${data.user_info.sec_uid}`);
38213
38701
  }
38214
38702
  } else {
38215
38703
  config.douyin.push({
38216
38704
  switch: true,
38217
38705
  sec_uid,
38218
38706
  group_id: [`${groupId}:${botId}`],
38219
- remark: UserInfoData.data.user.nickname,
38707
+ remark: data.user_info.nickname,
38220
38708
  short_id: user_shortid,
38221
38709
  pushTypes: ["post", "live"]
38222
38710
  });
38223
- if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid, UserInfoData.data.user.nickname);
38711
+ if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid, data.user_info.nickname);
38224
38712
  Config.Modify("pushlist", "douyin", config.douyin);
38225
- await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${UserInfoData.data.user.nickname}\n抖音号:${user_shortid}`);
38713
+ await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${data.user_info.nickname}\n抖音号:${user_shortid}`);
38226
38714
  if (Config.douyin.push.switch === false) await this.e.reply("请发送「#设置抖音推送开启」以进行推送");
38227
- logger$1.info(`\n设置成功!${UserInfoData.data.user.nickname}\n抖音号:${user_shortid}\nsec_uid${UserInfoData.data.user.sec_uid}`);
38715
+ logger$1.info(`\n设置成功!${data.user_info.nickname}\n抖音号:${user_shortid}\nsec_uid${data.user_info.sec_uid}`);
38228
38716
  }
38229
38717
  await this.renderPushList();
38230
38718
  } catch (error) {
@@ -40235,10 +40723,7 @@ var handleSetDouyinPush = wrapWithErrorHandler(async (e) => {
40235
40723
  logger$1.info(`抖音推送已${enable ? "开启" : "关闭"}`);
40236
40724
  return true;
40237
40725
  }
40238
- const data = await douyinFetcher.searchContent({
40239
- query,
40240
- type: "user"
40241
- });
40726
+ const data = await douyinFetcher.fetchGuestUserInfo({ unique_id: query });
40242
40727
  await new DouYinpush(e).setting(data.data);
40243
40728
  return true;
40244
40729
  }, { businessName: "设置抖音推送" });
package/lib/style.css CHANGED
@@ -14063,6 +14063,13 @@
14063
14063
  overflow: hidden;
14064
14064
  }
14065
14065
 
14066
+ .line-clamp-5 {
14067
+ -webkit-line-clamp: 5;
14068
+ -webkit-box-orient: vertical;
14069
+ display: -webkit-box;
14070
+ overflow: hidden;
14071
+ }
14072
+
14066
14073
  .block {
14067
14074
  display: block;
14068
14075
  }
@@ -14339,6 +14346,10 @@
14339
14346
  height: calc(var(--spacing) * 110);
14340
14347
  }
14341
14348
 
14349
+ .h-120 {
14350
+ height: calc(var(--spacing) * 120);
14351
+ }
14352
+
14342
14353
  .h-125 {
14343
14354
  height: calc(var(--spacing) * 125);
14344
14355
  }
@@ -14359,6 +14370,10 @@
14359
14370
  height: calc(var(--spacing) * 175);
14360
14371
  }
14361
14372
 
14373
+ .h-180 {
14374
+ height: calc(var(--spacing) * 180);
14375
+ }
14376
+
14362
14377
  .h-200 {
14363
14378
  height: calc(var(--spacing) * 200);
14364
14379
  }
@@ -15129,6 +15144,10 @@
15129
15144
  scale: var(--tw-scale-x) var(--tw-scale-y);
15130
15145
  }
15131
15146
 
15147
+ .scale-\[1\.06\] {
15148
+ scale: 1.06;
15149
+ }
15150
+
15132
15151
  .scale-\[1\.08\] {
15133
15152
  scale: 1.08;
15134
15153
  }
@@ -15249,6 +15268,10 @@
15249
15268
  grid-template-columns: repeat(6, minmax(0, 1fr));
15250
15269
  }
15251
15270
 
15271
+ .grid-cols-10 {
15272
+ grid-template-columns: repeat(10, minmax(0, 1fr));
15273
+ }
15274
+
15252
15275
  .grid-cols-12 {
15253
15276
  grid-template-columns: repeat(12, minmax(0, 1fr));
15254
15277
  }
@@ -15505,6 +15528,10 @@
15505
15528
  column-gap: calc(var(--spacing) * 3);
15506
15529
  }
15507
15530
 
15531
+ .gap-x-4 {
15532
+ column-gap: calc(var(--spacing) * 4);
15533
+ }
15534
+
15508
15535
  .gap-x-5 {
15509
15536
  column-gap: calc(var(--spacing) * 5);
15510
15537
  }
@@ -16089,6 +16116,16 @@
16089
16116
  }
16090
16117
  }
16091
16118
 
16119
+ .border-foreground\/20 {
16120
+ border-color: var(--foreground);
16121
+ }
16122
+
16123
+ @supports (color: color-mix(in lab, red, red)) {
16124
+ .border-foreground\/20 {
16125
+ border-color: color-mix(in oklab, var(--foreground) 20%, transparent);
16126
+ }
16127
+ }
16128
+
16092
16129
  .border-gray-200 {
16093
16130
  border-color: var(--color-gray-200);
16094
16131
  }
@@ -16523,7 +16560,17 @@
16523
16560
  }
16524
16561
  }
16525
16562
 
16526
- .bg-foreground, .bg-foreground\/50 {
16563
+ .bg-foreground, .bg-foreground\/6 {
16564
+ background-color: var(--foreground);
16565
+ }
16566
+
16567
+ @supports (color: color-mix(in lab, red, red)) {
16568
+ .bg-foreground\/6 {
16569
+ background-color: color-mix(in oklab, var(--foreground) 6%, transparent);
16570
+ }
16571
+ }
16572
+
16573
+ .bg-foreground\/50 {
16527
16574
  background-color: var(--foreground);
16528
16575
  }
16529
16576
 
@@ -16543,6 +16590,16 @@
16543
16590
  }
16544
16591
  }
16545
16592
 
16593
+ .bg-foreground\/80 {
16594
+ background-color: var(--foreground);
16595
+ }
16596
+
16597
+ @supports (color: color-mix(in lab, red, red)) {
16598
+ .bg-foreground\/80 {
16599
+ background-color: color-mix(in oklab, var(--foreground) 80%, transparent);
16600
+ }
16601
+ }
16602
+
16546
16603
  .bg-indigo-500 {
16547
16604
  background-color: var(--color-indigo-500);
16548
16605
  }
@@ -17846,6 +17903,10 @@
17846
17903
  font-size: 36px;
17847
17904
  }
17848
17905
 
17906
+ .text-\[38px\] {
17907
+ font-size: 38px;
17908
+ }
17909
+
17849
17910
  .text-\[40px\] {
17850
17911
  font-size: 40px;
17851
17912
  }
@@ -17914,6 +17975,10 @@
17914
17975
  font-size: 72px;
17915
17976
  }
17916
17977
 
17978
+ .text-\[76px\] {
17979
+ font-size: 76px;
17980
+ }
17981
+
17917
17982
  .text-\[80px\] {
17918
17983
  font-size: 80px;
17919
17984
  }
@@ -17930,6 +17995,10 @@
17930
17995
  font-size: 96px;
17931
17996
  }
17932
17997
 
17998
+ .text-\[112px\] {
17999
+ font-size: 112px;
18000
+ }
18001
+
17933
18002
  .text-\[120px\] {
17934
18003
  font-size: 120px;
17935
18004
  }
@@ -17994,6 +18063,11 @@
17994
18063
  line-height: 1.4;
17995
18064
  }
17996
18065
 
18066
+ .leading-\[1\.05\] {
18067
+ --tw-leading: 1.05;
18068
+ line-height: 1.05;
18069
+ }
18070
+
17997
18071
  .leading-\[1\.6\] {
17998
18072
  --tw-leading: 1.6;
17999
18073
  line-height: 1.6;
@@ -18009,6 +18083,11 @@
18009
18083
  line-height: 1.08;
18010
18084
  }
18011
18085
 
18086
+ .leading-\[1\.12\] {
18087
+ --tw-leading: 1.12;
18088
+ line-height: 1.12;
18089
+ }
18090
+
18012
18091
  .leading-\[1\.16\] {
18013
18092
  --tw-leading: 1.16;
18014
18093
  line-height: 1.16;
@@ -18029,6 +18108,11 @@
18029
18108
  line-height: 1.34;
18030
18109
  }
18031
18110
 
18111
+ .leading-\[1\.35\] {
18112
+ --tw-leading: 1.35;
18113
+ line-height: 1.35;
18114
+ }
18115
+
18032
18116
  .leading-\[1\.45\] {
18033
18117
  --tw-leading: 1.45;
18034
18118
  line-height: 1.45;
@@ -18239,6 +18323,10 @@
18239
18323
  letter-spacing: var(--tracking-widest);
18240
18324
  }
18241
18325
 
18326
+ .text-balance {
18327
+ text-wrap: balance;
18328
+ }
18329
+
18242
18330
  .wrap-break-word {
18243
18331
  overflow-wrap: break-word;
18244
18332
  }
@@ -18337,7 +18425,7 @@
18337
18425
  }
18338
18426
  }
18339
18427
 
18340
- .text-background\/80 {
18428
+ .text-background, .text-background\/80 {
18341
18429
  color: var(--background);
18342
18430
  }
18343
18431
 
@@ -18483,6 +18571,16 @@
18483
18571
  }
18484
18572
  }
18485
18573
 
18574
+ .text-foreground\/25 {
18575
+ color: var(--foreground);
18576
+ }
18577
+
18578
+ @supports (color: color-mix(in lab, red, red)) {
18579
+ .text-foreground\/25 {
18580
+ color: color-mix(in oklab, var(--foreground) 25%, transparent);
18581
+ }
18582
+ }
18583
+
18486
18584
  .text-foreground\/28 {
18487
18585
  color: var(--foreground);
18488
18586
  }
@@ -18898,6 +18996,10 @@
18898
18996
  opacity: .5;
18899
18997
  }
18900
18998
 
18999
+ .opacity-55 {
19000
+ opacity: .55;
19001
+ }
19002
+
18901
19003
  .opacity-60 {
18902
19004
  opacity: .6;
18903
19005
  }
@@ -19047,6 +19149,11 @@
19047
19149
  filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
19048
19150
  }
19049
19151
 
19152
+ .blur-\[36px\] {
19153
+ --tw-blur: blur(36px);
19154
+ filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
19155
+ }
19156
+
19050
19157
  .blur-\[46px\] {
19051
19158
  --tw-blur: blur(46px);
19052
19159
  filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "karin-plugin-kkk",
3
- "version": "2.45.2-beta.0",
3
+ "version": "2.45.2-beta.1",
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-23T19:29:44.843Z",
86
+ "timestamp": "2026-10-26T06:09:50.297Z",
87
87
  "engines": {
88
88
  "node": ">=18.0.0"
89
89
  }