DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

133563825as-ai /

133563825as-ai/dsh-asmrone

Verified

DeepSeek Harness 音声库插件:asmr.one / B站 / DLsite 试听 / 本机曲库四源合一

★ 1 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@314d0e46

dsh-asmrone

开源(MIT)的 DeepSeek Harness 专用插件:把 asmr.one (DLsite 同人音声整库镜像,六万余部)、B 站、DLsite 官方免费试听、以及手机本地已经下好的音声 四个来源接进对话 —— 搜作品、看音轨、在线播放(后台播放 + 拖进度)、按自己的权重重排结果、 批量下载与删除,全程不必离开 DSH。带 Web 面板,也带一条让 agent 直接推歌出声的通道。

四个来源对网络的要求不一样:asmr.one 与 DLsite 要代理;B 站和本机曲库不用 —— 没挂梯子的时候也有得听。

装

dsh plugin --profile web add link:/root/dsh-asmrone

装完要重启 dsh 才生效(dsh plugin 只是 pnpm 转发,没有 reload 子命令)。

Web 面板

侧边栏底部一枚 音声库 按钮(跟会话管理插件同款双行样式),点开是居中面板:

  • 顶部:搜索框(回车即搜)、排序下拉(销量 / 评分 / 发售日 / 最新上架)
  • 筛选 chips:「只要中文」「排除女性向」,以及一枚 权重排序 开关
  • 权重面板:销量 / 评分 / 评价数 / 新鲜度 四条滑块(02),松手即重排; 另有候选池深度(15 页)与「推荐配置 / 归零」两个预设。权重全 0 时走官方排序
  • 作品卡片:封面、标题、社团、评分、销量、时长、声优、标签;开权重时右下角显示归一化得分
  • 点卡片 → 音轨清单内联展开在该卡片正下方(不跳页、不开新窗口)
  • 底栏常驻播放条:播放/暂停、可拖动的进度条、当前 / 总时长、音量

界面用 dsh 自己的设计令牌(--dsw-alias-*)与 #4f7cff 主色,纯 SVG 图标, 跟随系统深浅色 —— 跟余额、会话管理两个插件是同一套观感。

后台播放

<audio> 不在 React 树里,它是挂在 document.body 上的页面级元素。所以容器怎么重建 都不影响它,具体表现:

  • 关掉面板 → 继续放,屏幕底部留一条悬浮迷你条(播放/暂停、进度、停、展开)
  • 切回对话页 → 继续放,迷你条跟着在
  • 锁屏 / 通知栏 → 有系统媒体控制(MediaSession,含 ±15s / ±30s 跳转)

藏 audio 用 1px + opacity:0,没用 display:none —— 后者在部分 WebView 上会直接停播。

音频走 host 代理 /asmrone/stream 而不是前端直连 —— asmr.one 的 CDN 不回 CORS 头, 前端 fetch 会被浏览器挡死;走代理还能把 302 与 Range 一并透传。

七个工具

工具 干什么
asmr_search 搜作品。关键词 / 排序 / 分页 / 中文版筛选 / 性别过滤,返回评分、销量、时长、声优、标签和作品页地址
asmr_work 列某部作品的完整音轨树,可顺带并发探测每轨体积
asmr_local 本地音声库:列已经下到手机上的作品与音轨、按名字/RJ 号找、直接推给面板播放。不需要网络
asmr_play 取音轨播放直链,并默认推给面板播放器立即出声(push:false 只取地址不打扰)
asmr_download 批量下载音频到本机。默认只下 MP3、跳过已存在的文件、按作品名建子目录
asmr_trial 抓 DLsite 官方试听包(免费公开,免登录),自带 zip 解压与 Shift-JIS 文件名修复
asmr_config 查看 / 修改偏好;action=tags 直接列 asmr.one 的 422 个中文标签

典型用法:

asmr_search  query=简体中文版 order=dl_count chineseOnly=true
asmr_work    id=1006912 resolveSizes=true
asmr_play    id=1006912 index=2      # 推第 2 轨到面板开始放
asmr_download id=1006912 title=舔耳按摩店 keyword=通常
asmr_trial   workno=RJ01726233 download=true

agent 推歌

模型侧没有播放能力 —— asmr_play 顶多算出一串 URL,用户在对话里点了也听不到任何东西。 所以工具在返回直链的同时,往一个单槽待播队列里压一条;前端每 3 秒轮询 /asmrone/pending 取走并播放。配上 asmr-ambience 技能,用户说一句「失眠了」 或「写东西想听点东西」就能直接出声,不用自己开面板。

队列刻意做得很小:只留最后一条 + 自增 seq + 2 分钟 TTL。

  • 带 seq 轮询 → 同一首不会被反复重播
  • TTL → 迟到的推送不会在半小时后突然响起来
  • 单槽 → 连推三首只放最后一首,避免攒出一屋子「早就忘了的曲子」

技能在 /root/.dsh/skills/asmr-ambience/,里面还写了按音轨名判断开头直入还是慢热铺垫 的挑片规则(導入 / ご挨拶 这类第 1 轨是铺垫,本番 / いきなり 这类是直接开始)—— 助眠要挑前者,直奔主题要挑后者。

没开代理时:本地曲库

asmr.one 是境外站。没有代理时在线那条链路(搜索 / 音轨 / 封面 / 在线播放)整条不通 —— fetch failed、超时、连接重置都算。这时候面板不该变成一块砖,所以有一条完全离线的路:

  • 面板:顶部「本地曲库」标签页。列出已经下到本机的音声(asmr_download 落的, 加上 localDirs 指向的目录),点开是音轨,点了就放。
  • 模型:asmr_local 工具。action=list 看有什么,action=play key=<作品> index=2 直接推给播放器。
  • 播放:音频走 /asmrone/local-stream,从磁盘直读,支持 Range 拖进度,一个字节都不出网。 跟在线播放共用同一个播放器 —— 一样能后台播、一样有悬浮条。

扫盘带 60 秒缓存(5 G / 154 个文件要遍历目录树 + 逐个 stat),面板上的「重扫磁盘」强制刷新。 配置的目录不存在时面板会明确标出来,不会静默算成 0 部。

文件绝对路径只留在 host 侧:前端用 key+index 取流,不回传路径。 /asmrone/local-stream?path= 那条入口只对配置过的根目录内、且是音频扩展名的文件放行 —— 前缀比较带分隔符(挡住 /x/asmr-evil 蹭 /x/asmr),并走 realpath 解析,符号链接也绕不出去。

HTTP 数据面

面板用的接口,挂在 webServer 的 /asmrone 前缀下。

方法与路径 说明
GET /asmrone/config 读配置 + 可用排序字段
POST /asmrone/config 改配置(白名单键)
GET /asmrone/search q / order / page / pageSize / chinese / female
GET /asmrone/work id= 取音轨树
GET /asmrone/sizes POST {hashes} 批量探测体积
GET /asmrone/stream hash= 音频代理,透传 302 与 Range
GET /asmrone/pending since= 取待播条目(agent 推歌的拉取端)
GET /asmrone/local 本地曲库列表;q= 过滤、force=1 绕过 60 秒缓存重扫
GET /asmrone/local-stream 本地文件流;key=+index= 或 path=,支持 Range
POST /asmrone/play {id, hash?, index?} 解析音轨并入队,供 agent / 脚本推歌;带 localKey 时推本地文件
POST /asmrone/download {id, title?, hashes?, keyword?, includeWav?}
GET /asmrone/trial rj= 探 DLsite 试听包
GET /asmrone/tags 标签表

配置

容器里的 JSON:<DSH_HOME>/asmrone/config.json,用 asmr_config 改,改完立即生效。

键 默认 说明
outputDir /sdcard/Download/ASMR(无外置存储时退回数据目录) 下载落盘目录,同时是本地曲库的第 0 个根
localDirs [] 额外的本地音声根目录(试听包解出来的、手动拷进去的都算)
languageFilter male male 剔除女性向/乙女向/BL;all 不过滤
defaultOrder dl_count 默认排序字段
downloadConcurrency 4 下载并发,1~8
maxWorkMb 800 单个试听包体积上限
pageSize 20 搜索默认每页条数

基础设施项(接口地址、超时)在同名 profile 的 cordis.patch.yml 里覆盖,别改随包的 cordis.patch.yml —— 升级时会被覆盖。

接口依据

全部端点都实测过(2026-10):

端点 用途
GET /api/search/{q} 关键词搜索,支持 page / pageSize / order
GET /api/works 全库列表
GET /api/tags/ 标签表,422 条,带 zh-cn 译名
GET /api/tracks/{id} 音轨树(folder / audio 嵌套)
GET /api/media/stream/{hash} 音频流,302 跳 CDN,支持 Range

GET /api/works/{id} 返回 401,作品详情从列表/搜索结果里取 —— 那些对象本身带全部字段。

DLsite 试听的坑

试听不是 mp3,是 zip 包。早期按 .mp3 拼 URL 全部 404,就因为后缀猜错了。 真实地址在 touch 页的 Nuxt payload 里:"trials":<索引> 指向无服务器序列化数组, 展开后拿到 //trial.dlsite.com/doujin/RJ01727000/RJ01726233_trial.zip。

play.dlsite.com/api/viewer/work/<RJ> 只有元数据(sample_type: "image" 那类),拿不到音频。 不少音声作品确实只有图片试听,这时工具会明确报「无音频试听」。

zip 解压自己实现了(只用 zlib.inflateRawSync + 中央目录解析),因为宿主机器不一定有 unzip。老 DLsite 包的 Shift-JIS 文件名靠 TextDecoder('shift_jis') 还原。

开发

npm run check       # 语法检查(src/ + src/tools/ + client/)
npm test            # 45 个用例;在线用例网络不通时自动跳过
npm run verify:http # 起假 webServer 打真实端点(需要能访问 asmr.one)

test/rank.test.mjs 用了一个取巧但不偷工的做法:它从 client/client.js 里把 #region rank-core 那段纯函数截出来再求值。被测的就是线上那一份代码,不存在 「测试跑的是另一份复制品」的漂移;谁把那段改成不纯(引用 window / react)会当场报错。 test/http-pending.test.mjs 则用假 api 顶掉 asmr.one,所以推歌链路离线也能验。

硬约束

运行期零依赖。 只 import Node 内置模块,dependencies 是空的。装了插件的人不需要 往插件目录里塞 node_modules 软链 —— 也就不会出现「在插件目录跑一次 npm install 却写进 宿主 node_modules」这类事故。src/define-tool.js 顶部有完整说明。

不内置内容偏好。 插件不预设任何题材倾向,性别过滤、排序、落盘目录全部来自可改的配置。

许可

MIT

—/ 5

No ratings yet

Verified DSH bundle

Commit 314d0e46c876

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout