feat(files): wide file manager layout and basic previews (FM-2)
- Files page uses a wide layout (route handle layout:"wide"): no max width, full-height directory tree docked next to the sidebar, resizable (200-520px, remembered, double-click resets) and collapsible; mobile keeps the tree in a drawer. - GET /files/preview (admin console session only, same path guards as download): text/NFO with encoding detection (BOM/UTF-16/UTF-8/GB18030/Big5), subtitles first 200 cues (SRT/VTT/ASS/SSA, PGS timings), .torrent file list/trackers (passkey masked)/infohash, image dimensions. Reads at most 1 MiB of text; .torrent capped at 4 MiB. - Download also allows text files, .torrent and avif/gif. - Research notes in docs/design/file-preview-research.md. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
3add4bab41
commit
289e8b297a
20 files changed
+1294
-159
No files matched your search
@@ -4,6 +4,7 @@ import {
|
||||
applyIdentifyCompleted,
|
||||
clickSelect,
|
||||
collapseCrumbs,
|
||||
cueTime,
|
||||
deleteBlockText,
|
||||
emptySelection,
|
||||
entryStatusView,
|
||||
@@ -18,6 +19,8 @@ import {
|
||||
opApplies,
|
||||
opDisabledReason,
|
||||
parseEpisodes,
|
||||
prettyJson,
|
||||
previewKindOf,
|
||||
pruneSelection,
|
||||
selectAll,
|
||||
shiftEpisodes,
|
||||
@@ -329,3 +332,20 @@ describe("识别远端回填(S-7)", () => {
|
||||
expect(f.items[0]?.warnings).toEqual(["远端查询失败,只有本地结果:超时"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("预览(FM-2)", () => {
|
||||
it("按扩展名分预览类型,目录与未知扩展名不预览", () => {
|
||||
expect(previewKindOf({ type: "file", ext: "NFO" })).toBe("text");
|
||||
expect(previewKindOf({ type: "file", ext: "ass" })).toBe("subtitle");
|
||||
expect(previewKindOf({ type: "file", ext: "torrent" })).toBe("torrent");
|
||||
expect(previewKindOf({ type: "file", ext: "avif" })).toBe("image");
|
||||
expect(previewKindOf({ type: "file", ext: "mkv" })).toBeNull();
|
||||
expect(previewKindOf({ type: "dir", ext: null })).toBeNull();
|
||||
});
|
||||
it("时间轴与 JSON 美化", () => {
|
||||
expect(cueTime(3_723_045)).toBe("01:02:03.045");
|
||||
expect(prettyJson('{"a":1}', false)).toBe('{\n "a": 1\n}');
|
||||
expect(prettyJson('{"a":', false)).toBe('{"a":');
|
||||
expect(prettyJson('{"a":1}', true)).toBe('{"a":1}');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user