SPlayer WebSocket API 完整指南:实时控制播放器与接收播放状态
2026/9/16 19:14:30 网站建设 项目流程

SPlayer WebSocket API 完整指南:实时控制播放器与接收播放状态

【免费下载链接】SPlayer🎵 A cross-platform music player with Jellyfin / Navidrome / Emby media server support, word-by-word lyrics, desktop & taskbar lyrics, cloud music drive, local library management, audio spectrum visualization and mobile-friendly UI. 简约的跨平台音乐播放器,支持逐字歌词、桌面歌词、任务栏歌词、云盘音乐、本地音乐管理及流媒体播放项目地址: https://gitcode.com/GitHub_Trending/spl/SPlayer

导读

本文档系统讲解 SPlayer(基于 Vue 3 + TypeScript + Electron 的跨平台音乐播放器)内置的 WebSocket 本地服务:通过ws://localhost:25885建立双向实时通信,客户端既可以下发play/pause/next/prev等控制命令远程操纵播放器,也能实时订阅歌曲切换、播放进度、歌词数据等状态广播。阅读本文后,你将能够编写自己的 WebSocket 客户端(如桌面小组件、智能家居面板、脚本或移动端遥控器),在数分钟内接入 SPlayer 的播放控制与状态监控能力。

WebSocket API 概览

SPlayer 在 Electron 主进程中内置了一个基于ws库的 WebSocket 服务器(核心实现见 SocketService.ts),专门用于对外提供实时双向通信能力:

  • 基础路径ws://localhost:25885(默认端口,可在设置中修改,范围为 1~65535)
  • 服务模式:仅在 Electron 桌面端生效,监听127.0.0.1回环地址,属于本地服务
  • 默认状态:默认关闭,需在「设置 → 网络 → WebSocket 配置」中手动开启;开启后每次启动应用会自动拉起服务
  • 消息载体:所有业务消息均为 JSON 文本帧;心跳检测使用裸文本PING/PONG

从 electron/main/store/index.ts 与defaults配置可见,WebSocket 相关状态在本地持久化存储中的结构为:

websocket: { enabled: false, // 是否启用 port: 25885, // 监听端口 }

在设置界面启用并配置服务

WebSocket 服务默认不启动。在 SPlayer 的「设置 → 网络」分组中找到WebSocket 配置区块(实现见 network.ts),包含三个配置项:

配置项类型说明
启用 WebSocket开关开启后可通过 WebSocket 获取状态或控制播放器
WebSocket 端口数字输入(1~65535)更改后需要测试并保存才能生效;服务运行时该输入框被禁用
测试端口配置按钮("测试并保存")仅在端口值与已保存值不一致时显示

启用流程遵循"先测试、再启用"的安全逻辑(对应 network.ts):

  1. 输入新的端口号;
  2. 点击测试并保存:应用会通过 IPC 通道socket-test-port调用主进程的testPort()检测端口是否可绑定(实现见 SocketService.ts),检测到EADDRINUSE(端口被占用)或EACCES(权限不足)即判定不可用,测试成功才把配置写入本地存储;
  3. 打开启用 WebSocket开关:应用通过 IPC 通道socket-start启动服务(见 ipc-socket.ts),启动成功后持久化{ enabled: true, port },此后每次应用启动都会调用SocketService.tryAutoStart()自动恢复服务(见 electron/main/index.ts)。

如果启动时端口已被占用,服务会自动把websocket.enabled重置为false,避免下次启动再次失败(见 SocketService.ts)。

建立连接

在服务已开启的前提下,任意 WebSocket 客户端都可以直连:

const ws = new WebSocket("ws://localhost:25885");

连接成功后,服务器会自动发送一条welcome欢迎消息(见handleClientConnection中的sendWelcome,SocketService.ts),客户端可据此确认握手完成。

提示:服务绑定的是127.0.0.1,因此仅本机可访问;如需局域网内遥控播放器,需要在系统层面做端口转发或反向代理,SPlayer 默认不开放外部访问。

消息协议总览

所有业务消息统一采用如下 JSON 信封格式:

{ "type": "消息类型", "data": {} }

其中type为必填字段,data为可选载荷。按方向划分,协议包含三类消息:

  • 客户端 → 服务器(请求)control(播放控制)、get-song-info(获取当前歌曲信息);
  • 服务器 → 客户端(响应)control-responsesong-infoerror
  • 服务器 → 客户端(广播)welcomestatus-changesong-changeprogress-changelyric-change
  • 心跳:客户端发送文本PING,服务器回复文本PONG

服务端对消息的解析与分发逻辑位于 SocketService.ts:先做PING判定,再尝试JSON.parse,接着校验"根对象必须是非数组对象"、"必须包含type字段",最后按type分发到对应的处理函数,未知类型会返回error

控制播放器

消息类型control

请求格式

{ "type": "control", "data": { "command": "toggle|play|pause|next|prev" } }

命令说明

命令作用底层 IPC 事件
toggle播放/暂停切换playOrPause
play播放play
pause暂停pause
next下一曲playNext
prev上一曲playPrev

命令到 IPC 事件的映射关系见 SocketService.ts:handleControlCommand收到命令后,通过mainWin.webContents.send(ipcEvent)把指令转发给渲染进程,由前端播放器状态机真正执行操作。执行前会校验主窗口是否存在(未初始化或已销毁则报错应用程序未找到或已销毁)。

成功响应

{ "type": "control-response", "data": { "success": true, "command": "toggle", "message": "播放/暂停切换命令已执行" } }

错误响应

{ "type": "error", "data": { "message": "错误信息" } }

获取当前播放信息

消息类型get-song-info,无需data字段:

{ "type": "get-song-info" }

服务端收到后,会通过 IPC 链路向渲染进程请求当前曲目快照(见 track-info.ts 与 initIpc.ts):主进程发送request-track-info,渲染进程汇总播放状态、当前歌曲对象与歌词数据后以return-track-info回复,整个过程有 2 秒超时保护,超时返回获取当前播放信息失败

成功响应

{ "type": "song-info", "data": { "playStatus": "play", "playName": "歌曲名", "artistName": "歌手名", "albumName": "专辑名", "currentTime": 123.45, "volume": 1, "playRate": 1, "id": 123456, "name": "歌曲名", "artists": "歌手名", "album": "专辑名", "cover": "http://...", "duration": 300, "lrcData": [], "yrcData": [] } }

字段含义补充说明(依据 initIpc.ts 的组装逻辑):

字段含义来源
playStatus播放状态(如play/pause播放器状态 store
playName/artistName/albumName当前曲目的名称/歌手/专辑(格式化展示用)getPlayerInfoObj()
currentTime当前播放进度(秒)播放器状态 store
volume音量(0~1)播放器状态 store
playRate播放倍率播放器状态 store
id/name/artists/album/cover/duration当前歌曲对象的原始字段(展开playSong音乐 store
lrcData/yrcData普通歌词 / 逐字歌词数组歌词 store(歌词未加载完成时返回空数组)
lyricLoading/lyricIndex歌词加载状态与当前行索引(附加字段)歌词 store

错误响应

{ "type": "error", "data": { "message": "获取当前播放信息失败" } }

事件广播

当播放器状态发生变化时,服务器会向所有已连接客户端广播消息。广播统一走SocketService.broadcast()(SocketService.ts),其内部会遍历客户端集合,仅向OPEN状态的连接发送,并统计成功/失败数量写入日志。广播的触发入口集中在 ipc-socket.ts,由渲染进程通过play-status-changeplay-song-changeplay-lyric-changeset-progress等 IPC 事件驱动。

欢迎消息

连接成功后服务器自动发送:

{ "type": "welcome", "data": { "message": "欢迎连接到 SPlayer WebSocket 服务", "timestamp": 1234567890123 } }

播放状态更新

当播放/暂停状态改变时触发(渲染进程sendPlayStatusplay-status-change,见 PlayerIpc.ts):

{ "type": "status-change", "data": { "status": true, "timestamp": 1234567890123 } }

status为布尔值:true表示播放中,false表示暂停。

歌曲信息更新

当切换歌曲或歌曲信息加载完成时触发(渲染进程sendSongChangeplay-song-change,见 PlayerIpc.ts):

{ "type": "song-change", "data": { "title": "歌曲名 - 歌手", "name": "歌曲名", "artist": "歌手", "album": "专辑名", "duration": 240000, "timestamp": 1234567890123 } }

注意duration单位为毫秒(ms),与song-info中按秒计量的duration不同。

播放进度更新

播放过程中实时触发。渲染进程通过sendSocketProgress500ms 节流的频率推送(见 PlayerIpc.ts),因此实际广播间隔约 500ms:

{ "type": "progress-change", "data": { "currentTime": 12000, "duration": 240000, "timestamp": 1234567890123 } }

currentTimeduration单位均为毫秒。服务端收到set-progress时会校验currentTimeduration是否都已提供,缺一即丢弃(见 ipc-socket.ts)。

歌词更新

当歌词数据加载或改变时触发(渲染进程sendLyricplay-lyric-change,同样带 500ms 节流,见 PlayerIpc.ts):

{ "type": "lyric-change", "data": { "lrcData": [], "yrcData": [], "timestamp": 1234567890123 } }

lrcData为普通(逐行)歌词数据,yrcData为逐字歌词数据。服务端只有在两者之一非空时才进行广播(见 ipc-socket.ts),避免无歌词时产生无意义消息。

心跳检测

为避免长连接被中间设备或操作系统回收,客户端可以定期发送文本消息PING,服务器会立即自动回复文本消息PONG

// 发送心跳(建议每 20~30 秒一次) ws.send("PING"); // 服务器自动回复 PONG ws.onmessage = (event) => { if (event.data === "PONG") { console.log("心跳正常"); } };

服务端的实现非常轻量:在handleMessage中对消息做trim().toUpperCase()后直接与"PING"比较,匹配则向该连接回发"PONG"并提前返回,不进入 JSON 解析流程(见 SocketService.ts)。客户端可以据此实现断线自动重连逻辑。

错误处理与常见错误

服务端在以下场景会向客户端发送error消息:

{ "type": "error", "data": { "message": "错误描述信息" } }

常见错误及触发条件汇总:

错误消息触发条件
应用程序未找到或已销毁主窗口未初始化或已被销毁(控制命令无法转发到渲染进程)
缺少 command 参数control消息的data中没有command字段
未知的控制命令command不在toggle/play/pause/next/prev之内
消息格式错误,请发送有效的 JSON 格式消息消息无法被JSON.parse解析(附带原始消息前 100 字符便于排查)
消息格式错误,根对象必须是对象类型根对象是数组或非对象类型
消息格式错误,缺少 type 字段对象中没有type字段
未知的消息类型: xxxtype不在control/get-song-info之内
获取当前播放信息失败渲染进程未返回歌曲信息或 2 秒内超时

客户端最佳实践:收到error后检查data.message做对应处理;连接意外关闭时(onclose)结合PING/PONG心跳做指数退避重连。

完整客户端示例

以下代码演示一个可直接运行的 WebSocket 控制端:连接后自动获取当前歌曲信息,发送控制命令,并实时打印各类状态广播。

const ws = new WebSocket("ws://localhost:25885"); // 连接成功后:获取歌曲信息 + 执行播放/暂停切换 ws.onopen = () => { console.log("已连接 SPlayer WebSocket 服务"); // 获取当前播放信息 ws.send(JSON.stringify({ type: "get-song-info" })); // 播放/暂停切换 ws.send( JSON.stringify({ type: "control", data: { command: "toggle" }, }), ); // 下一曲 ws.send( JSON.stringify({ type: "control", data: { command: "next" }, }), ); }; // 接收消息 ws.onmessage = (event) => { // 心跳回复是纯文本 PONG,先做文本判断 if (event.data === "PONG") return; const message = JSON.parse(event.data); switch (message.type) { case "welcome": console.log("欢迎消息:", message.data.message); break; case "song-info": console.log("当前歌曲:", message.data.playName, "-", message.data.artistName); break; case "control-response": console.log("控制命令已执行:", message.data.command); break; case "status-change": console.log("播放状态:", message.data.status ? "播放中" : "已暂停"); break; case "song-change": console.log("切换歌曲:", message.data.title); break; case "progress-change": console.log("进度:", message.data.currentTime, "/", message.data.duration, "ms"); break; case "lyric-change": console.log("歌词已更新:", message.data.lrcData, message.data.yrcData); break; case "error": console.error("发生错误:", message.data.message); break; default: console.log("收到消息:", message); } }; // 心跳:每 25 秒发送一次 PING setInterval(() => { if (ws.readyState === WebSocket.OPEN) ws.send("PING"); }, 25000); // 断线自动重连(简单实现) ws.onclose = () => { console.log("连接断开,3 秒后重连..."); setTimeout(() => { location.reload(); // 在浏览器/Node 场景改为重新 new WebSocket(...) }, 3000); };

底层实现要点

  • 单例服务SocketService采用单例模式,SocketService.getInstance()全局唯一;isRunning()/getPort()分别暴露运行状态与当前端口,供 IPC 层查询(SocketService.ts)。
  • 端口可用性预检:启动前先用net.createServer()探测端口,捕获EADDRINUSE/EACCES即判定不可用(SocketService.ts),避免WebSocketServer启动即报错。
  • 连接生命周期管理:服务用Set<WebSocket>维护在线客户端;连接建立时加入集合、发送欢迎消息;close时移除;stop()时先逐个关闭客户端再关闭服务并清理(SocketService.ts)。
  • 全链路广播链路:渲染进程(Vue 播放器)→ IPC(play-status-change/play-song-change/play-lyric-change/set-progress)→ 主进程 ipc-socket.ts →SocketService.broadcast()→ 所有 WebSocket 客户端。换言之,客户端收到的每条广播最终都源自播放器状态 store 的变更,数据一致性有保障。
  • 配套 HTTP API:WebSocket 服务与 SPlayer 的本地 HTTP API 服务(默认端口25884,见 docs/api.md)并存互补——HTTP 适合一次性请求/轮询,WebSocket 适合实时控制与订阅。两者共享同一套播放控制能力,可混合使用。

相关文档

  • SPlayer 使用指南:播放器整体功能与操作说明
  • 本地 HTTP API 接口文档:25884端口的 REST 控制接口
  • SocketService 核心实现:WebSocket 服务端完整源码
  • WebSocket IPC 桥接层:IPC 事件与广播消息的映射
  • 网络设置(含 WebSocket 配置):设置界面中 WebSocket 开关、端口与测试逻辑
  • 渲染进程 IPC 封装:request-track-info/return-track-info的歌曲信息组装逻辑

【免费下载链接】SPlayer🎵 A cross-platform music player with Jellyfin / Navidrome / Emby media server support, word-by-word lyrics, desktop & taskbar lyrics, cloud music drive, local library management, audio spectrum visualization and mobile-friendly UI. 简约的跨平台音乐播放器,支持逐字歌词、桌面歌词、任务栏歌词、云盘音乐、本地音乐管理及流媒体播放项目地址: https://gitcode.com/GitHub_Trending/spl/SPlayer

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询