karin-plugin-kkk 2.45.2-beta.0 → 2.45.2-beta.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 +24 -0
- package/lib/apps/admin.js +1 -1
- package/lib/apps/help.js +1 -1
- package/lib/apps/push.js +1 -1
- package/lib/apps/qrlogin.js +1 -1
- package/lib/apps/statistics.js +1 -1
- package/lib/apps/testPush.js +1 -1
- package/lib/apps/tools.js +2 -2
- package/lib/build-metadata.json +5 -5
- package/lib/core_chunk/RiskVerify.js +1 -1
- package/lib/core_chunk/amagiClient.js +1 -1
- package/lib/core_chunk/db.js +1 -1
- package/lib/core_chunk/main.js +1210 -320
- package/lib/root.js +1 -1
- package/lib/style.css +89 -39
- package/lib/template-registry.js +1 -1
- package/lib/web.config.js +1 -1
- package/package.json +2 -2
package/lib/core_chunk/main.js
CHANGED
|
@@ -7,7 +7,7 @@ import fs from "node:fs";
|
|
|
7
7
|
import path, { resolve } from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
import karin, { BOT_CONNECT, app, authMiddleware, checkPkgUpdate, common, config, createBadRequestResponse, createNotFoundResponse, createServerErrorResponse, createSuccessResponse, db, defineConfig, exec, ffmpeg, ffprobe, getPkgVersion, getRemotePkgVersion, hooks, isDocker, karin as karin$1, karinPathHtml, logger, logs, mkdirSync, parseChangelog, range, render, restart, segment, updatePkg, watch } from "node-karin";
|
|
10
|
-
import crypto from "node:crypto";
|
|
10
|
+
import crypto, { randomBytes } from "node:crypto";
|
|
11
11
|
import { deflateSync, inflateSync } from "node:zlib";
|
|
12
12
|
import express from "node-karin/express";
|
|
13
13
|
import axios, { AxiosError } from "node-karin/axios";
|
|
@@ -1113,6 +1113,7 @@ var Common = new class Tools {
|
|
|
1113
1113
|
unit = 1;
|
|
1114
1114
|
}
|
|
1115
1115
|
}
|
|
1116
|
+
if (unit > 1) temp += unit;
|
|
1116
1117
|
return result + temp;
|
|
1117
1118
|
}
|
|
1118
1119
|
/**
|
|
@@ -7644,6 +7645,7 @@ var templateFonts = (() => {
|
|
|
7644
7645
|
var SMART_THEME_PATHS = /* @__PURE__ */ new Set([
|
|
7645
7646
|
"douyin/video-work",
|
|
7646
7647
|
"douyin/image-work",
|
|
7648
|
+
"douyin/mix",
|
|
7647
7649
|
"bilibili/dynamic/DYNAMIC_TYPE_LIVE_RCMD"
|
|
7648
7650
|
]);
|
|
7649
7651
|
/**
|
|
@@ -7653,7 +7655,7 @@ var SMART_THEME_PATHS = /* @__PURE__ */ new Set([
|
|
|
7653
7655
|
*/
|
|
7654
7656
|
var getCoverUrl$1 = (path, data) => {
|
|
7655
7657
|
if (!data || typeof data !== "object") return "";
|
|
7656
|
-
if (path === "douyin/video-work" || path === "bilibili/dynamic/DYNAMIC_TYPE_LIVE_RCMD") {
|
|
7658
|
+
if (path === "douyin/video-work" || path === "douyin/mix" || path === "bilibili/dynamic/DYNAMIC_TYPE_LIVE_RCMD") {
|
|
7657
7659
|
const imageUrl = data.image_url;
|
|
7658
7660
|
return typeof imageUrl === "string" ? imageUrl : "";
|
|
7659
7661
|
}
|
|
@@ -11789,6 +11791,8 @@ var DecorationCard = ({ data }) => {
|
|
|
11789
11791
|
};
|
|
11790
11792
|
//#endregion
|
|
11791
11793
|
//#region ktr/template/bilibili/bangumi/components/bangumi.tsx
|
|
11794
|
+
/** 海报每页展示的集数,和 core 的 EPISODE_SELECTION_PAGE_SIZE 保持一致 */
|
|
11795
|
+
var DEFAULT_POSTER_PAGE_SIZE$1 = 15;
|
|
11792
11796
|
/**
|
|
11793
11797
|
* 格式化数字显示
|
|
11794
11798
|
* @param num 要格式化的数字
|
|
@@ -11812,20 +11816,6 @@ var formatDateParts = (timestamp) => {
|
|
|
11812
11816
|
};
|
|
11813
11817
|
};
|
|
11814
11818
|
/**
|
|
11815
|
-
* 格式化完整日期时间
|
|
11816
|
-
* @param timestamp 时间戳
|
|
11817
|
-
* @returns 格式化的日期时间字符串
|
|
11818
|
-
*/
|
|
11819
|
-
var formatDateTime = (timestamp) => {
|
|
11820
|
-
return (/* @__PURE__ */ new Date(timestamp * 1e3)).toLocaleDateString("zh-CN", {
|
|
11821
|
-
year: "numeric",
|
|
11822
|
-
month: "short",
|
|
11823
|
-
day: "numeric",
|
|
11824
|
-
hour: "2-digit",
|
|
11825
|
-
minute: "2-digit"
|
|
11826
|
-
});
|
|
11827
|
-
};
|
|
11828
|
-
/**
|
|
11829
11819
|
* B站番剧头部组件
|
|
11830
11820
|
* @param props 头部组件属性
|
|
11831
11821
|
*/
|
|
@@ -11837,102 +11827,88 @@ var BangumiBilibiliHeader = (props) => {
|
|
|
11837
11827
|
className: "flex relative z-10 gap-25 p-25",
|
|
11838
11828
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11839
11829
|
className: "flex flex-col shrink-0 gap-20",
|
|
11840
|
-
children: [
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
className: "
|
|
11851
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11852
|
-
className: "relative",
|
|
11853
|
-
children: [
|
|
11854
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
11855
|
-
className: "w-28 h-28 rounded-full select-text",
|
|
11856
|
-
src: `https://images.weserv.nl/?url=${encodeURIComponent(props.upInfo.avatar)}`,
|
|
11857
|
-
alt: props.upInfo.uname
|
|
11858
|
-
}),
|
|
11859
|
-
props.upInfo.avatar_subscript_url && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
11860
|
-
className: "absolute -right-1 -bottom-1 w-8 h-8 select-text",
|
|
11861
|
-
src: props.upInfo.avatar_subscript_url,
|
|
11862
|
-
alt: "头像角标"
|
|
11863
|
-
}),
|
|
11864
|
-
props.upInfo.pendant?.image && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
11865
|
-
className: "absolute inset-0 w-full h-full transform select-text scale-160",
|
|
11866
|
-
src: props.upInfo.pendant.image,
|
|
11867
|
-
alt: props.upInfo.pendant.name || "挂件"
|
|
11868
|
-
})
|
|
11869
|
-
]
|
|
11870
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11871
|
-
className: "flex flex-col gap-4",
|
|
11872
|
-
children: [
|
|
11873
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11874
|
-
className: "flex gap-3 items-center",
|
|
11875
|
-
children: [
|
|
11876
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
11877
|
-
className: "text-4xl font-medium select-text",
|
|
11878
|
-
style: { color: props.upInfo.vip_status === 1 ? props.upInfo.nickname_color || "#FB7299" : "#EDEDED" },
|
|
11879
|
-
children: props.upInfo.uname
|
|
11880
|
-
}),
|
|
11881
|
-
props.upInfo.verify_type > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
11882
|
-
className: "flex items-center",
|
|
11883
|
-
children: props.upInfo.verify_type === 1 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Shield, {
|
|
11884
|
-
width: 20,
|
|
11885
|
-
className: "text-warning"
|
|
11886
|
-
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Crown, {
|
|
11887
|
-
width: 20,
|
|
11888
|
-
className: "text-accent"
|
|
11889
|
-
})
|
|
11890
|
-
}),
|
|
11891
|
-
props.upInfo.vip_status === 1 && props.upInfo.vip_label?.text && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chip, {
|
|
11892
|
-
size: "sm",
|
|
11893
|
-
className: "px-2 py-1 text-xs select-text",
|
|
11894
|
-
style: {
|
|
11895
|
-
backgroundColor: props.upInfo.vip_label.bg_color || "#FB7299",
|
|
11896
|
-
color: props.upInfo.vip_label.text_color || "#FFFFFF",
|
|
11897
|
-
borderColor: props.upInfo.vip_label.border_color || "transparent"
|
|
11898
|
-
},
|
|
11899
|
-
children: props.upInfo.vip_label.text
|
|
11900
|
-
})
|
|
11901
|
-
]
|
|
11902
|
-
}),
|
|
11903
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11904
|
-
className: "flex gap-6 items-center text-3xl select-text text-foreground",
|
|
11905
|
-
children: [
|
|
11906
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Users, { size: 30 }),
|
|
11907
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [formatNumber$2(props.upInfo.follower), "粉丝"] }),
|
|
11908
|
-
props.upInfo.is_follow === 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chip, {
|
|
11909
|
-
size: "sm",
|
|
11910
|
-
color: "accent",
|
|
11911
|
-
variant: "soft",
|
|
11912
|
-
className: "text-xs select-text",
|
|
11913
|
-
children: "已关注"
|
|
11914
|
-
})
|
|
11915
|
-
]
|
|
11916
|
-
}),
|
|
11917
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11918
|
-
className: "flex gap-2 items-center text-2xl select-text text-foreground/70",
|
|
11919
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Hash, { size: 20 }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: ["UID: ", props.upInfo.mid] })]
|
|
11920
|
-
})
|
|
11921
|
-
]
|
|
11922
|
-
})]
|
|
11923
|
-
}),
|
|
11924
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11925
|
-
className: "flex text-3xl select-text text-foreground",
|
|
11830
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
11831
|
+
className: "overflow-hidden rounded-4xl w-120 h-160",
|
|
11832
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
11833
|
+
src: props.mainCover,
|
|
11834
|
+
alt: props.title,
|
|
11835
|
+
className: "object-cover w-full h-full select-text"
|
|
11836
|
+
})
|
|
11837
|
+
}), props.upInfo && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11838
|
+
className: "flex gap-12 items-center mt-15",
|
|
11839
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11840
|
+
className: "relative",
|
|
11926
11841
|
children: [
|
|
11927
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
11928
|
-
|
|
11929
|
-
|
|
11930
|
-
|
|
11842
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
11843
|
+
className: "w-28 h-28 rounded-full select-text",
|
|
11844
|
+
src: `https://images.weserv.nl/?url=${encodeURIComponent(props.upInfo.avatar)}`,
|
|
11845
|
+
alt: props.upInfo.uname
|
|
11846
|
+
}),
|
|
11847
|
+
props.upInfo.avatar_subscript_url && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
11848
|
+
className: "absolute -right-1 -bottom-1 w-8 h-8 select-text",
|
|
11849
|
+
src: props.upInfo.avatar_subscript_url,
|
|
11850
|
+
alt: "头像角标"
|
|
11931
11851
|
}),
|
|
11932
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
11852
|
+
props.upInfo.pendant?.image && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
11853
|
+
className: "absolute inset-0 w-full h-full transform select-text scale-160",
|
|
11854
|
+
src: props.upInfo.pendant.image,
|
|
11855
|
+
alt: props.upInfo.pendant.name || "挂件"
|
|
11856
|
+
})
|
|
11933
11857
|
]
|
|
11934
|
-
})
|
|
11935
|
-
|
|
11858
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11859
|
+
className: "flex flex-col gap-4",
|
|
11860
|
+
children: [
|
|
11861
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11862
|
+
className: "flex gap-3 items-center",
|
|
11863
|
+
children: [
|
|
11864
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
11865
|
+
className: "text-4xl font-medium select-text",
|
|
11866
|
+
style: { color: props.upInfo.vip_status === 1 ? props.upInfo.nickname_color || "#FB7299" : "#EDEDED" },
|
|
11867
|
+
children: props.upInfo.uname
|
|
11868
|
+
}),
|
|
11869
|
+
props.upInfo.verify_type > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
11870
|
+
className: "flex items-center",
|
|
11871
|
+
children: props.upInfo.verify_type === 1 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Shield, {
|
|
11872
|
+
width: 20,
|
|
11873
|
+
className: "text-warning"
|
|
11874
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Crown, {
|
|
11875
|
+
width: 20,
|
|
11876
|
+
className: "text-accent"
|
|
11877
|
+
})
|
|
11878
|
+
}),
|
|
11879
|
+
props.upInfo.vip_status === 1 && props.upInfo.vip_label?.text && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chip, {
|
|
11880
|
+
size: "sm",
|
|
11881
|
+
className: "px-2 py-1 text-xs select-text",
|
|
11882
|
+
style: {
|
|
11883
|
+
backgroundColor: props.upInfo.vip_label.bg_color || "#FB7299",
|
|
11884
|
+
color: props.upInfo.vip_label.text_color || "#FFFFFF",
|
|
11885
|
+
borderColor: props.upInfo.vip_label.border_color || "transparent"
|
|
11886
|
+
},
|
|
11887
|
+
children: props.upInfo.vip_label.text
|
|
11888
|
+
})
|
|
11889
|
+
]
|
|
11890
|
+
}),
|
|
11891
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11892
|
+
className: "flex gap-6 items-center text-3xl select-text text-foreground",
|
|
11893
|
+
children: [
|
|
11894
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Users, { size: 30 }),
|
|
11895
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [formatNumber$2(props.upInfo.follower), "粉丝"] }),
|
|
11896
|
+
props.upInfo.is_follow === 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chip, {
|
|
11897
|
+
size: "sm",
|
|
11898
|
+
color: "accent",
|
|
11899
|
+
variant: "soft",
|
|
11900
|
+
className: "text-xs select-text",
|
|
11901
|
+
children: "已关注"
|
|
11902
|
+
})
|
|
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] })]
|
|
11908
|
+
})
|
|
11909
|
+
]
|
|
11910
|
+
})]
|
|
11911
|
+
})]
|
|
11936
11912
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11937
11913
|
className: "flex flex-col flex-1 justify-between text-foreground",
|
|
11938
11914
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
@@ -12055,171 +12031,132 @@ var BangumiBilibiliHeader = (props) => {
|
|
|
12055
12031
|
})
|
|
12056
12032
|
});
|
|
12057
12033
|
};
|
|
12034
|
+
/** 文字选集提示里的命令高亮,和海报的强调色保持一致 */
|
|
12035
|
+
var CommandChip$1 = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12036
|
+
className: "inline-flex items-center rounded-xl bg-danger px-4 py-1.5 font-semibold text-danger-foreground",
|
|
12037
|
+
children
|
|
12038
|
+
});
|
|
12058
12039
|
/**
|
|
12059
|
-
* B
|
|
12040
|
+
* B站番剧剧集列表组件。
|
|
12041
|
+
* 每页最多 15 集,3 列网格展示封面 + 标题;长番剧不会再生成超长截图。
|
|
12060
12042
|
* @param props 剧集列表组件属性
|
|
12061
12043
|
*/
|
|
12062
12044
|
var BangumiBilibiliEpisodes = (props) => {
|
|
12063
|
-
const
|
|
12064
|
-
const
|
|
12065
|
-
|
|
12066
|
-
|
|
12067
|
-
|
|
12068
|
-
|
|
12069
|
-
|
|
12070
|
-
|
|
12071
|
-
const
|
|
12072
|
-
const
|
|
12073
|
-
|
|
12074
|
-
const episodesInDate = groupedEpisodes[dateIndex];
|
|
12075
|
-
episodesInDate.forEach((episode, episodeIndex) => {
|
|
12076
|
-
flattenedEpisodes.push({
|
|
12077
|
-
episode,
|
|
12078
|
-
isFirstOfDate: episodeIndex === 0,
|
|
12079
|
-
isLastOfDate: episodeIndex === episodesInDate.length - 1,
|
|
12080
|
-
isLastOfAll: false,
|
|
12081
|
-
dateKey: dateIndex,
|
|
12082
|
-
episodesInSameDate: episodesInDate.length
|
|
12083
|
-
});
|
|
12084
|
-
});
|
|
12085
|
-
});
|
|
12086
|
-
if (flattenedEpisodes.length > 0) flattenedEpisodes[flattenedEpisodes.length - 1].isLastOfAll = true;
|
|
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} 集`;
|
|
12087
12056
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12088
12057
|
className: "px-10",
|
|
12089
|
-
children: [
|
|
12090
|
-
|
|
12091
|
-
|
|
12092
|
-
|
|
12093
|
-
|
|
12094
|
-
|
|
12095
|
-
|
|
12096
|
-
|
|
12097
|
-
|
|
12098
|
-
|
|
12058
|
+
children: [
|
|
12059
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12060
|
+
className: "flex flex-wrap gap-6 items-center mb-16 text-5xl font-bold select-text text-foreground",
|
|
12061
|
+
children: [
|
|
12062
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Play, { size: 46 }),
|
|
12063
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "剧集列表" }),
|
|
12064
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Chip, {
|
|
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
|
+
]
|
|
12080
|
+
}),
|
|
12081
|
+
props.selectionMode !== "button" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12082
|
+
className: "flex flex-col gap-4 mb-12 text-3xl select-text text-foreground/80",
|
|
12083
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12084
|
+
className: "flex flex-wrap gap-3 items-center",
|
|
12099
12085
|
children: [
|
|
12100
|
-
"
|
|
12101
|
-
|
|
12102
|
-
"
|
|
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: "选集" })
|
|
12103
12089
|
]
|
|
12104
|
-
})
|
|
12105
|
-
|
|
12106
|
-
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
|
|
12112
|
-
className: "flex gap-15",
|
|
12113
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12114
|
-
className: "flex flex-col shrink-0 items-center w-20",
|
|
12115
|
-
children: isFirstOfDate ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
12116
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12117
|
-
className: "text-4xl select-text text-foreground",
|
|
12118
|
-
children: month
|
|
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: "/"
|
|
12119
12098
|
}),
|
|
12120
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("
|
|
12121
|
-
|
|
12122
|
-
|
|
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: "/"
|
|
12123
12103
|
}),
|
|
12124
|
-
|
|
12125
|
-
|
|
12126
|
-
|
|
12127
|
-
|
|
12128
|
-
|
|
12129
|
-
|
|
12130
|
-
|
|
12131
|
-
|
|
12132
|
-
|
|
12133
|
-
|
|
12104
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip$1, { children: "第?页" }),
|
|
12105
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "翻页" })
|
|
12106
|
+
]
|
|
12107
|
+
})]
|
|
12108
|
+
}),
|
|
12109
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12110
|
+
className: "grid grid-cols-3 gap-8",
|
|
12111
|
+
children: visibleEpisodes.map((episode, index) => {
|
|
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",
|
|
12134
12116
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12135
|
-
className: "
|
|
12136
|
-
children: [
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
|
|
12141
|
-
|
|
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
|
|
12142
12140
|
})
|
|
12143
|
-
|
|
12144
|
-
|
|
12145
|
-
|
|
12146
|
-
|
|
12147
|
-
|
|
12148
|
-
|
|
12149
|
-
|
|
12150
|
-
|
|
12151
|
-
})]
|
|
12152
|
-
})]
|
|
12153
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12154
|
-
className: "shrink-0 pr-20",
|
|
12155
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12156
|
-
className: "text-5xl font-semibold select-text text-foreground/70",
|
|
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",
|
|
12157
12149
|
children: [
|
|
12158
|
-
|
|
12159
|
-
|
|
12160
|
-
"
|
|
12150
|
+
month,
|
|
12151
|
+
day,
|
|
12152
|
+
"日"
|
|
12161
12153
|
]
|
|
12162
|
-
})
|
|
12163
|
-
})]
|
|
12164
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12165
|
-
className: "overflow-hidden shadow-large bg-surface rounded-4xl",
|
|
12166
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12167
|
-
className: "flex gap-12 p-12",
|
|
12168
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12169
|
-
className: "relative shrink-0",
|
|
12170
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12171
|
-
className: "overflow-hidden relative h-64 rounded-3xl w-md",
|
|
12172
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnhancedImage, {
|
|
12173
|
-
src: episode.cover,
|
|
12174
|
-
alt: `第${actualEpisodeNumber}集 ${episode.long_title}`,
|
|
12175
|
-
className: "object-cover w-full h-full select-text"
|
|
12176
|
-
}), episode.badge && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chip, {
|
|
12177
|
-
size: "lg",
|
|
12178
|
-
className: "absolute top-6 right-8 rounded-2xl py-1 text-lg font-medium select-text scale-150",
|
|
12179
|
-
style: {
|
|
12180
|
-
backgroundColor: episode.badge_info?.bg_color || "#FB7299",
|
|
12181
|
-
color: "#FFFFFF"
|
|
12182
|
-
},
|
|
12183
|
-
children: episode.badge_info?.text || episode.badge
|
|
12184
|
-
})]
|
|
12185
|
-
})
|
|
12186
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12187
|
-
className: "flex flex-col flex-1 justify-center h-64",
|
|
12188
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12189
|
-
className: "mb-8 text-5xl font-semibold select-text text-foreground line-clamp-2",
|
|
12190
|
-
children: episode.long_title
|
|
12191
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12192
|
-
className: "space-y-4 text-4xl",
|
|
12193
|
-
children: [
|
|
12194
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12195
|
-
className: "flex gap-6 items-center select-text text-foreground/70",
|
|
12196
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Hash, { size: 36 }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12197
|
-
className: "truncate",
|
|
12198
|
-
children: episode.bvid
|
|
12199
|
-
})]
|
|
12200
|
-
}),
|
|
12201
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12202
|
-
className: "flex gap-6 items-center select-text text-foreground/70",
|
|
12203
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Clock, { size: 36 }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12204
|
-
className: "whitespace-nowrap",
|
|
12205
|
-
children: formatDateTime(episode.pub_time)
|
|
12206
|
-
})]
|
|
12207
|
-
}),
|
|
12208
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12209
|
-
className: "flex gap-6 items-center select-text text-foreground/70",
|
|
12210
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Share2, { size: 36 }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12211
|
-
className: "truncate",
|
|
12212
|
-
children: episode.link
|
|
12213
|
-
})]
|
|
12214
|
-
})
|
|
12215
|
-
]
|
|
12216
|
-
})]
|
|
12217
12154
|
})]
|
|
12218
|
-
})
|
|
12219
|
-
})
|
|
12220
|
-
})
|
|
12221
|
-
}
|
|
12222
|
-
|
|
12155
|
+
})]
|
|
12156
|
+
}, `${episodeNumber}-${episode.bvid}`);
|
|
12157
|
+
})
|
|
12158
|
+
})
|
|
12159
|
+
]
|
|
12223
12160
|
});
|
|
12224
12161
|
};
|
|
12225
12162
|
var BangumiBilibili = import_react.memo((props) => {
|
|
@@ -16112,7 +16049,7 @@ var DouyinMoreIcon = ({ size = 36, ...props }) => /* @__PURE__ */ (0, import_jsx
|
|
|
16112
16049
|
});
|
|
16113
16050
|
//#endregion
|
|
16114
16051
|
//#region ktr/template/douyin/article-work/components/ArticleWork.tsx
|
|
16115
|
-
var getTitleClassName$
|
|
16052
|
+
var getTitleClassName$3 = (titleLength) => {
|
|
16116
16053
|
if (titleLength > 96) return "text-[42px] leading-[1.34]";
|
|
16117
16054
|
if (titleLength > 72) return "text-[48px] leading-[1.3]";
|
|
16118
16055
|
if (titleLength > 48) return "text-[54px] leading-[1.26]";
|
|
@@ -16271,7 +16208,7 @@ var DouyinPosterHeader$2 = ({ data, ctx }) => {
|
|
|
16271
16208
|
var DouyinArticleTitle = ({ data }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", {
|
|
16272
16209
|
className: "mt-13",
|
|
16273
16210
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
|
|
16274
|
-
className: `${getTitleClassName$
|
|
16211
|
+
className: `${getTitleClassName$3(data.title.length)} font-bold text-foreground select-text`,
|
|
16275
16212
|
style: {
|
|
16276
16213
|
wordBreak: "break-word",
|
|
16277
16214
|
overflowWrap: "break-word"
|
|
@@ -17749,7 +17686,7 @@ var imageMediaTypeMeta = {
|
|
|
17749
17686
|
icon: o$3
|
|
17750
17687
|
}
|
|
17751
17688
|
};
|
|
17752
|
-
var getTitleClassName$
|
|
17689
|
+
var getTitleClassName$2 = (titleLength) => {
|
|
17753
17690
|
if (titleLength > 96) return "text-[42px] leading-[1.34]";
|
|
17754
17691
|
if (titleLength > 72) return "text-[48px] leading-[1.3]";
|
|
17755
17692
|
if (titleLength > 48) return "text-[54px] leading-[1.26]";
|
|
@@ -17871,7 +17808,7 @@ var DouyinPosterTitle$1 = ({ data }) => {
|
|
|
17871
17808
|
const { title, desc } = data;
|
|
17872
17809
|
const hasTitle = Boolean(title?.nodes.length);
|
|
17873
17810
|
const hasDesc = Boolean(desc?.nodes.length);
|
|
17874
|
-
const titleClassName = getTitleClassName$
|
|
17811
|
+
const titleClassName = getTitleClassName$2(title ? extractRichTextPlainText(title).length : 0);
|
|
17875
17812
|
const richTextOptions = {
|
|
17876
17813
|
hashtag: { className: cn("text-inherit opacity-60", !hasTitle && "text-6xl") },
|
|
17877
17814
|
mention: { className: "text-inherit" }
|
|
@@ -18597,6 +18534,418 @@ var live_default = defineTemplate({
|
|
|
18597
18534
|
validate: (data) => typeof data === "object" && data !== null && typeof data.share_url === "string"
|
|
18598
18535
|
});
|
|
18599
18536
|
//#endregion
|
|
18537
|
+
//#region ktr/template/douyin/mix/components/Mix.tsx
|
|
18538
|
+
/** 海报每页展示的集数,和 core 的 EPISODE_SELECTION_PAGE_SIZE 保持一致 */
|
|
18539
|
+
var DEFAULT_POSTER_PAGE_SIZE = 15;
|
|
18540
|
+
/** 万/亿 计数,数值与单位分开返回:数字用大号等宽,单位用小号 */
|
|
18541
|
+
var splitCount = (count) => {
|
|
18542
|
+
if (count >= 1e8) return {
|
|
18543
|
+
value: (count / 1e8).toFixed(1),
|
|
18544
|
+
unit: "亿"
|
|
18545
|
+
};
|
|
18546
|
+
if (count >= 1e4) return {
|
|
18547
|
+
value: (count / 1e4).toFixed(1),
|
|
18548
|
+
unit: "万"
|
|
18549
|
+
};
|
|
18550
|
+
return {
|
|
18551
|
+
value: count.toString(),
|
|
18552
|
+
unit: ""
|
|
18553
|
+
};
|
|
18554
|
+
};
|
|
18555
|
+
/** 总时长:不到一小时按分钟,否则按小时保留一位 */
|
|
18556
|
+
var splitRuntime = (milliseconds) => {
|
|
18557
|
+
const minutes = Math.round(milliseconds / 6e4);
|
|
18558
|
+
if (minutes < 60) return {
|
|
18559
|
+
value: minutes.toString(),
|
|
18560
|
+
unit: "分钟"
|
|
18561
|
+
};
|
|
18562
|
+
return {
|
|
18563
|
+
value: (minutes / 60).toFixed(1),
|
|
18564
|
+
unit: "小时"
|
|
18565
|
+
};
|
|
18566
|
+
};
|
|
18567
|
+
/** 单集时长 mm:ss */
|
|
18568
|
+
var formatDuration$4 = (milliseconds) => {
|
|
18569
|
+
const totalSeconds = Math.round(milliseconds / 1e3);
|
|
18570
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
18571
|
+
const seconds = totalSeconds % 60;
|
|
18572
|
+
return `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
|
|
18573
|
+
};
|
|
18574
|
+
/** 标题按字数分档:短标题撑满,长标题收小并最多三行 */
|
|
18575
|
+
var getTitleClassName$1 = (titleLength) => {
|
|
18576
|
+
if (titleLength <= 8) return "text-[112px] leading-[1.05]";
|
|
18577
|
+
if (titleLength <= 14) return "text-[96px] leading-[1.08]";
|
|
18578
|
+
if (titleLength <= 22) return "text-[76px] leading-[1.12]";
|
|
18579
|
+
return "text-[60px] leading-[1.18]";
|
|
18580
|
+
};
|
|
18581
|
+
/** 弥散背景:海报模糊铺底 + 单色离散杂色 */
|
|
18582
|
+
var MixBackground = ({ data, ctx }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18583
|
+
className: "pointer-events-none absolute inset-0 overflow-hidden select-none",
|
|
18584
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AmbientCover, {
|
|
18585
|
+
src: data.image_url,
|
|
18586
|
+
ctx
|
|
18587
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
18588
|
+
className: "absolute inset-0 opacity-[0.35] mix-blend-overlay dark:mix-blend-soft-light",
|
|
18589
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
|
|
18590
|
+
className: "h-full w-full",
|
|
18591
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
18592
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("filter", {
|
|
18593
|
+
id: "douyinMixNoise",
|
|
18594
|
+
children: [
|
|
18595
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feTurbulence", {
|
|
18596
|
+
type: "fractalNoise",
|
|
18597
|
+
baseFrequency: "0.8",
|
|
18598
|
+
numOctaves: "2",
|
|
18599
|
+
stitchTiles: "stitch"
|
|
18600
|
+
}),
|
|
18601
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feColorMatrix", {
|
|
18602
|
+
type: "saturate",
|
|
18603
|
+
values: "0"
|
|
18604
|
+
}),
|
|
18605
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("feComponentTransfer", { children: [
|
|
18606
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncR", {
|
|
18607
|
+
type: "discrete",
|
|
18608
|
+
tableValues: "0 1"
|
|
18609
|
+
}),
|
|
18610
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncG", {
|
|
18611
|
+
type: "discrete",
|
|
18612
|
+
tableValues: "0 1"
|
|
18613
|
+
}),
|
|
18614
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncB", {
|
|
18615
|
+
type: "discrete",
|
|
18616
|
+
tableValues: "0 1"
|
|
18617
|
+
})
|
|
18618
|
+
] }),
|
|
18619
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feComponentTransfer", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncA", {
|
|
18620
|
+
type: "linear",
|
|
18621
|
+
slope: "2",
|
|
18622
|
+
intercept: "-0.5"
|
|
18623
|
+
}) })
|
|
18624
|
+
]
|
|
18625
|
+
}) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
|
|
18626
|
+
width: "100%",
|
|
18627
|
+
height: "100%",
|
|
18628
|
+
filter: "url(#douyinMixNoise)",
|
|
18629
|
+
fill: "white"
|
|
18630
|
+
})]
|
|
18631
|
+
})
|
|
18632
|
+
})]
|
|
18633
|
+
});
|
|
18634
|
+
var MixHeader = ({ ctx }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
|
|
18635
|
+
className: "flex items-center justify-between",
|
|
18636
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18637
|
+
className: "flex items-center gap-4",
|
|
18638
|
+
children: [
|
|
18639
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "h-4 w-4 rounded-full bg-foreground/80" }),
|
|
18640
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
18641
|
+
className: "text-[26px] font-bold uppercase tracking-[0.24em] text-muted",
|
|
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
|
+
]
|
|
18649
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
|
|
18650
|
+
src: isDark(ctx) ? "/image/douyin/dylogo-light.svg" : "/image/douyin/dylogo-dark.svg",
|
|
18651
|
+
alt: "抖音",
|
|
18652
|
+
className: "h-17 w-auto shrink-0 object-contain opacity-90"
|
|
18653
|
+
})]
|
|
18654
|
+
});
|
|
18655
|
+
var MixHero = ({ data }) => {
|
|
18656
|
+
const { kind, image_url, mix_name, author, statistics, episodes, total_episode, updated_to_episode } = data;
|
|
18657
|
+
const countUnit = kind === "collection" ? "个视频" : "集";
|
|
18658
|
+
const runtime = splitRuntime(episodes.reduce((sum, item) => sum + item.duration, 0));
|
|
18659
|
+
const stats = [
|
|
18660
|
+
{
|
|
18661
|
+
icon: a,
|
|
18662
|
+
label: "总播放",
|
|
18663
|
+
...splitCount(statistics.play_count)
|
|
18664
|
+
},
|
|
18665
|
+
{
|
|
18666
|
+
icon: DouyinLikeIcon,
|
|
18667
|
+
label: "总点赞",
|
|
18668
|
+
...splitCount(statistics.digg_count)
|
|
18669
|
+
},
|
|
18670
|
+
{
|
|
18671
|
+
icon: DouyinFavoriteIcon,
|
|
18672
|
+
label: "总收藏",
|
|
18673
|
+
...splitCount(statistics.collect_count)
|
|
18674
|
+
},
|
|
18675
|
+
{
|
|
18676
|
+
icon: c,
|
|
18677
|
+
label: "总时长",
|
|
18678
|
+
...runtime
|
|
18679
|
+
}
|
|
18680
|
+
];
|
|
18681
|
+
const follower = splitCount(author.follower_count);
|
|
18682
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
18683
|
+
className: "mt-14 flex gap-14",
|
|
18684
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18685
|
+
className: `relative ${kind === "collection" ? "h-120" : "h-180"} w-120 shrink-0`,
|
|
18686
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
|
|
18687
|
+
src: image_url,
|
|
18688
|
+
alt: "",
|
|
18689
|
+
"aria-hidden": "true",
|
|
18690
|
+
className: "absolute inset-0 h-full w-full scale-[1.06] rounded-[40px] object-cover opacity-55 blur-[36px] saturate-[1.2]",
|
|
18691
|
+
referrerPolicy: "no-referrer",
|
|
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"
|
|
18699
|
+
})]
|
|
18700
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18701
|
+
className: "flex min-w-0 flex-1 flex-col justify-between gap-10",
|
|
18702
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
18703
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
|
|
18704
|
+
className: `${getTitleClassName$1(mix_name.length)} line-clamp-3 font-bold text-balance text-foreground select-text`,
|
|
18705
|
+
style: {
|
|
18706
|
+
wordBreak: "break-word",
|
|
18707
|
+
overflowWrap: "break-word"
|
|
18708
|
+
},
|
|
18709
|
+
children: mix_name
|
|
18710
|
+
}),
|
|
18711
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18712
|
+
className: "mt-8 flex flex-wrap items-center gap-4",
|
|
18713
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
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
|
+
})]
|
|
18729
|
+
}),
|
|
18730
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18731
|
+
className: "mt-10 flex min-w-0 items-center gap-5",
|
|
18732
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
|
|
18733
|
+
src: author.avatar,
|
|
18734
|
+
alt: "头像",
|
|
18735
|
+
className: "h-20 w-20 shrink-0 rounded-full object-cover shadow-xl",
|
|
18736
|
+
referrerPolicy: "no-referrer",
|
|
18737
|
+
crossOrigin: "anonymous"
|
|
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);
|
|
18785
|
+
})
|
|
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
|
|
18809
|
+
})]
|
|
18810
|
+
});
|
|
18811
|
+
};
|
|
18812
|
+
/** 文字选集提示里的命令高亮,和 B 站番剧模板保持一致 */
|
|
18813
|
+
var CommandChip = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
18814
|
+
className: "inline-flex items-center rounded-xl bg-danger px-4 py-1.5 font-semibold text-danger-foreground",
|
|
18815
|
+
children
|
|
18816
|
+
});
|
|
18817
|
+
var MixEpisodes = ({ data }) => {
|
|
18818
|
+
const { kind, episodes, total_episode, updated_to_episode, selectionMode } = data;
|
|
18819
|
+
const pageSize = Math.max(1, data.posterPageSize ?? DEFAULT_POSTER_PAGE_SIZE);
|
|
18820
|
+
const pageCount = Math.max(1, Math.ceil(episodes.length / pageSize));
|
|
18821
|
+
const page = Math.min(Math.max(1, data.posterPage ?? 1), pageCount);
|
|
18822
|
+
const start = (page - 1) * pageSize;
|
|
18823
|
+
const visibleEpisodes = episodes.slice(start, start + pageSize);
|
|
18824
|
+
if (visibleEpisodes.length === 0) return null;
|
|
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",
|
|
18835
|
+
children: [
|
|
18836
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionTitle$1, {
|
|
18837
|
+
extra: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
18838
|
+
className: "text-[30px] font-semibold text-muted",
|
|
18839
|
+
children: selectionMode === "button" ? range : `第 ${page}/${pageCount} 页 · ${range}`
|
|
18840
|
+
}),
|
|
18841
|
+
children: "选集"
|
|
18842
|
+
}),
|
|
18843
|
+
selectionMode !== "button" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18844
|
+
className: "flex flex-col gap-4 mt-8 text-[32px] select-text text-foreground/80",
|
|
18845
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18846
|
+
className: "flex flex-wrap gap-3 items-center",
|
|
18847
|
+
children: [
|
|
18848
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "发送" }),
|
|
18849
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip, { children: "第?集" }),
|
|
18850
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "选集" })
|
|
18851
|
+
]
|
|
18852
|
+
}), pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18853
|
+
className: "flex flex-wrap gap-3 items-center",
|
|
18854
|
+
children: [
|
|
18855
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "发送" }),
|
|
18856
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandChip, { children: "上一页" }),
|
|
18857
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
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: "翻页" })
|
|
18868
|
+
]
|
|
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
|
+
})
|
|
18907
|
+
}),
|
|
18908
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18909
|
+
className: "flex flex-wrap items-center justify-between gap-6 mt-8 text-[26px] text-muted",
|
|
18910
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
18911
|
+
"已列出 ",
|
|
18912
|
+
episodes.length,
|
|
18913
|
+
" / ",
|
|
18914
|
+
total_episode,
|
|
18915
|
+
" ",
|
|
18916
|
+
countUnit,
|
|
18917
|
+
missingEpisodes.length > 0 && `;接口未返回第 ${missingEpisodes.join("、")} ${countUnit},暂不能解析。`,
|
|
18918
|
+
updated_to_episode < total_episode && `;已更新至第 ${updated_to_episode} ${countUnit}。`
|
|
18919
|
+
] }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
18920
|
+
className: "select-text",
|
|
18921
|
+
children: ["图片生成于: ", format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss")]
|
|
18922
|
+
})]
|
|
18923
|
+
})
|
|
18924
|
+
]
|
|
18925
|
+
});
|
|
18926
|
+
};
|
|
18927
|
+
var DouyinMix = import_react.memo((props) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DefaultLayout, {
|
|
18928
|
+
...props,
|
|
18929
|
+
className: "relative overflow-hidden",
|
|
18930
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MixBackground, { ...props }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
18931
|
+
className: "relative z-10 px-20 pt-18",
|
|
18932
|
+
children: [
|
|
18933
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MixHeader, { ...props }),
|
|
18934
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MixHero, { ...props }),
|
|
18935
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MixSynopsis, { ...props }),
|
|
18936
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MixEpisodes, { ...props })
|
|
18937
|
+
]
|
|
18938
|
+
})]
|
|
18939
|
+
}));
|
|
18940
|
+
DouyinMix.displayName = "DouyinMix";
|
|
18941
|
+
//#endregion
|
|
18942
|
+
//#region ktr/template/douyin/mix/index.tsx
|
|
18943
|
+
var mix_default = defineTemplate({
|
|
18944
|
+
name: "合集选集",
|
|
18945
|
+
description: "抖音合集(短剧 / 普通合集)选集列表模板",
|
|
18946
|
+
component: DouyinMix
|
|
18947
|
+
});
|
|
18948
|
+
//#endregion
|
|
18600
18949
|
//#region ktr/template/douyin/musicinfo/components/MusicInfo.tsx
|
|
18601
18950
|
/**
|
|
18602
18951
|
* 抖音Logo头部组件
|
|
@@ -29428,6 +29777,7 @@ var templates = {
|
|
|
29428
29777
|
"douyin/favorite-list": favorite_list_default,
|
|
29429
29778
|
"douyin/image-work": image_work_default,
|
|
29430
29779
|
"douyin/live": live_default,
|
|
29780
|
+
"douyin/mix": mix_default,
|
|
29431
29781
|
"douyin/musicinfo": musicinfo_default,
|
|
29432
29782
|
"douyin/qrcodeImg": qrcodeImg_default$2,
|
|
29433
29783
|
"douyin/recommend-list": recommend_list_default,
|
|
@@ -30205,6 +30555,268 @@ var wrapWithErrorHandler = (fn, options) => {
|
|
|
30205
30555
|
}
|
|
30206
30556
|
};
|
|
30207
30557
|
};
|
|
30558
|
+
/** 每个会话最多缓存几张海报,避免长番剧来回翻页把图片全留在内存里 */
|
|
30559
|
+
var MAX_CACHED_POSTERS = 3;
|
|
30560
|
+
/** 会话表上限,防止异常流量无限堆积 */
|
|
30561
|
+
var MAX_SESSIONS = 500;
|
|
30562
|
+
/** 句中的「第N集」,集数可以是阿拉伯数字或中文数字,数字两侧允许空格 */
|
|
30563
|
+
var EPISODE_IN_TEXT = /第\s*([0-9]+|[零一二三四五六七八九十百千]+)\s*集/;
|
|
30564
|
+
/** 整条回复只有集数:「12」「12集」「十二」 */
|
|
30565
|
+
var EPISODE_ONLY = /^([0-9]+|[零一二三四五六七八九十百千]+)\s*集?$/;
|
|
30566
|
+
/**
|
|
30567
|
+
* 支持按钮 + 上下文交互选集的适配器。
|
|
30568
|
+
* 目前只有 QQBot;后续适配器确认支持 callback 按钮和指令按钮(输入框)后再加入。
|
|
30569
|
+
*/
|
|
30570
|
+
var BUTTON_SELECTION_PROTOCOLS = /* @__PURE__ */ new Set(["qqbot"]);
|
|
30571
|
+
var sessions = /* @__PURE__ */ new Map();
|
|
30572
|
+
var parseStatSkipped = /* @__PURE__ */ new WeakSet();
|
|
30573
|
+
var bilibiliAutoSelectEvents = /* @__PURE__ */ new WeakSet();
|
|
30574
|
+
/**
|
|
30575
|
+
* 从用户输入中解析集数。
|
|
30576
|
+
* @param text 用户输入
|
|
30577
|
+
* @returns 集数(从 1 开始);没解析出来返回 null
|
|
30578
|
+
*/
|
|
30579
|
+
var parseEpisodeNumber = (text) => {
|
|
30580
|
+
const normalized = text.trim();
|
|
30581
|
+
const raw = (EPISODE_IN_TEXT.exec(normalized) ?? EPISODE_ONLY.exec(normalized))?.[1];
|
|
30582
|
+
if (!raw) return null;
|
|
30583
|
+
const episode = /^[0-9]+$/.test(raw) ? Number(raw) : Common.chineseToArabic(raw);
|
|
30584
|
+
return Number.isInteger(episode) && episode > 0 ? episode : null;
|
|
30585
|
+
};
|
|
30586
|
+
/** 解析 `#选集` 命令的第二个参数,支持页码和集数。 */
|
|
30587
|
+
var parseEpisodeSelectionAction = (action) => {
|
|
30588
|
+
const pageMatch = /^page:\s*(\d+)$/.exec(action.trim());
|
|
30589
|
+
if (pageMatch) {
|
|
30590
|
+
const page = Number(pageMatch[1]);
|
|
30591
|
+
return Number.isInteger(page) && page > 0 ? {
|
|
30592
|
+
type: "page",
|
|
30593
|
+
page
|
|
30594
|
+
} : null;
|
|
30595
|
+
}
|
|
30596
|
+
const episode = parseEpisodeNumber(action);
|
|
30597
|
+
return episode === null ? null : {
|
|
30598
|
+
type: "episode",
|
|
30599
|
+
episode
|
|
30600
|
+
};
|
|
30601
|
+
};
|
|
30602
|
+
/**
|
|
30603
|
+
* 解析文字选集的翻页命令。
|
|
30604
|
+
* 支持「上一页」「下一页」「第12页」「十二页」「12页」「page:12」;
|
|
30605
|
+
* 单独的「12」仍然表示集数,避免和选集输入冲突。
|
|
30606
|
+
*/
|
|
30607
|
+
var parseEpisodePosterPageAction = (text) => {
|
|
30608
|
+
const normalized = text.trim();
|
|
30609
|
+
if (/^(?:上一页|上页|上一頁)$/.test(normalized)) return { type: "prev" };
|
|
30610
|
+
if (/^(?:下一页|下页|下一頁)$/.test(normalized)) return { type: "next" };
|
|
30611
|
+
const rawPage = /^page:(\d+)$/.exec(normalized)?.[1] ?? /^(?:第\s*)?([0-9]+|[零一二三四五六七八九十百千]+)\s*页$/.exec(normalized)?.[1];
|
|
30612
|
+
if (!rawPage) return null;
|
|
30613
|
+
const page = /^[0-9]+$/.test(rawPage) ? Number(rawPage) : Common.chineseToArabic(rawPage);
|
|
30614
|
+
return Number.isInteger(page) && page > 0 ? {
|
|
30615
|
+
type: "page",
|
|
30616
|
+
page
|
|
30617
|
+
} : null;
|
|
30618
|
+
};
|
|
30619
|
+
/** 生成会话作用域;群聊内所有人共用,私聊只绑定当前用户。 */
|
|
30620
|
+
var getEpisodeSelectionScope = (event) => {
|
|
30621
|
+
const subPeer = event.contact.subPeer || "";
|
|
30622
|
+
return `${event.selfId}:${event.contact.peer}:${subPeer}`;
|
|
30623
|
+
};
|
|
30624
|
+
/** 当前适配器是否支持按钮 + 上下文交互选集(目前为 QQBot 群聊/单聊)。 */
|
|
30625
|
+
var isButtonSelectionScene = (event) => {
|
|
30626
|
+
return BUTTON_SELECTION_PROTOCOLS.has(event.bot.adapter.protocol) && (event.isGroup || event.isFriend);
|
|
30627
|
+
};
|
|
30628
|
+
/** 标记本次解析只负责发选集,不计入解析统计。 */
|
|
30629
|
+
var markParseStatSkipped = (event) => {
|
|
30630
|
+
parseStatSkipped.add(event);
|
|
30631
|
+
};
|
|
30632
|
+
/** 消费一次性统计跳过标记。 */
|
|
30633
|
+
var consumeParseStatSkip = (event) => {
|
|
30634
|
+
return parseStatSkipped.delete(event);
|
|
30635
|
+
};
|
|
30636
|
+
/** 标记本次 B 站 ep 解析来自选集按钮,需要直接选中对应集。 */
|
|
30637
|
+
var markBilibiliEpisodeAutoSelect = (event) => {
|
|
30638
|
+
bilibiliAutoSelectEvents.add(event);
|
|
30639
|
+
};
|
|
30640
|
+
/** 消费一次 B 站自动选集标记,用户分享的 ep 链接不会命中。 */
|
|
30641
|
+
var consumeBilibiliEpisodeAutoSelect = (event) => {
|
|
30642
|
+
return bilibiliAutoSelectEvents.delete(event);
|
|
30643
|
+
};
|
|
30644
|
+
var cleanupExpiredSessions = () => {
|
|
30645
|
+
const now = Date.now();
|
|
30646
|
+
for (const [token, session] of sessions) if (session.expiresAt <= now) sessions.delete(token);
|
|
30647
|
+
};
|
|
30648
|
+
var createToken = () => {
|
|
30649
|
+
for (;;) {
|
|
30650
|
+
const token = randomBytes(6).toString("base64url");
|
|
30651
|
+
if (!sessions.has(token)) return token;
|
|
30652
|
+
}
|
|
30653
|
+
};
|
|
30654
|
+
/**
|
|
30655
|
+
* 创建一次选集会话。
|
|
30656
|
+
* @param scope 由 {@link getEpisodeSelectionScope} 生成
|
|
30657
|
+
* @param options 海报、剧集和平台信息
|
|
30658
|
+
* @returns 可放进按钮 data 的短 token 会话
|
|
30659
|
+
*/
|
|
30660
|
+
var createEpisodeSelection = (scope, options) => {
|
|
30661
|
+
cleanupExpiredSessions();
|
|
30662
|
+
if (sessions.size >= MAX_SESSIONS) {
|
|
30663
|
+
const oldest = sessions.keys().next().value;
|
|
30664
|
+
if (oldest) sessions.delete(oldest);
|
|
30665
|
+
}
|
|
30666
|
+
const session = {
|
|
30667
|
+
token: createToken(),
|
|
30668
|
+
scope,
|
|
30669
|
+
title: options.title,
|
|
30670
|
+
platform: options.platform,
|
|
30671
|
+
scene: options.scene,
|
|
30672
|
+
pageSize: Math.max(1, options.pageSize ?? 15),
|
|
30673
|
+
poster: options.poster,
|
|
30674
|
+
posterPages: /* @__PURE__ */ new Map([[options.posterPage ?? 1, options.poster]]),
|
|
30675
|
+
renderPoster: options.renderPoster,
|
|
30676
|
+
episodes: options.episodes,
|
|
30677
|
+
forceBurnDanmaku: options.forceBurnDanmaku ?? false,
|
|
30678
|
+
expiresAt: Date.now() + 12e4,
|
|
30679
|
+
currentMessageId: "",
|
|
30680
|
+
currentMessageSentAt: 0
|
|
30681
|
+
};
|
|
30682
|
+
sessions.set(session.token, session);
|
|
30683
|
+
return session;
|
|
30684
|
+
};
|
|
30685
|
+
/** 任务结束后立即关闭会话,旧按钮再次点击时只提示不再解析。 */
|
|
30686
|
+
var endEpisodeSelection = (token, scope) => {
|
|
30687
|
+
const session = sessions.get(token);
|
|
30688
|
+
if (!session || session.scope !== scope) return false;
|
|
30689
|
+
return sessions.delete(token);
|
|
30690
|
+
};
|
|
30691
|
+
/** 读取有效会话;token 不存在、scope 不匹配或已过期时返回 null。 */
|
|
30692
|
+
var getEpisodeSelection = (token, scope) => {
|
|
30693
|
+
const session = sessions.get(token);
|
|
30694
|
+
if (!session) return null;
|
|
30695
|
+
if (session.scope !== scope) return null;
|
|
30696
|
+
if (session.expiresAt <= Date.now()) {
|
|
30697
|
+
sessions.delete(token);
|
|
30698
|
+
return null;
|
|
30699
|
+
}
|
|
30700
|
+
return session;
|
|
30701
|
+
};
|
|
30702
|
+
/** 翻页成功后重新计算 120 秒有效期。 */
|
|
30703
|
+
var touchEpisodeSelection = (token, scope) => {
|
|
30704
|
+
const session = getEpisodeSelection(token, scope);
|
|
30705
|
+
if (!session) return false;
|
|
30706
|
+
session.expiresAt = Date.now() + 12e4;
|
|
30707
|
+
return true;
|
|
30708
|
+
};
|
|
30709
|
+
/** 记录当前选集消息,供下一次翻页撤回。 */
|
|
30710
|
+
var setEpisodeSelectionMessage = (session, messageId, sentAt = Date.now()) => {
|
|
30711
|
+
session.currentMessageId = messageId;
|
|
30712
|
+
session.currentMessageSentAt = messageId ? sentAt : 0;
|
|
30713
|
+
};
|
|
30714
|
+
/** 只有距离发送不超过 110 秒时才尝试撤回,避免顶格撞平台 120 秒窗口。 */
|
|
30715
|
+
var canRecallEpisodeMessage = (messageId, sentAt, now = Date.now()) => {
|
|
30716
|
+
if (!messageId || !sentAt) return false;
|
|
30717
|
+
const age = now - sentAt;
|
|
30718
|
+
return age >= 0 && age <= 11e4;
|
|
30719
|
+
};
|
|
30720
|
+
/** 会话里记录的当前消息是否还能撤回。 */
|
|
30721
|
+
var canRecallEpisodeSelectionMessage = (session, now = Date.now()) => {
|
|
30722
|
+
return canRecallEpisodeMessage(session.currentMessageId, session.currentMessageSentAt, now);
|
|
30723
|
+
};
|
|
30724
|
+
/** 总页数;海报和按钮共用。空选集返回 0。 */
|
|
30725
|
+
var getEpisodePageCount = (session) => {
|
|
30726
|
+
return Math.ceil(session.episodes.length / session.pageSize);
|
|
30727
|
+
};
|
|
30728
|
+
/** 取指定页;页码越界返回 null。 */
|
|
30729
|
+
var getEpisodePage = (session, page) => {
|
|
30730
|
+
if (!Number.isInteger(page) || page < 1) return null;
|
|
30731
|
+
const pageCount = getEpisodePageCount(session);
|
|
30732
|
+
if (page > pageCount) return null;
|
|
30733
|
+
const start = (page - 1) * session.pageSize;
|
|
30734
|
+
const items = session.episodes.slice(start, start + session.pageSize);
|
|
30735
|
+
if (!items.length) return null;
|
|
30736
|
+
return {
|
|
30737
|
+
page,
|
|
30738
|
+
pageCount,
|
|
30739
|
+
items,
|
|
30740
|
+
firstEpisode: items[0].episode,
|
|
30741
|
+
lastEpisode: items[items.length - 1].episode
|
|
30742
|
+
};
|
|
30743
|
+
};
|
|
30744
|
+
/** 取海报页(按需渲染并缓存);没有分页渲染器时始终返回初始海报。 */
|
|
30745
|
+
var getEpisodeSelectionPoster = async (session, posterPage) => {
|
|
30746
|
+
const cached = session.posterPages.get(posterPage);
|
|
30747
|
+
if (cached) return cached;
|
|
30748
|
+
if (!session.renderPoster) return session.poster;
|
|
30749
|
+
const poster = await session.renderPoster(posterPage);
|
|
30750
|
+
session.posterPages.set(posterPage, poster);
|
|
30751
|
+
while (session.posterPages.size > MAX_CACHED_POSTERS) {
|
|
30752
|
+
const oldest = session.posterPages.keys().next().value;
|
|
30753
|
+
if (oldest === void 0) break;
|
|
30754
|
+
session.posterPages.delete(oldest);
|
|
30755
|
+
}
|
|
30756
|
+
return poster;
|
|
30757
|
+
};
|
|
30758
|
+
/**
|
|
30759
|
+
* 生成 QQBot keyboard 行。
|
|
30760
|
+
* 跳转输入行在最上面,集数按钮每行 5 个,翻页按钮单独一行;
|
|
30761
|
+
* 15 集一页时正好 1 + 3 + 1 = 5 行,不会超过 QQBot 的上限。
|
|
30762
|
+
*/
|
|
30763
|
+
var buildEpisodeKeyboardRows = (session, page) => {
|
|
30764
|
+
const data = getEpisodePage(session, page);
|
|
30765
|
+
if (!data) return [];
|
|
30766
|
+
const rows = [];
|
|
30767
|
+
if (data.pageCount > 1) rows.push([{
|
|
30768
|
+
text: "跳转到第x页",
|
|
30769
|
+
data: `#选集 ${session.token} page:`,
|
|
30770
|
+
enter: false,
|
|
30771
|
+
style: 1
|
|
30772
|
+
}]);
|
|
30773
|
+
for (let index = 0; index < data.items.length; index += 5) rows.push(data.items.slice(index, index + 5).map((item) => ({
|
|
30774
|
+
text: String(item.episode),
|
|
30775
|
+
show: String(item.episode),
|
|
30776
|
+
callback: true,
|
|
30777
|
+
data: `#选集 ${session.token} ${item.episode}`,
|
|
30778
|
+
style: 1
|
|
30779
|
+
})));
|
|
30780
|
+
const navigation = [];
|
|
30781
|
+
if (data.page > 1) navigation.push({
|
|
30782
|
+
text: "上一页",
|
|
30783
|
+
callback: true,
|
|
30784
|
+
data: `#选集 ${session.token} page:${data.page - 1}`
|
|
30785
|
+
});
|
|
30786
|
+
if (data.page < data.pageCount) navigation.push({
|
|
30787
|
+
text: "下一页",
|
|
30788
|
+
callback: true,
|
|
30789
|
+
data: `#选集 ${session.token} page:${data.page + 1}`
|
|
30790
|
+
});
|
|
30791
|
+
if (navigation.length) rows.push(navigation);
|
|
30792
|
+
return rows;
|
|
30793
|
+
};
|
|
30794
|
+
/** 生成选集提示文本。 */
|
|
30795
|
+
var buildEpisodeSelectionText = (session, page) => {
|
|
30796
|
+
const data = getEpisodePage(session, page);
|
|
30797
|
+
if (!data) return "";
|
|
30798
|
+
const range = data.firstEpisode === data.lastEpisode ? `第 ${data.firstEpisode} 集` : `第 ${data.firstEpisode}–${data.lastEpisode} 集`;
|
|
30799
|
+
return `《${session.title}》\n${range} · 第 ${data.page}/${data.pageCount} 页\n点击下方按钮选集(120 秒内有效)。`;
|
|
30800
|
+
};
|
|
30801
|
+
/** 按实际集号查找目标。 */
|
|
30802
|
+
var resolveEpisodeTarget = (session, episode) => {
|
|
30803
|
+
return session.episodes.find((item) => item.episode === episode)?.target ?? null;
|
|
30804
|
+
};
|
|
30805
|
+
/** 生成现有解析命令能识别的目标链接。 */
|
|
30806
|
+
var buildEpisodeTargetUrl = (target) => {
|
|
30807
|
+
return target.platform === "douyin" ? `https://www.douyin.com/video/${target.awemeId}` : `https://www.bilibili.com/bangumi/play/ep${target.epId}`;
|
|
30808
|
+
};
|
|
30809
|
+
/**
|
|
30810
|
+
* 组装 QQBot 选集消息:复用已渲染海报,并附当前页文本和 keyboard。
|
|
30811
|
+
* 海报按需传入(翻页跨 15 集区块时由调用方重新渲染),默认复用初始海报。
|
|
30812
|
+
*/
|
|
30813
|
+
var buildEpisodeSelectionReply = (session, page, poster = session.poster) => {
|
|
30814
|
+
const text = buildEpisodeSelectionText(session, page);
|
|
30815
|
+
const rows = buildEpisodeKeyboardRows(session, page);
|
|
30816
|
+
const elements = [...poster, segment.text(text)];
|
|
30817
|
+
if (rows.length) elements.push(segment.keyboard(rows));
|
|
30818
|
+
return elements;
|
|
30819
|
+
};
|
|
30208
30820
|
//#endregion
|
|
30209
30821
|
//#region src/platform/bilibili/danmaku.ts
|
|
30210
30822
|
/**
|
|
@@ -31489,8 +32101,13 @@ var Bilibili = class extends Base {
|
|
|
31489
32101
|
const videoInfo = await this.amagi.bilibili.fetcher.fetchBangumiInfo({ [iddata.isEpid ? "ep_id" : "season_id"]: iddata.realid });
|
|
31490
32102
|
this.islogin = (await checkCk()).Status === "isLogin";
|
|
31491
32103
|
this.isVIP = (await checkCk()).isVIP;
|
|
31492
|
-
const
|
|
31493
|
-
|
|
32104
|
+
const sourceEpisodes = videoInfo.data.result.episodes ?? [];
|
|
32105
|
+
if (!sourceEpisodes.length) {
|
|
32106
|
+
await this.e.reply("未获取到可解析的剧集,请稍后重试");
|
|
32107
|
+
return true;
|
|
32108
|
+
}
|
|
32109
|
+
const displayEpisodes = sourceEpisodes.map((item, index) => ({
|
|
32110
|
+
episode: index + 1,
|
|
31494
32111
|
cover: item.cover,
|
|
31495
32112
|
bvid: item.bvid,
|
|
31496
32113
|
link: item.short_link,
|
|
@@ -31498,8 +32115,23 @@ var Bilibili = class extends Base {
|
|
|
31498
32115
|
pub_time: item.pub_time,
|
|
31499
32116
|
badge: item.badge === "" ? "限免" : item.badge,
|
|
31500
32117
|
badge_info: item.badge_info
|
|
31501
|
-
});
|
|
31502
|
-
|
|
32118
|
+
})).reverse();
|
|
32119
|
+
const episodeTargets = sourceEpisodes.map((item, index) => ({
|
|
32120
|
+
episode: index + 1,
|
|
32121
|
+
target: {
|
|
32122
|
+
platform: "bilibili",
|
|
32123
|
+
epId: String(item.ep_id)
|
|
32124
|
+
}
|
|
32125
|
+
})).reverse();
|
|
32126
|
+
const autoSelectEpisode = consumeBilibiliEpisodeAutoSelect(this.e);
|
|
32127
|
+
const linkedEpId = iddata.isEpid ? String(iddata.realid).replace(/^ep/i, "") : "";
|
|
32128
|
+
const linkedSourceIndex = linkedEpId ? sourceEpisodes.findIndex((item) => String(item.ep_id) === linkedEpId) : -1;
|
|
32129
|
+
const linkedDisplayIndex = linkedSourceIndex >= 0 ? sourceEpisodes.length - 1 - linkedSourceIndex : -1;
|
|
32130
|
+
let selectedIndex = autoSelectEpisode ? linkedSourceIndex : -1;
|
|
32131
|
+
const buttonSelection = isButtonSelectionScene(this.e);
|
|
32132
|
+
const selectionMode = buttonSelection ? "button" : "text";
|
|
32133
|
+
/** 按海报页码渲染:15 集一页,长番剧不会撑爆单张 PNG */
|
|
32134
|
+
const renderPoster = (posterPage) => Render(this.e, "bilibili/bangumi", {
|
|
31503
32135
|
mainCover: videoInfo.data.result.cover,
|
|
31504
32136
|
Actors: videoInfo.data.result.actors,
|
|
31505
32137
|
Evaluate: videoInfo.data.result.evaluate,
|
|
@@ -31512,38 +32144,104 @@ var Bilibili = class extends Base {
|
|
|
31512
32144
|
UPInfo: videoInfo.data.result.up_info,
|
|
31513
32145
|
Copyright: videoInfo.data.result.rights.copyright,
|
|
31514
32146
|
Stat: videoInfo.data.result.stat,
|
|
31515
|
-
Episodes,
|
|
31516
|
-
length:
|
|
31517
|
-
|
|
31518
|
-
|
|
31519
|
-
|
|
31520
|
-
reply: true,
|
|
31521
|
-
throwOnTimeout: false
|
|
32147
|
+
Episodes: displayEpisodes,
|
|
32148
|
+
length: sourceEpisodes.length,
|
|
32149
|
+
selectionMode,
|
|
32150
|
+
posterPage,
|
|
32151
|
+
posterPageSize: 15
|
|
31522
32152
|
});
|
|
31523
|
-
if (
|
|
31524
|
-
|
|
31525
|
-
|
|
31526
|
-
|
|
31527
|
-
|
|
31528
|
-
|
|
31529
|
-
|
|
31530
|
-
|
|
32153
|
+
if (autoSelectEpisode) {
|
|
32154
|
+
if (linkedSourceIndex < 0) {
|
|
32155
|
+
await this.e.reply("未找到该集,请重新发送番剧链接");
|
|
32156
|
+
return true;
|
|
32157
|
+
}
|
|
32158
|
+
} else if (buttonSelection) {
|
|
32159
|
+
const initialPage = linkedDisplayIndex >= 0 ? Math.floor(linkedDisplayIndex / 15) + 1 : 1;
|
|
32160
|
+
const poster = await renderPoster(initialPage);
|
|
32161
|
+
const session = createEpisodeSelection(getEpisodeSelectionScope(this.e), {
|
|
32162
|
+
title: videoInfo.data.result.title,
|
|
32163
|
+
platform: "bilibili",
|
|
32164
|
+
scene: this.e.isFriend ? "friend" : "group",
|
|
32165
|
+
poster,
|
|
32166
|
+
posterPage: initialPage,
|
|
32167
|
+
renderPoster,
|
|
32168
|
+
episodes: episodeTargets,
|
|
32169
|
+
forceBurnDanmaku: this.forceBurnDanmaku
|
|
32170
|
+
});
|
|
32171
|
+
markParseStatSkipped(this.e);
|
|
32172
|
+
const sentAt = Date.now();
|
|
32173
|
+
setEpisodeSelectionMessage(session, (await this.e.reply(buildEpisodeSelectionReply(session, initialPage, poster))).messageId, sentAt);
|
|
32174
|
+
return true;
|
|
31531
32175
|
} else {
|
|
31532
|
-
|
|
31533
|
-
|
|
32176
|
+
const posterPageCount = Math.ceil(displayEpisodes.length / 15);
|
|
32177
|
+
let posterPage = linkedDisplayIndex >= 0 ? Math.floor(linkedDisplayIndex / 15) + 1 : 1;
|
|
32178
|
+
/** 上一页海报消息,翻页发送成功后撤回,避免聊天里堆一串过期海报 */
|
|
32179
|
+
let posterMessageId = "";
|
|
32180
|
+
let posterMessageSentAt = 0;
|
|
32181
|
+
for (;;) {
|
|
32182
|
+
const poster = await renderPoster(posterPage);
|
|
32183
|
+
const start = (posterPage - 1) * 15;
|
|
32184
|
+
const pageEpisodes = displayEpisodes.slice(start, start + 15);
|
|
32185
|
+
const firstEpisode = pageEpisodes[0]?.episode ?? 0;
|
|
32186
|
+
const lastEpisode = pageEpisodes[pageEpisodes.length - 1]?.episode ?? 0;
|
|
32187
|
+
const range = firstEpisode === lastEpisode ? `第 ${firstEpisode} 集` : `第 ${firstEpisode}–${lastEpisode} 集`;
|
|
32188
|
+
const sentAt = Date.now();
|
|
32189
|
+
const result = await this.e.reply([...poster, segment.text(`《${videoInfo.data.result.title}》\n${range}(共 ${displayEpisodes.length} 集)\n第 ${posterPage}/${posterPageCount} 页\n发送 第?集 选集${posterPageCount > 1 ? ",发送 上一页 / 下一页 / 第?页 翻页" : ""}(120 秒内有效)`)]);
|
|
32190
|
+
const previousMessageId = posterMessageId;
|
|
32191
|
+
const previousMessageSentAt = posterMessageSentAt;
|
|
32192
|
+
posterMessageId = result.messageId;
|
|
32193
|
+
posterMessageSentAt = result.messageId ? sentAt : 0;
|
|
32194
|
+
if (previousMessageId && canRecallEpisodeMessage(previousMessageId, previousMessageSentAt)) try {
|
|
32195
|
+
await this.e.bot.recallMsg(this.e.contact, previousMessageId);
|
|
32196
|
+
} catch (error) {
|
|
32197
|
+
logger$1.debug("[选集] 撤回上一页失败:", error);
|
|
32198
|
+
}
|
|
32199
|
+
const context = await karin.ctx(this.e, {
|
|
32200
|
+
reply: true,
|
|
32201
|
+
throwOnTimeout: false,
|
|
32202
|
+
time: 120
|
|
32203
|
+
});
|
|
32204
|
+
if (!context) return true;
|
|
32205
|
+
const replyText = context.msg.trim();
|
|
32206
|
+
if (/^[#/]/.test(replyText) || /(https?:\/\/|b23\.tv|bilibili\.com|douyin\.com|iesdouyin\.com)/i.test(replyText)) return true;
|
|
32207
|
+
const pageAction = parseEpisodePosterPageAction(context.msg);
|
|
32208
|
+
if (pageAction) {
|
|
32209
|
+
const nextPage = pageAction.type === "prev" ? posterPage - 1 : pageAction.type === "next" ? posterPage + 1 : pageAction.page;
|
|
32210
|
+
if (nextPage < 1 || nextPage > posterPageCount) {
|
|
32211
|
+
await this.e.reply(`页码超出范围,请发送 1-${posterPageCount} 之间的页码`);
|
|
32212
|
+
continue;
|
|
32213
|
+
}
|
|
32214
|
+
posterPage = nextPage;
|
|
32215
|
+
continue;
|
|
32216
|
+
}
|
|
32217
|
+
const parsedEpisode = parseEpisodeNumber(context.msg);
|
|
32218
|
+
if (parsedEpisode === null || parsedEpisode > sourceEpisodes.length) {
|
|
32219
|
+
await this.e.reply(parsedEpisode === null ? "匹配内容失败,请发送 第?集 选择集数,或发送 上一页 / 下一页 / 第?页 翻页" : `第${parsedEpisode}集不在可解析的剧集里,请重新选择`);
|
|
32220
|
+
continue;
|
|
32221
|
+
}
|
|
32222
|
+
selectedIndex = parsedEpisode - 1;
|
|
32223
|
+
break;
|
|
32224
|
+
}
|
|
32225
|
+
}
|
|
32226
|
+
const episodeInfo = sourceEpisodes[selectedIndex];
|
|
32227
|
+
if (!episodeInfo) {
|
|
32228
|
+
await this.e.reply("未找到该集,请重新发送番剧链接");
|
|
31534
32229
|
return true;
|
|
31535
32230
|
}
|
|
32231
|
+
const displayEpisode = selectedIndex + 1;
|
|
32232
|
+
this.downloadfilename = episodeInfo.share_copy.substring(0, 50).replace(/[\\/:*?"<>|\r\n\s]/g, " ");
|
|
32233
|
+
await this.e.reply(`收到请求,第${displayEpisode}集\n${this.downloadfilename}\n正在下载中`);
|
|
31536
32234
|
const bangumidataBASEURL = bilibiliApiUrls.getBangumiStream({
|
|
31537
|
-
cid:
|
|
31538
|
-
ep_id:
|
|
32235
|
+
cid: episodeInfo.cid,
|
|
32236
|
+
ep_id: episodeInfo.ep_id.toString()
|
|
31539
32237
|
});
|
|
31540
32238
|
const Params = await genParams(bangumidataBASEURL);
|
|
31541
|
-
if (!this.islogin) this.e.reply("B站ck未配置或已失效,无法获取视频流,可尝试【#B站登录】以配置新ck");
|
|
32239
|
+
if (!this.islogin) await this.e.reply("B站ck未配置或已失效,无法获取视频流,可尝试【#B站登录】以配置新ck");
|
|
31542
32240
|
const playUrlData = await new Network({
|
|
31543
32241
|
url: bangumidataBASEURL + Params,
|
|
31544
32242
|
headers: this.headers
|
|
31545
32243
|
}).getData();
|
|
31546
|
-
if (
|
|
32244
|
+
if (episodeInfo.badge === "会员" && !this.isVIP) {
|
|
31547
32245
|
logger$1.warn("该CK不是大会员,无法获取视频流");
|
|
31548
32246
|
return true;
|
|
31549
32247
|
}
|
|
@@ -37019,6 +37717,137 @@ var DouYin = class DouYin extends Base {
|
|
|
37019
37717
|
}
|
|
37020
37718
|
return true;
|
|
37021
37719
|
}
|
|
37720
|
+
case "mix_work": {
|
|
37721
|
+
this.workType = "bangumi";
|
|
37722
|
+
/** 单次最多拉取的集数,超出部分不展示 */
|
|
37723
|
+
const episodeLimit = 200;
|
|
37724
|
+
const timeoutSeconds = 120;
|
|
37725
|
+
const awemeList = (await this.amagi.douyin.fetcher.fetchMixAweme({
|
|
37726
|
+
mix_id: data.mix_id,
|
|
37727
|
+
number: episodeLimit
|
|
37728
|
+
})).data.aweme_list;
|
|
37729
|
+
const first = awemeList[0];
|
|
37730
|
+
if (!first) throw new Error("获取合集作品列表失败,可能是因为该合集已被删除或设置为私密。");
|
|
37731
|
+
const mixInfo = first.mix_info;
|
|
37732
|
+
const author = first.author;
|
|
37733
|
+
const isPlaylet = typeof mixInfo.statis.total_episode === "number";
|
|
37734
|
+
const totalEpisode = isPlaylet ? mixInfo.statis.total_episode : mixInfo.statis.updated_to_episode;
|
|
37735
|
+
const displayEpisodes = [...awemeList.map((aweme) => ({
|
|
37736
|
+
episode: aweme.mix_info.statis.current_episode,
|
|
37737
|
+
aweme_id: aweme.aweme_id,
|
|
37738
|
+
title: aweme.desc.replace(/#\S+/g, "").trim(),
|
|
37739
|
+
duration: aweme.video.duration,
|
|
37740
|
+
cover: aweme.video.cover?.url_list?.[0] ?? "",
|
|
37741
|
+
originCover: aweme.video.origin_cover?.url_list?.[0] ?? ""
|
|
37742
|
+
}))].sort((a, b) => b.episode - a.episode);
|
|
37743
|
+
const buttonSelection = isButtonSelectionScene(this.e);
|
|
37744
|
+
const selectionMode = buttonSelection ? "button" : "text";
|
|
37745
|
+
/** 按海报页码渲染:15 集一页,长合集不会撑爆单张 PNG */
|
|
37746
|
+
const renderPoster = (posterPage) => Render(this.e, "douyin/mix", {
|
|
37747
|
+
kind: isPlaylet ? "playlet" : "collection",
|
|
37748
|
+
mix_name: mixInfo.mix_name,
|
|
37749
|
+
image_url: mixInfo.cover_url.url_list[0],
|
|
37750
|
+
desc: isPlaylet ? displayEpisodes[0]?.title ?? "" : "",
|
|
37751
|
+
total_episode: totalEpisode,
|
|
37752
|
+
updated_to_episode: mixInfo.statis.updated_to_episode,
|
|
37753
|
+
author: {
|
|
37754
|
+
nickname: author.nickname,
|
|
37755
|
+
avatar: author.avatar_thumb.url_list[0],
|
|
37756
|
+
short_id: author.unique_id === "" ? author.short_id : author.unique_id,
|
|
37757
|
+
follower_count: author.follower_count,
|
|
37758
|
+
verified: !!author.custom_verify || !!author.enterprise_verify_reason
|
|
37759
|
+
},
|
|
37760
|
+
statistics: {
|
|
37761
|
+
play_count: awemeList.reduce((sum, aweme) => sum + aweme.statistics.play_count, 0),
|
|
37762
|
+
digg_count: awemeList.reduce((sum, aweme) => sum + aweme.statistics.digg_count, 0),
|
|
37763
|
+
collect_count: awemeList.reduce((sum, aweme) => sum + aweme.statistics.collect_count, 0)
|
|
37764
|
+
},
|
|
37765
|
+
episodes: displayEpisodes,
|
|
37766
|
+
timeoutSeconds,
|
|
37767
|
+
selectionMode,
|
|
37768
|
+
posterPage,
|
|
37769
|
+
posterPageSize: 15
|
|
37770
|
+
});
|
|
37771
|
+
if (buttonSelection) {
|
|
37772
|
+
const initialPage = 1;
|
|
37773
|
+
const poster = await renderPoster(initialPage);
|
|
37774
|
+
const session = createEpisodeSelection(getEpisodeSelectionScope(this.e), {
|
|
37775
|
+
title: mixInfo.mix_name,
|
|
37776
|
+
platform: "douyin",
|
|
37777
|
+
scene: this.e.isFriend ? "friend" : "group",
|
|
37778
|
+
poster,
|
|
37779
|
+
posterPage: initialPage,
|
|
37780
|
+
renderPoster,
|
|
37781
|
+
episodes: displayEpisodes.map((item) => ({
|
|
37782
|
+
episode: item.episode,
|
|
37783
|
+
target: {
|
|
37784
|
+
platform: "douyin",
|
|
37785
|
+
awemeId: String(item.aweme_id)
|
|
37786
|
+
}
|
|
37787
|
+
})),
|
|
37788
|
+
forceBurnDanmaku: this.forceBurnDanmaku
|
|
37789
|
+
});
|
|
37790
|
+
markParseStatSkipped(this.e);
|
|
37791
|
+
const sentAt = Date.now();
|
|
37792
|
+
setEpisodeSelectionMessage(session, (await this.e.reply(buildEpisodeSelectionReply(session, initialPage, poster))).messageId, sentAt);
|
|
37793
|
+
return true;
|
|
37794
|
+
}
|
|
37795
|
+
const posterPageCount = Math.ceil(displayEpisodes.length / 15);
|
|
37796
|
+
let posterPage = 1;
|
|
37797
|
+
/** 上一页海报消息,翻页发送成功后撤回,避免聊天里堆一串过期海报 */
|
|
37798
|
+
let posterMessageId = "";
|
|
37799
|
+
let posterMessageSentAt = 0;
|
|
37800
|
+
for (;;) {
|
|
37801
|
+
const poster = await renderPoster(posterPage);
|
|
37802
|
+
const start = (posterPage - 1) * 15;
|
|
37803
|
+
const pageEpisodes = displayEpisodes.slice(start, start + 15);
|
|
37804
|
+
const firstEpisode = pageEpisodes[0]?.episode ?? 0;
|
|
37805
|
+
const lastEpisode = pageEpisodes[pageEpisodes.length - 1]?.episode ?? 0;
|
|
37806
|
+
const range = firstEpisode === lastEpisode ? `第 ${firstEpisode} 集` : `第 ${firstEpisode}–${lastEpisode} 集`;
|
|
37807
|
+
const sentAt = Date.now();
|
|
37808
|
+
const result = await this.e.reply([...poster, segment.text(`《${mixInfo.mix_name}》\n${range}(共 ${totalEpisode} 集,已列出 ${displayEpisodes.length} 集)\n第 ${posterPage}/${posterPageCount} 页\n发送 第?集 选集${posterPageCount > 1 ? ",发送 上一页 / 下一页 / 第?页 翻页" : ""}(${timeoutSeconds} 秒内有效)`)]);
|
|
37809
|
+
const previousMessageId = posterMessageId;
|
|
37810
|
+
const previousMessageSentAt = posterMessageSentAt;
|
|
37811
|
+
posterMessageId = result.messageId;
|
|
37812
|
+
posterMessageSentAt = result.messageId ? sentAt : 0;
|
|
37813
|
+
if (previousMessageId && canRecallEpisodeMessage(previousMessageId, previousMessageSentAt)) try {
|
|
37814
|
+
await this.e.bot.recallMsg(this.e.contact, previousMessageId);
|
|
37815
|
+
} catch (error) {
|
|
37816
|
+
logger.debug("[选集] 撤回上一页失败:", error);
|
|
37817
|
+
}
|
|
37818
|
+
const context = await karin.ctx(this.e, {
|
|
37819
|
+
reply: true,
|
|
37820
|
+
throwOnTimeout: false,
|
|
37821
|
+
time: timeoutSeconds
|
|
37822
|
+
});
|
|
37823
|
+
if (!context) return true;
|
|
37824
|
+
const replyText = context.msg.trim();
|
|
37825
|
+
if (/^[#/]/.test(replyText) || /(https?:\/\/|b23\.tv|bilibili\.com|douyin\.com|iesdouyin\.com)/i.test(replyText)) return true;
|
|
37826
|
+
const pageAction = parseEpisodePosterPageAction(context.msg);
|
|
37827
|
+
if (pageAction) {
|
|
37828
|
+
const nextPage = pageAction.type === "prev" ? posterPage - 1 : pageAction.type === "next" ? posterPage + 1 : pageAction.page;
|
|
37829
|
+
if (nextPage < 1 || nextPage > posterPageCount) {
|
|
37830
|
+
await this.e.reply(`页码超出范围,请发送 1-${posterPageCount} 之间的页码`);
|
|
37831
|
+
continue;
|
|
37832
|
+
}
|
|
37833
|
+
posterPage = nextPage;
|
|
37834
|
+
continue;
|
|
37835
|
+
}
|
|
37836
|
+
const episode = parseEpisodeNumber(context.msg);
|
|
37837
|
+
const target = episode === null ? void 0 : displayEpisodes.find((item) => item.episode === episode);
|
|
37838
|
+
if (!target) {
|
|
37839
|
+
await this.e.reply(episode === null ? "匹配内容失败,请发送 第?集 选择集数,或发送 上一页 / 下一页 / 第?页 翻页" : `第${episode}集不在可解析的剧集里,请重新选择`);
|
|
37840
|
+
continue;
|
|
37841
|
+
}
|
|
37842
|
+
await this.e.reply(`收到请求,第${episode}集\n${mixInfo.mix_name}\n正在解析中`);
|
|
37843
|
+
const targetData = {
|
|
37844
|
+
type: "one_work",
|
|
37845
|
+
aweme_id: target.aweme_id
|
|
37846
|
+
};
|
|
37847
|
+
await new DouYin(context, targetData, { forceBurnDanmaku: this.forceBurnDanmaku }).DouyinHandler(targetData);
|
|
37848
|
+
return true;
|
|
37849
|
+
}
|
|
37850
|
+
}
|
|
37022
37851
|
case "music_work": {
|
|
37023
37852
|
this.workType = "music";
|
|
37024
37853
|
const musicInfo = (await this.amagi.douyin.fetcher.fetchMusicInfo({ music_id: data.music_id })).data.music_info;
|
|
@@ -37214,6 +38043,14 @@ var getDouyinID = async (event, url, log = true) => {
|
|
|
37214
38043
|
room_id: longLink.split("/").pop()
|
|
37215
38044
|
};
|
|
37216
38045
|
break;
|
|
38046
|
+
case /\/(?:share\/(?:playlet|mix)\/detail|collection)\/(\d+)/.test(longLink): {
|
|
38047
|
+
const mixMatch = /\/(?:share\/(?:playlet|mix)\/detail|collection)\/(\d+)/.exec(longLink);
|
|
38048
|
+
result = {
|
|
38049
|
+
type: "mix_work",
|
|
38050
|
+
mix_id: mixMatch ? mixMatch[1] : void 0
|
|
38051
|
+
};
|
|
38052
|
+
break;
|
|
38053
|
+
}
|
|
37217
38054
|
case /video\/(\d+)/.test(longLink):
|
|
37218
38055
|
case /article\/(\d+)/.test(longLink):
|
|
37219
38056
|
case /note\/(\d+)/.test(longLink): {
|
|
@@ -38164,23 +39001,10 @@ var DouYinpush = class extends Base {
|
|
|
38164
39001
|
const botId = this.e.selfId;
|
|
38165
39002
|
try {
|
|
38166
39003
|
const inputDouyinId = this.e.msg.replace(/^#设置抖音推送/, "").trim();
|
|
38167
|
-
/**
|
|
38168
|
-
* 搜索结果按响应形态自述(判别式 `__search_type`,由 amagi 的 normalize 按响应结构 +
|
|
38169
|
-
* 请求类型写入)。订阅只认「用户搜索」那一支:抖音把 user 请求回成别的形态时在这里说清楚,
|
|
38170
|
-
* 而不是拿一个 undefined 去遍历。
|
|
38171
|
-
*/
|
|
38172
|
-
if (data.__search_type !== "user") throw new Error(`抖音没有返回用户搜索结果(返回形态:${data.__search_type ?? "未知"})`);
|
|
38173
|
-
let matchedUser = null;
|
|
38174
|
-
for (const userItem of data.user_list) if ((userItem.user_info.unique_id === "" ? userItem.user_info.short_id : userItem.user_info.unique_id) === inputDouyinId) {
|
|
38175
|
-
matchedUser = userItem.user_info;
|
|
38176
|
-
break;
|
|
38177
|
-
}
|
|
38178
|
-
if (!matchedUser) throw new Error(`未找到抖音号为 ${inputDouyinId} 的用户`);
|
|
38179
|
-
const sec_uid = matchedUser.sec_uid;
|
|
38180
|
-
const UserInfoData = await this.amagi.douyin.fetcher.fetchUserProfile({ sec_uid });
|
|
38181
39004
|
/** 处理抖音号 */
|
|
38182
|
-
|
|
38183
|
-
|
|
39005
|
+
const user_shortid = data.user_info.unique_id === "" ? data.user_info.short_id : data.user_info.unique_id;
|
|
39006
|
+
const sec_uid = data.user_info.sec_uid;
|
|
39007
|
+
if (inputDouyinId !== user_shortid) throw new Error(`未找到抖音号为 ${inputDouyinId} 的用户`);
|
|
38184
39008
|
config.douyin ??= [];
|
|
38185
39009
|
const existingItem = config.douyin.find((item) => item.sec_uid === sec_uid);
|
|
38186
39010
|
const isSubscribed = await douyinDBInstance.isSubscribed(sec_uid, groupId);
|
|
@@ -38200,31 +39024,31 @@ var DouYinpush = class extends Base {
|
|
|
38200
39024
|
config.douyin.splice(index, 1);
|
|
38201
39025
|
}
|
|
38202
39026
|
Config.Modify("pushlist", "douyin", config.douyin);
|
|
38203
|
-
await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n删除成功!${
|
|
38204
|
-
logger$1.info(`\n删除成功!${
|
|
39027
|
+
await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n删除成功!${data.user_info.nickname}\n抖音号:${user_shortid}`);
|
|
39028
|
+
logger$1.info(`\n删除成功!${data.user_info.nickname}\n抖音号:${user_shortid}\nsec_uid${data.user_info.sec_uid}`);
|
|
38205
39029
|
} else {
|
|
38206
39030
|
existingItem.group_id.push(`${groupId}:${botId}`);
|
|
38207
39031
|
if (!existingItem.pushTypes || existingItem.pushTypes.length === 0) existingItem.pushTypes = ["post", "live"];
|
|
38208
|
-
if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid,
|
|
39032
|
+
if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid, data.user_info.nickname);
|
|
38209
39033
|
Config.Modify("pushlist", "douyin", config.douyin);
|
|
38210
|
-
await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${
|
|
39034
|
+
await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${data.user_info.nickname}\n抖音号:${user_shortid}`);
|
|
38211
39035
|
if (Config.douyin.push.switch === false) await this.e.reply("请发送「#设置抖音推送开启」以进行推送");
|
|
38212
|
-
logger$1.info(`\n设置成功!${
|
|
39036
|
+
logger$1.info(`\n设置成功!${data.user_info.nickname}\n抖音号:${user_shortid}\nsec_uid${data.user_info.sec_uid}`);
|
|
38213
39037
|
}
|
|
38214
39038
|
} else {
|
|
38215
39039
|
config.douyin.push({
|
|
38216
39040
|
switch: true,
|
|
38217
39041
|
sec_uid,
|
|
38218
39042
|
group_id: [`${groupId}:${botId}`],
|
|
38219
|
-
remark:
|
|
39043
|
+
remark: data.user_info.nickname,
|
|
38220
39044
|
short_id: user_shortid,
|
|
38221
39045
|
pushTypes: ["post", "live"]
|
|
38222
39046
|
});
|
|
38223
|
-
if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid,
|
|
39047
|
+
if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid, data.user_info.nickname);
|
|
38224
39048
|
Config.Modify("pushlist", "douyin", config.douyin);
|
|
38225
|
-
await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${
|
|
39049
|
+
await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${data.user_info.nickname}\n抖音号:${user_shortid}`);
|
|
38226
39050
|
if (Config.douyin.push.switch === false) await this.e.reply("请发送「#设置抖音推送开启」以进行推送");
|
|
38227
|
-
logger$1.info(`\n设置成功!${
|
|
39051
|
+
logger$1.info(`\n设置成功!${data.user_info.nickname}\n抖音号:${user_shortid}\nsec_uid${data.user_info.sec_uid}`);
|
|
38228
39052
|
}
|
|
38229
39053
|
await this.renderPushList();
|
|
38230
39054
|
} catch (error) {
|
|
@@ -40235,10 +41059,7 @@ var handleSetDouyinPush = wrapWithErrorHandler(async (e) => {
|
|
|
40235
41059
|
logger$1.info(`抖音推送已${enable ? "开启" : "关闭"}`);
|
|
40236
41060
|
return true;
|
|
40237
41061
|
}
|
|
40238
|
-
const data = await douyinFetcher.
|
|
40239
|
-
query,
|
|
40240
|
-
type: "user"
|
|
40241
|
-
});
|
|
41062
|
+
const data = await douyinFetcher.fetchGuestUserInfo({ unique_id: query });
|
|
40242
41063
|
await new DouYinpush(e).setting(data.data);
|
|
40243
41064
|
return true;
|
|
40244
41065
|
}, { businessName: "设置抖音推送" });
|
|
@@ -41539,7 +42360,7 @@ var handleDouyin = wrapWithErrorHandler(async (e, next) => {
|
|
|
41539
42360
|
const iddata = await getDouyinID(e, url);
|
|
41540
42361
|
const douyin = new DouYin(e, iddata, { forceBurnDanmaku });
|
|
41541
42362
|
await douyin.DouyinHandler(iddata);
|
|
41542
|
-
await recordParseStat(e, "douyin", {
|
|
42363
|
+
if (!consumeParseStatSkip(e)) await recordParseStat(e, "douyin", {
|
|
41543
42364
|
workType: douyin.workType,
|
|
41544
42365
|
durationMs: Date.now() - startedAt
|
|
41545
42366
|
});
|
|
@@ -41564,7 +42385,7 @@ var handleBilibili = wrapWithErrorHandler(async (e, next) => {
|
|
|
41564
42385
|
const iddata = await getBilibiliID(url);
|
|
41565
42386
|
const bilibili = new Bilibili(e, iddata, { forceBurnDanmaku });
|
|
41566
42387
|
await bilibili.BilibiliHandler(iddata);
|
|
41567
|
-
await recordParseStat(e, "bilibili", {
|
|
42388
|
+
if (!consumeParseStatSkip(e)) await recordParseStat(e, "bilibili", {
|
|
41568
42389
|
workType: bilibili.workType,
|
|
41569
42390
|
durationMs: Date.now() - startedAt
|
|
41570
42391
|
});
|
|
@@ -41635,6 +42456,75 @@ var xiaohongshu = karin.command(reg.xiaohongshu, handleXiaohongshu, {
|
|
|
41635
42456
|
priority: Config.app.videoTool ? -Infinity : 800
|
|
41636
42457
|
});
|
|
41637
42458
|
var prefix = karin.command(/^#?(解析|kkk解析|弹幕解析)/, handlePrefix, { name: "kkk-视频功能-引用解析" });
|
|
42459
|
+
var handleEpisodeSelection = wrapWithErrorHandler(async (e, next) => {
|
|
42460
|
+
if (!isButtonSelectionScene(e)) return next();
|
|
42461
|
+
const match = /^#选集\s+([A-Za-z0-9_-]+)(?:\s+(.+?))?\s*$/.exec(e.msg);
|
|
42462
|
+
if (!match) return next();
|
|
42463
|
+
const [, token, actionText] = match;
|
|
42464
|
+
const session = getEpisodeSelection(token, getEpisodeSelectionScope(e));
|
|
42465
|
+
if (!session) {
|
|
42466
|
+
await e.reply("本次选集已结束,请重新发送原链接", { at: true });
|
|
42467
|
+
return true;
|
|
42468
|
+
}
|
|
42469
|
+
if (!actionText) {
|
|
42470
|
+
await e.reply("请点击下方按钮,或点击「跳转到第x页」输入页码");
|
|
42471
|
+
return true;
|
|
42472
|
+
}
|
|
42473
|
+
const action = parseEpisodeSelectionAction(actionText);
|
|
42474
|
+
if (!action) {
|
|
42475
|
+
await e.reply("集数或页码格式不正确,请重新选择");
|
|
42476
|
+
return true;
|
|
42477
|
+
}
|
|
42478
|
+
if (action.type === "page") {
|
|
42479
|
+
if (!getEpisodePage(session, action.page)) {
|
|
42480
|
+
await e.reply("页码超出范围,请重新选择");
|
|
42481
|
+
return true;
|
|
42482
|
+
}
|
|
42483
|
+
const poster = await getEpisodeSelectionPoster(session, action.page);
|
|
42484
|
+
const previousMessageId = session.currentMessageId;
|
|
42485
|
+
const sentAt = Date.now();
|
|
42486
|
+
const result = await e.reply(buildEpisodeSelectionReply(session, action.page, poster));
|
|
42487
|
+
const shouldRecall = canRecallEpisodeSelectionMessage(session);
|
|
42488
|
+
setEpisodeSelectionMessage(session, result.messageId, sentAt);
|
|
42489
|
+
if (previousMessageId && shouldRecall) await e.bot.recallMsg(e.contact, previousMessageId).catch((error) => {
|
|
42490
|
+
logger$1.debug("[选集] 撤回上一页失败:", error);
|
|
42491
|
+
});
|
|
42492
|
+
touchEpisodeSelection(token, session.scope);
|
|
42493
|
+
return true;
|
|
42494
|
+
}
|
|
42495
|
+
const target = resolveEpisodeTarget(session, action.episode);
|
|
42496
|
+
if (!target) {
|
|
42497
|
+
await e.reply(`第${action.episode}集不在可解析的剧集里,请重新选择`);
|
|
42498
|
+
return true;
|
|
42499
|
+
}
|
|
42500
|
+
if (target.platform === "douyin" && !Config.douyin.switch) {
|
|
42501
|
+
endEpisodeSelection(token, session.scope);
|
|
42502
|
+
await e.reply("抖音解析未开启");
|
|
42503
|
+
return true;
|
|
42504
|
+
}
|
|
42505
|
+
if (target.platform === "bilibili" && !Config.bilibili.switch) {
|
|
42506
|
+
endEpisodeSelection(token, session.scope);
|
|
42507
|
+
await e.reply("B站解析未开启");
|
|
42508
|
+
return true;
|
|
42509
|
+
}
|
|
42510
|
+
if (!endEpisodeSelection(token, session.scope)) {
|
|
42511
|
+
await e.reply("本次选集已结束,请重新发送原链接");
|
|
42512
|
+
return true;
|
|
42513
|
+
}
|
|
42514
|
+
const originalMsg = e.msg;
|
|
42515
|
+
e.msg = `${session.forceBurnDanmaku ? "#弹幕解析 " : "#解析"}${buildEpisodeTargetUrl(target)}`;
|
|
42516
|
+
try {
|
|
42517
|
+
if (target.platform === "douyin") await handleDouyin(e, () => {});
|
|
42518
|
+
else {
|
|
42519
|
+
markBilibiliEpisodeAutoSelect(e);
|
|
42520
|
+
await handleBilibili(e, () => {});
|
|
42521
|
+
}
|
|
42522
|
+
} finally {
|
|
42523
|
+
e.msg = originalMsg;
|
|
42524
|
+
}
|
|
42525
|
+
return true;
|
|
42526
|
+
}, { businessName: "KKK选集" });
|
|
42527
|
+
var episodeSelection = karin.command(/^#选集\s+/, handleEpisodeSelection, { name: "kkk-视频功能-选集" });
|
|
41638
42528
|
var douyinAPP = Config.douyin.switch && douyin;
|
|
41639
42529
|
var bilibiliAPP = Config.bilibili.switch && bilibili;
|
|
41640
42530
|
var kuaishouAPP = Config.kuaishou.switch && kuaishou;
|
|
@@ -43173,4 +44063,4 @@ mkdirSync(`${karinPathBase}/${Root.pluginName}/data`);
|
|
|
43173
44063
|
mkdirSync(Common.tempDri.images);
|
|
43174
44064
|
mkdirSync(Common.tempDri.video);
|
|
43175
44065
|
//#endregion
|
|
43176
|
-
export {
|
|
44066
|
+
export { bilibiliFetcher as $, removeOldFiles as A, douyinDBInstance as B, changelog as C, biRefreshLogin as D, biLogin as E, runWithVerifyContext as F, METRIC_BUCKETS as G, getDouyinDB as H, templates as I, DouyinDBBase as J, StatisticsDBBase as K, webConfig as L, testWrapWithErrorHandler as M, xhsLogin as N, dylogin as O, handleRiskChallenge as P, SOFT_ERROR_CODES as Q, bilibiliDBInstance as R, setdyPush as S, version as T, getStatisticsDB as U, getBilibiliDB as V, initAllDatabases as W, AmagiBase as X, BilibiliDBBase as Y, AmagiError as Z, douyinPush as _, bilibiliAPP as a, reloadAmagiConfig as at, globalIgnore as b, kuaishouAPP as c, Root as ct, testPush as d, douyinFetcher as et, globalStatistics as f, bilibiliPushList as g, bilibiliPush as h, update as i, registerAmagiReloadListener as it, task as j, ksLogin as k, prefix as l, qrLogin as m, kkkUpdateCommand as n, isSoftFailure as nt, douyinAPP as o, softFetch as ot, groupStatistics as p, resolveMetricBucket as q, kkkUpdateTest as r, kuaishouFetcher as rt, episodeSelection as s, xiaohongshuFetcher as st, kkkUpdate as t, getAmagiClient as tt, xiaohongshuAPP as u, douyinPushList as v, help as w, setbiliPush as x, forcePush as y, cleanOldDynamicCache as z };
|