Dutch translation by Benny
[enigma2-plugins.git] / lastfm / src / scrobbler.py
1 from re import sub
2 from datetime import datetime
3 from md5 import md5
4 from twisted.internet import reactor
5 from enigma import iServiceInformation, iPlayableService
6 from Components.config import config
7 from twisted.web.client import getPage
8
9 from urllib import  urlencode as urllib_urlencode
10
11 class LastFMScrobbler(object):
12     client     = "tst" # this must be changed to a own ID
13     version    = "1.0"
14     host        = "post.audioscrobbler.com"
15     port       = 80
16     loggedin  = False # indicates, if we are logged in
17
18     def __init__(self):
19         self.user = config.plugins.LastFM.username.value
20         self.password = config.plugins.LastFM.password.value
21         self.tracks2Submit = []
22     
23     def addTrack2Submit(self,track):
24         self.tracks2Submit.append(track)
25     
26     def removeTrack2Submit(self,track):
27         self.tracks2Submit.remove(track)
28         
29     def handshake(self):
30         print "[LastFMScrobbler] try logging into lastfm-submission-server"
31         url = "http://"+self.host+":"+str(self.port)+"?"+urllib_urlencode({
32             "hs":"true",
33             "p":"1.1",
34             "c":self.client,
35             "v":self.version,
36             "u":self.user
37             })
38         getPage(url).addCallback(self.handshakeCB).addErrback(self.handshakeCBError)
39
40     def handshakeCBError(self,data): 
41         self.failed(data.split("\n"))
42
43     def handshakeCB(self,data): 
44         result = data.split("\n")   
45         if result[0].startswith("BADUSER"):
46             return self.baduser(result[1:])
47         if result[0].startswith("UPTODATE"):
48             return self.uptodate(result[1:])
49         if result[0].startswith("FAILED"):
50             return self.failed(result)
51
52     def uptodate(self,lines):
53         self.md5 = sub("\n$","",lines[0])
54         self.submiturl = sub("\n$","",lines[1])
55         self.loggedin = True
56         print "[LastFMScrobbler] logged in"
57         self.submit()
58         
59     def baduser(self,lines):
60         print "[LastFMScrobbler] Bad user"
61         
62     def failed(self,lines):
63         print "[LastFMScrobbler] FAILED",lines[0]
64            
65     def submit(self):
66         if self.loggedin is False:
67             self.handshake()
68             return False
69         tracks = self.tracks2Submit
70         print "[LastFMScrobbler] Submitting ",len(tracks)," tracks"
71         md5response = md5(md5(self.password).hexdigest()+self.md5).hexdigest()
72         post = {}
73         post["u"]=self.user
74         post["s"]=md5response
75         count = 0
76         for track in tracks:
77             track.urlencoded(post,count)
78             count += 1
79         (host,port) = self.submiturl.split("/")[2].split(":")
80         url = "http://"+host+":"+port+"/"+"/".join(self.submiturl.split("/")[3:])
81         data = self.encode(post)
82         getPage(url,method="POST",headers = {'Content-Type': "application/x-www-form-urlencoded",'Content-Length': str(len(data))},postdata=data).addCallback(self.submitCB).addErrback(self.submitCBError)
83     
84     def encode(self,postdict):
85         result=[]
86         for key,value in postdict.items():
87             result.append(key+"="+value)
88         return "&".join(result)
89
90     def submitCBError(self,data):
91         self.failed(data.split("\n"))
92         
93     def submitCB(self,data):
94         results = data.split("\n")
95         if results[0].startswith("OK"):
96             print "[LastFMScrobbler] Submitting successful"
97             self.tracks2Submit = []
98         if results[0].startswith("FAILED"):
99             print "[LastFMScrobbler] Submitting failed,",results[0]
100             self.failed([results[0],"INTERVAL 0"])
101
102 ############
103
104 class Track(object):
105     def __init__(self,artist,name,album,length=-1,mbid=None,tracktime=None):
106         self.params = {}
107         self.artist = artist
108         self.name = name
109         self.album = album
110         self.length = length
111         self.mbid = mbid
112         self.tracktime = tracktime
113         self.date = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
114         
115     def __repr__(self):
116         return "'"+self.name+"' by '"+self.artist+"' from '"+self.album+"'"
117
118     def urlencoded(self,encodedict,num):
119         if self.length is not None:
120             encodedict["l["+str(num)+"]"]=str(self.length)
121         else:
122             encodedict["l["+str(num)+"]"]=''
123         
124         if self.mbid is not None:
125             encodedic["m["+str(num)+"]"]=self.mbid
126         else:
127             encodedict["m["+str(num)+"]"]=''
128         
129         encodedict["i["+str(num)+"]"]=self.date
130         encodedict["a["+str(num)+"]"]=self.artist
131         encodedict["t["+str(num)+"]"]=self.name
132         encodedict["b["+str(num)+"]"]=self.album
133 ##########
134 class EventListener:
135     time2wait4submit = 30
136     
137     def __init__(self,session,streamplayer):
138         self.session = session
139         self.streamplayer = streamplayer
140         
141         self.tracks_checking_for = []
142 #        self.scrobbler = LastFMScrobbler(config.plugins.LastFM.username.value,config.plugins.LastFM.password.value)
143 #        self.scrobbler.handshake()
144         
145     def onEvent(self,event):
146         if event == iPlayableService.evUpdatedInfo:
147             track = self.getCurrentServiceType()
148             try:
149                 self.tracks_checking_for.index(str(track))
150             except ValueError,e:
151                 if track is not False:
152                     self.tracks_checking_for.append(str(track))
153                     if track.length < self.time2wait4submit:
154                         waittime = self.time2wait4submit
155                     else:
156                         waittime = track.length/2
157                     print "[LastFMScrobbler] waiting",waittime,"sec. until checking if the track "+str(track)+" is still playing"
158                     reactor.callLater(waittime, self.checkTrack, track)
159
160     def startListenToEvents(self):
161         self.session.nav.event.append(self.onEvent)
162
163     def stopListentoEvents(self):
164         self.session.nav.event.remove(self.onEvent)
165     
166     def getCurrentServiceType(self):
167         currPlay = self.session.nav.getCurrentService()
168         sref=self.session.nav.getCurrentlyPlayingServiceReference()
169         if sref is None:
170             #print "[LastFMScrobbler] CurrentlyPlayingServiceReference is None, not submitting to LastFM"
171             return False
172         elif sref.toString().startswith("4097:") is not True:
173             #print "[LastFMScrobbler] CurrentlyPlayingServiceReference is not a File, not submitting to LastFM"
174             return False
175         elif self.streamplayer.is_playing:
176             print "[LastFMScrobbler] LastFm-Plugin is playing"
177             trdata= self.streamplayer.playlist.getTrack(self.streamplayer.currentplaylistitemnumber)
178             track = self.getTrack(artist=trdata['creator'],title=trdata['title'],album=trdata['album'],length=(trdata["duration"]/1000))
179             return track
180         elif currPlay is not None:
181             tracklength = -1
182             seek = currPlay and currPlay.seek()
183             if seek != None:
184                 r= seek.getLength()
185                 if not r[0]:
186                     tracklength = r[1] / 90000
187             return self.getTrack( artist = currPlay.info().getInfoString(iServiceInformation.sArtist),
188                                   title = currPlay.info().getInfoString(iServiceInformation.sTitle),
189                                   album = currPlay.info().getInfoString(iServiceInformation.sAlbum),
190                                   length = tracklength,
191                                  )
192              
193              
194     def getTrack(self , artist = None, title = None, album = None,length=-1):
195         if artist == "" or artist is None:
196             print "[LastFMScrobbler] CurrentlyPlayingServiceReference has no Artist, not submitting to LastFM"
197             return False
198         elif title == "" or title is None:
199             print "[LastFMScrobbler] CurrentlyPlayingServiceReference has no Tracktitle, not submitting to LastFM"
200             return False
201         else:
202             return Track(artist,title,album,length=length)
203             
204     
205     def checkTrack(self,track):
206         trackcurrent = self.getCurrentServiceType()
207         if str(track) == str(trackcurrent):
208             print "[LastFMScrobbler] sending track to lastfm as now playing... "+str(track)
209             self.scrobbler = LastFMScrobbler()
210             self.scrobbler.addTrack2Submit(track)
211             self.scrobbler.submit()
212             self.tracks_checking_for.remove(str(track))
213         else:
214             print "[LastFMScrobbler] track is not playing, skipping sending "+str(track)
215