diff --git a/apps/server/src/modules/acquisition-organize/index.ts b/apps/server/src/modules/acquisition-organize/index.ts index 5f482143..ce9d726a 100644 --- a/apps/server/src/modules/acquisition-organize/index.ts +++ b/apps/server/src/modules/acquisition-organize/index.ts @@ -133,7 +133,7 @@ export function createAcquisitionOrganizeModule(overrides: AoOverrides = {}): Se key: "cache.threshold", defaults: { name: "下载盘检查", - description: "下载盘超过暂停线时清理已入库的下载", + description: "下载盘超过暂停线时清理已整理的下载", group: "maintain", schedule: every(planMs), }, @@ -155,8 +155,8 @@ export function createAcquisitionOrganizeModule(overrides: AoOverrides = {}): Se registerScheduledJob(ctx, { key: "downloads.orchestrate", defaults: { - name: "补提交与补入库", - description: "补交没提交成功的下载,补整理下载完但没入库的任务,重新排队卡住的整理", + name: "补提交与补整理", + description: "补交没提交成功的下载,补整理下载完但没整理的任务,重新排队卡住的整理", group: "download", schedule: every(planMs), }, @@ -165,7 +165,7 @@ export function createAcquisitionOrganizeModule(overrides: AoOverrides = {}): Se const imports = await sweepPendingImports(d); const rec = await recoverStalledRecords(d); return ( - `补提交 ${submitted},补入库 ${imports}` + + `补提交 ${submitted},补整理 ${imports}` + (rec.requeued ? `,重排整理 ${rec.requeued}` : "") + (rec.failed ? `,整理停止 ${rec.failed}` : "") + (rec.removed ? `,移除下载任务 ${rec.removed}` : "") @@ -278,7 +278,7 @@ async function sweepPendingImports(d: AoDeps): Promise { ); if (q) n++; } catch (err) { - d.ctx.logger.warn({ downloadTaskId: r.id, err: { message: errMessage(err) } }, "补入库入队失败"); + d.ctx.logger.warn({ downloadTaskId: r.id, err: { message: errMessage(err) } }, "补整理入队失败"); } } return n; diff --git a/apps/server/src/modules/acquisition-organize/routes/downloads.ts b/apps/server/src/modules/acquisition-organize/routes/downloads.ts index 5fb72e43..2d335e38 100644 --- a/apps/server/src/modules/acquisition-organize/routes/downloads.ts +++ b/apps/server/src/modules/acquisition-organize/routes/downloads.ts @@ -158,7 +158,7 @@ export function registerDownloadRoutes(app: ModuleApp, d: AoDeps) { method: "post", path: "/download-cache/cleanup", scope: "admin", - summary: "入队一轮缓存清理(只清已验证入库且满足保留/H&R 的纳管任务);返回任务 id,进度见任务页", + summary: "入队一轮缓存清理(只清已核验整理且满足保留/H&R 的纳管任务);返回任务 id,进度见任务页", body: z.object({ downloaderInstanceId: z.uuid().optional() }), response: accepted, }, diff --git a/apps/server/src/modules/acquisition-organize/routes/library-versions.ts b/apps/server/src/modules/acquisition-organize/routes/library-versions.ts index 8e3d285b..cd5fca82 100644 --- a/apps/server/src/modules/acquisition-organize/routes/library-versions.ts +++ b/apps/server/src/modules/acquisition-organize/routes/library-versions.ts @@ -14,7 +14,7 @@ export function registerLibraryVersionRoutes(app: ModuleApp, d: AoDeps) { method: "get", path: "/library/{id}/versions", scope: "read", - summary: "作品的入库版本:每季每集的本地文件版本与规格、季 / 作品汇总、与版本目标的比对", + summary: "作品的已整理版本:每季每集的本地文件版本与规格、季 / 作品汇总、与版本目标的比对", params: IdParam, query: LibraryVersionsQuery, response: LibraryVersions, diff --git a/apps/server/src/modules/acquisition-organize/routes/library.ts b/apps/server/src/modules/acquisition-organize/routes/library.ts index 6b938747..3431682e 100644 --- a/apps/server/src/modules/acquisition-organize/routes/library.ts +++ b/apps/server/src/modules/acquisition-organize/routes/library.ts @@ -433,7 +433,7 @@ export function registerLibraryRoutes(app: ModuleApp, d: AoDeps) { mode: req.mode, actor: { type: actor?.type === "api_key" ? "api_key" : "user", id: actor?.id ?? null }, }); - if (!recs.length) throw new ApiException("precondition_failed", "作品没有已入库文件。到文件管理里对目录刮削"); + if (!recs.length) throw new ApiException("precondition_failed", "作品没有已整理文件。到文件管理里对目录刮削"); return { mediaEntityId: params.id, taskId: recs[0]?.taskId ?? null, diff --git a/apps/server/src/modules/acquisition-organize/services/manual-acquisition.ts b/apps/server/src/modules/acquisition-organize/services/manual-acquisition.ts index 80252015..99de405f 100644 --- a/apps/server/src/modules/acquisition-organize/services/manual-acquisition.ts +++ b/apps/server/src/modules/acquisition-organize/services/manual-acquisition.ts @@ -63,7 +63,7 @@ export async function planManualAcquisition( if (!topo?.savePath) throw new ApiException("precondition_failed", "没有可用的下载器或保存目录"); const replacementIds = body.importMode === "replace" ? [...new Set(body.replacementAssetIds)] : []; if (body.importMode === "replace" && (!entityId || replacementIds.length === 0)) - throw new ApiException("bad_request", "洗版入库需要明确作品及要替换的已有版本"); + throw new ApiException("bad_request", "洗版需要明确作品及要替换的已有版本"); if (replacementIds.length) { const assets = await db .selectFrom("media_asset") diff --git a/apps/server/src/modules/acquisition-organize/services/organize-exec.ts b/apps/server/src/modules/acquisition-organize/services/organize-exec.ts index 044e5db6..b9f4f5a1 100644 --- a/apps/server/src/modules/acquisition-organize/services/organize-exec.ts +++ b/apps/server/src/modules/acquisition-organize/services/organize-exec.ts @@ -420,7 +420,7 @@ export async function executeRecord( if (outcome.replaced?.disposition === "left") { await upsertDecision(d, db, { kind: "other", - title: "新版本已入库,旧文件未能处置", + title: "新版本已整理,旧文件未能处置", summary: `${pf.dst} 已替换为新版本;旧文件留在 ${outcome.replaced.path}`, subjectType: "organization_record", subjectId: recordId, @@ -604,7 +604,7 @@ export async function verifyInPlace( ): Promise { const observed = await fsr.proxy.statSafe(path, { root: frozen.rootPath, sentinel: frozen.sentinel }); if (observed.kind !== "ok" || !observed.facts.isFile || observed.facts.isSymbolicLink) { - return { status: "failed", error: { code: "SOURCE_MISSING", message: "原地入库的文件不存在或不可访问" } }; + return { status: "failed", error: { code: "SOURCE_MISSING", message: "原地整理的文件不存在或不可访问" } }; } const planned = frozen.sourceFacts?.[path]; if (observed.facts.size !== size || (planned && observed.facts.mtimeMs !== planned.mtimeMs)) { diff --git a/apps/server/src/modules/acquisition-organize/services/organize-finalize.ts b/apps/server/src/modules/acquisition-organize/services/organize-finalize.ts index fae3c190..a1ea1b65 100644 --- a/apps/server/src/modules/acquisition-organize/services/organize-finalize.ts +++ b/apps/server/src/modules/acquisition-organize/services/organize-finalize.ts @@ -437,7 +437,7 @@ export async function finalizeRecord(d: AoDeps, recordId: string): Promise { const selected = [...new Set(ids)]; - if (!selected.length) throw new Error("洗版入库必须选择旧版本"); + if (!selected.length) throw new Error("洗版必须选择旧版本"); const assets = await d.ctx.db.selectFrom("media_asset").selectAll().where("id", "in", selected).execute(); if ( assets.length !== selected.length || @@ -592,7 +592,7 @@ export async function quarantineNotVideo(d: AoDeps, frozen: FrozenPlan, recordId const names = [...rejectedMains].map((p) => basename(p)); await upsertDecision(d, db, { kind: "other", - title: `${rejectedMains.size} 个文件不是视频,没有入库`, + title: `${rejectedMains.size} 个文件不是视频,没有整理`, summary: `${names.slice(0, 5).join("、")}${names.length > 5 ? " 等" : ""} 没有视频流(伪装或损坏的文件)。${ moved.length ? "已拷进媒体库的文件移入回收站" : "" }${left.length ? `${moved.length ? "," : ""}${left.length} 个文件留在媒体库里待核对` : ""}${ diff --git a/apps/server/src/modules/acquisition-organize/services/scrape.ts b/apps/server/src/modules/acquisition-organize/services/scrape.ts index d50de135..95d9ff26 100644 --- a/apps/server/src/modules/acquisition-organize/services/scrape.ts +++ b/apps/server/src/modules/acquisition-organize/services/scrape.ts @@ -565,7 +565,7 @@ export async function scrapeAfterImport( }); } catch (err) { // 新记录入队失败时 queueScrape 已把它标成 task_enqueue_failed(整理详情可见);这里再兜一条,防止没留下记录 - d.ctx.logger.warn({ entityId, recordId, dir, err: { message: errMessage(err) } }, "入库后自动刮削没排上"); + d.ctx.logger.warn({ entityId, recordId, dir, err: { message: errMessage(err) } }, "整理后自动刮削没排上"); const marked = await d.ctx.db .selectFrom("scrape_record") .select("id") @@ -577,7 +577,7 @@ export async function scrapeAfterImport( } } } catch (err) { - d.ctx.logger.warn({ entityId, recordId, err: { message: errMessage(err) } }, "入库后自动刮削没排上"); + d.ctx.logger.warn({ entityId, recordId, err: { message: errMessage(err) } }, "整理后自动刮削没排上"); await recordScrapeSkipped(d, recordId, "scrape_internal_error", { root, match }); } } diff --git a/apps/server/src/modules/acquisition-organize/services/subscriptions.ts b/apps/server/src/modules/acquisition-organize/services/subscriptions.ts index c5c491cb..d1857262 100644 --- a/apps/server/src/modules/acquisition-organize/services/subscriptions.ts +++ b/apps/server/src/modules/acquisition-organize/services/subscriptions.ts @@ -798,7 +798,7 @@ export async function afterSlotVerified( kind: "other", severity: "info", title: "疑似缺集", - summary: `已入库最高集之前缺:${desc}。总集数未知,订阅继续追踪`.slice(0, 500), + summary: `已整理最高集之前缺:${desc}。总集数未知,订阅继续追踪`.slice(0, 500), subjectType: "acquisition_slot", subjectId: slot.id, dedupeKey: `suspected_missing:${slot.id}`, diff --git a/apps/server/src/modules/acquisition-organize/services/takeover.ts b/apps/server/src/modules/acquisition-organize/services/takeover.ts index bc7ccc65..64e894d9 100644 --- a/apps/server/src/modules/acquisition-organize/services/takeover.ts +++ b/apps/server/src/modules/acquisition-organize/services/takeover.ts @@ -100,7 +100,7 @@ const OUTCOME_TEXT: Record = { export function takeoverSummary(t: TakeoverIdentify | null): string { if (!t) return "下载内容未关联作品。识别或指定作品后再整理"; const what = [t.parsed.title, t.parsed.year].filter(Boolean).join(" "); - return `按文件名识别${what ? `「${what}」` : ""}:${OUTCOME_TEXT[t.result.outcome]}。选择作品、作为临时作品入库,或忽略`; + return `按文件名识别${what ? `「${what}」` : ""}:${OUTCOME_TEXT[t.result.outcome]}。选择作品、作为临时作品整理,或忽略`; } /** 接管识别失败 / 歧义的事项选项:候选(最多 3 个)、选择作品(本地 / TMDB)、作为临时作品入库、忽略 */ @@ -140,7 +140,7 @@ export function identityOptions(t: TakeoverIdentify | null, fallbackTitle: strin t?.parsed.mediaTypeHint === "tv" || t?.parsed.season !== undefined || t?.parsed.episodes !== undefined; out.push({ key: "provisional", - label: "作为临时作品入库", + label: "作为临时作品整理", description: "按文件名建本地临时作品后整理,之后可合并或补外部身份", input: { provisional: { kind: tvLike ? "series" : "movie", title, year: t?.parsed.year ?? null } }, }); @@ -153,7 +153,7 @@ export function identityOptions(t: TakeoverIdentify | null, fallbackTitle: strin export const CONFLICT_OPTIONS: DecisionOptionInput[] = [ { key: "replace", label: "替换", description: "新文件核验通过后替换已有文件,旧文件进回收站" }, { key: "keep_both", label: "保留两者", description: "新文件改名(加序号)后放在旁边,已有文件不动" }, - { key: "skip", label: "跳过", description: "已存在的文件不整理,其余文件照常入库" }, + { key: "skip", label: "跳过", description: "已存在的文件不整理,其余文件照常整理" }, ]; // ── 保留两者:把目标已存在的主视频(连同附属文件)改名为 "<名称> (n)" ── diff --git a/apps/server/src/modules/file-manager/mutate.ts b/apps/server/src/modules/file-manager/mutate.ts index 6b1733ba..c764ef05 100644 --- a/apps/server/src/modules/file-manager/mutate.ts +++ b/apps/server/src/modules/file-manager/mutate.ts @@ -68,7 +68,7 @@ export async function renameEntry( if (hits.length > 0) throw new FilesError( "download_active", - `该路径属于下载任务 ${hits.map((h) => h.taskId).join(", ")},重命名会让下载器找不到文件。先整理入库再改`, + `该路径属于下载任务 ${hits.map((h) => h.taskId).join(", ")},重命名会让下载器找不到文件。先整理再改`, ); const dirAbs = dirname(r.abs); diff --git a/apps/server/src/modules/file-manager/organize.ts b/apps/server/src/modules/file-manager/organize.ts index 2d17a25c..c12896cb 100644 --- a/apps/server/src/modules/file-manager/organize.ts +++ b/apps/server/src/modules/file-manager/organize.ts @@ -306,7 +306,7 @@ export async function organizeFiles( if (action === "in_place") { // 本次保留实际库根与路径,不使用来源配置的搬运目标。 if (!r.def.libraryRootId) - throw new FilesError("bad_request", "原地入库需要文件位于已登记的媒体库目录;请先在设置中登记该目录"); + throw new FilesError("bad_request", "原地整理需要文件位于已登记的媒体库目录;请先在设置中登记该目录"); targetLib = r.def.libraryRootId; } if (action !== "in_place" && it.targetDir) { diff --git a/apps/server/src/modules/file-manager/transfer.ts b/apps/server/src/modules/file-manager/transfer.ts index 742ee55f..72816f78 100644 --- a/apps/server/src/modules/file-manager/transfer.ts +++ b/apps/server/src/modules/file-manager/transfer.ts @@ -230,7 +230,7 @@ export async function transfer( if (hnrBlocks.length > 0) throw new FilesError( "download_active", - `源属于下载任务 ${[...new Set(hnrBlocks.map((h) => h.taskId))].join(", ")},直接移动会让下载器丢失文件。改用整理入库,它会按做种义务决定能否移动`, + `源属于下载任务 ${[...new Set(hnrBlocks.map((h) => h.taskId))].join(", ")},直接移动会让下载器丢失文件。改用整理,它会按做种义务决定能否移动`, ); if (!isAdmin(principal)) { // 每个源按其(目录则为其下)已登记资产求作品集合,逐一核对授权;任一不覆盖 → 整体拒绝并列出未授权项 diff --git a/apps/server/src/modules/file-manager/trash.ts b/apps/server/src/modules/file-manager/trash.ts index e330e0fb..d71ea7f7 100644 --- a/apps/server/src/modules/file-manager/trash.ts +++ b/apps/server/src/modules/file-manager/trash.ts @@ -157,7 +157,7 @@ const BLOCK_ERR: Record< > = { download_active: ["download_active", "属于未完成或做种义务未满足的下载任务"], is_root: ["bad_request", "不能删除根目录或只读根下的内容"], - needs_retire: ["needs_retire", "含已入库文件,需勾选「同时从媒体库移除」"], + needs_retire: ["needs_retire", "含已整理文件,需勾选「同时从媒体库移除」"], needs_unbind: ["needs_unbind", "是作品/季的绑定目录,需勾选「解除绑定」"], root_unavailable: ["root_unavailable", "根不可用"], not_found: ["not_found", "不存在"], diff --git a/apps/server/test/acquisition-organize/organize-not-video.test.ts b/apps/server/test/acquisition-organize/organize-not-video.test.ts index ccccb370..dccf7aae 100644 --- a/apps/server/test/acquisition-organize/organize-not-video.test.ts +++ b/apps/server/test/acquisition-organize/organize-not-video.test.ts @@ -76,7 +76,7 @@ describe.skipIf(!hasPg)("整理:不是视频的文件不留在媒体库", () => .select(["title", "status"]) .where("dedupe_key", "=", `organize_not_video:${plan.recordId}`) .execute(); - expect(decisions).toEqual([{ title: "1 个文件不是视频,没有入库", status: "open" }]); + expect(decisions).toEqual([{ title: "1 个文件不是视频,没有整理", status: "open" }]); // 重放:已结束记录不重复移动 await executeRecord(h.d, plan.recordId!); diff --git a/apps/web/app/api/downloads.ts b/apps/web/app/api/downloads.ts index 7897b7b6..b27ada55 100644 --- a/apps/web/app/api/downloads.ts +++ b/apps/web/app/api/downloads.ts @@ -211,8 +211,8 @@ export const DOWNLOAD_STATUS_LABEL: Record = { paused: "已暂停", stalled: "无进展", completed: "下载完成", - importing: "入库中", - imported: "已入库", + importing: "整理中", + imported: "已整理", failed: "失败", removed: "已移除", missing: "下载器中缺失", diff --git a/apps/web/app/api/records.ts b/apps/web/app/api/records.ts index cb67eb8d..cd78dad8 100644 --- a/apps/web/app/api/records.ts +++ b/apps/web/app/api/records.ts @@ -182,7 +182,7 @@ export const TRIGGER_LABEL: Record = { auto: "自 /** 整理方式 / 文件操作(记录的 action) */ export const ACTION_LABEL = { copy: "复制", - in_place: "原地入库", + in_place: "原地整理", move: "移动", rename: "重命名", relocate: "目录调整", diff --git a/apps/web/app/components/downloads/board-format.test.ts b/apps/web/app/components/downloads/board-format.test.ts index ab5afad2..5d285146 100644 --- a/apps/web/app/components/downloads/board-format.test.ts +++ b/apps/web/app/components/downloads/board-format.test.ts @@ -25,12 +25,12 @@ describe("下载面板展示换算(DL-2)", () => { expect(formatEta(3 * 86400 + 4 * 3600)).toBe("3 天 4 小时"); }); - it("最近一次整理结果:已入库 / 整理中 / 待整理 / 入库失败 / 部分入库;有问题的链到整理记录就地处理", () => { + it("最近一次整理结果:已整理 / 整理中 / 待整理 / 整理失败 / 部分整理;有问题的链到整理记录就地处理", () => { expect(organizeState({ status: "completed", organize: null })).toMatchObject({ label: "待整理", to: null }); expect(organizeState({ status: "importing", organize: null })?.label).toBe("整理中"); - expect(organizeState({ status: "imported", organize: null })?.label).toBe("已入库"); + expect(organizeState({ status: "imported", organize: null })?.label).toBe("已整理"); expect(organizeState({ status: "completed", organize: rec("succeeded") })).toMatchObject({ - label: "已入库", + label: "已整理", tone: "success", to: `/console/organize/${RID}`, }); @@ -44,7 +44,7 @@ describe("下载面板展示换算(DL-2)", () => { }); // 原因码转成人话,不直接给人看 expect(failed).toMatchObject({ - label: "入库失败", + label: "整理失败", tone: "destructive", hint: "没识别出作品。指定作品后重新整理", }); @@ -52,7 +52,7 @@ describe("下载面板展示换算(DL-2)", () => { expect(organizeState({ status: "completed", organize: rec("failed", { reason: "磁盘已满" }) })?.hint).toBe( "磁盘已满", ); - expect(organizeState({ status: "completed", organize: rec("partial") })?.label).toBe("部分入库"); + expect(organizeState({ status: "completed", organize: rec("partial") })?.label).toBe("部分整理"); expect(organizeState({ status: "completed", organize: rec("failed", { reason: "transfer_failed" }) })?.hint).toBe( "文件没有整理成功。在整理记录里查看失败的文件", ); @@ -72,11 +72,11 @@ describe("下载面板展示换算(DL-2)", () => { it("外部任务:没整理过显示 —(null),整理过的照常显示结果", () => { expect(organizeState({ status: "completed", organize: null, managed: false })).toBeNull(); expect(organizeState({ status: "completed", organize: null, managed: true })?.label).toBe("待整理"); - expect(organizeState({ status: "completed", organize: rec("succeeded"), managed: false })?.label).toBe("已入库"); + expect(organizeState({ status: "completed", organize: rec("succeeded"), managed: false })?.label).toBe("已整理"); expect( organizeState({ status: "completed", organize: rec("failed", { reason: "transfer_failed" }), managed: false }) ?.label, - ).toBe("入库失败"); + ).toBe("整理失败"); }); it("连接数:全 0 且总数未知时不显示", () => { diff --git a/apps/web/app/components/downloads/board-format.ts b/apps/web/app/components/downloads/board-format.ts index 7d8e9d0a..cab0ccfc 100644 --- a/apps/web/app/components/downloads/board-format.ts +++ b/apps/web/app/components/downloads/board-format.ts @@ -40,7 +40,7 @@ export function reasonHint(raw: string | null | undefined): string | null { } /** - * 已完成任务的最近一次整理结果:已入库 / 整理中 / 待整理 / 入库失败 / 部分入库。 + * 已完成任务的最近一次整理结果:已整理 / 整理中 / 待整理 / 整理失败 / 部分整理。 * 外部任务(managed=false)没整理过时不算"待整理",返回 null(界面显示 —);整理过的照常显示结果。 */ export function organizeState( @@ -51,9 +51,9 @@ export function organizeState( // 有问题的整理在整理记录详情里就地处理(待处理中心已取消) const to = rec ? consolePath("organize", rec.recordId) : null; if (rec?.status === "succeeded" || (t.status === "imported" && rec?.status !== "failed")) - return { label: "已入库", tone: "success", to, hint: null }; - if (rec?.status === "failed") return { label: "入库失败", tone: "destructive", to, hint: reasonHint(rec.reason) }; - if (rec?.status === "partial") return { label: "部分入库", tone: "warning", to, hint: reasonHint(rec.reason) }; + return { label: "已整理", tone: "success", to, hint: null }; + if (rec?.status === "failed") return { label: "整理失败", tone: "destructive", to, hint: reasonHint(rec.reason) }; + if (rec?.status === "partial") return { label: "部分整理", tone: "warning", to, hint: reasonHint(rec.reason) }; if (rec?.status === "queued" || rec?.status === "running" || t.status === "importing") return { label: "整理中", tone: "neutral", to, hint: null }; return { label: "待整理", tone: "warning", to: rec?.decision ? to : null, hint: null }; diff --git a/apps/web/app/components/downloads/cache-volumes.tsx b/apps/web/app/components/downloads/cache-volumes.tsx index 6295a7d3..3645aa25 100644 --- a/apps/web/app/components/downloads/cache-volumes.tsx +++ b/apps/web/app/components/downloads/cache-volumes.tsx @@ -119,7 +119,7 @@ export function CacheVolumes() { } title="按规则清理下载缓存?" - description="只清理已入库、且满足保留期与 H&R 的本工具任务,其余不动。" + description="只清理已整理、且满足保留期与 H&R 的本工具任务,其余不动。" confirmLabel="清理" onConfirm={() => cleanup.mutateAsync(undefined).then( diff --git a/apps/web/app/components/downloads/download-detail.tsx b/apps/web/app/components/downloads/download-detail.tsx index 3ed2218c..66bbbebe 100644 --- a/apps/web/app/components/downloads/download-detail.tsx +++ b/apps/web/app/components/downloads/download-detail.tsx @@ -96,7 +96,7 @@ export function DownloadDetail({ task, live }: { task: DownloadTask; live?: Down const trace = useDownloadTrace(task, plan.data); const [organizing, setOrganizing] = useState(false); const canOrganize = ["completed", "importing", "imported"].includes(task.status); - // 下载完成但最近一次整理失败:状态行只写"下载完成"会误导,单独说明入库失败 + // 下载完成但最近一次整理失败:状态行只写"下载完成"会误导,单独说明整理失败 const lastRecord = [...(trace.records.data?.items ?? [])].sort((a, b) => (b.startedAt ?? b.createdAt).localeCompare(a.startedAt ?? a.createdAt), )[0]; @@ -143,7 +143,7 @@ export function DownloadDetail({ task, live }: { task: DownloadTask; live?: Down ) : null} {importFailed ? (

- 入库失败:{reasonLine(importFailed.reason)}。 + 整理失败:{reasonLine(importFailed.reason)}。 去整理记录处理 diff --git a/apps/web/app/components/downloads/manual-download-dialog.tsx b/apps/web/app/components/downloads/manual-download-dialog.tsx index 7c96ec19..de8a3567 100644 --- a/apps/web/app/components/downloads/manual-download-dialog.tsx +++ b/apps/web/app/components/downloads/manual-download-dialog.tsx @@ -610,10 +610,10 @@ export function ExistingVersionsSection({

{summary ?? `媒体库已有 ${versions.length} 个版本`}

onModeChange(v === "replace" ? "replace" : "normal")} - allLabel="正常入库,保留已有版本" + allLabel="保留" options={[{ value: "replace", label: "一次性洗版" }]} />
@@ -640,7 +640,7 @@ export function ExistingVersionsSection({ ))}

- 本次新文件成功入库后替换所选旧文件。剧集只替换成功对应的季集,其余保留。 + 本次新文件整理成功后替换所选旧文件。剧集只替换成功对应的季集,其余保留。

) : null} diff --git a/apps/web/app/components/episode-mapping/model.ts b/apps/web/app/components/episode-mapping/model.ts index d3062756..ca7a743a 100644 --- a/apps/web/app/components/episode-mapping/model.ts +++ b/apps/web/app/components/episode-mapping/model.ts @@ -45,7 +45,7 @@ export const VALIDATION: Record同步 {pv.assetLocations} 条文件位置,写一条整理记录。 ) : null} {pv.bindings.length > 0 ? ( - 这是作品或季的绑定目录。改名后旧绑定标为已替代,之后入库用新目录。 + 这是作品或季的绑定目录。改名后旧绑定标为已替代,之后整理用新目录。 ) : null} ) : null} @@ -629,7 +629,7 @@ export function TransferDialog({ 冲突 {conflicts.length}(跳过,不覆盖) ) : null} {plan.pairs.some((p) => p.registered) ? ( - 含已入库文件,执行后同步位置 + 含已整理文件,执行后同步位置 ) : null} {hnrBlocked ? ( @@ -790,7 +790,7 @@ export function DeleteDialog({ {single ? `删除 ${single}?` : `删除 ${items.length} 项?`} - 已检查做种任务、已入库文件和路径绑定。下载器里的任务不受影响。 + 已检查做种任务、已整理文件和路径绑定。下载器里的任务不受影响。
{check.isPending ? ( @@ -837,7 +837,7 @@ export function DeleteDialog({

))} {c.assets.length ? ( -

已入库文件 {c.assets.length} 个(删除后从媒体库移除,已满足的收录版本退回待处理)

+

已整理文件 {c.assets.length} 个(删除后从媒体库移除,已满足的收录版本退回待处理)

) : null} {c.bindings.map((bd) => (

@@ -869,7 +869,7 @@ export function DeleteDialog({ 解除路径绑定 - 绑定标为已替代,该作品下次入库重新选目录。 + 绑定标为已替代,该作品下次整理重新选目录。 @@ -1139,7 +1139,7 @@ export function ScrapeDialog({ items, root, onClose }: { items: FileEntry[]; roo 刮削{single ? ` · ${single.name}` : ` · ${items.length} 项`} - 按路径识别作品,在所在目录写 NFO 和图片,Emby、Jellyfin、Kodi 直接读取。没入库的也能刮削。 + 按路径识别作品,在所在目录写 NFO 和图片,Emby、Jellyfin、Kodi 直接读取。没整理的也能刮削。 {!started ? ( diff --git a/apps/web/app/components/files/file-detail.tsx b/apps/web/app/components/files/file-detail.tsx index d1825fd9..7916a78e 100644 --- a/apps/web/app/components/files/file-detail.tsx +++ b/apps/web/app/components/files/file-detail.tsx @@ -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({ {e.asset ? ( - + { 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(); }); diff --git a/apps/web/app/components/files/model.ts b/apps/web/app/components/files/model.ts index 68c4428f..ce7902f6 100644 --- a/apps/web/app/components/files/model.ts +++ b/apps/web/app/components/files/model.ts @@ -26,7 +26,7 @@ export function entryStatusView(e: Pick): string | null { - return s.inLibrary > 0 ? `已入库 ${s.inLibrary}/${s.episodeCount}` : null; + return s.inLibrary > 0 ? `已整理 ${s.inLibrary}/${s.episodeCount}` : null; } const pad = (n: number) => String(n).padStart(2, "0"); @@ -63,5 +63,5 @@ export function originText( /** 切换确认的说明:改的是作品设置,影响季表、集数映射、订阅与刮削 */ export function switchDescription(target: string): string { - return `作品改按「${target}」分季:季与集按 TMDB 原季集迁到新位置,已入库文件跟着走;集数映射、订阅和刮削都按新季集,已绑定的资源会重新换算。之后可以再切回来。`; + return `作品改按「${target}」分季:季与集按 TMDB 原季集迁到新位置,已整理文件跟着走;集数映射、订阅和刮削都按新季集,已绑定的资源会重新换算。之后可以再切回来。`; } diff --git a/apps/web/app/components/library/episode-structure.test.ts b/apps/web/app/components/library/episode-structure.test.ts index 268cd437..c0892e63 100644 --- a/apps/web/app/components/library/episode-structure.test.ts +++ b/apps/web/app/components/library/episode-structure.test.ts @@ -110,7 +110,7 @@ describe("季集结构:纯函数", () => { it("季卡片文案与原季集对照", () => { expect(seasonLine({ airDate: "2024-07-07", episodeCount: 13 })).toBe("2024 · 13 集"); expect(inLibraryText({ inLibrary: 0, episodeCount: 13 })).toBeNull(); - expect(inLibraryText({ inLibrary: 3, episodeCount: 13 })).toBe("已入库 3/13"); + expect(inLibraryText({ inLibrary: 3, episodeCount: 13 })).toBe("已整理 3/13"); expect(originText(2, { episodeNumber: 2, tmdbSeason: 1, tmdbEpisode: 14 })).toBe("原 S01E14"); expect(originText(1, { episodeNumber: 2, tmdbSeason: 1, tmdbEpisode: 2 })).toBeNull(); }); @@ -131,14 +131,14 @@ describe("季集结构:组件", () => { expect(html).toContain('aria-label="当前"'); }); - it("季卡片:季名、首播年 · 集数、已入库 x/y,选中的高亮", () => { + it("季卡片:季名、首播年 · 集数、已整理 x/y,选中的高亮", () => { const html = renderToStaticMarkup( createElement(SeasonCardGrid, { seasons: structure.seasons, selected: 2, onPick: () => {} }), ); expect(html).toContain("第一部"); expect(html).toContain("2024 · 12 集"); - expect(html).toContain("已入库 1/13"); - expect(html).not.toContain("已入库 0/12"); + expect(html).toContain("已整理 1/13"); + expect(html).not.toContain("已整理 0/12"); expect(html).toMatch(/aria-pressed="true"[^>]*class="[^"]*pill-selected/); }); diff --git a/apps/web/app/components/library/episode-structure.tsx b/apps/web/app/components/library/episode-structure.tsx index ef0473cf..653a5ca8 100644 --- a/apps/web/app/components/library/episode-structure.tsx +++ b/apps/web/app/components/library/episode-structure.tsx @@ -141,7 +141,7 @@ export function StructurePreview({ seasons }: { seasons: EpisodeStructureSeason[ overview: null, summary: ( = s.episodeCount ? "success" : "neutral"}> - 已入库 {s.inLibrary}/{s.episodeCount} + 已整理 {s.inLibrary}/{s.episodeCount} ), }} @@ -171,7 +171,7 @@ export function StructurePreview({ seasons }: { seasons: EpisodeStructureSeason[ runtime: null, stillPath: null, voteAverage: null, - status: e.inLibrary ? { label: "已入库", tone: "success" } : { label: "未入库", tone: "neutral" }, + status: e.inLibrary ? { label: "已整理", tone: "success" } : { label: "未整理", tone: "neutral" }, extra: originText(s.seasonNumber, e) ? (

{originText(s.seasonNumber, e)} @@ -228,7 +228,7 @@ export function EpisodeStructureSwitcher({ entityId, children }: { entityId: str

- 预览「{target?.label ?? DEFAULT_STRUCTURE_LABEL}」的分季,已入库按 TMDB 原季集对照。 + 预览「{target?.label ?? DEFAULT_STRUCTURE_LABEL}」的分季,已整理按 TMDB 原季集对照。

@@ -207,7 +207,7 @@ export function StepOptions({
-
+
刷新元数据 @@ -216,7 +216,7 @@ export function StepOptions({ set({ refreshMetadata: v })} - aria-label="入库后刷新元数据" + aria-label="整理后刷新元数据" />

diff --git a/apps/web/app/components/organize-wizard/step-preview.tsx b/apps/web/app/components/organize-wizard/step-preview.tsx index 303dd6b7..2007ebcc 100644 --- a/apps/web/app/components/organize-wizard/step-preview.tsx +++ b/apps/web/app/components/organize-wizard/step-preview.tsx @@ -112,7 +112,7 @@ function FileLine({ f, roots, nested }: { f: GroupFile; roots: FileRoot[]; neste ) : f.target === f.source ? ( 原地登记 ) : !f.target ? ( - 不入库 + 不整理 ) : null; return (

  • diff --git a/apps/web/app/components/organize/delete-records-dialog.tsx b/apps/web/app/components/organize/delete-records-dialog.tsx index 0bfb6f6a..4f63aadb 100644 --- a/apps/web/app/components/organize/delete-records-dialog.tsx +++ b/apps/web/app/components/organize/delete-records-dialog.tsx @@ -138,7 +138,7 @@ function Summary({ {files.length ? (

    {files.join("、")}({formatBytes(plan.bytes, 1)})会移入回收站,可以在回收站还原。 - {plan.assets ? `其中 ${plan.assets} 个是已入库文件,会从媒体库移除。` : ""} + {plan.assets ? `其中 ${plan.assets} 个是已整理文件,会从媒体库移除。` : ""}

    ) : (

    {withFiles ? "没有找到还在的文件,只删记录。" : "只删记录,文件不动。"}

    diff --git a/apps/web/app/components/organize/record-attention.test.ts b/apps/web/app/components/organize/record-attention.test.ts index c8a2f737..a066015f 100644 --- a/apps/web/app/components/organize/record-attention.test.ts +++ b/apps/web/app/components/organize/record-attention.test.ts @@ -26,7 +26,7 @@ const decision = (over: Partial> = {}) { key: "candidate_0", label: "Foo (2019)", input: { candidate: { mediaEntityId: R } } }, { key: "select_entity", label: "选择作品(本地)", input: { requires: "mediaEntityId" } }, { key: "select_tmdb", label: "选择作品(TMDB)", input: { requires: "tmdb" } }, - { key: "provisional", label: "作为临时作品入库", input: {} }, + { key: "provisional", label: "作为临时作品整理", input: {} }, { key: "dismiss", label: "忽略" }, ], agentRunId: null, @@ -54,7 +54,7 @@ describe("整理记录行内处理", () => { for (const t of ["指定作品", "让智能体识别", "重新整理", "忽略", "Foo (2019)"]) expect(out).toContain(t); // 「选择作品(本地 / TMDB)」并进「指定作品」,不单列;临时作品不在行内 expect(out).not.toContain("选择作品(本地)"); - expect(out).not.toContain("作为临时作品入库"); + expect(out).not.toContain("作为临时作品整理"); }); it("智能体识别中:显示进度与会话入口,不再给指定 / 识别按钮", () => { diff --git a/apps/web/app/components/organize/record-parts.test.ts b/apps/web/app/components/organize/record-parts.test.ts index 7cc3a789..7bb595e5 100644 --- a/apps/web/app/components/organize/record-parts.test.ts +++ b/apps/web/app/components/organize/record-parts.test.ts @@ -89,7 +89,7 @@ describe("整理记录列表:整理方式、分类、分组", () => { "移动", "复制", "硬链接", - "原地入库", + "原地整理", ]); }); diff --git a/apps/web/app/components/search/search-results-ui.test.ts b/apps/web/app/components/search/search-results-ui.test.ts index ae04c23b..dd1b620a 100644 --- a/apps/web/app/components/search/search-results-ui.test.ts +++ b/apps/web/app/components/search/search-results-ui.test.ts @@ -88,7 +88,7 @@ describe("库内状态文案", () => { it("未收录 / 已建档 / 已收录 / 正在下载;收录版本满足与缺失", () => { expect(inventoryBadge(inv({})).label).toBe("不在媒体库"); expect(inventoryBadge(inv({ state: "tracked" })).label).toBe("在媒体库 · 未下载"); - expect(inventoryBadge(inv({ state: "owned", versionCount: 2 })).label).toBe("已入库 · 2 个版本"); + expect(inventoryBadge(inv({ state: "owned", versionCount: 2 })).label).toBe("已整理 · 2 个版本"); expect(inventoryBadge(inv({ state: "downloading", downloadingCount: 1 })).label).toBe("正在下载 1 个"); expect( slotLine(inv({ state: "owned", slotTotal: 2, slotSatisfied: 1, missing: [{ slotId: ID, name: "2160p" }] })), diff --git a/apps/web/app/components/search/work-card.tsx b/apps/web/app/components/search/work-card.tsx index f862ec17..47527f97 100644 --- a/apps/web/app/components/search/work-card.tsx +++ b/apps/web/app/components/search/work-card.tsx @@ -37,7 +37,7 @@ export function inventoryBadge(inv: WorkInventory): { label: string; tone: Statu case "downloading": return { label: `正在下载 ${inv.downloadingCount} 个`, tone: "warning" }; case "owned": - return { label: `已入库 · ${inv.versionCount} 个版本`, tone: "success" }; + return { label: `已整理 · ${inv.versionCount} 个版本`, tone: "success" }; default: return { label: "在媒体库 · 未下载", tone: "neutral" }; } diff --git a/apps/web/app/components/subscriptions/actions.tsx b/apps/web/app/components/subscriptions/actions.tsx index 5d86801b..69408497 100644 --- a/apps/web/app/components/subscriptions/actions.tsx +++ b/apps/web/app/components/subscriptions/actions.tsx @@ -186,7 +186,7 @@ export function SubscriptionMenu({ open={confirmReset} onOpenChange={setConfirmReset} title="重置这个订阅的进度?" - description="取消还没提交、或下载任务已不在的计划,清掉延后记录,然后重新评估。仍在下载的任务、已入库文件和总集数保留。" + description="取消还没提交、或下载任务已不在的计划,清掉延后记录,然后重新评估。仍在下载的任务、已整理文件和总集数保留。" confirmLabel="重置" onConfirm={() => ops.reset(sub.id).catch((e) => { @@ -216,7 +216,7 @@ export function DeleteSubscriptionsDialog({ open={open} onOpenChange={onOpenChange} title={ids.length > 1 ? `删除 ${ids.length} 个订阅?` : "删除这个订阅?"} - description="不再搜索和追更。已入库文件、收录版本和下载记录保留,可在订阅历史里重新订阅。" + description="不再搜索和追更。已整理文件、收录版本和下载记录保留,可在订阅历史里重新订阅。" confirmLabel="删除" destructive onConfirm={() => diff --git a/apps/web/app/components/subscriptions/model.ts b/apps/web/app/components/subscriptions/model.ts index 005062b8..44bfdc9e 100644 --- a/apps/web/app/components/subscriptions/model.ts +++ b/apps/web/app/components/subscriptions/model.ts @@ -65,7 +65,7 @@ export function slotBadge(s: SubscriptionSlotSummary): ToneLabel { if (s.inflight > 0) return { label: `在途 ${s.inflight}`, tone: "neutral" }; if (s.missing > 0) return { label: `缺 ${s.missing}`, tone: "destructive" }; if (s.total !== null && s.total > 0 && s.have >= s.total) return { label: "已齐", tone: "success" }; - return { label: s.have > 0 ? `已入库 ${s.have}` : "未开始", tone: "neutral" }; + return { label: s.have > 0 ? `已整理 ${s.have}` : "未开始", tone: "neutral" }; } /** 名称列表折叠:≤max 个名 + "+N";空 = emptyLabel */ @@ -121,7 +121,7 @@ export function cellKind(c: CoverageCell): CellKind { } export const CELL_LABEL: Record = { - have: "已入库", + have: "已整理", upgradable: "可升级", inflight: "在途", deferred: "延后", @@ -429,9 +429,9 @@ export function draftToParams( // ── 日历(设计 §4)── export const CALENDAR_STATE_LABEL: Record = { - have: "已入库", - partial: "部分入库", - missing: "未入库", + have: "已整理", + partial: "部分整理", + missing: "未整理", upcoming: "未播出", }; diff --git a/apps/web/app/components/subscriptions/overview-item.tsx b/apps/web/app/components/subscriptions/overview-item.tsx index b2d59b31..0c682c30 100644 --- a/apps/web/app/components/subscriptions/overview-item.tsx +++ b/apps/web/app/components/subscriptions/overview-item.tsx @@ -57,7 +57,7 @@ export function ProgressBlock({ x, className }: { x: Pick {unknown ? null : ( <> diff --git a/apps/web/app/components/subscriptions/slot-panel.tsx b/apps/web/app/components/subscriptions/slot-panel.tsx index 9d2da3f9..59d77a94 100644 --- a/apps/web/app/components/subscriptions/slot-panel.tsx +++ b/apps/web/app/components/subscriptions/slot-panel.tsx @@ -110,7 +110,7 @@ export function SlotPanel({ disabled={setOrder.isPending} renderExtra={(r, i) => ( - 已入库 {r.summary.have} + 已整理 {r.summary.have} 缺 {r.summary.missing} 在途 {r.summary.inflight} {i === 0 ? null : {r.autoFill ? "自动补全" : "只登记缺失"}} diff --git a/apps/web/app/components/subscriptions/subscription-form.tsx b/apps/web/app/components/subscriptions/subscription-form.tsx index e9286ae4..72e27b3c 100644 --- a/apps/web/app/components/subscriptions/subscription-form.tsx +++ b/apps/web/app/components/subscriptions/subscription-form.tsx @@ -694,7 +694,7 @@ export function SubscriptionFormDialog({ void targets.refetch()} /> ) : !list.length ? ( - + ) : (
    setTab(v as "upload" | "online")}> diff --git a/apps/web/app/lib/labels.ts b/apps/web/app/lib/labels.ts index d5ceae79..258f83c4 100644 --- a/apps/web/app/lib/labels.ts +++ b/apps/web/app/lib/labels.ts @@ -30,8 +30,8 @@ const DOWNLOAD: Record = { paused: { label: "已暂停", tone: "warning" }, stalled: { label: "无进展", tone: "warning" }, completed: { label: "下载完成", tone: "success" }, - importing: { label: "入库中", tone: "neutral" }, - imported: { label: "已入库", tone: "success" }, + importing: { label: "整理中", tone: "neutral" }, + imported: { label: "已整理", tone: "success" }, failed: { label: "失败", tone: "destructive" }, removed: { label: "已移除", tone: "neutral" }, missing: { label: "丢失", tone: "destructive" }, diff --git a/apps/web/app/routes/console/files.tsx b/apps/web/app/routes/console/files.tsx index 62c718e3..76ef9bda 100644 --- a/apps/web/app/routes/console/files.tsx +++ b/apps/web/app/routes/console/files.tsx @@ -717,7 +717,7 @@ export default function FilesPage() { key: "scrape", label: "刷新元数据", icon: RefreshCw, - disabled: selected.every((e) => e.asset) ? null : "只对已入库的文件", + disabled: selected.every((e) => e.asset) ? null : "只对已整理的文件", onSelect: () => act("scrape", selected), }); items.push({ diff --git a/apps/web/app/routes/console/library.$id.tsx b/apps/web/app/routes/console/library.$id.tsx index b4f23a5c..86d5fdc1 100644 --- a/apps/web/app/routes/console/library.$id.tsx +++ b/apps/web/app/routes/console/library.$id.tsx @@ -141,7 +141,7 @@ function PathsPanel({ detail }: { detail: LibraryDetail }) { @@ -608,7 +608,7 @@ function UnitsPanel({ entity, detail }: { entity: ReturnType covered.has(u.id) ? ( - 已入库 + 已整理 ) : ( — ), @@ -711,10 +711,10 @@ function EpisodesPanel({ detail, units }: { detail: LibraryDetail; units: Conten if (hit) return hit; const season = seasonUnitOf(u.seasonNumber!); if (covered.has(u.id) || (season && covered.has(season.id))) - return { label: "已入库", tone: "success", have: true }; + return { label: "已整理", tone: "success", have: true }; const air = finalOf(u, "airDate")?.value ?? u.airDate; if (typeof air === "string" && air > today()) return { label: "未播出", tone: "neutral", have: false }; - return { label: sub ? "缺失" : "未入库", tone: sub ? "destructive" : "neutral", have: false }; + return { label: sub ? "缺失" : "未整理", tone: sub ? "destructive" : "neutral", have: false }; }; const haveIn = (n: number) => episodes.filter((u) => u.seasonNumber === n && statusOf(u)?.have).length; const initial = @@ -747,7 +747,7 @@ function EpisodesPanel({ detail, units }: { detail: LibraryDetail; units: Conten description={ sub ? "库内状态按订阅的覆盖矩阵;标题与简介按语言回退链取值" - : "没有订阅时只看是否已入库;标题与简介按语言回退链取值" + : "没有订阅时只看是否已整理;标题与简介按语言回退链取值" } actions={