Files
rootandClaude Opus 5.5 ea42018d3f docs(copy): 设置页接入、媒体库、整理、系统分区文案按 human-copy 重写
- 下载器说明去掉「接管」,选下载器顺序写成一句;缓存盘统一为下载盘
- 「凭据」统一为「凭证」;去掉说明里的「同 MP」「待处理」等旧称
- 整理来源的基线、存量说法改成用户能懂的话,确认按钮写动作
- 数据保留里「站点快照」「待识别条目」按术语表改名

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
2026-10-07 01:48:45 +08:00

116 lines
4.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { DEFAULT_SETTINGS } from "@umt/contracts";
import { secretPatch } from "~/lib/secret.ts";
import { str } from "./resource-section.tsx";
import { type CardSpec, SettingsCard, SettingsGate } from "./settings-card.tsx";
// 元数据:TMDB 接入(API Key 只写,存 secret;Base URL)与语言回退、特别篇。缓存在「缓存」分区,资源识别在「获取」分区。
const DEFAULT_LANGUAGES = DEFAULT_SETTINGS.metadata.languages;
/** "zh-CN, zh_sg en" → ["zh-CN","zh-SG","en"];不合法的项丢弃,全空回缺省 */
function parseLanguages(v: string): string[] {
const out = v
.split(/[,,、\s]+/)
.map((x) => x.trim().replace("_", "-"))
.filter(Boolean)
.map((x) => {
const [l, r] = x.split("-");
return r ? `${l!.toLowerCase()}-${r.toUpperCase()}` : l!.toLowerCase();
})
.filter((x) => /^[a-z]{2,3}(-[A-Z]{2})?$/.test(x));
return out.length ? [...new Set(out)].slice(0, 8) : [...DEFAULT_LANGUAGES];
}
export const TMDB_CARD: CardSpec = {
anchor: "tmdb",
title: "TMDB",
description: "留空时用环境变量 TMDB_API_KEY / TMDB_ACCESS_TOKEN / TMDB_BASE_URL。",
fields: [
{
name: "metadata.tmdbApiKey",
label: "API Key",
kind: "secret",
secret: { set: (v) => v["metadata.tmdbApiKey:set"] === true, clearable: true },
hint: "v3 API Key 或 v4 Read Access Token",
wide: true,
},
{
name: "metadata.tmdbBaseUrl",
label: "Base URL",
kind: "url",
placeholder: "https://api.themoviedb.org",
hint: "自建反代时填写;留空用官方地址",
wide: true,
},
],
fromSettings: (s) => ({
"metadata.tmdbApiKey": "",
"metadata.tmdbApiKey:set": !!s.metadata.tmdbApiKeySecretRef,
"metadata.tmdbBaseUrl": s.metadata.tmdbBaseUrl ?? "",
}),
toPatch: (v) => {
const key = secretPatch(v["metadata.tmdbApiKey"]);
return {
metadata: {
tmdbBaseUrl: str(v["metadata.tmdbBaseUrl"]) || null,
...(key !== undefined ? { tmdbApiKey: key } : {}),
},
};
},
};
export const LANGUAGE_CARD: CardSpec = {
anchor: "language",
title: "语言与季集",
description: "作品、季、集的标题和简介按语言回退链取值;特别篇决定是否拉取季 0。",
fields: [
{
name: "metadata.languages",
label: "语言回退链",
kind: "text",
placeholder: DEFAULT_LANGUAGES.join(", "),
hint: "逗号分隔,如 zh-CN, zh-SG。标题和每集信息取链上第一个有值的语言,简介默认只取中文。只认简繁中文、英文和作品原语言(如日语作品的 ja-JP),其他语言跳过",
wide: true,
},
{
name: "metadata.overviewNonChineseFallback",
label: "简介回退到非中文",
kind: "switch",
hint: "没有中文简介时,按回退链取英文等语言。关闭时留空,标题不受影响",
wide: true,
},
{
name: "metadata.includeSpecials",
label: "包含特别篇(季 0)",
kind: "switch",
hint: "全量刷新和元数据回刷时,TMDB 有季 0 就一并拉取每集信息。特别篇不计入正片季的总集数和订阅完成判定",
wide: true,
},
],
fromSettings: (s) => ({
"metadata.languages": (s.metadata.languages ?? DEFAULT_LANGUAGES).join(", "),
"metadata.includeSpecials": s.metadata.includeSpecials !== false,
"metadata.overviewNonChineseFallback": s.metadata.overviewNonChineseFallback === true,
}),
toPatch: (v) => ({
metadata: {
languages: parseLanguages(str(v["metadata.languages"])),
includeSpecials: v["metadata.includeSpecials"] === true,
overviewNonChineseFallback: v["metadata.overviewNonChineseFallback"] === true,
},
}),
};
export function MetadataSection() {
return (
<SettingsGate>
{(s) => (
<>
<SettingsCard section="metadata" spec={TMDB_CARD} settings={s} />
<SettingsCard section="metadata" spec={LANGUAGE_CARD} settings={s} />
</>
)}
</SettingsGate>
);
}