Renders local audio/video paths as inline, playable previews in DSH chat: replaces paths with <audio>/<video> players backed by same-origin /api/media-preview/* route, with explicit error statuses.
Install
# from npm (prebuilt)
dsh plugin --profile web add media-preview
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:xiaokaizhou/dsh-media-preview
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
DSH plugin: renders local/online audio/video/image paths as inline, playable previews in chat
When an assistant message or tool result contains a local media path or an online http(s) media link, it is replaced inline with a playable <audio> / <video controls playsInline> / <img> element. Local paths are proxied through /api/media-preview/<base64-path>; online links use the direct URL.
Default mode is unrestricted: any file readable by the DSH process can be served. Permission and IO errors are returned as explicit HTTP statuses and reason strings so the browser's native <video> and <audio> error events display meaningful messages.
Companion plugins
Part of a generate → orchestrate → preview loop with two sibling DSH plugins by the same author:
| Plugin | Role | npm |
|---|---|---|
| dsh-llm-multimodal | Produces the media: generate_image / generate_video / generate_vision / generate_tts / generate_music / generate_text |
npm: dsh-llm-multimodal |
| dsh-media-studio | Orchestrates it: multi-project infinite canvas, asset library, global search, soft references | npm: dsh-media-studio |
Where each one renders. The two plugins serve media over different routes for different surfaces, and they complement rather than duplicate each other:
- This plugin handles the chat surface: a
file://path orhttp(s)link in an assistant message or tool result becomes an inline player. It serves any DSH-readable file (unrestrictedmode) at/api/media-preview/<base64-path>. - media-studio handles the canvas surface: files inside a project are served at
/api/media-studio/media-filewithETag/304andCache-Control: private, max-age=86400, immutable, plus a Service Worker that pre-heats video/audio headers for near-zero-buffer playback on the canvas.
Since dsh-llm-multimodal writes generated media into the active media-studio project by default, installing all three means: generate → see it on the canvas → read the file:// path in chat as a player. Install order does not matter; none of the three has a hard dependency on another.
Features
- Range requests (
bytes=start-end) →206 Partial Contentfor seeking in<video> - Whole-file GET →
200 OK - Caching →
Cache-Control: private, max-age=60 - Client regex matches only
/Users|/tmp|/private/tmp|/var/folders|/var/tmproots with supported extensions, avoiding arbitrary URLs or paths outside the user's home/temp tree - UTF-8 safe path encoding for non-ASCII folder names
<style>cleanup: injected CSS is owned by the client Fiber and removed automatically when the plugin unloads
Supported extensions (27)
Both local paths and online links are supported:
Audio/Video (15): mp3 wav m4a flac ogg opus aac mp4 mov mkv m4v webm avi 3gp ogv
Images (12): png jpg jpeg gif bmp webp svg tiff ico avif heic heif
Online examples: https://example.com/clip.mp4, https://cdn.site.com/img/photo.webp
Preview

Install
# from your DSH web profile
cd ~/.dsh/profiles/web
# Option 1 (recommended): dsh CLI from the npm registry
dsh plugin --profile web add media-preview
# Option 2: dsh CLI from GitHub
dsh plugin --profile web add xiaokaizhou/dsh-media-preview
# Option 3: pnpm from the registry (requires a manual step, see below)
pnpm add media-preview
The profile package.json lives at:
- Default:
~/.dsh/profiles/web/package.json(macOS / Linux) - Windows:
%USERPROFILE%\.dsh\profiles\web\package.json - Custom
$DSH_HOME:$DSH_HOME/profiles/web/package.json(override viaDSH_HOMEenv) - Multiple profiles:
~/.dsh/profiles/<profile-name>/package.jsonfor each
For Option 2, add this to the profile package.json above:
"dsh": {
"profile": {
"bundles": [
"media-preview"
]
}
}
Restart dsh web after any source change.
Limitations
- Whole-file buffered through
fs.readBytes(cap 500 MB). Large videos can be slow to start —<video>needs metadata before it can render the first frame. Range requests slice the same in-memory buffer. - No directory listing. No symlink policy beyond what
fs.statreports. - The 500 MB cap is per-request, not per-session. Future versions could stream chunks via
child_processddif the cap proves too low.
Failure modes
| Condition | Status | Reason |
|---|---|---|
| File missing | 404 |
not found: <errno> |
| Permission denied | 500 |
permission denied: <errno> |
| Is a directory | 415 |
is a directory, not a file |
| Symlink loop | 400 |
symlink loop or too many links |
| Path too long | 400 |
path too long |
| Unsupported extension | 415 |
unsupported media type: <ext> |
| File > 500 MB | 413 |
file too large: <bytes> > 524288000 cap |
| Range invalid | 416 |
Content-Range: bytes */<total> |
License
MIT
Sponsorship
If this plugin saves you time, you can buy me a coffee with one of the following QR codes.
Links
More in this category
zhu1090093659/dsh-web#packages/dsh-task-board★ 8801
Task board for the dsh web GUI: a sidebar multi-column kanban whose cards run in real DSH agent sessions and can also be scheduled with cron expressions, executed host-side even with the browser closed.
zhu1090093659/dsh-web#packages/dsh-web-all★ 8801
Plugin and skin collection for the DSH Web UI: task board, Git graph, right-side panel, remote mobile UI, pet, live token stats, and a skin center.
MeteorNOX/DeepSeek-Balance-Whale-Widget★ 4908
A fixed-corner whale widget for the DSH web GUI — balance, today's usage and per-turn cost with peak/off-peak pricing, editable balance-alert and daily-budget bubbles, a module-based custom bubble queue with A/B weighted choices and random lines or images, 30+ vendor templates (OpenAI, OpenRouter, Kimi, SiliconFlow, Ark, Zhipu, MiniMax and more) with per-model balance and subscription quota, plus task-end sound, imported audio, custom roles and a resource manager. Local-only, no telemetry.
ccch1mneyyy/dsh-TUI★ 4640
Claude Code-style full-screen terminal UI: pixel-whale header, live status line, and streaming thought expansion.
omdsh-dev/DSH-better-sidebar★ 4198
Full sidebar workbench with file rendering and editing, terminal, Git, and subagents; third-party plugins can register new tabs.
Devin-AXIS/deepseek-design#deepseek-idesign★ 1463
Visual design studio for websites, app prototypes, posters, cards, reports, and magazines, with templates, direct element editing, selection-aware AI draft handoff, and export.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.