有人成功从远程广播流读取 SHOUTcast/Icecast 元数据吗?
有 多个库 可以从本地 MP3 文件读取元数据,但似乎没有一个库设计用于使用无线电流(本质上是远程服务器上永无休止的 MP3 文件)。
其他建议建议从 mp3 流的开头下载有限数量的比特,但这通常会导致一堆十六进制输出,而没有任何类似于文本元数据的内容。
有人知道更成功的解决方案吗?谢谢。
#!/usr/bin/env python
import urllib2
stream_url = 'http://pub1.di.fm/di_classictrance'
request = urllib2.Request(stream_url)
try:
request.add_header('Icy-MetaData', 1)
response = urllib2.urlopen(request)
icy_metaint_header = response.headers.get('icy-metaint')
if icy_metaint_header is not None:
metaint = int(icy_metaint_header)
read_buffer = metaint+255
content = response.read(read_buffer)
title = content[metaint:].split("'")[1]
print title
except:
print 'Error'
欲了解更多详情,请查看此链接
我使用了一些 @dbogdan 的代码并创建了一个每天用于超过 4000 个流的库。 它运行良好且稳定,支持元数据,例如歌曲标题、艺术家姓名、比特率和内容类型。
您可以在以下位置找到它: https://github.com/Dirble/streamscrobbler-python
对于 10 年后发现自己在这里的其他人,这里是 @dbogdan 代码的 python3 版本。值得注意的是
content[metaint:].split("'")[1]
非常不可靠,所以我采用了更直接的正则表达式方法。
from urllib import request as urequest
SRCHTITLE = __import__("re").compile(r'StreamTitle=(\'|")(?P<title>.*)\1;').search
def _id3(self, url:str) -> dict:
request = urequest.Request(url, headers={'Icy-MetaData': 1})
with urequest.urlopen(request) as resp:
metaint = int(resp.headers.get('icy-metaint', '-1'))
if metaint<0: return False
resp.read(metaint) #this isn't seekable so, arbitrarily read to the point we want
title = m.group('title' ) if (m := SRCHTITLE(f'{resp.read(255)}')) else ''
return dict(
site_url = resp.headers.get('icy-url' ) ,
name = resp.headers.get('icy-name' ).title(),
genre = resp.headers.get('icy-genre').title(),
title = title)
由于 mp3 是一种专有格式,因此规范并不那么容易获得。 我认为这个网站提供了很好的概述。
在普通 mp3 文件中,ID3v1 元数据标签位于文件的最末尾,它组成了最后 128 个字节。这实际上是一个糟糕的设计。 ID3 系统是作为事后添加到 mp3 中的,所以我想在不破坏向后兼容性的情况下没有其他方法可以做到这一点。这意味着如果广播流像永无止境的 mp3 文件一样提供,则不能有正常意义上的 ID3 标签。
我会向广播电台的运营人员核实;也许他们把 ID3 标签放在了不标准的地方?