#!/usr/bin/python

import urllib2,urllib,re,time,md5,xml.utils.iso8601,pyid3lib,sys,mad,ao,thread
import keypress

class Scrobbler(object):
    def __init__(self,user,password,client="tst",version="1.0",url="http://post.audioscrobbler.com/"):
        self.url = url
        self.user = user
        self.password = password
        self.client = client
        self.version = version
    def handshake(self):
        url = self.url+"?"+urllib.urlencode({
            "hs":"true",
            "p":"1.1",
            "c":self.client,
            "v":self.version,
            "u":self.user
            })
        result = urllib2.urlopen(url).readlines()
        if result[0].startswith("BADUSER"):
            return self.baduser(result[1:])
        if result[0].startswith("UPTODATE"):
            return self.uptodate(result[1:])
        if result[0].startswith("FAILED"):
            return self.failed(result)
    def uptodate(self,lines):
        self.md5 = re.sub("\n$","",lines[0])
        self.submiturl = re.sub("\n$","",lines[1])
        self.interval(lines[2])
    def baduser(self,lines):
        print "Bad user"
    def failed(self,lines):
        print lines[0]
        self.interval(lines[1])
    def interval(self,line):
        match = re.match("INTERVAL (\d+)",line)
        if match is not None:
            print "[audioscrobbler] Sleeping for",match.group(1),"secs"
            time.sleep(int(match.group(1)))
    def submit(self,tracks):
        print "[audioscrobbler] Submitting"
        md5response = md5.md5(md5.md5(self.password).hexdigest()+self.md5).hexdigest()
        post = "u="+self.user+"&s="+md5response
        count = 0
        for track in tracks:
            post += "&"
            post += track.urlencoded(count)
            count += 1
        post = unicode(post)
        print post
        result = urllib2.urlopen(self.submiturl,post)
        results = result.readlines()
        if results[0].startswith("OK"):
            print "OK"
            self.interval(results[1])
        if results[0].startswith("FAILED"):
            self.failed([results[0],"INTERVAL 0"])

class Track(object):
    def __init__(self,artist,name,album,length,mbid=None,tracktime=None):
        self.params = {}
        self.artist = artist
        self.name = name
        self.album = album
        self.length = str(length)
        self.mbid = mbid
        self.tracktime = tracktime
        self.date = re.sub("(\d\d\d\d-\d\d-\d\d)T(\d\d:\d\d:\d\d).*","\\1 \\2",xml.utils.iso8601.tostring(time.time()))

    def __repr__(self):
        return "'"+self.name+"' by '"+self.artist+"' from '"+self.album+"'"

    def urlencoded(self,num):
        encode = ""
        encode += "a["+str(num)+"]="+urllib.quote_plus(self.artist)
        encode += "&t["+str(num)+"]="+urllib.quote_plus(self.name)
        encode += "&l["+str(num)+"]="+urllib.quote_plus(self.length)
        encode += "&i["+str(num)+"]="+(self.date)
        if self.mbid is not None:
            encode += "&m["+str(num)+"]="+urllib.quote_plus(self.mbid)
        else:
            encode += "&m["+str(num)+"]="
        encode += "&b["+str(num)+"]="+urllib.quote_plus(self.album)
        return encode

class MP3Track(Track):
    def __init__(self,filename):
        self.read_mp3_info(filename)

    def read_mp3_info(self,filename):
        tag = pyid3lib.tag(filename)
        try:
            album = tag.album
        except AttributeError:
            album = ''
        Track.__init__(self,tag.artist,tag.title,album,self.length(filename))
    def length(self,filename):
        return mad.MadFile(filename).total_time()/1000

def format_time(millisecs):
    return "%02d:%02d" % (millisecs/1000/60,(millisecs/1000)%60)

def mp3_play(filename,session):
    mf = mad.MadFile(filename)
    dev = ao.AudioDevice('oss', bits=16, rate=mf.samplerate())
    track = MP3Track(f)
    print track
    submitted = False
    bored = False
    while not bored:
        #try:
            #i = keypress.checkkey()
            #if i == 110 or i == 78:
                #break
        #except keypress.NotTTYException:
            #pass
        buffy = mf.read()
        if buffy is None:
            break
        dev.play(buffy, len(buffy))
        status = format_time(mf.current_time())+" / "+format_time(mf.total_time())
        status += " ("+("%.01f" % (100*(mf.current_time()+0.0)/mf.total_time()))+"%)"
        print status+"\r",
        if (not submitted) and ((mf.current_time()+0.0)/mf.total_time() > 0.05 or mf.current_time()>120000):
            track.tracktime = mf.current_time()/1000
            thread.start_new_thread(session.submit,([track],))
            submitted = True
        sys.stdout.flush()

if __name__ == '__main__':
    s = Scrobbler("username","password")
    s.handshake()
    for f in sys.argv[1:]:
        mp3_play(f,s)
