karin-plugin-kkk 2.45.1 → 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 +30 -0
- package/lib/build-metadata.json +5 -5
- package/lib/core_chunk/default.js +164 -3
- package/lib/core_chunk/main.js +611 -53
- package/lib/style.css +109 -2
- package/package.json +2 -2
package/lib/core_chunk/main.js
CHANGED
|
@@ -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$
|
|
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$
|
|
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$
|
|
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$
|
|
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,
|
|
@@ -31253,6 +31665,41 @@ var buildBilibiliRichTextForwardMessage = async (document, options = {}) => {
|
|
|
31253
31665
|
//#endregion
|
|
31254
31666
|
//#region src/platform/bilibili/bilibili.ts
|
|
31255
31667
|
var img$1;
|
|
31668
|
+
/**
|
|
31669
|
+
* B站 PCDN 线路的域名特征。
|
|
31670
|
+
* 这类域名常被代理/去广告规则的 hosts 指向 0.0.0.0,直接请求会 ECONNREFUSED。
|
|
31671
|
+
*/
|
|
31672
|
+
var BILIBILI_PCDN_HOST_RE = /(?:^|\.)(?:mcdn|pcdn)\.bilivideo\.(?:cn|com)$|(?:^|\.)szbdyd\.com$/i;
|
|
31673
|
+
/** B站自有 CDN 域名,PCDN 之外的线路可作为稳定备选 */
|
|
31674
|
+
var BILIBILI_CDN_HOST_RE = /(?:^|\.)bilivideo\.(?:cn|com)$/i;
|
|
31675
|
+
/** 取 URL 的 hostname,非法 URL 返回空串 */
|
|
31676
|
+
var getUrlHostname = (url) => {
|
|
31677
|
+
try {
|
|
31678
|
+
return new URL(url).hostname;
|
|
31679
|
+
} catch {
|
|
31680
|
+
return "";
|
|
31681
|
+
}
|
|
31682
|
+
};
|
|
31683
|
+
/** 判断一条 B站直链是否走 PCDN 线路 */
|
|
31684
|
+
var isBilibiliPcdnUrl = (url) => BILIBILI_PCDN_HOST_RE.test(getUrlHostname(url));
|
|
31685
|
+
/** 判断一条 B站直链是否走 B站自有 CDN */
|
|
31686
|
+
var isBilibiliCdnUrl = (url) => BILIBILI_CDN_HOST_RE.test(getUrlHostname(url));
|
|
31687
|
+
/**
|
|
31688
|
+
* 从播放接口返回的流信息里选一条可用直链。
|
|
31689
|
+
*
|
|
31690
|
+
* `base_url` 可能落在 PCDN 线路上,而 `backup_url` 里通常还有常规 CDN;
|
|
31691
|
+
* 主直链不是 PCDN 时保持原行为,是 PCDN 时优先换到 B站自有 CDN 的备用直链,
|
|
31692
|
+
* 全部不可用时退回 `base_url`。
|
|
31693
|
+
*/
|
|
31694
|
+
var getBilibiliStreamUrl = (stream) => {
|
|
31695
|
+
if (!stream) return void 0;
|
|
31696
|
+
const baseUrl = stream.base_url ?? stream.baseUrl;
|
|
31697
|
+
if (baseUrl && !isBilibiliPcdnUrl(baseUrl)) return baseUrl;
|
|
31698
|
+
const backups = (stream.backup_url ?? stream.backupUrl ?? []).filter((url) => Boolean(url));
|
|
31699
|
+
const officialBackup = backups.find((url) => isBilibiliCdnUrl(url) && !isBilibiliPcdnUrl(url));
|
|
31700
|
+
const normalBackup = backups.find((url) => !isBilibiliPcdnUrl(url));
|
|
31701
|
+
return officialBackup ?? normalBackup ?? baseUrl ?? backups[0];
|
|
31702
|
+
};
|
|
31256
31703
|
/** 评论请求统一使用匿名态,避免账号 Cookie 改变评论热度池结果。 */
|
|
31257
31704
|
var bilibiliAnonymousRequestConfig = { headers: { Cookie: "" } };
|
|
31258
31705
|
/**
|
|
@@ -31375,7 +31822,7 @@ var Bilibili = class extends Base {
|
|
|
31375
31822
|
/** 替换原始的视频信息对象 */
|
|
31376
31823
|
playUrlData.data.data.dash.video = simplify;
|
|
31377
31824
|
/** 没有音频流(如纯视频稿件)时拿不到音频地址,按只统计视频流大小处理 */
|
|
31378
|
-
const audioUrl = playUrlData.data.data.dash.audio?.[0]
|
|
31825
|
+
const audioUrl = getBilibiliStreamUrl(playUrlData.data.data.dash.audio?.[0]);
|
|
31379
31826
|
/** 给视频信息对象删除不符合条件的视频流 */
|
|
31380
31827
|
correctList = await bilibiliProcessVideos({
|
|
31381
31828
|
accept_description: playUrlData.data.data.accept_description,
|
|
@@ -31385,7 +31832,7 @@ var Bilibili = class extends Base {
|
|
|
31385
31832
|
playUrlData.data.data.dash.video = correctList.videoList;
|
|
31386
31833
|
playUrlData.data.data.accept_description = correctList.accept_description;
|
|
31387
31834
|
/** 获取第一个视频流的大小 */
|
|
31388
|
-
videoSize = await getvideosize(correctList.videoList[0]
|
|
31835
|
+
videoSize = await getvideosize(getBilibiliStreamUrl(correctList.videoList[0]), audioUrl, infoData.data.data.bvid);
|
|
31389
31836
|
} else videoSize = (nockData.data.durl[0].size / 1048576).toFixed(2);
|
|
31390
31837
|
if (Config.bilibili.sendContent.some((content) => content === "comment")) {
|
|
31391
31838
|
const commentsData = await softFetch(() => this.amagi.bilibili.fetcher.fetchComments({
|
|
@@ -31526,7 +31973,7 @@ var Bilibili = class extends Base {
|
|
|
31526
31973
|
accept_description: playUrlData.result.accept_description,
|
|
31527
31974
|
bvid: videoInfo.data.result.season_id.toString(),
|
|
31528
31975
|
qn: Config.bilibili.videoQuality
|
|
31529
|
-
}, simplify, playUrlData.result.dash.audio?.[0]
|
|
31976
|
+
}, simplify, getBilibiliStreamUrl(playUrlData.result.dash.audio?.[0]));
|
|
31530
31977
|
playUrlData.result.dash.video = correctList.videoList;
|
|
31531
31978
|
playUrlData.result.cept_description = correctList.accept_description;
|
|
31532
31979
|
}
|
|
@@ -32105,12 +32552,12 @@ var Bilibili = class extends Base {
|
|
|
32105
32552
|
logger$1.debug("是否登录:", this.islogin);
|
|
32106
32553
|
switch (this.islogin) {
|
|
32107
32554
|
case true: {
|
|
32108
|
-
logger$1.debug("视频 URL:", this.Type === "one_video" ? playUrlData.data?.dash?.video[0]
|
|
32555
|
+
logger$1.debug("视频 URL:", this.Type === "one_video" ? getBilibiliStreamUrl(playUrlData.data?.dash?.video[0]) : getBilibiliStreamUrl(playUrlData.result.dash.video[0]));
|
|
32109
32556
|
const downloadHeaders = {
|
|
32110
32557
|
...this.headers,
|
|
32111
32558
|
Referer: "https://www.bilibili.com"
|
|
32112
32559
|
};
|
|
32113
|
-
const bmp4Raw = await downloadFile(this.Type === "one_video" ? playUrlData.data?.dash?.video[0]
|
|
32560
|
+
const bmp4Raw = await downloadFile(this.Type === "one_video" ? getBilibiliStreamUrl(playUrlData.data?.dash?.video[0]) : getBilibiliStreamUrl(playUrlData.result.dash.video[0]), {
|
|
32114
32561
|
title: `Bil_V_${this.Type === "one_video" ? infoData && infoData.data.bvid : infoData && infoData.result.season_id}.m4s`,
|
|
32115
32562
|
headers: downloadHeaders
|
|
32116
32563
|
});
|
|
@@ -32120,7 +32567,7 @@ var Bilibili = class extends Base {
|
|
|
32120
32567
|
return false;
|
|
32121
32568
|
}
|
|
32122
32569
|
await Common.removeFile(bmp4Raw.filepath, true);
|
|
32123
|
-
const audioUrl = this.Type === "one_video" ? playUrlData.data?.dash?.audio?.[0]
|
|
32570
|
+
const audioUrl = this.Type === "one_video" ? getBilibiliStreamUrl(playUrlData.data?.dash?.audio?.[0]) : getBilibiliStreamUrl(playUrlData.result.dash.audio?.[0]);
|
|
32124
32571
|
logger$1.debug("音频 URL:", audioUrl);
|
|
32125
32572
|
/** 没有音频流(如纯视频稿件)时为 undefined,此时无从合成,直接发视频流 */
|
|
32126
32573
|
let bmp3;
|
|
@@ -32465,7 +32912,7 @@ var bilibiliProcessVideos = async (qualityOptions, videoList, audioUrl) => {
|
|
|
32465
32912
|
}
|
|
32466
32913
|
const results = {};
|
|
32467
32914
|
for (const video of videoList) {
|
|
32468
|
-
const size = await getvideosize(video
|
|
32915
|
+
const size = await getvideosize(getBilibiliStreamUrl(video), audioUrl, qualityOptions.bvid);
|
|
32469
32916
|
results[video.id] = size;
|
|
32470
32917
|
}
|
|
32471
32918
|
const sizes = Object.values(results).map((size) => parseFloat(size.replace("MB", "")));
|
|
@@ -33778,7 +34225,7 @@ var Bilibilipush = class extends Base {
|
|
|
33778
34225
|
/** 替换原始的视频信息对象 */
|
|
33779
34226
|
playUrlData.data.data.dash.video = simplify;
|
|
33780
34227
|
/** 没有音频流(如纯视频稿件)时拿不到音频地址,按只统计视频流大小处理 */
|
|
33781
|
-
const audioUrl = playUrlData.data.data.dash.audio?.[0]
|
|
34228
|
+
const audioUrl = getBilibiliStreamUrl(playUrlData.data.data.dash.audio?.[0]);
|
|
33782
34229
|
/** 给视频信息对象删除不符合条件的视频流 */
|
|
33783
34230
|
correctList = await bilibiliProcessVideos({
|
|
33784
34231
|
accept_description: playUrlData.data.data.accept_description,
|
|
@@ -33789,14 +34236,14 @@ var Bilibilipush = class extends Base {
|
|
|
33789
34236
|
playUrlData.data.data.dash.video = correctList.videoList;
|
|
33790
34237
|
playUrlData.data.data.accept_description = correctList.accept_description;
|
|
33791
34238
|
/** 获取第一个视频流的大小 */
|
|
33792
|
-
videoSize = await getvideosize(correctList.videoList[0]
|
|
34239
|
+
videoSize = await getvideosize(getBilibiliStreamUrl(correctList.videoList[0]), audioUrl, data[dynamicId].Dynamic_Data.modules.module_dynamic.major.archive.bvid);
|
|
33793
34240
|
if (Config.app.usefilelimit && Number(videoSize) > Number(Config.app.filelimit) && !Config.app.compress) {
|
|
33794
34241
|
await karin.sendMsg(botId, Contact, [segment.text(`设定的最大上传大小为 ${Config.app.filelimit}MB\n当前解析到的视频大小为 ${Number(videoSize)}MB\n视频太大了,还是去B站看吧~`), segment.reply(status.messageId)]);
|
|
33795
34242
|
break;
|
|
33796
34243
|
}
|
|
33797
34244
|
logger$1.mark(`当前处于自动推送状态,解析到的视频大小为 ${logger$1.yellow(Number(videoSize))} MB`);
|
|
33798
34245
|
const infoData = await this.amagi.bilibili.fetcher.fetchVideoInfo({ bvid: data[dynamicId].Dynamic_Data.modules.module_dynamic.major.archive.bvid });
|
|
33799
|
-
const mp4File = await downloadFile(playUrlData.data?.data?.dash?.video[0]
|
|
34246
|
+
const mp4File = await downloadFile(getBilibiliStreamUrl(playUrlData.data?.data?.dash?.video[0]), {
|
|
33800
34247
|
title: `Bil_V_${infoData.data.data.bvid}.mp4`,
|
|
33801
34248
|
headers: bilibiliBaseHeaders
|
|
33802
34249
|
});
|
|
@@ -35495,6 +35942,24 @@ async function burnDouyinDanmaku(videoPath, danmakuList, outputPath, options = {
|
|
|
35495
35942
|
return result.status;
|
|
35496
35943
|
}
|
|
35497
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
|
|
35498
35963
|
//#region src/platform/douyin/videoQuality.ts
|
|
35499
35964
|
/** 档位优先级,从高到低 */
|
|
35500
35965
|
var QUALITY_PRIORITY = [
|
|
@@ -36984,6 +37449,69 @@ var DouYin = class DouYin extends Base {
|
|
|
36984
37449
|
}
|
|
36985
37450
|
return true;
|
|
36986
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
|
+
}
|
|
36987
37515
|
case "music_work": {
|
|
36988
37516
|
this.workType = "music";
|
|
36989
37517
|
const musicInfo = (await this.amagi.douyin.fetcher.fetchMusicInfo({ music_id: data.music_id })).data.music_info;
|
|
@@ -37179,6 +37707,14 @@ var getDouyinID = async (event, url, log = true) => {
|
|
|
37179
37707
|
room_id: longLink.split("/").pop()
|
|
37180
37708
|
};
|
|
37181
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
|
+
}
|
|
37182
37718
|
case /video\/(\d+)/.test(longLink):
|
|
37183
37719
|
case /article\/(\d+)/.test(longLink):
|
|
37184
37720
|
case /note\/(\d+)/.test(longLink): {
|
|
@@ -37433,6 +37969,26 @@ async function processRecommendList(contentList, sec_uid, userinfo, item, target
|
|
|
37433
37969
|
return result;
|
|
37434
37970
|
}
|
|
37435
37971
|
//#endregion
|
|
37972
|
+
//#region src/platform/douyin/shortUrl.ts
|
|
37973
|
+
/**
|
|
37974
|
+
* 把分享链接换成抖音签发的 `v.douyin.com` 短链(二维码专用)。
|
|
37975
|
+
*
|
|
37976
|
+
* 短链由 amagi 的 `douyin.shortUrl` 端点签发:同一 target 恒得同一短码,
|
|
37977
|
+
* 内容比任何规范链接都短,能明显降低二维码密度。该端点免登录但仍要 `a_bogus` 签名,
|
|
37978
|
+
* 可能因签名或平台策略失败 —— 失败不阻塞推送,回退原链接即可。
|
|
37979
|
+
* @param target - 待缩短的分享链接(规范链接或视频直链均可)
|
|
37980
|
+
* @returns 短链;签发失败时原样返回 target
|
|
37981
|
+
*/
|
|
37982
|
+
var toDouyinShortUrl = async (target) => {
|
|
37983
|
+
try {
|
|
37984
|
+
const shortUrl = (await douyinFetcher.fetchShortUrl({ target })).data?.data;
|
|
37985
|
+
return typeof shortUrl === "string" && shortUrl.length > 0 ? shortUrl : target;
|
|
37986
|
+
} catch (error) {
|
|
37987
|
+
logger$1.debug(`[抖音短链] 签发失败,二维码回退原链接:${error instanceof Error ? error.message : String(error)}`);
|
|
37988
|
+
return target;
|
|
37989
|
+
}
|
|
37990
|
+
};
|
|
37991
|
+
//#endregion
|
|
37436
37992
|
//#region src/platform/douyin/push.ts
|
|
37437
37993
|
var douyinBaseHeaders = {
|
|
37438
37994
|
...BASE_HEADERS,
|
|
@@ -37610,6 +38166,7 @@ var DouYinpush = class extends Base {
|
|
|
37610
38166
|
const playAddr = selectedVideo?.play_addr ?? pushItem.Detail_Data.video?.play_addr;
|
|
37611
38167
|
workShareLink = playAddr ? buildDouyinPlayUrl(playAddr) : `https://www.douyin.com/video/${actualAwemeId}`;
|
|
37612
38168
|
}
|
|
38169
|
+
workShareLink = await toDouyinShortUrl(workShareLink);
|
|
37613
38170
|
}
|
|
37614
38171
|
switch (pushItem.pushType) {
|
|
37615
38172
|
case "live":
|
|
@@ -38108,23 +38665,10 @@ var DouYinpush = class extends Base {
|
|
|
38108
38665
|
const botId = this.e.selfId;
|
|
38109
38666
|
try {
|
|
38110
38667
|
const inputDouyinId = this.e.msg.replace(/^#设置抖音推送/, "").trim();
|
|
38111
|
-
/**
|
|
38112
|
-
* 搜索结果按响应形态自述(判别式 `__search_type`,由 amagi 的 normalize 按响应结构 +
|
|
38113
|
-
* 请求类型写入)。订阅只认「用户搜索」那一支:抖音把 user 请求回成别的形态时在这里说清楚,
|
|
38114
|
-
* 而不是拿一个 undefined 去遍历。
|
|
38115
|
-
*/
|
|
38116
|
-
if (data.__search_type !== "user") throw new Error(`抖音没有返回用户搜索结果(返回形态:${data.__search_type ?? "未知"})`);
|
|
38117
|
-
let matchedUser = null;
|
|
38118
|
-
for (const userItem of data.user_list) if ((userItem.user_info.unique_id === "" ? userItem.user_info.short_id : userItem.user_info.unique_id) === inputDouyinId) {
|
|
38119
|
-
matchedUser = userItem.user_info;
|
|
38120
|
-
break;
|
|
38121
|
-
}
|
|
38122
|
-
if (!matchedUser) throw new Error(`未找到抖音号为 ${inputDouyinId} 的用户`);
|
|
38123
|
-
const sec_uid = matchedUser.sec_uid;
|
|
38124
|
-
const UserInfoData = await this.amagi.douyin.fetcher.fetchUserProfile({ sec_uid });
|
|
38125
38668
|
/** 处理抖音号 */
|
|
38126
|
-
|
|
38127
|
-
|
|
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} 的用户`);
|
|
38128
38672
|
config.douyin ??= [];
|
|
38129
38673
|
const existingItem = config.douyin.find((item) => item.sec_uid === sec_uid);
|
|
38130
38674
|
const isSubscribed = await douyinDBInstance.isSubscribed(sec_uid, groupId);
|
|
@@ -38144,31 +38688,31 @@ var DouYinpush = class extends Base {
|
|
|
38144
38688
|
config.douyin.splice(index, 1);
|
|
38145
38689
|
}
|
|
38146
38690
|
Config.Modify("pushlist", "douyin", config.douyin);
|
|
38147
|
-
await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n删除成功!${
|
|
38148
|
-
logger$1.info(`\n删除成功!${
|
|
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}`);
|
|
38149
38693
|
} else {
|
|
38150
38694
|
existingItem.group_id.push(`${groupId}:${botId}`);
|
|
38151
38695
|
if (!existingItem.pushTypes || existingItem.pushTypes.length === 0) existingItem.pushTypes = ["post", "live"];
|
|
38152
|
-
if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid,
|
|
38696
|
+
if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid, data.user_info.nickname);
|
|
38153
38697
|
Config.Modify("pushlist", "douyin", config.douyin);
|
|
38154
|
-
await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${
|
|
38698
|
+
await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${data.user_info.nickname}\n抖音号:${user_shortid}`);
|
|
38155
38699
|
if (Config.douyin.push.switch === false) await this.e.reply("请发送「#设置抖音推送开启」以进行推送");
|
|
38156
|
-
logger$1.info(`\n设置成功!${
|
|
38700
|
+
logger$1.info(`\n设置成功!${data.user_info.nickname}\n抖音号:${user_shortid}\nsec_uid${data.user_info.sec_uid}`);
|
|
38157
38701
|
}
|
|
38158
38702
|
} else {
|
|
38159
38703
|
config.douyin.push({
|
|
38160
38704
|
switch: true,
|
|
38161
38705
|
sec_uid,
|
|
38162
38706
|
group_id: [`${groupId}:${botId}`],
|
|
38163
|
-
remark:
|
|
38707
|
+
remark: data.user_info.nickname,
|
|
38164
38708
|
short_id: user_shortid,
|
|
38165
38709
|
pushTypes: ["post", "live"]
|
|
38166
38710
|
});
|
|
38167
|
-
if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid,
|
|
38711
|
+
if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid, data.user_info.nickname);
|
|
38168
38712
|
Config.Modify("pushlist", "douyin", config.douyin);
|
|
38169
|
-
await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${
|
|
38713
|
+
await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${data.user_info.nickname}\n抖音号:${user_shortid}`);
|
|
38170
38714
|
if (Config.douyin.push.switch === false) await this.e.reply("请发送「#设置抖音推送开启」以进行推送");
|
|
38171
|
-
logger$1.info(`\n设置成功!${
|
|
38715
|
+
logger$1.info(`\n设置成功!${data.user_info.nickname}\n抖音号:${user_shortid}\nsec_uid${data.user_info.sec_uid}`);
|
|
38172
38716
|
}
|
|
38173
38717
|
await this.renderPushList();
|
|
38174
38718
|
} catch (error) {
|
|
@@ -39280,6 +39824,8 @@ var Xiaohongshu = class extends Base {
|
|
|
39280
39824
|
let staticImgPath = "";
|
|
39281
39825
|
if (staticImg.filepath) staticImgPath = staticImg.filepath;
|
|
39282
39826
|
const livePhotoVideo = xiaohongshuGetLivePhotoVideo(item.stream);
|
|
39827
|
+
/** 这条动图是否已产出至少一个待发送元素(视频 / 实况图 / 静态兜底) */
|
|
39828
|
+
let hasPushedItem = false;
|
|
39283
39829
|
if (livePhotoVideo) {
|
|
39284
39830
|
const livePhotoPath = Common.tempDri.video + `livephoto_${Date.now()}_${index}.mp4`;
|
|
39285
39831
|
const livePhoto = await downloadFile(livePhotoVideo.master_url, {
|
|
@@ -39317,6 +39863,7 @@ var Xiaohongshu = class extends Base {
|
|
|
39317
39863
|
});
|
|
39318
39864
|
const videoPath = Config.app.videoSendMode === "base64" ? `base64://${fs.readFileSync(filePath).toString("base64")}` : `file://${filePath}`;
|
|
39319
39865
|
processedImages.push(segment.video(videoPath));
|
|
39866
|
+
hasPushedItem = true;
|
|
39320
39867
|
}
|
|
39321
39868
|
}
|
|
39322
39869
|
if (shouldGenerateLivePhoto) {
|
|
@@ -39334,6 +39881,7 @@ var Xiaohongshu = class extends Base {
|
|
|
39334
39881
|
});
|
|
39335
39882
|
const motionPhotoCover = processLocalImageFile(motionPhotoCoverPath);
|
|
39336
39883
|
processedImages.push(segment.image(motionPhotoCover));
|
|
39884
|
+
hasPushedItem = true;
|
|
39337
39885
|
hasPushedMotionPhotoCover = true;
|
|
39338
39886
|
hasGeneratedLivePhoto = true;
|
|
39339
39887
|
logger.debug(`小红书实况图生成成功: ${motionPhotoCoverPath}`);
|
|
@@ -39342,12 +39890,17 @@ var Xiaohongshu = class extends Base {
|
|
|
39342
39890
|
if (!hasPushedMotionPhotoCover) {
|
|
39343
39891
|
const imageUrl = await processImageUrl(item.url_default, title, index);
|
|
39344
39892
|
processedImages.push(segment.image(imageUrl));
|
|
39893
|
+
hasPushedItem = true;
|
|
39345
39894
|
}
|
|
39346
39895
|
}
|
|
39347
39896
|
logger.mark("正在尝试删除缓存文件");
|
|
39348
39897
|
await Common.removeFile(livePhoto.filepath, true);
|
|
39349
39898
|
}
|
|
39350
39899
|
}
|
|
39900
|
+
if (!hasPushedItem) {
|
|
39901
|
+
const fallbackImage = staticImgPath ? processLocalImageFile(staticImgPath) : await processImageUrl(item.url_default, title, index);
|
|
39902
|
+
processedImages.push(segment.image(fallbackImage));
|
|
39903
|
+
}
|
|
39351
39904
|
if (staticImgPath) temp.push({
|
|
39352
39905
|
filepath: staticImgPath,
|
|
39353
39906
|
totalBytes: 0
|
|
@@ -39375,6 +39928,10 @@ var Xiaohongshu = class extends Base {
|
|
|
39375
39928
|
} finally {
|
|
39376
39929
|
for (const item of temp) await Common.removeFile(item.filepath, true);
|
|
39377
39930
|
}
|
|
39931
|
+
else {
|
|
39932
|
+
logger.warn(`小红书图集解析未生成可发送内容,note_id=${data.note_id}`);
|
|
39933
|
+
for (const item of temp) await Common.removeFile(item.filepath, true);
|
|
39934
|
+
}
|
|
39378
39935
|
}
|
|
39379
39936
|
if (NoteData.data.data.items[0].note_card.video && Config.xiaohongshu.sendContent.includes("video")) {
|
|
39380
39937
|
const video = NoteData.data.data.items[0].note_card.video;
|
|
@@ -40166,10 +40723,7 @@ var handleSetDouyinPush = wrapWithErrorHandler(async (e) => {
|
|
|
40166
40723
|
logger$1.info(`抖音推送已${enable ? "开启" : "关闭"}`);
|
|
40167
40724
|
return true;
|
|
40168
40725
|
}
|
|
40169
|
-
const data = await douyinFetcher.
|
|
40170
|
-
query,
|
|
40171
|
-
type: "user"
|
|
40172
|
-
});
|
|
40726
|
+
const data = await douyinFetcher.fetchGuestUserInfo({ unique_id: query });
|
|
40173
40727
|
await new DouYinpush(e).setting(data.data);
|
|
40174
40728
|
return true;
|
|
40175
40729
|
}, { businessName: "设置抖音推送" });
|
|
@@ -41216,13 +41770,17 @@ var globalStatistics = karin.command(/^#?kkk全局解析统计$/, handleGlobalSt
|
|
|
41216
41770
|
});
|
|
41217
41771
|
//#endregion
|
|
41218
41772
|
//#region src/apps/testPush.ts
|
|
41219
|
-
/**
|
|
41220
|
-
function buildWorkShareLink(aweme, selectedVideo) {
|
|
41773
|
+
/** 构建与生产推送一致的作品二维码短链(签发失败回退原链接)。 */
|
|
41774
|
+
async function buildWorkShareLink(aweme, selectedVideo) {
|
|
41221
41775
|
const workTypeInfo = getWorkTypeInfo(aweme);
|
|
41222
|
-
|
|
41223
|
-
if (workTypeInfo.
|
|
41224
|
-
|
|
41225
|
-
|
|
41776
|
+
let target;
|
|
41777
|
+
if (workTypeInfo.isArticle) target = `https://www.douyin.com/article/${aweme.aweme_id}`;
|
|
41778
|
+
else if (workTypeInfo.isImage) target = `https://www.douyin.com/note/${aweme.aweme_id}`;
|
|
41779
|
+
else {
|
|
41780
|
+
const playAddr = selectedVideo?.play_addr ?? aweme.video?.play_addr;
|
|
41781
|
+
target = playAddr ? buildDouyinPlayUrl(playAddr) : `https://www.douyin.com/video/${aweme.aweme_id}`;
|
|
41782
|
+
}
|
|
41783
|
+
return await toDouyinShortUrl(target);
|
|
41226
41784
|
}
|
|
41227
41785
|
/**
|
|
41228
41786
|
* 测试抖音推送命令处理器
|
|
@@ -41266,7 +41824,7 @@ var handleTestPush = wrapWithErrorHandler(async (e) => {
|
|
|
41266
41824
|
const aweme = workData.data.aweme_detail;
|
|
41267
41825
|
const Detail_Data = buildDouyinWorkDetail(aweme, { user_info: (await douyinFetcher.fetchUserProfile({ sec_uid: aweme.author.sec_uid })).data });
|
|
41268
41826
|
const selectedVideo = aweme.video?.bit_rate?.length ? douyinProcessVideos(aweme.video.bit_rate, Config.douyin.videoQuality)[0] : null;
|
|
41269
|
-
const shareLink = buildWorkShareLink(Detail_Data, selectedVideo);
|
|
41827
|
+
const shareLink = await buildWorkShareLink(Detail_Data, selectedVideo);
|
|
41270
41828
|
images = await renderWorkImage({
|
|
41271
41829
|
e,
|
|
41272
41830
|
Detail_Data,
|
|
@@ -41305,7 +41863,7 @@ var handleTestPush = wrapWithErrorHandler(async (e) => {
|
|
|
41305
41863
|
user_info: userinfo.data,
|
|
41306
41864
|
author_user_info: authorUserInfo
|
|
41307
41865
|
});
|
|
41308
|
-
const shareLink = buildWorkShareLink(Detail_Data, aweme.video?.bit_rate?.length ? douyinProcessVideos(aweme.video.bit_rate, Config.douyin.videoQuality)[0] : null);
|
|
41866
|
+
const shareLink = await buildWorkShareLink(Detail_Data, aweme.video?.bit_rate?.length ? douyinProcessVideos(aweme.video.bit_rate, Config.douyin.videoQuality)[0] : null);
|
|
41309
41867
|
images = await renderFavoriteImage({
|
|
41310
41868
|
e,
|
|
41311
41869
|
Detail_Data,
|
|
@@ -41344,7 +41902,7 @@ var handleTestPush = wrapWithErrorHandler(async (e) => {
|
|
|
41344
41902
|
user_info: userinfo.data,
|
|
41345
41903
|
author_user_info: authorUserInfo
|
|
41346
41904
|
});
|
|
41347
|
-
const shareLink = buildWorkShareLink(Detail_Data, aweme.video?.bit_rate?.length ? douyinProcessVideos(aweme.video.bit_rate, Config.douyin.videoQuality)[0] : null);
|
|
41905
|
+
const shareLink = await buildWorkShareLink(Detail_Data, aweme.video?.bit_rate?.length ? douyinProcessVideos(aweme.video.bit_rate, Config.douyin.videoQuality)[0] : null);
|
|
41348
41906
|
images = await renderRecommendImage({
|
|
41349
41907
|
e,
|
|
41350
41908
|
Detail_Data,
|