🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI
广告☁️ 云服务器特惠阿里云首购 8 折 · 腾讯云合作特惠
DeepSeek Harness Hub
← 返回列表

yuanyiHY/dsh-rail-equalizer

DeepSeek Harnessspec-screened扫描:低风险在 GitHub 查看 ↗
未验证

让 DSH 的「轮次导航」导轨聊天右侧那根刻度条跟着系统正在播放的声音实时律动。

尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/17 · 已提供中文文档

让 DSH 的回合导航栏实时响应系统音频(Windows)。通过 koffi 进行 WASAPI 环回捕获——无需权限提示、不使用麦克风、不进行屏幕录制;浏览器端只注入一个样式表和 CSS 变量,绝不修改官方组件。

综合分
29.2
GitHub 分
29.2
用户评分
—
★ Stars
0
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add yuanyiHY/dsh-rail-equalizer
该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
信任档位:需留意实装验证未通过
是什么
dsh 原生插件 · vision
装得上吗
实装验证未通过(dependency_conflict),装前请到仓库确认最近更新与 issue
安全吗
本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
还在维护吗
活跃:最近一次提交在 9 天前

档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →

⚠︎ 实装验证未通过(dependency_conflict · 2026/9/25) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
数据截至 2026/9/24(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-client-ui-conversation@deepseek-ai/dsh-host-webserver
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

由 DeepSeek 最新模型翻译生成
dsh-rail-equalizer

让 DSH 的「轮次导航」导轨(聊天右侧那根刻度条)跟着系统正在播放的声音实时律动。

放音乐、放视频、打游戏 —— 只要声音是从这台电脑的默认播放设备出来的,导轨就会跟着动。
不需要任何授权、不弹任何窗口、不碰麦克风、不录屏,戴耳机照样工作。

轮次导航跟着系统声音律动

侧栏里的「律动」开关

仅 Windows。 音频采集层依赖 WASAPI。英文说明见 README.en.md。

它是怎么拿到声音的

这是本插件唯一"重"的地方,值得说清楚。

浏览器的 getDisplayMedia(屏幕共享)做不到"一次授权" —— 这是 Chrome/Edge 刻意的安全设计:每次调用都必须重新选一次共享目标,权限不做持久化,没有任何 API 能绕过。而麦克风方案在戴耳机时完全无效。

所以本插件走的是宿主端 WASAPI 回环:DSH 的宿主进程(Node)通过 koffi 直接调用 Windows Core Audio 的 COM 接口,抓默认播放设备正在渲染的 PCM。

IMMDeviceEnumerator.GetDefaultAudioEndpoint(eRender)
→ IMMDevice.Activate(IAudioClient)
→ IAudioClient.Initialize(AUDCLNT_STREAMFLAGS_LOOPBACK)
→ IAudioClient.GetService(IAudioCaptureClient)
→ 轮询 GetBuffer / ReleaseBuffer

和 OBS 抓桌面音频是同一个机制。它不是"录音",是在读系统混音器已经把声音交给声卡的那份数据,所以:

- 没有任何"权限"概念需要向谁申请
- 耳机 / 音箱 / HDMI / 虚拟声卡,抓的都是默认播放设备(你在系统里切输出,它跟着切)
- 只读,不写入、不改变音量、不影响任何正在播放的程序
- 音频数据只在内存里过一遍算电平,不出这台电脑、不落盘

koffi 通过 optionalDependencies(@koromix/koffi-win32-x64)分发预编译二进制,装包即用,不需要 Visual Studio / node-gyp / 任何编译工具链。

它是怎么做到"不动原组件"的

官方导轨由 @deepseek-ai/dsh-client-ui-chat 渲染。本插件没有 patch、没有 fork、没有替换它的任何代码或组件。

浏览器半只做四件事:

| 做什么 | 具体 |
|---|---|
| 打一个标记 | 往导轨的  上加 data-dsh-eq 属性 |
| 注入一张样式表 | 一个  标签,全部靠 CSS 覆盖(两套构建的横条选择器都覆盖) |
| 写几个变量 | document.documentElement 上的 --dsh-eq- |
| 画一个控制行 | 侧栏那一行是纯 DOM(insertBefore 插进文档流);展开的设置面板走官方 shell.overlay 插槽 |

为什么这不可能破坏功能:

1. 律动只作用于可见的那根横条,而且只叠加 scale / filter / box-shadow 三个属性。
官方导轨在不同 DSH 构建里画横条的方式不一样,两种都覆盖:
- 新构建:横条是真实的 ,它的尺寸/透明度/配色由 React 写成内联样式。
内联样式优先级很高,所以绝不能去改这四个属性 —— 改用独立的 scale 属性叠加:
scale 与 transform 是两个互不覆盖的属性(最终矩阵 = translate × rotate × scale × transform),
元素原有的内联尺寸与四态差异一像素都不会动。
- 旧构建:横条是 button 的 ::before 伪元素,那里用 transform: … scaleX() scaleY() 叠加。
两套选择器各自只在对应构建里命中,互不干扰。
2. 无论哪种构建,都不碰 width / height / opacity / background-color ——
官方四态(当前 / 悬停 / 未加载 / 生成中)的尺寸与配色差异一个都没被改。
3. 变形从 1 起算(静止即恒等变换),filter 从 brightness(1) 起算,无辉光时 box-shadow 不画 ——
电平静默时视觉效果就是原样。伪元素与 scale 都不参与布局,也不会出现在 getBoundingClientRect() 里,
所以导轨的滚动、坐标定位、点击跳转在几何上完全不受影响。
4. 只叠加 filter: brightness() 与 box-shadow,不动 background / color,主题 token 原样生效。
5. 正在生成的那一轮带 aria-busy="true",样式表显式把它排除在行波动画之外 —— 它自己那条"呼吸"表现一点没被覆盖。
6. 每个刻度的行波相位用 nth-child 静态生成 CSS(设在行容器上靠继承下发),完全不往 DOM 里写东西,不会和 React 的渲染打架。
7. 关闭 = 移除属性 + 移除样式表 + 清空变量,三件事一起做。关掉之后导轨和没见过这个插件完全一样。

安装

仅 Windows。 音频采集层依赖 WASAPI,package.json 里也声明了 os: ["win32"],所以在 macOS / Linux 上会被包管理器直接拒装,而不是装完再崩。

dsh plugin --profile desktop add github:yuanyiHY/dsh-rail-equalizer

装完重启 DSH Desktop(宿主进程要重新加载 bundle 才会注册路由)。

从源码 / 本地目录安装(改代码即时生效)

git clone https://github.com/yuanyiHY/dsh-rail-equalizer
dsh plugin --profile desktop add link:
⚠️ 安装路径里不能有空格 —— dsh plugin 会把参数转给 pnpm,带空格的路径会被切碎成多个包名。本地开发建议放在 ~/.dsh/local-plugins/ 这类没有空格的目录下。

不需要编译工具链。 koffi 虽然带一个 install 脚本,但原生二进制是打包在 optional dependency(@koromix/koffi-win32-x64)里的,脚本没执行也能正常加载。pnpm 若提示需要授权构建脚本,跳过不影响使用。

卸载

dsh plugin --profile desktop remove dsh-rail-equalizer

重启后宿主侧的采集与路由完全消失。浏览器侧因为插件不再加载,什么都不会注入。
也可以只点侧栏那一行的开关关掉 —— 效果等同,且立刻生效。

使用

侧栏里、官方「工作区」区块正上方会出现一行:

┌──────────────────────┐
│ ♪  律动        [ ⬤ ] │   ← 点整行(开关以外)展开 / 收起设置面板
└──────────────────────┘      点右侧开关 → 直接开 / 关

这一行是插进侧栏文档流的(insertBefore 到 [class="_regionArea"] 之前),
用和生态里其它插件(如技能中心)一样的做法,并带自愈:React 重渲染把它挤掉就重新插回去。

为什么不注册进官方插槽? 侧栏唯一位置合适的 sidebar.workspaces 是 kind: "single" ——
往里注册会顶掉官方的工作区区块。而侧栏其余插槽(sidebar.settings / sidebar.brand.)也都是 single。
所以只能插 DOM,这也是其它侧栏插件共同的做法。

为什么不用浮层(position: fixed)? 试过,不行 —— 浮层会盖住同样插在这一区域的
其它插件(技能中心那一行就是这么被盖没的)。插进文档流后各占各的位置,谁都不挡谁。

也没有单独的齿轮按钮了 —— 免得和 DSH 自己的设置齿轮撞脸。设置面板只在展开时出现,
定位到这一行的右侧(--dsh-eq-pill-x/y 由 JS 实测写入)。

设置面板里:

| 项目 | 说明 |
|---|---|
| 总开关 | 关掉后导轨完全恢复默认样式(样式表被移除,不是"置零") |
| 运动方式 | 四选一,即时生效,见下表 |
| 灵敏度 | 0.4–3.0。系统音量小、音乐本身轻的时候往上调 |
| 强度 | 0.2–2.0。整体变形幅度 |
| 低频冲击 | 0–2.0。鼓点让刻度纵向"砸"下去多少 |
| 行波 | 只在「行波」模式下有意义:关掉则波浪不跑,刻度原地起伏 |
| 波速 | 行波周期,0.46×–2.4×(滑杆值 2600–500ms) |

四种运动方式

用现有的 N 根刻度当素材,四种完全不同的运动模型:

| 方式 | 观感 | 驱动量 |
|---|---|---|
| 频谱(默认) | 每根刻度长度 = 它负责的那段频率,低音→高音依次排开,像音乐播放器的频谱条 | --dsh-eq-v(该刻度分到的频段) |
| 脉动 | 所有刻度同相位,整排一起伸缩呼吸,最"齐" | --dsh-eq-lvl + 全局动画相位 |
| 摆动 | 刻度本身不变形,整条导轨左右往复摆动 | --dsh-eq-sw × 电平 |
| 行波 | 每根刻度错开相位,一条波沿轨道向上跑 | --dsh-eq-lvl + 每刻度相位 |

频谱模式是唯一的"真频谱":宿主端跑 2048 点 FFT + Hann 窗,把 40Hz→16kHz 按对数切成 16 段(和听感一致),客户端再按实际刻度数把 16 段均匀铺到 N 根刻度上 —— 所以 5 根刻度也能看到从低到高的完整分布,50 根刻度就是一根根连续的频谱。

客户端会热重载、宿主不会,所以可能出现「客户端新版 / 宿主旧版」。此时没有频段数据,频谱模式会自动降级成整排一起动,而不是完全不动。自检里的 bandsAvailable 会告诉你当前是哪种。

面板底部有实时电平条和后端状态(设备格式 / 连接状态 / 出错原因)。设置存在浏览器 localStorage(键 dsh-rail-eq:settings:v1)。

CPU 与省电

- 采集是按需的:有浏览器连上 SSE 流才开始抓,最后一个断开后 8 秒自动停。页面没开时这个插件完全不占 CPU。
- 实测解码开销约 2 ms/s CPU(48kHz 立体声 float32),可以忽略。
- 电平以 ~30Hz 经同源 SSE 推送;浏览器侧再用 requestAnimationFrame 平滑到屏幕刷新率。
- 尊重系统的「减少动态效果」(prefers-reduced-motion):此时只保留柔和的亮度起伏,不做变形与行波。

出问题怎么办

导轨完全不动

1. 点侧栏那一行展开设置面板,看底部状态:
- 采集失败:... → 看下面「常见报错」
- 已连接,等待音频… → 链路是通的,只是系统此刻没在放声音
- 连接中… → 宿主路由没起来,八成是没重启 DSH
- 当前平台不支持(仅 Windows) → 预期行为,本实现是 Windows 专用的
2. 确认声音确实是从默认播放设备出来的。有些播放器可以指定独立输出设备,如果它绕过了默认设备,就抓不到。
3. 确认导轨还在页面上(轮次导航是官方组件,官方改名/移除的话本插件会静默不生效,不影响其它功能)。
4. 还是没效果 → 看浏览器半的自检。宿主侧看不到 DOM,所以浏览器半会把自己的状态回传给宿主,
读 GET /rail-eq/status 里的 clientReport 字段,能看到:
railFound(找没找到导轨)、matched(CSS 选择器命中没有)、mode / tickCount(当前模式、数到几根刻度)、
bandsAvailable(宿主有没有在发频段数据)、vars(电平变量写了多少)、
tick.scale / tickRect(横条被拉伸成多大)、uiRendered(标题栏按钮有没有真的被渲染)。
排查「装了但没效果」这一类问题,这个字段通常一眼就能定位。
Initialize(LOOPBACK) 失败 0x88890008 —— 该设备不支持回环(少见,某些独占模式/虚拟声卡)。切一个默认输出设备再试。

不支持的混音格式 tag=... —— 设备的混音格式既不是 IEEE float32 也不是 PCM16。把默认播放设备的格式改成 16bit/24bit、44100/48000Hz 通常能解决。

手动重启采集(换过播放设备之后):

curl -X POST http://127.0.0.1:/rail-eq/restart

正常情况下不需要 —— 采集出错会自动重试。

调试用的接口

| 路由 | 用途 |
|---|---|
| GET /rail-eq/status | 完整状态:是否在采集、音频格式、包数、客户端数、当前电平 |
| GET /rail-eq/level | 单发当前电平,不会启动采集 |
| GET /rail-eq/stream | SSE 电平流(浏览器半用的就是它) |
| POST /rail-eq/restart | 重启采集 |
| POST /rail-eq/report | 浏览器半自检回传(排「没效果」用,结果出现在 /status 的 clientReport) |

开发

lib/
index.js     宿主半:SSE 路由 + 采集生命周期(Cordis 插件)
wasapi.js    WASAPI 回环采集(koffi 直调 Core Audio COM)
analyzer.js  PCM → 4 个时域电平 + 16 段对数频谱(2048 点 radix-2 FFT + Hann 窗,快攻慢放包络)
client.js    浏览器半:导轨绑定 + CSS 变量 + 控制 UI
test/
host-integration.mjs  宿主端集成测试(不需要 DSH 重启)
band-probe.mjs        单点频段探针(验证某个频率落在哪一段)
make-tone.mjs         生成测试音

宿主半是纯 ESM,浏览器半是 window.__ModuleLoader__.load({ id, factory }) 形态的静态 bundle,都不需要构建步骤。改完 lib/.js 重启 DSH 生效。

跑测试(有声音在放时最有意义):

node test/make-tone.mjs 30
另开一个窗口播放 test/tone.wav,然后:
node test/host-integration.mjs

测试会覆盖:路由分发、404、按需采集(单发探活不该启动采集)、SSE 头与推流、status 补发、电平数值健康度、四频段独立性、频谱结构(最强段显著高于中位段)、断开后自动停机、dispose 清理。

koffi 踩过的两个坑

1. 输出参数不是返回值数组。 koffi 里 _Out_ 参数要传一个容器([null])进去,原生代码把结果写回容器,函数返回值就是 C 的返回值(这里是 HRESULT)。
2. COM vtable 要手动解引用。 koffi.decode(obj, 'void ') 拿到 vtable 指针,再 koffi.decode(vtable, index  ptrSize, 'void ') 拿到方法指针,最后 koffi.call(fn, proto, obj, ...)。proto 的第一个参数是 this。

已知限制

- 仅 Windows。 音频采集层依赖 WASAPI。macOS 可以用 ScreenCaptureKit 或虚拟声卡,没有实现。
- 抓的是默认播放设备。 播放器如果指定了独立输出设备,抓不到。
- 导轨的定位靠语义锚点(nav + button[class="_mark"],优先用 aria-label),不依赖中英文案也不依赖哈希类名。官方若大改导轨 DOM 结构,findRail() 一个函数就能修。
- 没有接入 DSH 的 locale 命名空间,界面文案是中英混合。

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

同作者(yuanyiHY)的其他插件

💬 加入社群

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

DPharness QQ 群二维码,QQ 扫码进群
QQ 扫码进群
DPharness 飞书群二维码,飞书扫码进群
飞书扫码进群