- 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]>
38 lines
3.9 KiB
Markdown
38 lines
3.9 KiB
Markdown
# 文件管理基础预览调研(FM-2)
|
||
|
||
2026-09-29。范围:文件管理详情抽屉里除视频播放以外的预览。前提:单容器 4C/8G;前端库只能来自 npm;所有读取走 `resolveIn` + `recheck`(realpath 在登记目录内、符号链接目标也须在内),仅管理员控制台会话。
|
||
|
||
**核实**:镜像 `/usr/local/bin` 只有 `ffprobe` 9.0.2(141 MB,取自 `mwader/static-ffmpeg:9.0.2`),**没有 ffmpeg**。同一镜像里的 ffmpeg 静态二进制也是 141 MB,加进来要改 Dockerfile 和编译参数 `--allow-run`。
|
||
|
||
**MP 对照**:MoviePilot 文件管理只有图片预览(`/storage/image` 取原图转 blob),另有识别和刮削,没有文本、字幕和种子预览。
|
||
|
||
## 逐项结论
|
||
|
||
| 类别 | 用户价值 | 实现 | 安全 | 工作量 | 建议 |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| 图片 jpg/png/webp/avif/gif | 高:核对海报、背景是否刮对 | 原图经 `/files/download?inline` 显示(≤20 MB,`loading=lazy`);服务端读文件头回宽高 | SVG 不内联(可带脚本);`nosniff` + `sandbox` CSP | S | **已做** |
|
||
| 图片缩略图 | 中:列表网格、海报墙 | 需 ffmpeg(+141 MB)或 sharp/libvips(npm 原生模块,`deno compile` 嵌入风险)或 wasm 解码(内存峰值高) | 解码炸弹(超大分辨率):限像素数 | M | 后做,等有网格视图再定 |
|
||
| 文本 nfo/txt/log/md/json/xml/yaml | 高:看 NFO、发布说明、日志 | 服务端读前 1 MB,编码探测 BOM → UTF-16 → UTF-8 → GB18030/Big5 择优 → Latin-1;json 美化 | 一律按纯文本渲染(React 转义),md 不渲染 HTML | S | **已做** |
|
||
| Markdown 渲染 | 低 | markdown-it + DOMPurify(约 60 KB) | 必须消毒 | S | 不做,纯文本够用 |
|
||
| 字幕 srt/vtt/ass/ssa | 高:确认语言、编码、时间轴对不对 | 服务端解析前 1 MB,按时间排序回前 200 条;ASS 取 `Title`、去覆写标签 | 纯文本输出 | S | **已做** |
|
||
| 字幕 sup(PGS) | 中 | 解析段头,只列起止时间 | 只读段头 | S | **已做**;渲染图形不做 |
|
||
| 音频 flac/mp3 试听 | 低:库里音频多是音轨附件 | 浏览器 `<audio>` + HTTP Range;需给下载接口加 Range 与音频类型放行 | 大文件流式,不经内存 | S | 后做 |
|
||
| PDF | 很低:媒体库几乎没有 | `<iframe>` 内嵌(浏览器自带);pdf.js 约 1 MB 不值 | 内嵌需同源 + sandbox | S | 不做 |
|
||
| 压缩包列表 zip/rar/7z | 中:字幕包、原盘分卷 | zip 纯 JS 读中央目录即可;rar/7z 需 `unrar`/`7z` 子进程或 wasm(libarchive.js 约 1 MB) | 只读目录不解压,不会触发压缩炸弹;条目数设上限;文件名当纯文本 | zip S / rar·7z M | zip 后做,rar/7z 视需求 |
|
||
| .torrent | 高:核对资源内容、hash、是否私有 | 复用 `@umt/adapters` 的 `parseTorrent`;≤4 MB;回前 500 个文件与 tracker | tracker 里的 passkey 服务端打码 | S | **已做** |
|
||
| 视频规格 | 高 | 已有「探测」(ffprobe 摘要,缓存 24 小时) | — | — | 已有 |
|
||
| 视频关键帧截图条 | 中:确认片源、是否黑边/HDR 发灰 | 需 ffmpeg;每次 4–6 帧、限时、结果缓存到 DATA_DIR | 并发与 CPU 上限(4C);超时 SIGKILL | M | 后做,和缩略图一起决定是否加 ffmpeg |
|
||
| ISO/BDMV 结构识别 | 中:原盘目录显示主片、时长 | BDMV 目录读 `index.bdmv`/`MPLS` 找最长播放列表;ISO 需 UDF 解析 | 只读 | M(BDMV)/ L(ISO) | 后做,先做 BDMV 目录 |
|
||
|
||
## 已实现(本分支)
|
||
|
||
- `GET /files/preview?root&path`:返回 `text / subtitle / torrent / image` 四种结构,只回 JSON,不回原始内容;扩展名白名单与前端同表。上限:文本和字幕读前 1 MB,图片读头 512 KB,.torrent ≤4 MB,超过回 413。
|
||
- 下载接口同步放行文本类、.torrent、avif/gif;视频仍不经浏览器。
|
||
- 预览不写审计(只读、量大),下载仍写。
|
||
- 前端:详情抽屉「预览」节;格式、编码、hash、分块等收进「技术信息」。
|
||
|
||
## 需要决定
|
||
|
||
1. 是否在镜像里加 ffmpeg(+141 MB):决定缩略图、截图条两项。
|
||
2. 音频试听要给下载接口加 Range,是否放开音频类型。
|