karin-plugin-kkk 2.45.2-beta.2 → 2.45.2-beta.4
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 +33 -0
- package/lib/build-metadata.json +5 -5
- package/lib/core_chunk/default.js +1 -1
- package/lib/core_chunk/main.js +1635 -890
- package/lib/core_chunk/vendor.js +14679 -14477
- package/lib/style.css +267 -74
- package/lib/web/assets/CronEditor-CgKG-Kxz.js +1 -0
- package/lib/web/assets/DesktopLayout-BI9Jr5f2.js +1 -0
- package/lib/web/assets/MobileLayout-qix3wT2a.js +1 -0
- package/lib/web/assets/ThemeSwitch-D1i5cqbr.js +1 -0
- package/lib/web/assets/createLucideIcon-BQ-Qp6cj.js +11 -0
- package/lib/web/assets/index-BVZg44aV.css +2 -0
- package/lib/web/assets/index-DSqk8j2R.js +45 -0
- package/lib/web/assets/rolldown-runtime-hePW80VL.js +1 -0
- package/lib/web/assets/separator-DVo6bTG_.js +1 -0
- package/lib/web/index.html +4 -2
- package/package.json +3 -3
- package/lib/web/assets/CronEditor-DSx8kkQQ.js +0 -1
- package/lib/web/assets/DesktopLayout-BJTY9p_l.js +0 -1
- package/lib/web/assets/MobileLayout-BKJi8d_L.js +0 -1
- package/lib/web/assets/ThemeSwitch-Cipx1aP1.js +0 -1
- package/lib/web/assets/index-D1zuPqD3.css +0 -2
- package/lib/web/assets/index-RFCFN09q.js +0 -47
- package/lib/web/assets/separator-CCrVXPvv.js +0 -1
package/lib/core_chunk/main.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
globalThis.__KTR_BUNDLED__ = true;
|
|
2
2
|
import { o as __toESM } from "./rolldown-runtime.js";
|
|
3
3
|
import { a as createBilibiliRoutes, c as createXiaohongshuRoutes, i as bilibiliApiUrls, l as wbi_sign, n as DynamicType, o as createDouyinRoutes, r as MajorType, s as createKuaishouRoutes, t as Client } from "./default.js";
|
|
4
|
-
import { $ as RiPieChart2Fill, $n as
|
|
4
|
+
import { $ as RiPieChart2Fill, $n as Gauge, $t as User, A as MdFitScreen, An as Plus, Ar as Box, At as m, B as AiFillHeart, Bn as Maximize, Br as format, Bt as o$2, C as webassembly_default, Cn as RotateCcw, Cr as CircleCheckBig, Ct as Chip, D as tailwind_css_default, Dn as Quote, Dr as Camera, Dt as o, E as tsdown_default, En as Radio, Er as ChartColumn, Et as r, F as FaCommentDots, Fn as MousePointerClick, Fr as ArrowRight, Ft as c$2, G as RiArrowRightFill, Gn as LayoutTemplate, Gr as createTemplateRenderer, Gt as m$3, H as AiFillStar, Hn as LoaderCircle, Hr as require_jsx_runtime, Ht as p, I as FaMusic, In as Moon, Ir as ArrowDownWideNarrow, It as a$1, J as RiHeart3Fill, Jn as Heart, Jr as require_react, Jt as X, K as RiGroupLine, Kn as Info, Kr as resolveTemplateStyle, Kt as zhCN, L as FaTiktok, Ln as Monitor, Lr as parse, Lt as m$1, M as MdLightbulbOutline, Mn as Pencil, Mr as Bookmark, Mt as n, N as MdLocationOn, Nn as Palette, Nr as BookOpenText, Nt as p$1, O as sqlite_default, On as QrCode, Or as Calendar, Ot as o$1, P as MdSchedule, Pn as Network$1, Pr as BellRing, Pt as e, Q as RiMessage3Fill, Qn as Gift, Qt as UsersRound, R as FaUserGroup, Rn as MessageCircle, Rr as fromUnixTime, Rt as m$2, S as rehypeHighlight, Sn as Route, Sr as CircleCheck, St as SiAnthropic, T as typescript_default, Tn as RefreshCw, Tr as Check, Tt as o$3, U as AiOutlineVideoCamera, Un as ListChecks, Ur as twMerge, Ut as n$1, V as AiFillPushpin, Vn as MapPin, Vr as differenceInSeconds, Vt as c, W as Markdown, Wn as Link, Wr as clsx, Wt as s$1, X as RiHeartLine, Xn as Globe, Xr as defineTemplate, Xt as Video, Y as RiHeart3Line, Yn as Hash, Yr as HtmlWrapper, Yt as WandSparkles, Z as RiLiveLine, Zn as GitBranch, Zt as Users, _ as use, _n as Share2, _r as Clapperboard, _t as SiHonor, a as drawDither, an as Timer, ar as Eye, at as RiTrophyFill, b as install$2, bn as ScanLine, br as CircleEllipsis, bt as SiBilibili, c as install$11, cn as Star, cr as EighthNotes, ct as RiVideoLine, d as install$8, dn as Sparkles, dr as Cpu, dt as SiVivo, en as UserRound, er as Gamepad2, et as RiShareForwardFill, f as install$7, fn as Smartphone, fr as CornerDownLeft, ft as SiSamsung, g as install$5, gn as ShieldAlert, gr as Clock3, gt as SiHuawei, h as install$6, hn as ShieldCheck, hr as Clock, ht as SiKuaishou, in as Trash, ir as FileExclamationPoint, it as RiTiktokFill, j as MdInfoOutline, jn as Play, jr as Bot, jt as a, k as react_default, kn as Puzzle, kr as Braces, kt as s, l as install$10, ln as Square, lr as Download, lt as SiXiaomi, m as install$4, mn as Shield, mr as Code, mt as SiOneplus, nn as Upload, nr as FileText, nt as RiStarLine, o as require_jpeg_js, on as Terminal, or as EyeOff, ot as RiUserFollowLine, p as install$3, pn as ShoppingBag, pr as Copy, pt as SiOppo, q as RiHashtag, qn as Image$1, qr as require_server_node, qt as Zap, rn as TriangleAlert, rr as FilePlay, rt as RiThumbUpFill, s as require_heic_decode, sn as Sun, sr as ExternalLink, st as RiVerifiedBadgeFill, tn as UserPlus, tr as FingerprintPattern, tt as RiStarFill, u as install$9, un as SquarePen, ur as Crown, ut as SiXiaohongshu, v as init, vn as Settings2, vr as CircleQuestionMark, vt as SiGooglephotos, w as vite_default, wn as Repeat, wr as CircleAlert, wt as Button, x as install$1, xn as Save, xr as CircleDashed, xt as SiApple, y as install, yn as Search, yr as CircleFadingArrowUp, yt as SiGithub, z as BiImage, zn as Menu, zr as formatDistanceToNow, zt as c$1 } from "./vendor.js";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import fs from "node:fs";
|
|
7
7
|
import path, { resolve } from "node:path";
|
|
@@ -1362,6 +1362,8 @@ function getEmojiId(e, type) {
|
|
|
1362
1362
|
return (platform in PLATFORM_EMOJI_IDS ? PLATFORM_EMOJI_IDS[platform] : PLATFORM_EMOJI_IDS.other)[type];
|
|
1363
1363
|
}
|
|
1364
1364
|
PLATFORM_EMOJI_IDS.qq;
|
|
1365
|
+
/** 同一条消息上的表情写操作按发起顺序串行执行:适配器并发处理时,后发的 remove 不能先于先发的 add 生效 */
|
|
1366
|
+
var reactionChains = /* @__PURE__ */ new WeakMap();
|
|
1365
1367
|
/**
|
|
1366
1368
|
* 设置消息表情回复
|
|
1367
1369
|
* @param e 消息事件对象
|
|
@@ -1372,13 +1374,19 @@ PLATFORM_EMOJI_IDS.qq;
|
|
|
1372
1374
|
async function setEmojiReaction(e, emojiId, isSet = true) {
|
|
1373
1375
|
if (!Config.app.EmojiReply) return false;
|
|
1374
1376
|
if (e.isPrivate) return false;
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1377
|
+
const write = async () => {
|
|
1378
|
+
try {
|
|
1379
|
+
await e.bot.setMsgReaction(e.contact, e.messageId, emojiId, isSet);
|
|
1380
|
+
return true;
|
|
1381
|
+
} catch (err) {
|
|
1382
|
+
logger$1.debug("[EmojiReaction] 设置表情回复失败(已忽略):", err);
|
|
1383
|
+
return false;
|
|
1384
|
+
}
|
|
1385
|
+
};
|
|
1386
|
+
const previous = reactionChains.get(e);
|
|
1387
|
+
const current = previous ? previous.then(write, write) : write();
|
|
1388
|
+
reactionChains.set(e, current);
|
|
1389
|
+
return current;
|
|
1382
1390
|
}
|
|
1383
1391
|
/**
|
|
1384
1392
|
* 表情回复管理器
|
|
@@ -1488,6 +1496,85 @@ var EmojiReactionManager = class {
|
|
|
1488
1496
|
return this.emojiIds.size;
|
|
1489
1497
|
}
|
|
1490
1498
|
};
|
|
1499
|
+
/** 表情反馈节奏:收到消息 1.5 秒后补「处理中」,结束时再把「处理中」换成结果 */
|
|
1500
|
+
var EMOJI_PROCESSING_DELAY_MS = 1500;
|
|
1501
|
+
var EMOJI_RESULT_DELAY_MS = 1500;
|
|
1502
|
+
/** 已由业务侧收尾的消息及结果;失败结果可以覆盖先前的成功,成功不会覆盖失败 */
|
|
1503
|
+
var settledEvents = /* @__PURE__ */ new WeakMap();
|
|
1504
|
+
/** 这条消息最近一次收尾的完整过程;成功收尾前要等它落地,确认业务侧是否真的收尾成功 */
|
|
1505
|
+
var settleTasks = /* @__PURE__ */ new WeakMap();
|
|
1506
|
+
/**
|
|
1507
|
+
* 给一条消息的表情收尾:撤掉「处理中」,补上结果表情。
|
|
1508
|
+
*
|
|
1509
|
+
* 子上下文处理完成后用它把父消息也收尾;收尾过的消息会被标记,
|
|
1510
|
+
* 外层 `wrapWithErrorHandler` 之后不会再改它的表情。
|
|
1511
|
+
* 失败可以覆盖先前的成功(先撤掉 ✅ 再补 ❌),成功不会覆盖失败。
|
|
1512
|
+
* @param e 需要收尾的消息
|
|
1513
|
+
* @param type 结果表情,默认 SUCCESS
|
|
1514
|
+
*/
|
|
1515
|
+
var settleEmojiReaction = async (e, type = "SUCCESS") => {
|
|
1516
|
+
const settled = settledEvents.get(e);
|
|
1517
|
+
if (settled === "ERROR" || settled === type) return;
|
|
1518
|
+
settledEvents.set(e, type);
|
|
1519
|
+
const task = (async () => {
|
|
1520
|
+
await setEmojiReaction(e, getEmojiId(e, "PROCESSING"), false);
|
|
1521
|
+
if (settled === "SUCCESS") await setEmojiReaction(e, getEmojiId(e, "SUCCESS"), false);
|
|
1522
|
+
if (!await setEmojiReaction(e, getEmojiId(e, type), true) && settledEvents.get(e) === type) settledEvents.delete(e);
|
|
1523
|
+
})();
|
|
1524
|
+
settleTasks.set(e, task);
|
|
1525
|
+
await task;
|
|
1526
|
+
};
|
|
1527
|
+
/** 等这条消息上最近一次收尾过程落地(没有收尾过则立即返回)。 */
|
|
1528
|
+
var waitForSettle = async (e) => {
|
|
1529
|
+
const task = settleTasks.get(e);
|
|
1530
|
+
if (task) await task;
|
|
1531
|
+
};
|
|
1532
|
+
/** 这条消息的表情是否已经由业务侧收尾。 */
|
|
1533
|
+
var isEmojiReactionSettled = (e) => settledEvents.has(e);
|
|
1534
|
+
/**
|
|
1535
|
+
* 给一条消息创建表情反馈流程。
|
|
1536
|
+
* @param e 触发本次处理的消息
|
|
1537
|
+
*/
|
|
1538
|
+
var createEmojiReactionFlow = (e) => {
|
|
1539
|
+
const manager = new EmojiReactionManager(e);
|
|
1540
|
+
let processingTimer = null;
|
|
1541
|
+
/** 定时器补 ⏳ 的请求;失败时要等它落地再撤,否则本地还没记录会漏撤 */
|
|
1542
|
+
let processingAdd = null;
|
|
1543
|
+
let finished = false;
|
|
1544
|
+
const begin = async () => {
|
|
1545
|
+
await manager.add("EYES");
|
|
1546
|
+
processingTimer = setTimeout(() => {
|
|
1547
|
+
if (isEmojiReactionSettled(e)) return;
|
|
1548
|
+
processingAdd = manager.add("PROCESSING");
|
|
1549
|
+
}, EMOJI_PROCESSING_DELAY_MS);
|
|
1550
|
+
};
|
|
1551
|
+
const succeed = async () => {
|
|
1552
|
+
if (finished) return;
|
|
1553
|
+
await waitForSettle(e);
|
|
1554
|
+
if (finished || isEmojiReactionSettled(e)) return;
|
|
1555
|
+
finished = true;
|
|
1556
|
+
setTimeout(() => {
|
|
1557
|
+
manager.replace("PROCESSING", "SUCCESS").catch(() => {});
|
|
1558
|
+
}, EMOJI_RESULT_DELAY_MS);
|
|
1559
|
+
};
|
|
1560
|
+
const fail = async () => {
|
|
1561
|
+
if (finished) return;
|
|
1562
|
+
finished = true;
|
|
1563
|
+
if (processingTimer) clearTimeout(processingTimer);
|
|
1564
|
+
if (processingAdd) await processingAdd;
|
|
1565
|
+
if (settledEvents.get(e) === "SUCCESS") {
|
|
1566
|
+
await settleEmojiReaction(e, "ERROR");
|
|
1567
|
+
return;
|
|
1568
|
+
}
|
|
1569
|
+
if (manager.has(getEmojiId(e, "PROCESSING"))) await manager.remove("PROCESSING");
|
|
1570
|
+
await manager.add("ERROR");
|
|
1571
|
+
};
|
|
1572
|
+
return {
|
|
1573
|
+
begin,
|
|
1574
|
+
succeed,
|
|
1575
|
+
fail
|
|
1576
|
+
};
|
|
1577
|
+
};
|
|
1491
1578
|
//#endregion
|
|
1492
1579
|
//#region src/module/utils/MotionPhoto.ts
|
|
1493
1580
|
var xmpHeaderBuffer = Buffer.from("http://ns.adobe.com/xap/1.0/\0", "utf8");
|
|
@@ -10436,11 +10523,6 @@ var webConfig = defineConfig({
|
|
|
10436
10523
|
}
|
|
10437
10524
|
});
|
|
10438
10525
|
//#endregion
|
|
10439
|
-
//#region ktr/utils/cn.ts
|
|
10440
|
-
function cn(...inputs) {
|
|
10441
|
-
return twMerge(clsx(inputs));
|
|
10442
|
-
}
|
|
10443
|
-
//#endregion
|
|
10444
10526
|
//#region ktr/utils/theme.ts
|
|
10445
10527
|
/**
|
|
10446
10528
|
* 判断当前渲染是否为深色主题。
|
|
@@ -10450,6 +10532,48 @@ function cn(...inputs) {
|
|
|
10450
10532
|
* @returns 深色主题返回 true。
|
|
10451
10533
|
*/
|
|
10452
10534
|
var isDark = (ctx) => ctx.theme?.mode === "dark";
|
|
10535
|
+
/** 主题色压色罩不透明度 (0~1):edge 为顶/底两端,middle 为中间带;调小 middle 封面色更透 */
|
|
10536
|
+
var AMBIENT_OVERLAY_OPACITY = {
|
|
10537
|
+
edge: .9,
|
|
10538
|
+
middle: .2
|
|
10539
|
+
};
|
|
10540
|
+
/** 用 color-mix 生成三段压色渐变(0% / 50% / 100% 停靠点对应 edge / middle / edge) */
|
|
10541
|
+
var overlayGradient = (color, edge, middle) => `linear-gradient(to bottom, color-mix(in oklab, ${color} ${edge * 100}%, transparent), color-mix(in oklab, ${color} ${middle * 100}%, transparent), color-mix(in oklab, ${color} ${edge * 100}%, transparent))`;
|
|
10542
|
+
/**
|
|
10543
|
+
* 氛围背景基础层:高斯模糊封面 + 主题色压色罩。
|
|
10544
|
+
* 压色罩浅色用主题背景色、深色用纯黑(两个层按 dark 变体显隐),
|
|
10545
|
+
* 各模板在此之上再叠加自己的杂色纹理层。
|
|
10546
|
+
* 贡献度参数优先取 ctx.ambientCover(core 注入的用户配置),缺省用模块内默认值。
|
|
10547
|
+
*/
|
|
10548
|
+
var AmbientCover = import_react.memo(({ src, ctx }) => {
|
|
10549
|
+
const coverOpacity = ctx?.ambientCover?.coverOpacity ?? .7;
|
|
10550
|
+
const edge = ctx?.ambientCover?.overlayEdgeOpacity ?? AMBIENT_OVERLAY_OPACITY.edge;
|
|
10551
|
+
const middle = ctx?.ambientCover?.overlayMiddleOpacity ?? AMBIENT_OVERLAY_OPACITY.middle;
|
|
10552
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
10553
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
|
|
10554
|
+
src,
|
|
10555
|
+
alt: "",
|
|
10556
|
+
className: "absolute inset-0 h-full w-full scale-150 object-cover blur-[120px] saturate-[1.8]",
|
|
10557
|
+
style: { opacity: coverOpacity },
|
|
10558
|
+
referrerPolicy: "no-referrer",
|
|
10559
|
+
crossOrigin: "anonymous"
|
|
10560
|
+
}),
|
|
10561
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
10562
|
+
className: "absolute inset-0 dark:hidden",
|
|
10563
|
+
style: { background: overlayGradient("var(--background)", edge, middle) }
|
|
10564
|
+
}),
|
|
10565
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
10566
|
+
className: "absolute inset-0 hidden dark:block",
|
|
10567
|
+
style: { background: overlayGradient("#000", edge, middle) }
|
|
10568
|
+
})
|
|
10569
|
+
] });
|
|
10570
|
+
});
|
|
10571
|
+
AmbientCover.displayName = "AmbientCover";
|
|
10572
|
+
//#endregion
|
|
10573
|
+
//#region ktr/utils/cn.ts
|
|
10574
|
+
function cn(...inputs) {
|
|
10575
|
+
return twMerge(clsx(inputs));
|
|
10576
|
+
}
|
|
10453
10577
|
//#endregion
|
|
10454
10578
|
//#region ktr/template/components/GlowImage.tsx
|
|
10455
10579
|
var GlowImage = ({ src, children, alt, className, imgClassName, mode = "blur-layer", blurRadius = 18, glowStrength = .6, scale = 1.06, shadowRadius = 28, crossOrigin }) => {
|
|
@@ -11793,390 +11917,708 @@ var DecorationCard = ({ data }) => {
|
|
|
11793
11917
|
//#region ktr/template/bilibili/bangumi/components/bangumi.tsx
|
|
11794
11918
|
/** 海报每页展示的集数,和 core 的 EPISODE_SELECTION_PAGE_SIZE 保持一致 */
|
|
11795
11919
|
var DEFAULT_POSTER_PAGE_SIZE$1 = 15;
|
|
11796
|
-
/**
|
|
11797
|
-
|
|
11798
|
-
|
|
11799
|
-
|
|
11800
|
-
*/
|
|
11801
|
-
var
|
|
11802
|
-
|
|
11803
|
-
|
|
11804
|
-
|
|
11920
|
+
/** 选集有效期兜底(秒),正常由 data.timeoutSeconds 下发,和 core 的 EPISODE_SELECTION_TTL_SECONDS 保持一致 */
|
|
11921
|
+
var DEFAULT_TIMEOUT_SECONDS$1 = 120;
|
|
11922
|
+
/** QQBot 键盘每行的数字按钮数,和 core 的 EPISODE_SELECTION_BUTTONS_PER_ROW 保持一致 */
|
|
11923
|
+
var KEYS_PER_ROW$1 = 5;
|
|
11924
|
+
/** 演职员栏最多列出的「角色 声优」对数,其余折叠成「等 N 人」 */
|
|
11925
|
+
var CAST_LIMIT = 5;
|
|
11926
|
+
/** B 站粉:浅色主题压深到 #E04F86(大字对比度约 3.4:1),深色主题用品牌色 #FB7299 */
|
|
11927
|
+
var ACCENT_TEXT = "text-[#E04F86] dark:text-[#FB7299]";
|
|
11928
|
+
var ACCENT_BG = "bg-[#E04F86] dark:bg-[#FB7299]";
|
|
11929
|
+
/** 命令 chip 底色:覆盆子粉,白字对比度约 4.7:1 */
|
|
11930
|
+
var CHIP_BG$1 = "#CC3D72";
|
|
11931
|
+
/** 徽标缺色时的中性兜底 */
|
|
11932
|
+
var BADGE_FALLBACK = "#71717A";
|
|
11933
|
+
/** 网格补位块的跨列类名(Tailwind 只认静态字面量) */
|
|
11934
|
+
var COL_SPAN$1 = {
|
|
11935
|
+
1: "col-span-1",
|
|
11936
|
+
2: "col-span-2",
|
|
11937
|
+
3: "col-span-3",
|
|
11938
|
+
4: "col-span-4"
|
|
11939
|
+
};
|
|
11940
|
+
var COPYRIGHT_LABEL = { dujia: "独家" };
|
|
11941
|
+
/** 万/亿 计数拆成数值与单位:10 亿以下的亿级两位小数,其余一位,去掉末尾 0(306.0万 → 306万);不足 1 万原样返回 */
|
|
11942
|
+
var splitCount$1 = (count) => {
|
|
11943
|
+
if (count >= 1e9) return {
|
|
11944
|
+
value: `${Number((count / 1e8).toFixed(1))}`,
|
|
11945
|
+
unit: "亿"
|
|
11946
|
+
};
|
|
11947
|
+
if (count >= 1e8) return {
|
|
11948
|
+
value: `${Number((count / 1e8).toFixed(2))}`,
|
|
11949
|
+
unit: "亿"
|
|
11950
|
+
};
|
|
11951
|
+
if (count >= 1e4) return {
|
|
11952
|
+
value: `${Number((count / 1e4).toFixed(1))}`,
|
|
11953
|
+
unit: "万"
|
|
11954
|
+
};
|
|
11955
|
+
return {
|
|
11956
|
+
value: Math.max(0, Math.round(count)).toString(),
|
|
11957
|
+
unit: ""
|
|
11958
|
+
};
|
|
11805
11959
|
};
|
|
11806
|
-
/**
|
|
11807
|
-
|
|
11808
|
-
*
|
|
11809
|
-
|
|
11810
|
-
*/
|
|
11811
|
-
var formatDateParts = (timestamp) => {
|
|
11812
|
-
const date = /* @__PURE__ */ new Date(timestamp * 1e3);
|
|
11960
|
+
/** 「1800.1万追番」「1158.7万系列追番」拆成数值 / 单位 / 标签;数值照抄 B 站的文本,和番剧页显示一致 */
|
|
11961
|
+
var parseFollowText = (text) => {
|
|
11962
|
+
const match = /^\s*(\d+(?:\.\d+)?)\s*(万|亿)?\s*(.*)$/.exec(text || "");
|
|
11963
|
+
if (!match) return null;
|
|
11813
11964
|
return {
|
|
11814
|
-
|
|
11815
|
-
|
|
11965
|
+
value: match[1],
|
|
11966
|
+
unit: match[2] ?? "",
|
|
11967
|
+
label: match[3].trim() || "追番"
|
|
11816
11968
|
};
|
|
11817
11969
|
};
|
|
11818
|
-
/**
|
|
11819
|
-
|
|
11820
|
-
|
|
11821
|
-
|
|
11822
|
-
|
|
11823
|
-
const
|
|
11824
|
-
|
|
11825
|
-
|
|
11826
|
-
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
|
|
11830
|
-
|
|
11831
|
-
|
|
11832
|
-
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
|
|
11859
|
-
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
|
|
11970
|
+
/** 演职员表:后端给的是换行分隔的「角色:声优」「职务:人名」「其他配音演员:a、b、c」 */
|
|
11971
|
+
var STAFF_ROLE = /导演|监督|统筹|监制|制片|出品|编剧|原作|原著|音乐|作曲|美术|剪辑|分镜|作画|动画|总监|策划|配音指导/;
|
|
11972
|
+
var EXTRA_CAST_ROLE = /^(其他)?(配音)?演员$|^其他配音$|^其他声优$/;
|
|
11973
|
+
var parseCredits = (raw) => {
|
|
11974
|
+
const cast = [];
|
|
11975
|
+
const staff = [];
|
|
11976
|
+
const extras = [];
|
|
11977
|
+
for (const line of (raw || "").split(/\r?\n/)) {
|
|
11978
|
+
const text = line.trim();
|
|
11979
|
+
if (!text) continue;
|
|
11980
|
+
const index = text.search(/[::]/);
|
|
11981
|
+
if (index < 0) {
|
|
11982
|
+
extras.push(...text.split(/[、,,]/).map((name) => name.trim()).filter(Boolean));
|
|
11983
|
+
continue;
|
|
11984
|
+
}
|
|
11985
|
+
const role = text.slice(0, index).replace(/\s+/g, "");
|
|
11986
|
+
const value = text.slice(index + 1).trim();
|
|
11987
|
+
if (!role || !value) continue;
|
|
11988
|
+
if (EXTRA_CAST_ROLE.test(role)) extras.push(...value.split(/[、,,]/).map((name) => name.trim()).filter(Boolean));
|
|
11989
|
+
else if (STAFF_ROLE.test(role)) staff.push({
|
|
11990
|
+
role,
|
|
11991
|
+
name: value
|
|
11992
|
+
});
|
|
11993
|
+
else cast.push({
|
|
11994
|
+
role,
|
|
11995
|
+
actor: value
|
|
11996
|
+
});
|
|
11997
|
+
}
|
|
11998
|
+
return {
|
|
11999
|
+
cast,
|
|
12000
|
+
staff,
|
|
12001
|
+
extras,
|
|
12002
|
+
voiceCount: (/* @__PURE__ */ new Set([...cast.map((item) => item.actor), ...extras])).size
|
|
12003
|
+
};
|
|
12004
|
+
};
|
|
12005
|
+
/** 发布日期统一写成 2026.10.24,等宽数字列对齐,跨年也不歧义 */
|
|
12006
|
+
var formatPubDate = (seconds) => seconds > 0 ? format(/* @__PURE__ */ new Date(seconds * 1e3), "yyyy.MM.dd") : "";
|
|
12007
|
+
/** 按展示顺序(最新在前)写区间;只有一集时写「第 a 集」 */
|
|
12008
|
+
var formatEpisodeRange$1 = (first, last) => first === last ? `第 ${first} 集` : `第 ${first}–${last} 集`;
|
|
12009
|
+
/** 标题按字数分档:短标题撑满版面,长标题收字号换行 */
|
|
12010
|
+
var getTitleClassName$4 = (length) => {
|
|
12011
|
+
if (length <= 6) return "text-[132px] leading-[1.05]";
|
|
12012
|
+
if (length <= 10) return "text-[112px] leading-[1.08]";
|
|
12013
|
+
if (length <= 16) return "text-[96px] leading-[1.1] line-clamp-2";
|
|
12014
|
+
if (length <= 24) return "text-[80px] leading-[1.14] line-clamp-2";
|
|
12015
|
+
return "text-[68px] leading-[1.18] line-clamp-3";
|
|
12016
|
+
};
|
|
12017
|
+
/** 巨型区间数字的字宽系数(字号的倍数,含 -0.04em 字距),按 tabular 数字和短横线的实测宽度取上限 */
|
|
12018
|
+
var RANGE_NUMERAL_ADVANCE$1 = .56;
|
|
12019
|
+
/** 目录页巨型区间数字的字号:按左栏内容宽度和字符数反推,最大 184px,4 位集号的长区间也不会溢出 */
|
|
12020
|
+
var getRangeNumeralSize$1 = (length, compact) => Math.min(184, Math.floor((compact ? 448 : 520) / (Math.max(length, 1) * RANGE_NUMERAL_ADVANCE$1)));
|
|
12021
|
+
/** 背景:封面弥散 + 离散噪点,与兄弟模板同一套图层 */
|
|
12022
|
+
var PosterBackground$1 = ({ src, ctx }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12023
|
+
className: "pointer-events-none absolute inset-0 overflow-hidden select-none",
|
|
12024
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AmbientCover, {
|
|
12025
|
+
src,
|
|
12026
|
+
ctx
|
|
12027
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12028
|
+
className: "absolute inset-0 opacity-[0.35] mix-blend-overlay dark:mix-blend-soft-light",
|
|
12029
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
|
|
12030
|
+
className: "h-full w-full",
|
|
12031
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
12032
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("filter", {
|
|
12033
|
+
id: "bangumiNoise",
|
|
12034
|
+
children: [
|
|
12035
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feTurbulence", {
|
|
12036
|
+
type: "fractalNoise",
|
|
12037
|
+
baseFrequency: "0.8",
|
|
12038
|
+
numOctaves: "2",
|
|
12039
|
+
stitchTiles: "stitch"
|
|
12040
|
+
}),
|
|
12041
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feColorMatrix", {
|
|
12042
|
+
type: "saturate",
|
|
12043
|
+
values: "0"
|
|
12044
|
+
}),
|
|
12045
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("feComponentTransfer", { children: [
|
|
12046
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncR", {
|
|
12047
|
+
type: "discrete",
|
|
12048
|
+
tableValues: "0 1"
|
|
12049
|
+
}),
|
|
12050
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncG", {
|
|
12051
|
+
type: "discrete",
|
|
12052
|
+
tableValues: "0 1"
|
|
12053
|
+
}),
|
|
12054
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncB", {
|
|
12055
|
+
type: "discrete",
|
|
12056
|
+
tableValues: "0 1"
|
|
12057
|
+
})
|
|
12058
|
+
] }),
|
|
12059
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feComponentTransfer", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncA", {
|
|
12060
|
+
type: "linear",
|
|
12061
|
+
slope: "2",
|
|
12062
|
+
intercept: "-0.5"
|
|
12063
|
+
}) })
|
|
12064
|
+
]
|
|
12065
|
+
}) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
|
|
12066
|
+
width: "100%",
|
|
12067
|
+
height: "100%",
|
|
12068
|
+
filter: "url(#bangumiNoise)",
|
|
12069
|
+
fill: "white"
|
|
12070
|
+
})]
|
|
12071
|
+
})
|
|
12072
|
+
})]
|
|
12073
|
+
});
|
|
12074
|
+
/** 刊头:栏目名 + 平台 logo,靠字距和留白收束 */
|
|
12075
|
+
var Masthead$1 = ({ label, ctx }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
|
|
12076
|
+
className: "flex items-center justify-between pb-7",
|
|
12077
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12078
|
+
className: "flex items-center gap-5 text-[26px] font-bold tracking-[0.32em] text-foreground",
|
|
12079
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `h-5 w-5 ${ACCENT_BG}` }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: label })]
|
|
12080
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
|
|
12081
|
+
src: isDark(ctx) ? "/image/bilibili/bilibili-light.png" : "/image/bilibili/bilibili.png",
|
|
12082
|
+
alt: "哔哩哔哩",
|
|
12083
|
+
className: "h-14 w-auto"
|
|
12084
|
+
})]
|
|
12085
|
+
});
|
|
12086
|
+
/** 眉题:强调色小号粗体,用细点分隔 */
|
|
12087
|
+
var Kicker$1 = ({ items }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12088
|
+
className: `flex flex-wrap items-center gap-x-4 text-[30px] font-bold ${ACCENT_TEXT}`,
|
|
12089
|
+
children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.Fragment, { children: [index > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12090
|
+
className: "text-muted",
|
|
12091
|
+
children: "·"
|
|
12092
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: item })] }, `${index}-${item}`))
|
|
12093
|
+
});
|
|
12094
|
+
/** 数据栏:四格铺在浅色面板上,用留白代替分隔线,小标签 + 粗体大数字 + 小单位 */
|
|
12095
|
+
var Ledger$1 = ({ items }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12096
|
+
className: "grid grid-cols-4 gap-x-10 rounded-3xl bg-foreground/5 px-10 py-8",
|
|
12097
|
+
children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12098
|
+
className: "text-[24px] font-medium text-foreground/65",
|
|
12099
|
+
children: item.label
|
|
12100
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12101
|
+
className: "mt-1 flex items-baseline gap-1.5 text-foreground",
|
|
12102
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12103
|
+
className: "text-[60px] leading-none font-black tabular-nums",
|
|
12104
|
+
children: item.value
|
|
12105
|
+
}), item.unit && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12106
|
+
className: "text-[26px] font-bold",
|
|
12107
|
+
children: item.unit
|
|
12108
|
+
})]
|
|
12109
|
+
})] }, item.label))
|
|
12110
|
+
});
|
|
12111
|
+
/** 演职员栏的一行:左侧小标签,右侧内容 */
|
|
12112
|
+
var CreditRow = ({ label, children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12113
|
+
className: "flex gap-6",
|
|
12114
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
|
|
12115
|
+
className: "w-16 shrink-0 pt-0.5 text-[24px] font-bold text-foreground/65",
|
|
12116
|
+
children: label
|
|
12117
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", {
|
|
12118
|
+
className: "min-w-0 flex-1 text-[26px] leading-[1.55] text-foreground",
|
|
12119
|
+
children
|
|
12120
|
+
})]
|
|
12121
|
+
});
|
|
12122
|
+
/** 专题 hero:左封面,右眉题 / 大标题 / 类型 / 简介 / 演职员栏 */
|
|
12123
|
+
var Hero$1 = ({ data }) => {
|
|
12124
|
+
const credits = parseCredits(data.Actors);
|
|
12125
|
+
const shownCast = credits.cast.slice(0, CAST_LIMIT);
|
|
12126
|
+
const shownExtras = shownCast.length > 0 ? [] : credits.extras.slice(0, CAST_LIMIT);
|
|
12127
|
+
const shownCount = shownCast.length + shownExtras.length;
|
|
12128
|
+
const statusParts = (data.newEP?.desc || "").split(/[,,]/).map((part) => part.trim()).filter(Boolean);
|
|
12129
|
+
const copyright = COPYRIGHT_LABEL[data.Copyright];
|
|
12130
|
+
const kicker = [
|
|
12131
|
+
"番剧",
|
|
12132
|
+
...copyright ? [copyright] : [],
|
|
12133
|
+
...statusParts
|
|
12134
|
+
];
|
|
12135
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12136
|
+
className: "flex items-stretch gap-16",
|
|
12137
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12138
|
+
className: "relative min-h-146.75 w-110 shrink-0 overflow-hidden rounded-8xl bg-surface-secondary shadow-2xl shadow-black/20",
|
|
12139
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12140
|
+
className: "absolute inset-0",
|
|
12141
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
12142
|
+
src: data.mainCover,
|
|
12143
|
+
alt: data.Title,
|
|
12144
|
+
className: "h-full w-full object-cover"
|
|
12145
|
+
})
|
|
12146
|
+
})
|
|
12147
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12148
|
+
className: "flex min-w-0 flex-1 flex-col",
|
|
12149
|
+
children: [
|
|
12150
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Kicker$1, { items: kicker }),
|
|
12151
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
|
|
12152
|
+
className: `mt-5 font-black tracking-tight text-balance text-foreground ${getTitleClassName$4(data.Title.length)}`,
|
|
12153
|
+
children: data.Title
|
|
12154
|
+
}),
|
|
12155
|
+
data.Styles.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12156
|
+
className: "mt-3 text-[30px] font-medium text-foreground/70",
|
|
12157
|
+
children: data.Styles.join(" / ")
|
|
12158
|
+
}),
|
|
12159
|
+
data.Evaluate && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
12160
|
+
className: "mt-5 line-clamp-3 text-[30px] leading-[1.55] font-light text-foreground/80",
|
|
12161
|
+
children: data.Evaluate
|
|
12162
|
+
}),
|
|
12163
|
+
(shownCount > 0 || credits.staff.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12164
|
+
className: "mt-auto pt-8",
|
|
12165
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("dl", {
|
|
12166
|
+
className: "flex flex-col gap-2.5 pt-6",
|
|
12167
|
+
children: [shownCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CreditRow, {
|
|
12168
|
+
label: "声优",
|
|
12169
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
12170
|
+
className: "flex flex-wrap gap-x-7",
|
|
11863
12171
|
children: [
|
|
11864
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
11865
|
-
|
|
11866
|
-
|
|
11867
|
-
|
|
11868
|
-
|
|
11869
|
-
|
|
11870
|
-
|
|
11871
|
-
|
|
11872
|
-
|
|
11873
|
-
className: "text-warning"
|
|
11874
|
-
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Crown, {
|
|
11875
|
-
width: 20,
|
|
11876
|
-
className: "text-accent"
|
|
12172
|
+
shownCast.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
12173
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12174
|
+
className: "text-foreground/60",
|
|
12175
|
+
children: item.role
|
|
12176
|
+
}),
|
|
12177
|
+
" ",
|
|
12178
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12179
|
+
className: "font-bold",
|
|
12180
|
+
children: item.actor
|
|
11877
12181
|
})
|
|
12182
|
+
] }, `${item.role}-${item.actor}`)),
|
|
12183
|
+
shownExtras.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12184
|
+
className: "font-bold",
|
|
12185
|
+
children: shownExtras.join("、")
|
|
11878
12186
|
}),
|
|
11879
|
-
|
|
11880
|
-
|
|
11881
|
-
|
|
11882
|
-
|
|
11883
|
-
|
|
11884
|
-
|
|
11885
|
-
|
|
11886
|
-
},
|
|
11887
|
-
children: props.upInfo.vip_label.text
|
|
12187
|
+
credits.voiceCount > shownCount && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
12188
|
+
className: "text-foreground/60",
|
|
12189
|
+
children: [
|
|
12190
|
+
"等 ",
|
|
12191
|
+
credits.voiceCount,
|
|
12192
|
+
" 人"
|
|
12193
|
+
]
|
|
11888
12194
|
})
|
|
11889
12195
|
]
|
|
11890
|
-
})
|
|
11891
|
-
|
|
11892
|
-
|
|
11893
|
-
|
|
11894
|
-
|
|
11895
|
-
|
|
11896
|
-
|
|
11897
|
-
|
|
11898
|
-
|
|
11899
|
-
|
|
11900
|
-
|
|
11901
|
-
|
|
12196
|
+
})
|
|
12197
|
+
}), credits.staff.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CreditRow, {
|
|
12198
|
+
label: "制作",
|
|
12199
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12200
|
+
className: "flex flex-wrap gap-x-7",
|
|
12201
|
+
children: credits.staff.slice(0, 3).map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
12202
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12203
|
+
className: "text-foreground/60",
|
|
12204
|
+
children: item.role
|
|
12205
|
+
}),
|
|
12206
|
+
" ",
|
|
12207
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12208
|
+
className: "font-bold",
|
|
12209
|
+
children: item.name
|
|
11902
12210
|
})
|
|
11903
|
-
]
|
|
11904
|
-
}),
|
|
11905
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11906
|
-
className: "flex gap-2 items-center text-2xl select-text text-foreground/70",
|
|
11907
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Hash, { size: 20 }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: ["UID: ", props.upInfo.mid] })]
|
|
12211
|
+
] }, `${item.role}-${item.name}`))
|
|
11908
12212
|
})
|
|
11909
|
-
]
|
|
11910
|
-
})]
|
|
11911
|
-
})]
|
|
11912
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11913
|
-
className: "flex flex-col flex-1 justify-between text-foreground",
|
|
11914
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
11915
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
11916
|
-
className: "mb-8 text-8xl font-bold leading-tight select-text",
|
|
11917
|
-
children: props.title
|
|
11918
|
-
}),
|
|
11919
|
-
props.subtitle && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
11920
|
-
className: "mb-12 text-4xl select-text text-foreground",
|
|
11921
|
-
children: props.subtitle
|
|
11922
|
-
}),
|
|
11923
|
-
props.styles && props.styles.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
11924
|
-
className: "flex flex-wrap gap-8 mb-12",
|
|
11925
|
-
children: props.styles.map((style, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chip, {
|
|
11926
|
-
size: "lg",
|
|
11927
|
-
className: "w-32 h-12 rounded-xl bg-surface-secondary px-4 py-2 text-3xl text-foreground backdrop-blur-sm select-text",
|
|
11928
|
-
children: style
|
|
11929
|
-
}, index))
|
|
11930
|
-
}),
|
|
11931
|
-
actorList.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11932
|
-
className: "mb-12",
|
|
11933
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11934
|
-
className: "flex gap-6 items-center mb-6 text-3xl select-text text-foreground",
|
|
11935
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Users, { size: 30 }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "声优阵容" })]
|
|
11936
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11937
|
-
className: "flex flex-wrap gap-8",
|
|
11938
|
-
children: [actorList.slice(0, 6).map((actor, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
11939
|
-
className: "text-3xl select-text text-foreground",
|
|
11940
|
-
children: actor
|
|
11941
|
-
}, index)), actorList.length > 6 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11942
|
-
className: "text-3xl select-text text-foreground",
|
|
11943
|
-
children: [
|
|
11944
|
-
"等",
|
|
11945
|
-
actorList.length,
|
|
11946
|
-
"人"
|
|
11947
|
-
]
|
|
11948
|
-
})]
|
|
11949
|
-
})]
|
|
11950
|
-
}),
|
|
11951
|
-
props.evaluate && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11952
|
-
className: "mb-12",
|
|
11953
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11954
|
-
className: "flex gap-6 items-center mb-6 text-3xl select-text text-foreground",
|
|
11955
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Star, { size: 30 }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "评价" })]
|
|
11956
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
11957
|
-
className: "text-3xl leading-relaxed select-text text-foreground",
|
|
11958
|
-
children: props.evaluate
|
|
11959
12213
|
})]
|
|
11960
12214
|
})
|
|
11961
|
-
|
|
11962
|
-
|
|
12215
|
+
})
|
|
12216
|
+
]
|
|
12217
|
+
})]
|
|
12218
|
+
});
|
|
12219
|
+
};
|
|
12220
|
+
/** 可执行命令:统一实心高对比 chip */
|
|
12221
|
+
var CommandChip$1 = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12222
|
+
className: "inline-flex h-15 items-center rounded-2xl px-6 text-[30px] font-bold whitespace-nowrap text-white shadow-lg shadow-black/15",
|
|
12223
|
+
style: { backgroundColor: CHIP_BG$1 },
|
|
12224
|
+
children
|
|
12225
|
+
});
|
|
12226
|
+
/** 有效期说明:两种模式共用;主句加粗,补充说明降一档。只有一页时没有翻页,不提重新计时 */
|
|
12227
|
+
var ValidityNote$1 = ({ seconds, pageCount }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12228
|
+
className: "flex items-start gap-3 text-[26px] leading-snug",
|
|
12229
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Timer, {
|
|
12230
|
+
className: "mt-0.5 h-7 w-7 shrink-0 text-foreground/70",
|
|
12231
|
+
strokeWidth: 2.2
|
|
12232
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12233
|
+
className: "font-bold text-foreground",
|
|
12234
|
+
children: [
|
|
12235
|
+
seconds,
|
|
12236
|
+
" 秒内有效",
|
|
12237
|
+
pageCount > 1 && ",翻页重新计时"
|
|
12238
|
+
]
|
|
12239
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12240
|
+
className: "mt-0.5 text-foreground/65",
|
|
12241
|
+
children: "过期请重新发送原链接"
|
|
12242
|
+
})] })]
|
|
12243
|
+
});
|
|
12244
|
+
/** 文字命令模式:只列出当前页真正能用的命令;后端也认纯数字集号,用本页第一集举例 */
|
|
12245
|
+
var TextGuide$1 = ({ first, page, pageCount, seconds }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12246
|
+
className: "flex flex-col gap-5",
|
|
12247
|
+
children: [
|
|
12248
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12249
|
+
className: "text-[34px] font-black text-foreground",
|
|
12250
|
+
children: "回复文字选集"
|
|
12251
|
+
}),
|
|
12252
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12253
|
+
className: "flex items-center gap-5",
|
|
12254
|
+
children: [
|
|
12255
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12256
|
+
className: "w-19 shrink-0 text-[28px] font-bold text-foreground",
|
|
12257
|
+
children: "选集"
|
|
12258
|
+
}),
|
|
12259
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12260
|
+
className: "text-[26px] text-foreground/65",
|
|
12261
|
+
children: "发送"
|
|
12262
|
+
}),
|
|
12263
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip$1, { children: "第?集" }),
|
|
12264
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
12265
|
+
className: "text-[26px] text-foreground/65",
|
|
12266
|
+
children: ["也可只发集号,如 ", first]
|
|
12267
|
+
})
|
|
12268
|
+
]
|
|
12269
|
+
}),
|
|
12270
|
+
pageCount > 1 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12271
|
+
className: "flex items-center gap-5",
|
|
12272
|
+
children: [
|
|
12273
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12274
|
+
className: "w-19 shrink-0 text-[28px] font-bold text-foreground",
|
|
12275
|
+
children: "翻页"
|
|
12276
|
+
}),
|
|
12277
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12278
|
+
className: "text-[26px] text-foreground/65",
|
|
12279
|
+
children: "发送"
|
|
12280
|
+
}),
|
|
12281
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12282
|
+
className: "flex flex-wrap gap-3",
|
|
11963
12283
|
children: [
|
|
11964
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
11965
|
-
|
|
11966
|
-
|
|
11967
|
-
className: "flex items-baseline",
|
|
11968
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
11969
|
-
className: "text-4xl font-bold select-text text-foreground",
|
|
11970
|
-
children: formatNumber$2(props.stat.views).slice(0, -1)
|
|
11971
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
11972
|
-
className: "text-xl font-bold select-text text-foreground",
|
|
11973
|
-
children: formatNumber$2(props.stat.views).slice(-1)
|
|
11974
|
-
})]
|
|
11975
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
11976
|
-
className: "text-2xl whitespace-nowrap select-text",
|
|
11977
|
-
children: "播放"
|
|
11978
|
-
})]
|
|
11979
|
-
}),
|
|
11980
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11981
|
-
className: "items-center min-w-0",
|
|
11982
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11983
|
-
className: "flex items-baseline",
|
|
11984
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
11985
|
-
className: "text-4xl font-bold select-text text-foreground",
|
|
11986
|
-
children: formatNumber$2(props.stat.favorites).slice(0, -1)
|
|
11987
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
11988
|
-
className: "text-xl font-bold select-text text-foreground",
|
|
11989
|
-
children: formatNumber$2(props.stat.favorites).slice(-1)
|
|
11990
|
-
})]
|
|
11991
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
11992
|
-
className: "text-2xl whitespace-nowrap select-text",
|
|
11993
|
-
children: "收藏"
|
|
11994
|
-
})]
|
|
11995
|
-
}),
|
|
11996
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11997
|
-
className: "items-center min-w-0",
|
|
11998
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11999
|
-
className: "flex items-baseline",
|
|
12000
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12001
|
-
className: "text-4xl font-bold select-text text-foreground",
|
|
12002
|
-
children: formatNumber$2(props.stat.danmakus).slice(0, -1)
|
|
12003
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12004
|
-
className: "text-xl font-bold select-text text-foreground",
|
|
12005
|
-
children: formatNumber$2(props.stat.danmakus).slice(-1)
|
|
12006
|
-
})]
|
|
12007
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12008
|
-
className: "text-2xl whitespace-nowrap select-text",
|
|
12009
|
-
children: "弹幕"
|
|
12010
|
-
})]
|
|
12011
|
-
}),
|
|
12012
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12013
|
-
className: "items-center min-w-0",
|
|
12014
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12015
|
-
className: "flex items-baseline",
|
|
12016
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12017
|
-
className: "text-4xl font-bold select-text text-foreground",
|
|
12018
|
-
children: formatNumber$2(props.stat.coins).slice(0, -1)
|
|
12019
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12020
|
-
className: "text-xl font-bold select-text text-foreground",
|
|
12021
|
-
children: formatNumber$2(props.stat.coins).slice(-1)
|
|
12022
|
-
})]
|
|
12023
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12024
|
-
className: "text-2xl whitespace-nowrap select-text",
|
|
12025
|
-
children: "投币"
|
|
12026
|
-
})]
|
|
12027
|
-
})
|
|
12284
|
+
page > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip$1, { children: "上一页" }),
|
|
12285
|
+
page < pageCount && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip$1, { children: "下一页" }),
|
|
12286
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip$1, { children: "第?页" })
|
|
12028
12287
|
]
|
|
12029
|
-
})
|
|
12288
|
+
})
|
|
12289
|
+
]
|
|
12290
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12291
|
+
className: "flex items-center gap-5",
|
|
12292
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12293
|
+
className: "w-19 shrink-0 text-[28px] font-bold text-foreground",
|
|
12294
|
+
children: "翻页"
|
|
12295
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12296
|
+
className: "text-[26px] text-foreground/65",
|
|
12297
|
+
children: "只有这一页,无需翻页"
|
|
12030
12298
|
})]
|
|
12299
|
+
}),
|
|
12300
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidityNote$1, {
|
|
12301
|
+
seconds,
|
|
12302
|
+
pageCount
|
|
12031
12303
|
})
|
|
12032
|
-
|
|
12033
|
-
};
|
|
12034
|
-
/**
|
|
12035
|
-
var
|
|
12036
|
-
className: "
|
|
12304
|
+
]
|
|
12305
|
+
});
|
|
12306
|
+
/** 键盘示意里的一枚按钮:数字键与「跳转」是蓝框键(style 1),翻页是灰框键;small 给 4 位集号用 */
|
|
12307
|
+
var SketchKey$1 = ({ children, quiet, small }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12308
|
+
className: quiet ? "flex h-11 flex-1 items-center justify-center rounded-lg border-2 border-foreground/20 text-[24px] font-bold text-foreground/60" : `flex h-11 flex-1 items-center justify-center rounded-lg border-2 border-foreground/45 font-bold text-foreground tabular-nums ${small ? "text-[18px]" : "text-[24px]"}`,
|
|
12037
12309
|
children
|
|
12038
12310
|
});
|
|
12039
|
-
/**
|
|
12040
|
-
|
|
12041
|
-
|
|
12042
|
-
|
|
12043
|
-
|
|
12044
|
-
|
|
12045
|
-
const totalEpisodes = props.length > 0 ? props.length : props.Episodes.length;
|
|
12046
|
-
const pageSize = Math.max(1, props.posterPageSize ?? DEFAULT_POSTER_PAGE_SIZE$1);
|
|
12047
|
-
const pageCount = Math.max(1, Math.ceil(totalEpisodes / pageSize));
|
|
12048
|
-
const page = Math.min(Math.max(1, props.posterPage ?? 1), pageCount);
|
|
12049
|
-
const start = (page - 1) * pageSize;
|
|
12050
|
-
const visibleEpisodes = props.Episodes.slice(start, start + pageSize);
|
|
12051
|
-
if (visibleEpisodes.length === 0) return null;
|
|
12052
|
-
const episodeNumbers = visibleEpisodes.map((episode, index) => episode.episode ?? start + index + 1);
|
|
12053
|
-
const firstEpisode = episodeNumbers[0];
|
|
12054
|
-
const lastEpisode = episodeNumbers[episodeNumbers.length - 1];
|
|
12055
|
-
const range = firstEpisode === lastEpisode ? `第 ${firstEpisode} 集` : `第 ${firstEpisode}–${lastEpisode} 集`;
|
|
12311
|
+
/** 按钮模式的键盘示意:只画本页真实存在的按钮,排布与 QQBot 键盘一致;宽度固定,4 位集号收小字号,左侧说明不被挤到换行 */
|
|
12312
|
+
var KeySketch$1 = ({ numbers, page, pageCount }) => {
|
|
12313
|
+
const rows = [];
|
|
12314
|
+
for (let index = 0; index < numbers.length; index += KEYS_PER_ROW$1) rows.push(numbers.slice(index, index + KEYS_PER_ROW$1));
|
|
12315
|
+
const navigation = [page > 1 ? "上一页" : "", page < pageCount ? "下一页" : ""].filter(Boolean);
|
|
12316
|
+
const small = numbers.some((number) => number >= 1e3);
|
|
12056
12317
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12057
|
-
className: "
|
|
12318
|
+
className: "flex w-82.5 shrink-0 flex-col gap-1.5 self-start rounded-3xl bg-surface/60 p-3",
|
|
12319
|
+
children: [
|
|
12320
|
+
pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SketchKey$1, { children: "跳转到第x页" }),
|
|
12321
|
+
rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12322
|
+
className: "flex gap-1.5",
|
|
12323
|
+
children: row.map((number) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SketchKey$1, {
|
|
12324
|
+
small,
|
|
12325
|
+
children: number
|
|
12326
|
+
}, number))
|
|
12327
|
+
}, row[0])),
|
|
12328
|
+
navigation.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12329
|
+
className: "flex gap-1.5",
|
|
12330
|
+
children: navigation.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SketchKey$1, {
|
|
12331
|
+
quiet: true,
|
|
12332
|
+
children: label
|
|
12333
|
+
}, label))
|
|
12334
|
+
})
|
|
12335
|
+
]
|
|
12336
|
+
});
|
|
12337
|
+
};
|
|
12338
|
+
/** 按钮模式:引导点按钮,不出现任何手打命令 */
|
|
12339
|
+
var ButtonGuide$1 = ({ numbers, page, pageCount, seconds }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12340
|
+
className: "flex gap-6",
|
|
12341
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12342
|
+
className: "flex min-w-0 flex-1 flex-col gap-4",
|
|
12058
12343
|
children: [
|
|
12059
12344
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12060
|
-
className: "flex
|
|
12061
|
-
children: [
|
|
12062
|
-
|
|
12063
|
-
|
|
12064
|
-
|
|
12065
|
-
size: "lg",
|
|
12066
|
-
color: "danger",
|
|
12067
|
-
variant: "soft",
|
|
12068
|
-
className: "h-18 px-4 py-2 text-4xl select-text",
|
|
12069
|
-
children: [
|
|
12070
|
-
"共",
|
|
12071
|
-
totalEpisodes,
|
|
12072
|
-
"集"
|
|
12073
|
-
]
|
|
12074
|
-
}),
|
|
12075
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12076
|
-
className: "text-3xl font-semibold select-text text-muted",
|
|
12077
|
-
children: props.selectionMode === "button" ? range : `第 ${page}/${pageCount} 页 · ${range}`
|
|
12078
|
-
})
|
|
12079
|
-
]
|
|
12345
|
+
className: "flex items-center gap-3 text-[34px] font-black text-foreground",
|
|
12346
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MousePointerClick, {
|
|
12347
|
+
className: `h-9 w-9 shrink-0 ${ACCENT_TEXT}`,
|
|
12348
|
+
strokeWidth: 2.4
|
|
12349
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "点击下方按钮选集" })]
|
|
12080
12350
|
}),
|
|
12081
|
-
|
|
12082
|
-
className: "flex flex-col gap-
|
|
12083
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.
|
|
12084
|
-
className: "flex flex-wrap gap-3 items-center",
|
|
12085
|
-
children: [
|
|
12086
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "发送" }),
|
|
12087
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip$1, { children: "第?集" }),
|
|
12088
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "选集" })
|
|
12089
|
-
]
|
|
12090
|
-
}), pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12091
|
-
className: "flex flex-wrap gap-3 items-center",
|
|
12092
|
-
children: [
|
|
12093
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "发送" }),
|
|
12094
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip$1, { children: "上一页" }),
|
|
12095
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12096
|
-
className: "text-foreground/30",
|
|
12097
|
-
children: "/"
|
|
12098
|
-
}),
|
|
12099
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip$1, { children: "下一页" }),
|
|
12100
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12101
|
-
className: "text-foreground/30",
|
|
12102
|
-
children: "/"
|
|
12103
|
-
}),
|
|
12104
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip$1, { children: "第?页" }),
|
|
12105
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "翻页" })
|
|
12106
|
-
]
|
|
12107
|
-
})]
|
|
12351
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("ul", {
|
|
12352
|
+
className: "flex flex-col gap-2 text-[26px] leading-snug text-foreground/80",
|
|
12353
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: "数字键即集号,点一下直接解析" }), pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: "「跳转到第x页」补上页码再发送" })]
|
|
12108
12354
|
}),
|
|
12109
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
12110
|
-
|
|
12111
|
-
|
|
12112
|
-
const episodeNumber = episodeNumbers[index];
|
|
12113
|
-
const { month, day } = formatDateParts(episode.pub_time);
|
|
12114
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12115
|
-
className: "flex flex-col overflow-hidden bg-surface rounded-3xl shadow-large",
|
|
12116
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12117
|
-
className: "overflow-hidden relative aspect-video",
|
|
12118
|
-
children: [
|
|
12119
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
12120
|
-
src: episode.cover,
|
|
12121
|
-
alt: `第${episodeNumber}集 ${episode.long_title}`,
|
|
12122
|
-
className: "object-cover w-full h-full select-text"
|
|
12123
|
-
}),
|
|
12124
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12125
|
-
className: "absolute top-4 left-4 px-3 py-1 text-2xl font-bold text-white rounded-xl bg-black/65",
|
|
12126
|
-
children: [
|
|
12127
|
-
"第",
|
|
12128
|
-
episodeNumber,
|
|
12129
|
-
"集"
|
|
12130
|
-
]
|
|
12131
|
-
}),
|
|
12132
|
-
episode.badge && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chip, {
|
|
12133
|
-
size: "sm",
|
|
12134
|
-
className: "absolute top-4 right-4 px-2 py-1 text-lg font-medium select-text",
|
|
12135
|
-
style: {
|
|
12136
|
-
backgroundColor: episode.badge_info?.bg_color || "#FB7299",
|
|
12137
|
-
color: "#FFFFFF"
|
|
12138
|
-
},
|
|
12139
|
-
children: episode.badge_info?.text || episode.badge
|
|
12140
|
-
})
|
|
12141
|
-
]
|
|
12142
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12143
|
-
className: "flex flex-col flex-1 gap-3 p-5",
|
|
12144
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12145
|
-
className: "text-3xl font-semibold leading-snug select-text text-foreground line-clamp-2",
|
|
12146
|
-
children: episode.long_title || `第${episodeNumber}集`
|
|
12147
|
-
}), episode.pub_time > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12148
|
-
className: "mt-auto text-2xl select-text text-foreground/60",
|
|
12149
|
-
children: [
|
|
12150
|
-
month,
|
|
12151
|
-
day,
|
|
12152
|
-
"日"
|
|
12153
|
-
]
|
|
12154
|
-
})]
|
|
12155
|
-
})]
|
|
12156
|
-
}, `${episodeNumber}-${episode.bvid}`);
|
|
12157
|
-
})
|
|
12355
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidityNote$1, {
|
|
12356
|
+
seconds,
|
|
12357
|
+
pageCount
|
|
12158
12358
|
})
|
|
12159
12359
|
]
|
|
12360
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(KeySketch$1, {
|
|
12361
|
+
numbers,
|
|
12362
|
+
page,
|
|
12363
|
+
pageCount
|
|
12364
|
+
})]
|
|
12365
|
+
});
|
|
12366
|
+
/** 目录页开篇:巨型区间数字 + 操作说明 */
|
|
12367
|
+
var Contents$1 = ({ items, page, pageCount, mode, seconds }) => {
|
|
12368
|
+
const first = items[0]?.number ?? 0;
|
|
12369
|
+
const last = items[items.length - 1]?.number ?? 0;
|
|
12370
|
+
const numeral = first === last ? `${first}` : `${first}–${last}`;
|
|
12371
|
+
const compact = mode === "button";
|
|
12372
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12373
|
+
className: "flex items-end justify-between",
|
|
12374
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12375
|
+
className: "flex items-baseline gap-5",
|
|
12376
|
+
children: [
|
|
12377
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `h-6 w-6 self-center ${ACCENT_BG}` }),
|
|
12378
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
|
|
12379
|
+
className: "text-[72px] leading-none font-black text-foreground",
|
|
12380
|
+
children: "选集"
|
|
12381
|
+
}),
|
|
12382
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12383
|
+
className: "text-[24px] font-bold tracking-[0.3em] text-foreground/55",
|
|
12384
|
+
children: "CONTENTS"
|
|
12385
|
+
})
|
|
12386
|
+
]
|
|
12387
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12388
|
+
className: "rounded-full bg-foreground/10 px-7 py-2 text-[34px] font-bold text-foreground tabular-nums",
|
|
12389
|
+
children: [
|
|
12390
|
+
"第 ",
|
|
12391
|
+
page,
|
|
12392
|
+
" / ",
|
|
12393
|
+
pageCount,
|
|
12394
|
+
" 页"
|
|
12395
|
+
]
|
|
12396
|
+
})]
|
|
12397
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12398
|
+
className: "mt-8 flex items-stretch",
|
|
12399
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12400
|
+
className: compact ? "w-120 shrink-0 pr-8" : "w-140 shrink-0 pr-10",
|
|
12401
|
+
children: [
|
|
12402
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12403
|
+
className: "leading-[0.84] font-light tracking-[-0.04em] whitespace-nowrap text-foreground tabular-nums",
|
|
12404
|
+
style: { fontSize: getRangeNumeralSize$1(numeral.length, compact) },
|
|
12405
|
+
children: numeral
|
|
12406
|
+
}),
|
|
12407
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12408
|
+
className: "mt-6 text-[30px] leading-snug font-bold text-foreground",
|
|
12409
|
+
children: formatEpisodeRange$1(first, last)
|
|
12410
|
+
}),
|
|
12411
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12412
|
+
className: "mt-1 flex items-center gap-2.5 text-[28px] font-bold text-foreground",
|
|
12413
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowDownWideNarrow, {
|
|
12414
|
+
className: `h-8 w-8 shrink-0 ${ACCENT_TEXT}`,
|
|
12415
|
+
strokeWidth: 2.4
|
|
12416
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "最新在前" })]
|
|
12417
|
+
})
|
|
12418
|
+
]
|
|
12419
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12420
|
+
className: "min-w-0 flex-1 pl-10",
|
|
12421
|
+
children: mode === "button" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ButtonGuide$1, {
|
|
12422
|
+
numbers: items.map((item) => item.number),
|
|
12423
|
+
page,
|
|
12424
|
+
pageCount,
|
|
12425
|
+
seconds
|
|
12426
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextGuide$1, {
|
|
12427
|
+
first,
|
|
12428
|
+
page,
|
|
12429
|
+
pageCount,
|
|
12430
|
+
seconds
|
|
12431
|
+
})
|
|
12432
|
+
})]
|
|
12433
|
+
})] });
|
|
12434
|
+
};
|
|
12435
|
+
/** 集号栏:按本页最大位数取宽度,同一页标题左缘对齐;4 位集号降字号,不挤占标题 */
|
|
12436
|
+
var NUMBER_COLUMN_CLASS = [
|
|
12437
|
+
"min-w-14 text-[80px]",
|
|
12438
|
+
"min-w-26 text-[80px]",
|
|
12439
|
+
"min-w-37.5 text-[80px]",
|
|
12440
|
+
"min-w-37 text-[60px]"
|
|
12441
|
+
];
|
|
12442
|
+
/** 选集单元:封面右上角是 B 站徽标,下方大集号在左,标题两行 + 日期作说明文字 */
|
|
12443
|
+
var BangumiCell = ({ item, dark, numberClassName }) => {
|
|
12444
|
+
const { episode, number } = item;
|
|
12445
|
+
const badge = episode.badge || episode.badge_info?.text || "";
|
|
12446
|
+
const badgeColor = (dark ? episode.badge_info?.bg_color_night || episode.badge_info?.bg_color : episode.badge_info?.bg_color) || BADGE_FALLBACK;
|
|
12447
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12448
|
+
className: "min-w-0",
|
|
12449
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12450
|
+
className: "relative aspect-video overflow-hidden rounded-3xl bg-surface-secondary shadow-lg shadow-black/10",
|
|
12451
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
12452
|
+
src: episode.cover,
|
|
12453
|
+
alt: episode.long_title || `第 ${number} 集`,
|
|
12454
|
+
className: "h-full w-full object-cover"
|
|
12455
|
+
}), badge && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12456
|
+
className: "absolute top-4 right-4 rounded-xl px-3.5 py-1 text-[24px] leading-normal font-bold text-white shadow-md shadow-black/20",
|
|
12457
|
+
style: { backgroundColor: badgeColor },
|
|
12458
|
+
children: badge
|
|
12459
|
+
})]
|
|
12460
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12461
|
+
className: "mt-4 flex gap-4",
|
|
12462
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12463
|
+
className: `shrink-0 leading-[0.9] font-black tracking-tight text-foreground tabular-nums ${numberClassName}`,
|
|
12464
|
+
children: number
|
|
12465
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12466
|
+
className: "min-w-0 flex-1 pt-0.5",
|
|
12467
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12468
|
+
className: "line-clamp-2 text-[30px] leading-tight font-bold text-pretty text-foreground",
|
|
12469
|
+
children: episode.long_title || `第 ${number} 集`
|
|
12470
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12471
|
+
className: "mt-1 font-mono text-[26px] leading-tight text-foreground/65",
|
|
12472
|
+
children: formatPubDate(episode.pub_time)
|
|
12473
|
+
})]
|
|
12474
|
+
})]
|
|
12475
|
+
})]
|
|
12476
|
+
});
|
|
12477
|
+
};
|
|
12478
|
+
/** 最后一页不满一行时的收尾块:说明最新剧集在哪一页,并给出往回翻的方式 */
|
|
12479
|
+
var EndCard$1 = ({ span, listed, pageCount, mode }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12480
|
+
className: `${COL_SPAN$1[span] ?? "col-span-1"} flex flex-col justify-center self-stretch rounded-3xl bg-foreground/5 p-9`,
|
|
12481
|
+
children: [
|
|
12482
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12483
|
+
className: "flex items-center gap-4 text-[40px] leading-tight font-black text-foreground",
|
|
12484
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `h-5 w-5 shrink-0 ${ACCENT_BG}` }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: pageCount > 1 ? "已是最后一页" : "只有这一页" })]
|
|
12485
|
+
}),
|
|
12486
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
12487
|
+
className: "mt-4 text-[28px] leading-normal text-foreground/75",
|
|
12488
|
+
children: pageCount > 1 ? "最新的剧集在第 1 页" : `共 ${listed} 集`
|
|
12489
|
+
}),
|
|
12490
|
+
pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12491
|
+
className: "flex flex-wrap items-center gap-3 pt-6 text-[28px] text-foreground/70",
|
|
12492
|
+
children: mode === "button" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "点键盘「上一页」往回翻" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
12493
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "发送" }),
|
|
12494
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip$1, { children: "上一页" }),
|
|
12495
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "往回翻" })
|
|
12496
|
+
] })
|
|
12497
|
+
})
|
|
12498
|
+
]
|
|
12499
|
+
});
|
|
12500
|
+
/** 选集网格:3 列,标题两行可读;最后一页不满一行时补收尾块 */
|
|
12501
|
+
var EpisodeGrid$1 = ({ items, dark, isLastPage, pageCount, listed, mode }) => {
|
|
12502
|
+
const columns = 3;
|
|
12503
|
+
const remainder = items.length % columns;
|
|
12504
|
+
const fill = isLastPage && remainder > 0 ? columns - remainder : 0;
|
|
12505
|
+
const digits = Math.max(1, ...items.map((item) => `${item.number}`.length));
|
|
12506
|
+
const numberClassName = NUMBER_COLUMN_CLASS[Math.min(digits, 4) - 1];
|
|
12507
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12508
|
+
className: "grid grid-cols-3 gap-x-10 gap-y-11",
|
|
12509
|
+
children: [items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BangumiCell, {
|
|
12510
|
+
item,
|
|
12511
|
+
dark,
|
|
12512
|
+
numberClassName
|
|
12513
|
+
}, `${item.number}-${item.episode.bvid}`)), fill > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EndCard$1, {
|
|
12514
|
+
span: fill,
|
|
12515
|
+
listed,
|
|
12516
|
+
pageCount,
|
|
12517
|
+
mode
|
|
12518
|
+
})]
|
|
12160
12519
|
});
|
|
12161
12520
|
};
|
|
12521
|
+
/** 版权栏:左侧列出数量、UP 主与 season 号,右侧生成时间 */
|
|
12522
|
+
var Colophon$1 = ({ notes }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("footer", {
|
|
12523
|
+
className: "flex items-start justify-between gap-10 pt-7 text-[24px] leading-relaxed text-foreground/65",
|
|
12524
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12525
|
+
className: "min-w-0",
|
|
12526
|
+
children: notes.join(" · ")
|
|
12527
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12528
|
+
className: "shrink-0 select-text",
|
|
12529
|
+
children: ["图片生成于: ", format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss")]
|
|
12530
|
+
})]
|
|
12531
|
+
});
|
|
12162
12532
|
var BangumiBilibili = import_react.memo((props) => {
|
|
12163
|
-
|
|
12533
|
+
const { data, ctx } = props;
|
|
12534
|
+
const dark = isDark(ctx);
|
|
12535
|
+
const total = data.length > 0 ? data.length : data.Episodes.length;
|
|
12536
|
+
const numbered = data.Episodes.map((episode, index) => ({
|
|
12537
|
+
episode,
|
|
12538
|
+
number: episode.episode ?? total - index
|
|
12539
|
+
}));
|
|
12540
|
+
const pageSize = Math.max(1, data.posterPageSize ?? DEFAULT_POSTER_PAGE_SIZE$1);
|
|
12541
|
+
const pageCount = Math.max(1, Math.ceil(numbered.length / pageSize));
|
|
12542
|
+
const page = Math.min(Math.max(1, data.posterPage ?? 1), pageCount);
|
|
12543
|
+
const visible = numbered.slice((page - 1) * pageSize, page * pageSize);
|
|
12544
|
+
const mode = data.selectionMode ?? "text";
|
|
12545
|
+
const seconds = data.timeoutSeconds && data.timeoutSeconds > 0 ? data.timeoutSeconds : DEFAULT_TIMEOUT_SECONDS$1;
|
|
12546
|
+
const follow = parseFollowText(data.Stat.follow_text) ?? {
|
|
12547
|
+
...splitCount$1(data.Stat.favorites),
|
|
12548
|
+
label: "追番"
|
|
12549
|
+
};
|
|
12550
|
+
const ledger = [
|
|
12551
|
+
{
|
|
12552
|
+
label: "播放",
|
|
12553
|
+
...splitCount$1(data.Stat.views)
|
|
12554
|
+
},
|
|
12555
|
+
{
|
|
12556
|
+
label: follow.label,
|
|
12557
|
+
value: follow.value,
|
|
12558
|
+
unit: follow.unit
|
|
12559
|
+
},
|
|
12560
|
+
{
|
|
12561
|
+
label: "弹幕",
|
|
12562
|
+
...splitCount$1(data.Stat.danmakus)
|
|
12563
|
+
},
|
|
12564
|
+
{
|
|
12565
|
+
label: "投币",
|
|
12566
|
+
...splitCount$1(data.Stat.coins)
|
|
12567
|
+
}
|
|
12568
|
+
];
|
|
12569
|
+
const notes = [
|
|
12570
|
+
`已列出 ${numbered.length} 集`,
|
|
12571
|
+
`UP 主 ${data.UPInfo.uname} · 粉丝 ${Object.values(splitCount$1(data.UPInfo.follower)).join("")}`,
|
|
12572
|
+
...data.seasonID ? [`ss${data.seasonID}`] : []
|
|
12573
|
+
];
|
|
12574
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DefaultLayout, {
|
|
12164
12575
|
...props,
|
|
12165
|
-
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
|
|
12172
|
-
|
|
12173
|
-
|
|
12174
|
-
|
|
12175
|
-
|
|
12176
|
-
|
|
12177
|
-
|
|
12178
|
-
|
|
12179
|
-
|
|
12576
|
+
className: "relative overflow-hidden",
|
|
12577
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PosterBackground$1, {
|
|
12578
|
+
src: data.mainCover,
|
|
12579
|
+
ctx
|
|
12580
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
12581
|
+
className: "relative z-10 px-20 pt-18",
|
|
12582
|
+
children: [
|
|
12583
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Masthead$1, {
|
|
12584
|
+
label: "BILIBILI BANGUMI · EPISODE GUIDE",
|
|
12585
|
+
ctx
|
|
12586
|
+
}),
|
|
12587
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12588
|
+
className: "mt-12",
|
|
12589
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Hero$1, { data })
|
|
12590
|
+
}),
|
|
12591
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12592
|
+
className: "mt-12",
|
|
12593
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Ledger$1, { items: ledger })
|
|
12594
|
+
}),
|
|
12595
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12596
|
+
className: "mt-16",
|
|
12597
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Contents$1, {
|
|
12598
|
+
items: visible,
|
|
12599
|
+
page,
|
|
12600
|
+
pageCount,
|
|
12601
|
+
mode,
|
|
12602
|
+
seconds
|
|
12603
|
+
})
|
|
12604
|
+
}),
|
|
12605
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12606
|
+
className: "mt-12",
|
|
12607
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EpisodeGrid$1, {
|
|
12608
|
+
items: visible,
|
|
12609
|
+
dark,
|
|
12610
|
+
isLastPage: page === pageCount,
|
|
12611
|
+
pageCount,
|
|
12612
|
+
listed: numbered.length,
|
|
12613
|
+
mode
|
|
12614
|
+
})
|
|
12615
|
+
}),
|
|
12616
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12617
|
+
className: "mt-14",
|
|
12618
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Colophon$1, { notes })
|
|
12619
|
+
})
|
|
12620
|
+
]
|
|
12621
|
+
})]
|
|
12180
12622
|
});
|
|
12181
12623
|
});
|
|
12182
12624
|
BangumiBilibili.displayName = "BangumiBilibili";
|
|
@@ -14634,43 +15076,6 @@ var DYNAMIC_TYPE_FORWARD_default = defineTemplate({
|
|
|
14634
15076
|
component: BilibiliForwardDynamic,
|
|
14635
15077
|
validate: (data) => typeof data === "object" && data !== null && typeof data.share_url === "string"
|
|
14636
15078
|
});
|
|
14637
|
-
/** 主题色压色罩不透明度 (0~1):edge 为顶/底两端,middle 为中间带;调小 middle 封面色更透 */
|
|
14638
|
-
var AMBIENT_OVERLAY_OPACITY = {
|
|
14639
|
-
edge: .9,
|
|
14640
|
-
middle: .2
|
|
14641
|
-
};
|
|
14642
|
-
/** 用 color-mix 生成三段压色渐变(0% / 50% / 100% 停靠点对应 edge / middle / edge) */
|
|
14643
|
-
var overlayGradient = (color, edge, middle) => `linear-gradient(to bottom, color-mix(in oklab, ${color} ${edge * 100}%, transparent), color-mix(in oklab, ${color} ${middle * 100}%, transparent), color-mix(in oklab, ${color} ${edge * 100}%, transparent))`;
|
|
14644
|
-
/**
|
|
14645
|
-
* 氛围背景基础层:高斯模糊封面 + 主题色压色罩。
|
|
14646
|
-
* 压色罩浅色用主题背景色、深色用纯黑(两个层按 dark 变体显隐),
|
|
14647
|
-
* 各模板在此之上再叠加自己的杂色纹理层。
|
|
14648
|
-
* 贡献度参数优先取 ctx.ambientCover(core 注入的用户配置),缺省用模块内默认值。
|
|
14649
|
-
*/
|
|
14650
|
-
var AmbientCover = import_react.memo(({ src, ctx }) => {
|
|
14651
|
-
const coverOpacity = ctx?.ambientCover?.coverOpacity ?? .7;
|
|
14652
|
-
const edge = ctx?.ambientCover?.overlayEdgeOpacity ?? AMBIENT_OVERLAY_OPACITY.edge;
|
|
14653
|
-
const middle = ctx?.ambientCover?.overlayMiddleOpacity ?? AMBIENT_OVERLAY_OPACITY.middle;
|
|
14654
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
14655
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
|
|
14656
|
-
src,
|
|
14657
|
-
alt: "",
|
|
14658
|
-
className: "absolute inset-0 h-full w-full scale-150 object-cover blur-[120px] saturate-[1.8]",
|
|
14659
|
-
style: { opacity: coverOpacity },
|
|
14660
|
-
referrerPolicy: "no-referrer",
|
|
14661
|
-
crossOrigin: "anonymous"
|
|
14662
|
-
}),
|
|
14663
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
14664
|
-
className: "absolute inset-0 dark:hidden",
|
|
14665
|
-
style: { background: overlayGradient("var(--background)", edge, middle) }
|
|
14666
|
-
}),
|
|
14667
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
14668
|
-
className: "absolute inset-0 hidden dark:block",
|
|
14669
|
-
style: { background: overlayGradient("#000", edge, middle) }
|
|
14670
|
-
})
|
|
14671
|
-
] });
|
|
14672
|
-
});
|
|
14673
|
-
AmbientCover.displayName = "AmbientCover";
|
|
14674
15079
|
//#endregion
|
|
14675
15080
|
//#region ktr/template/bilibili/dynamic/DYNAMIC_TYPE_LIVE_RCMD/components/DYNAMIC_TYPE_LIVE_RCMD.tsx
|
|
14676
15081
|
/** B站品牌粉,直播状态徽章 / 脉冲灯 / 均衡器强调条统一使用,与封面取色无关。 */
|
|
@@ -18537,22 +18942,41 @@ var live_default = defineTemplate({
|
|
|
18537
18942
|
//#region ktr/template/douyin/mix/components/Mix.tsx
|
|
18538
18943
|
/** 海报每页展示的集数,和 core 的 EPISODE_SELECTION_PAGE_SIZE 保持一致 */
|
|
18539
18944
|
var DEFAULT_POSTER_PAGE_SIZE = 15;
|
|
18540
|
-
/**
|
|
18945
|
+
/** 选集有效期兜底(秒),正常由 data.timeoutSeconds 下发 */
|
|
18946
|
+
var DEFAULT_TIMEOUT_SECONDS = 120;
|
|
18947
|
+
/** QQBot 键盘每行的数字按钮数,和 core 的 EPISODE_SELECTION_BUTTONS_PER_ROW 保持一致 */
|
|
18948
|
+
var KEYS_PER_ROW = 5;
|
|
18949
|
+
/** 抖音红:眉题、章节方块等装饰的唯一强调色 */
|
|
18950
|
+
var ACCENT = "#FE2C55";
|
|
18951
|
+
/** 命令 chip 底色:同色相压深一档,白字对比度约 4.8:1 */
|
|
18952
|
+
var CHIP_BG = "#E0144C";
|
|
18953
|
+
/** 网格补位块的跨列类名(Tailwind 只认静态字面量) */
|
|
18954
|
+
var COL_SPAN = {
|
|
18955
|
+
1: "col-span-1",
|
|
18956
|
+
2: "col-span-2",
|
|
18957
|
+
3: "col-span-3",
|
|
18958
|
+
4: "col-span-4"
|
|
18959
|
+
};
|
|
18960
|
+
/** 万/亿 计数拆成数值与单位:10 亿以下的亿级两位小数,其余一位,去掉末尾 0(596.0万 → 596万);不足 1 万原样返回 */
|
|
18541
18961
|
var splitCount = (count) => {
|
|
18962
|
+
if (count >= 1e9) return {
|
|
18963
|
+
value: `${Number((count / 1e8).toFixed(1))}`,
|
|
18964
|
+
unit: "亿"
|
|
18965
|
+
};
|
|
18542
18966
|
if (count >= 1e8) return {
|
|
18543
|
-
value: (count / 1e8).toFixed(
|
|
18967
|
+
value: `${Number((count / 1e8).toFixed(2))}`,
|
|
18544
18968
|
unit: "亿"
|
|
18545
18969
|
};
|
|
18546
18970
|
if (count >= 1e4) return {
|
|
18547
|
-
value: (count / 1e4).toFixed(1)
|
|
18971
|
+
value: `${Number((count / 1e4).toFixed(1))}`,
|
|
18548
18972
|
unit: "万"
|
|
18549
18973
|
};
|
|
18550
18974
|
return {
|
|
18551
|
-
value: count.toString(),
|
|
18975
|
+
value: Math.max(0, Math.round(count)).toString(),
|
|
18552
18976
|
unit: ""
|
|
18553
18977
|
};
|
|
18554
18978
|
};
|
|
18555
|
-
/**
|
|
18979
|
+
/** 总时长:不到一小时按分钟,否则按小时保留一位,去掉末尾 0 */
|
|
18556
18980
|
var splitRuntime = (milliseconds) => {
|
|
18557
18981
|
const minutes = Math.round(milliseconds / 6e4);
|
|
18558
18982
|
if (minutes < 60) return {
|
|
@@ -18560,29 +18984,56 @@ var splitRuntime = (milliseconds) => {
|
|
|
18560
18984
|
unit: "分钟"
|
|
18561
18985
|
};
|
|
18562
18986
|
return {
|
|
18563
|
-
value: (minutes / 60).toFixed(1)
|
|
18987
|
+
value: `${Number((minutes / 60).toFixed(1))}`,
|
|
18564
18988
|
unit: "小时"
|
|
18565
18989
|
};
|
|
18566
18990
|
};
|
|
18567
|
-
/** 单集时长 mm:ss */
|
|
18991
|
+
/** 单集时长 m:ss,超过一小时 h:mm:ss */
|
|
18568
18992
|
var formatDuration$4 = (milliseconds) => {
|
|
18569
|
-
const
|
|
18570
|
-
const
|
|
18571
|
-
const
|
|
18572
|
-
|
|
18993
|
+
const total = Math.max(0, Math.round(milliseconds / 1e3));
|
|
18994
|
+
const h = Math.floor(total / 3600);
|
|
18995
|
+
const m = Math.floor(total % 3600 / 60);
|
|
18996
|
+
const s = (total % 60).toString().padStart(2, "0");
|
|
18997
|
+
return h > 0 ? `${h}:${m.toString().padStart(2, "0")}:${s}` : `${m}:${s}`;
|
|
18573
18998
|
};
|
|
18574
|
-
/**
|
|
18575
|
-
var
|
|
18576
|
-
|
|
18577
|
-
|
|
18578
|
-
|
|
18579
|
-
|
|
18580
|
-
|
|
18581
|
-
|
|
18582
|
-
|
|
18999
|
+
/** 缺集说明最多列出的段数,超出折成「等 N 集」 */
|
|
19000
|
+
var MISSING_SEGMENT_LIMIT = 8;
|
|
19001
|
+
/**
|
|
19002
|
+
* 把升序集号写成「17、94、99–230 集」:连续 3 个及以上压成区间,两个相邻的照常列出;
|
|
19003
|
+
* 段数超过上限时只列前几段,后面接「等 N 集」,N 是全部缺集数。
|
|
19004
|
+
*/
|
|
19005
|
+
var formatMissing = (numbers, unit) => {
|
|
19006
|
+
const parts = [];
|
|
19007
|
+
let index = 0;
|
|
19008
|
+
while (index < numbers.length) {
|
|
19009
|
+
let end = index;
|
|
19010
|
+
while (end + 1 < numbers.length && numbers[end + 1] === numbers[end] + 1) end++;
|
|
19011
|
+
if (end - index >= 2) parts.push(`${numbers[index]}–${numbers[end]}`);
|
|
19012
|
+
else parts.push(...numbers.slice(index, end + 1).map(String));
|
|
19013
|
+
index = end + 1;
|
|
19014
|
+
}
|
|
19015
|
+
if (parts.length <= MISSING_SEGMENT_LIMIT) return `第 ${parts.join("、")} ${unit}`;
|
|
19016
|
+
return `第 ${parts.slice(0, MISSING_SEGMENT_LIMIT).join("、")} 等 ${numbers.length} ${unit}`;
|
|
19017
|
+
};
|
|
19018
|
+
/** 按展示顺序(最新在前)写区间;只有一集时写「第 a 集」 */
|
|
19019
|
+
var formatEpisodeRange = (first, last) => first === last ? `第 ${first} 集` : `第 ${first}–${last} 集`;
|
|
19020
|
+
/** 标题按字数分档:短标题撑满版面,长标题收字号换行 */
|
|
19021
|
+
var getTitleClassName$1 = (length) => {
|
|
19022
|
+
if (length <= 6) return "text-[132px] leading-[1.05]";
|
|
19023
|
+
if (length <= 10) return "text-[112px] leading-[1.08]";
|
|
19024
|
+
if (length <= 16) return "text-[96px] leading-[1.1] line-clamp-2";
|
|
19025
|
+
if (length <= 24) return "text-[80px] leading-[1.14] line-clamp-2";
|
|
19026
|
+
return "text-[68px] leading-[1.18] line-clamp-3";
|
|
19027
|
+
};
|
|
19028
|
+
/** 巨型区间数字的字宽系数(字号的倍数,含 -0.04em 字距),按 tabular 数字和短横线的实测宽度取上限 */
|
|
19029
|
+
var RANGE_NUMERAL_ADVANCE = .56;
|
|
19030
|
+
/** 目录页巨型区间数字的字号:按左栏内容宽度和字符数反推,最大 184px,4 位集号的长区间也不会溢出 */
|
|
19031
|
+
var getRangeNumeralSize = (length, compact) => Math.min(184, Math.floor((compact ? 448 : 520) / (Math.max(length, 1) * RANGE_NUMERAL_ADVANCE)));
|
|
19032
|
+
/** 背景:封面弥散 + 离散噪点,与兄弟模板同一套图层 */
|
|
19033
|
+
var PosterBackground = ({ src, ctx }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18583
19034
|
className: "pointer-events-none absolute inset-0 overflow-hidden select-none",
|
|
18584
19035
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AmbientCover, {
|
|
18585
|
-
src
|
|
19036
|
+
src,
|
|
18586
19037
|
ctx
|
|
18587
19038
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
18588
19039
|
className: "absolute inset-0 opacity-[0.35] mix-blend-overlay dark:mix-blend-soft-light",
|
|
@@ -18631,312 +19082,555 @@ var MixBackground = ({ data, ctx }) => /* @__PURE__ */ (0, import_jsx_runtime.js
|
|
|
18631
19082
|
})
|
|
18632
19083
|
})]
|
|
18633
19084
|
});
|
|
18634
|
-
|
|
18635
|
-
|
|
19085
|
+
/** 刊头:栏目名 + 平台 logo,靠字距和留白收束 */
|
|
19086
|
+
var Masthead = ({ label, ctx }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
|
|
19087
|
+
className: "flex items-center justify-between pb-7",
|
|
18636
19088
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18637
|
-
className: "flex items-center gap-
|
|
18638
|
-
children: [
|
|
18639
|
-
|
|
18640
|
-
|
|
18641
|
-
|
|
18642
|
-
children: "Douyin Mix"
|
|
18643
|
-
}),
|
|
18644
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
18645
|
-
className: "text-[26px] font-bold text-muted",
|
|
18646
|
-
children: "· 合集选集"
|
|
18647
|
-
})
|
|
18648
|
-
]
|
|
19089
|
+
className: "flex items-center gap-5 text-[26px] font-bold tracking-[0.32em] text-foreground",
|
|
19090
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19091
|
+
className: "h-5 w-5",
|
|
19092
|
+
style: { backgroundColor: ACCENT }
|
|
19093
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: label })]
|
|
18649
19094
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
|
|
18650
19095
|
src: isDark(ctx) ? "/image/douyin/dylogo-light.svg" : "/image/douyin/dylogo-dark.svg",
|
|
18651
19096
|
alt: "抖音",
|
|
18652
|
-
className: "h-
|
|
19097
|
+
className: "h-14 w-auto"
|
|
18653
19098
|
})]
|
|
18654
19099
|
});
|
|
18655
|
-
|
|
18656
|
-
|
|
18657
|
-
|
|
18658
|
-
|
|
18659
|
-
|
|
18660
|
-
|
|
18661
|
-
|
|
18662
|
-
|
|
18663
|
-
|
|
18664
|
-
|
|
18665
|
-
|
|
18666
|
-
|
|
18667
|
-
|
|
18668
|
-
|
|
18669
|
-
|
|
18670
|
-
|
|
18671
|
-
|
|
18672
|
-
|
|
18673
|
-
|
|
18674
|
-
|
|
18675
|
-
{
|
|
18676
|
-
|
|
18677
|
-
|
|
18678
|
-
|
|
18679
|
-
|
|
18680
|
-
|
|
18681
|
-
|
|
18682
|
-
|
|
18683
|
-
|
|
19100
|
+
/** 眉题:强调色小号粗体,用细点分隔 */
|
|
19101
|
+
var Kicker = ({ items }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19102
|
+
className: "flex flex-wrap items-center gap-x-4 text-[30px] font-bold",
|
|
19103
|
+
style: { color: ACCENT },
|
|
19104
|
+
children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.Fragment, { children: [index > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19105
|
+
className: "text-muted",
|
|
19106
|
+
children: "·"
|
|
19107
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: item })] }, `${index}-${item}`))
|
|
19108
|
+
});
|
|
19109
|
+
/** 数据栏:四格铺在浅色面板上,用留白代替分隔线,小标签 + 粗体大数字 + 小单位 */
|
|
19110
|
+
var Ledger = ({ items }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19111
|
+
className: "grid grid-cols-4 gap-x-10 rounded-3xl bg-foreground/5 px-10 py-8",
|
|
19112
|
+
children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19113
|
+
className: "text-[24px] font-medium text-foreground/65",
|
|
19114
|
+
children: item.label
|
|
19115
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19116
|
+
className: "mt-1 flex items-baseline gap-1.5 text-foreground",
|
|
19117
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19118
|
+
className: "text-[60px] leading-none font-black tabular-nums",
|
|
19119
|
+
children: item.value
|
|
19120
|
+
}), item.unit && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19121
|
+
className: "text-[26px] font-bold",
|
|
19122
|
+
children: item.unit
|
|
19123
|
+
})]
|
|
19124
|
+
})] }, item.label))
|
|
19125
|
+
});
|
|
19126
|
+
/** 署名行:头像 + 作者名 + 认证 + 次要信息 */
|
|
19127
|
+
var Byline = ({ avatar, name, verified, meta }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19128
|
+
className: "flex items-center gap-5",
|
|
19129
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19130
|
+
className: "h-19 w-19 shrink-0 overflow-hidden rounded-full ring-2 ring-foreground/10",
|
|
19131
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
19132
|
+
src: avatar,
|
|
19133
|
+
alt: name,
|
|
19134
|
+
className: "h-full w-full object-cover",
|
|
19135
|
+
isCircular: true
|
|
19136
|
+
})
|
|
19137
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19138
|
+
className: "min-w-0",
|
|
18684
19139
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18685
|
-
className:
|
|
18686
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("
|
|
18687
|
-
|
|
18688
|
-
|
|
18689
|
-
|
|
18690
|
-
className: "
|
|
18691
|
-
|
|
18692
|
-
crossOrigin: "anonymous"
|
|
18693
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
|
|
18694
|
-
src: image_url,
|
|
18695
|
-
alt: "合集海报",
|
|
18696
|
-
className: "relative h-full w-full rounded-[40px] object-cover shadow-2xl",
|
|
18697
|
-
referrerPolicy: "no-referrer",
|
|
18698
|
-
crossOrigin: "anonymous"
|
|
19140
|
+
className: "flex items-center gap-2",
|
|
19141
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19142
|
+
className: "truncate text-[34px] font-bold text-foreground",
|
|
19143
|
+
children: name
|
|
19144
|
+
}), verified && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RiVerifiedBadgeFill, {
|
|
19145
|
+
className: "h-8 w-8 shrink-0",
|
|
19146
|
+
style: { color: ACCENT }
|
|
18699
19147
|
})]
|
|
19148
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19149
|
+
className: "mt-0.5 text-[24px] text-foreground/65",
|
|
19150
|
+
children: meta
|
|
19151
|
+
})]
|
|
19152
|
+
})]
|
|
19153
|
+
});
|
|
19154
|
+
/** 专题 hero:左封面,右眉题 / 大标题 / 导语 / 署名 */
|
|
19155
|
+
var Hero = ({ data }) => {
|
|
19156
|
+
const isPlaylet = data.kind === "playlet";
|
|
19157
|
+
const total = data.total_episode;
|
|
19158
|
+
const updated = data.updated_to_episode;
|
|
19159
|
+
const kicker = isPlaylet ? ["短剧", ...total > 0 && updated < total ? [`共 ${total} 集`, `更新至第 ${updated} 集`] : total > 0 ? [`全 ${total} 集`, "已完结"] : []] : ["合集", ...total > 0 ? [`共 ${total} 个视频`] : []];
|
|
19160
|
+
const authorMeta = [data.author.short_id ? `抖音号 ${data.author.short_id}` : "", `粉丝 ${Object.values(splitCount(data.author.follower_count)).join("")}`].filter(Boolean).join(" · ");
|
|
19161
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19162
|
+
className: "flex items-stretch gap-16",
|
|
19163
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19164
|
+
className: isPlaylet ? "relative min-h-150 w-100 shrink-0 overflow-hidden rounded-8xl bg-surface-secondary shadow-2xl shadow-black/20" : "relative min-h-100 w-100 shrink-0 overflow-hidden rounded-8xl bg-surface-secondary shadow-2xl shadow-black/20",
|
|
19165
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19166
|
+
className: "absolute inset-0",
|
|
19167
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
19168
|
+
src: data.image_url,
|
|
19169
|
+
alt: data.mix_name,
|
|
19170
|
+
className: "h-full w-full object-cover"
|
|
19171
|
+
})
|
|
19172
|
+
})
|
|
18700
19173
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18701
|
-
className: "flex min-w-0 flex-1 flex-col
|
|
18702
|
-
children: [
|
|
19174
|
+
className: "flex min-w-0 flex-1 flex-col",
|
|
19175
|
+
children: [
|
|
19176
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Kicker, { items: kicker }),
|
|
18703
19177
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
|
|
18704
|
-
className:
|
|
18705
|
-
|
|
18706
|
-
wordBreak: "break-word",
|
|
18707
|
-
overflowWrap: "break-word"
|
|
18708
|
-
},
|
|
18709
|
-
children: mix_name
|
|
19178
|
+
className: `mt-5 font-black tracking-tight text-balance text-foreground ${getTitleClassName$1(data.mix_name.length)}`,
|
|
19179
|
+
children: data.mix_name
|
|
18710
19180
|
}),
|
|
18711
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
18712
|
-
className:
|
|
18713
|
-
children:
|
|
18714
|
-
className: "rounded-full bg-foreground px-7 py-3 text-[30px] font-bold leading-none text-background",
|
|
18715
|
-
children: [
|
|
18716
|
-
"共 ",
|
|
18717
|
-
total_episode,
|
|
18718
|
-
" ",
|
|
18719
|
-
countUnit
|
|
18720
|
-
]
|
|
18721
|
-
}), updated_to_episode < total_episode && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
18722
|
-
className: "rounded-full border border-foreground/20 px-7 py-3 text-[30px] font-semibold leading-none text-foreground/80",
|
|
18723
|
-
children: [
|
|
18724
|
-
"更新至第 ",
|
|
18725
|
-
updated_to_episode,
|
|
18726
|
-
" 集"
|
|
18727
|
-
]
|
|
18728
|
-
})]
|
|
19181
|
+
data.desc && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
19182
|
+
className: `mt-7 text-[32px] leading-[1.6] font-light text-foreground/80 ${isPlaylet ? "line-clamp-4" : "line-clamp-2"}`,
|
|
19183
|
+
children: data.desc
|
|
18729
19184
|
}),
|
|
18730
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
18731
|
-
className: "mt-
|
|
18732
|
-
children:
|
|
18733
|
-
|
|
18734
|
-
|
|
18735
|
-
|
|
18736
|
-
|
|
18737
|
-
|
|
18738
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18739
|
-
className: "min-w-0",
|
|
18740
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18741
|
-
className: "flex min-w-0 items-center gap-2",
|
|
18742
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
18743
|
-
className: "truncate text-[38px] font-bold leading-tight text-foreground select-text",
|
|
18744
|
-
children: author.nickname
|
|
18745
|
-
}), author.verified && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RiVerifiedBadgeFill, {
|
|
18746
|
-
size: 34,
|
|
18747
|
-
className: "shrink-0 text-foreground/70"
|
|
18748
|
-
})]
|
|
18749
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18750
|
-
className: "mt-1 truncate text-[26px] text-muted select-text",
|
|
18751
|
-
children: [
|
|
18752
|
-
"抖音号 ",
|
|
18753
|
-
author.short_id,
|
|
18754
|
-
" · 粉丝 ",
|
|
18755
|
-
follower.value,
|
|
18756
|
-
follower.unit
|
|
18757
|
-
]
|
|
18758
|
-
})]
|
|
18759
|
-
})]
|
|
18760
|
-
})
|
|
18761
|
-
] }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
18762
|
-
className: "grid grid-cols-2 gap-x-10 gap-y-8",
|
|
18763
|
-
children: stats.map((stat) => {
|
|
18764
|
-
const Icon = stat.icon;
|
|
18765
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18766
|
-
className: "min-w-0",
|
|
18767
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18768
|
-
className: "flex items-center gap-3 text-[28px] font-semibold text-muted",
|
|
18769
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, {
|
|
18770
|
-
size: 32,
|
|
18771
|
-
weight: "fill",
|
|
18772
|
-
className: "text-foreground/80"
|
|
18773
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: stat.label })]
|
|
18774
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18775
|
-
className: "mt-2 flex items-baseline gap-2 text-foreground select-text",
|
|
18776
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
18777
|
-
className: "text-[64px] font-semibold leading-none tabular-nums",
|
|
18778
|
-
children: stat.value
|
|
18779
|
-
}), stat.unit && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
18780
|
-
className: "text-[28px] font-bold",
|
|
18781
|
-
children: stat.unit
|
|
18782
|
-
})]
|
|
18783
|
-
})]
|
|
18784
|
-
}, stat.label);
|
|
19185
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19186
|
+
className: "mt-auto pt-18",
|
|
19187
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Byline, {
|
|
19188
|
+
avatar: data.author.avatar,
|
|
19189
|
+
name: data.author.nickname,
|
|
19190
|
+
verified: data.author.verified,
|
|
19191
|
+
meta: authorMeta
|
|
19192
|
+
})
|
|
18785
19193
|
})
|
|
18786
|
-
|
|
18787
|
-
})]
|
|
18788
|
-
});
|
|
18789
|
-
};
|
|
18790
|
-
/** 区块标题:竖条 + 标题 */
|
|
18791
|
-
var SectionTitle$1 = ({ children, extra }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18792
|
-
className: "flex items-end justify-between gap-8",
|
|
18793
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18794
|
-
className: "flex items-center gap-4",
|
|
18795
|
-
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", {
|
|
18796
|
-
className: "text-[44px] font-bold leading-none text-foreground",
|
|
18797
|
-
children
|
|
18798
|
-
})]
|
|
18799
|
-
}), extra]
|
|
18800
|
-
});
|
|
18801
|
-
var MixSynopsis = ({ data }) => {
|
|
18802
|
-
if (!data.desc) return null;
|
|
18803
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
18804
|
-
className: "mt-16",
|
|
18805
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionTitle$1, { children: "简介" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
18806
|
-
className: "mt-6 line-clamp-5 text-[40px] leading-[1.6] text-foreground/85 select-text",
|
|
18807
|
-
style: { overflowWrap: "break-word" },
|
|
18808
|
-
children: data.desc
|
|
19194
|
+
]
|
|
18809
19195
|
})]
|
|
18810
19196
|
});
|
|
18811
19197
|
};
|
|
18812
|
-
/**
|
|
19198
|
+
/** 可执行命令:统一实心高对比 chip */
|
|
18813
19199
|
var CommandChip = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
18814
|
-
className: "inline-flex items-center rounded-
|
|
19200
|
+
className: "inline-flex h-15 items-center rounded-2xl px-6 text-[30px] font-bold whitespace-nowrap text-white shadow-lg shadow-black/15",
|
|
19201
|
+
style: { backgroundColor: CHIP_BG },
|
|
18815
19202
|
children
|
|
18816
19203
|
});
|
|
18817
|
-
|
|
18818
|
-
|
|
18819
|
-
|
|
18820
|
-
|
|
18821
|
-
|
|
18822
|
-
|
|
18823
|
-
|
|
18824
|
-
|
|
18825
|
-
const firstEpisode = visibleEpisodes[0].episode;
|
|
18826
|
-
const lastEpisode = visibleEpisodes[visibleEpisodes.length - 1].episode;
|
|
18827
|
-
const range = firstEpisode === lastEpisode ? `第 ${firstEpisode} 集` : `第 ${firstEpisode}–${lastEpisode} 集`;
|
|
18828
|
-
const countUnit = kind === "collection" ? "个视频" : "集";
|
|
18829
|
-
const maxEpisode = episodes.reduce((max, item) => Math.max(max, item.episode), 0);
|
|
18830
|
-
const episodeSet = new Set(episodes.map((item) => item.episode));
|
|
18831
|
-
const missingEpisodes = [];
|
|
18832
|
-
for (let episode = 1; episode <= Math.max(maxEpisode, updated_to_episode); episode++) if (!episodeSet.has(episode)) missingEpisodes.push(episode);
|
|
18833
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
18834
|
-
className: "mt-16",
|
|
19204
|
+
/** 有效期说明:两种模式共用;主句加粗,补充说明降一档。只有一页时没有翻页,不提重新计时 */
|
|
19205
|
+
var ValidityNote = ({ seconds, pageCount }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19206
|
+
className: "flex items-start gap-3 text-[26px] leading-snug",
|
|
19207
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Timer, {
|
|
19208
|
+
className: "mt-0.5 h-7 w-7 shrink-0 text-foreground/70",
|
|
19209
|
+
strokeWidth: 2.2
|
|
19210
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19211
|
+
className: "font-bold text-foreground",
|
|
18835
19212
|
children: [
|
|
18836
|
-
|
|
18837
|
-
|
|
18838
|
-
|
|
18839
|
-
|
|
19213
|
+
seconds,
|
|
19214
|
+
" 秒内有效",
|
|
19215
|
+
pageCount > 1 && ",翻页重新计时"
|
|
19216
|
+
]
|
|
19217
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19218
|
+
className: "mt-0.5 text-foreground/65",
|
|
19219
|
+
children: "过期请重新发送原链接"
|
|
19220
|
+
})] })]
|
|
19221
|
+
});
|
|
19222
|
+
/** 文字命令模式:只列出当前页真正能用的命令;后端也认纯数字集号,用本页第一集举例 */
|
|
19223
|
+
var TextGuide = ({ first, page, pageCount, seconds }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19224
|
+
className: "flex flex-col gap-5",
|
|
19225
|
+
children: [
|
|
19226
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19227
|
+
className: "text-[34px] font-black text-foreground",
|
|
19228
|
+
children: "回复文字选集"
|
|
19229
|
+
}),
|
|
19230
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19231
|
+
className: "flex items-center gap-5",
|
|
19232
|
+
children: [
|
|
19233
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19234
|
+
className: "w-19 shrink-0 text-[28px] font-bold text-foreground",
|
|
19235
|
+
children: "选集"
|
|
18840
19236
|
}),
|
|
18841
|
-
|
|
18842
|
-
|
|
18843
|
-
|
|
18844
|
-
|
|
18845
|
-
|
|
18846
|
-
|
|
18847
|
-
|
|
18848
|
-
|
|
18849
|
-
|
|
18850
|
-
|
|
18851
|
-
|
|
18852
|
-
|
|
18853
|
-
|
|
19237
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19238
|
+
className: "text-[26px] text-foreground/65",
|
|
19239
|
+
children: "发送"
|
|
19240
|
+
}),
|
|
19241
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip, { children: "第?集" }),
|
|
19242
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
19243
|
+
className: "text-[26px] text-foreground/65",
|
|
19244
|
+
children: ["也可只发集号,如 ", first]
|
|
19245
|
+
})
|
|
19246
|
+
]
|
|
19247
|
+
}),
|
|
19248
|
+
pageCount > 1 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19249
|
+
className: "flex items-center gap-5",
|
|
19250
|
+
children: [
|
|
19251
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19252
|
+
className: "w-19 shrink-0 text-[28px] font-bold text-foreground",
|
|
19253
|
+
children: "翻页"
|
|
19254
|
+
}),
|
|
19255
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19256
|
+
className: "text-[26px] text-foreground/65",
|
|
19257
|
+
children: "发送"
|
|
19258
|
+
}),
|
|
19259
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19260
|
+
className: "flex flex-wrap gap-3",
|
|
18854
19261
|
children: [
|
|
18855
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
18856
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip, { children: "
|
|
18857
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("
|
|
18858
|
-
className: "text-foreground/30",
|
|
18859
|
-
children: "/"
|
|
18860
|
-
}),
|
|
18861
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip, { children: "下一页" }),
|
|
18862
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
18863
|
-
className: "text-foreground/30",
|
|
18864
|
-
children: "/"
|
|
18865
|
-
}),
|
|
18866
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip, { children: "第?页" }),
|
|
18867
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "翻页" })
|
|
19262
|
+
page > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip, { children: "上一页" }),
|
|
19263
|
+
page < pageCount && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip, { children: "下一页" }),
|
|
19264
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip, { children: "第?页" })
|
|
18868
19265
|
]
|
|
18869
|
-
})]
|
|
18870
|
-
}),
|
|
18871
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
18872
|
-
className: "grid grid-cols-3 gap-8 mt-8",
|
|
18873
|
-
children: visibleEpisodes.map((episode) => {
|
|
18874
|
-
const cover = kind === "collection" ? episode.cover || episode.originCover : episode.originCover || episode.cover;
|
|
18875
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18876
|
-
className: "flex flex-col overflow-hidden bg-surface rounded-3xl shadow-large",
|
|
18877
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18878
|
-
className: `relative overflow-hidden ${kind === "collection" ? "aspect-square" : "aspect-[3/4]"}`,
|
|
18879
|
-
children: [
|
|
18880
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
18881
|
-
src: cover || "",
|
|
18882
|
-
alt: `第${episode.episode}集 ${episode.title}`,
|
|
18883
|
-
className: "object-cover w-full h-full select-text"
|
|
18884
|
-
}),
|
|
18885
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18886
|
-
className: "absolute top-4 left-4 px-3 py-1 text-2xl font-bold text-white rounded-xl bg-black/65",
|
|
18887
|
-
children: [
|
|
18888
|
-
"第",
|
|
18889
|
-
episode.episode,
|
|
18890
|
-
"集"
|
|
18891
|
-
]
|
|
18892
|
-
}),
|
|
18893
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
18894
|
-
className: "absolute right-4 bottom-4 px-3 py-1 text-xl font-semibold text-white rounded-xl bg-black/65 tabular-nums",
|
|
18895
|
-
children: formatDuration$4(episode.duration)
|
|
18896
|
-
})
|
|
18897
|
-
]
|
|
18898
|
-
}), kind === "collection" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
18899
|
-
className: "flex flex-col flex-1 gap-3 p-5",
|
|
18900
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
18901
|
-
className: "text-3xl font-semibold leading-snug select-text text-foreground line-clamp-2",
|
|
18902
|
-
children: episode.title || `第${episode.episode}集`
|
|
18903
|
-
})
|
|
18904
|
-
})]
|
|
18905
|
-
}, `${episode.episode}-${episode.aweme_id}`);
|
|
18906
19266
|
})
|
|
18907
|
-
|
|
18908
|
-
|
|
18909
|
-
|
|
18910
|
-
|
|
18911
|
-
|
|
18912
|
-
|
|
18913
|
-
|
|
18914
|
-
|
|
18915
|
-
|
|
18916
|
-
|
|
18917
|
-
|
|
18918
|
-
|
|
18919
|
-
|
|
18920
|
-
|
|
18921
|
-
|
|
18922
|
-
|
|
19267
|
+
]
|
|
19268
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19269
|
+
className: "flex items-center gap-5",
|
|
19270
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19271
|
+
className: "w-19 shrink-0 text-[28px] font-bold text-foreground",
|
|
19272
|
+
children: "翻页"
|
|
19273
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19274
|
+
className: "text-[26px] text-foreground/65",
|
|
19275
|
+
children: "只有这一页,无需翻页"
|
|
19276
|
+
})]
|
|
19277
|
+
}),
|
|
19278
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidityNote, {
|
|
19279
|
+
seconds,
|
|
19280
|
+
pageCount
|
|
19281
|
+
})
|
|
19282
|
+
]
|
|
19283
|
+
});
|
|
19284
|
+
/** 键盘示意里的一枚按钮:数字键与「跳转」是蓝框键(style 1),翻页是灰框键;small 给 4 位集号用 */
|
|
19285
|
+
var SketchKey = ({ children, quiet, small }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19286
|
+
className: quiet ? "flex h-11 flex-1 items-center justify-center rounded-lg border-2 border-foreground/20 text-[24px] font-bold text-foreground/60" : `flex h-11 flex-1 items-center justify-center rounded-lg border-2 border-foreground/45 font-bold text-foreground tabular-nums ${small ? "text-[18px]" : "text-[24px]"}`,
|
|
19287
|
+
children
|
|
19288
|
+
});
|
|
19289
|
+
/** 按钮模式的键盘示意:只画本页真实存在的按钮,排布与 QQBot 键盘一致;宽度固定,4 位集号收小字号,左侧说明不被挤到换行 */
|
|
19290
|
+
var KeySketch = ({ episodes, page, pageCount }) => {
|
|
19291
|
+
const rows = [];
|
|
19292
|
+
for (let index = 0; index < episodes.length; index += KEYS_PER_ROW) rows.push(episodes.slice(index, index + KEYS_PER_ROW));
|
|
19293
|
+
const navigation = [page > 1 ? "上一页" : "", page < pageCount ? "下一页" : ""].filter(Boolean);
|
|
19294
|
+
const small = episodes.some((episode) => episode >= 1e3);
|
|
19295
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19296
|
+
className: "flex w-82.5 shrink-0 flex-col gap-1.5 self-start rounded-3xl bg-surface/60 p-3",
|
|
19297
|
+
children: [
|
|
19298
|
+
pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SketchKey, { children: "跳转到第x页" }),
|
|
19299
|
+
rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19300
|
+
className: "flex gap-1.5",
|
|
19301
|
+
children: row.map((episode) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SketchKey, {
|
|
19302
|
+
small,
|
|
19303
|
+
children: episode
|
|
19304
|
+
}, episode))
|
|
19305
|
+
}, row[0])),
|
|
19306
|
+
navigation.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19307
|
+
className: "flex gap-1.5",
|
|
19308
|
+
children: navigation.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SketchKey, {
|
|
19309
|
+
quiet: true,
|
|
19310
|
+
children: label
|
|
19311
|
+
}, label))
|
|
18923
19312
|
})
|
|
18924
19313
|
]
|
|
18925
19314
|
});
|
|
18926
19315
|
};
|
|
18927
|
-
|
|
18928
|
-
|
|
18929
|
-
className: "
|
|
18930
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.
|
|
18931
|
-
className: "
|
|
19316
|
+
/** 按钮模式:引导点按钮,不出现任何手打命令 */
|
|
19317
|
+
var ButtonGuide = ({ episodes, page, pageCount, seconds }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19318
|
+
className: "flex gap-6",
|
|
19319
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19320
|
+
className: "flex min-w-0 flex-1 flex-col gap-4",
|
|
18932
19321
|
children: [
|
|
18933
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
18934
|
-
|
|
18935
|
-
|
|
18936
|
-
|
|
19322
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19323
|
+
className: "flex items-center gap-3 text-[34px] font-black text-foreground",
|
|
19324
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MousePointerClick, {
|
|
19325
|
+
className: "h-9 w-9 shrink-0",
|
|
19326
|
+
strokeWidth: 2.4,
|
|
19327
|
+
style: { color: ACCENT }
|
|
19328
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "点击下方按钮选集" })]
|
|
19329
|
+
}),
|
|
19330
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("ul", {
|
|
19331
|
+
className: "flex flex-col gap-2 text-[26px] leading-snug text-foreground/80",
|
|
19332
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: "数字键即集号,点一下直接解析" }), pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: "「跳转到第x页」补上页码再发送" })]
|
|
19333
|
+
}),
|
|
19334
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidityNote, {
|
|
19335
|
+
seconds,
|
|
19336
|
+
pageCount
|
|
19337
|
+
})
|
|
18937
19338
|
]
|
|
19339
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(KeySketch, {
|
|
19340
|
+
episodes,
|
|
19341
|
+
page,
|
|
19342
|
+
pageCount
|
|
18938
19343
|
})]
|
|
18939
|
-
})
|
|
19344
|
+
});
|
|
19345
|
+
/** 目录页开篇:巨型区间数字 + 操作说明 */
|
|
19346
|
+
var Contents = ({ episodes, missingNote, page, pageCount, mode, seconds }) => {
|
|
19347
|
+
const first = episodes[0]?.episode ?? 0;
|
|
19348
|
+
const last = episodes[episodes.length - 1]?.episode ?? 0;
|
|
19349
|
+
const numeral = first === last ? `${first}` : `${first}–${last}`;
|
|
19350
|
+
const compact = mode === "button";
|
|
19351
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19352
|
+
className: "flex items-end justify-between",
|
|
19353
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19354
|
+
className: "flex items-baseline gap-5",
|
|
19355
|
+
children: [
|
|
19356
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19357
|
+
className: "h-6 w-6 self-center",
|
|
19358
|
+
style: { backgroundColor: ACCENT }
|
|
19359
|
+
}),
|
|
19360
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
|
|
19361
|
+
className: "text-[72px] leading-none font-black text-foreground",
|
|
19362
|
+
children: "选集"
|
|
19363
|
+
}),
|
|
19364
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19365
|
+
className: "text-[24px] font-bold tracking-[0.3em] text-foreground/55",
|
|
19366
|
+
children: "CONTENTS"
|
|
19367
|
+
})
|
|
19368
|
+
]
|
|
19369
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19370
|
+
className: "rounded-full bg-foreground/10 px-7 py-2 text-[34px] font-bold text-foreground tabular-nums",
|
|
19371
|
+
children: [
|
|
19372
|
+
"第 ",
|
|
19373
|
+
page,
|
|
19374
|
+
" / ",
|
|
19375
|
+
pageCount,
|
|
19376
|
+
" 页"
|
|
19377
|
+
]
|
|
19378
|
+
})]
|
|
19379
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19380
|
+
className: "mt-8 flex items-stretch",
|
|
19381
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19382
|
+
className: compact ? "w-120 shrink-0 pr-8" : "w-140 shrink-0 pr-10",
|
|
19383
|
+
children: [
|
|
19384
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19385
|
+
className: "leading-[0.84] font-light tracking-[-0.04em] whitespace-nowrap text-foreground tabular-nums",
|
|
19386
|
+
style: { fontSize: getRangeNumeralSize(numeral.length, compact) },
|
|
19387
|
+
children: numeral
|
|
19388
|
+
}),
|
|
19389
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19390
|
+
className: "mt-6 text-[30px] leading-snug font-bold text-foreground",
|
|
19391
|
+
children: formatEpisodeRange(first, last)
|
|
19392
|
+
}),
|
|
19393
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19394
|
+
className: "mt-1 flex items-center gap-2.5 text-[28px] font-bold text-foreground",
|
|
19395
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowDownWideNarrow, {
|
|
19396
|
+
className: "h-8 w-8 shrink-0",
|
|
19397
|
+
strokeWidth: 2.4,
|
|
19398
|
+
style: { color: ACCENT }
|
|
19399
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "最新在前" })]
|
|
19400
|
+
}),
|
|
19401
|
+
missingNote && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19402
|
+
className: "mt-2 text-[26px] leading-snug text-foreground/65",
|
|
19403
|
+
children: missingNote
|
|
19404
|
+
})
|
|
19405
|
+
]
|
|
19406
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19407
|
+
className: "min-w-0 flex-1 pl-10",
|
|
19408
|
+
children: mode === "button" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ButtonGuide, {
|
|
19409
|
+
episodes: episodes.map((episode) => episode.episode),
|
|
19410
|
+
page,
|
|
19411
|
+
pageCount,
|
|
19412
|
+
seconds
|
|
19413
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextGuide, {
|
|
19414
|
+
first,
|
|
19415
|
+
page,
|
|
19416
|
+
pageCount,
|
|
19417
|
+
seconds
|
|
19418
|
+
})
|
|
19419
|
+
})]
|
|
19420
|
+
})] });
|
|
19421
|
+
};
|
|
19422
|
+
/** 短剧单元:每集文案都是同一段简介,只留集号 + 时长,像目录条目一样左右分列 */
|
|
19423
|
+
var PlayletCell = ({ episode, numberClassName }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19424
|
+
className: "min-w-0",
|
|
19425
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19426
|
+
className: "aspect-3/4 overflow-hidden rounded-3xl bg-surface-secondary shadow-lg shadow-black/10",
|
|
19427
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
19428
|
+
src: episode.originCover || episode.cover || "",
|
|
19429
|
+
alt: `第 ${episode.episode} 集`,
|
|
19430
|
+
className: "h-full w-full object-cover object-[50%_30%]"
|
|
19431
|
+
})
|
|
19432
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19433
|
+
className: "mt-4 flex items-baseline gap-3",
|
|
19434
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19435
|
+
className: `leading-none font-black tracking-tight text-foreground tabular-nums ${numberClassName}`,
|
|
19436
|
+
children: episode.episode
|
|
19437
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19438
|
+
className: "font-mono text-[26px] text-foreground/65",
|
|
19439
|
+
children: formatDuration$4(episode.duration)
|
|
19440
|
+
})]
|
|
19441
|
+
})]
|
|
19442
|
+
});
|
|
19443
|
+
/** 短剧集号字号:5 列单元只有约 230px 宽,4 位集号降一档,给时长留位置;min-w 让同页时长列对齐 */
|
|
19444
|
+
var PLAYLET_NUMBER_CLASS = [
|
|
19445
|
+
"min-w-14 text-[72px]",
|
|
19446
|
+
"min-w-24 text-[72px]",
|
|
19447
|
+
"min-w-32 text-[72px]",
|
|
19448
|
+
"min-w-34 text-[56px]"
|
|
19449
|
+
];
|
|
19450
|
+
/** 合集集号栏:按本页最大位数取宽度,同一页标题左缘对齐;4 位集号降字号,不挤占标题 */
|
|
19451
|
+
var COLLECTION_NUMBER_CLASS = [
|
|
19452
|
+
"min-w-14 text-[80px]",
|
|
19453
|
+
"min-w-26 text-[80px]",
|
|
19454
|
+
"min-w-37.5 text-[80px]",
|
|
19455
|
+
"min-w-37 text-[60px]"
|
|
19456
|
+
];
|
|
19457
|
+
/** 普通合集单元:时长压在封面右下角,标题让出整列宽度显示三行 */
|
|
19458
|
+
var CollectionCell = ({ episode, numberClassName }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19459
|
+
className: "min-w-0",
|
|
19460
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19461
|
+
className: "relative aspect-video overflow-hidden rounded-3xl bg-surface-secondary shadow-lg shadow-black/10",
|
|
19462
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
19463
|
+
src: episode.originCover || episode.cover || "",
|
|
19464
|
+
alt: episode.title,
|
|
19465
|
+
className: "h-full w-full object-cover"
|
|
19466
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19467
|
+
className: "absolute right-3 bottom-3 rounded-lg bg-black/60 px-2.5 py-0.5 font-mono text-[24px] text-white",
|
|
19468
|
+
children: formatDuration$4(episode.duration)
|
|
19469
|
+
})]
|
|
19470
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19471
|
+
className: "mt-4 flex gap-4",
|
|
19472
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19473
|
+
className: `shrink-0 leading-[0.9] font-black tracking-tight text-foreground tabular-nums ${numberClassName}`,
|
|
19474
|
+
children: episode.episode
|
|
19475
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19476
|
+
className: "line-clamp-3 min-w-0 flex-1 pt-0.5 text-[30px] leading-tight font-bold text-pretty text-foreground",
|
|
19477
|
+
children: episode.title || "未命名视频"
|
|
19478
|
+
})]
|
|
19479
|
+
})]
|
|
19480
|
+
});
|
|
19481
|
+
/** 最后一页不满一行时的收尾块:说明最新内容在哪一页,并给出往回翻的方式 */
|
|
19482
|
+
var EndCard = ({ span, noun, countText, pageCount, mode }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19483
|
+
className: `${COL_SPAN[span] ?? "col-span-1"} flex flex-col justify-center self-stretch rounded-3xl bg-foreground/5 p-9`,
|
|
19484
|
+
children: [
|
|
19485
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19486
|
+
className: "flex items-center gap-4 text-[40px] leading-tight font-black text-foreground",
|
|
19487
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19488
|
+
className: "h-5 w-5 shrink-0",
|
|
19489
|
+
style: { backgroundColor: ACCENT }
|
|
19490
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: pageCount > 1 ? "已是最后一页" : "只有这一页" })]
|
|
19491
|
+
}),
|
|
19492
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
19493
|
+
className: "mt-4 text-[28px] leading-normal text-foreground/75",
|
|
19494
|
+
children: pageCount > 1 ? `最新的${noun}在第 1 页` : countText
|
|
19495
|
+
}),
|
|
19496
|
+
pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19497
|
+
className: "flex flex-wrap items-center gap-3 pt-6 text-[28px] text-foreground/70",
|
|
19498
|
+
children: mode === "button" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "点键盘「上一页」往回翻" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
19499
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "发送" }),
|
|
19500
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip, { children: "上一页" }),
|
|
19501
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "往回翻" })
|
|
19502
|
+
] })
|
|
19503
|
+
})
|
|
19504
|
+
]
|
|
19505
|
+
});
|
|
19506
|
+
/** 选集网格:短剧 5 列对应键盘每行 5 个按钮;普通合集 3 列,保证标题三行可读 */
|
|
19507
|
+
var EpisodeGrid = ({ episodes, isPlaylet, isLastPage, pageCount, listed, mode }) => {
|
|
19508
|
+
const columns = isPlaylet ? 5 : 3;
|
|
19509
|
+
const remainder = episodes.length % columns;
|
|
19510
|
+
const fill = isLastPage && remainder > 0 ? columns - remainder : 0;
|
|
19511
|
+
const showEndCard = fill > 1 || fill === 1 && !isPlaylet;
|
|
19512
|
+
const digits = Math.min(Math.max(1, ...episodes.map((episode) => `${episode.episode}`.length)), 4);
|
|
19513
|
+
const numberClassName = isPlaylet ? PLAYLET_NUMBER_CLASS[digits - 1] : COLLECTION_NUMBER_CLASS[digits - 1];
|
|
19514
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19515
|
+
className: isPlaylet ? "grid grid-cols-5 gap-x-7 gap-y-10" : "grid grid-cols-3 gap-x-10 gap-y-11",
|
|
19516
|
+
children: [episodes.map((episode) => isPlaylet ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlayletCell, {
|
|
19517
|
+
episode,
|
|
19518
|
+
numberClassName
|
|
19519
|
+
}, episode.aweme_id) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CollectionCell, {
|
|
19520
|
+
episode,
|
|
19521
|
+
numberClassName
|
|
19522
|
+
}, episode.aweme_id)), showEndCard && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EndCard, {
|
|
19523
|
+
span: fill,
|
|
19524
|
+
noun: isPlaylet ? "剧集" : "视频",
|
|
19525
|
+
countText: isPlaylet ? `共 ${listed} 集` : `共 ${listed} 个视频`,
|
|
19526
|
+
pageCount,
|
|
19527
|
+
mode
|
|
19528
|
+
})]
|
|
19529
|
+
});
|
|
19530
|
+
};
|
|
19531
|
+
/** 版权栏:左侧列出数量与缺集说明,右侧生成时间 */
|
|
19532
|
+
var Colophon = ({ notes }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("footer", {
|
|
19533
|
+
className: "flex items-start justify-between gap-10 pt-7 text-[24px] leading-relaxed text-foreground/65",
|
|
19534
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19535
|
+
className: "min-w-0",
|
|
19536
|
+
children: notes.join(" · ")
|
|
19537
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19538
|
+
className: "shrink-0 select-text",
|
|
19539
|
+
children: ["图片生成于: ", format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss")]
|
|
19540
|
+
})]
|
|
19541
|
+
});
|
|
19542
|
+
var DouyinMix = import_react.memo((props) => {
|
|
19543
|
+
const { data, ctx } = props;
|
|
19544
|
+
const isPlaylet = data.kind === "playlet";
|
|
19545
|
+
const pageSize = Math.max(1, data.posterPageSize ?? DEFAULT_POSTER_PAGE_SIZE);
|
|
19546
|
+
const pageCount = Math.max(1, Math.ceil(data.episodes.length / pageSize));
|
|
19547
|
+
const page = Math.min(Math.max(1, data.posterPage ?? 1), pageCount);
|
|
19548
|
+
const visible = data.episodes.slice((page - 1) * pageSize, page * pageSize);
|
|
19549
|
+
const mode = data.selectionMode ?? "text";
|
|
19550
|
+
const seconds = data.timeoutSeconds > 0 ? data.timeoutSeconds : DEFAULT_TIMEOUT_SECONDS;
|
|
19551
|
+
const listedSet = new Set(data.episodes.map((episode) => episode.episode));
|
|
19552
|
+
const maxEpisode = data.episodes.reduce((max, episode) => Math.max(max, episode.episode), 0);
|
|
19553
|
+
const missing = [];
|
|
19554
|
+
for (let episode = 1; episode <= Math.max(maxEpisode, data.updated_to_episode); episode++) if (!listedSet.has(episode)) missing.push(episode);
|
|
19555
|
+
const upper = page > 1 ? data.episodes[(page - 1) * pageSize - 1].episode : Infinity;
|
|
19556
|
+
const lower = page < pageCount ? visible[visible.length - 1].episode : 0;
|
|
19557
|
+
const pageMissing = missing.filter((episode) => episode < upper && episode > lower);
|
|
19558
|
+
const unit = isPlaylet ? "集" : "个视频";
|
|
19559
|
+
const totalDuration = data.episodes.reduce((sum, episode) => sum + episode.duration, 0);
|
|
19560
|
+
const ledger = [
|
|
19561
|
+
{
|
|
19562
|
+
label: "播放",
|
|
19563
|
+
...splitCount(data.statistics.play_count)
|
|
19564
|
+
},
|
|
19565
|
+
{
|
|
19566
|
+
label: "点赞",
|
|
19567
|
+
...splitCount(data.statistics.digg_count)
|
|
19568
|
+
},
|
|
19569
|
+
{
|
|
19570
|
+
label: "收藏",
|
|
19571
|
+
...splitCount(data.statistics.collect_count)
|
|
19572
|
+
},
|
|
19573
|
+
isPlaylet ? {
|
|
19574
|
+
label: "单集均长",
|
|
19575
|
+
value: formatDuration$4(data.episodes.length ? totalDuration / data.episodes.length : 0),
|
|
19576
|
+
unit: ""
|
|
19577
|
+
} : {
|
|
19578
|
+
label: "总时长",
|
|
19579
|
+
...splitRuntime(totalDuration)
|
|
19580
|
+
}
|
|
19581
|
+
];
|
|
19582
|
+
const notes = [data.total_episode > 0 ? `已列出 ${data.episodes.length} / ${data.total_episode} ${unit}` : `已列出 ${data.episodes.length} ${unit}`, ...missing.length > 0 ? [`接口未返回${formatMissing(missing, unit)},暂不能选`] : []];
|
|
19583
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DefaultLayout, {
|
|
19584
|
+
...props,
|
|
19585
|
+
className: "relative overflow-hidden",
|
|
19586
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PosterBackground, {
|
|
19587
|
+
src: data.image_url,
|
|
19588
|
+
ctx
|
|
19589
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
19590
|
+
className: "relative z-10 px-20 pt-18",
|
|
19591
|
+
children: [
|
|
19592
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Masthead, {
|
|
19593
|
+
label: isPlaylet ? "DOUYIN PLAYLET · EPISODE GUIDE" : "DOUYIN COLLECTION · EPISODE GUIDE",
|
|
19594
|
+
ctx
|
|
19595
|
+
}),
|
|
19596
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19597
|
+
className: "mt-12",
|
|
19598
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Hero, { data })
|
|
19599
|
+
}),
|
|
19600
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19601
|
+
className: "mt-12",
|
|
19602
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Ledger, { items: ledger })
|
|
19603
|
+
}),
|
|
19604
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19605
|
+
className: "mt-16",
|
|
19606
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Contents, {
|
|
19607
|
+
episodes: visible,
|
|
19608
|
+
missingNote: pageMissing.length > 0 ? `缺${formatMissing(pageMissing, unit)},暂不能选` : "",
|
|
19609
|
+
page,
|
|
19610
|
+
pageCount,
|
|
19611
|
+
mode,
|
|
19612
|
+
seconds
|
|
19613
|
+
})
|
|
19614
|
+
}),
|
|
19615
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19616
|
+
className: "mt-12",
|
|
19617
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EpisodeGrid, {
|
|
19618
|
+
episodes: visible,
|
|
19619
|
+
isPlaylet,
|
|
19620
|
+
isLastPage: page === pageCount,
|
|
19621
|
+
pageCount,
|
|
19622
|
+
listed: data.episodes.length,
|
|
19623
|
+
mode
|
|
19624
|
+
})
|
|
19625
|
+
}),
|
|
19626
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19627
|
+
className: "mt-14",
|
|
19628
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Colophon, { notes })
|
|
19629
|
+
})
|
|
19630
|
+
]
|
|
19631
|
+
})]
|
|
19632
|
+
});
|
|
19633
|
+
});
|
|
18940
19634
|
DouyinMix.displayName = "DouyinMix";
|
|
18941
19635
|
//#endregion
|
|
18942
19636
|
//#region ktr/template/douyin/mix/index.tsx
|
|
@@ -30524,31 +31218,16 @@ var wrapWithErrorHandler = (fn, options) => {
|
|
|
30524
31218
|
const rawEvent = e;
|
|
30525
31219
|
const normalizedEvent = await injectBotToEventForPushTask(rawEvent, options.businessName);
|
|
30526
31220
|
const normalizedNext = next ?? (() => void 0);
|
|
30527
|
-
const
|
|
30528
|
-
|
|
30529
|
-
let successTimer = null;
|
|
30530
|
-
if (emojiManager) {
|
|
30531
|
-
await emojiManager.add("EYES");
|
|
30532
|
-
processingTimer = setTimeout(() => {
|
|
30533
|
-
emojiManager.add("PROCESSING").catch(() => {});
|
|
30534
|
-
}, 1500);
|
|
30535
|
-
}
|
|
31221
|
+
const emojiFlow = Boolean(rawEvent) && !isPushTask(rawEvent, options.businessName) ? createEmojiReactionFlow(rawEvent) : void 0;
|
|
31222
|
+
if (emojiFlow) await emojiFlow.begin();
|
|
30536
31223
|
const runHandler = () => fn(normalizedEvent, normalizedNext);
|
|
30537
31224
|
const ctx = logger$1.runContext(async () => rawEvent ? runWithVerifyContext(rawEvent, runHandler) : runHandler());
|
|
30538
31225
|
try {
|
|
30539
31226
|
const result = await ctx.run();
|
|
30540
|
-
|
|
30541
|
-
emojiManager.replace("PROCESSING", "SUCCESS").catch(() => {});
|
|
30542
|
-
}, 1500);
|
|
31227
|
+
await emojiFlow?.succeed();
|
|
30543
31228
|
return result;
|
|
30544
31229
|
} catch (error) {
|
|
30545
|
-
|
|
30546
|
-
if (successTimer) clearTimeout(successTimer);
|
|
30547
|
-
if (emojiManager) {
|
|
30548
|
-
const processingEmojiId = emojiManager["getPlatformEmojiId"]("PROCESSING");
|
|
30549
|
-
if (emojiManager.has(processingEmojiId)) await emojiManager.remove("PROCESSING");
|
|
30550
|
-
await emojiManager.add("ERROR");
|
|
30551
|
-
}
|
|
31230
|
+
await emojiFlow?.fail();
|
|
30552
31231
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
30553
31232
|
if (await handleBusinessError(error, options, parseLogsToStructured(ctx.logs()), normalizedEvent) === "handled") return void 0;
|
|
30554
31233
|
throw error;
|
|
@@ -30669,6 +31348,7 @@ var createEpisodeSelection = (scope, options) => {
|
|
|
30669
31348
|
title: options.title,
|
|
30670
31349
|
platform: options.platform,
|
|
30671
31350
|
scene: options.scene,
|
|
31351
|
+
ownerId: options.ownerId,
|
|
30672
31352
|
pageSize: Math.max(1, options.pageSize ?? 15),
|
|
30673
31353
|
poster: options.poster,
|
|
30674
31354
|
posterPages: /* @__PURE__ */ new Map([[options.posterPage ?? 1, options.poster]]),
|
|
@@ -30699,6 +31379,13 @@ var getEpisodeSelection = (token, scope) => {
|
|
|
30699
31379
|
}
|
|
30700
31380
|
return session;
|
|
30701
31381
|
};
|
|
31382
|
+
/**
|
|
31383
|
+
* 判断用户是否有权操作这次选集。
|
|
31384
|
+
* 只有发起人本人能翻页/选集;没有记录发起人时退回旧行为(不做限制)。
|
|
31385
|
+
*/
|
|
31386
|
+
var isEpisodeSelectionOwner = (session, userId) => {
|
|
31387
|
+
return !session.ownerId || session.ownerId === userId;
|
|
31388
|
+
};
|
|
30702
31389
|
/** 翻页成功后重新计算 120 秒有效期。 */
|
|
30703
31390
|
var touchEpisodeSelection = (token, scope) => {
|
|
30704
31391
|
const session = getEpisodeSelection(token, scope);
|
|
@@ -30759,34 +31446,41 @@ var getEpisodeSelectionPoster = async (session, posterPage) => {
|
|
|
30759
31446
|
* 生成 QQBot keyboard 行。
|
|
30760
31447
|
* 跳转输入行在最上面,集数按钮每行 5 个,翻页按钮单独一行;
|
|
30761
31448
|
* 15 集一页时正好 1 + 3 + 1 = 5 行,不会超过 QQBot 的上限。
|
|
31449
|
+
* 群聊里每个按钮都带发起人的点击权限(QQBot 原生 permission),别人点了不生效;
|
|
31450
|
+
* 私聊只有对方一人可见,且 QQ 私聊不支持「指定用户」权限,不加 list,靠命令侧校验。
|
|
30762
31451
|
*/
|
|
30763
31452
|
var buildEpisodeKeyboardRows = (session, page) => {
|
|
30764
31453
|
const data = getEpisodePage(session, page);
|
|
30765
31454
|
if (!data) return [];
|
|
31455
|
+
const ownerPermission = session.ownerId && session.scene === "group" ? { list: [session.ownerId] } : {};
|
|
30766
31456
|
const rows = [];
|
|
30767
31457
|
if (data.pageCount > 1) rows.push([{
|
|
30768
31458
|
text: "跳转到第x页",
|
|
30769
31459
|
data: `#选集 ${session.token} page:`,
|
|
30770
31460
|
enter: false,
|
|
30771
|
-
style: 1
|
|
31461
|
+
style: 1,
|
|
31462
|
+
...ownerPermission
|
|
30772
31463
|
}]);
|
|
30773
31464
|
for (let index = 0; index < data.items.length; index += 5) rows.push(data.items.slice(index, index + 5).map((item) => ({
|
|
30774
31465
|
text: String(item.episode),
|
|
30775
31466
|
show: String(item.episode),
|
|
30776
31467
|
callback: true,
|
|
30777
31468
|
data: `#选集 ${session.token} ${item.episode}`,
|
|
30778
|
-
style: 1
|
|
31469
|
+
style: 1,
|
|
31470
|
+
...ownerPermission
|
|
30779
31471
|
})));
|
|
30780
31472
|
const navigation = [];
|
|
30781
31473
|
if (data.page > 1) navigation.push({
|
|
30782
31474
|
text: "上一页",
|
|
30783
31475
|
callback: true,
|
|
30784
|
-
data: `#选集 ${session.token} page:${data.page - 1}
|
|
31476
|
+
data: `#选集 ${session.token} page:${data.page - 1}`,
|
|
31477
|
+
...ownerPermission
|
|
30785
31478
|
});
|
|
30786
31479
|
if (data.page < data.pageCount) navigation.push({
|
|
30787
31480
|
text: "下一页",
|
|
30788
31481
|
callback: true,
|
|
30789
|
-
data: `#选集 ${session.token} page:${data.page + 1}
|
|
31482
|
+
data: `#选集 ${session.token} page:${data.page + 1}`,
|
|
31483
|
+
...ownerPermission
|
|
30790
31484
|
});
|
|
30791
31485
|
if (navigation.length) rows.push(navigation);
|
|
30792
31486
|
return rows;
|
|
@@ -30796,7 +31490,8 @@ var buildEpisodeSelectionText = (session, page) => {
|
|
|
30796
31490
|
const data = getEpisodePage(session, page);
|
|
30797
31491
|
if (!data) return "";
|
|
30798
31492
|
const range = data.firstEpisode === data.lastEpisode ? `第 ${data.firstEpisode} 集` : `第 ${data.firstEpisode}–${data.lastEpisode} 集`;
|
|
30799
|
-
|
|
31493
|
+
const ownerHint = session.scene === "group" ? ",仅发起人可操作" : "";
|
|
31494
|
+
return `《${session.title}》\n${range} · 第 ${data.page}/${data.pageCount} 页\n点击下方按钮选集(120 秒内有效${ownerHint})。`;
|
|
30800
31495
|
};
|
|
30801
31496
|
/** 按实际集号查找目标。 */
|
|
30802
31497
|
var resolveEpisodeTarget = (session, episode) => {
|
|
@@ -32128,6 +32823,8 @@ var Bilibili = class extends Base {
|
|
|
32128
32823
|
const linkedSourceIndex = linkedEpId ? sourceEpisodes.findIndex((item) => String(item.ep_id) === linkedEpId) : -1;
|
|
32129
32824
|
const linkedDisplayIndex = linkedSourceIndex >= 0 ? sourceEpisodes.length - 1 - linkedSourceIndex : -1;
|
|
32130
32825
|
let selectedIndex = autoSelectEpisode ? linkedSourceIndex : -1;
|
|
32826
|
+
/** 文字选集消息的表情反馈流程:翻页留到新海报发出、选集留到下载结束后再收尾 */
|
|
32827
|
+
let emojiFlow = null;
|
|
32131
32828
|
const buttonSelection = isButtonSelectionScene(this.e);
|
|
32132
32829
|
const selectionMode = buttonSelection ? "button" : "text";
|
|
32133
32830
|
/** 按海报页码渲染:15 集一页,长番剧不会撑爆单张 PNG */
|
|
@@ -32146,6 +32843,7 @@ var Bilibili = class extends Base {
|
|
|
32146
32843
|
Stat: videoInfo.data.result.stat,
|
|
32147
32844
|
Episodes: displayEpisodes,
|
|
32148
32845
|
length: sourceEpisodes.length,
|
|
32846
|
+
timeoutSeconds: 120,
|
|
32149
32847
|
selectionMode,
|
|
32150
32848
|
posterPage,
|
|
32151
32849
|
posterPageSize: 15
|
|
@@ -32162,6 +32860,7 @@ var Bilibili = class extends Base {
|
|
|
32162
32860
|
title: videoInfo.data.result.title,
|
|
32163
32861
|
platform: "bilibili",
|
|
32164
32862
|
scene: this.e.isFriend ? "friend" : "group",
|
|
32863
|
+
ownerId: this.e.userId,
|
|
32165
32864
|
poster,
|
|
32166
32865
|
posterPage: initialPage,
|
|
32167
32866
|
renderPoster,
|
|
@@ -32178,95 +32877,123 @@ var Bilibili = class extends Base {
|
|
|
32178
32877
|
/** 上一页海报消息,翻页发送成功后撤回,避免聊天里堆一串过期海报 */
|
|
32179
32878
|
let posterMessageId = "";
|
|
32180
32879
|
let posterMessageSentAt = 0;
|
|
32181
|
-
|
|
32182
|
-
|
|
32183
|
-
|
|
32184
|
-
|
|
32185
|
-
|
|
32186
|
-
|
|
32187
|
-
|
|
32188
|
-
|
|
32189
|
-
|
|
32190
|
-
|
|
32191
|
-
|
|
32192
|
-
|
|
32193
|
-
|
|
32194
|
-
|
|
32195
|
-
|
|
32196
|
-
|
|
32197
|
-
|
|
32198
|
-
|
|
32199
|
-
|
|
32200
|
-
|
|
32201
|
-
|
|
32202
|
-
|
|
32203
|
-
|
|
32204
|
-
|
|
32205
|
-
|
|
32206
|
-
|
|
32207
|
-
|
|
32208
|
-
|
|
32209
|
-
|
|
32210
|
-
if (
|
|
32211
|
-
|
|
32880
|
+
try {
|
|
32881
|
+
for (;;) {
|
|
32882
|
+
const poster = await renderPoster(posterPage);
|
|
32883
|
+
const start = (posterPage - 1) * 15;
|
|
32884
|
+
const pageEpisodes = displayEpisodes.slice(start, start + 15);
|
|
32885
|
+
const firstEpisode = pageEpisodes[0]?.episode ?? 0;
|
|
32886
|
+
const lastEpisode = pageEpisodes[pageEpisodes.length - 1]?.episode ?? 0;
|
|
32887
|
+
const range = firstEpisode === lastEpisode ? `第 ${firstEpisode} 集` : `第 ${firstEpisode}–${lastEpisode} 集`;
|
|
32888
|
+
const sentAt = Date.now();
|
|
32889
|
+
const result = await this.e.reply([...poster, segment.text(`《${videoInfo.data.result.title}》\n${range}(共 ${displayEpisodes.length} 集)\n第 ${posterPage}/${posterPageCount} 页\n发送 第?集 选集${posterPageCount > 1 ? ",发送 上一页 / 下一页 / 第?页 翻页" : ""}(120 秒内有效)`)]);
|
|
32890
|
+
if (emojiFlow) {
|
|
32891
|
+
await emojiFlow.succeed();
|
|
32892
|
+
settleEmojiReaction(this.e);
|
|
32893
|
+
emojiFlow = null;
|
|
32894
|
+
}
|
|
32895
|
+
const previousMessageId = posterMessageId;
|
|
32896
|
+
const previousMessageSentAt = posterMessageSentAt;
|
|
32897
|
+
posterMessageId = result.messageId;
|
|
32898
|
+
posterMessageSentAt = result.messageId ? sentAt : 0;
|
|
32899
|
+
if (previousMessageId && canRecallEpisodeMessage(previousMessageId, previousMessageSentAt)) try {
|
|
32900
|
+
await this.e.bot.recallMsg(this.e.contact, previousMessageId);
|
|
32901
|
+
} catch (error) {
|
|
32902
|
+
logger$1.debug("[选集] 撤回上一页失败:", error);
|
|
32903
|
+
}
|
|
32904
|
+
const context = await karin.ctx(this.e, {
|
|
32905
|
+
reply: true,
|
|
32906
|
+
throwOnTimeout: false,
|
|
32907
|
+
time: 120
|
|
32908
|
+
});
|
|
32909
|
+
if (!context) return true;
|
|
32910
|
+
const replyText = context.msg.trim();
|
|
32911
|
+
if (/^[#/]/.test(replyText) || /(https?:\/\/|b23\.tv|bilibili\.com|douyin\.com|iesdouyin\.com)/i.test(replyText)) return true;
|
|
32912
|
+
emojiFlow = createEmojiReactionFlow(context);
|
|
32913
|
+
await emojiFlow.begin();
|
|
32914
|
+
const pageAction = parseEpisodePosterPageAction(context.msg);
|
|
32915
|
+
if (pageAction) {
|
|
32916
|
+
const nextPage = pageAction.type === "prev" ? posterPage - 1 : pageAction.type === "next" ? posterPage + 1 : pageAction.page;
|
|
32917
|
+
if (nextPage < 1 || nextPage > posterPageCount) {
|
|
32918
|
+
await this.e.reply(`页码超出范围,请发送 1-${posterPageCount} 之间的页码`);
|
|
32919
|
+
await emojiFlow.fail();
|
|
32920
|
+
settleEmojiReaction(this.e);
|
|
32921
|
+
emojiFlow = null;
|
|
32922
|
+
continue;
|
|
32923
|
+
}
|
|
32924
|
+
posterPage = nextPage;
|
|
32212
32925
|
continue;
|
|
32213
32926
|
}
|
|
32214
|
-
|
|
32215
|
-
|
|
32216
|
-
|
|
32217
|
-
|
|
32218
|
-
|
|
32219
|
-
|
|
32220
|
-
|
|
32927
|
+
const parsedEpisode = parseEpisodeNumber(context.msg);
|
|
32928
|
+
if (parsedEpisode === null || parsedEpisode > sourceEpisodes.length) {
|
|
32929
|
+
await this.e.reply(parsedEpisode === null ? "匹配内容失败,请发送 第?集 选择集数,或发送 上一页 / 下一页 / 第?页 翻页" : `第${parsedEpisode}集不在可解析的剧集里,请重新选择`);
|
|
32930
|
+
await emojiFlow.fail();
|
|
32931
|
+
settleEmojiReaction(this.e);
|
|
32932
|
+
emojiFlow = null;
|
|
32933
|
+
continue;
|
|
32934
|
+
}
|
|
32935
|
+
selectedIndex = parsedEpisode - 1;
|
|
32936
|
+
break;
|
|
32221
32937
|
}
|
|
32222
|
-
|
|
32223
|
-
|
|
32938
|
+
} catch (error) {
|
|
32939
|
+
if (emojiFlow) await emojiFlow.fail();
|
|
32940
|
+
throw error;
|
|
32224
32941
|
}
|
|
32225
32942
|
}
|
|
32226
32943
|
const episodeInfo = sourceEpisodes[selectedIndex];
|
|
32227
|
-
|
|
32228
|
-
|
|
32229
|
-
|
|
32230
|
-
|
|
32231
|
-
|
|
32232
|
-
|
|
32233
|
-
|
|
32234
|
-
|
|
32235
|
-
|
|
32236
|
-
|
|
32237
|
-
|
|
32238
|
-
|
|
32239
|
-
|
|
32240
|
-
const playUrlData = await new Network({
|
|
32241
|
-
url: bangumidataBASEURL + Params,
|
|
32242
|
-
headers: this.headers
|
|
32243
|
-
}).getData();
|
|
32244
|
-
if (episodeInfo.badge === "会员" && !this.isVIP) {
|
|
32245
|
-
logger$1.warn("该CK不是大会员,无法获取视频流");
|
|
32246
|
-
return true;
|
|
32247
|
-
}
|
|
32248
|
-
if (Config.bilibili.videoQuality === 0) {
|
|
32249
|
-
/** 提取出视频流信息对象,并排除清晰度重复的视频流 */
|
|
32250
|
-
const simplify = playUrlData.result.dash.video.filter((item, index, self) => {
|
|
32251
|
-
return self.findIndex((t) => {
|
|
32252
|
-
return t.id === item.id;
|
|
32253
|
-
}) === index;
|
|
32944
|
+
try {
|
|
32945
|
+
if (!episodeInfo) {
|
|
32946
|
+
await this.e.reply("未找到该集,请重新发送番剧链接");
|
|
32947
|
+
if (emojiFlow) await emojiFlow.fail();
|
|
32948
|
+
await settleEmojiReaction(this.e, "ERROR");
|
|
32949
|
+
return true;
|
|
32950
|
+
}
|
|
32951
|
+
const displayEpisode = selectedIndex + 1;
|
|
32952
|
+
this.downloadfilename = episodeInfo.share_copy.substring(0, 50).replace(/[\\/:*?"<>|\r\n\s]/g, " ");
|
|
32953
|
+
await this.e.reply(`收到请求,第${displayEpisode}集\n${this.downloadfilename}\n正在下载中`);
|
|
32954
|
+
const bangumidataBASEURL = bilibiliApiUrls.getBangumiStream({
|
|
32955
|
+
cid: episodeInfo.cid,
|
|
32956
|
+
ep_id: episodeInfo.ep_id.toString()
|
|
32254
32957
|
});
|
|
32255
|
-
|
|
32256
|
-
|
|
32257
|
-
|
|
32258
|
-
|
|
32259
|
-
|
|
32260
|
-
|
|
32261
|
-
|
|
32262
|
-
|
|
32263
|
-
|
|
32264
|
-
|
|
32958
|
+
const Params = await genParams(bangumidataBASEURL);
|
|
32959
|
+
if (!this.islogin) await this.e.reply("B站ck未配置或已失效,无法获取视频流,可尝试【#B站登录】以配置新ck");
|
|
32960
|
+
const playUrlData = await new Network({
|
|
32961
|
+
url: bangumidataBASEURL + Params,
|
|
32962
|
+
headers: this.headers
|
|
32963
|
+
}).getData();
|
|
32964
|
+
if (episodeInfo.badge === "会员" && !this.isVIP) {
|
|
32965
|
+
logger$1.warn("该CK不是大会员,无法获取视频流");
|
|
32966
|
+
if (emojiFlow) await emojiFlow.fail();
|
|
32967
|
+
await settleEmojiReaction(this.e, "ERROR");
|
|
32968
|
+
return true;
|
|
32969
|
+
}
|
|
32970
|
+
if (Config.bilibili.videoQuality === 0) {
|
|
32971
|
+
/** 提取出视频流信息对象,并排除清晰度重复的视频流 */
|
|
32972
|
+
const simplify = playUrlData.result.dash.video.filter((item, index, self) => {
|
|
32973
|
+
return self.findIndex((t) => {
|
|
32974
|
+
return t.id === item.id;
|
|
32975
|
+
}) === index;
|
|
32976
|
+
});
|
|
32977
|
+
/** 替换原始的视频信息对象 */
|
|
32978
|
+
playUrlData.result.dash.video = simplify;
|
|
32979
|
+
/** 给视频信息对象删除不符合条件的视频流 */
|
|
32980
|
+
const correctList = await bilibiliProcessVideos({
|
|
32981
|
+
accept_description: playUrlData.result.accept_description,
|
|
32982
|
+
bvid: videoInfo.data.result.season_id.toString(),
|
|
32983
|
+
qn: Config.bilibili.videoQuality
|
|
32984
|
+
}, simplify, getBilibiliStreamUrl(playUrlData.result.dash.audio?.[0]));
|
|
32985
|
+
playUrlData.result.dash.video = correctList.videoList;
|
|
32986
|
+
playUrlData.result.cept_description = correctList.accept_description;
|
|
32987
|
+
}
|
|
32988
|
+
await this.getvideo({
|
|
32989
|
+
infoData: videoInfo.data,
|
|
32990
|
+
playUrlData
|
|
32991
|
+
});
|
|
32992
|
+
if (emojiFlow) await emojiFlow.succeed();
|
|
32993
|
+
} catch (error) {
|
|
32994
|
+
if (emojiFlow) await emojiFlow.fail();
|
|
32995
|
+
throw error;
|
|
32265
32996
|
}
|
|
32266
|
-
await this.getvideo({
|
|
32267
|
-
infoData: videoInfo.data,
|
|
32268
|
-
playUrlData
|
|
32269
|
-
});
|
|
32270
32997
|
break;
|
|
32271
32998
|
}
|
|
32272
32999
|
case "dynamic_info": {
|
|
@@ -37057,6 +37784,26 @@ async function renderLiveImage(options) {
|
|
|
37057
37784
|
});
|
|
37058
37785
|
}
|
|
37059
37786
|
//#endregion
|
|
37787
|
+
//#region src/platform/douyin/shortUrl.ts
|
|
37788
|
+
/**
|
|
37789
|
+
* 把分享链接换成抖音签发的 `v.douyin.com` 短链(二维码专用)。
|
|
37790
|
+
*
|
|
37791
|
+
* 短链由 amagi 的 `douyin.shortUrl` 端点签发:同一 target 恒得同一短码,
|
|
37792
|
+
* 内容比任何规范链接都短,能明显降低二维码密度。该端点免登录但仍要 `a_bogus` 签名,
|
|
37793
|
+
* 可能因签名或平台策略失败 —— 失败不阻塞推送,回退原链接即可。
|
|
37794
|
+
* @param target - 待缩短的分享链接(规范链接或视频直链均可)
|
|
37795
|
+
* @returns 短链;签发失败时原样返回 target
|
|
37796
|
+
*/
|
|
37797
|
+
var toDouyinShortUrl = async (target) => {
|
|
37798
|
+
try {
|
|
37799
|
+
const shortUrl = (await douyinFetcher.fetchShortUrl({ target })).data?.data;
|
|
37800
|
+
return typeof shortUrl === "string" && shortUrl.length > 0 ? shortUrl : target;
|
|
37801
|
+
} catch (error) {
|
|
37802
|
+
logger$1.debug(`[抖音短链] 签发失败,二维码回退原链接:${error instanceof Error ? error.message : String(error)}`);
|
|
37803
|
+
return target;
|
|
37804
|
+
}
|
|
37805
|
+
};
|
|
37806
|
+
//#endregion
|
|
37060
37807
|
//#region src/platform/douyin/types.ts
|
|
37061
37808
|
/**
|
|
37062
37809
|
* 把 amagi 返回的 aweme 对象装配成渲染/推送使用的作品详情。
|
|
@@ -37106,13 +37853,13 @@ var DouYin = class DouYin extends Base {
|
|
|
37106
37853
|
if (VideoData.data.aweme_detail === null) throw new Error("获取作品详情失败,可能是因为该作品已被删除或设置为私密。");
|
|
37107
37854
|
/**
|
|
37108
37855
|
* 根据 aweme_type 判断作品类型
|
|
37109
|
-
* - `0`、`4`、`55`:视频作品;`4` 是剧集合集
|
|
37856
|
+
* - `0`、`4`、`55`、`61`:视频作品;`4` 是剧集合集
|
|
37110
37857
|
* - `163`:文章作品
|
|
37111
37858
|
* - `68`:图文作品(含图集、合辑等)
|
|
37112
37859
|
*/
|
|
37113
37860
|
const aweme_type = VideoData.data.aweme_detail.aweme_type;
|
|
37114
37861
|
const isArticle = aweme_type === 163;
|
|
37115
|
-
const isVideo = aweme_type === 0 || aweme_type === 4 || aweme_type === 55;
|
|
37862
|
+
const isVideo = aweme_type === 0 || aweme_type === 4 || aweme_type === 55 || aweme_type === 61;
|
|
37116
37863
|
const CommentsData = await this.amagi.douyin.fetcher.fetchWorkComments({
|
|
37117
37864
|
aweme_id: data.aweme_id,
|
|
37118
37865
|
number: Config.douyin.numcomment
|
|
@@ -37503,7 +38250,7 @@ var DouYin = class DouYin extends Base {
|
|
|
37503
38250
|
} else {
|
|
37504
38251
|
const aweme = VideoData.data.aweme_detail;
|
|
37505
38252
|
const userProfile = await this.amagi.douyin.fetcher.fetchUserProfile({ sec_uid: aweme.author.sec_uid });
|
|
37506
|
-
const shareLink = isVideo && selectedVideo ? buildDouyinPlayUrl(selectedVideo.play_addr) : `https://www.douyin.com/${isArticle ? "article" : "note"}/${aweme.aweme_id}
|
|
38253
|
+
const shareLink = await toDouyinShortUrl(isVideo && selectedVideo ? buildDouyinPlayUrl(selectedVideo.play_addr) : `https://www.douyin.com/${isArticle ? "article" : "note"}/${aweme.aweme_id}`);
|
|
37507
38254
|
const workInfoImg = await renderWorkImage({
|
|
37508
38255
|
e: this.e,
|
|
37509
38256
|
Detail_Data: buildDouyinWorkDetail(aweme, { user_info: userProfile.data }),
|
|
@@ -37531,7 +38278,7 @@ var DouYin = class DouYin extends Base {
|
|
|
37531
38278
|
Type: isArticle ? "文章" : isVideo ? "视频" : this.is_slides ? "合辑" : "图集",
|
|
37532
38279
|
CommentsData: douyinCommentsRes.CommentsData,
|
|
37533
38280
|
CommentLength: douyinCommentsRes.CommentsData.length ?? 0,
|
|
37534
|
-
share_url: isVideo && selectedVideo ? buildDouyinPlayUrl(selectedVideo.play_addr) : `https://www.douyin.com/${isArticle ? "article" : "note"}/${aweme.aweme_id}
|
|
38281
|
+
share_url: await toDouyinShortUrl(isVideo && selectedVideo ? buildDouyinPlayUrl(selectedVideo.play_addr) : `https://www.douyin.com/${isArticle ? "article" : "note"}/${aweme.aweme_id}`),
|
|
37535
38282
|
VideoSize: mp4size,
|
|
37536
38283
|
VideoFPS: FPS,
|
|
37537
38284
|
ImageLength: imagenum,
|
|
@@ -37689,28 +38436,17 @@ var DouYin = class DouYin extends Base {
|
|
|
37689
38436
|
if (context) {
|
|
37690
38437
|
const num = parseInt(context.msg.trim());
|
|
37691
38438
|
if (!isNaN(num) && num >= 1 && num <= displayVideos.length) {
|
|
37692
|
-
const
|
|
37693
|
-
|
|
37694
|
-
let successTimer = null;
|
|
37695
|
-
await emojiManager.add("EYES");
|
|
37696
|
-
processingTimer = setTimeout(() => {
|
|
37697
|
-
emojiManager.add("PROCESSING").catch(() => {});
|
|
37698
|
-
}, 1500);
|
|
38439
|
+
const emojiFlow = createEmojiReactionFlow(context);
|
|
38440
|
+
await emojiFlow.begin();
|
|
37699
38441
|
try {
|
|
37700
38442
|
const targetData = {
|
|
37701
38443
|
type: "one_work",
|
|
37702
38444
|
aweme_id: displayVideos[num - 1].aweme_id
|
|
37703
38445
|
};
|
|
37704
38446
|
await new DouYin(context, targetData).DouyinHandler(targetData);
|
|
37705
|
-
|
|
37706
|
-
emojiManager.replace("PROCESSING", "SUCCESS").catch(() => {});
|
|
37707
|
-
}, 1500);
|
|
38447
|
+
await emojiFlow.succeed();
|
|
37708
38448
|
} catch (error) {
|
|
37709
|
-
|
|
37710
|
-
if (successTimer) clearTimeout(successTimer);
|
|
37711
|
-
const processingEmojiId = getEmojiId(context, "PROCESSING");
|
|
37712
|
-
if (emojiManager.has(processingEmojiId)) await emojiManager.remove("PROCESSING");
|
|
37713
|
-
await emojiManager.add("ERROR");
|
|
38449
|
+
await emojiFlow.fail();
|
|
37714
38450
|
throw error;
|
|
37715
38451
|
}
|
|
37716
38452
|
}
|
|
@@ -37775,6 +38511,7 @@ var DouYin = class DouYin extends Base {
|
|
|
37775
38511
|
title: mixInfo.mix_name,
|
|
37776
38512
|
platform: "douyin",
|
|
37777
38513
|
scene: this.e.isFriend ? "friend" : "group",
|
|
38514
|
+
ownerId: this.e.userId,
|
|
37778
38515
|
poster,
|
|
37779
38516
|
posterPage: initialPage,
|
|
37780
38517
|
renderPoster,
|
|
@@ -37797,55 +38534,79 @@ var DouYin = class DouYin extends Base {
|
|
|
37797
38534
|
/** 上一页海报消息,翻页发送成功后撤回,避免聊天里堆一串过期海报 */
|
|
37798
38535
|
let posterMessageId = "";
|
|
37799
38536
|
let posterMessageSentAt = 0;
|
|
37800
|
-
|
|
37801
|
-
|
|
37802
|
-
|
|
37803
|
-
|
|
37804
|
-
|
|
37805
|
-
|
|
37806
|
-
|
|
37807
|
-
|
|
37808
|
-
|
|
37809
|
-
|
|
37810
|
-
|
|
37811
|
-
|
|
37812
|
-
|
|
37813
|
-
|
|
37814
|
-
|
|
37815
|
-
|
|
37816
|
-
|
|
37817
|
-
|
|
37818
|
-
|
|
37819
|
-
|
|
37820
|
-
|
|
37821
|
-
|
|
37822
|
-
|
|
37823
|
-
|
|
37824
|
-
|
|
37825
|
-
|
|
37826
|
-
|
|
37827
|
-
|
|
37828
|
-
|
|
37829
|
-
|
|
37830
|
-
|
|
38537
|
+
/** 子上下文消息的表情反馈流程:翻页时留到新海报发出后再算成功 */
|
|
38538
|
+
let emojiFlow = null;
|
|
38539
|
+
try {
|
|
38540
|
+
for (;;) {
|
|
38541
|
+
const poster = await renderPoster(posterPage);
|
|
38542
|
+
const start = (posterPage - 1) * 15;
|
|
38543
|
+
const pageEpisodes = displayEpisodes.slice(start, start + 15);
|
|
38544
|
+
const firstEpisode = pageEpisodes[0]?.episode ?? 0;
|
|
38545
|
+
const lastEpisode = pageEpisodes[pageEpisodes.length - 1]?.episode ?? 0;
|
|
38546
|
+
const range = firstEpisode === lastEpisode ? `第 ${firstEpisode} 集` : `第 ${firstEpisode}–${lastEpisode} 集`;
|
|
38547
|
+
const sentAt = Date.now();
|
|
38548
|
+
const result = await this.e.reply([...poster, segment.text(`《${mixInfo.mix_name}》\n${range}(共 ${totalEpisode} 集,已列出 ${displayEpisodes.length} 集)\n第 ${posterPage}/${posterPageCount} 页\n发送 第?集 选集${posterPageCount > 1 ? ",发送 上一页 / 下一页 / 第?页 翻页" : ""}(${timeoutSeconds} 秒内有效)`)]);
|
|
38549
|
+
if (emojiFlow) {
|
|
38550
|
+
await emojiFlow.succeed();
|
|
38551
|
+
settleEmojiReaction(this.e);
|
|
38552
|
+
emojiFlow = null;
|
|
38553
|
+
}
|
|
38554
|
+
const previousMessageId = posterMessageId;
|
|
38555
|
+
const previousMessageSentAt = posterMessageSentAt;
|
|
38556
|
+
posterMessageId = result.messageId;
|
|
38557
|
+
posterMessageSentAt = result.messageId ? sentAt : 0;
|
|
38558
|
+
if (previousMessageId && canRecallEpisodeMessage(previousMessageId, previousMessageSentAt)) try {
|
|
38559
|
+
await this.e.bot.recallMsg(this.e.contact, previousMessageId);
|
|
38560
|
+
} catch (error) {
|
|
38561
|
+
logger.debug("[选集] 撤回上一页失败:", error);
|
|
38562
|
+
}
|
|
38563
|
+
const context = await karin.ctx(this.e, {
|
|
38564
|
+
reply: true,
|
|
38565
|
+
throwOnTimeout: false,
|
|
38566
|
+
time: timeoutSeconds
|
|
38567
|
+
});
|
|
38568
|
+
if (!context) return true;
|
|
38569
|
+
const replyText = context.msg.trim();
|
|
38570
|
+
if (/^[#/]/.test(replyText) || /(https?:\/\/|b23\.tv|bilibili\.com|douyin\.com|iesdouyin\.com)/i.test(replyText)) return true;
|
|
38571
|
+
emojiFlow = createEmojiReactionFlow(context);
|
|
38572
|
+
await emojiFlow.begin();
|
|
38573
|
+
const pageAction = parseEpisodePosterPageAction(context.msg);
|
|
38574
|
+
if (pageAction) {
|
|
38575
|
+
const nextPage = pageAction.type === "prev" ? posterPage - 1 : pageAction.type === "next" ? posterPage + 1 : pageAction.page;
|
|
38576
|
+
if (nextPage < 1 || nextPage > posterPageCount) {
|
|
38577
|
+
await this.e.reply(`页码超出范围,请发送 1-${posterPageCount} 之间的页码`);
|
|
38578
|
+
await emojiFlow.fail();
|
|
38579
|
+
settleEmojiReaction(this.e);
|
|
38580
|
+
emojiFlow = null;
|
|
38581
|
+
continue;
|
|
38582
|
+
}
|
|
38583
|
+
posterPage = nextPage;
|
|
37831
38584
|
continue;
|
|
37832
38585
|
}
|
|
37833
|
-
|
|
37834
|
-
|
|
37835
|
-
|
|
37836
|
-
|
|
37837
|
-
|
|
37838
|
-
|
|
37839
|
-
|
|
37840
|
-
|
|
38586
|
+
const episode = parseEpisodeNumber(context.msg);
|
|
38587
|
+
const target = episode === null ? void 0 : displayEpisodes.find((item) => item.episode === episode);
|
|
38588
|
+
if (!target) {
|
|
38589
|
+
await this.e.reply(episode === null ? "匹配内容失败,请发送 第?集 选择集数,或发送 上一页 / 下一页 / 第?页 翻页" : `第${episode}集不在可解析的剧集里,请重新选择`);
|
|
38590
|
+
await emojiFlow.fail();
|
|
38591
|
+
settleEmojiReaction(this.e);
|
|
38592
|
+
emojiFlow = null;
|
|
38593
|
+
continue;
|
|
38594
|
+
}
|
|
38595
|
+
const episodeTitle = (isPlaylet ? mixInfo.mix_name : target.title || mixInfo.mix_name).replace(/\s+/g, " ").trim();
|
|
38596
|
+
await this.e.reply(`收到请求,第${episode}集\n${episodeTitle}\n正在解析中`);
|
|
38597
|
+
const targetData = {
|
|
38598
|
+
type: "one_work",
|
|
38599
|
+
aweme_id: target.aweme_id
|
|
38600
|
+
};
|
|
38601
|
+
await new DouYin(context, targetData, { forceBurnDanmaku: this.forceBurnDanmaku }).DouyinHandler(targetData);
|
|
38602
|
+
await emojiFlow.succeed();
|
|
38603
|
+
settleEmojiReaction(this.e);
|
|
38604
|
+
emojiFlow = null;
|
|
38605
|
+
return true;
|
|
37841
38606
|
}
|
|
37842
|
-
|
|
37843
|
-
|
|
37844
|
-
|
|
37845
|
-
aweme_id: target.aweme_id
|
|
37846
|
-
};
|
|
37847
|
-
await new DouYin(context, targetData, { forceBurnDanmaku: this.forceBurnDanmaku }).DouyinHandler(targetData);
|
|
37848
|
-
return true;
|
|
38607
|
+
} catch (error) {
|
|
38608
|
+
if (emojiFlow) await emojiFlow.fail();
|
|
38609
|
+
throw error;
|
|
37849
38610
|
}
|
|
37850
38611
|
}
|
|
37851
38612
|
case "music_work": {
|
|
@@ -38305,26 +39066,6 @@ async function processRecommendList(contentList, sec_uid, userinfo, item, target
|
|
|
38305
39066
|
return result;
|
|
38306
39067
|
}
|
|
38307
39068
|
//#endregion
|
|
38308
|
-
//#region src/platform/douyin/shortUrl.ts
|
|
38309
|
-
/**
|
|
38310
|
-
* 把分享链接换成抖音签发的 `v.douyin.com` 短链(二维码专用)。
|
|
38311
|
-
*
|
|
38312
|
-
* 短链由 amagi 的 `douyin.shortUrl` 端点签发:同一 target 恒得同一短码,
|
|
38313
|
-
* 内容比任何规范链接都短,能明显降低二维码密度。该端点免登录但仍要 `a_bogus` 签名,
|
|
38314
|
-
* 可能因签名或平台策略失败 —— 失败不阻塞推送,回退原链接即可。
|
|
38315
|
-
* @param target - 待缩短的分享链接(规范链接或视频直链均可)
|
|
38316
|
-
* @returns 短链;签发失败时原样返回 target
|
|
38317
|
-
*/
|
|
38318
|
-
var toDouyinShortUrl = async (target) => {
|
|
38319
|
-
try {
|
|
38320
|
-
const shortUrl = (await douyinFetcher.fetchShortUrl({ target })).data?.data;
|
|
38321
|
-
return typeof shortUrl === "string" && shortUrl.length > 0 ? shortUrl : target;
|
|
38322
|
-
} catch (error) {
|
|
38323
|
-
logger$1.debug(`[抖音短链] 签发失败,二维码回退原链接:${error instanceof Error ? error.message : String(error)}`);
|
|
38324
|
-
return target;
|
|
38325
|
-
}
|
|
38326
|
-
};
|
|
38327
|
-
//#endregion
|
|
38328
39069
|
//#region src/platform/douyin/push.ts
|
|
38329
39070
|
var douyinBaseHeaders = {
|
|
38330
39071
|
...BASE_HEADERS,
|
|
@@ -42466,6 +43207,10 @@ var handleEpisodeSelection = wrapWithErrorHandler(async (e, next) => {
|
|
|
42466
43207
|
await e.reply("本次选集已结束,请重新发送原链接", { at: true });
|
|
42467
43208
|
return true;
|
|
42468
43209
|
}
|
|
43210
|
+
if (!isEpisodeSelectionOwner(session, e.userId)) {
|
|
43211
|
+
await e.reply("这次选集只对发起人生效,请自己发送原链接", { at: true });
|
|
43212
|
+
return true;
|
|
43213
|
+
}
|
|
42469
43214
|
if (!actionText) {
|
|
42470
43215
|
await e.reply("请点击下方按钮,或点击「跳转到第x页」输入页码");
|
|
42471
43216
|
return true;
|