是否有标准方法来查询流媒体广播服务当前正在播放的歌曲?
我目前正在为每个电台以不同的方式实现这一点,例如 SomaFM:
$wg=join("\n",`wget -q -O - https://somafm.com/secretagent/songhistory.html`);
$wg=~/\(Now\).*>([^<]*)<\/a><\/td><td>([^<]*)/s;
print "Secret Agent\n$1\n$2\n"
或Radio Svizzera Classica:
$wg=join("\n",`wget -q -O - http://www.radioswissclassic.ch/en`);
$wg=~/On Air.*?titletag">([^<]*).*?artist">([^<]*)/s;
print "Radio Svizzera Classic\n$1\n$2\n"
是否有解析 HTML 页面的标准化替代方案,当布局更改时可能会中断?
对于具有 ICY 元数据的 SHOUTcast/Icecast 风格电台(构成互联网广播电台的大部分),最好的办法是从流本身获取此数据。
首先,您需要一个实际流的 URL。 如果您访问 SomaFM 的 Secret Agent 页面 http://somafm.com/secretagent/,您将看到在其他播放器中收听的链接。 作为示例,我们使用 128k AAC 链接,该链接指向 http://somafm.com/secretagent130.pls。 这不是实际的流...它是一个播放列表文件,其中包含指向实际流的链接。 在您最喜欢的文本或代码编辑器中打开它,看看我的意思:
[playlist]
numberofentries=2
File1=http://ice1.somafm.com/secretagent-128-aac
Title1=SomaFM: Secret Agent (#1 ): The soundtrack for your stylish, mysterious, dangerous life. For Spies and PIs too!
Length1=-1
File2=http://ice2.somafm.com/secretagent-128-aac
Title2=SomaFM: Secret Agent (#2 ): The soundtrack for your stylish, mysterious, dangerous life. For Spies and PIs too!
Length2=-1
Version=2
互联网广播电台通常包含多个服务器以进行故障转移。 如果听者与一个项目断开连接,玩家通常会滚动到下一个项目。 当一台服务器达到其侦听器限制时,这也很有用...玩家(希望)最终会到达另一台处于活动状态的服务器。
无论如何,启动 Wireshark 或其他数据包嗅探器的副本。 点击音频播放器中的 URL 之一,然后检查流量。 我们首先要查看的是请求和响应。
GET /secretagent-128-aac HTTP/1.1
Host: ice1.somafm.com
User-Agent: VLC/2.2.4 LibVLC/2.2.4
Range: bytes=0-
Connection: close
Icy-MetaData: 1
HTTP/1.0 200 OK
Content-Type: audio/aacp
Date: Sat, 20 May 2017 20:43:56 GMT
icy-br:128
icy-genre:Various
icy-name:Secret Agent from SomaFM [SomaFM]
icy-notice1:<BR>This stream requires <a href="http://www.winamp.com/">Winamp</a><BR>
icy-notice2:SHOUTcast Distributed Network Audio Server/Linux v1.9.5<BR>
icy-pub:0
icy-url:http://SomaFM.com
Server: Icecast 2.4.0-kh3
Cache-Control: no-cache, no-store
Pragma: no-cache
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, Accept, X-Requested-With, Content-Type
Access-Control-Allow-Methods: GET, OPTIONS, HEAD
Connection: Close
Expires: Mon, 26 Jul 1997 05:00:00 GMT
icy-metaint:45000
这些互联网广播服务器要么是 HTTP(在 Icecast 等情况下),要么是非常接近 HTTP(传统 SHOUTcast),并接受正常的
GET
请求。 在这种情况下,我的播放器 (VLC) 发出 GET
请求 /secretagent-128-aac
,这是实际流的路径。
我的播放器还包含一个关键的请求标头:
Icy-MetaData: 1
此
Icy-MetaData
标头要求服务器将元数据与音频流数据混合。 也就是说,“正在播放”的曲目信息将定期发送并注入流中。
在服务器响应标头中,还有另一个关键标头:
icy-metaint:45000
这告诉我们两件事......第一是服务器同意发送元数据。 第二个是元数据间隔是45,000字节。 每 45,000 字节,服务器将注入一块元数据。 让我们回到数据包嗅探器,看看它是什么样子的:
元数据块的第一个字节,
0x06
,告诉我们元数据块有多长。 将该字节的值乘以 16,您将得到元数据块的长度(以字节为单位)。 也就是说,第一个元数据块字节的 0x06
告诉我们接下来的 96 个字节将是元数据,然后再返回常规流数据。 请注意,这意味着整个元数据为 97 字节...1 字节用于长度指示符,然后 96 字节(在本例中)用于其余部分。
现在,让我们了解实际的文本元数据格式:
StreamTitle='Buscemi - First Flight To London';StreamUrl='http://SomaFM.com/secretagent/';
看起来非常简单。
key='value'
,分号 ;
分隔。 不过,这有一些大问题。 例如......没有真正标准的方法来转义单引号。 如果元数据值需要包含单引号,有时是 \'
,有时是 '''
。 有时候根本就逃不掉!
此外,并非所有服务器都使用相同的字符编码。 您可能可以放心地假设 UTF-8,但请注意某些服务器可能会有所不同,或者只是简单地破坏了自己的元数据编码。
无论如何,既然您知道了这一切是如何工作的,那么您就可以实施了。 如果您愿意,我有一些您可以许可的代码。 一种是 Node.js API 服务器,当给定流 URL 时,它会为您返回元数据,并在服务器端完成所有缓冲和解析。 另一个是基于 MSE 的客户端播放器...请注意,这只适用于支持 CORS 的服务器,据我所知,目前只有我自己的服务器(AudioPump CDN)可以做到这一点。 如果您对此代码感兴趣,请随时向我发送电子邮件,地址为 [email protected]。 如果您对我在 Stack Overflow 上的回答有疑问,请在此处发表评论。