feat(files): W5-A2 move/copy via planImport, organize overrides, delete records, download
- /files/move|copy go through planImport's new `transfer` variant (keep names, directory expanded to per-file plan) → organization_record + verifyAndImport/executeRecord: per-file ledger resumable, fsproxy, cross-volume directory move = per-file copy→verify→delete then remove empty source dirs; shared plan store + plan_stale; asset_location follows per file, path_binding revised when a whole directory moved (finalizeTransfer); request waits up to FILES_TRANSFER_WAIT_SEC, else executed.pending - /files/organize per-item overrides take effect: season/episodes (domain planOrganize overrides), contentUnitId coverage, targetDir (no binding), operation, slotId (satisfied after verify); warnings only for inapplicable overrides - delete/trash/restore write organization_record (action trash|delete|restore, file-level results; migration 0026) - GET /files/download (admin session, nfo/subtitle/image, size cap, streamed, audited) - GET /files/records?ids|planIds for the organize page - fs race errors map to 503/404/403/400 instead of 500 - runbook updated Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
3641ab9573
commit
36aa99b8aa
25 files changed
+1766
-271
No files matched your search
@@ -270,6 +270,44 @@ describe("W4-E4:字幕 .default 与 latest 旧版本判定口径(对照 MP)", ()
|
||||
expect(subs.some((n) => n?.endsWith(".eng.srt"))).toBe(true);
|
||||
});
|
||||
|
||||
it("逐文件季/集覆写:优先于文件名解析,目录前缀对其下文件生效,电影忽略", () => {
|
||||
const D = "/dl/Weird.Name";
|
||||
const plan = planOrganize({
|
||||
operation: "copy",
|
||||
mediaType: "tv",
|
||||
sourceRoot: D,
|
||||
files: [
|
||||
{ path: `${D}/weird-a.mkv`, size: GiB },
|
||||
{ path: `${D}/weird-a.chs.srt`, size: 1000 },
|
||||
{ path: `${D}/Show.S01E05.mkv`, size: GiB },
|
||||
{ path: `${D}/sub/Show.S01E07.mkv`, size: GiB },
|
||||
],
|
||||
entity: { title: "剧", year: 2020 },
|
||||
target: { seasonDirs: { 1: "/lib/剧/Season 1", 2: "/lib/剧/Season 2" } },
|
||||
overrides: {
|
||||
[`${D}/weird-a.mkv`]: { season: 2, episodes: { start: 3, end: 4 } },
|
||||
[`${D}/Show.S01E05.mkv`]: { episodes: { start: 6, end: 6 } },
|
||||
[`${D}/sub`]: { season: 2 },
|
||||
},
|
||||
});
|
||||
expect(plan.files.map((f) => f.dst)).toEqual([
|
||||
"/lib/剧/Season 2/剧 - S02E03-E04.mkv",
|
||||
"/lib/剧/Season 1/剧 - S01E06.mkv",
|
||||
"/lib/剧/Season 2/剧 - S02E07.mkv",
|
||||
"/lib/剧/Season 2/剧 - S02E03-E04.chi.zh-cn.srt",
|
||||
]);
|
||||
expect(plan.files[0]).toMatchObject({ season: 2, episodes: { start: 3, end: 4 } });
|
||||
const movie = planOrganize({
|
||||
operation: "copy",
|
||||
mediaType: "movie",
|
||||
files: [{ path: "/dl/M.2020.mkv", size: GiB }],
|
||||
entity: { title: "M", year: 2020 },
|
||||
target: { movieDir: "/lib/M (2020)" },
|
||||
overrides: { "/dl/M.2020.mkv": { season: 3 } },
|
||||
});
|
||||
expect(movie.files[0]!.dst).toBe("/lib/M (2020)/M (2020).mkv");
|
||||
});
|
||||
|
||||
it("findOtherVersions:同季同集同 Part、只看视频扩展名", () => {
|
||||
const sib = [
|
||||
"/lib/S01/Show - S01E01 - 1080p.mkv",
|
||||
|
||||
Reference in new issue
Block a user