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