Files
UHD_Media_Tool/apps/web/app/components/settings/metadata.tsx
T
2026-10-06 18:27:51 +08:00

116 lines
4.0 KiB
TypeScript
Raw 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: "标题和每集信息按顺序取第一个有值的语言,简介默认只取链里的中文;中文名取链中第一个中文值。只认简繁中文、英文和作品原语言(如日语作品的 ja-JP),其它语言跳过。逗号分隔,如 zh-CN, zh-SG",
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>
);
}