karin-plugin-kkk 2.45.2-beta.3 → 2.45.2
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 +32 -0
- package/lib/build-metadata.json +5 -5
- package/lib/core_chunk/default.js +1 -1
- package/lib/core_chunk/main.js +1633 -869
- 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 +2 -2
- 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,724 @@ 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
|
+
/** 版权番剧没有 up_info 时,从制作人员里取制作公司:优先「动画制作」,其次「制作/製作」 */
|
|
12006
|
+
var parseMaker = (raw) => {
|
|
12007
|
+
let fallback = "";
|
|
12008
|
+
for (const line of (raw || "").split(/\r?\n/)) {
|
|
12009
|
+
const match = /^\s*(动画制作公司|动画制作|制作公司|制作|製作)[::]\s*(.+?)\s*$/.exec(line);
|
|
12010
|
+
if (!match) continue;
|
|
12011
|
+
if (/动画制作/.test(match[1])) return match[2];
|
|
12012
|
+
if (!fallback) fallback = match[2];
|
|
12013
|
+
}
|
|
12014
|
+
return fallback;
|
|
12015
|
+
};
|
|
12016
|
+
/** 发布日期统一写成 2026.10.24,等宽数字列对齐,跨年也不歧义 */
|
|
12017
|
+
var formatPubDate = (seconds) => seconds > 0 ? format(/* @__PURE__ */ new Date(seconds * 1e3), "yyyy.MM.dd") : "";
|
|
12018
|
+
/** 按展示顺序(最新在前)写区间;只有一集时写「第 a 集」 */
|
|
12019
|
+
var formatEpisodeRange$1 = (first, last) => first === last ? `第 ${first} 集` : `第 ${first}–${last} 集`;
|
|
12020
|
+
/** 标题按字数分档:短标题撑满版面,长标题收字号换行 */
|
|
12021
|
+
var getTitleClassName$4 = (length) => {
|
|
12022
|
+
if (length <= 6) return "text-[132px] leading-[1.05]";
|
|
12023
|
+
if (length <= 10) return "text-[112px] leading-[1.08]";
|
|
12024
|
+
if (length <= 16) return "text-[96px] leading-[1.1] line-clamp-2";
|
|
12025
|
+
if (length <= 24) return "text-[80px] leading-[1.14] line-clamp-2";
|
|
12026
|
+
return "text-[68px] leading-[1.18] line-clamp-3";
|
|
12027
|
+
};
|
|
12028
|
+
/** 巨型区间数字的字宽系数(字号的倍数,含 -0.04em 字距),按 tabular 数字和短横线的实测宽度取上限 */
|
|
12029
|
+
var RANGE_NUMERAL_ADVANCE$1 = .56;
|
|
12030
|
+
/** 目录页巨型区间数字的字号:按左栏内容宽度和字符数反推,最大 184px,4 位集号的长区间也不会溢出 */
|
|
12031
|
+
var getRangeNumeralSize$1 = (length, compact) => Math.min(184, Math.floor((compact ? 448 : 520) / (Math.max(length, 1) * RANGE_NUMERAL_ADVANCE$1)));
|
|
12032
|
+
/** 背景:封面弥散 + 离散噪点,与兄弟模板同一套图层 */
|
|
12033
|
+
var PosterBackground$1 = ({ src, ctx }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12034
|
+
className: "pointer-events-none absolute inset-0 overflow-hidden select-none",
|
|
12035
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AmbientCover, {
|
|
12036
|
+
src,
|
|
12037
|
+
ctx
|
|
12038
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12039
|
+
className: "absolute inset-0 opacity-[0.35] mix-blend-overlay dark:mix-blend-soft-light",
|
|
12040
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
|
|
12041
|
+
className: "h-full w-full",
|
|
12042
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
12043
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("filter", {
|
|
12044
|
+
id: "bangumiNoise",
|
|
12045
|
+
children: [
|
|
12046
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feTurbulence", {
|
|
12047
|
+
type: "fractalNoise",
|
|
12048
|
+
baseFrequency: "0.8",
|
|
12049
|
+
numOctaves: "2",
|
|
12050
|
+
stitchTiles: "stitch"
|
|
12051
|
+
}),
|
|
12052
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feColorMatrix", {
|
|
12053
|
+
type: "saturate",
|
|
12054
|
+
values: "0"
|
|
12055
|
+
}),
|
|
12056
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("feComponentTransfer", { children: [
|
|
12057
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncR", {
|
|
12058
|
+
type: "discrete",
|
|
12059
|
+
tableValues: "0 1"
|
|
12060
|
+
}),
|
|
12061
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncG", {
|
|
12062
|
+
type: "discrete",
|
|
12063
|
+
tableValues: "0 1"
|
|
12064
|
+
}),
|
|
12065
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncB", {
|
|
12066
|
+
type: "discrete",
|
|
12067
|
+
tableValues: "0 1"
|
|
12068
|
+
})
|
|
12069
|
+
] }),
|
|
12070
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feComponentTransfer", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncA", {
|
|
12071
|
+
type: "linear",
|
|
12072
|
+
slope: "2",
|
|
12073
|
+
intercept: "-0.5"
|
|
12074
|
+
}) })
|
|
12075
|
+
]
|
|
12076
|
+
}) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
|
|
12077
|
+
width: "100%",
|
|
12078
|
+
height: "100%",
|
|
12079
|
+
filter: "url(#bangumiNoise)",
|
|
12080
|
+
fill: "white"
|
|
12081
|
+
})]
|
|
12082
|
+
})
|
|
12083
|
+
})]
|
|
12084
|
+
});
|
|
12085
|
+
/** 刊头:栏目名 + 平台 logo,靠字距和留白收束 */
|
|
12086
|
+
var Masthead$1 = ({ label, ctx }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
|
|
12087
|
+
className: "flex items-center justify-between pb-7",
|
|
12088
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12089
|
+
className: "flex items-center gap-5 text-[26px] font-bold tracking-[0.32em] text-foreground",
|
|
12090
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `h-5 w-5 ${ACCENT_BG}` }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: label })]
|
|
12091
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
|
|
12092
|
+
src: isDark(ctx) ? "/image/bilibili/bilibili-light.png" : "/image/bilibili/bilibili.png",
|
|
12093
|
+
alt: "哔哩哔哩",
|
|
12094
|
+
className: "h-14 w-auto"
|
|
12095
|
+
})]
|
|
12096
|
+
});
|
|
12097
|
+
/** 眉题:强调色小号粗体,用细点分隔 */
|
|
12098
|
+
var Kicker$1 = ({ items }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12099
|
+
className: `flex flex-wrap items-center gap-x-4 text-[30px] font-bold ${ACCENT_TEXT}`,
|
|
12100
|
+
children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.Fragment, { children: [index > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12101
|
+
className: "text-muted",
|
|
12102
|
+
children: "·"
|
|
12103
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: item })] }, `${index}-${item}`))
|
|
12104
|
+
});
|
|
12105
|
+
/** 数据栏:四格铺在浅色面板上,用留白代替分隔线,小标签 + 粗体大数字 + 小单位 */
|
|
12106
|
+
var Ledger$1 = ({ items }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12107
|
+
className: "grid grid-cols-4 gap-x-10 rounded-3xl bg-foreground/5 px-10 py-8",
|
|
12108
|
+
children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12109
|
+
className: "text-[24px] font-medium text-foreground/65",
|
|
12110
|
+
children: item.label
|
|
12111
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12112
|
+
className: "mt-1 flex items-baseline gap-1.5 text-foreground",
|
|
12113
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12114
|
+
className: "text-[60px] leading-none font-black tabular-nums",
|
|
12115
|
+
children: item.value
|
|
12116
|
+
}), item.unit && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12117
|
+
className: "text-[26px] font-bold",
|
|
12118
|
+
children: item.unit
|
|
12119
|
+
})]
|
|
12120
|
+
})] }, item.label))
|
|
12121
|
+
});
|
|
12122
|
+
/** 演职员栏的一行:左侧小标签,右侧内容 */
|
|
12123
|
+
var CreditRow = ({ label, children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12124
|
+
className: "flex gap-6",
|
|
12125
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
|
|
12126
|
+
className: "w-16 shrink-0 pt-0.5 text-[24px] font-bold text-foreground/65",
|
|
12127
|
+
children: label
|
|
12128
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", {
|
|
12129
|
+
className: "min-w-0 flex-1 text-[26px] leading-[1.55] text-foreground",
|
|
12130
|
+
children
|
|
12131
|
+
})]
|
|
12132
|
+
});
|
|
12133
|
+
/** 专题 hero:左封面,右眉题 / 大标题 / 类型 / 简介 / 演职员栏 */
|
|
12134
|
+
var Hero$1 = ({ data }) => {
|
|
12135
|
+
const credits = parseCredits(data.Actors);
|
|
12136
|
+
const shownCast = credits.cast.slice(0, CAST_LIMIT);
|
|
12137
|
+
const shownExtras = shownCast.length > 0 ? [] : credits.extras.slice(0, CAST_LIMIT);
|
|
12138
|
+
const shownCount = shownCast.length + shownExtras.length;
|
|
12139
|
+
const statusParts = (data.newEP?.desc || "").split(/[,,]/).map((part) => part.trim()).filter(Boolean);
|
|
12140
|
+
const copyright = COPYRIGHT_LABEL[data.Copyright];
|
|
12141
|
+
const kicker = [
|
|
12142
|
+
"番剧",
|
|
12143
|
+
...copyright ? [copyright] : [],
|
|
12144
|
+
...statusParts
|
|
12145
|
+
];
|
|
12146
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12147
|
+
className: "flex items-stretch gap-16",
|
|
12148
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12149
|
+
className: "relative min-h-146.75 w-110 shrink-0 overflow-hidden rounded-8xl bg-surface-secondary shadow-2xl shadow-black/20",
|
|
12150
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12151
|
+
className: "absolute inset-0",
|
|
12152
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
12153
|
+
src: data.mainCover,
|
|
12154
|
+
alt: data.Title,
|
|
12155
|
+
className: "h-full w-full object-cover"
|
|
12156
|
+
})
|
|
12157
|
+
})
|
|
12158
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12159
|
+
className: "flex min-w-0 flex-1 flex-col",
|
|
12160
|
+
children: [
|
|
12161
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Kicker$1, { items: kicker }),
|
|
12162
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
|
|
12163
|
+
className: `mt-5 font-black tracking-tight text-balance text-foreground ${getTitleClassName$4(data.Title.length)}`,
|
|
12164
|
+
children: data.Title
|
|
12165
|
+
}),
|
|
12166
|
+
data.Styles.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12167
|
+
className: "mt-3 text-[30px] font-medium text-foreground/70",
|
|
12168
|
+
children: data.Styles.join(" / ")
|
|
12169
|
+
}),
|
|
12170
|
+
data.Evaluate && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
12171
|
+
className: "mt-5 line-clamp-3 text-[30px] leading-[1.55] font-light text-foreground/80",
|
|
12172
|
+
children: data.Evaluate
|
|
12173
|
+
}),
|
|
12174
|
+
(shownCount > 0 || credits.staff.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12175
|
+
className: "mt-auto pt-8",
|
|
12176
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("dl", {
|
|
12177
|
+
className: "flex flex-col gap-2.5 pt-6",
|
|
12178
|
+
children: [shownCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CreditRow, {
|
|
12179
|
+
label: "声优",
|
|
12180
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
12181
|
+
className: "flex flex-wrap gap-x-7",
|
|
11863
12182
|
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"
|
|
12183
|
+
shownCast.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
12184
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12185
|
+
className: "text-foreground/60",
|
|
12186
|
+
children: item.role
|
|
12187
|
+
}),
|
|
12188
|
+
" ",
|
|
12189
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12190
|
+
className: "font-bold",
|
|
12191
|
+
children: item.actor
|
|
11877
12192
|
})
|
|
12193
|
+
] }, `${item.role}-${item.actor}`)),
|
|
12194
|
+
shownExtras.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12195
|
+
className: "font-bold",
|
|
12196
|
+
children: shownExtras.join("、")
|
|
11878
12197
|
}),
|
|
11879
|
-
|
|
11880
|
-
|
|
11881
|
-
|
|
11882
|
-
|
|
11883
|
-
|
|
11884
|
-
|
|
11885
|
-
|
|
11886
|
-
},
|
|
11887
|
-
children: props.upInfo.vip_label.text
|
|
12198
|
+
credits.voiceCount > shownCount && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
12199
|
+
className: "text-foreground/60",
|
|
12200
|
+
children: [
|
|
12201
|
+
"等 ",
|
|
12202
|
+
credits.voiceCount,
|
|
12203
|
+
" 人"
|
|
12204
|
+
]
|
|
11888
12205
|
})
|
|
11889
12206
|
]
|
|
11890
|
-
})
|
|
11891
|
-
|
|
11892
|
-
|
|
11893
|
-
|
|
11894
|
-
|
|
11895
|
-
|
|
11896
|
-
|
|
11897
|
-
|
|
11898
|
-
|
|
11899
|
-
|
|
11900
|
-
|
|
11901
|
-
|
|
12207
|
+
})
|
|
12208
|
+
}), credits.staff.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CreditRow, {
|
|
12209
|
+
label: "制作",
|
|
12210
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12211
|
+
className: "flex flex-wrap gap-x-7",
|
|
12212
|
+
children: credits.staff.slice(0, 3).map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
12213
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12214
|
+
className: "text-foreground/60",
|
|
12215
|
+
children: item.role
|
|
12216
|
+
}),
|
|
12217
|
+
" ",
|
|
12218
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12219
|
+
className: "font-bold",
|
|
12220
|
+
children: item.name
|
|
11902
12221
|
})
|
|
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] })]
|
|
12222
|
+
] }, `${item.role}-${item.name}`))
|
|
11908
12223
|
})
|
|
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
12224
|
})]
|
|
11960
12225
|
})
|
|
11961
|
-
|
|
11962
|
-
|
|
12226
|
+
})
|
|
12227
|
+
]
|
|
12228
|
+
})]
|
|
12229
|
+
});
|
|
12230
|
+
};
|
|
12231
|
+
/** 可执行命令:统一实心高对比 chip */
|
|
12232
|
+
var CommandChip$1 = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12233
|
+
className: "inline-flex h-15 items-center rounded-2xl px-6 text-[30px] font-bold whitespace-nowrap text-white shadow-lg shadow-black/15",
|
|
12234
|
+
style: { backgroundColor: CHIP_BG$1 },
|
|
12235
|
+
children
|
|
12236
|
+
});
|
|
12237
|
+
/** 有效期说明:两种模式共用;主句加粗,补充说明降一档。只有一页时没有翻页,不提重新计时 */
|
|
12238
|
+
var ValidityNote$1 = ({ seconds, pageCount }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12239
|
+
className: "flex items-start gap-3 text-[26px] leading-snug",
|
|
12240
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Timer, {
|
|
12241
|
+
className: "mt-0.5 h-7 w-7 shrink-0 text-foreground/70",
|
|
12242
|
+
strokeWidth: 2.2
|
|
12243
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12244
|
+
className: "font-bold text-foreground",
|
|
12245
|
+
children: [
|
|
12246
|
+
seconds,
|
|
12247
|
+
" 秒内有效",
|
|
12248
|
+
pageCount > 1 && ",翻页重新计时"
|
|
12249
|
+
]
|
|
12250
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12251
|
+
className: "mt-0.5 text-foreground/65",
|
|
12252
|
+
children: "过期请重新发送原链接"
|
|
12253
|
+
})] })]
|
|
12254
|
+
});
|
|
12255
|
+
/** 文字命令模式:只列出当前页真正能用的命令;后端也认纯数字集号,用本页第一集举例 */
|
|
12256
|
+
var TextGuide$1 = ({ first, page, pageCount, seconds }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12257
|
+
className: "flex flex-col gap-5",
|
|
12258
|
+
children: [
|
|
12259
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12260
|
+
className: "text-[34px] font-black text-foreground",
|
|
12261
|
+
children: "回复文字选集"
|
|
12262
|
+
}),
|
|
12263
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12264
|
+
className: "flex items-center gap-5",
|
|
12265
|
+
children: [
|
|
12266
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12267
|
+
className: "w-19 shrink-0 text-[28px] font-bold text-foreground",
|
|
12268
|
+
children: "选集"
|
|
12269
|
+
}),
|
|
12270
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12271
|
+
className: "text-[26px] text-foreground/65",
|
|
12272
|
+
children: "发送"
|
|
12273
|
+
}),
|
|
12274
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip$1, { children: "第?集" }),
|
|
12275
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
12276
|
+
className: "text-[26px] text-foreground/65",
|
|
12277
|
+
children: ["也可只发集号,如 ", first]
|
|
12278
|
+
})
|
|
12279
|
+
]
|
|
12280
|
+
}),
|
|
12281
|
+
pageCount > 1 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12282
|
+
className: "flex items-center gap-5",
|
|
12283
|
+
children: [
|
|
12284
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12285
|
+
className: "w-19 shrink-0 text-[28px] font-bold text-foreground",
|
|
12286
|
+
children: "翻页"
|
|
12287
|
+
}),
|
|
12288
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12289
|
+
className: "text-[26px] text-foreground/65",
|
|
12290
|
+
children: "发送"
|
|
12291
|
+
}),
|
|
12292
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12293
|
+
className: "flex flex-wrap gap-3",
|
|
11963
12294
|
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
|
-
})
|
|
12295
|
+
page > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip$1, { children: "上一页" }),
|
|
12296
|
+
page < pageCount && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip$1, { children: "下一页" }),
|
|
12297
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip$1, { children: "第?页" })
|
|
12028
12298
|
]
|
|
12029
|
-
})
|
|
12299
|
+
})
|
|
12300
|
+
]
|
|
12301
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12302
|
+
className: "flex items-center gap-5",
|
|
12303
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12304
|
+
className: "w-19 shrink-0 text-[28px] font-bold text-foreground",
|
|
12305
|
+
children: "翻页"
|
|
12306
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12307
|
+
className: "text-[26px] text-foreground/65",
|
|
12308
|
+
children: "只有这一页,无需翻页"
|
|
12030
12309
|
})]
|
|
12310
|
+
}),
|
|
12311
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidityNote$1, {
|
|
12312
|
+
seconds,
|
|
12313
|
+
pageCount
|
|
12031
12314
|
})
|
|
12032
|
-
|
|
12033
|
-
};
|
|
12034
|
-
/**
|
|
12035
|
-
var
|
|
12036
|
-
className: "
|
|
12315
|
+
]
|
|
12316
|
+
});
|
|
12317
|
+
/** 键盘示意里的一枚按钮:数字键与「跳转」是蓝框键(style 1),翻页是灰框键;small 给 4 位集号用 */
|
|
12318
|
+
var SketchKey$1 = ({ children, quiet, small }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12319
|
+
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
12320
|
children
|
|
12038
12321
|
});
|
|
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} 集`;
|
|
12322
|
+
/** 按钮模式的键盘示意:只画本页真实存在的按钮,排布与 QQBot 键盘一致;宽度固定,4 位集号收小字号,左侧说明不被挤到换行 */
|
|
12323
|
+
var KeySketch$1 = ({ numbers, page, pageCount }) => {
|
|
12324
|
+
const rows = [];
|
|
12325
|
+
for (let index = 0; index < numbers.length; index += KEYS_PER_ROW$1) rows.push(numbers.slice(index, index + KEYS_PER_ROW$1));
|
|
12326
|
+
const navigation = [page > 1 ? "上一页" : "", page < pageCount ? "下一页" : ""].filter(Boolean);
|
|
12327
|
+
const small = numbers.some((number) => number >= 1e3);
|
|
12056
12328
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12057
|
-
className: "
|
|
12329
|
+
className: "flex w-82.5 shrink-0 flex-col gap-1.5 self-start rounded-3xl bg-surface/60 p-3",
|
|
12330
|
+
children: [
|
|
12331
|
+
pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SketchKey$1, { children: "跳转到第x页" }),
|
|
12332
|
+
rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12333
|
+
className: "flex gap-1.5",
|
|
12334
|
+
children: row.map((number) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SketchKey$1, {
|
|
12335
|
+
small,
|
|
12336
|
+
children: number
|
|
12337
|
+
}, number))
|
|
12338
|
+
}, row[0])),
|
|
12339
|
+
navigation.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12340
|
+
className: "flex gap-1.5",
|
|
12341
|
+
children: navigation.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SketchKey$1, {
|
|
12342
|
+
quiet: true,
|
|
12343
|
+
children: label
|
|
12344
|
+
}, label))
|
|
12345
|
+
})
|
|
12346
|
+
]
|
|
12347
|
+
});
|
|
12348
|
+
};
|
|
12349
|
+
/** 按钮模式:引导点按钮,不出现任何手打命令 */
|
|
12350
|
+
var ButtonGuide$1 = ({ numbers, page, pageCount, seconds }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12351
|
+
className: "flex gap-6",
|
|
12352
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12353
|
+
className: "flex min-w-0 flex-1 flex-col gap-4",
|
|
12058
12354
|
children: [
|
|
12059
12355
|
/* @__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
|
-
]
|
|
12356
|
+
className: "flex items-center gap-3 text-[34px] font-black text-foreground",
|
|
12357
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MousePointerClick, {
|
|
12358
|
+
className: `h-9 w-9 shrink-0 ${ACCENT_TEXT}`,
|
|
12359
|
+
strokeWidth: 2.4
|
|
12360
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "点击下方按钮选集" })]
|
|
12080
12361
|
}),
|
|
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
|
-
})]
|
|
12362
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("ul", {
|
|
12363
|
+
className: "flex flex-col gap-2 text-[26px] leading-snug text-foreground/80",
|
|
12364
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: "数字键即集号,点一下直接解析" }), pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: "「跳转到第x页」补上页码再发送" })]
|
|
12108
12365
|
}),
|
|
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
|
-
})
|
|
12366
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidityNote$1, {
|
|
12367
|
+
seconds,
|
|
12368
|
+
pageCount
|
|
12158
12369
|
})
|
|
12159
12370
|
]
|
|
12371
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(KeySketch$1, {
|
|
12372
|
+
numbers,
|
|
12373
|
+
page,
|
|
12374
|
+
pageCount
|
|
12375
|
+
})]
|
|
12376
|
+
});
|
|
12377
|
+
/** 目录页开篇:巨型区间数字 + 操作说明 */
|
|
12378
|
+
var Contents$1 = ({ items, page, pageCount, mode, seconds }) => {
|
|
12379
|
+
const first = items[0]?.number ?? 0;
|
|
12380
|
+
const last = items[items.length - 1]?.number ?? 0;
|
|
12381
|
+
const numeral = first === last ? `${first}` : `${first}–${last}`;
|
|
12382
|
+
const compact = mode === "button";
|
|
12383
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12384
|
+
className: "flex items-end justify-between",
|
|
12385
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12386
|
+
className: "flex items-baseline gap-5",
|
|
12387
|
+
children: [
|
|
12388
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `h-6 w-6 self-center ${ACCENT_BG}` }),
|
|
12389
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
|
|
12390
|
+
className: "text-[72px] leading-none font-black text-foreground",
|
|
12391
|
+
children: "选集"
|
|
12392
|
+
}),
|
|
12393
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12394
|
+
className: "text-[24px] font-bold tracking-[0.3em] text-foreground/55",
|
|
12395
|
+
children: "CONTENTS"
|
|
12396
|
+
})
|
|
12397
|
+
]
|
|
12398
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12399
|
+
className: "rounded-full bg-foreground/10 px-7 py-2 text-[34px] font-bold text-foreground tabular-nums",
|
|
12400
|
+
children: [
|
|
12401
|
+
"第 ",
|
|
12402
|
+
page,
|
|
12403
|
+
" / ",
|
|
12404
|
+
pageCount,
|
|
12405
|
+
" 页"
|
|
12406
|
+
]
|
|
12407
|
+
})]
|
|
12408
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12409
|
+
className: "mt-8 flex items-stretch",
|
|
12410
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12411
|
+
className: compact ? "w-120 shrink-0 pr-8" : "w-140 shrink-0 pr-10",
|
|
12412
|
+
children: [
|
|
12413
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12414
|
+
className: "leading-[0.84] font-light tracking-[-0.04em] whitespace-nowrap text-foreground tabular-nums",
|
|
12415
|
+
style: { fontSize: getRangeNumeralSize$1(numeral.length, compact) },
|
|
12416
|
+
children: numeral
|
|
12417
|
+
}),
|
|
12418
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12419
|
+
className: "mt-6 text-[30px] leading-snug font-bold text-foreground",
|
|
12420
|
+
children: formatEpisodeRange$1(first, last)
|
|
12421
|
+
}),
|
|
12422
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12423
|
+
className: "mt-1 flex items-center gap-2.5 text-[28px] font-bold text-foreground",
|
|
12424
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowDownWideNarrow, {
|
|
12425
|
+
className: `h-8 w-8 shrink-0 ${ACCENT_TEXT}`,
|
|
12426
|
+
strokeWidth: 2.4
|
|
12427
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "最新在前" })]
|
|
12428
|
+
})
|
|
12429
|
+
]
|
|
12430
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12431
|
+
className: "min-w-0 flex-1 pl-10",
|
|
12432
|
+
children: mode === "button" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ButtonGuide$1, {
|
|
12433
|
+
numbers: items.map((item) => item.number),
|
|
12434
|
+
page,
|
|
12435
|
+
pageCount,
|
|
12436
|
+
seconds
|
|
12437
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextGuide$1, {
|
|
12438
|
+
first,
|
|
12439
|
+
page,
|
|
12440
|
+
pageCount,
|
|
12441
|
+
seconds
|
|
12442
|
+
})
|
|
12443
|
+
})]
|
|
12444
|
+
})] });
|
|
12445
|
+
};
|
|
12446
|
+
/** 集号栏:按本页最大位数取宽度,同一页标题左缘对齐;4 位集号降字号,不挤占标题 */
|
|
12447
|
+
var NUMBER_COLUMN_CLASS = [
|
|
12448
|
+
"min-w-14 text-[80px]",
|
|
12449
|
+
"min-w-26 text-[80px]",
|
|
12450
|
+
"min-w-37.5 text-[80px]",
|
|
12451
|
+
"min-w-37 text-[60px]"
|
|
12452
|
+
];
|
|
12453
|
+
/** 选集单元:封面右上角是 B 站徽标,下方大集号在左,标题两行 + 日期作说明文字 */
|
|
12454
|
+
var BangumiCell = ({ item, dark, numberClassName }) => {
|
|
12455
|
+
const { episode, number } = item;
|
|
12456
|
+
const badge = episode.badge || episode.badge_info?.text || "";
|
|
12457
|
+
const badgeColor = (dark ? episode.badge_info?.bg_color_night || episode.badge_info?.bg_color : episode.badge_info?.bg_color) || BADGE_FALLBACK;
|
|
12458
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12459
|
+
className: "min-w-0",
|
|
12460
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12461
|
+
className: "relative aspect-video overflow-hidden rounded-3xl bg-surface-secondary shadow-lg shadow-black/10",
|
|
12462
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
12463
|
+
src: episode.cover,
|
|
12464
|
+
alt: episode.long_title || `第 ${number} 集`,
|
|
12465
|
+
className: "h-full w-full object-cover"
|
|
12466
|
+
}), badge && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12467
|
+
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",
|
|
12468
|
+
style: { backgroundColor: badgeColor },
|
|
12469
|
+
children: badge
|
|
12470
|
+
})]
|
|
12471
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12472
|
+
className: "mt-4 flex gap-4",
|
|
12473
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12474
|
+
className: `shrink-0 leading-[0.9] font-black tracking-tight text-foreground tabular-nums ${numberClassName}`,
|
|
12475
|
+
children: number
|
|
12476
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12477
|
+
className: "min-w-0 flex-1 pt-0.5",
|
|
12478
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12479
|
+
className: "line-clamp-2 text-[30px] leading-tight font-bold text-pretty text-foreground",
|
|
12480
|
+
children: episode.long_title || `第 ${number} 集`
|
|
12481
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12482
|
+
className: "mt-1 font-mono text-[26px] leading-tight text-foreground/65",
|
|
12483
|
+
children: formatPubDate(episode.pub_time)
|
|
12484
|
+
})]
|
|
12485
|
+
})]
|
|
12486
|
+
})]
|
|
12487
|
+
});
|
|
12488
|
+
};
|
|
12489
|
+
/** 最后一页不满一行时的收尾块:说明最新剧集在哪一页,并给出往回翻的方式 */
|
|
12490
|
+
var EndCard$1 = ({ span, listed, pageCount, mode }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12491
|
+
className: `${COL_SPAN$1[span] ?? "col-span-1"} flex flex-col justify-center self-stretch rounded-3xl bg-foreground/5 p-9`,
|
|
12492
|
+
children: [
|
|
12493
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12494
|
+
className: "flex items-center gap-4 text-[40px] leading-tight font-black text-foreground",
|
|
12495
|
+
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 ? "已是最后一页" : "只有这一页" })]
|
|
12496
|
+
}),
|
|
12497
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
12498
|
+
className: "mt-4 text-[28px] leading-normal text-foreground/75",
|
|
12499
|
+
children: pageCount > 1 ? "最新的剧集在第 1 页" : `共 ${listed} 集`
|
|
12500
|
+
}),
|
|
12501
|
+
pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12502
|
+
className: "flex flex-wrap items-center gap-3 pt-6 text-[28px] text-foreground/70",
|
|
12503
|
+
children: mode === "button" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "点键盘「上一页」往回翻" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
12504
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "发送" }),
|
|
12505
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip$1, { children: "上一页" }),
|
|
12506
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "往回翻" })
|
|
12507
|
+
] })
|
|
12508
|
+
})
|
|
12509
|
+
]
|
|
12510
|
+
});
|
|
12511
|
+
/** 选集网格:3 列,标题两行可读;最后一页不满一行时补收尾块 */
|
|
12512
|
+
var EpisodeGrid$1 = ({ items, dark, isLastPage, pageCount, listed, mode }) => {
|
|
12513
|
+
const columns = 3;
|
|
12514
|
+
const remainder = items.length % columns;
|
|
12515
|
+
const fill = isLastPage && remainder > 0 ? columns - remainder : 0;
|
|
12516
|
+
const digits = Math.max(1, ...items.map((item) => `${item.number}`.length));
|
|
12517
|
+
const numberClassName = NUMBER_COLUMN_CLASS[Math.min(digits, 4) - 1];
|
|
12518
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12519
|
+
className: "grid grid-cols-3 gap-x-10 gap-y-11",
|
|
12520
|
+
children: [items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BangumiCell, {
|
|
12521
|
+
item,
|
|
12522
|
+
dark,
|
|
12523
|
+
numberClassName
|
|
12524
|
+
}, `${item.number}-${item.episode.bvid}`)), fill > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EndCard$1, {
|
|
12525
|
+
span: fill,
|
|
12526
|
+
listed,
|
|
12527
|
+
pageCount,
|
|
12528
|
+
mode
|
|
12529
|
+
})]
|
|
12530
|
+
});
|
|
12531
|
+
};
|
|
12532
|
+
/** 版权栏:左侧列出数量、UP 主与 season 号,右侧生成时间 */
|
|
12533
|
+
var Colophon$1 = ({ notes }) => {
|
|
12534
|
+
const [generatedAt] = import_react.useState(() => format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss"));
|
|
12535
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("footer", {
|
|
12536
|
+
className: "flex items-start justify-between gap-10 pt-7 text-[24px] leading-relaxed text-foreground/65",
|
|
12537
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12538
|
+
className: "min-w-0",
|
|
12539
|
+
children: notes.join(" · ")
|
|
12540
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12541
|
+
className: "shrink-0 select-text",
|
|
12542
|
+
children: ["图片生成于: ", generatedAt]
|
|
12543
|
+
})]
|
|
12160
12544
|
});
|
|
12161
12545
|
};
|
|
12162
12546
|
var BangumiBilibili = import_react.memo((props) => {
|
|
12163
|
-
|
|
12547
|
+
const { data, ctx } = props;
|
|
12548
|
+
const dark = isDark(ctx);
|
|
12549
|
+
const total = data.length > 0 ? data.length : data.Episodes.length;
|
|
12550
|
+
const numbered = data.Episodes.map((episode, index) => ({
|
|
12551
|
+
episode,
|
|
12552
|
+
number: episode.episode ?? total - index
|
|
12553
|
+
}));
|
|
12554
|
+
const pageSize = Math.max(1, data.posterPageSize ?? DEFAULT_POSTER_PAGE_SIZE$1);
|
|
12555
|
+
const pageCount = Math.max(1, Math.ceil(numbered.length / pageSize));
|
|
12556
|
+
const page = Math.min(Math.max(1, data.posterPage ?? 1), pageCount);
|
|
12557
|
+
const visible = numbered.slice((page - 1) * pageSize, page * pageSize);
|
|
12558
|
+
const mode = data.selectionMode ?? "text";
|
|
12559
|
+
const seconds = data.timeoutSeconds && data.timeoutSeconds > 0 ? data.timeoutSeconds : DEFAULT_TIMEOUT_SECONDS$1;
|
|
12560
|
+
const follow = parseFollowText(data.Stat.follow_text) ?? {
|
|
12561
|
+
...splitCount$1(data.Stat.favorites),
|
|
12562
|
+
label: "追番"
|
|
12563
|
+
};
|
|
12564
|
+
const ledger = [
|
|
12565
|
+
{
|
|
12566
|
+
label: "播放",
|
|
12567
|
+
...splitCount$1(data.Stat.views)
|
|
12568
|
+
},
|
|
12569
|
+
{
|
|
12570
|
+
label: follow.label,
|
|
12571
|
+
value: follow.value,
|
|
12572
|
+
unit: follow.unit
|
|
12573
|
+
},
|
|
12574
|
+
{
|
|
12575
|
+
label: "弹幕",
|
|
12576
|
+
...splitCount$1(data.Stat.danmakus)
|
|
12577
|
+
},
|
|
12578
|
+
{
|
|
12579
|
+
label: "投币",
|
|
12580
|
+
...splitCount$1(data.Stat.coins)
|
|
12581
|
+
}
|
|
12582
|
+
];
|
|
12583
|
+
const maker = data.UPInfo ? "" : parseMaker(data.Staff ?? "");
|
|
12584
|
+
const upNote = data.UPInfo ? `UP 主 ${data.UPInfo.uname} · 粉丝 ${Object.values(splitCount$1(data.UPInfo.follower)).join("")}` : [maker && `制作 ${maker}`, data.Stat.follow_text].filter(Boolean).join(" · ");
|
|
12585
|
+
const notes = [
|
|
12586
|
+
`已列出 ${numbered.length} 集`,
|
|
12587
|
+
...upNote ? [upNote] : [],
|
|
12588
|
+
...data.seasonID ? [`ss${data.seasonID}`] : []
|
|
12589
|
+
];
|
|
12590
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DefaultLayout, {
|
|
12164
12591
|
...props,
|
|
12165
|
-
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
|
|
12172
|
-
|
|
12173
|
-
|
|
12174
|
-
|
|
12175
|
-
|
|
12176
|
-
|
|
12177
|
-
|
|
12178
|
-
|
|
12179
|
-
|
|
12592
|
+
className: "relative overflow-hidden",
|
|
12593
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PosterBackground$1, {
|
|
12594
|
+
src: data.mainCover,
|
|
12595
|
+
ctx
|
|
12596
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
12597
|
+
className: "relative z-10 px-20 pt-18",
|
|
12598
|
+
children: [
|
|
12599
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Masthead$1, {
|
|
12600
|
+
label: "BILIBILI BANGUMI · EPISODE GUIDE",
|
|
12601
|
+
ctx
|
|
12602
|
+
}),
|
|
12603
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12604
|
+
className: "mt-12",
|
|
12605
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Hero$1, { data })
|
|
12606
|
+
}),
|
|
12607
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12608
|
+
className: "mt-12",
|
|
12609
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Ledger$1, { items: ledger })
|
|
12610
|
+
}),
|
|
12611
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12612
|
+
className: "mt-16",
|
|
12613
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Contents$1, {
|
|
12614
|
+
items: visible,
|
|
12615
|
+
page,
|
|
12616
|
+
pageCount,
|
|
12617
|
+
mode,
|
|
12618
|
+
seconds
|
|
12619
|
+
})
|
|
12620
|
+
}),
|
|
12621
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12622
|
+
className: "mt-12",
|
|
12623
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EpisodeGrid$1, {
|
|
12624
|
+
items: visible,
|
|
12625
|
+
dark,
|
|
12626
|
+
isLastPage: page === pageCount,
|
|
12627
|
+
pageCount,
|
|
12628
|
+
listed: numbered.length,
|
|
12629
|
+
mode
|
|
12630
|
+
})
|
|
12631
|
+
}),
|
|
12632
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12633
|
+
className: "mt-14",
|
|
12634
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Colophon$1, { notes })
|
|
12635
|
+
})
|
|
12636
|
+
]
|
|
12637
|
+
})]
|
|
12180
12638
|
});
|
|
12181
12639
|
});
|
|
12182
12640
|
BangumiBilibili.displayName = "BangumiBilibili";
|
|
@@ -14634,43 +15092,6 @@ var DYNAMIC_TYPE_FORWARD_default = defineTemplate({
|
|
|
14634
15092
|
component: BilibiliForwardDynamic,
|
|
14635
15093
|
validate: (data) => typeof data === "object" && data !== null && typeof data.share_url === "string"
|
|
14636
15094
|
});
|
|
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
15095
|
//#endregion
|
|
14675
15096
|
//#region ktr/template/bilibili/dynamic/DYNAMIC_TYPE_LIVE_RCMD/components/DYNAMIC_TYPE_LIVE_RCMD.tsx
|
|
14676
15097
|
/** B站品牌粉,直播状态徽章 / 脉冲灯 / 均衡器强调条统一使用,与封面取色无关。 */
|
|
@@ -18537,22 +18958,41 @@ var live_default = defineTemplate({
|
|
|
18537
18958
|
//#region ktr/template/douyin/mix/components/Mix.tsx
|
|
18538
18959
|
/** 海报每页展示的集数,和 core 的 EPISODE_SELECTION_PAGE_SIZE 保持一致 */
|
|
18539
18960
|
var DEFAULT_POSTER_PAGE_SIZE = 15;
|
|
18540
|
-
/**
|
|
18961
|
+
/** 选集有效期兜底(秒),正常由 data.timeoutSeconds 下发 */
|
|
18962
|
+
var DEFAULT_TIMEOUT_SECONDS = 120;
|
|
18963
|
+
/** QQBot 键盘每行的数字按钮数,和 core 的 EPISODE_SELECTION_BUTTONS_PER_ROW 保持一致 */
|
|
18964
|
+
var KEYS_PER_ROW = 5;
|
|
18965
|
+
/** 抖音红:眉题、章节方块等装饰的唯一强调色 */
|
|
18966
|
+
var ACCENT = "#FE2C55";
|
|
18967
|
+
/** 命令 chip 底色:同色相压深一档,白字对比度约 4.8:1 */
|
|
18968
|
+
var CHIP_BG = "#E0144C";
|
|
18969
|
+
/** 网格补位块的跨列类名(Tailwind 只认静态字面量) */
|
|
18970
|
+
var COL_SPAN = {
|
|
18971
|
+
1: "col-span-1",
|
|
18972
|
+
2: "col-span-2",
|
|
18973
|
+
3: "col-span-3",
|
|
18974
|
+
4: "col-span-4"
|
|
18975
|
+
};
|
|
18976
|
+
/** 万/亿 计数拆成数值与单位:10 亿以下的亿级两位小数,其余一位,去掉末尾 0(596.0万 → 596万);不足 1 万原样返回 */
|
|
18541
18977
|
var splitCount = (count) => {
|
|
18978
|
+
if (count >= 1e9) return {
|
|
18979
|
+
value: `${Number((count / 1e8).toFixed(1))}`,
|
|
18980
|
+
unit: "亿"
|
|
18981
|
+
};
|
|
18542
18982
|
if (count >= 1e8) return {
|
|
18543
|
-
value: (count / 1e8).toFixed(
|
|
18983
|
+
value: `${Number((count / 1e8).toFixed(2))}`,
|
|
18544
18984
|
unit: "亿"
|
|
18545
18985
|
};
|
|
18546
18986
|
if (count >= 1e4) return {
|
|
18547
|
-
value: (count / 1e4).toFixed(1)
|
|
18987
|
+
value: `${Number((count / 1e4).toFixed(1))}`,
|
|
18548
18988
|
unit: "万"
|
|
18549
18989
|
};
|
|
18550
18990
|
return {
|
|
18551
|
-
value: count.toString(),
|
|
18991
|
+
value: Math.max(0, Math.round(count)).toString(),
|
|
18552
18992
|
unit: ""
|
|
18553
18993
|
};
|
|
18554
18994
|
};
|
|
18555
|
-
/**
|
|
18995
|
+
/** 总时长:不到一小时按分钟,否则按小时保留一位,去掉末尾 0 */
|
|
18556
18996
|
var splitRuntime = (milliseconds) => {
|
|
18557
18997
|
const minutes = Math.round(milliseconds / 6e4);
|
|
18558
18998
|
if (minutes < 60) return {
|
|
@@ -18560,29 +19000,56 @@ var splitRuntime = (milliseconds) => {
|
|
|
18560
19000
|
unit: "分钟"
|
|
18561
19001
|
};
|
|
18562
19002
|
return {
|
|
18563
|
-
value: (minutes / 60).toFixed(1)
|
|
19003
|
+
value: `${Number((minutes / 60).toFixed(1))}`,
|
|
18564
19004
|
unit: "小时"
|
|
18565
19005
|
};
|
|
18566
19006
|
};
|
|
18567
|
-
/** 单集时长 mm:ss */
|
|
19007
|
+
/** 单集时长 m:ss,超过一小时 h:mm:ss */
|
|
18568
19008
|
var formatDuration$4 = (milliseconds) => {
|
|
18569
|
-
const
|
|
18570
|
-
const
|
|
18571
|
-
const
|
|
18572
|
-
|
|
19009
|
+
const total = Math.max(0, Math.round(milliseconds / 1e3));
|
|
19010
|
+
const h = Math.floor(total / 3600);
|
|
19011
|
+
const m = Math.floor(total % 3600 / 60);
|
|
19012
|
+
const s = (total % 60).toString().padStart(2, "0");
|
|
19013
|
+
return h > 0 ? `${h}:${m.toString().padStart(2, "0")}:${s}` : `${m}:${s}`;
|
|
18573
19014
|
};
|
|
18574
|
-
/**
|
|
18575
|
-
var
|
|
18576
|
-
|
|
18577
|
-
|
|
18578
|
-
|
|
18579
|
-
|
|
18580
|
-
|
|
18581
|
-
|
|
18582
|
-
|
|
19015
|
+
/** 缺集说明最多列出的段数,超出折成「等 N 集」 */
|
|
19016
|
+
var MISSING_SEGMENT_LIMIT = 8;
|
|
19017
|
+
/**
|
|
19018
|
+
* 把升序集号写成「17、94、99–230 集」:连续 3 个及以上压成区间,两个相邻的照常列出;
|
|
19019
|
+
* 段数超过上限时只列前几段,后面接「等 N 集」,N 是全部缺集数。
|
|
19020
|
+
*/
|
|
19021
|
+
var formatMissing = (numbers, unit) => {
|
|
19022
|
+
const parts = [];
|
|
19023
|
+
let index = 0;
|
|
19024
|
+
while (index < numbers.length) {
|
|
19025
|
+
let end = index;
|
|
19026
|
+
while (end + 1 < numbers.length && numbers[end + 1] === numbers[end] + 1) end++;
|
|
19027
|
+
if (end - index >= 2) parts.push(`${numbers[index]}–${numbers[end]}`);
|
|
19028
|
+
else parts.push(...numbers.slice(index, end + 1).map(String));
|
|
19029
|
+
index = end + 1;
|
|
19030
|
+
}
|
|
19031
|
+
if (parts.length <= MISSING_SEGMENT_LIMIT) return `第 ${parts.join("、")} ${unit}`;
|
|
19032
|
+
return `第 ${parts.slice(0, MISSING_SEGMENT_LIMIT).join("、")} 等 ${numbers.length} ${unit}`;
|
|
19033
|
+
};
|
|
19034
|
+
/** 按展示顺序(最新在前)写区间;只有一集时写「第 a 集」 */
|
|
19035
|
+
var formatEpisodeRange = (first, last) => first === last ? `第 ${first} 集` : `第 ${first}–${last} 集`;
|
|
19036
|
+
/** 标题按字数分档:短标题撑满版面,长标题收字号换行 */
|
|
19037
|
+
var getTitleClassName$1 = (length) => {
|
|
19038
|
+
if (length <= 6) return "text-[132px] leading-[1.05]";
|
|
19039
|
+
if (length <= 10) return "text-[112px] leading-[1.08]";
|
|
19040
|
+
if (length <= 16) return "text-[96px] leading-[1.1] line-clamp-2";
|
|
19041
|
+
if (length <= 24) return "text-[80px] leading-[1.14] line-clamp-2";
|
|
19042
|
+
return "text-[68px] leading-[1.18] line-clamp-3";
|
|
19043
|
+
};
|
|
19044
|
+
/** 巨型区间数字的字宽系数(字号的倍数,含 -0.04em 字距),按 tabular 数字和短横线的实测宽度取上限 */
|
|
19045
|
+
var RANGE_NUMERAL_ADVANCE = .56;
|
|
19046
|
+
/** 目录页巨型区间数字的字号:按左栏内容宽度和字符数反推,最大 184px,4 位集号的长区间也不会溢出 */
|
|
19047
|
+
var getRangeNumeralSize = (length, compact) => Math.min(184, Math.floor((compact ? 448 : 520) / (Math.max(length, 1) * RANGE_NUMERAL_ADVANCE)));
|
|
19048
|
+
/** 背景:封面弥散 + 离散噪点,与兄弟模板同一套图层 */
|
|
19049
|
+
var PosterBackground = ({ src, ctx }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18583
19050
|
className: "pointer-events-none absolute inset-0 overflow-hidden select-none",
|
|
18584
19051
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AmbientCover, {
|
|
18585
|
-
src
|
|
19052
|
+
src,
|
|
18586
19053
|
ctx
|
|
18587
19054
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
18588
19055
|
className: "absolute inset-0 opacity-[0.35] mix-blend-overlay dark:mix-blend-soft-light",
|
|
@@ -18631,312 +19098,558 @@ var MixBackground = ({ data, ctx }) => /* @__PURE__ */ (0, import_jsx_runtime.js
|
|
|
18631
19098
|
})
|
|
18632
19099
|
})]
|
|
18633
19100
|
});
|
|
18634
|
-
|
|
18635
|
-
|
|
19101
|
+
/** 刊头:栏目名 + 平台 logo,靠字距和留白收束 */
|
|
19102
|
+
var Masthead = ({ label, ctx }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
|
|
19103
|
+
className: "flex items-center justify-between pb-7",
|
|
18636
19104
|
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
|
-
]
|
|
19105
|
+
className: "flex items-center gap-5 text-[26px] font-bold tracking-[0.32em] text-foreground",
|
|
19106
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19107
|
+
className: "h-5 w-5",
|
|
19108
|
+
style: { backgroundColor: ACCENT }
|
|
19109
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: label })]
|
|
18649
19110
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
|
|
18650
19111
|
src: isDark(ctx) ? "/image/douyin/dylogo-light.svg" : "/image/douyin/dylogo-dark.svg",
|
|
18651
19112
|
alt: "抖音",
|
|
18652
|
-
className: "h-
|
|
19113
|
+
className: "h-14 w-auto"
|
|
18653
19114
|
})]
|
|
18654
19115
|
});
|
|
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
|
-
|
|
19116
|
+
/** 眉题:强调色小号粗体,用细点分隔 */
|
|
19117
|
+
var Kicker = ({ items }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19118
|
+
className: "flex flex-wrap items-center gap-x-4 text-[30px] font-bold",
|
|
19119
|
+
style: { color: ACCENT },
|
|
19120
|
+
children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.Fragment, { children: [index > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19121
|
+
className: "text-muted",
|
|
19122
|
+
children: "·"
|
|
19123
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: item })] }, `${index}-${item}`))
|
|
19124
|
+
});
|
|
19125
|
+
/** 数据栏:四格铺在浅色面板上,用留白代替分隔线,小标签 + 粗体大数字 + 小单位 */
|
|
19126
|
+
var Ledger = ({ items }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19127
|
+
className: "grid grid-cols-4 gap-x-10 rounded-3xl bg-foreground/5 px-10 py-8",
|
|
19128
|
+
children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19129
|
+
className: "text-[24px] font-medium text-foreground/65",
|
|
19130
|
+
children: item.label
|
|
19131
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19132
|
+
className: "mt-1 flex items-baseline gap-1.5 text-foreground",
|
|
19133
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19134
|
+
className: "text-[60px] leading-none font-black tabular-nums",
|
|
19135
|
+
children: item.value
|
|
19136
|
+
}), item.unit && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19137
|
+
className: "text-[26px] font-bold",
|
|
19138
|
+
children: item.unit
|
|
19139
|
+
})]
|
|
19140
|
+
})] }, item.label))
|
|
19141
|
+
});
|
|
19142
|
+
/** 署名行:头像 + 作者名 + 认证 + 次要信息 */
|
|
19143
|
+
var Byline = ({ avatar, name, verified, meta }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19144
|
+
className: "flex items-center gap-5",
|
|
19145
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19146
|
+
className: "h-19 w-19 shrink-0 overflow-hidden rounded-full ring-2 ring-foreground/10",
|
|
19147
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
19148
|
+
src: avatar,
|
|
19149
|
+
alt: name,
|
|
19150
|
+
className: "h-full w-full object-cover",
|
|
19151
|
+
isCircular: true
|
|
19152
|
+
})
|
|
19153
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19154
|
+
className: "min-w-0",
|
|
18684
19155
|
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"
|
|
19156
|
+
className: "flex items-center gap-2",
|
|
19157
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19158
|
+
className: "truncate text-[34px] font-bold text-foreground",
|
|
19159
|
+
children: name
|
|
19160
|
+
}), verified && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RiVerifiedBadgeFill, {
|
|
19161
|
+
className: "h-8 w-8 shrink-0",
|
|
19162
|
+
style: { color: ACCENT }
|
|
18699
19163
|
})]
|
|
19164
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19165
|
+
className: "mt-0.5 text-[24px] text-foreground/65",
|
|
19166
|
+
children: meta
|
|
19167
|
+
})]
|
|
19168
|
+
})]
|
|
19169
|
+
});
|
|
19170
|
+
/** 专题 hero:左封面,右眉题 / 大标题 / 导语 / 署名 */
|
|
19171
|
+
var Hero = ({ data }) => {
|
|
19172
|
+
const isPlaylet = data.kind === "playlet";
|
|
19173
|
+
const total = data.total_episode;
|
|
19174
|
+
const updated = data.updated_to_episode;
|
|
19175
|
+
const kicker = isPlaylet ? ["短剧", ...total > 0 && updated < total ? [`共 ${total} 集`, `更新至第 ${updated} 集`] : total > 0 ? [`全 ${total} 集`, "已完结"] : []] : ["合集", ...total > 0 ? [`共 ${total} 个视频`] : []];
|
|
19176
|
+
const authorMeta = [data.author.short_id ? `抖音号 ${data.author.short_id}` : "", `粉丝 ${Object.values(splitCount(data.author.follower_count)).join("")}`].filter(Boolean).join(" · ");
|
|
19177
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19178
|
+
className: "flex items-stretch gap-16",
|
|
19179
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19180
|
+
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",
|
|
19181
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19182
|
+
className: "absolute inset-0",
|
|
19183
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
19184
|
+
src: data.image_url,
|
|
19185
|
+
alt: data.mix_name,
|
|
19186
|
+
className: "h-full w-full object-cover"
|
|
19187
|
+
})
|
|
19188
|
+
})
|
|
18700
19189
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18701
|
-
className: "flex min-w-0 flex-1 flex-col
|
|
18702
|
-
children: [
|
|
19190
|
+
className: "flex min-w-0 flex-1 flex-col",
|
|
19191
|
+
children: [
|
|
19192
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Kicker, { items: kicker }),
|
|
18703
19193
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
|
|
18704
|
-
className:
|
|
18705
|
-
|
|
18706
|
-
wordBreak: "break-word",
|
|
18707
|
-
overflowWrap: "break-word"
|
|
18708
|
-
},
|
|
18709
|
-
children: mix_name
|
|
19194
|
+
className: `mt-5 font-black tracking-tight text-balance text-foreground ${getTitleClassName$1(data.mix_name.length)}`,
|
|
19195
|
+
children: data.mix_name
|
|
18710
19196
|
}),
|
|
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
|
-
})]
|
|
19197
|
+
data.desc && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
19198
|
+
className: `mt-7 text-[32px] leading-[1.6] font-light text-foreground/80 ${isPlaylet ? "line-clamp-4" : "line-clamp-2"}`,
|
|
19199
|
+
children: data.desc
|
|
18729
19200
|
}),
|
|
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);
|
|
19201
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19202
|
+
className: "mt-auto pt-18",
|
|
19203
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Byline, {
|
|
19204
|
+
avatar: data.author.avatar,
|
|
19205
|
+
name: data.author.nickname,
|
|
19206
|
+
verified: data.author.verified,
|
|
19207
|
+
meta: authorMeta
|
|
19208
|
+
})
|
|
18785
19209
|
})
|
|
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
|
|
19210
|
+
]
|
|
18809
19211
|
})]
|
|
18810
19212
|
});
|
|
18811
19213
|
};
|
|
18812
|
-
/**
|
|
19214
|
+
/** 可执行命令:统一实心高对比 chip */
|
|
18813
19215
|
var CommandChip = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
18814
|
-
className: "inline-flex items-center rounded-
|
|
19216
|
+
className: "inline-flex h-15 items-center rounded-2xl px-6 text-[30px] font-bold whitespace-nowrap text-white shadow-lg shadow-black/15",
|
|
19217
|
+
style: { backgroundColor: CHIP_BG },
|
|
18815
19218
|
children
|
|
18816
19219
|
});
|
|
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",
|
|
19220
|
+
/** 有效期说明:两种模式共用;主句加粗,补充说明降一档。只有一页时没有翻页,不提重新计时 */
|
|
19221
|
+
var ValidityNote = ({ seconds, pageCount }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19222
|
+
className: "flex items-start gap-3 text-[26px] leading-snug",
|
|
19223
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Timer, {
|
|
19224
|
+
className: "mt-0.5 h-7 w-7 shrink-0 text-foreground/70",
|
|
19225
|
+
strokeWidth: 2.2
|
|
19226
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19227
|
+
className: "font-bold text-foreground",
|
|
18835
19228
|
children: [
|
|
18836
|
-
|
|
18837
|
-
|
|
18838
|
-
|
|
18839
|
-
|
|
19229
|
+
seconds,
|
|
19230
|
+
" 秒内有效",
|
|
19231
|
+
pageCount > 1 && ",翻页重新计时"
|
|
19232
|
+
]
|
|
19233
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19234
|
+
className: "mt-0.5 text-foreground/65",
|
|
19235
|
+
children: "过期请重新发送原链接"
|
|
19236
|
+
})] })]
|
|
19237
|
+
});
|
|
19238
|
+
/** 文字命令模式:只列出当前页真正能用的命令;后端也认纯数字集号,用本页第一集举例 */
|
|
19239
|
+
var TextGuide = ({ first, page, pageCount, seconds }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19240
|
+
className: "flex flex-col gap-5",
|
|
19241
|
+
children: [
|
|
19242
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19243
|
+
className: "text-[34px] font-black text-foreground",
|
|
19244
|
+
children: "回复文字选集"
|
|
19245
|
+
}),
|
|
19246
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19247
|
+
className: "flex items-center gap-5",
|
|
19248
|
+
children: [
|
|
19249
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19250
|
+
className: "w-19 shrink-0 text-[28px] font-bold text-foreground",
|
|
19251
|
+
children: "选集"
|
|
18840
19252
|
}),
|
|
18841
|
-
|
|
18842
|
-
|
|
18843
|
-
|
|
18844
|
-
|
|
18845
|
-
|
|
18846
|
-
|
|
18847
|
-
|
|
18848
|
-
|
|
18849
|
-
|
|
18850
|
-
|
|
18851
|
-
|
|
18852
|
-
|
|
18853
|
-
|
|
19253
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19254
|
+
className: "text-[26px] text-foreground/65",
|
|
19255
|
+
children: "发送"
|
|
19256
|
+
}),
|
|
19257
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip, { children: "第?集" }),
|
|
19258
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
19259
|
+
className: "text-[26px] text-foreground/65",
|
|
19260
|
+
children: ["也可只发集号,如 ", first]
|
|
19261
|
+
})
|
|
19262
|
+
]
|
|
19263
|
+
}),
|
|
19264
|
+
pageCount > 1 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19265
|
+
className: "flex items-center gap-5",
|
|
19266
|
+
children: [
|
|
19267
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19268
|
+
className: "w-19 shrink-0 text-[28px] font-bold text-foreground",
|
|
19269
|
+
children: "翻页"
|
|
19270
|
+
}),
|
|
19271
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19272
|
+
className: "text-[26px] text-foreground/65",
|
|
19273
|
+
children: "发送"
|
|
19274
|
+
}),
|
|
19275
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19276
|
+
className: "flex flex-wrap gap-3",
|
|
18854
19277
|
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: "翻页" })
|
|
19278
|
+
page > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip, { children: "上一页" }),
|
|
19279
|
+
page < pageCount && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip, { children: "下一页" }),
|
|
19280
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip, { children: "第?页" })
|
|
18868
19281
|
]
|
|
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
19282
|
})
|
|
18907
|
-
|
|
18908
|
-
|
|
18909
|
-
|
|
18910
|
-
|
|
18911
|
-
|
|
18912
|
-
|
|
18913
|
-
|
|
18914
|
-
|
|
18915
|
-
|
|
18916
|
-
|
|
18917
|
-
|
|
18918
|
-
|
|
18919
|
-
|
|
18920
|
-
|
|
18921
|
-
|
|
18922
|
-
|
|
19283
|
+
]
|
|
19284
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19285
|
+
className: "flex items-center gap-5",
|
|
19286
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19287
|
+
className: "w-19 shrink-0 text-[28px] font-bold text-foreground",
|
|
19288
|
+
children: "翻页"
|
|
19289
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19290
|
+
className: "text-[26px] text-foreground/65",
|
|
19291
|
+
children: "只有这一页,无需翻页"
|
|
19292
|
+
})]
|
|
19293
|
+
}),
|
|
19294
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidityNote, {
|
|
19295
|
+
seconds,
|
|
19296
|
+
pageCount
|
|
19297
|
+
})
|
|
19298
|
+
]
|
|
19299
|
+
});
|
|
19300
|
+
/** 键盘示意里的一枚按钮:数字键与「跳转」是蓝框键(style 1),翻页是灰框键;small 给 4 位集号用 */
|
|
19301
|
+
var SketchKey = ({ children, quiet, small }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19302
|
+
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]"}`,
|
|
19303
|
+
children
|
|
19304
|
+
});
|
|
19305
|
+
/** 按钮模式的键盘示意:只画本页真实存在的按钮,排布与 QQBot 键盘一致;宽度固定,4 位集号收小字号,左侧说明不被挤到换行 */
|
|
19306
|
+
var KeySketch = ({ episodes, page, pageCount }) => {
|
|
19307
|
+
const rows = [];
|
|
19308
|
+
for (let index = 0; index < episodes.length; index += KEYS_PER_ROW) rows.push(episodes.slice(index, index + KEYS_PER_ROW));
|
|
19309
|
+
const navigation = [page > 1 ? "上一页" : "", page < pageCount ? "下一页" : ""].filter(Boolean);
|
|
19310
|
+
const small = episodes.some((episode) => episode >= 1e3);
|
|
19311
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19312
|
+
className: "flex w-82.5 shrink-0 flex-col gap-1.5 self-start rounded-3xl bg-surface/60 p-3",
|
|
19313
|
+
children: [
|
|
19314
|
+
pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SketchKey, { children: "跳转到第x页" }),
|
|
19315
|
+
rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19316
|
+
className: "flex gap-1.5",
|
|
19317
|
+
children: row.map((episode) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SketchKey, {
|
|
19318
|
+
small,
|
|
19319
|
+
children: episode
|
|
19320
|
+
}, episode))
|
|
19321
|
+
}, row[0])),
|
|
19322
|
+
navigation.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19323
|
+
className: "flex gap-1.5",
|
|
19324
|
+
children: navigation.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SketchKey, {
|
|
19325
|
+
quiet: true,
|
|
19326
|
+
children: label
|
|
19327
|
+
}, label))
|
|
18923
19328
|
})
|
|
18924
19329
|
]
|
|
18925
19330
|
});
|
|
18926
19331
|
};
|
|
18927
|
-
|
|
18928
|
-
|
|
18929
|
-
className: "
|
|
18930
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.
|
|
18931
|
-
className: "
|
|
19332
|
+
/** 按钮模式:引导点按钮,不出现任何手打命令 */
|
|
19333
|
+
var ButtonGuide = ({ episodes, page, pageCount, seconds }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19334
|
+
className: "flex gap-6",
|
|
19335
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19336
|
+
className: "flex min-w-0 flex-1 flex-col gap-4",
|
|
18932
19337
|
children: [
|
|
18933
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
18934
|
-
|
|
18935
|
-
|
|
18936
|
-
|
|
19338
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19339
|
+
className: "flex items-center gap-3 text-[34px] font-black text-foreground",
|
|
19340
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MousePointerClick, {
|
|
19341
|
+
className: "h-9 w-9 shrink-0",
|
|
19342
|
+
strokeWidth: 2.4,
|
|
19343
|
+
style: { color: ACCENT }
|
|
19344
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "点击下方按钮选集" })]
|
|
19345
|
+
}),
|
|
19346
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("ul", {
|
|
19347
|
+
className: "flex flex-col gap-2 text-[26px] leading-snug text-foreground/80",
|
|
19348
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: "数字键即集号,点一下直接解析" }), pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: "「跳转到第x页」补上页码再发送" })]
|
|
19349
|
+
}),
|
|
19350
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidityNote, {
|
|
19351
|
+
seconds,
|
|
19352
|
+
pageCount
|
|
19353
|
+
})
|
|
18937
19354
|
]
|
|
19355
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(KeySketch, {
|
|
19356
|
+
episodes,
|
|
19357
|
+
page,
|
|
19358
|
+
pageCount
|
|
18938
19359
|
})]
|
|
18939
|
-
})
|
|
19360
|
+
});
|
|
19361
|
+
/** 目录页开篇:巨型区间数字 + 操作说明 */
|
|
19362
|
+
var Contents = ({ episodes, missingNote, page, pageCount, mode, seconds }) => {
|
|
19363
|
+
const first = episodes[0]?.episode ?? 0;
|
|
19364
|
+
const last = episodes[episodes.length - 1]?.episode ?? 0;
|
|
19365
|
+
const numeral = first === last ? `${first}` : `${first}–${last}`;
|
|
19366
|
+
const compact = mode === "button";
|
|
19367
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19368
|
+
className: "flex items-end justify-between",
|
|
19369
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19370
|
+
className: "flex items-baseline gap-5",
|
|
19371
|
+
children: [
|
|
19372
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19373
|
+
className: "h-6 w-6 self-center",
|
|
19374
|
+
style: { backgroundColor: ACCENT }
|
|
19375
|
+
}),
|
|
19376
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
|
|
19377
|
+
className: "text-[72px] leading-none font-black text-foreground",
|
|
19378
|
+
children: "选集"
|
|
19379
|
+
}),
|
|
19380
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19381
|
+
className: "text-[24px] font-bold tracking-[0.3em] text-foreground/55",
|
|
19382
|
+
children: "CONTENTS"
|
|
19383
|
+
})
|
|
19384
|
+
]
|
|
19385
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19386
|
+
className: "rounded-full bg-foreground/10 px-7 py-2 text-[34px] font-bold text-foreground tabular-nums",
|
|
19387
|
+
children: [
|
|
19388
|
+
"第 ",
|
|
19389
|
+
page,
|
|
19390
|
+
" / ",
|
|
19391
|
+
pageCount,
|
|
19392
|
+
" 页"
|
|
19393
|
+
]
|
|
19394
|
+
})]
|
|
19395
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19396
|
+
className: "mt-8 flex items-stretch",
|
|
19397
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19398
|
+
className: compact ? "w-120 shrink-0 pr-8" : "w-140 shrink-0 pr-10",
|
|
19399
|
+
children: [
|
|
19400
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19401
|
+
className: "leading-[0.84] font-light tracking-[-0.04em] whitespace-nowrap text-foreground tabular-nums",
|
|
19402
|
+
style: { fontSize: getRangeNumeralSize(numeral.length, compact) },
|
|
19403
|
+
children: numeral
|
|
19404
|
+
}),
|
|
19405
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19406
|
+
className: "mt-6 text-[30px] leading-snug font-bold text-foreground",
|
|
19407
|
+
children: formatEpisodeRange(first, last)
|
|
19408
|
+
}),
|
|
19409
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19410
|
+
className: "mt-1 flex items-center gap-2.5 text-[28px] font-bold text-foreground",
|
|
19411
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowDownWideNarrow, {
|
|
19412
|
+
className: "h-8 w-8 shrink-0",
|
|
19413
|
+
strokeWidth: 2.4,
|
|
19414
|
+
style: { color: ACCENT }
|
|
19415
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "最新在前" })]
|
|
19416
|
+
}),
|
|
19417
|
+
missingNote && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19418
|
+
className: "mt-2 text-[26px] leading-snug text-foreground/65",
|
|
19419
|
+
children: missingNote
|
|
19420
|
+
})
|
|
19421
|
+
]
|
|
19422
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19423
|
+
className: "min-w-0 flex-1 pl-10",
|
|
19424
|
+
children: mode === "button" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ButtonGuide, {
|
|
19425
|
+
episodes: episodes.map((episode) => episode.episode),
|
|
19426
|
+
page,
|
|
19427
|
+
pageCount,
|
|
19428
|
+
seconds
|
|
19429
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextGuide, {
|
|
19430
|
+
first,
|
|
19431
|
+
page,
|
|
19432
|
+
pageCount,
|
|
19433
|
+
seconds
|
|
19434
|
+
})
|
|
19435
|
+
})]
|
|
19436
|
+
})] });
|
|
19437
|
+
};
|
|
19438
|
+
/** 短剧单元:每集文案都是同一段简介,只留集号 + 时长,像目录条目一样左右分列 */
|
|
19439
|
+
var PlayletCell = ({ episode, numberClassName }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19440
|
+
className: "min-w-0",
|
|
19441
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19442
|
+
className: "aspect-3/4 overflow-hidden rounded-3xl bg-surface-secondary shadow-lg shadow-black/10",
|
|
19443
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
19444
|
+
src: episode.originCover || episode.cover || "",
|
|
19445
|
+
alt: `第 ${episode.episode} 集`,
|
|
19446
|
+
className: "h-full w-full object-cover object-[50%_30%]"
|
|
19447
|
+
})
|
|
19448
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19449
|
+
className: "mt-4 flex items-baseline gap-3",
|
|
19450
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19451
|
+
className: `leading-none font-black tracking-tight text-foreground tabular-nums ${numberClassName}`,
|
|
19452
|
+
children: episode.episode
|
|
19453
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19454
|
+
className: "font-mono text-[26px] text-foreground/65",
|
|
19455
|
+
children: formatDuration$4(episode.duration)
|
|
19456
|
+
})]
|
|
19457
|
+
})]
|
|
19458
|
+
});
|
|
19459
|
+
/** 短剧集号字号:5 列单元只有约 230px 宽,4 位集号降一档,给时长留位置;min-w 让同页时长列对齐 */
|
|
19460
|
+
var PLAYLET_NUMBER_CLASS = [
|
|
19461
|
+
"min-w-14 text-[72px]",
|
|
19462
|
+
"min-w-24 text-[72px]",
|
|
19463
|
+
"min-w-32 text-[72px]",
|
|
19464
|
+
"min-w-34 text-[56px]"
|
|
19465
|
+
];
|
|
19466
|
+
/** 合集集号栏:按本页最大位数取宽度,同一页标题左缘对齐;4 位集号降字号,不挤占标题 */
|
|
19467
|
+
var COLLECTION_NUMBER_CLASS = [
|
|
19468
|
+
"min-w-14 text-[80px]",
|
|
19469
|
+
"min-w-26 text-[80px]",
|
|
19470
|
+
"min-w-37.5 text-[80px]",
|
|
19471
|
+
"min-w-37 text-[60px]"
|
|
19472
|
+
];
|
|
19473
|
+
/** 普通合集单元:时长压在封面右下角,标题让出整列宽度显示三行 */
|
|
19474
|
+
var CollectionCell = ({ episode, numberClassName }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19475
|
+
className: "min-w-0",
|
|
19476
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19477
|
+
className: "relative aspect-video overflow-hidden rounded-3xl bg-surface-secondary shadow-lg shadow-black/10",
|
|
19478
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
19479
|
+
src: episode.originCover || episode.cover || "",
|
|
19480
|
+
alt: episode.title,
|
|
19481
|
+
className: "h-full w-full object-cover"
|
|
19482
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19483
|
+
className: "absolute right-3 bottom-3 rounded-lg bg-black/60 px-2.5 py-0.5 font-mono text-[24px] text-white",
|
|
19484
|
+
children: formatDuration$4(episode.duration)
|
|
19485
|
+
})]
|
|
19486
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19487
|
+
className: "mt-4 flex gap-4",
|
|
19488
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19489
|
+
className: `shrink-0 leading-[0.9] font-black tracking-tight text-foreground tabular-nums ${numberClassName}`,
|
|
19490
|
+
children: episode.episode
|
|
19491
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19492
|
+
className: "line-clamp-3 min-w-0 flex-1 pt-0.5 text-[30px] leading-tight font-bold text-pretty text-foreground",
|
|
19493
|
+
children: episode.title || "未命名视频"
|
|
19494
|
+
})]
|
|
19495
|
+
})]
|
|
19496
|
+
});
|
|
19497
|
+
/** 最后一页不满一行时的收尾块:说明最新内容在哪一页,并给出往回翻的方式 */
|
|
19498
|
+
var EndCard = ({ span, noun, countText, pageCount, mode }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19499
|
+
className: `${COL_SPAN[span] ?? "col-span-1"} flex flex-col justify-center self-stretch rounded-3xl bg-foreground/5 p-9`,
|
|
19500
|
+
children: [
|
|
19501
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19502
|
+
className: "flex items-center gap-4 text-[40px] leading-tight font-black text-foreground",
|
|
19503
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19504
|
+
className: "h-5 w-5 shrink-0",
|
|
19505
|
+
style: { backgroundColor: ACCENT }
|
|
19506
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: pageCount > 1 ? "已是最后一页" : "只有这一页" })]
|
|
19507
|
+
}),
|
|
19508
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
19509
|
+
className: "mt-4 text-[28px] leading-normal text-foreground/75",
|
|
19510
|
+
children: pageCount > 1 ? `最新的${noun}在第 1 页` : countText
|
|
19511
|
+
}),
|
|
19512
|
+
pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19513
|
+
className: "flex flex-wrap items-center gap-3 pt-6 text-[28px] text-foreground/70",
|
|
19514
|
+
children: mode === "button" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "点键盘「上一页」往回翻" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
19515
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "发送" }),
|
|
19516
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip, { children: "上一页" }),
|
|
19517
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "往回翻" })
|
|
19518
|
+
] })
|
|
19519
|
+
})
|
|
19520
|
+
]
|
|
19521
|
+
});
|
|
19522
|
+
/** 选集网格:短剧 5 列对应键盘每行 5 个按钮;普通合集 3 列,保证标题三行可读 */
|
|
19523
|
+
var EpisodeGrid = ({ episodes, isPlaylet, isLastPage, pageCount, listed, mode }) => {
|
|
19524
|
+
const columns = isPlaylet ? 5 : 3;
|
|
19525
|
+
const remainder = episodes.length % columns;
|
|
19526
|
+
const fill = isLastPage && remainder > 0 ? columns - remainder : 0;
|
|
19527
|
+
const showEndCard = fill > 1 || fill === 1 && !isPlaylet;
|
|
19528
|
+
const digits = Math.min(Math.max(1, ...episodes.map((episode) => `${episode.episode}`.length)), 4);
|
|
19529
|
+
const numberClassName = isPlaylet ? PLAYLET_NUMBER_CLASS[digits - 1] : COLLECTION_NUMBER_CLASS[digits - 1];
|
|
19530
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19531
|
+
className: isPlaylet ? "grid grid-cols-5 gap-x-7 gap-y-10" : "grid grid-cols-3 gap-x-10 gap-y-11",
|
|
19532
|
+
children: [episodes.map((episode) => isPlaylet ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlayletCell, {
|
|
19533
|
+
episode,
|
|
19534
|
+
numberClassName
|
|
19535
|
+
}, episode.aweme_id) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CollectionCell, {
|
|
19536
|
+
episode,
|
|
19537
|
+
numberClassName
|
|
19538
|
+
}, episode.aweme_id)), showEndCard && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EndCard, {
|
|
19539
|
+
span: fill,
|
|
19540
|
+
noun: isPlaylet ? "剧集" : "视频",
|
|
19541
|
+
countText: isPlaylet ? `共 ${listed} 集` : `共 ${listed} 个视频`,
|
|
19542
|
+
pageCount,
|
|
19543
|
+
mode
|
|
19544
|
+
})]
|
|
19545
|
+
});
|
|
19546
|
+
};
|
|
19547
|
+
/** 版权栏:左侧列出数量与缺集说明,右侧生成时间 */
|
|
19548
|
+
var Colophon = ({ notes }) => {
|
|
19549
|
+
const [generatedAt] = import_react.useState(() => format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss"));
|
|
19550
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("footer", {
|
|
19551
|
+
className: "flex items-start justify-between gap-10 pt-7 text-[24px] leading-relaxed text-foreground/65",
|
|
19552
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19553
|
+
className: "min-w-0",
|
|
19554
|
+
children: notes.join(" · ")
|
|
19555
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19556
|
+
className: "shrink-0 select-text",
|
|
19557
|
+
children: ["图片生成于: ", generatedAt]
|
|
19558
|
+
})]
|
|
19559
|
+
});
|
|
19560
|
+
};
|
|
19561
|
+
var DouyinMix = import_react.memo((props) => {
|
|
19562
|
+
const { data, ctx } = props;
|
|
19563
|
+
const isPlaylet = data.kind === "playlet";
|
|
19564
|
+
const pageSize = Math.max(1, data.posterPageSize ?? DEFAULT_POSTER_PAGE_SIZE);
|
|
19565
|
+
const pageCount = Math.max(1, Math.ceil(data.episodes.length / pageSize));
|
|
19566
|
+
const page = Math.min(Math.max(1, data.posterPage ?? 1), pageCount);
|
|
19567
|
+
const visible = data.episodes.slice((page - 1) * pageSize, page * pageSize);
|
|
19568
|
+
const mode = data.selectionMode ?? "text";
|
|
19569
|
+
const seconds = data.timeoutSeconds > 0 ? data.timeoutSeconds : DEFAULT_TIMEOUT_SECONDS;
|
|
19570
|
+
const listedSet = new Set(data.episodes.map((episode) => episode.episode));
|
|
19571
|
+
const maxEpisode = data.episodes.reduce((max, episode) => Math.max(max, episode.episode), 0);
|
|
19572
|
+
const missing = [];
|
|
19573
|
+
for (let episode = 1; episode <= Math.max(maxEpisode, data.updated_to_episode); episode++) if (!listedSet.has(episode)) missing.push(episode);
|
|
19574
|
+
const upper = page > 1 ? data.episodes[(page - 1) * pageSize - 1].episode : Infinity;
|
|
19575
|
+
const lower = page < pageCount ? visible[visible.length - 1].episode : 0;
|
|
19576
|
+
const pageMissing = missing.filter((episode) => episode < upper && episode > lower);
|
|
19577
|
+
const unit = isPlaylet ? "集" : "个视频";
|
|
19578
|
+
const totalDuration = data.episodes.reduce((sum, episode) => sum + episode.duration, 0);
|
|
19579
|
+
const ledger = [
|
|
19580
|
+
{
|
|
19581
|
+
label: "播放",
|
|
19582
|
+
...splitCount(data.statistics.play_count)
|
|
19583
|
+
},
|
|
19584
|
+
{
|
|
19585
|
+
label: "点赞",
|
|
19586
|
+
...splitCount(data.statistics.digg_count)
|
|
19587
|
+
},
|
|
19588
|
+
{
|
|
19589
|
+
label: "收藏",
|
|
19590
|
+
...splitCount(data.statistics.collect_count)
|
|
19591
|
+
},
|
|
19592
|
+
isPlaylet ? {
|
|
19593
|
+
label: "单集均长",
|
|
19594
|
+
value: formatDuration$4(data.episodes.length ? totalDuration / data.episodes.length : 0),
|
|
19595
|
+
unit: ""
|
|
19596
|
+
} : {
|
|
19597
|
+
label: "总时长",
|
|
19598
|
+
...splitRuntime(totalDuration)
|
|
19599
|
+
}
|
|
19600
|
+
];
|
|
19601
|
+
const notes = [data.total_episode > 0 ? `已列出 ${data.episodes.length} / ${data.total_episode} ${unit}` : `已列出 ${data.episodes.length} ${unit}`, ...missing.length > 0 ? [`接口未返回${formatMissing(missing, unit)},暂不能选`] : []];
|
|
19602
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DefaultLayout, {
|
|
19603
|
+
...props,
|
|
19604
|
+
className: "relative overflow-hidden",
|
|
19605
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PosterBackground, {
|
|
19606
|
+
src: data.image_url,
|
|
19607
|
+
ctx
|
|
19608
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
19609
|
+
className: "relative z-10 px-20 pt-18",
|
|
19610
|
+
children: [
|
|
19611
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Masthead, {
|
|
19612
|
+
label: isPlaylet ? "DOUYIN PLAYLET · EPISODE GUIDE" : "DOUYIN COLLECTION · EPISODE GUIDE",
|
|
19613
|
+
ctx
|
|
19614
|
+
}),
|
|
19615
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19616
|
+
className: "mt-12",
|
|
19617
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Hero, { data })
|
|
19618
|
+
}),
|
|
19619
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19620
|
+
className: "mt-12",
|
|
19621
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Ledger, { items: ledger })
|
|
19622
|
+
}),
|
|
19623
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19624
|
+
className: "mt-16",
|
|
19625
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Contents, {
|
|
19626
|
+
episodes: visible,
|
|
19627
|
+
missingNote: pageMissing.length > 0 ? `缺${formatMissing(pageMissing, unit)},暂不能选` : "",
|
|
19628
|
+
page,
|
|
19629
|
+
pageCount,
|
|
19630
|
+
mode,
|
|
19631
|
+
seconds
|
|
19632
|
+
})
|
|
19633
|
+
}),
|
|
19634
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19635
|
+
className: "mt-12",
|
|
19636
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EpisodeGrid, {
|
|
19637
|
+
episodes: visible,
|
|
19638
|
+
isPlaylet,
|
|
19639
|
+
isLastPage: page === pageCount,
|
|
19640
|
+
pageCount,
|
|
19641
|
+
listed: data.episodes.length,
|
|
19642
|
+
mode
|
|
19643
|
+
})
|
|
19644
|
+
}),
|
|
19645
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19646
|
+
className: "mt-14",
|
|
19647
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Colophon, { notes })
|
|
19648
|
+
})
|
|
19649
|
+
]
|
|
19650
|
+
})]
|
|
19651
|
+
});
|
|
19652
|
+
});
|
|
18940
19653
|
DouyinMix.displayName = "DouyinMix";
|
|
18941
19654
|
//#endregion
|
|
18942
19655
|
//#region ktr/template/douyin/mix/index.tsx
|
|
@@ -30524,31 +31237,16 @@ var wrapWithErrorHandler = (fn, options) => {
|
|
|
30524
31237
|
const rawEvent = e;
|
|
30525
31238
|
const normalizedEvent = await injectBotToEventForPushTask(rawEvent, options.businessName);
|
|
30526
31239
|
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
|
-
}
|
|
31240
|
+
const emojiFlow = Boolean(rawEvent) && !isPushTask(rawEvent, options.businessName) ? createEmojiReactionFlow(rawEvent) : void 0;
|
|
31241
|
+
if (emojiFlow) await emojiFlow.begin();
|
|
30536
31242
|
const runHandler = () => fn(normalizedEvent, normalizedNext);
|
|
30537
31243
|
const ctx = logger$1.runContext(async () => rawEvent ? runWithVerifyContext(rawEvent, runHandler) : runHandler());
|
|
30538
31244
|
try {
|
|
30539
31245
|
const result = await ctx.run();
|
|
30540
|
-
|
|
30541
|
-
emojiManager.replace("PROCESSING", "SUCCESS").catch(() => {});
|
|
30542
|
-
}, 1500);
|
|
31246
|
+
await emojiFlow?.succeed();
|
|
30543
31247
|
return result;
|
|
30544
31248
|
} 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
|
-
}
|
|
31249
|
+
await emojiFlow?.fail();
|
|
30552
31250
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
30553
31251
|
if (await handleBusinessError(error, options, parseLogsToStructured(ctx.logs()), normalizedEvent) === "handled") return void 0;
|
|
30554
31252
|
throw error;
|
|
@@ -30669,6 +31367,7 @@ var createEpisodeSelection = (scope, options) => {
|
|
|
30669
31367
|
title: options.title,
|
|
30670
31368
|
platform: options.platform,
|
|
30671
31369
|
scene: options.scene,
|
|
31370
|
+
ownerId: options.ownerId,
|
|
30672
31371
|
pageSize: Math.max(1, options.pageSize ?? 15),
|
|
30673
31372
|
poster: options.poster,
|
|
30674
31373
|
posterPages: /* @__PURE__ */ new Map([[options.posterPage ?? 1, options.poster]]),
|
|
@@ -30699,6 +31398,13 @@ var getEpisodeSelection = (token, scope) => {
|
|
|
30699
31398
|
}
|
|
30700
31399
|
return session;
|
|
30701
31400
|
};
|
|
31401
|
+
/**
|
|
31402
|
+
* 判断用户是否有权操作这次选集。
|
|
31403
|
+
* 只有发起人本人能翻页/选集;没有记录发起人时退回旧行为(不做限制)。
|
|
31404
|
+
*/
|
|
31405
|
+
var isEpisodeSelectionOwner = (session, userId) => {
|
|
31406
|
+
return !session.ownerId || session.ownerId === userId;
|
|
31407
|
+
};
|
|
30702
31408
|
/** 翻页成功后重新计算 120 秒有效期。 */
|
|
30703
31409
|
var touchEpisodeSelection = (token, scope) => {
|
|
30704
31410
|
const session = getEpisodeSelection(token, scope);
|
|
@@ -30759,34 +31465,41 @@ var getEpisodeSelectionPoster = async (session, posterPage) => {
|
|
|
30759
31465
|
* 生成 QQBot keyboard 行。
|
|
30760
31466
|
* 跳转输入行在最上面,集数按钮每行 5 个,翻页按钮单独一行;
|
|
30761
31467
|
* 15 集一页时正好 1 + 3 + 1 = 5 行,不会超过 QQBot 的上限。
|
|
31468
|
+
* 群聊里每个按钮都带发起人的点击权限(QQBot 原生 permission),别人点了不生效;
|
|
31469
|
+
* 私聊只有对方一人可见,且 QQ 私聊不支持「指定用户」权限,不加 list,靠命令侧校验。
|
|
30762
31470
|
*/
|
|
30763
31471
|
var buildEpisodeKeyboardRows = (session, page) => {
|
|
30764
31472
|
const data = getEpisodePage(session, page);
|
|
30765
31473
|
if (!data) return [];
|
|
31474
|
+
const ownerPermission = session.ownerId && session.scene === "group" ? { list: [session.ownerId] } : {};
|
|
30766
31475
|
const rows = [];
|
|
30767
31476
|
if (data.pageCount > 1) rows.push([{
|
|
30768
31477
|
text: "跳转到第x页",
|
|
30769
31478
|
data: `#选集 ${session.token} page:`,
|
|
30770
31479
|
enter: false,
|
|
30771
|
-
style: 1
|
|
31480
|
+
style: 1,
|
|
31481
|
+
...ownerPermission
|
|
30772
31482
|
}]);
|
|
30773
31483
|
for (let index = 0; index < data.items.length; index += 5) rows.push(data.items.slice(index, index + 5).map((item) => ({
|
|
30774
31484
|
text: String(item.episode),
|
|
30775
31485
|
show: String(item.episode),
|
|
30776
31486
|
callback: true,
|
|
30777
31487
|
data: `#选集 ${session.token} ${item.episode}`,
|
|
30778
|
-
style: 1
|
|
31488
|
+
style: 1,
|
|
31489
|
+
...ownerPermission
|
|
30779
31490
|
})));
|
|
30780
31491
|
const navigation = [];
|
|
30781
31492
|
if (data.page > 1) navigation.push({
|
|
30782
31493
|
text: "上一页",
|
|
30783
31494
|
callback: true,
|
|
30784
|
-
data: `#选集 ${session.token} page:${data.page - 1}
|
|
31495
|
+
data: `#选集 ${session.token} page:${data.page - 1}`,
|
|
31496
|
+
...ownerPermission
|
|
30785
31497
|
});
|
|
30786
31498
|
if (data.page < data.pageCount) navigation.push({
|
|
30787
31499
|
text: "下一页",
|
|
30788
31500
|
callback: true,
|
|
30789
|
-
data: `#选集 ${session.token} page:${data.page + 1}
|
|
31501
|
+
data: `#选集 ${session.token} page:${data.page + 1}`,
|
|
31502
|
+
...ownerPermission
|
|
30790
31503
|
});
|
|
30791
31504
|
if (navigation.length) rows.push(navigation);
|
|
30792
31505
|
return rows;
|
|
@@ -30796,7 +31509,8 @@ var buildEpisodeSelectionText = (session, page) => {
|
|
|
30796
31509
|
const data = getEpisodePage(session, page);
|
|
30797
31510
|
if (!data) return "";
|
|
30798
31511
|
const range = data.firstEpisode === data.lastEpisode ? `第 ${data.firstEpisode} 集` : `第 ${data.firstEpisode}–${data.lastEpisode} 集`;
|
|
30799
|
-
|
|
31512
|
+
const ownerHint = session.scene === "group" ? ",仅发起人可操作" : "";
|
|
31513
|
+
return `《${session.title}》\n${range} · 第 ${data.page}/${data.pageCount} 页\n点击下方按钮选集(120 秒内有效${ownerHint})。`;
|
|
30800
31514
|
};
|
|
30801
31515
|
/** 按实际集号查找目标。 */
|
|
30802
31516
|
var resolveEpisodeTarget = (session, episode) => {
|
|
@@ -32128,6 +32842,8 @@ var Bilibili = class extends Base {
|
|
|
32128
32842
|
const linkedSourceIndex = linkedEpId ? sourceEpisodes.findIndex((item) => String(item.ep_id) === linkedEpId) : -1;
|
|
32129
32843
|
const linkedDisplayIndex = linkedSourceIndex >= 0 ? sourceEpisodes.length - 1 - linkedSourceIndex : -1;
|
|
32130
32844
|
let selectedIndex = autoSelectEpisode ? linkedSourceIndex : -1;
|
|
32845
|
+
/** 文字选集消息的表情反馈流程:翻页留到新海报发出、选集留到下载结束后再收尾 */
|
|
32846
|
+
let emojiFlow = null;
|
|
32131
32847
|
const buttonSelection = isButtonSelectionScene(this.e);
|
|
32132
32848
|
const selectionMode = buttonSelection ? "button" : "text";
|
|
32133
32849
|
/** 按海报页码渲染:15 集一页,长番剧不会撑爆单张 PNG */
|
|
@@ -32142,10 +32858,12 @@ var Bilibili = class extends Base {
|
|
|
32142
32858
|
seasonID: videoInfo.data.result.season_id,
|
|
32143
32859
|
subtitle: videoInfo.data.result.subtitle,
|
|
32144
32860
|
UPInfo: videoInfo.data.result.up_info,
|
|
32861
|
+
Staff: videoInfo.data.result.staff,
|
|
32145
32862
|
Copyright: videoInfo.data.result.rights.copyright,
|
|
32146
32863
|
Stat: videoInfo.data.result.stat,
|
|
32147
32864
|
Episodes: displayEpisodes,
|
|
32148
32865
|
length: sourceEpisodes.length,
|
|
32866
|
+
timeoutSeconds: 120,
|
|
32149
32867
|
selectionMode,
|
|
32150
32868
|
posterPage,
|
|
32151
32869
|
posterPageSize: 15
|
|
@@ -32162,6 +32880,7 @@ var Bilibili = class extends Base {
|
|
|
32162
32880
|
title: videoInfo.data.result.title,
|
|
32163
32881
|
platform: "bilibili",
|
|
32164
32882
|
scene: this.e.isFriend ? "friend" : "group",
|
|
32883
|
+
ownerId: this.e.userId,
|
|
32165
32884
|
poster,
|
|
32166
32885
|
posterPage: initialPage,
|
|
32167
32886
|
renderPoster,
|
|
@@ -32178,95 +32897,123 @@ var Bilibili = class extends Base {
|
|
|
32178
32897
|
/** 上一页海报消息,翻页发送成功后撤回,避免聊天里堆一串过期海报 */
|
|
32179
32898
|
let posterMessageId = "";
|
|
32180
32899
|
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
|
-
|
|
32900
|
+
try {
|
|
32901
|
+
for (;;) {
|
|
32902
|
+
const poster = await renderPoster(posterPage);
|
|
32903
|
+
const start = (posterPage - 1) * 15;
|
|
32904
|
+
const pageEpisodes = displayEpisodes.slice(start, start + 15);
|
|
32905
|
+
const firstEpisode = pageEpisodes[0]?.episode ?? 0;
|
|
32906
|
+
const lastEpisode = pageEpisodes[pageEpisodes.length - 1]?.episode ?? 0;
|
|
32907
|
+
const range = firstEpisode === lastEpisode ? `第 ${firstEpisode} 集` : `第 ${firstEpisode}–${lastEpisode} 集`;
|
|
32908
|
+
const sentAt = Date.now();
|
|
32909
|
+
const result = await this.e.reply([...poster, segment.text(`《${videoInfo.data.result.title}》\n${range}(共 ${displayEpisodes.length} 集)\n第 ${posterPage}/${posterPageCount} 页\n发送 第?集 选集${posterPageCount > 1 ? ",发送 上一页 / 下一页 / 第?页 翻页" : ""}(120 秒内有效)`)]);
|
|
32910
|
+
if (emojiFlow) {
|
|
32911
|
+
await emojiFlow.succeed();
|
|
32912
|
+
settleEmojiReaction(this.e);
|
|
32913
|
+
emojiFlow = null;
|
|
32914
|
+
}
|
|
32915
|
+
const previousMessageId = posterMessageId;
|
|
32916
|
+
const previousMessageSentAt = posterMessageSentAt;
|
|
32917
|
+
posterMessageId = result.messageId;
|
|
32918
|
+
posterMessageSentAt = result.messageId ? sentAt : 0;
|
|
32919
|
+
if (previousMessageId && canRecallEpisodeMessage(previousMessageId, previousMessageSentAt)) try {
|
|
32920
|
+
await this.e.bot.recallMsg(this.e.contact, previousMessageId);
|
|
32921
|
+
} catch (error) {
|
|
32922
|
+
logger$1.debug("[选集] 撤回上一页失败:", error);
|
|
32923
|
+
}
|
|
32924
|
+
const context = await karin.ctx(this.e, {
|
|
32925
|
+
reply: true,
|
|
32926
|
+
throwOnTimeout: false,
|
|
32927
|
+
time: 120
|
|
32928
|
+
});
|
|
32929
|
+
if (!context) return true;
|
|
32930
|
+
const replyText = context.msg.trim();
|
|
32931
|
+
if (/^[#/]/.test(replyText) || /(https?:\/\/|b23\.tv|bilibili\.com|douyin\.com|iesdouyin\.com)/i.test(replyText)) return true;
|
|
32932
|
+
emojiFlow = createEmojiReactionFlow(context);
|
|
32933
|
+
await emojiFlow.begin();
|
|
32934
|
+
const pageAction = parseEpisodePosterPageAction(context.msg);
|
|
32935
|
+
if (pageAction) {
|
|
32936
|
+
const nextPage = pageAction.type === "prev" ? posterPage - 1 : pageAction.type === "next" ? posterPage + 1 : pageAction.page;
|
|
32937
|
+
if (nextPage < 1 || nextPage > posterPageCount) {
|
|
32938
|
+
await this.e.reply(`页码超出范围,请发送 1-${posterPageCount} 之间的页码`);
|
|
32939
|
+
await emojiFlow.fail();
|
|
32940
|
+
settleEmojiReaction(this.e);
|
|
32941
|
+
emojiFlow = null;
|
|
32942
|
+
continue;
|
|
32943
|
+
}
|
|
32944
|
+
posterPage = nextPage;
|
|
32212
32945
|
continue;
|
|
32213
32946
|
}
|
|
32214
|
-
|
|
32215
|
-
|
|
32216
|
-
|
|
32217
|
-
|
|
32218
|
-
|
|
32219
|
-
|
|
32220
|
-
|
|
32947
|
+
const parsedEpisode = parseEpisodeNumber(context.msg);
|
|
32948
|
+
if (parsedEpisode === null || parsedEpisode > sourceEpisodes.length) {
|
|
32949
|
+
await this.e.reply(parsedEpisode === null ? "匹配内容失败,请发送 第?集 选择集数,或发送 上一页 / 下一页 / 第?页 翻页" : `第${parsedEpisode}集不在可解析的剧集里,请重新选择`);
|
|
32950
|
+
await emojiFlow.fail();
|
|
32951
|
+
settleEmojiReaction(this.e);
|
|
32952
|
+
emojiFlow = null;
|
|
32953
|
+
continue;
|
|
32954
|
+
}
|
|
32955
|
+
selectedIndex = parsedEpisode - 1;
|
|
32956
|
+
break;
|
|
32221
32957
|
}
|
|
32222
|
-
|
|
32223
|
-
|
|
32958
|
+
} catch (error) {
|
|
32959
|
+
if (emojiFlow) await emojiFlow.fail();
|
|
32960
|
+
throw error;
|
|
32224
32961
|
}
|
|
32225
32962
|
}
|
|
32226
32963
|
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;
|
|
32964
|
+
try {
|
|
32965
|
+
if (!episodeInfo) {
|
|
32966
|
+
await this.e.reply("未找到该集,请重新发送番剧链接");
|
|
32967
|
+
if (emojiFlow) await emojiFlow.fail();
|
|
32968
|
+
await settleEmojiReaction(this.e, "ERROR");
|
|
32969
|
+
return true;
|
|
32970
|
+
}
|
|
32971
|
+
const displayEpisode = selectedIndex + 1;
|
|
32972
|
+
this.downloadfilename = episodeInfo.share_copy.substring(0, 50).replace(/[\\/:*?"<>|\r\n\s]/g, " ");
|
|
32973
|
+
await this.e.reply(`收到请求,第${displayEpisode}集\n${this.downloadfilename}\n正在下载中`);
|
|
32974
|
+
const bangumidataBASEURL = bilibiliApiUrls.getBangumiStream({
|
|
32975
|
+
cid: episodeInfo.cid,
|
|
32976
|
+
ep_id: episodeInfo.ep_id.toString()
|
|
32254
32977
|
});
|
|
32255
|
-
|
|
32256
|
-
|
|
32257
|
-
|
|
32258
|
-
|
|
32259
|
-
|
|
32260
|
-
|
|
32261
|
-
|
|
32262
|
-
|
|
32263
|
-
|
|
32264
|
-
|
|
32978
|
+
const Params = await genParams(bangumidataBASEURL);
|
|
32979
|
+
if (!this.islogin) await this.e.reply("B站ck未配置或已失效,无法获取视频流,可尝试【#B站登录】以配置新ck");
|
|
32980
|
+
const playUrlData = await new Network({
|
|
32981
|
+
url: bangumidataBASEURL + Params,
|
|
32982
|
+
headers: this.headers
|
|
32983
|
+
}).getData();
|
|
32984
|
+
if (episodeInfo.badge === "会员" && !this.isVIP) {
|
|
32985
|
+
logger$1.warn("该CK不是大会员,无法获取视频流");
|
|
32986
|
+
if (emojiFlow) await emojiFlow.fail();
|
|
32987
|
+
await settleEmojiReaction(this.e, "ERROR");
|
|
32988
|
+
return true;
|
|
32989
|
+
}
|
|
32990
|
+
if (Config.bilibili.videoQuality === 0) {
|
|
32991
|
+
/** 提取出视频流信息对象,并排除清晰度重复的视频流 */
|
|
32992
|
+
const simplify = playUrlData.result.dash.video.filter((item, index, self) => {
|
|
32993
|
+
return self.findIndex((t) => {
|
|
32994
|
+
return t.id === item.id;
|
|
32995
|
+
}) === index;
|
|
32996
|
+
});
|
|
32997
|
+
/** 替换原始的视频信息对象 */
|
|
32998
|
+
playUrlData.result.dash.video = simplify;
|
|
32999
|
+
/** 给视频信息对象删除不符合条件的视频流 */
|
|
33000
|
+
const correctList = await bilibiliProcessVideos({
|
|
33001
|
+
accept_description: playUrlData.result.accept_description,
|
|
33002
|
+
bvid: videoInfo.data.result.season_id.toString(),
|
|
33003
|
+
qn: Config.bilibili.videoQuality
|
|
33004
|
+
}, simplify, getBilibiliStreamUrl(playUrlData.result.dash.audio?.[0]));
|
|
33005
|
+
playUrlData.result.dash.video = correctList.videoList;
|
|
33006
|
+
playUrlData.result.cept_description = correctList.accept_description;
|
|
33007
|
+
}
|
|
33008
|
+
await this.getvideo({
|
|
33009
|
+
infoData: videoInfo.data,
|
|
33010
|
+
playUrlData
|
|
33011
|
+
});
|
|
33012
|
+
if (emojiFlow) await emojiFlow.succeed();
|
|
33013
|
+
} catch (error) {
|
|
33014
|
+
if (emojiFlow) await emojiFlow.fail();
|
|
33015
|
+
throw error;
|
|
32265
33016
|
}
|
|
32266
|
-
await this.getvideo({
|
|
32267
|
-
infoData: videoInfo.data,
|
|
32268
|
-
playUrlData
|
|
32269
|
-
});
|
|
32270
33017
|
break;
|
|
32271
33018
|
}
|
|
32272
33019
|
case "dynamic_info": {
|
|
@@ -37126,13 +37873,13 @@ var DouYin = class DouYin extends Base {
|
|
|
37126
37873
|
if (VideoData.data.aweme_detail === null) throw new Error("获取作品详情失败,可能是因为该作品已被删除或设置为私密。");
|
|
37127
37874
|
/**
|
|
37128
37875
|
* 根据 aweme_type 判断作品类型
|
|
37129
|
-
* - `0`、`4`、`55`:视频作品;`4` 是剧集合集
|
|
37876
|
+
* - `0`、`4`、`55`、`61`:视频作品;`4` 是剧集合集
|
|
37130
37877
|
* - `163`:文章作品
|
|
37131
37878
|
* - `68`:图文作品(含图集、合辑等)
|
|
37132
37879
|
*/
|
|
37133
37880
|
const aweme_type = VideoData.data.aweme_detail.aweme_type;
|
|
37134
37881
|
const isArticle = aweme_type === 163;
|
|
37135
|
-
const isVideo = aweme_type === 0 || aweme_type === 4 || aweme_type === 55;
|
|
37882
|
+
const isVideo = aweme_type === 0 || aweme_type === 4 || aweme_type === 55 || aweme_type === 61;
|
|
37136
37883
|
const CommentsData = await this.amagi.douyin.fetcher.fetchWorkComments({
|
|
37137
37884
|
aweme_id: data.aweme_id,
|
|
37138
37885
|
number: Config.douyin.numcomment
|
|
@@ -37709,28 +38456,17 @@ var DouYin = class DouYin extends Base {
|
|
|
37709
38456
|
if (context) {
|
|
37710
38457
|
const num = parseInt(context.msg.trim());
|
|
37711
38458
|
if (!isNaN(num) && num >= 1 && num <= displayVideos.length) {
|
|
37712
|
-
const
|
|
37713
|
-
|
|
37714
|
-
let successTimer = null;
|
|
37715
|
-
await emojiManager.add("EYES");
|
|
37716
|
-
processingTimer = setTimeout(() => {
|
|
37717
|
-
emojiManager.add("PROCESSING").catch(() => {});
|
|
37718
|
-
}, 1500);
|
|
38459
|
+
const emojiFlow = createEmojiReactionFlow(context);
|
|
38460
|
+
await emojiFlow.begin();
|
|
37719
38461
|
try {
|
|
37720
38462
|
const targetData = {
|
|
37721
38463
|
type: "one_work",
|
|
37722
38464
|
aweme_id: displayVideos[num - 1].aweme_id
|
|
37723
38465
|
};
|
|
37724
38466
|
await new DouYin(context, targetData).DouyinHandler(targetData);
|
|
37725
|
-
|
|
37726
|
-
emojiManager.replace("PROCESSING", "SUCCESS").catch(() => {});
|
|
37727
|
-
}, 1500);
|
|
38467
|
+
await emojiFlow.succeed();
|
|
37728
38468
|
} catch (error) {
|
|
37729
|
-
|
|
37730
|
-
if (successTimer) clearTimeout(successTimer);
|
|
37731
|
-
const processingEmojiId = getEmojiId(context, "PROCESSING");
|
|
37732
|
-
if (emojiManager.has(processingEmojiId)) await emojiManager.remove("PROCESSING");
|
|
37733
|
-
await emojiManager.add("ERROR");
|
|
38469
|
+
await emojiFlow.fail();
|
|
37734
38470
|
throw error;
|
|
37735
38471
|
}
|
|
37736
38472
|
}
|
|
@@ -37795,6 +38531,7 @@ var DouYin = class DouYin extends Base {
|
|
|
37795
38531
|
title: mixInfo.mix_name,
|
|
37796
38532
|
platform: "douyin",
|
|
37797
38533
|
scene: this.e.isFriend ? "friend" : "group",
|
|
38534
|
+
ownerId: this.e.userId,
|
|
37798
38535
|
poster,
|
|
37799
38536
|
posterPage: initialPage,
|
|
37800
38537
|
renderPoster,
|
|
@@ -37817,56 +38554,79 @@ var DouYin = class DouYin extends Base {
|
|
|
37817
38554
|
/** 上一页海报消息,翻页发送成功后撤回,避免聊天里堆一串过期海报 */
|
|
37818
38555
|
let posterMessageId = "";
|
|
37819
38556
|
let posterMessageSentAt = 0;
|
|
37820
|
-
|
|
37821
|
-
|
|
37822
|
-
|
|
37823
|
-
|
|
37824
|
-
|
|
37825
|
-
|
|
37826
|
-
|
|
37827
|
-
|
|
37828
|
-
|
|
37829
|
-
|
|
37830
|
-
|
|
37831
|
-
|
|
37832
|
-
|
|
37833
|
-
|
|
37834
|
-
|
|
37835
|
-
|
|
37836
|
-
|
|
37837
|
-
|
|
37838
|
-
|
|
37839
|
-
|
|
37840
|
-
|
|
37841
|
-
|
|
37842
|
-
|
|
37843
|
-
|
|
37844
|
-
|
|
37845
|
-
|
|
37846
|
-
|
|
37847
|
-
|
|
37848
|
-
|
|
37849
|
-
|
|
37850
|
-
|
|
38557
|
+
/** 子上下文消息的表情反馈流程:翻页时留到新海报发出后再算成功 */
|
|
38558
|
+
let emojiFlow = null;
|
|
38559
|
+
try {
|
|
38560
|
+
for (;;) {
|
|
38561
|
+
const poster = await renderPoster(posterPage);
|
|
38562
|
+
const start = (posterPage - 1) * 15;
|
|
38563
|
+
const pageEpisodes = displayEpisodes.slice(start, start + 15);
|
|
38564
|
+
const firstEpisode = pageEpisodes[0]?.episode ?? 0;
|
|
38565
|
+
const lastEpisode = pageEpisodes[pageEpisodes.length - 1]?.episode ?? 0;
|
|
38566
|
+
const range = firstEpisode === lastEpisode ? `第 ${firstEpisode} 集` : `第 ${firstEpisode}–${lastEpisode} 集`;
|
|
38567
|
+
const sentAt = Date.now();
|
|
38568
|
+
const result = await this.e.reply([...poster, segment.text(`《${mixInfo.mix_name}》\n${range}(共 ${totalEpisode} 集,已列出 ${displayEpisodes.length} 集)\n第 ${posterPage}/${posterPageCount} 页\n发送 第?集 选集${posterPageCount > 1 ? ",发送 上一页 / 下一页 / 第?页 翻页" : ""}(${timeoutSeconds} 秒内有效)`)]);
|
|
38569
|
+
if (emojiFlow) {
|
|
38570
|
+
await emojiFlow.succeed();
|
|
38571
|
+
settleEmojiReaction(this.e);
|
|
38572
|
+
emojiFlow = null;
|
|
38573
|
+
}
|
|
38574
|
+
const previousMessageId = posterMessageId;
|
|
38575
|
+
const previousMessageSentAt = posterMessageSentAt;
|
|
38576
|
+
posterMessageId = result.messageId;
|
|
38577
|
+
posterMessageSentAt = result.messageId ? sentAt : 0;
|
|
38578
|
+
if (previousMessageId && canRecallEpisodeMessage(previousMessageId, previousMessageSentAt)) try {
|
|
38579
|
+
await this.e.bot.recallMsg(this.e.contact, previousMessageId);
|
|
38580
|
+
} catch (error) {
|
|
38581
|
+
logger.debug("[选集] 撤回上一页失败:", error);
|
|
38582
|
+
}
|
|
38583
|
+
const context = await karin.ctx(this.e, {
|
|
38584
|
+
reply: true,
|
|
38585
|
+
throwOnTimeout: false,
|
|
38586
|
+
time: timeoutSeconds
|
|
38587
|
+
});
|
|
38588
|
+
if (!context) return true;
|
|
38589
|
+
const replyText = context.msg.trim();
|
|
38590
|
+
if (/^[#/]/.test(replyText) || /(https?:\/\/|b23\.tv|bilibili\.com|douyin\.com|iesdouyin\.com)/i.test(replyText)) return true;
|
|
38591
|
+
emojiFlow = createEmojiReactionFlow(context);
|
|
38592
|
+
await emojiFlow.begin();
|
|
38593
|
+
const pageAction = parseEpisodePosterPageAction(context.msg);
|
|
38594
|
+
if (pageAction) {
|
|
38595
|
+
const nextPage = pageAction.type === "prev" ? posterPage - 1 : pageAction.type === "next" ? posterPage + 1 : pageAction.page;
|
|
38596
|
+
if (nextPage < 1 || nextPage > posterPageCount) {
|
|
38597
|
+
await this.e.reply(`页码超出范围,请发送 1-${posterPageCount} 之间的页码`);
|
|
38598
|
+
await emojiFlow.fail();
|
|
38599
|
+
settleEmojiReaction(this.e);
|
|
38600
|
+
emojiFlow = null;
|
|
38601
|
+
continue;
|
|
38602
|
+
}
|
|
38603
|
+
posterPage = nextPage;
|
|
37851
38604
|
continue;
|
|
37852
38605
|
}
|
|
37853
|
-
|
|
37854
|
-
|
|
37855
|
-
|
|
37856
|
-
|
|
37857
|
-
|
|
37858
|
-
|
|
37859
|
-
|
|
37860
|
-
|
|
38606
|
+
const episode = parseEpisodeNumber(context.msg);
|
|
38607
|
+
const target = episode === null ? void 0 : displayEpisodes.find((item) => item.episode === episode);
|
|
38608
|
+
if (!target) {
|
|
38609
|
+
await this.e.reply(episode === null ? "匹配内容失败,请发送 第?集 选择集数,或发送 上一页 / 下一页 / 第?页 翻页" : `第${episode}集不在可解析的剧集里,请重新选择`);
|
|
38610
|
+
await emojiFlow.fail();
|
|
38611
|
+
settleEmojiReaction(this.e);
|
|
38612
|
+
emojiFlow = null;
|
|
38613
|
+
continue;
|
|
38614
|
+
}
|
|
38615
|
+
const episodeTitle = (isPlaylet ? mixInfo.mix_name : target.title || mixInfo.mix_name).replace(/\s+/g, " ").trim();
|
|
38616
|
+
await this.e.reply(`收到请求,第${episode}集\n${episodeTitle}\n正在解析中`);
|
|
38617
|
+
const targetData = {
|
|
38618
|
+
type: "one_work",
|
|
38619
|
+
aweme_id: target.aweme_id
|
|
38620
|
+
};
|
|
38621
|
+
await new DouYin(context, targetData, { forceBurnDanmaku: this.forceBurnDanmaku }).DouyinHandler(targetData);
|
|
38622
|
+
await emojiFlow.succeed();
|
|
38623
|
+
settleEmojiReaction(this.e);
|
|
38624
|
+
emojiFlow = null;
|
|
38625
|
+
return true;
|
|
37861
38626
|
}
|
|
37862
|
-
|
|
37863
|
-
await
|
|
37864
|
-
|
|
37865
|
-
type: "one_work",
|
|
37866
|
-
aweme_id: target.aweme_id
|
|
37867
|
-
};
|
|
37868
|
-
await new DouYin(context, targetData, { forceBurnDanmaku: this.forceBurnDanmaku }).DouyinHandler(targetData);
|
|
37869
|
-
return true;
|
|
38627
|
+
} catch (error) {
|
|
38628
|
+
if (emojiFlow) await emojiFlow.fail();
|
|
38629
|
+
throw error;
|
|
37870
38630
|
}
|
|
37871
38631
|
}
|
|
37872
38632
|
case "music_work": {
|
|
@@ -42467,6 +43227,10 @@ var handleEpisodeSelection = wrapWithErrorHandler(async (e, next) => {
|
|
|
42467
43227
|
await e.reply("本次选集已结束,请重新发送原链接", { at: true });
|
|
42468
43228
|
return true;
|
|
42469
43229
|
}
|
|
43230
|
+
if (!isEpisodeSelectionOwner(session, e.userId)) {
|
|
43231
|
+
await e.reply("这次选集只对发起人生效,请自己发送原链接", { at: true });
|
|
43232
|
+
return true;
|
|
43233
|
+
}
|
|
42470
43234
|
if (!actionText) {
|
|
42471
43235
|
await e.reply("请点击下方按钮,或点击「跳转到第x页」输入页码");
|
|
42472
43236
|
return true;
|