deepseek-media-gallery
侧边栏按钮打开半透明弹窗,浏览、预览、下载和删除生成的图片与视频;设置页可改图片目录、记录目录与下载目录。
yuanyihy
@yuanyihy
⬇ 1
★ 0
main
安装
dsh plugin --profile web add github:yuanyihy/deepseek-media-gallery
需要可复现安装时,可在仓库后追加 #commit 固定提交。
侧边栏按钮打开半透明弹窗,浏览、预览、下载和删除生成的图片与视频;设置页可改图片目录、记录目录与下载目录。
该插件未提供要点说明,请参考仓库 README。
cordisdeepseek-harnessdshdsh-plugingalleryimage
- 安装并启动 DeepSeek Harness:
npx @deepseek-ai/dsh web - 在终端执行上面的安装命令(CLI 会解析插件并核验来源)
- 用 dsh plugins list 确认已安装,必要时重启 Harness 生效
插件以当前 dsh 进程的权限运行,安装时可能执行代码。请先通读仓库源码与许可证,确认无破坏性命令与越权访问;本站只做索引,不对第三方插件安全性作担保。
| 代码仓库 | github.com/yuanyihy/deepseek-media-gallery |
| 许可证 | MIT |
| 主要语言 | main |
| 下载量 | 1 |
| GitHub 星标 | 0 |
| 最近推送 | 2026-09-16 |
| 收录日期 | 2026-09-19 |
| 分类 | 界面增强 |
事实信息来自公开插件目录快照(2026-10-03),介绍文案由本站再加工。
以下为插件仓库 README 全文(原始内容,由公开目录抓取整理)。
# DeepSeek Media Gallery
DSH(cordis)插件:把一个媒体目录里的图片/视频列成画廊 —— 预览、Range 播放、下载到桌面、删除。入口是**侧边栏底部的按钮**,打开一个**半透明弹出窗口**(不占中央聊天区)。

插件分两半:
| 半边 | 文件 | 作用 |
| --- | --- | --- |
| 宿主(Node) | `lib/index.js` | cordis 插件:`name` / `inject` / `Config` / `apply`,注册 `/*` 路由 |
| 浏览器 | `lib/client.js` | DSH 客户端插件:`window.__ModuleLoader__.load({id, factory})`,`apply(ctx)` 里经 `ctx.slots` 注册入口按钮 + 弹窗 |
浏览器半边是 React 原生渲染,不是 iframe。
`client/` 目录下另有一套**独立页面**(`index.html` + `client.js`),由宿主路由 `/` 与 `/client.js` 提供,用于直接在浏览器打开画廊调试。它与 `lib/client.js` 无关,别混淆。
## 侧边栏与弹窗
| 插槽 | kind | 注册项 | 说明 |
| --- | --- | --- | --- |
| `sidebar.footer.action` | list | `{ id: 'media-gallery-panel', order: 60 }` | 侧边栏底部(设置旁边)的入口按钮,owner props 含 `wide` |
| `shell.overlay` | list | `{ id: 'media-gallery-panel', order: 60 }` | 帧级浮层,弹窗本体渲染在这里 |
**刻意不注册** `main` / `sidebar.panellist` —— 那两个会把画廊变成占据中央区的常驻面板("把聊天框都占了")。弹窗关闭时组件返回 `null`,不常驻 DOM。
关闭方式有三种:右上角 ✕、点背景遮罩、按 Esc(先关预览大图,再关窗口)。
## 设置(位置可二次设置)
弹窗右上角齿轮进入设置页,三项路径都能改,**保存后立即生效,不需要重启**:
| 键 | 含义 | 默认 |
| --- | --- | --- |
| `generatedDir` | 图片存放位置(画廊扫描这里) | `$DSH_HOME/plugin-data/image-gen/generated` |
| `dataRoot` | 记录存放位置(`tasks.json` / `mcp-records.json`) | `$DSH_HOME/plugin-data/media-gallery` |
| `downloadDir` | 下载位置 | 自动探测的桌面 |
- 「选择…」按钮先试**宿主原生目录对话框**(`ctx.uiWorkspace.pickDirectory()`),失败则**自动退到内置目录浏览器**,并在顶部说明退化的原因。两条路径都拿不到时提示直接填路径。
- 内置浏览器:**盘符切换行**(点一下换到别的盘)+ 面包屑跳转 + 逐层进入子文件夹 + 「选用此目录」+ 新建文件夹 + 「转到」直接粘路径(支持 `E:\` 和 `\\server\share` 这类 UNC)。
- **为什么需要盘符行**:`browse` 能力只会列"某个盘里面",`crumbs` 的祖先链到 `C:` 就断了 —— 不列盘符就永远出不了当前盘。盘符只有宿主能枚举,所以走 `GET /api/drives`(Windows 上探测 A–Z,比调 wmic/PowerShell 便宜也安全)。
- **为什么必须内置一个**:`pick()` 需要 `native` 能力,而 `@deepseek-ai/dsh-host-directory-picker-auto` 的判定是 `if (facts.platform !== "linux" || !facts.linuxChooser) return "browse"` —— 即 **native 只在 Linux**(zenity/kdialog + DISPLAY)成立,Windows/macOS 上 `pick()` 必然报 `directoryPicker.pick needs the native capability; the composed picker serves "browse"`。而 `browse` 能力(`listDirectory` / `createDirectory`)处处可用,内置浏览器就走它。
- 另外两个踩过的坑:① 服务由 `@deepseek-ai/dsh-client-ui-workspace` 提供,可能晚于本插件注册,所以**不能**在 `apply()` 时快照,必须点击现取;② cordis 的 reflect 层规定「属性访问未 inject 的服务会抛 `cannot get property "..." without inject`」,而 `ctx.get(name)` 是 *read a service without the inject requirement* —— 必须**先走 `ctx.get()`**,否则异常被 catch 吞掉,永远取不到服务。
- `listDirectory` 只接受**全限定路径**;输入框里是相对值时浏览器从宿主主目录起步。
- 输入框留空(灰色占位符显示默认值)表示回退到默认值。
- 每行下方显示该目录当前状态:是否存在、以及图片目录里有多少个媒体文件。
- 值的优先级:**用户保存的设置 > profile `cordis.patch.yml` 里的 config > 环境变量 > 自动默认**。前三者通过 dsh-settings 的 `base` 组合层实现(`generatedDir`/`dataRoot` 仍可用 `DEEPSEEK_MEDIA_GENERATED_DIR` / `DEEPSEEK_MEDIA_DATA_DIR` 覆盖种子)。
因为设置是**每次请求实时读取**的,改完目录后下一次 `/api/tasks` 就是新目录,无需重启 host。
### 目录扫描兜底
画廊不只列"登记过"的文件:`tasks.json` / `mcp-records.json` 里没有、但确实躺在图片目录里的媒体文件也会列出来(上限 500 个,按修改时间倒序,`adapterId: "scan"`)。所以把插件指向一个装满图片的普通文件夹也能直接用。
## 背景板(与「律动」同款半透明)
`dsh-rail-equalizer` 的面板底色是 `var(--dsw-specific-input-major, var(--dsw-alias-bg-base))`。这个 token 由毛玻璃主题 **wallpaper-engine** 定义成 `rgba(255,255,255,var(--we-glass-alpha))`,所以只要用**同一个 token**,半透明观感就和律动一致,不需要自己拍透明度:
| 用途 | 取值 |
| --- | --- |
| 弹窗底色 | `var(--dsw-specific-input-major, var(--dsw-alias-bg-base))` |
| 卡片底色 | `var(--dsw-specific-bubble, var(--dsw-alias-bg-layer-1))` |
| 模糊 | `blur(var(--we-blur,16px)) saturate(var(--we-saturate,1.8))` |
后两个 `--we-*` 变量同样来自 wallpaper-engine,缺省值即其默认值;没有主题时全部回落到官方 `--dsw-alias-*`。
## 下载(原素材作为备份,不动)
| 方式 | 行为 |
| --- | --- |
| 卡片上的 ⤓ / 预览里的「下载」 | `POST /api/download` → 服务端把文件**复制**到下载位置,原文件保持原样 |
| 复制失败(如没有写权限) | 自动退回浏览器下载 `/api/file/`(`Content-Disposition: attachment`) |
同名文件不会覆盖:第二份会存成 `名字 (2).ext`。删除才是真正删掉存档文件,别拿删除当"清空桌面"。
## 目录结构
```
lib/index.js 宿主半边(cordis 插件)
lib/client.js 浏览器半边(侧边栏按钮 + 弹窗 + 设置页)
client/index.html 独立页面
client/client.js 独立页面脚本(≠ lib/client.js)
cordis.patch.yml bundle patch:把本插件插进 profile 层栈
test/plugin.test.mjs 宿主半边测试(60 条)
test/client.test.mjs 浏览器半边测试(73 条)
test/preview.mjs 本地预览:用真实 handler 起临时服务
legacy/ Hana 形状的旧实现(routes/、旧 index.js、manifest.json),DSH 不加载,仅作参考
```
数据文件格式(`dataRoot` 下):
- `tasks.json`:`[{ taskId, status: "done", files: [...], prompt, modelId, createdAt }]`,只有 `status === "done"` 且文件存在才渲染。
- `mcp-records.json`:`[{ taskId?, filename, prompt?, modelId?, createdAt? }]`,MCP 生图(`ofapp-image-mcp`)的产物登记在这里。
两处都会读,并按 filename 去重(同名时保留 `tasks.json` 的条目,元数据更全),剩下的再交给目录扫描兜底。
## 宿主路由(前缀默认 `/deepseek-media-gallery`)
| 方法 | 路径 | 说明 |
| --- | --- | --- |
| GET | `/` | 独立页面 |
| GET | `/client.js` | 独立页面脚本 |
| GET | `/api/tasks` | 媒体列表(tasks + mcp-records + 目录扫描,去重) |
| GET | `/api/media/:filename` | 媒体流,支持 Range(`bytes=0-9`、`bytes=-10`、`bytes=50-`,越界/畸形 416) |
| GET | `/api/file/:filename` | 附件下载(浏览器兜底) |
| GET | `/api/drives` | 目录浏览器可跳转的根(Windows 盘符列表 / POSIX `/`) |
| GET | `/api/settings` | 当前值 / 默认值 / 各目录状态 |
| POST | `/api/settings` | 更新路径(空字符串 = 回退默认) |
| POST | `/api/download` | 复制到下载位置(`{ filename, destDir?, overwrite? }`) |
| DELETE | `/api/tasks/:id` | 删除记录 + 存档文件 + 对应 mcp 记录;体 `{ "filename": "..." }` |
删除**不可撤销**。`filename` 只接受媒体目录内的裸文件名,拒绝路径分隔符、`..`、`:` 与 NUL。
## 配置项
`Config` 是 schemastery schema(**不能**是普通对象:cordis 走 `Config["~standard"].validate()`,dsh-settings 会把 schema 当函数调用):
| 键 | 默认 | 说明 |
| --- | --- | --- |
| `routePrefix` | `/deepseek-media-gallery` | 路由前缀 |
| `dshHome` | `""` | 留空用 `DSH_HOME` |
| `generatedDir` / `dataRoot` / `downloadDir` | `""` | 设置项的**种子值**,用户在面板里保存的值优先 |
浏览器半边用 `PREFIX` 常量拼请求地址(`lib/client.js` 顶部),**改了 `routePrefix` 要同步改它**。
## 开发
```bash
npm test # 宿主 60 条 + 浏览器 73 条
node test/preview.mjs --port 43199 \
--generated "<图片目录>" --data "<记录目录>"
```
`test/` 下的脚本会先把 `lib/`、`client/` 和自己复制到 `~/.dsh/profiles/` 下一个临时目录再跑 —— 插件自身没有 `node_modules`,`@deepseek-ai/*` 只有从 profile 的 node_modules 树里才解析得到。
## 说明与局限
- **纯本地**:所有读写都在本机文件系统上完成,不联网、不上传任何东西。
- 宿主路由挂在 DSH 的本地 webserver 上(默认只监听 `127.0.0.1`),没有额外的鉴权层;`routePrefix` 可以改,但别把它暴露到公网。
- **平台**:Windows / macOS / Linux 都能用。差异只有目录选择器 —— 原生对话框仅 Linux 有(zenity/kdialog),其余平台自动走内置浏览器。
- 删除**不可撤销**:会同时删掉记录和磁盘上的媒体文件。下载是复制,不动原文件。
- 画廊按 `dataRoot` 里的 `tasks.json` / `mcp-records.json` 索引;没有任何登记时用目录扫描兜底。这两个文件由你使用的生图插件(例如 `ofapp-image-mcp`)写入。
## 安装
npm 包形状:`package.json` 的 `dsh.bundle.patch` 指向 `cordis.patch.yml`(插进 profile 层栈),`dsh.client` 声明浏览器半边(`exports["./client"]` → `lib/client.js`)。peer 依赖从 profile 的 node_modules 解析。改完需要重启 host 才会重新加载。
数据来源:公开的 DeepSeek Harness 插件目录与各插件 GitHub 仓库。本站为独立第三方目录,与 DeepSeek、幻方(High-Flyer)及插件作者均无隶属或背书关系。