Get metadata from an Icecast radio stream 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)&lt;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 "total data is", lengthTotal,"\n"

    print "TOtal bytes we should get is", (metaInt+4080),"\n"

    while lengthTotal&lt;(metaInt+4080):
        data = s.recv(8192)
        lengthTotal=lengthTotal+len(data)
        print "Total length now is", lengthTotal 
        string12=string12+data
        #The first character after MetaInterval number of characters define the length of actual metadata/16
    metaLen=ord(string12[metaInt])
    print "This is multiplier", metaLen, "No of characters to read ", (metaLen*16)

    metaString=string12[metaInt+1:metaInt+1+(metaLen*16)]+'\n'
    print "Extracted String is \n", metaString

    f.write(str(metaString))
    s.close
    f.close


The code sends a request header to the radio stream and then receives a response like this:


  ICY 200 OK
  icy-notice1:This stream requires Winamp
  icy-notice2:SHOUTcast Distributed Network Audio Server/Linux v1.9.8
  icy-name:Buddha
  icy-genre:
  icy-url:http://www.buddharadio.com
  content-type:audio/aac
  icy-pub:0
  icy-metaint:32768
  icy-br:32


The icy-metaint defines the data interval after the metadata appears in the data stream.

I use a while loop to read in the Meta Data Interval+Max Meta Data Length of data and then slice the metadata and save it in a file.
def radioPoller():


Python convention says that function names should be lowercase_with_undescores. Also, they should be verb, so: poll_radio would be better

    s = 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 request


Instead 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)&lt;1024:
        data=s.recv(1024)               #recieving a few characters


Shouldn'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 data 


Why assign splitter to a local variable? just pass the constant.

    metaInt=int(data1[0])                      #find the metadata interval byte length
    #print metaInt  


Rather 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 part


You 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&lt;(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.close


These 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 metadata