docs(storage): Alist 使用与真机验收 runbook,整理 / 文件管理 / MP 对照更新
- 新增 docs/runbook/storage-alist.md:登记、行为要点、临时 OpenList 容器真机验收步骤、排查 - organize.md 加「Alist / OpenList 存储」;moviepilot-filemanager.md 末节改为已做; v3 对照保留 rclone 不照抄、网盘改为 Alist 已接;file-manager-v2 存储切换与目的存储两行更新 - 设计文档补实现落点与偏离;矩阵测试补原地整理与目标已存在替换 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
fed2202e74
commit
adbb9b59a0
7 files changed
+225
-8
No files matched your search
@@ -32,7 +32,7 @@
|
||||
|
||||
| # | MP 功能点 | 我们 | v2 决定 |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | 存储切换菜单(local/115/阿里/Alist/SMB/rclone) | ≠ 左栏按"媒体库/下载目录"列登记目录 | 改:登记目录 = 库根 + 下载器路径映射,不接网盘(REQ §7.1.1) |
|
||||
| 1 | 存储切换菜单(local/115/阿里/Alist/SMB/rclone) | ≠ 左栏按"媒体库/下载目录"列登记目录 | 改:登记目录 = 库根 + 下载器路径映射;2026-10-07 起多一组「Alist 存储」(见 `storage-alist.md`),115 / SMB / rclone 不接 |
|
||||
| 2 | 初始位置 = 下载目录公共前缀,记住上次存储 | ≠ 默认第一个在线库根 | 改:上次位置(localStorage)> 第一个下载目录 > 第一个库根。整理从下载目录开始 |
|
||||
| 3 | 面包屑(桌面全段,移动端只显示存储名) | ✓ 可拖放 | 照抄 + 移动端折叠成"…/父/当前" |
|
||||
| 4 | "上一级"按钮 | ✗ 只有 Backspace | 照抄:工具栏加"上一级" |
|
||||
@@ -63,7 +63,7 @@
|
||||
| 29 | 递归重命名目录内媒体(一个失败即中止) | ✗ | 改:放进向导"原地按模板改名"模式,先预览(阶段 3) |
|
||||
| 30 | 删除确认"是否确认删除{name}?" | ✓+ 回收站 + 引用检查 | 保留 |
|
||||
| 31 | 新建目录对话框 | ✓+ 名称校验 | 保留 |
|
||||
| 32 | 整理:目的存储 | — | 不做:只有本机路径 |
|
||||
| 32 | 整理:目的存储 | ✓ | 媒体库目录可登记在 Alist 上,选目标库根即选存储(见 `storage-alist.md`) |
|
||||
| 33 | 整理方式 copy/move/link/softlink | ≠ 复制/移动 | 保留两项;硬链接灰显"W5" |
|
||||
| 34 | 目的路径(自动 / 目录配置下拉 / 手输) | ≠ 目标库根(契约有 targetDir,界面没有) | 改:自动 / 指定库根 / 指定目录(§6.2) |
|
||||
| 35 | 按源路径推荐目标(`/manual/target-path`) | ≠ 按作品绑定或类型 | 保留我们的:已绑定作品沿用原目录 |
|
||||
|
||||
@@ -119,7 +119,7 @@ new AlistClient({ baseUrl, auth: {kind:"token",token} | {kind:"password",usernam
|
||||
## 3. 存储抽象(服务端)
|
||||
|
||||
- 表 `storage_instance`(迁移 0090):`id, name, kind('alist'), flavor('alist'|'openlist'), base_url, root_path, auth_kind('token'|'password'|'guest'), username, secret_ref, path_password_ref, enabled, options jsonb, health_status, last_health_at, health_detail, version_info, created_at, updated_at`。凭据走现有 `secret` 表(`SecretPurpose` 加 `storage_credential`),API 只写不读(与下载器 / 媒体服务器同语义:省略或空串不变、null 清除)。
|
||||
- `options`:`qps`(5)、`concurrency`(4)、`timeoutMs`(30000)、`idleTimeoutMs`(120000)、`taskTimeoutMs`(21600000)、`retries`(3)、`uploadAsTask`(false)、`snapshotMaxDepth`(5)、`snapshotCheckFolderModtime`(true,MP 本地缺省 true;OpenList 在 MP 里是开关、缺省关——我们缺省开并可关)。
|
||||
- `options`:`qps`(5)、`concurrency`(4)、`timeoutMs`(30000)、`idleTimeoutMs`(120000)、`taskTimeoutMs`(21600000)、`retries`(3)、`uploadAsTask`(false)、`snapshotMaxDepth`(5)、`snapshotCheckFolderModtime`(true,同 MP `OPENLIST_SNAPSHOT_CHECK_FOLDER_MODTIME` 缺省开,可关)。
|
||||
- `apps/server/src/storage/`:
|
||||
- `registry.ts`:按 id 取实例 + 解密凭据 → `AlistClient`(按 `updated_at` 缓存,配置一改就重建)。
|
||||
- `vpath.ts`:`/@alist/<id>/<path>` 编解码;`displayPath()` 给界面「存储名:/路径」。
|
||||
@@ -184,7 +184,7 @@ ffprobe(§7)判定没有视频流时,远端新文件同样 move 进 `.umt-
|
||||
|
||||
## 8. 目录监控(远端快照)
|
||||
|
||||
- 来源配置选 Alist 根 + 触发方式「目录快照」:`walkSource` 对远端走 `storage/snapshot.ts`:BFS 列目录,深度 ≤ `snapshotMaxDepth`(MP 5);`snapshotCheckFolderModtime` 开时,子目录 `modified` 不晚于上次扫描时间就沿用上次快照里该子树的文件(根目录每轮都列,用于发现删除,同 MP);列表失败的子树保留旧快照(MP「查询异常时保留基线」)。
|
||||
- 来源配置选 Alist 根 + 触发方式「目录快照」:`walkSource` 对远端走 `walkRemoteSource`(`file-manager/source-monitor.ts`):BFS 列目录,深度 ≤ `snapshotMaxDepth`(MP 5);`snapshotCheckFolderModtime` 开时,子目录 `modified` 不晚于上次扫描时间就沿用上次快照里该子树的文件(根目录每轮都列,用于发现删除,同 MP);列表失败的子树保留旧快照(MP「查询异常时保留基线」)。
|
||||
- 之后完全复用现有语义:首扫建基线不整理;新文件 / 变化文件需连续两次观察大小与修改时间一致才整理;结果按现有批次识别上限分批;失败写 `organize_source_snapshot.last_error`,保留旧快照。
|
||||
- 扫描间隔沿用来源配置 `intervalSec`(MP 按文件数自适应 `adjust_interval`;我们已有逐来源间隔,不再自适应)。
|
||||
- 按实例限速:快照的 list 走同一个令牌桶,不会打爆网盘。
|
||||
@@ -228,3 +228,27 @@ ffprobe(§7)判定没有视频流时,远端新文件同样 move 进 `.umt-
|
||||
- 前端:存储设置表单、文件管理存储切换。
|
||||
- 真机:`*.real.test.ts`,`UMT_ALIST_REAL_URL` / `UMT_ALIST_REAL_TOKEN` 等环境变量开启,缺省跳过;跑本地 → OpenList → 本地往返。
|
||||
- 真机验收(用户不提供真实 Alist,协调者自起 OpenList 容器):步骤见 `docs/runbook/storage-alist.md`;脚本 `scripts/alist-e2e.ts` 可对任意 base URL + 令牌跑往返与 Alist 内移动。
|
||||
|
||||
## 13. 实现落点(2026-10-07)
|
||||
|
||||
| 部分 | 文件 |
|
||||
| --- | --- |
|
||||
| 适配器 | `packages/adapters/src/alist/{client,errors,limiter,redact}.ts`;测试用模拟 `mock.ts`(导出 `@umt/adapters/alist-mock`) |
|
||||
| 存储注册表 / 虚拟路径 / vfs / 传输 / 远端探测 | `apps/server/src/storage/{registry,vpath,vfs,transfer,probe}.ts` |
|
||||
| 设置接口 | `apps/server/src/modules/auth-settings/storage-routes.ts`;契约 `packages/contracts/src/storage.ts` |
|
||||
| 文件管理 | `file-manager/common.ts`(`st:` 根、`resolveIn` 远端分支)、`list.ts`、`mutate.ts`、`trash.ts`、`transfer.ts`、`tree.ts`、`download.ts`、`preview.ts`、`upload.ts` |
|
||||
| 整理 | `organize-plan.ts`、`organize-exec.ts`(`transferFile` 远端分派)、`organize-transfer.ts`、`organize-finalize.ts`、`replacement.ts`、`organize-guard.ts`、`reconcile.ts` |
|
||||
| 刮削 / 目录监控 | `acquisition-organize/services/scrape.ts`(`atomicWrite` 远端上传)、`file-manager/source-monitor.ts`(`walkRemoteSource`) |
|
||||
| 健康 | `system/health.ts`(`storage_instance` 挂载项) |
|
||||
| 前端 | `components/settings/storages.tsx`、`instances.tsx`(库根选存储)、`components/files/*`(存储组、上传、显示路径) |
|
||||
|
||||
## 14. 与设计的偏离
|
||||
|
||||
- 远端目录监控放在 `source-monitor.ts` 的 `walkRemoteSource`,没有单独的 `storage/snapshot.ts`。
|
||||
- 文件管理「下载」到浏览器仍守本地同一规则(NFO / 字幕 / 图片 / 文本 ≤ 20 MiB);大文件「下载到本地」用「复制到」本机媒体库(走整理执行与账本)。MP 允许浏览器下载任意文件。
|
||||
- Alist 根的目录树与列表不做递归目录摘要(视频数),目录树子目录一律显示可展开,避免逐目录请求网盘。
|
||||
- 存储根是 Alist 的 `/`(各挂载的上一级)时,回收站放在被删项所在挂载的 `.umt-trash`。
|
||||
- 已整理的文件不能「移动到」非媒体库的 Alist 存储根(会脱离媒体库),只能复制或先从媒体库移除。
|
||||
- 补字幕(`subtitles`)只写本机媒体库;Alist 媒体库上的字幕写入不在本次范围(MP 的 Alist 能力里没有)。
|
||||
- 库存对账(`reconcile`)对 Alist 库根逐个位置 `get`,受实例限速;没有按目录批量列。
|
||||
- 迁移只用了 0090;0091 未使用。
|
||||
Reference in new issue
Block a user