0. 需求来源
网易云音乐的 Mac 客户端,无法将播放记录同步到 Last.fm, 而且也不太想下载客户端。所以想听歌的时候一般都用网页版,还可以配合 Web Scrobbler 追踪播放记录。 (使用过程中还顺便提交了 两个 PR. )
但是网页版歌词无法在菜单栏上显示,只能在当前网页显示。所以搜了一圈找到一个 SwiftBar
开源工具,可以自定义菜单栏。 (后来发现也可以在播放条右边找到画中画歌词
按钮,可以开启一个画中画功能。搜了一下原理大概是不断将歌词绘制到一个 cavans
上,然后新建一个 video
元素,可以不 append 到页面中,直接通过 requestPictureInPicture
打开画中画。此为后话,有兴趣的可以深入了解。)
下面记录一下具体步骤。
1. 安装菜单栏自定义工具 SwiftBar
brew install swiftbar
下载慢?试试设置镜像:https://mirrors.tuna.tsinghua.edu.cn/help/homebrew/
2. 启动歌词推送服务器
// 先新建一个文件 main.go 放在哪里都行
package main
import (
"fmt"
"net/http"
"strings"
"sync"
"sync/atomic"
"time"
)
func main() {
type Client struct {
ID string
Ch chan string
}
var (
nextID = atomic.Int64{}
title = "" // 标题
by = "" // 艺术家
clients = sync.Map{} // 读取端 string -> *Client
actionCh = make(chan string, 1)
)
// 动作指令
http.HandleFunc("/action/send", func(w http.ResponseWriter, r *http.Request) {
var q = r.URL.Query()
var action = q.Get("action")
fmt.Printf(">> action = %v\n", action)
select {
case actionCh <- action:
default:
}
})
http.HandleFunc("/action/get", func(w http.ResponseWriter, r *http.Request) {
var action = "nop"
select {
case action = <-actionCh:
case <-time.After(10 * time.Second): // 10s 超时
}
fmt.Fprintln(w, action)
})
// 接收推送的歌词
http.HandleFunc("/set", func(w http.ResponseWriter, r *http.Request) {
var q = r.URL.Query()
if q.Has("title") { // 标题
title = q.Get("title")
by = q.Get("by")
fmt.Println()
fmt.Println()
fmt.Println(title + " - " + by)
fmt.Println()
}
if q.Has("current") { // 歌词
var lyrics = r.URL.Query().Get("current")
lyrics = strings.TrimSpace(lyrics)
fmt.Println(lyrics)
clients.Range(func(_, value any) bool { // 推送给所有的读取端
client := value.(*Client)
select {
case client.Ch <- lyrics:
default: // 推送失败忽略
}
return true
})
}
})
// 获取当前歌词
http.HandleFunc("/next", func(w http.ResponseWriter, r *http.Request) {
var (
lyrics = ""
client = &Client{
ID: fmt.Sprintf("%d", nextID.Add(1)),
Ch: make(chan string, 1),
}
)
clients.Store(client.ID, client)
defer func() {
clients.Delete(client.ID)
}()
select {
case lyrics = <-client.Ch: // 获取歌词
case <-time.After(10 * time.Second): // 10s 超时
}
fmt.Fprintln(w, "~~~") // 提醒 Swiftbar 刷新内容
if lyrics != "" { // 拿到了歌词就输出
fmt.Fprintln(w, lyrics)
if title != "" { // 如果有标题一起输出 点击歌词可以看到
fmt.Fprintln(w, "---")
fmt.Fprintln(w, title)
fmt.Fprintln(w, by)
}
} else { // 超时了
if title != "" {
fmt.Fprintln(w, title+" - "+by)
} else {
fmt.Fprintln(w, "未在播放")
}
}
})
fmt.Printf("服务已启动\n")
http.ListenAndServe(":51917", nil)
}
func log(format string, args ...any) {
fmt.Printf(format+"\n", args...)
}
# 然后启动它
go run main.go
3. 安装油猴插件将网页版歌词实时推送
点击 这里 安装。 或者打开 这个页面 再点击右上角的 Raw
也可(这种方式是最新脚本)。 `
4. 打开 SwiftBar 加载插件
先设置好插件目录,然后在插件目录中新建文件 163lyrics.sh
, 内容如下:
#!/usr/bin/env bash
# <bitbar.title>网易云音乐网页版歌词显示</bitbar.title>
# <bitbar.version>v1.1</bitbar.version>
# <bitbar.author>Youth.霖</bitbar.author>
# <bitbar.author.github>youthlin</bitbar.author.github>
# <bitbar.desc>网易云音乐网页版歌词显示</bitbar.desc>
# <bitbar.abouturl>https://gist.github.com/youthlin/be34fa9bb50b37ac39aa0ce59265632b/</bitbar.abouturl>
# <bitbar.droptypes>Supported UTI's for dropping things on menu bar</bitbar.droptypes>
# <swiftbar.runInBash>false</swiftbar.runInBash>
# <swiftbar.hideRunInTerminal>true</swiftbar.hideRunInTerminal>
# <swiftbar.hideLastUpdated>true</swiftbar.hideLastUpdated>
# <swiftbar.hideDisablePlugin>true</swiftbar.hideDisablePlugin>
# <swiftbar.type>streamable</swiftbar.type>
# 如果带参数 就执行动作 通过menu生成的菜单 点击时触发
if [[ "$1" = "action" ]]; then
# 发送控制指令
curl http://localhost:51917/action/send?action=$2 >/dev/null 2>&1
exit
fi
menu() { # 输出菜单
echo "上一曲 | terminal=false bash=$0 param0=action param1=prev"
echo "暂停/播放 | terminal=false bash=$0 param0=action param1=toggle"
echo "下一曲 | terminal=false bash=$0 param0=action param1=next"
}
refresh() { # 更新歌词
# 服务器总是以 ~~~ 开头 10s超时
curl http://localhost:51917/next 2>/dev/null && menu # 输出歌词、曲名、艺术家
# 如果输出歌词成功 补充菜单
}
fallback() { # 如果更新歌词失败
echo '~~~' # 刷新
echo '歌词推送服务器未启动'
sleep 1 # 1s后重试(外层调用时死循环)
}
echo '~~~'
echo '播放以显示歌词'
menu
while true; do
# streamable 表示该脚本会不断输出 遇到 ~~~ 表示刷新
refresh || fallback
done
效果
打开 https://music.163.com/ 播放,应该就能在菜单栏上看到歌词了。
如果没有登录,想要登录发现播放列表会遮挡登录组件,可以先暂停油猴脚本,因为脚本需要确保歌词界面打开,才能读取到当前歌词。 或者在控制台执行:
document.querySelector('#g_playlist .listbd').style.height='60px'
document.querySelector('#g_playlist').style.height='100px'
使播放列表高度变矮一些。
注:代码可以在这里找到
https://gist.github.com/youthlin/be34fa9bb50b37ac39aa0ce59265632b
声明
- 本作品采用署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。除非特别注明, 霖博客文章均为原创。
- 转载请保留本文(《将网易云音乐网页版歌词显示到 Mac 菜单栏》)链接地址: https://youthlin.com/?p=1851
- 订阅本站:https://youthlin.com/feed/