feat(copy): 处理状态的「入库」改为「整理」,术语表与 check:copy 同步

真正入库取决于媒体服务器有没有扫到,本工具只负责整理(元数据、NFO 与图片、按规则归到目录)。
界面与面向用户的服务端文案里「已入库 / 未入库 / 部分入库 / 入库失败 / 入库中 / 入库后 / 原地入库…」
改为「已整理 / 未整理 / 部分整理 / 整理失败 / 整理中 / 整理后 / 原地整理…」;文件管理快速筛选「已整理」、
目录副行「n 个已整理 / 未整理」、季卡片「已整理 x/y」。代码标识符不改,「Emby 已有」这类媒体服务器状态保留。
glossary 加「整理」口径条目;check:copy 拦处理状态语境的「入库」搭配,其它线待替换的文件暂列 TERM_PENDING。

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-06 17:54:28 +08:00
1 parent 79c3b8c9b9
commit 550ac285f4
67 files changed
+171 -143

No files matched your search

+6 -6
View File
@@ -450,7 +450,7 @@ export function RenameDialog({
<Notice tone="neutral">同步 {pv.assetLocations} 条文件位置,写一条整理记录。</Notice>
) : null}
{pv.bindings.length > 0 ? (
<Notice tone="warning">这是作品或季的绑定目录。改名后旧绑定标为已替代,之后入库用新目录。</Notice>
<Notice tone="warning">这是作品或季的绑定目录。改名后旧绑定标为已替代,之后整理用新目录。</Notice>
) : null}
</>
) : null}
@@ -629,7 +629,7 @@ export function TransferDialog({
<StatusBadge tone="warning">冲突 {conflicts.length}(跳过,不覆盖)</StatusBadge>
) : null}
{plan.pairs.some((p) => p.registered) ? (
<StatusBadge>含已入库文件,执行后同步位置</StatusBadge>
<StatusBadge>含已整理文件,执行后同步位置</StatusBadge>
) : null}
</div>
{hnrBlocked ? (
@@ -790,7 +790,7 @@ export function DeleteDialog({
<DialogContent className="max-h-[92dvh] grid-rows-[auto_minmax(0,1fr)_auto] sm:max-w-2xl">
<DialogHeader>
<DialogTitle>{single ? `删除 ${single}?` : `删除 ${items.length} 项?`}</DialogTitle>
<DialogDescription>已检查做种任务、已入库文件和路径绑定。下载器里的任务不受影响。</DialogDescription>
<DialogDescription>已检查做种任务、已整理文件和路径绑定。下载器里的任务不受影响。</DialogDescription>
</DialogHeader>
<div className="min-h-0 space-y-3 overflow-y-auto">
{check.isPending ? (
@@ -837,7 +837,7 @@ export function DeleteDialog({
</p>
))}
{c.assets.length ? (
<p>已入库文件 {c.assets.length} 个(删除后从媒体库移除,已满足的收录版本退回待处理)</p>
<p>已整理文件 {c.assets.length} 个(删除后从媒体库移除,已满足的收录版本退回待处理)</p>
) : null}
{c.bindings.map((bd) => (
<p key={bd.bindingId}>
@@ -869,7 +869,7 @@ export function DeleteDialog({
<span>
解除路径绑定
<span className="block text-meta text-muted-foreground">
绑定标为已替代,该作品下次入库重新选目录。
绑定标为已替代,该作品下次整理重新选目录。
</span>
</span>
</label>
@@ -1139,7 +1139,7 @@ export function ScrapeDialog({ items, root, onClose }: { items: FileEntry[]; roo
<DialogHeader>
<DialogTitle>刮削{single ? ` · ${single.name}` : ` · ${items.length} 项`}</DialogTitle>
<DialogDescription>
按路径识别作品,在所在目录写 NFO 和图片,Emby、Jellyfin、Kodi 直接读取。没入库的也能刮削。
按路径识别作品,在所在目录写 NFO 和图片,Emby、Jellyfin、Kodi 直接读取。没整理的也能刮削。
</DialogDescription>
</DialogHeader>
{!started ? (
@@ -110,7 +110,7 @@ export function FileDetail({
value:
e.type === "dir"
? e.dirSummary
? `${e.dirSummary.videoCount}${e.dirSummary.partial ? "+" : ""} 个视频 · ${e.dirSummary.registeredCount} 个已入库`
? `${e.dirSummary.videoCount}${e.dirSummary.partial ? "+" : ""} 个视频 · ${e.dirSummary.registeredCount} 个已整理`
: "—"
: formatBytes(e.size, 2),
},
@@ -135,7 +135,7 @@ export function FileDetail({
</DetailSection>
{e.asset ? (
<DetailSection title="已入库文件">
<DetailSection title="已整理文件">
<KvList
items={[
{
+3 -3
View File
@@ -94,7 +94,7 @@ const base = {
describe("状态与禁用原因", () => {
it("状态徽标带文字,H&R 未满足为 warning,逃逸为 destructive", () => {
expect(entryStatusView({ ...base, status: "registered" })?.label).toBe("已入库");
expect(entryStatusView({ ...base, status: "registered" })?.label).toBe("已整理");
expect(
entryStatusView({
...base,
@@ -125,7 +125,7 @@ describe("状态与禁用原因", () => {
expect(opDisabledReason("move", seeding, lib)).toMatch(/H&R/);
expect(opDisabledReason("move", base, { kind: "library", writable: false })).toMatch(/只读/);
expect(opDisabledReason("rename", base, { kind: "download", writable: false })).toBeNull();
expect(opDisabledReason("scrape", base, lib)).toMatch(/未登记/);
expect(opDisabledReason("scrape", base, lib)).toMatch(/整理后才能/);
expect(opDisabledReason("writeNfo", base, lib)).toBeNull();
expect(opDisabledReason("writeNfo", base, { kind: "library", writable: false })).toMatch(/只读/);
expect(opDisabledReason("copyPath", { ...base, escape: true }, lib)).toBeNull();
@@ -272,7 +272,7 @@ describe("v2 菜单与副行", () => {
type: "dir" as const,
dirSummary: { videoCount: 13, registeredCount: 0, partial: false },
})?.text,
).toBe("13 个视频 · 未入库");
).toBe("13 个视频 · 未整理");
// 没有 parsedHint(服务端解析不出标题)时不显示副行,前端不自己解析
expect(entrySubline({ ...video, parsedHint: null })).toBeNull();
});
+6 -6
View File
@@ -26,7 +26,7 @@ export function entryStatusView(e: Pick<FileEntry, "status" | "download" | "esca
tone: "neutral",
};
case "registered":
return { label: "已入库", tone: "success" };
return { label: "已整理", tone: "success" };
case "seeding":
return e.download?.hnr === "unsatisfied"
? { label: "做种中·H&R 未满足", tone: "warning", hint: "H&R 满足前不能改名、删除或移动" }
@@ -42,7 +42,7 @@ export const FILTER_CHIPS = [
{ value: "", label: "全部" },
{ value: "video", label: "视频" },
{ value: "unidentified", label: "未识别" },
{ value: "registered", label: "已入库" },
{ value: "registered", label: "已整理" },
{ value: "downloading", label: "下载中" },
{ value: "temp", label: "未完成下载" },
] as const;
@@ -98,7 +98,7 @@ export function opDisabledReason(op: FileOp, e: FileEntry, root: Pick<FileRoot,
if (e.type === "file" && e.fileKind !== "video") return "只有视频或目录能整理";
return null;
case "scrape":
return e.asset ? null : "未登记,先整理入库";
return e.asset ? null : "整理后才能刷新元数据";
case "writeNfo":
if (root.kind === "library" && !root.writable) return "只读目录,不写 NFO";
if (e.status === "temp") return "未完成的文件不能刮削";
@@ -314,7 +314,7 @@ export function deleteBlockText(b: string | null): { text: string; soft: boolean
case "is_root":
return { text: "不能删除登记目录本身", soft: false };
case "needs_retire":
return { text: "含已入库文件,勾选「同时从媒体库移除」后才能删除", soft: true };
return { text: "含已整理文件,勾选「同时从媒体库移除」后才能删除", soft: true };
case "needs_unbind":
return { text: "是作品或季的绑定目录,勾选「解除路径绑定」后才能删除", soft: true };
case "root_unavailable":
@@ -431,7 +431,7 @@ export function menuModel(list: FileEntry[], root: Pick<FileRoot, "kind" | "writ
/**
* 行内 hover / 键盘聚焦时浮出的常用操作(桌面,§5.1;照 MP 的悬停图标,但只露 2–3 个,其余留在 ⋯ 菜单):
* 已入库 → 打开作品、刷新元数据、重命名;未入库视频 / 目录 → 整理、识别、刮削;
* 已整理 → 打开作品、刷新元数据、重命名;未整理视频 / 目录 → 整理、识别、刮削;
* 其余能识别的(临时文件里的视频等)→ 识别、重命名、移动到;别的文件 → 重命名、移动到。
*/
export function hoverOps(e: FileEntry): MenuKey[] {
@@ -472,7 +472,7 @@ export function entrySubline(e: FileEntry): { text: string; tone: "link" | "hint
const s = e.dirSummary;
if (!s.videoCount && !s.registeredCount) return null;
return {
text: `${s.videoCount}${s.partial ? "+" : ""} 个视频${s.registeredCount ? ` · ${s.registeredCount} 个已入库` : s.videoCount ? " · 未入库" : ""}`,
text: `${s.videoCount}${s.partial ? "+" : ""} 个视频${s.registeredCount ? ` · ${s.registeredCount} 个已整理` : s.videoCount ? " · 未整理" : ""}`,
tone: "meta",
};
}