patternpythonMinor
Get metadata from an Icecast radio stream
Viewed 0 times
streamradioicecastgetfrommetadata
Problem
I am new to Python and not very familiar with advanced Python data structures.
I have written a function to receive data from a socket in Python and perform string manipulations on it. The basic purpose of the code is to get the metadata from an Icecast radio stream based on suggestions I found elsewhere.
The function seems to work but it would be great it someone can help me optimize the string operation.
```
def radioPoller():
msg1="GET / HTTP/1.1"+'\r'+'\n'+"Host: sc.buddharadio.com"+'\r'+'\n'+"User-Agent: VLC/2.0.5 LibVLC/2.0.5"+'\r'+'\n'+"Range: bytes=0-"+'\r'+'\n'+"Connection: close"+'\r'+'\n'+"Icy-MetaData: 1"+'\r'+'\n'+'\r'+'\n'
if os.path.exists("/media/hdd1/data.txt"):
os.unlink("/media/hdd1/data.txt")
HOST = 'sc.buddharadio.com' # The remote host
PORT = 80 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
f=open("/media/hdd1/data.txt","w")
s.send(msg1) #sending http request
data=""
while len(data)<1024:
data=s.recv(1024) #recieving a few characters
t=data.find("metaint") #finding the metaint response header which contains interval after which metadata will be visible in data stream eg:-icy-metaint:32768
data=data[t+8:] #jumping 8 characters to the end of the string
splitter="\r\n" # to split the contents and find when header ends and
data1=data.split(splitter) #data1 stores the splitted data. First list has length and last has data
metaInt=int(data1[0]) #find the metadata interval byte length
#print metaInt
string12=data1[len(data1)-1] #contains only the data part
lengthTotal= len(string12) #length of data we have
print
I have written a function to receive data from a socket in Python and perform string manipulations on it. The basic purpose of the code is to get the metadata from an Icecast radio stream based on suggestions I found elsewhere.
The function seems to work but it would be great it someone can help me optimize the string operation.
```
def radioPoller():
msg1="GET / HTTP/1.1"+'\r'+'\n'+"Host: sc.buddharadio.com"+'\r'+'\n'+"User-Agent: VLC/2.0.5 LibVLC/2.0.5"+'\r'+'\n'+"Range: bytes=0-"+'\r'+'\n'+"Connection: close"+'\r'+'\n'+"Icy-MetaData: 1"+'\r'+'\n'+'\r'+'\n'
if os.path.exists("/media/hdd1/data.txt"):
os.unlink("/media/hdd1/data.txt")
HOST = 'sc.buddharadio.com' # The remote host
PORT = 80 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
f=open("/media/hdd1/data.txt","w")
s.send(msg1) #sending http request
data=""
while len(data)<1024:
data=s.recv(1024) #recieving a few characters
t=data.find("metaint") #finding the metaint response header which contains interval after which metadata will be visible in data stream eg:-icy-metaint:32768
data=data[t+8:] #jumping 8 characters to the end of the string
splitter="\r\n" # to split the contents and find when header ends and
data1=data.split(splitter) #data1 stores the splitted data. First list has length and last has data
metaInt=int(data1[0]) #find the metadata interval byte length
#print metaInt
string12=data1[len(data1)-1] #contains only the data part
lengthTotal= len(string12) #length of data we have
Solution
def radioPoller():Python convention says that function names should be lowercase_with_undescores. Also, they should be verb, so:
poll_radio would be betters = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))I recommend not using
s as its not obvious what that means. finalData=[]Python convention, local names should be
lowercase_with_underscores.f=open("/media/hdd1/data.txt","a")Again, don't use single letter variable names.
s.send(msg1) #sending http requestInstead of doing HTTP requests yourself, it'd make more sense to use urllib2 to do it for you. That way it'd take care of parsing etc.
Where is msg1 coming from? Also, you don't know that this sent all the data. To be sure all data was sent, use s.sendall
data=""
while len(data)<1024:
data=s.recv(1024) #recieving a few charactersShouldn't you be using
+=? t=data.find("metaint") #finding the metaint response header
data=data[t+8:] #jumping 8 characters to the end of the string
splitter="\r\n" # to split the contents and find when header ends and
data1=data.split(splitter) #data1 stores the splitted data. First list has length and last has dataWhy assign splitter to a local variable? just pass the constant.
metaInt=int(data1[0]) #find the metadata interval byte length
#print metaIntRather then mucking with this use, use python's tool to parse the headers for you.
finalData.append(data1[len(data1)-1]) #contains only the data partYou can use
data1[-1] for the same result. lengthTotal= len(finalData[0]) #length of data we have
#print "total data is", lengthTotal,"\n"
#print "TOtal bytes we should get is", (metaInt+4080),"\n"Don't leave dead code in comments
while lengthTotal<(metaInt+4080):
data = s.recv(8192)
lengthTotal=lengthTotal+len(data)
#print "Total length now is", lengthTotal
finalData.append(data)In this case I suggest using StringIO rather than a list.
print finalData
string12=''.join(finalData)Don't use meaningless names
metaLen=ord(string12[metaInt])
#print "This is multiplier", metaLen, "No of characters to read ", (metaLen*16)
metaString=string12[metaInt+1:metaInt+1+(metaLen*16)]
metaString=metaString+"\r\n"
#print "Extracted String is \n", metaString
f.write(str(metaString))It's already a string, don't pass it to str
s.close
f.closeThese last two don't do anything.
Here's my reworking of your code:
def parse_headers(response):
headers = {}
while True:
line = response.readline()
if line == '\r\n':
break # end of headers
if ':' in line:
key, value = line.split(':', 1)
headers[key] = value
return headers
def poll_radio():
request = urllib2.Request("http://sc.buddharadio.com:80/", headers = {
'User-Agent' : 'User-Agent: VLC/2.0.5 LibVLC/2.0.5',
'Icy-MetaData' : '1',
'Range' : 'bytes=0-',
})
# the connection will be close on exit from with block
with contextlib.closing(urllib2.urlopen(request)) as response:
headers = parse_headers(response)
meta_interval = int(headers['icy-metaint'])
response.read(meta_interval) # throw away the data until the meta interval
length = ord(response.read(1)) * 16 # length is encoded in the stream
metadata = response.read(length)
print metadataCode Snippets
def radioPoller():s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))finalData=[]f=open("/media/hdd1/data.txt","a")s.send(msg1) #sending http requestContext
StackExchange Code Review Q#23364, answer score: 5
Revisions (0)
No revisions yet.