OBS Studio 显示正在播放的歌曲 in Linux
为了能在 Linux 下直播时显示正在播放的歌曲,我写了个简单的 Shell 脚本。

前言

前言的前言

欢迎大家关注我的 bilibili 帐号:bili-Amazingrise

不定期直播搬砖,游戏,或者其他有趣的东西~

缘由

为了能在直播的时候,显示我正在播放的歌曲,我想了很多的方法。

看到了 KDE Connect 里面能显示正在播放的歌曲,我觉得一定可以很容易地获取到当前媒体的状态信息。

另外,这篇文章的诞生也是受到这位的启发:获取 macOS 网易云音乐的正在播放 —— 使用 LLDB 验证思路 (没错,就是这个主题的原作者。)

正文

原理

当然,我们的 Linux 没有那么复杂,用一个 Shell 脚本就能读取到当前播放的媒体。

由于 OBS Studio 支持从文本文件读取文字内容,并且显示在输出流上,我们可以用 Shell 脚本先读出当前播放的媒体信息,然后再将它写入某个文件里,最后让 OBS Studio 读取这个文件就可以了。

以我用的 Electron Netease Cloud Music 为例。

在 Linux 中,显示正在播放是通过调用 dbus mpris API 实现的。

仔细看该项目的源代码,可以找到这几行

const i = {
    name(suffix) {
        if (suffix) return `org.mpris.MediaPlayer2.${suffix}`;
        return 'org.mpris.MediaPlayer2';
    },
    path(suffix) {
        if (suffix) return `/org/mpris/MediaPlayer2/${suffix}`;
        return '/org/mpris/MediaPlayer2';
    }
};

我们可以获取到它的 dbus 路径(?暂且这么称呼),这个在后面会有用。

那么当前媒体的元数据(metadata)的形式是怎么样的呢?

于是我们用上面获取到的 dbus 路径,来获取到当前媒体的元数据。

dbus-send --print-reply --dest=org.mpris.MediaPlayer2.ElectronNCM /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:org.mpris.MediaPlayer2.Player string:Metadata

然后我们会得到这样一段结果:

method return time=1578801147.817851 sender=:1.89 -> destination=:1.303 serial=100 reply_serial=2
   variant       array [
         dict entry(
            string "mpris:trackid"
            variant                object path "/org/mpris/MediaPlayer2/1475050"
         )
         dict entry(
            string "mpris:length"
            variant                int64 164000000
         )
         dict entry(
            string "mpris:artUrl"
            variant                string "https://p1.music.126.net/QfpBYZjsztHjucFAIxfDgQ==/1746024464908302.jpg"
         )
         dict entry(
            string "xesam:album"
            variant                string "Working Class Hero: The Definitive Lennon"
         )
         dict entry(
            string "xesam:artist"
            variant                array [
                  string "John Lennon"
               ]
         )
         dict entry(
            string "xesam:discNumber"
            variant                int16 0
         )
         dict entry(
            string "xesam:title"
            variant                string "Oh My Love"
         )
         dict entry(
            string "xesam:trackNumber"
            variant                int16 9
         )
      ]

从结果中我们可以找到我们想要的信息:歌手,标题等等。

最后,我们只需要用正则表达式提取一下就🉑️️了。

实现

正则表达式 当时鼓捣了好久, 能用就行。

下面是具体的 Shell 脚本实现。

#/bin/sh!

echo "Song Daemon is running......"

PREFIX="Rise 正在播放:"
FILENAME="/tmp/songdaemon"
NOSONG="当前没有播放歌曲"
echo "$NOSONG" > $FILENAME

while [ : ]
do
	ARTIST=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.ElectronNCM /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:org.mpris.MediaPlayer2.Player string:Metadata | sed -n '/artist/{n;n;p}' | cut -d '"' -f 2) 2>/dev/null

	NAME=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.ElectronNCM /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:org.mpris.MediaPlayer2.Player string:Metadata | sed -n '/title/{n;p}' | cut -d '"' -f 2) 2>/dev/null

	# 其中 dest 参数为我的音乐播放器的名称,这是我翻源代码翻出来的。

	if [ "$NAME" == "" ]
	then
		CONTENT="$NOSONG"
	else
		CONTENT="$PREFIX $NAME - $ARTIST"
	fi
	if [ "$CONTENT" == "$(cat $FILENAME)" ]
	then
		sleep 1;
	else
		echo "$CONTENT" > $FILENAME
	fi
done

OBS Studio 怎么设置显示文件内容,我就不在此赘述了。

后记

不禁感叹一句,Linux 下获取正在播放的媒体可比 macOS 简单多了。

其实这篇文章应该是很早就写完的(脚本是2019年10月1号写完的)。但是由于本人工作繁忙,加上事情特别多,根本顾不上水这篇博文。

当时水了一些别的文章,总之这篇文章就留到了今年。

希望对各位有所帮助。

又水完一篇博客,好开心。


上次修改於 2020-01-12