Skip to content

feat(media): 内置音视频预览 + /sidebar/file 的媒体 MIME 与 Range - #1027

Open
feigo313 wants to merge 1 commit into
omdsh-dev:devfrom
feigo313:feat/media-preview
Open

feigo313 wants to merge 1 commit into
omdsh-dev:devfrom
feigo313:feat/media-preview

Conversation

@feigo313

Copy link
Copy Markdown

动机

侧边栏打开 .mp4 时没有任何 viewer 认领,文件落进 code 兜底:fsRead 读到 NUL 判二进制 → 停在「此文件类型不支持预览 · 下载查看」。agent 刚产出的成片只能下载到外部播放器看。

同时 /sidebar/file 的两处缺口让任何 <video> 都难受:

  1. MEDIA_TYPES 没有视频/音频条目,一律 application/octet-stream——<video> 靠 Content-Type 选 demuxer,等于让浏览器猜容器;
  2. 路由不支持 Range——能起播但不能拖时间轴,且必须等整份流。

方案

  • 新增内置 media viewer(fetchStrategy: 'mediaUrl'):音频走 <audio>、视频走 <video>,preload="metadata" 不预下整片;解码失败或地址缺失时显示提示并保留「下载」链接。不把字节复制进 Blob,也不缓冲整份文件。
  • MEDIA_TYPES 补齐:mp4/m4v/webm/ogv/mov 与 mp3/m4a/aac/wav/flac/ogg/oga/opus。
  • /sidebar/file 增加 accept-ranges: bytes 与 Range 处理(src/file-stream.ts 的 byteRangeOf + streamFileToResponse(..., range)):单段答 206 + content-range;支持后缀区间(bytes=-500)与越界 end 钳制;起点越界答 416 + bytes */size;多段 / 非 bytes 头回退整份 200(无 Range 头时行为与现在完全一致)。?download=1 的续传同享。

与推荐插件的关系

src/client/plugins-viewers.ts 里已推荐 dsh-video-preview(自带 /video 路由)。本 PR 的定位不是替代它,而是补两件只有本插件能做、且对任何 viewer 都成立的事:自己的 /sidebar/file 此前既没有媒体 MIME 也没有 Range。内置 viewer 让"刚生成的成片"开箱可看(零安装);装了第三方 viewer 时按「同扩展名 + 更高 priority」覆盖即可。

验证

Windows 11 / Node 24 / pnpm 11.8:

  • pnpm typecheck ✅ | pnpm lint ✅ | pnpm build ✅
  • pnpm exec vitest run tests/builtins.spec.ts tests/file-stream-route.spec.ts tests/locales.spec.ts tests/native-surface.spec.ts tests/file-open-claim.spec.ts tests/editor-large-file.spec.tsx tests/plugin-list.spec.ts tests/theme.spec.ts → 168 通过 / 1 失败;唯一失败是 serves a file reached through a symlink(本机无创建符号链接权限,改动前即失败,与本次改动无关)。
  • 新增用例:Range 窗口 / 后缀 / 越界钳制 / 416 / 回退 200 / 视频 MIME(真 node:http 服务器)、byteRangeOf 单测、media 的认领面与 mediaUrl 策略、媒体 MIME 表、21 种语言的键集对齐。
  • 未跑:pnpm test:mount(需要 Playwright 与全新 scratch profile)与全量单 worker 套件。

兼容

  • 无新增依赖;不改 DSH 源码;客户端 bundle 仍只 value-import 白名单宿主包(图标来自 dsh-client-ui-primitives)。
  • 新增字符串已同步全部 21 份词典(viewerMedia / mediaUnplayable),tests/locales.spec.ts 的键集一致性与 docs/external-plugin-guide.md §5 的清单同批更新。

`.mp4` had no viewer, so it fell through to the `code` catch-all, came back
binary from fs.read and landed on the download pane. This adds:

- a built-in `media` viewer (`fetchStrategy: 'mediaUrl'`): <audio> for the
  audio containers, <video> for everything else, `preload="metadata"`, and the
  download link kept as the escape hatch;
- media MIME types on `/sidebar/file` (video/mp4, video/webm, audio/mpeg, ...);
- HTTP Range on the same route (206 + content-range, suffix ranges, clamping
  past EOF, 416 + `bytes */size`, multi-range / non-bytes headers fall back to
  200), so the player scrubs instead of buffering to EOF.

Tests: Range cases on a real node:http server, byteRangeOf units, the media
viewer's claim surface, the MIME table, and the 21-language key-set equality
for the two new strings.
@feigo313

Copy link
Copy Markdown
Author

补一条服务端事实,供这个 PR 与 #1036 的取舍参考。

/sidebar/file 对媒体容器目前是「类型盲 + 无 Range」:MEDIA_TYPES 里没有视频/音频条目(一律 application/octet-stream),响应也不带 Accept-Ranges。

这不是只有「内置 viewer」才会踩到的问题。推荐目录里的 dsh-video-preview 之所以要自建一条 /video 路由(自己实现 206/416 与后缀区间),正是因为复用 /sidebar/file 既选不到 demuxer、也拖不动进度条。也就是说,无论最终选插件路线还是内置路线,这条路由的媒体 MIME 与 Range 都是该补的服务端缺口。

所以本 PR 可以拆开看:

我这边已先按插件路线落地(fork 了 dsh-video-preview 0.1.4:它 inject 的 webRuntime 在 0.2.x 已移除,改为 ctx.connection.requestRejection 才能挂载),本 PR 保留给你们判断。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants