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