Skip to content

feat: 插件 API 新增 playTrack 与 netease.request;并修复 splayer.request 的 Cookie 头静默失效 - #366

Closed
BB0813 wants to merge 2 commits into
SPlayer-Dev:devfrom
BB0813:feat/plugin-track-and-account-api
Closed

BB0813 wants to merge 2 commits into
SPlayer-Dev:devfrom
BB0813:feat/plugin-track-and-account-api

Conversation

@BB0813

@BB0813 BB0813 commented Oct 10, 2026 •

Copy link
Copy Markdown

给插件 API 加两个能力。动机是我想写一个与网易云官方「一起听」房间互通的控制插件(插件本体不在这个 PR 里,只作动机说明):让 SPlayer-Next 作为对等参与者进官方房间,和手机端 App / 官方电脑端听同一首歌。写的过程中撞到两个 API 缺口,所以一并提上来。


1. player.playTrack(track) —— 播放指定曲目(低风险)

PluginPlayerApi 目前只有 play / pause / next / prev / seek / setVolume / getPosition,没有任何办法让插件指定一首歌。需要按外部状态切歌的插件(一起听、远程遥控、定时电台、歌单自动切换)都会卡在这里。

改动很小,且落在已有的实现上:

  • shared/types/plugin.ts:PluginPlayerApi 加 playTrack(track: Track): void,HostCallMethod 加 "player.playTrack"
  • electron/main/plugins/host.ts:加一个 case,落到 playerControl.playTrack() —— MCP 的 play_track 工具本来就在用它,不是新逻辑
  • electron/main/plugins/host.worker.ts:splayer.player 加对应方法

权限沿用现有的 control(host 的门控是 method.startsWith("player.")),不新增门控。

2. splayer.netease.request(path, data) —— 以用户账号身份发请求(安全敏感,请重点审)

让插件借应用已登录的网易云会话调 /api/ 接口:宿主代发,插件拿不到 cookie 本身。

动机:插件沙箱读不到应用存在 SQLite(account_sessions 表)里的登录态,也读不到 Chromium cookie jar(应用的网易云客户端走 undici,不走 net.fetch)。所以任何要用网易云账号的插件,都得让用户再扫一次码、或者把 cookie 明文粘进插件设置。这个能力可以消掉这一步。

实现上是复用应用自己的请求层(createRequest 的 crypto: "api" 明文模式),因此 cookie 注入、客户端身份字段(osver / appver / versioncode …)、系统代理都是白拿的;新增的只是 electron/main/plugins/neteaseProxy.ts 这一层薄包装。

这部分的收敛措施:

  • 单独占一个权限 netease,没有挂在 network 下。 理由:network 是对所有音源插件自动授予的,如果挂在它下面,等于任何音源插件都能悄无声息地以用户账号身份操作网易云。独立权限是显式 opt-in,用户能在插件详情里直接看到「网易云账号」这一项。
  • 只放行明文 /api/ 路径,weapi / eapi 等加密入口不开放。
  • 应用本身未登录时以 PLUGIN_NOT_LOGGED_IN 失败。
  • 插件拿到的是响应体,不是凭据。

3. hostRequest 改用 credentials: "omit" —— 修一个静默失效(建议优先看这条)

写插件的过程中发现 splayer.request 有一个静默失效,与上面两个新能力无关,但影响所有设置 Cookie 头的插件:

默认 session 的 cookie jar 里只要存有该域名的 cookie,Chromium 就会用 jar 里的那份覆盖插件通过 headers.Cookie 设的值——插件设置的认证信息被静默丢弃。

我用一个不需要任何账号的实验钉死了它(同一个 session,往 jar 里预置 JARONLY):

请求头 服务端实际收到
只设 Cookie: EXPLICIT=… 只有 JARONLY,EXPLICIT 不见了
同上 + credentials: "omit" 只有 EXPLICIT ✅
不设 Cookie 头 自动带 JARONLY(符合预期)

这会形成一个自锁死循环:

  1. 插件的 cookie 过期、或还没配好 → 请求返回 401/业务错误;
  2. 这个响应会往默认 session 的 jar 里种下 cookie(实测:一次不带 cookie 的请求就够);
  3. 此后 jar 非空 → 插件设的 cookie 永远被丢弃 → 无论怎么重配、重启应用都不恢复。

对用户表现为「我明明填对了 cookie,插件一直说登录失效」。

修法是 net.ts 里的一行:credentials: "omit",关掉 cookie store 参与,让 splayer.request 只发插件显式设置的头。这也更符合文档里「网络只能经 splayer.request 发起」的语义——插件的请求应当是确定的,不该受宿主 Chromium 会话的隐式状态影响。

补丁里的 netease.request 本来就是宿主代发、不涉及这条;但它和这条是同一个根因面的问题,所以放在一起。如果这个 PR 只保留一处,我建议保留这一条。

⚠️ 风险声明

我知道这个 PR 有争议,把风险写在明面上:

  1. netease.request 实质扩大了插件的攻击面。 它把「以用户账号身份发请求」开放给了插件。虽然做了权限隔离和路径限制,但一个声明了 @grant netease 的插件仍可在用户不知情时操作其网易云账号(发评论、改收藏、退房间等)。现有插件模型是「安装即信任」,这个能力把误信一个插件的代价显著提高了——这一点我无法靠技术手段消除,只能靠权限名让它在安装时可见。

  2. 明文 /api/ 是社区实践路径,官方客户端走 weapi / eapi。这类接口的通断与风控策略由服务端决定,将来可能变化。我在真机上验证过 listen/together/*、song/detail、qrcode/unikey 等接口当前可用,但不保证长期稳定。

  3. HOST_API_LEVEL 3 → 4。 对存量插件是纯新增,老插件声明 ≤3 照常加载、行为不变;只有用到新能力的插件才需要声明 4。

  4. 我不了解项目对插件 API 的演进规划。这套改动可能和既定的方向不一致,或者你们本来就不打算开放这类能力。


我个人作为插件作者的态度

这个 PR 完全按需处理,不需要照顾我的感受。

如果维护者认为它:

  • 不合适 —— 和现有插件 API 的演进方向不一致;
  • 不安全 —— 尤其是 netease.request 这部分;
  • 没必要 —— 有别的做法,或者根本不想要这类插件;

请直接关闭这个 PR,我不会觉得被冒犯。 我只是把撞到的缺口提上来,判断权在维护者。

另外,这两个能力可以干净地拆开:

风险 拆开成本
playTrack 低 —— 纯 API 补全,落在既有实现上 —
netease.request 高 —— 需要权衡的那个 撤掉只需删 neteaseProxy.ts、PLUGIN_GRANTS 里一个词、host 里一段门控

如果只想要前者,我可以立刻把 netease.request 撤掉重提。


验证

  • pnpm typecheck(tsc + vue-tsc)全部通过
  • prettier 检查全部通过
  • 改动:12 个文件修改 + 1 个新增,+229 / −55
  • 插件侧我写了模拟宿主沙箱的测试,覆盖两个能力的「有 / 无」两种宿主:playTrack 缺失时降级到 MCP 回退,netease.request 缺失时降级到插件自带 cookie

主要涉及文件

electron/main/plugins/net.ts                       一行:credentials: "omit"
electron/main/plugins/neteaseProxy.ts              新增
electron/main/plugins/host.ts                      门控 + 两个 case
electron/main/plugins/host.worker.ts               两个命名空间
shared/types/plugin.ts                             PluginPlayerApi / PluginNeteaseApi / HostApi / HostCallMethod / PLUGIN_GRANTS
shared/defaults/plugin-api.ts                      HOST_API_LEVEL 3→4、NOT_LOGGED_IN
src/components/settings/custom/PluginDetailDialog.vue   新权限的图标
src/i18n/locales/{zh-CN,en-US}.json                新权限文案
docs/{,en/}plugins/index.md、docs/{,en/}plugins/control.md   文档

@BB0813 BB0813 changed the title feat: 插件 API 新增 playTrack 与 netease.request 两个能力 feat: 插件 API 新增 playTrack 与 netease.request;并修复 splayer.request 的 Cookie 头静默失效 Oct 10, 2026
@imsyy imsyy mentioned this pull request Oct 15, 2026
8 of 12 tasks
@imsyy imsyy closed this in #383 Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant