#!/usr/bin/python
  #########################################
  ##       Last updated 2004-11-20       ##
#############################################
## MPD Scrobbler client version 0.2.1      ##
## Good conformance added by Hannes Reich  ##
## Hacked-together MPD junk by Avery M.    ##
## Scrobbler class thanks to Matt Biddulph ##
#############################################
  ## 1:Replace "username" and "password" ##
  ## 2:Set optimal permissions (+x,a-r)  ##
  ## 3:Run at any time, listen to music! ##
  #########################################

import urllib2,urllib,re,time,md5,xml.utils.iso8601,sys,thread,mpdclient
# Requires the mpdclient library, download at http://musicpd.org/

def urlencoded(track,pos):
        encode = ""
        encode += "a[0]="+urllib.quote_plus(track.artist)
        encode += "&t[0]="+urllib.quote_plus(track.title)
        encode += "&l[0]="+urllib.quote_plus(str(pos))
        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()))
        encode += "&i[0]="+urllib.quote_plus(date)
        encode += "&m[0]="
        encode += "&b[0]="+urllib.quote_plus(track.album)
        return encode



class Scrobbler(object):

    def __init__(self,user,password,client="mpd",version="0.2.1",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("BADAUTH"):
            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 "ERROR! Username/password incorrect!"
    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 "Sleeping for",match.group(1),"secs"
            time.sleep(int(match.group(1)))
    def submit(self,track,pos):
        print "Submitting"
        md5response = md5.md5(md5.md5(self.password).hexdigest()+self.md5).hexdigest()
        post = "u="+self.user+"&s="+md5response
        post += "&"
        post += urlencoded(track,pos)
        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"])

def sleeper(control,s):
    # we submit only tracks longer than MinTrackLen seconds that have
    # played for SubmitTime seconds or SubmitPercentage or their
    # length
    MinTrackLen = 30
    SubmitTime = 240
    SubmitPercentage = 50

    # polling interval
    SleepTime = 5

    lastSong = False
    lastSecondPos = 0
    submitThis = False
    while 1:
        time.sleep(SleepTime)
        song = control.getCurrentSong()
	pos = control.getSongPosition()
	if song and pos:
		(secondPos, trackLen, percentPos) = pos;
		if (# have we just started playing?
		    not lastSong
		    # are we playing a different track than last time?
		    or song.title != lastSong.title or song.artist != lastSong.artist
		    or song.album != lastSong.album or song.track != lastSong.track
		    # have we restarted this track?
		    or (secondPos < lastSecondPos and secondPos <= SleepTime)
		    ):
			print "New song detected"
			if (song.title != '' and trackLen >= MinTrackLen):
				submitThis = True
			lastSong = song
		else:
			if (submitThis):
				# allow 1 second for rounding errors
				if (abs(secondPos - lastSecondPos - SleepTime) > 1):
					print "Seeking detected, will not submit this track"
					submitThis = False
				else:
					if(secondPos >= SubmitTime or percentPos >= SubmitPercentage):
						thread.start_new_thread(s.submit,(song,secondPos,))
						submitThis = False
		lastSecondPos = secondPos

if __name__ == '__main__':
    s = Scrobbler("username", "password") # <-- Your username goes here
    s.handshake()
    control = mpdclient.MpdController(host="localhost", port=6600) # <-- host
    sleeper(control,s)
