feat(web): 刮削设置与对话框加「更新」覆盖方式,内容没变的跳过不逐条列出
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
37cf0a398e
commit
4306bff6d3
4 files changed
+15
-7
No files matched your search
@@ -1093,8 +1093,8 @@ const SKIP_TEXT: Record<string, string> = {
|
||||
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<string[]>([]);
|
||||
const [choices, setChoices] = useState<FilesScrapeNeedsChoice[]>([]);
|
||||
const [picked, setPicked] = useState<Record<string, WizardEntity | null>>({});
|
||||
@@ -1157,6 +1157,7 @@ export function ScrapeDialog({ items, root, onClose }: { items: FileEntry[]; roo
|
||||
<fieldset aria-label="已有文件" className="m-0 flex flex-wrap gap-1.5 border-0 p-0">
|
||||
{(
|
||||
[
|
||||
["update", "更新"],
|
||||
["missing", "只补缺失"],
|
||||
["overwrite", "全部覆盖"],
|
||||
] as const
|
||||
|
||||
@@ -704,7 +704,7 @@ let seq = 0;
|
||||
const SCRAPES = new Map<string, ScrapeRecord>();
|
||||
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[] = [];
|
||||
|
||||
@@ -70,7 +70,7 @@ function FileRow({ f }: { f: ScrapeFileResult }) {
|
||||
)}
|
||||
</span>
|
||||
<span className="text-meta text-muted-foreground">{ROLE[f.role] ?? f.role}</span>
|
||||
{f.action !== "written" && f.reason && f.reason !== "scrape_exists" ? (
|
||||
{f.action !== "written" && f.reason && !QUIET_SKIPS.has(f.reason) ? (
|
||||
<span className={f.action === "failed" ? "text-meta text-destructive" : "text-meta text-muted-foreground"}>
|
||||
{reasonLine(f.reason, "写入失败")}
|
||||
</span>
|
||||
@@ -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";
|
||||
|
||||
@@ -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 (
|
||||
<div className="grid grid-cols-1 gap-8">
|
||||
|
||||
Reference in new issue
Block a user