docs(copy): 设置页接入、媒体库、整理、系统分区文案按 human-copy 重写

- 下载器说明去掉「接管」,选下载器顺序写成一句;缓存盘统一为下载盘
- 「凭据」统一为「凭证」;去掉说明里的「同 MP」「待处理」等旧称
- 整理来源的基线、存量说法改成用户能懂的话,确认按钮写动作
- 数据保留里「站点快照」「待识别条目」按术语表改名

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-07 01:48:45 +08:00
1 parent c57411f9a5
commit ea42018d3f
12 files changed
+35 -35

No files matched your search

+4 -4
View File
@@ -88,20 +88,20 @@ function SearchSitesBlock() {
export const IDENTITY_CARD: CardSpec = {
anchor: "identity",
title: "资源识别",
description: "默认只在资源命中订阅、作品别名或新作品规则,或你手动识别和搜索时查 TMDB;其余放进未识别,不进待处理。",
description: "默认只在资源命中订阅、作品别名或新作品规则,或你手动识别和搜索时查 TMDB;其余资源留在未识别。",
fields: [
{
name: "identity.eagerTmdbLookup",
label: "每条新资源都查 TMDB",
kind: "switch",
hint: "每条新资源都查一次 TMDB。RSS 量大时每天可能上千次请求,站点独有的短剧和综艺多半查不到",
hint: "RSS 量大时每天可能上千次请求;站点独有的短剧和综艺多半查不到",
wide: true,
},
{
name: "identity.detailIdsPerSiteHour",
label: "识别时每站每小时最多抓详情页",
kind: "number",
hint: "标题认不准时,抓站点详情页取 IMDb、TMDB 或豆瓣 ID 再识别;只在搜索、订阅相关资源、补全和手动重新识别时抓,RSS 收进来的资源不抓。0 = 不抓",
hint: "标题认不准时,抓站点详情页取 IMDb、TMDB 或豆瓣 ID 再识别;只在搜索、命中订阅、补全和手动重新识别时抓,RSS 收进来的资源不抓。0 = 不抓",
},
{
name: "identity.autoEnrich",
@@ -125,7 +125,7 @@ export const IDENTITY_CARD: CardSpec = {
},
{
name: "identity.enrichSnippetAllSites",
label: "也用其它网站的搜索摘要",
label: "也用其他网站的搜索摘要",
kind: "switch",
hint: "短剧多半只有聚合站收录。打开后,白名单以外网站的搜索摘要也用来抽年份、集数、主演、简介(只看搜索引擎给的摘要,不打开这些网页)",
wide: true,
@@ -50,7 +50,7 @@ function Verified({ p }: { p: BrowserProviderView }) {
function CapabilityTable({ p }: { p: BrowserProviderView }) {
const caps = p.capabilities;
if (!caps) return <p className="mt-4 text-caption text-muted-foreground">还没有探测过。点"测试连通"读取能力。</p>;
if (!caps) return <p className="mt-4 text-caption text-muted-foreground">还没有探测过。点「测试连通」读取能力。</p>;
return (
<div className="mt-5 space-y-2">
<h3 className="text-caption font-semibold">
@@ -81,7 +81,7 @@ function CapabilityTable({ p }: { p: BrowserProviderView }) {
})}
</ul>
<p className="text-meta text-muted-foreground">
"已核验"只来自对真实实例的逐项核验记录(见运行手册),探测只能判断接口在不在。未核验的能力在原站视图里标出。
「已核验」只来自对真实实例的逐项核验记录(见运行手册),探测只能判断接口在不在。未核验的能力在原站视图里标出。
</p>
</div>
);
@@ -124,7 +124,7 @@ export function BrowserProvidersBlock() {
},
{
key: "key",
header: "访问凭据",
header: "访问凭证",
hideBelow: "md",
cell: (r) => (r.hasAccessKey ? "已设置" : "未设置"),
},
@@ -148,7 +148,7 @@ export function BrowserProvidersBlock() {
const auth = (v.health?.detail as { error?: string } | undefined)?.error === "auth";
return {
ok: v.health?.status === "ok",
message: auth ? "访问凭据不对" : v.health?.status === "degraded" ? "浏览器服务正在恢复" : "连不上",
message: auth ? "访问凭证不对" : v.health?.status === "degraded" ? "浏览器服务正在恢复" : "连不上",
version: v.capabilities?.upstreamVersion ?? null,
};
}}
+1 -1
View File
@@ -279,7 +279,7 @@ export const TTL_CARD: CardSpec = {
fields: [
ttlField("tmdbSearchDays", "TMDB 搜索与识别结果"),
ttlField("tmdbDetailDays", "TMDB 详情"),
ttlField("tmdbMissDays", "TMDB 空结果", "搜索无结果、未识别时的负缓存"),
ttlField("tmdbMissDays", "TMDB 空结果", "搜索无结果或没识别出的结果也缓存,期内不重复查"),
ttlField("imageDays", "TMDB 人物与图片"),
ttlField("metaSearchDays", "豆瓣 / Bangumi 搜索"),
ttlField("metaDetailDays", "豆瓣 / Bangumi 条目"),
@@ -118,7 +118,7 @@ export function DownloadersTable() {
config={{
noun: "下载器实例",
description:
"只接管带管理标签的任务。可添加多个下载器:订阅或手动下载指定了下载器就用指定的,否则用站点指定的,再否则用默认下载器。多个实例共用一块缓存盘时填相同的缓存卷标识,水位合并计算。点行编辑实例和路径映射。",
"只管理带管理标签的任务。选下载器的顺序:订阅或手动下载指定的、站点指定的、默认下载器。多个实例共用一块下载盘时填相同的缓存卷标识,水位合并计算。点行编辑实例和路径映射。",
emptyHint: "添加 qBittorrent 后才能提交下载。",
drawerExtra: (r) => <PathMappingsPanel viewKind="downloader" instanceId={r.id} />,
columns: [
@@ -180,7 +180,7 @@ export function DownloadersTable() {
placeholder: "qbt_…",
visible: (v) => v.authKind === "api_key",
},
{ name: "managedTag", label: "管理标签", kind: "text", placeholder: "umt", hint: "只接管带此标签的任务" },
{ name: "managedTag", label: "管理标签", kind: "text", placeholder: "umt", hint: "只管理带这个标签的任务" },
{ name: "cacheVolumeKey", label: "缓存卷标识", kind: "text", placeholder: "cache-1" },
{
name: "hardPct",
@@ -357,7 +357,7 @@ const MEDIA_KIND = [
{ value: "series", label: "剧集" },
{ value: "variety", label: "综艺" },
{ value: "mixed", label: "混合" },
{ value: "other", label: "其它" },
{ value: "other", label: "其他" },
];
/** 库根路径 ↔ 存储 + 路径:Alist 上的库根存成 /@alist/<存储 id>/<Alist 内路径> */
+1 -1
View File
@@ -23,7 +23,7 @@ export function LibrarySection() {
section="library"
anchor="roots"
title="媒体库目录"
description="整理把作品放进这些目录;媒体服务器扫的也是它们。"
description="整理后的作品放在这些目录里,媒体服务器也扫描这些目录。"
plain
>
<LibraryRootsTable />
@@ -69,7 +69,7 @@ export const LANGUAGE_CARD: CardSpec = {
label: "语言回退链",
kind: "text",
placeholder: DEFAULT_LANGUAGES.join(", "),
hint: "标题和每集信息按顺序取第一个有值的语言,简介默认只取链里的中文;中文名取链中第一个中文值。只认简繁中文、英文和作品原语言(如日语作品的 ja-JP),其它语言跳过。逗号分隔,如 zh-CN, zh-SG",
hint: "逗号分隔,如 zh-CN, zh-SG。标题和每集信息取链上第一个有值的语言,简介默认只取中文。只认简繁中文、英文和作品原语言(如日语作品的 ja-JP),其他语言跳过",
wide: true,
},
{
+1 -1
View File
@@ -190,7 +190,7 @@ function RootNamingEditor({ root }: { root: LibraryRoot }) {
<div className="flex flex-wrap items-center gap-2">
{KINDS.map((k) => (
<StatusBadge key={k} tone={saved[k] ? "success" : "neutral"}>
{NAMING_KIND_LABEL[k]}:{saved[k] ? "媒体库目录覆盖" : "沿用全局"}
{NAMING_KIND_LABEL[k]}:{saved[k] ? "媒体库目录覆盖" : "沿用全局"}
</StatusBadge>
))}
</div>
@@ -59,7 +59,7 @@ export function ClassificationSection() {
})
}
>
让智能体协助
问智能体
</Button>
}
>
@@ -159,7 +159,7 @@ function SourceEditor({ initial, onClose }: { initial: OrganizeSourceView | null
<DialogHeader>
<DialogTitle>{initial ? "编辑整理来源" : "新增整理来源"}</DialogTitle>
<DialogDescription>
首次保存或更换来源目录先建立当前文件基线,只自动处理后续新增文件。历史文件请使用「整理存量」。
首次保存或更换来源目录时记下现有文件作为基线,之后只自动处理新增文件。已有文件用「整理存量」整理。
</DialogDescription>
</DialogHeader>
<div className="grid gap-4 sm:grid-cols-2">
@@ -316,7 +316,7 @@ function SourceEditor({ initial, onClose }: { initial: OrganizeSourceView | null
},
{
onSuccess: () => {
toast.success("来源已保存,当前存量不会自动整理");
toast.success("来源已保存,已有文件不会自动整理");
onClose();
},
onError: (e) => toast.error(filesErrorText(e, "保存来源失败")),
@@ -324,7 +324,7 @@ function SourceEditor({ initial, onClose }: { initial: OrganizeSourceView | null
);
}}
>
{save.isPending ? "保存并建立基线…" : "保存来源"}
{save.isPending ? "保存中…" : "保存来源"}
</Button>
</div>
</DialogContent>
@@ -360,7 +360,7 @@ export function OrganizeSourcesSection() {
section="library"
anchor="sources"
title="整理来源"
description="每条配置绑定一个来源与一个媒体库目标。新增来源建立基线,历史存量由你预览后执行。"
description="每条配置把一个来源目录对应到一个媒体库目录。新增的来源只自动处理之后出现的文件,已有文件用「整理存量」预览后整理。"
actions={
<Button size="sm" onClick={() => setEditor(null)}>
新增来源
@@ -369,13 +369,13 @@ export function OrganizeSourcesSection() {
>
<div className="space-y-3">
{sources.isPending ? (
<p>读取来源中…</p>
<p>加载中…</p>
) : sources.error ? (
<p role="alert" className="text-destructive">
{filesErrorText(sources.error, "读取来源失败")}
</p>
) : !sources.data?.items.length ? (
<p className="text-caption text-muted-foreground">尚未配置整理来源。</p>
<p className="text-caption text-muted-foreground">还没有整理来源。</p>
) : (
paged.items?.map((p) => (
<div key={p.id} className="space-y-2 rounded-xl border border-border p-3">
@@ -389,7 +389,7 @@ export function OrganizeSourcesSection() {
const { id, baselineAt: _, lastScanAt: _s, lastError: _e, fileCount: _c, ...body } = p;
save.mutate(
{ id, body: { ...body, enabled } },
{ onError: (e) => toast.error(filesErrorText(e, "切换启用失败")) },
{ onError: (e) => toast.error(filesErrorText(e, "切换失败")) },
);
}}
/>
@@ -408,7 +408,7 @@ export function OrganizeSourcesSection() {
r.items.length
? setWizard(stockWizardSource(p, r))
: toast.info(
`没有可整理文件;跳过 ${r.skipped},不可读取 ${r.unavailable}${r.truncated ? ",扫描达到上限" : ""}`,
`没有可整理的文件;跳过 ${r.skipped} 个,读不到 ${r.unavailable} 个${r.truncated ? ",已达扫描上限" : ""}`,
),
onError: (e) => toast.error(filesErrorText(e, "扫描存量失败")),
},
@@ -451,7 +451,7 @@ export function OrganizeSourcesSection() {
<DialogContent>
<DialogHeader>
<DialogTitle>删除来源「{deleting.name}」?</DialogTitle>
<DialogDescription>删除配置及监控快照,文件仍保留在原目录。</DialogDescription>
<DialogDescription>配置和监控快照会删除,目录里的文件不动。</DialogDescription>
</DialogHeader>
<Button
variant="outline"
@@ -463,7 +463,7 @@ export function OrganizeSourcesSection() {
})
}
>
确认删除来源
删除来源
</Button>
</DialogContent>
</Dialog>
@@ -61,7 +61,7 @@ export const SCRAPE_CARD: CardSpec = {
name: "organize.scrapeAfterImport",
label: "整理后自动刮削",
kind: "switch",
hint: "只对认出作品(有 TMDB ID 或本地元数据)的整理排刮削;没刮削的在整理记录上标「未刮削」",
hint: "只刮削认出作品的整理(有 TMDB ID 或本地元数据);没刮削的整理记录标「未刮削」",
},
{
name: "organize.scrapeMode",
+1 -1
View File
@@ -94,7 +94,7 @@ export const NETWORK_CARD: CardSpec = {
label: "User-Agent",
kind: "text",
placeholder: "跟随浏览器",
hint: "留空跟随浏览器(推荐),站点请求和浏览器用同一个 UA。填了则账号没单独填 UA 时都用它,和浏览器不一致",
hint: "留空时站点请求和浏览器用同一个 UA(推荐)。填写后,没单独设 UA 的账号都用这个值,与浏览器的 UA 不一致",
wide: true,
},
{
@@ -123,7 +123,7 @@ export const STORAGE_FIELDS: FieldSpec[] = [
name: "uploadAsTask",
label: "上传交给 Alist 后台任务",
kind: "switch",
hint: "开启后上传由 Alist 排队完成,本工具等任务结束再继续;缺省关闭(同 MP)",
hint: "开启后上传由 Alist 排队完成,本工具等任务结束再继续;缺省关闭",
},
{
name: "snapshotCheckFolderModtime",
@@ -197,7 +197,7 @@ export function StoragesTable() {
description:
"登记 Alist / OpenList 后,媒体库目录、整理来源和文件管理都能用它。网盘方向的上传、下载、复制和移动以接口成功、目标存在为准,不比对大小和哈希。",
emptyHint: "还没有登记 Alist / OpenList。",
deleteHint: "只删除登记和保存的凭据;被媒体库目录使用时不能删除。",
deleteHint: "只删除登记和保存的凭证;被媒体库目录使用时不能删除。",
columns: [
{
key: "name",
+5 -5
View File
@@ -59,9 +59,9 @@ const BUDGET_KEYS = ["pgDataGb", "pgDataWarnGb", "imagesGb", "backupsGb", "sessi
export const STORAGE_BUDGET_CARD: CardSpec = {
anchor: "storage",
title: "存储预算",
description: "超过预算时健康页告警;图片缓存超出容量按最久未访问删除。单位 GB。",
description: "超过预算时运行状态页告警;图片缓存超出容量按最久未访问删除。单位 GB。",
fields: [
gbField("pgDataGb", "数据库预算", "超过为严重"),
gbField("pgDataGb", "数据库预算", "超过时标为需要处理"),
gbField("pgDataWarnGb", "数据库告警线", "不高于数据库预算"),
gbField("imagesGb", "图片缓存容量"),
gbField("backupsGb", "备份目录预算"),
@@ -104,11 +104,11 @@ export const STORAGE_RETENTION_CARD: CardSpec = {
"未识别资源归档",
"未命中的条目这么久没有新证据就归档,仍可手动指定",
),
dayField("retentionDays", "engineRun", "后台运行记录", "仍被任务记录引用的跟随任务保留"),
dayField("retentionDays", "engineRun", "后台运行记录", "被任务记录引用的随任务一起保留"),
dayField("retentionDays", "outboxEvent", "已投递的内部事件"),
dayField("retentionDays", "resolutionAttempt", "识别尝试记录", "每个资源至少留最近 3 次"),
dayField("retentionDays", "identityResolved", "已识别的待识别条目", "忽略和归档的不删"),
dayField("retentionDays", "siteSnapshot", "站点快照", "每个站点最近一次成功的保留"),
dayField("retentionDays", "identityResolved", "未识别中已识别的条目", "忽略和归档的不删"),
dayField("retentionDays", "siteSnapshot", "站点抓取结果", "每个站点保留最近一次成功的抓取"),
],
fromSettings: (s) =>
Object.fromEntries(RETENTION_KEYS.map((k) => [`storage.retentionDays.${k}`, n(s.storage.retentionDays[k])])),