Monitoring ICY Stream Metadata Title (Python)

让人想犯罪 __ 提交于 2019-12-12 04:12:56

问题


I would like to continually read the stream and update the title information. (Something like this is posted here: Receive ice cast meta data with python, however it makes multiple requests, and I was looking to just make one stream request. The protocol is described here: http://www.smackfu.com/stuff/programming/shoutcast.html. It seems to only work once then stop working. Here is what I have so far:

import urllib2
import struct
import re

request = urllib2.Request('http://icy1.abacast.com:80/wbeb-wbebhd2aac-64')
request.add_header('Icy-MetaData','1')
opener = urllib2.build_opener()
data=opener.open(request)

while True:
    audio = data.read(2048) # 2048 is the metadata interval for this stream
    metadata_size = struct.unpack('B', data.read(1))[0]*16
    metadata = data.read(metadata_size).rstrip(b'\0')
    m = re.search(br"StreamTitle='([^']*)';", metadata)
    title = m.group(1).decode('latin1', errors='replace')
    print title

I believe the reason why that one doesn't work is that the url is not opened as a stream, is that possible to do with urllib2?

I also have one that doesnt work made with requests.get:

def monitor():
     url = 'http://icy1.abacast.com:80/wbeb-wbebhd2aac-64'
     r = requests.get(url, headers={'Icy-MetaData': 1}, stream=True)
     metadata = StringIO.StringIO()
     byte_counter = 0
     meta_counter = 0
     metadata_interval = r.headers['icy-metaint']
     metadata_size = 0
     length = None
     data_bool = True
     for data in r.iter_content(1):
        byte_counter+=1
        print "byte %s" % byte_counter
        if (byte_counter <= 2048):
            pass # audio data
        if (byte_counter > 2048):
            if (meta_counter == 0):
                metadata_size = struct.unpack('B', data)[0]*16
                print "METADATA SIZE: %s" % metadata_size
                meta_counter+=1
            elif (meta_counter <= int(metadata_size+1)):
                metadata.write(data)
                meta_counter+=1
            else: data_bool = False
        if (data_bool is False):
            byte_counter = 0
            meta_counter = 0
            meta_interval = 0
            metadata_size = 0
            meta = metadata.read().rstrip(b'\0')
            m = re.search(br"StreamTitle='([^']*)';", meta)
            if m is not None:
                title = m.group(1).decode('latin1', errors='replace')
                print "Title is: %s" % title
            metadata = StringIO.StringIO()
            data_bool = True

回答1:


Not sure if you did already find a way in the meantime. But as I came across the same question - here is my (working but barely tested) version.
Widely based on your suggestion, with some adaptions and python3 support:

from __future__ import unicode_literals

import re
import requests
import sys

try:
    from StringIO import StringIO as BytesIO
except ImportError:
    from io import BytesIO

def icy_monitor(stream_url, callback=None):

    r = requests.get(stream_url, headers={'Icy-MetaData': '1'}, stream=True)
    if r.encoding is None:
        r.encoding = 'utf-8'

    byte_counter = 0
    meta_counter = 0
    metadata_buffer = BytesIO()

    metadata_size = int(r.headers['icy-metaint']) + 255

    data_is_meta = False


    for byte in r.iter_content(1):

        byte_counter += 1

        if (byte_counter <= 2048):
            pass

        if (byte_counter > 2048):
            if (meta_counter == 0):
                meta_counter += 1

            elif (meta_counter <= int(metadata_size + 1)):

                metadata_buffer.write(byte)
                meta_counter += 1
            else:
                data_is_meta = True

        if (byte_counter > 2048 + metadata_size):
            byte_counter = 0

        if data_is_meta:

            metadata_buffer.seek(0)

            meta = metadata_buffer.read().rstrip(b'\0')

            m = re.search(br"StreamTitle='([^']*)';", bytes(meta))
            if m:
                title = m.group(1).decode(r.encoding, errors='replace')
                print('New title: {}'.format(title))

                if callback:
                    callback(title)

            byte_counter = 0
            meta_counter = 0
            metadata_buffer = BytesIO()

            data_is_meta = False


def print_title(title):
    print('Title: {}'.format(title))



if __name__ == '__main__':

    stream_url = sys.argv[1]
    icy_monitor(stream_url, callback=print_title)


来源:https://stackoverflow.com/questions/41022893/monitoring-icy-stream-metadata-title-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!