Skip to content

feat: ClassIsland 支持 - #49

Closed
WindDrift wants to merge 2 commits into
SPlayer-Dev:devfrom
WindDrift:dev
Closed

WindDrift wants to merge 2 commits into
SPlayer-Dev:devfrom
WindDrift:dev

Conversation

@WindDrift

@WindDrift WindDrift commented Jun 24, 2026 •

Copy link
Copy Markdown

背景

SPlayer-Next 当前已具备桌面歌词、灵动岛、任务栏歌词等"本应用内"的歌词展示能力,但无法将歌词推送到班级大屏课表软件 ClassIsland 主界面。

ClassIsland 生态已有成熟的 LyricsIsland 协议:

  • ExtraIsland 插件(ClassIsland 插件)作为 HTTP 服务器,监听 http://127.0.0.1:50063/
  • LyricsIslandBNCM(网易云音乐 BetterNCM 插件)作为客户端,向上述地址推送歌词

本 PR 让 SPlayer-Next 作为该协议的客户端,复用 ClassIsland 主界面这一展示位,扩大应用的使用场景。

image image

改动内容

新增

  • electron/main/services/lyricsIsland.ts:LyricsIsland 协议客户端核心服务
    • 订阅 nowPlaying 的 track-change / lyric-change / lyric-offset-change / position-sync 事件
    • 歌曲切换时推送歌名 + 歌手
    • 歌词行变化时推送当前行原文 + 翻译/下一行
    • 请求失败静默处理(ClassIsland 未运行时不影响播放)

修改

  • shared/types/settings.ts:新增 LyricsIslandSettings 接口,SystemConfig 新增 lyricsIsland 字段
  • shared/defaults/settings.ts:新增 lyricsIsland 默认值(enabled: false、port: 50063、showTranslation: true、showNextLine: true)
  • electron/main/services/nowPlaying.ts:onTrackChange / onLyricChange / onPositionSync / onLyricOffsetChange 四个订阅方法改为返回取消订阅函数(便于服务清理资源)
  • electron/main/utils/logger.ts:新增 lyricsIslandLog scoped logger
  • electron/main/core/index.ts:app.whenReady 中调用 initLyricsIsland(),before-quit 中调用 disposeLyricsIsland()
  • src/settings/categories/externalLyric.ts:新增"ClassIsland 联动"section(带 Beta 标签),含总开关与三个子项
  • src/i18n/locales/zh-CN.json / en-US.json:新增中英文文案

实现细节

协议一致性

  • 请求路径:POST /component/lyrics/lyrics/(与 ExtraIsland LyricsIslandLyricsProvider.cs 一致)
  • 请求体:{ "lyric": "<主歌词>", "extra": "<次级歌词>" }
  • 默认端口:50063(与 ExtraIsland、LyricsIslandBNCM base.js 一致)
  • 歌曲切换时发送歌名 + 歌手(与 LyricsIslandBNCM lyric.js 行为一致)

配置变更即时生效

服务在事件回调中实时读取 store.get("lyricsIsland.enabled") 等配置,用户在设置页切换开关后无需重启应用即可生效。

歌词行定位逻辑

  • 用 position + lyricOffsetMs 作为查找时间(支持用户调整的歌词偏移)
  • 遍历 LyricLine[] 找到 startTime <= time 的最大索引行
  • 仅当行索引变化时发送请求(避免高频 HTTP 请求)
  • 次级歌词优先级:翻译 > 下一行原文 > 空字符串

节流策略

  • position-sync 频率约 5Hz,但只在歌词行索引变化时发 HTTP 请求
  • HTTP 请求失败静默处理,不重试(避免 ClassIsland 未运行时日志爆炸)

使用说明

  1. 在 ClassIsland 中安装 ExtraIsland 插件(提供 LyricsIsland 协议服务端)
  2. 打开 SPlayer-Next → 设置 → 外部歌词 → ClassIsland 联动
  3. 开启"启用 ClassIsland 联动"开关
  4. 播放音乐,歌词将显示在 ClassIsland 主界面

可选配置:

  • 端口:默认 50063,一般无需修改
  • 显示翻译:次级歌词优先显示翻译歌词
  • 显示下一行:无翻译时显示下一行原文

测试验证

  • pnpm typecheck:node 通过
  • pnpm typecheck:web 通过
  • pnpm lint 通过
  • pnpm dev 构建启动成功
  • Windows 构建 测试通过

设计决策

为什么放在主进程?

  1. nowPlaying 服务在主进程,可直接订阅其 EventEmitter,无 IPC 开销
  2. HTTP 请求在主进程发送,不阻塞渲染层
  3. 与现有 lastfm、externalApi 等主进程服务架构一致
  4. 配置通过主进程 store 读取,无需额外 IPC

为什么不用现有的外部 API(HTTP+WS)服务器?

外部 API 是"被动响应外部请求",而 LyricsIsland 需要"主动推送"给 ClassIsland。两者方向相反,且外部 API 默认关闭、端口可配,不适合作为 LyricsIsland 的载体。

Edit

  • 换了一张图片以体现翻译行在 ClassIsland 主界面歌词副行的效果。
  • 加了一张图片以体现新增的设置项。

@imsyy

imsyy commented Jun 26, 2026

Copy link
Copy Markdown
Member

@WindDrift

WindDrift commented Jun 26, 2026 •

Copy link
Copy Markdown
Author

现已尝试通过插件形式实现本 PR 功能,可以试试功能正常不( https://splayer-next.imsyy.top/plugins/control.html#%E5%AE%8C%E6%95%B4%E7%A4%BA%E4%BE%8B

插件实现功能正常,将继续以插件形式开发,本 PR 将关闭。

Edit:插件已发布 SPlayerLRC-In-ClassIsland

@WindDrift WindDrift closed this Jun 26, 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.

2 participants