跳转到内容
⌂ 回到首页

沙箱插件教程

工坊 沙箱插件本地插件 不是同一套运行时。本页讲 SDK 里的 plugin-package 从 hello 到联网 catalog。索引 → 创意工坊 SDK

sources:provide / sources:direct 只能暴露你有权提供的 HTTP(S) 直链,不是接入网易云、Spotify 等平台。法律说明 → 下载与插件音源法律边界

my-plugin/
├── echo.workshop.project.json
├── content/
│ ├── echo.workshop.json # 外层清单 + networkHosts(若联网)
│ └── community.echo # check/sync 生成,勿手改
├── src/
│ ├── plugin.js # 入口,你主要改这里
│ ├── panel.html / panel.js # complete / catalog 等预设可能有
│ └── …
└── .echo-sdk/
└── echo-workshop-plugin.d.ts

文件顶行建议保留类型引用:

/// <reference path="../.echo-sdk/echo-workshop-plugin.d.ts" />
  1. 拷贝示例:
    Terminal window
    node .\bin\echo-workshop-sdk.mjs example hello-plugin .\my-hello
    cd .\my-hello
  2. src/plugin.js:注册一条命令,调用 echo.playback.getStatus(),弹 echo.ui.notify
  3. 权限只有 playback:read。若加 echo.library.*,须先:
    Terminal window
    npm run add -- --permission library:read
  4. 每次改完:
    Terminal window
    npm run check
    sync 会把 src/ 打进 content/community.echo 并重算哈希。
  5. npm run dev 在 mock host 里点 fixture;未声明的 echo.* 调用会 capability-denied

最小插件逻辑示例:

echo.commands.register('hello-echo', { title: 'Hello ECHO' }, async () => {
const status = await echo.playback.getStatus();
await echo.ui.notify(
status.currentTrackId
? '插件已连接,当前有歌在播。'
: '插件已连接,还没有播放。'
);
});

启用后用户要在 ECHO 右下角 插件 里找到命令;订阅工坊后还须点 使用,见 Steam 创意工坊

适合作者自托管 JSON API + 直链音频,不是平台爬虫。

  1. 按 recipe 新建:
    Terminal window
    node .\bin\echo-workshop-sdk.mjs init .\my-catalog --recipe source-catalog
    cd .\my-catalog
  2. 默认已有 sources:providesources:directfs:plugin 等权限;联网还要:
    Terminal window
    npm run add -- --permission network:request
  3. 在外层 content/echo.workshop.json(或通过项目配置)声明 networkHosts,例如你的 API 域名(纯域名,无 https://、无端口)。
  4. src/plugin.js 注册 provider,实现 search / browse / listCollection / resolve
    • 前三者只返回条目列表;
    • resolve 必须返回一条可播放的 http/https 直链
  5. npm run check — mock 会拒绝未在 networkHosts 里的域名和自定义端口。
  6. 用户第一次播某域名时,ECHO 还会再确认来源。

Provider 骨架(域名换成你的,且须在 networkHosts 中):

echo.sources.registerProvider('owned-catalog', { title: '我的目录' }, {
search: async ({ query, page, pageSize }) => {
const res = await echo.network.get(
`https://audio.example.com/catalog?q=${encodeURIComponent(query || '')}&page=${page}&pageSize=${pageSize}`
);
const payload = JSON.parse(res.body);
return {
tracks: payload.tracks ?? [],
total: payload.total ?? 0,
hasMore: payload.hasMore === true,
};
},
resolve: async ({ providerTrackId }) => {
const res = await echo.network.get(
`https://audio.example.com/resolve/${encodeURIComponent(providerTrackId)}`
);
const payload = JSON.parse(res.body);
return { url: payload.url, title: payload.title, artist: payload.artist };
},
});

不要填 Cookie、Token、Steam Guard;不要解析平台网页冒充官方曲库;不要自建播放后端绕过 Audio Core。

--preset / recipe包含能力
basic / hello 示例单命令
complete / plugin-complete命令、面板、Agent、metadata/lyrics/source 提供器
catalog / source-catalog直链目录 + 面板
lyrics / lyrics-source歌词 provide + 当前歌词面板

复杂项目先用 snippet list 复制片段,再 npm run next 看还能加什么权限。

Terminal window
node .\bin\echo-workshop-sdk.mjs api
node .\bin\echo-workshop-sdk.mjs api echo.queue.moveItem
node .\bin\echo-workshop-sdk.mjs api errors
常见权限用途
playback:read读播放状态
playback:control播放/暂停/切歌等
library:read分页读曲库公开字段
sources:provide注册音源 provider
sources:directresolve 返回直链
network:requestecho.network.*(须配 networkHosts)
lyrics:provide歌词候选
lyrics:read读当前清理后歌词文本
fs:plugin插件私有存储
agent:runtimeAgent 能力(complete 预设)

用户拒绝直链或一起听上传后不得循环弹窗;限流、只读保护才可退避重试(见 api errors)。

  • 最多 32 文件,单文件 512 KiB,整包 2 MiB
  • 内层 manifest.apiVersion 必须与外层 compatibility.pluginApiVersion 一致(新项用 2)。
  • 扩展名限 .css.html.js.mjs.json

插件创作指南 讲主程序 plugins/ 目录与更宽的 API 面。工坊包 不要 按那份文档改 community.echo 结构或假设有 Node / SQLite 访问。

本地插件页 → 工坊:重新用 SDK init --recipe …,不要直接复制文件夹到 Steam。

进阶能力:metadata、歌词、一起听

Section titled “进阶能力:metadata、歌词、一起听”

完整示例清单 → 官方示例与片段。下面是三类常见进阶插件能力。

用户选歌时,宿主向 provider 要候选,由用户决定是否采用;插件不能自动改库。

echo.metadata.registerProvider('clean-tags', { title: '标签候选' }, async ({ track }) => ({
candidates: [{ title: track.title, artist: track.artist, album: track.album, source: '作者目录', confidence: 0.7 }],
}));

需声明 metadata provider 贡献 + 对应权限(见 examples/metadata-provider/snippet list)。

JSON 歌词场面 不同:这是动态歌词候选,供宿主歌词选择器使用。

Terminal window
node .\bin\echo-workshop-sdk.mjs init .\my-lyrics --recipe lyrics-source
node .\bin\echo-workshop-sdk.mjs snippet lyrics-provider

lyrics:provide 只提交候选;保存、同步、播放仍由 ECHO 拥有。读当前曲清理后歌词文本用 lyrics:read(不含路径或账号)。

API 2 下上传当前本地曲到作者声明的上传 URL(不是把文件路径交给插件)。

  • 权限:playback:share + network:request
  • networkHosts 必须包含上传域名
  • 用户拒绝上传后不得自动重试弹窗

参考 examples/listen-together/plugin.js。生产环境会先解析公网地址再连接,并保留 Host/TLS 身份。

  • npm run check 全绿,fixture 通过
  • 权限列表与用户看到的授权框一致,能少则少
  • networkHosts 与代码里实际请求的域名一致
  • README 写清数据来源与用户需确认的直链性质
  • 创作台校验通过后发布