diff --git a/apps/web/app/components/files/dialogs.tsx b/apps/web/app/components/files/dialogs.tsx index 9d026129..1005a0ff 100644 --- a/apps/web/app/components/files/dialogs.tsx +++ b/apps/web/app/components/files/dialogs.tsx @@ -1093,8 +1093,8 @@ const SKIP_TEXT: Record = { export function ScrapeDialog({ items, root, onClose }: { items: FileEntry[]; root: FileRoot; onClose: () => void }) { const settings = useSettings(); const scrape = useScrape(); - const [mode, setMode] = useState<"missing" | "overwrite" | null>(null); - const curMode = mode ?? settings.data?.organize.scrapeMode ?? "missing"; + const [mode, setMode] = useState<"missing" | "overwrite" | "update" | null>(null); + const curMode = mode ?? settings.data?.organize.scrapeMode ?? "update"; const [recordIds, setRecordIds] = useState([]); const [choices, setChoices] = useState([]); const [picked, setPicked] = useState>({}); @@ -1157,6 +1157,7 @@ export function ScrapeDialog({ items, root, onClose }: { items: FileEntry[]; roo
{( [ + ["update", "更新"], ["missing", "只补缺失"], ["overwrite", "全部覆盖"], ] as const diff --git a/apps/web/app/components/files/mock.ts b/apps/web/app/components/files/mock.ts index 9640bd45..a9284f3c 100644 --- a/apps/web/app/components/files/mock.ts +++ b/apps/web/app/components/files/mock.ts @@ -704,7 +704,7 @@ let seq = 0; const SCRAPES = new Map(); function mockScrape(b: { items: { root: string; path: string; mediaEntityId?: string; external?: { externalId: string } }[]; - mode?: "missing" | "overwrite"; + mode?: "missing" | "overwrite" | "update"; }) { const records: ScrapeRecord[] = []; const needsChoice: unknown[] = []; diff --git a/apps/web/app/components/library/scrape-panel.tsx b/apps/web/app/components/library/scrape-panel.tsx index e27eadae..fe6e0429 100644 --- a/apps/web/app/components/library/scrape-panel.tsx +++ b/apps/web/app/components/library/scrape-panel.tsx @@ -70,7 +70,7 @@ function FileRow({ f }: { f: ScrapeFileResult }) { )} {ROLE[f.role] ?? f.role} - {f.action !== "written" && f.reason && f.reason !== "scrape_exists" ? ( + {f.action !== "written" && f.reason && !QUIET_SKIPS.has(f.reason) ? ( {reasonLine(f.reason, "写入失败")} @@ -80,11 +80,14 @@ function FileRow({ f }: { f: ScrapeFileResult }) { ); } +/** 不必逐条列出的跳过:已存在(不是本工具写的 / 只补缺失)、内容没变 */ +const QUIET_SKIPS = new Set(["scrape_exists", "scrape_unchanged"]); + /** 一条刮削记录:状态、目录与识别结果、计数、逐文件结果(缺省不列"已存在"跳过的) */ export function ScrapeRecordView({ record: s, showPath = false }: { record: ScrapeRecord; showPath?: boolean }) { const [showAll, setShowAll] = useState(false); const files = s.files; - const important = files.filter((f) => f.action !== "skipped" || f.reason !== "scrape_exists"); + const important = files.filter((f) => f.action !== "skipped" || !QUIET_SKIPS.has(f.reason ?? "")); const shown = showAll ? files : important.slice(0, 12); const hidden = files.length - shown.length; const done = s.status !== "queued" && s.status !== "running"; diff --git a/apps/web/app/components/settings/library.tsx b/apps/web/app/components/settings/library.tsx index b3db685b..dfdf130d 100644 --- a/apps/web/app/components/settings/library.tsx +++ b/apps/web/app/components/settings/library.tsx @@ -57,10 +57,11 @@ const SCRAPE_CARD: CardSpec = { label: "已有文件", kind: "select", options: [ + { value: "update", label: "更新" }, { value: "missing", label: "只补缺失" }, { value: "overwrite", label: "全部覆盖" }, ], - hint: "全部覆盖会替换目录里已有的 NFO 和图片,包括其他工具写的", + hint: "更新只替换本工具写过、之后没被改过的文件;全部覆盖会替换目录里已有的 NFO 和图片,包括其他工具写的", }, { name: "organize.scrapeImages", @@ -84,13 +85,16 @@ const SCRAPE_CARD: CardSpec = { toPatch: (v) => ({ organize: { scrapeAfterImport: v["organize.scrapeAfterImport"] === true, - scrapeMode: str(v["organize.scrapeMode"]) === "overwrite" ? "overwrite" : "missing", + scrapeMode: scrapeModeOf(str(v["organize.scrapeMode"])), scrapeImages: v["organize.scrapeImages"] === true, scrapeEpisodeThumbs: v["organize.scrapeEpisodeThumbs"] === true, }, }), }; +const scrapeModeOf = (v: string | null | undefined): "missing" | "overwrite" | "update" => + v === "overwrite" || v === "missing" ? v : "update"; + export function LibrarySection() { return (