前段时间闲来无事开了个直播间做做直播,直播时总是有弹幕问我bgm是什么,奈何我的直播歌单是和朋友一起凑出来的,有些歌我也不知道歌名,再说逐一回复也麻烦,于是想着把bgm名直接显示在屏幕上。

其实要实现这一功能并不复杂,直接挂个音乐播放器的小窗在屏幕上或者是使用现有的软件就行了。然而我实在懒得额外下载软件,只想集成在本身常驻运行,且自己开发的工具箱里。再者,额外显示一个窗口属实略显冗杂,比起只显示一行文字来说属实影响画面观感。

综合以上几点,我所需要的是一个直接嵌入在直播工具(如obs)中显示,且自动识别更新的一行歌名显示功能。

OBS

要在obs中显示动态更新的文字其实很简单:obs的文字显示可以选择“从文件读取”,选定一个文本文件,文本标签中的文字就会自动更新为文件内容的文本(观感延迟大概一秒)。

所以程序部分只需实时获取播放器信息,然后更新到文本文件。

win32

由于要获取播放器信息,直觉能想到,音乐播放器会将当前播放歌曲的名字作为窗口标题。这里以我用的网易云音乐为例,鼠标移到窗口上后发现显示的果然是当前播放的歌曲名。

这样一来要获取当前播放名就很容易了,只需使用win32api获取窗口名就行。

python

这里先以python为例,首先 pip install pypiwin32

win32中获取窗口标题的函数为

1
win32gui.GetWindowText(handle)

需要传入一个窗体句柄,一般可以通过className来获取。所以在这之前,我们要先获取到音乐播放器的className。

在这里我用了 win32gui.GetForegroundWindow() 来获取最前方的窗口,然后在运行代码后给予一个延迟,再把网易云音乐的窗口置于最前,然后输出相关信息:

1
2
3
4
5
6
7
8
9
from time import sleep
from win32 import win32gui

sleep(3) #延迟3s,打开音乐播放器(如网易云音乐)窗口

current_window = win32gui.GetForegroundWindow()
classname = win32gui.GetClassName(current_window)
title = win32gui.GetWindowText(current_window)
print(f'classname: {classname} title: {title}')
1
OUT: classname: OrpheusBrowserHost title: Tomorrow will be fine. - Sodagreen

有了这些信息,我们就可以先使用 win32gui.FindWindow('OrpheusBrowserHost', None) 来获取到窗体句柄,然后直接获取到窗口标题:

1
2
3
4
from win32 import win32gui

handle = win32gui.FindWindow('OrpheusBrowserHost', None)
musicInfo = win32gui.GetWindowText(handle)

csharp

由于我的桌面小工具是csharp实现的,所以最后也给出一段csharp的完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
IntPtr handle = FindWindow("OrpheusBrowserHost", null);
StringBuilder title = new StringBuilder(256);
GetWindowText(handle, title, title.Capacity);

string _curMusicInfo = title.ToString();

if (_curMusicInfo.Equals(curMusicInfo)) return;

curMusicInfo = _curMusicInfo;

try
{
string startupPath = Application.StartupPath + @"/data/music-info.txt";
using (StreamWriter sw = new StreamWriter(startupPath))
{
sw.WriteLine("当前播放: " + curMusicInfo);
}
}
catch (Exception err) { }