feat(file-manager): v2 backend gaps — TMDB candidate entities, min size, on-existing, naming source (W9-H)

- G1 createEntityFromTmdbCandidate (sources-identity service): entity + accepted
  manual external identity + season/episode units, idempotent per TMDB id;
  POST /files/entity-from-candidate and organize items with `external`
- G2 minSizeBytes for organize (excluded below_min_size) and identify
  (skipped + excludedBySize)
- G3 onExisting passed to planImport; dryRun marks each file
  (same/skip/replace/conflict); replace = explicit grant
- G4 naming template|keep; planImport namingMode/namingSource, frozen
  plan.naming {mode, templateSource, templateVersion}; targetSegments
- G5 identify prior-record hints, GET /files/record-sources, organize
  refreshMetadata, POST /files/scrape-batch (dedupe by entity)
- G8 GET /files/tree (parent, subdirs hasChildren, video/registered counts)
- G9 POST /files/suggest-name returns 501 until the naming engine lands

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-28 15:08:17 +08:00
1 parent 88bbed409c
commit 13132e7ad8
12 files changed
+977 -36

No files matched your search

+12 -1
View File
@@ -6,6 +6,7 @@ import { type AuthEnv, requireAdminSession, requireScope } from "../../http/auth
import { errorBody } from "../../http/errors.ts";
import { PathGuardError } from "../acquisition-organize/services/organize-guard.ts";
import type { ModuleApp } from "../types.ts";
import { entityFromCandidate } from "./candidate.ts";
import { FilesError, type FmDeps, fsErrorToFiles } from "./common.ts";
import { downloadFile } from "./download.ts";
import { identify } from "./identify.ts";
@@ -13,10 +14,12 @@ import { idempotent } from "./ledger.ts";
import { listDir, listRoots, statEntry } from "./list.ts";
import { mkdirIn, renameEntry } from "./mutate.ts";
import { organizeFiles } from "./organize.ts";
import { probeFiles, scrape } from "./probe.ts";
import { probeFiles, scrape, scrapeBatch } from "./probe.ts";
import { findRecords } from "./records.ts";
import { suggestName } from "./suggest-name.ts";
import { transfer } from "./transfer.ts";
import { deleteFiles, listTrash, purgeTrash, restoreTrash } from "./trash.ts";
import { recordSources, treeOf } from "./tree.ts";
// /files 路由:scope 由 contracts 端点定义(读 organize.read / 写 organize.execute),处理器内再按授权矩阵细分。
// FilesError → 信封 + 对应状态(根离线 503,message 以 `<reason>: ` 开头)。
@@ -107,4 +110,12 @@ export function registerFileRoutes(app: ModuleApp, d: FmDeps) {
mount(app, F.probe, async (_c, { body }) => probeFiles(d, body));
mount(app, F.records, async (_c, { query }) => findRecords(d, query));
mount(app, F.download, async (c, { query }) => downloadFile(d, c.get("principal"), query), true);
// W9-H 文件管理 v2
mount(app, F.entityFromCandidate, async (c, { body }) => entityFromCandidate(d, c.get("principal"), body));
mount(app, F.scrapeBatch, async (c, { body }) =>
idem(d, c, "scrape_batch", body, () => scrapeBatch(d, c.get("principal"), body)),
);
mount(app, F.tree, async (_c, { query }) => treeOf(d, query));
mount(app, F.recordSources, async (_c, { query }) => recordSources(d, query.recordId));
mount(app, F.suggestName, async (_c, { body }) => suggestName(d, body));
}