fix typo
[enigma2-plugins.git] / lastfm / src / plugin.py
1 from enigma import eTimer
2 from enigma import eConsoleAppContainer
3 from enigma import loadPic
4
5 from Screens.Screen import Screen
6 from Screens.MessageBox import MessageBox
7 from Screens.HelpMenu import HelpableScreen , HelpMenu              
8
9 from Components.Pixmap import Pixmap
10 from Components.Label import Label
11 from Components.MenuList import MenuList
12 from Components.ActionMap import ActionMap, NumberActionMap
13 from Components.config import config, ConfigSubsection, ConfigSlider,ConfigInteger,ConfigYesNo, ConfigText
14 from Components.HelpMenuList import HelpMenuList
15
16 from Tools import Notifications
17
18 from Plugins.Plugin import PluginDescriptor
19
20
21 from StreamPlayer import StreamPlayer
22 from LastFMConfig import LastFMConfigScreen
23 from LastFM import LastFM
24
25 import os
26 import urllib
27 ###############################################################################        
28 myname = "Last.FM"     
29 plugin_path = ""
30
31 ###############################################################################        
32
33 config.plugins.LastFM = ConfigSubsection()
34 config.plugins.LastFM.showcoverart = ConfigYesNo(default = False)
35 config.plugins.LastFM.username = ConfigText("user",fixed_size=False)
36 config.plugins.LastFM.password = ConfigText("passwd",fixed_size=False)
37 config.plugins.LastFM.timeoutstatustext = ConfigInteger(3,limits = (0, 10))
38 config.plugins.LastFM.timeouttabselect = ConfigInteger(2,limits = (0, 10))
39 config.plugins.LastFM.metadatarefreshinterval = ConfigInteger(5,limits = (0, 100))
40 config.plugins.LastFM.recommendedlevel = ConfigInteger(3,limits = (0, 100))
41
42 ###############################################################################        
43 def main(session,**kwargs):
44     session.open(LastFMScreenMain)    
45         
46 def Plugins(path,**kwargs):
47     global plugin_path
48     plugin_path = path
49     return PluginDescriptor(
50         name=myname, 
51         description="the social music revolution", 
52         where = PluginDescriptor.WHERE_PLUGINMENU,
53         fnc = main
54         )
55 ############################################################################### 
56 class LastFMScreenMain(Screen,HelpableScreen):
57     skin = """
58         <screen position="110,83" size="530,430" title="Last.FM" >
59             
60             <widget name="artist" position="0,0" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\"  foregroundColor=\"white\" font=\"Regular;18\" />          
61             <widget name="album" position="0,40" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\"  foregroundColor=\"white\" font=\"Regular;18\" />          
62             <widget name="track" position="0,80" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\"  foregroundColor=\"white\" font=\"Regular;18\" />          
63             
64             <widget name="info_artist" position="70,0" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\"  foregroundColor=\"white\" font=\"Regular;18\" />          
65             <widget name="info_album" position="70,40" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\"  foregroundColor=\"white\" font=\"Regular;18\" />          
66             <widget name="info_track" position="70,80" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\"  foregroundColor=\"white\" font=\"Regular;18\" />          
67             <widget name="info_cover" position="414,0" size="116,116" />          
68             
69             <widget name="tablist" position="0,120" size="150,260" scrollbarMode="showOnDemand" />            
70             <widget name="streamlist" position="150,120" size="380,260" scrollbarMode="showOnDemand" />            
71             
72             <widget name="button_red" position="10,400" size="60,30" backgroundColor=\"red\" valign=\"center\" halign=\"center\" zPosition=\"2\"  foregroundColor=\"white\" font=\"Regular;18\" />          
73             <widget name="button_green" position="80,400" size="60,30" backgroundColor=\"green\" valign=\"center\" halign=\"center\" zPosition=\"2\"  foregroundColor=\"white\" font=\"Regular;18\"/>            
74             <widget name="button_yellow" position="150,400" size="60,30" backgroundColor=\"yellow\" valign=\"center\" halign=\"center\" zPosition=\"2\"  foregroundColor=\"white\" font=\"Regular;18\" />            
75             <widget name="button_blue" position="220,400" size="60,30" backgroundColor=\"blue\" valign=\"center\" halign=\"center\" zPosition=\"2\"  foregroundColor=\"white\" font=\"Regular;18\" />            
76             <widget name="infolabel" position="290,400" size="290,30" valign=\"center\" halign=\"center\" zPosition=\"2\"  foregroundColor=\"white\" font=\"Regular;18\" />           
77         </screen>"""
78          
79     noCoverArtPNG = "/usr/share/enigma2/no_coverArt.png"
80     
81     def __init__(self, session, args = 0):
82         Screen.__init__(self, session)
83         HelpableScreen.__init__(self)
84         self.skin = LastFMScreenMain.skin
85         self.session = session
86         self.lastfm = LastFM()
87         self.streamplayer = StreamPlayer(session)
88         self.imageconverter = ImageConverter(self.setCoverArt)
89         Screen.__init__(self, session)
90         self.tabs=[("personal Stations",self.loadPersonalStations)
91                    ,("Global Tags",self.loadGlobalTags)
92                    ,("Top Tracks",self.loadTopTracks)
93                    ,("Recent Tracks",self.loadRecentTracks)
94                    ,("Loved Tracks",self.loadLovedTracks)
95                    ,("Banned Tracks",self.loadBannedTracks)
96                    ,("Friends",self.loadFriends)
97                    ,("Neighbours",self.loadNeighbours)
98                    ]
99         tablist =[]
100         for tab in self.tabs:
101             tablist.append((tab[0],tab))
102         self.tablist = MenuList(tablist)
103         self.tablist.onSelectionChanged.append(self.action_TabChanged)
104         
105         self["artist"] = Label(_("Artist")+":")
106         self["album"] = Label(_("Album")+":")
107         self["track"] = Label(_("Track")+":")
108         
109         self["info_artist"] = Label("N/A")
110         self["info_album"] = Label("N/A")
111         self["info_track"] = Label("N/A")
112         self["info_cover"] = Pixmap()
113         
114         self["tablist"] = self.tablist
115         self["streamlist"] = MenuList([])
116         
117         self["button_red"] = Label(_("play"))
118         self["button_green"] = Label(_("skip"))
119         self["button_yellow"] = Label(_("love"))
120         self["button_blue"] = Label(_("ban"))
121         self["infolabel"] = Label("")
122         
123         self["actions"] = ActionMap(["InfobarChannelSelection","WizardActions", "DirectionActions","MenuActions","ShortcutActions","GlobalActions","HelpActions"], 
124             {
125              "ok": self.action_ok,
126              "back": self.action_exit,
127              "red": self.action_startstop,
128              "green": self.action_green,
129              "yellow": self.action_yellow,
130              "blue": self.action_blue ,
131              "historyNext": self.action_nextTab,
132              "historyBack": self.action_prevTab,
133              
134              "menu": self.action_menu,
135              }, -1)
136         self.helpList.append((self["actions"], "WizardActions", [("ok", _("switch to selected Station"))]))
137         self.helpList.append((self["actions"], "WizardActions", [("back", _("quit Last.FM"))]))
138
139         self.helpList.append((self["actions"], "MenuActions", [("menu", _("open Configuration"))]))
140
141         self.helpList.append((self["actions"], "ShortcutActions", [("red", _("start/stop streaming"))]))
142         self.helpList.append((self["actions"], "ShortcutActions", [("green", _("skip current Track"))]))
143         self.helpList.append((self["actions"], "ShortcutActions", [("yellow", _("mark current Track as loved"))]))
144         self.helpList.append((self["actions"], "ShortcutActions", [("blue", _("ban Track, never play again"))]))
145         self.helpList.append((self["actions"], "InfobarChannelSelection", [("historyNext", _("select next Tab"))]))
146         self.helpList.append((self["actions"], "InfobarChannelSelection", [("historyBack", _("select prev Tab"))]))
147
148         self.onLayoutFinish.append(self.initLastFM)
149         self.onLayoutFinish.append(self.tabchangedtimerFired)
150         self.onLayoutFinish.append(self.setCoverArt)
151         
152         self.guiupdatetimer = eTimer()
153         self.guiupdatetimer.timeout.get().append(self.updateGUI)
154         
155         self.tabchangetimer = eTimer()
156         self.tabchangetimer.timeout.get().append(self.tabchangedtimerFired)
157         
158         self.infolabelcleartimer = eTimer()
159         self.infolabelcleartimer.timeout.get().append(self.clearInfoLabel)
160         
161         
162     def action_TabChanged(self):
163         self.tabchangetimer.stop()
164         self.tabchangetimer.start(config.plugins.LastFM.timeouttabselect.value*1000)
165         
166     def tabchangedtimerFired(self):
167         self.tablist.getCurrent()[1][1]()
168         self.tabchangetimer.stop()
169         
170     def action_nextTab(self):
171         self.tablist.down()
172             
173     def action_prevTab(self):
174         self.tablist.up()
175         
176     def showTab(self,tabnumber):
177         self.currenttab=tabnumber
178         print "showing tab",tabnumber
179         print self.tabs[tabnumber]
180                 
181     def action_menu(self):
182         self.session.open(LastFMConfigScreen)
183
184     def action_exit(self):
185         print "action_exit"
186         self.guiupdatetimer.stop()
187         self.streamplayer.stop()
188         self.close()
189
190     def action_ok(self):
191         print "action_ok"
192         selectedTag = self["streamlist"].l.getCurrentSelection()[1]
193         self.lastfm.changestation(selectedTag)
194         
195     def action_startstop(self):
196         if self.streamplayer.is_playing:
197             self.streamplayer.stop()
198             self.lastfm.metadata = {}
199             self.setInfoLabel("stream stopped")
200         
201         else:
202             self.setInfoLabel("starting stream",timeout=True)
203             if self.lastfm.info.has_key("stream_url"):
204                 self.streamplayer.play(self.lastfm.info["stream_url"])
205                 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
206
207     def action_green(self):
208         self.lastfm.skip()
209         self.setInfoLabel("Track skipped",timeout=True)
210         
211     def action_yellow(self):
212         self.lastfm.love()
213         self.setInfoLabel("Track loved",timeout=True)
214         
215     def action_blue(self):
216         self.lastfm.ban()
217         self.setInfoLabel("Track banned",timeout=True)
218            
219     def setInfoLabel(self,text,timeout=True):
220         self.infolabelcleartimer.stop() 
221         self["infolabel"].setText(text)
222         if timeout is True:
223             self.infolabelcleartimer.start(config.plugins.LastFM.timeoutstatustext.value*1000)
224             
225     def clearInfoLabel(self):
226         self["infolabel"].setText("")
227         
228     def updateGUI(self):
229         if self.streamplayer.is_playing is not True:
230             return None
231         print "updateGUI"
232         
233         if self.lastfm.state:
234             self.lastfm.getmetadata()
235         
236         if self.streamplayer.is_playing:
237             self["button_red"].setText(_("stop"))
238         else:
239             self["button_red"].setText(_("play"))            
240             
241         if self.lastfm.metadata.has_key("station"):
242             self.setTitle(myname+": "+self.lastfm.metadata["station"])
243         else:
244             self.setTitle(myname)
245
246         if self.lastfm.metadata.has_key("artist"):
247             self["info_artist"].setText(self.lastfm.metadata["artist"])
248         else:
249             self["info_artist"].setText("N/A")
250
251         if self.lastfm.metadata.has_key("album"):
252             self["info_album"].setText(self.lastfm.metadata["album"])
253         else:
254             self["info_album"].setText("N/A")
255
256         if self.lastfm.metadata.has_key("track"):
257             self["info_track"].setText(self.lastfm.metadata["track"])
258         else:
259             self["info_track"].setText("N/A")
260         
261         if self.lastfm.metadata.has_key("albumcover_large") and config.plugins.LastFM.showcoverart.value:
262             self.imageconverter.convert(self.lastfm.metadata["albumcover_large"])
263         elif self.lastfm.metadata.has_key("albumcover_medium") and config.plugins.LastFM.showcoverart.value:
264             self.imageconverter.convert(self.lastfm.metadata["albumcover_medium"])
265         elif self.lastfm.metadata.has_key("albumcover_small") and config.plugins.LastFM.showcoverart.value:
266             self.imageconverter.convert(self.lastfm.metadata["albumcover_small"],self.setCoverArt)
267         else:
268             self.setCoverArt()
269         
270         if self.streamplayer.is_playing:
271             self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
272         else:
273             self.setTitle(myname)
274             self.setCoverArt()
275             self["info_artist"].setText("N/A")
276             self["info_album"].setText("N/A")
277             self["info_track"].setText("N/A")
278             
279     def setCoverArt(self,pixmap=None):
280         if pixmap is None:
281             self["info_cover"].instance.setPixmapFromFile(self.noCoverArtPNG)            
282         else:
283             self["info_cover"].instance.setPixmap(pixmap.__deref__())
284     
285     def initLastFM(self):
286         self.setInfoLabel("loggin into last.fm")
287         (result,resulttext) = self.lastfm.connect(config.plugins.LastFM.username.value,config.plugins.LastFM.password.value)
288         if result is False:
289             self.setInfoLabel("login failed")
290             Notifications.AddPopup("Login to Last.FM failed!", resulttext,MessageBox.TYPE_INFO, 5)        
291         else:
292             self.setInfoLabel("login successful",timeout=True)      
293
294     def loadPersonalStations(self):
295         tags = []
296         x= {}
297         x["_display"] = "Personal Radio"
298         x["stationurl"] = self.lastfm.getPersonalURL(config.plugins.LastFM.username.value,level=config.plugins.LastFM.recommendedlevel.value)
299         tags.append(x)
300         
301         x= {}
302         x["_display"] = "Neighbours Tracks"
303         x["stationurl"] = self.lastfm.getNeighboursURL(config.plugins.LastFM.username.value)
304         tags.append(x)
305         
306         x= {}
307         x["_display"] = "Loved Tracks"
308         x["stationurl"] = self.lastfm.getLovedURL(config.plugins.LastFM.username.value)
309         tags.append(x)
310         
311         if self.lastfm.metadata.has_key("artist"):
312             x= {}
313             x["_display"] = "similar Tracks of current Artist"
314             x["stationurl"] = self.lastfm.getSimilarArtistsURL()
315             tags.append(x)
316             
317             x= {}
318             x["_display"] = "Tracks liked by Fans of current Track"
319             x["stationurl"] = self.lastfm.getArtistsLikedByFans()
320             tags.append(x)
321
322             x= {}
323             x["_display"] = "Group of Artist of current Track"
324             x["stationurl"] = self.lastfm.getArtistGroup()
325             tags.append(x)
326         
327
328         self.buildMenuList(tags)
329         
330     def loadGlobalTags(self):
331         self.setInfoLabel("loading Global Tags")
332         tags = self.lastfm.getGlobalTags()
333         self.buildMenuList(tags)
334
335     def loadTopTracks(self):
336         self.setInfoLabel("loading Top Tacks")
337         tracks = self.lastfm.getTopTracks(config.plugins.LastFM.username.value)
338         self.buildMenuList(tracks)
339
340     def loadRecentTracks(self):
341         self.setInfoLabel("loading recent Tracks")
342         tracks = self.lastfm.getRecentTracks(config.plugins.LastFM.username.value)
343         self.buildMenuList(tracks)
344
345     def loadLovedTracks(self):
346         self.setInfoLabel("loading loved Tracks")
347         tracks = self.lastfm.getRecentLovedTracks(config.plugins.LastFM.username.value)
348         self.buildMenuList(tracks)
349
350     def loadBannedTracks(self):
351         self.setInfoLabel("loading loved Tracks")
352         tracks = self.lastfm.getRecentBannedTracks(config.plugins.LastFM.username.value)
353         self.buildMenuList(tracks)
354         
355     def loadNeighbours(self):
356         self.setInfoLabel("loading Neighbours")
357         tracks = self.lastfm.getNeighbours(config.plugins.LastFM.username.value)
358         self.buildMenuList(tracks)
359
360     def loadFriends(self):
361         self.setInfoLabel("loading Friends")
362         tracks = self.lastfm.getFriends(config.plugins.LastFM.username.value)
363         self.buildMenuList(tracks)
364
365     def buildMenuList(self,items):
366         menuliste = []
367         for i in items:
368             menuliste.append((i['_display'],i['stationurl']))
369         self["streamlist"].l.setList(menuliste) 
370
371
372 class ImageConverter:
373     
374     targetfile= "/tmp/coverart"
375     lastURL =""
376
377     def __init__(self,callBack):
378         self.callBack = callBack
379
380     def convert(self,sourceURL):
381         if self.lastURL == sourceURL:
382             print "imageurl not changed, skipped"
383         else:
384             extension = sourceURL.split(".")[-1]
385             tmpfile = self.targetfile+"."+extension
386             
387             fpurl = urllib.urlopen(sourceURL)
388             raw = fpurl.read()
389             fpurl.close()
390             
391             fp = open(tmpfile,"w")
392             fp.write(raw)
393             fp.close()
394             
395             self.currPic = loadPic(tmpfile, 116, 116, 1, 1, 0,1)
396             
397             os.remove(tmpfile)
398             
399             self.callBack(pixmap=self.currPic)
400             self.lastURL = sourceURL