1 from enigma import eTimer
\r
2 from enigma import eConsoleAppContainer
\r
3 from enigma import loadPic
\r
5 from Screens.Screen import Screen
\r
6 from Screens.MessageBox import MessageBox
\r
7 from Screens.HelpMenu import HelpableScreen , HelpMenu
\r
9 from Components.Pixmap import Pixmap,MovingPixmap
\r
10 from Components.Label import Label
\r
11 from Components.MenuList import MenuList
\r
12 from Components.ActionMap import ActionMap, NumberActionMap
\r
13 from Components.config import config, ConfigSubsection, ConfigSlider,ConfigInteger,ConfigYesNo, ConfigText
\r
14 from Components.HelpMenuList import HelpMenuList
\r
17 from Tools import Notifications
\r
19 from Plugins.Plugin import PluginDescriptor
\r
21 from StreamPlayer import StreamPlayer
\r
22 from LastFMConfig import LastFMConfigScreen
\r
23 from LastFM import LastFM, lastfm_event_register
\r
30 ###############################################################################
\r
33 ###############################################################################
\r
35 config.plugins.LastFM = ConfigSubsection()
\r
36 config.plugins.LastFM.showcoverart = ConfigYesNo(default = True)
\r
37 config.plugins.LastFM.username = ConfigText("user",fixed_size=False)
\r
38 config.plugins.LastFM.password = ConfigText("passwd",fixed_size=False)
\r
39 config.plugins.LastFM.timeoutstatustext = ConfigInteger(3,limits = (0, 10))
\r
40 config.plugins.LastFM.timeouttabselect = ConfigInteger(2,limits = (0, 10))
\r
41 config.plugins.LastFM.metadatarefreshinterval = ConfigInteger(5,limits = (0, 100))
\r
42 config.plugins.LastFM.recommendedlevel = ConfigInteger(3,limits = (0, 100))
\r
44 config.plugins.LastFM.sreensaver = ConfigSubsection()
\r
45 config.plugins.LastFM.sreensaver.use = ConfigYesNo(default = True)
\r
46 config.plugins.LastFM.sreensaver.wait = ConfigInteger(30,limits = (0, 1000))
\r
47 config.plugins.LastFM.sreensaver.showcoverart = ConfigYesNo(default = True)
\r
48 config.plugins.LastFM.sreensaver.coverartanimation = ConfigYesNo(default = True)
\r
49 config.plugins.LastFM.sreensaver.coverartspeed = ConfigInteger(10,limits = (0, 100))
\r
50 config.plugins.LastFM.sreensaver.coverartinterval = ConfigInteger(10,limits = (0, 100))
\r
52 ###############################################################################
\r
53 def main(session,**kwargs):
\r
54 session.open(LastFMScreenMain)
\r
56 def Plugins(path,**kwargs):
\r
59 return PluginDescriptor(
\r
61 description="the social music revolution",
\r
62 where = PluginDescriptor.WHERE_PLUGINMENU,
\r
65 ###############################################################################
\r
66 class LastFMScreenMain(Screen,HelpableScreen,LastFM):
\r
68 <screen position="110,83" size="530,430" title="Last.FM" >
\r
70 <widget name="artist" position="0,0" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
\r
71 <widget name="album" position="0,40" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
\r
72 <widget name="track" position="0,80" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
\r
74 <widget name="info_artist" position="70,0" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
\r
75 <widget name="info_album" position="70,40" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
\r
76 <widget name="info_track" position="70,80" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
\r
77 <widget name="info_cover" position="414,0" size="116,116" />
\r
79 <widget name="tablist" position="0,120" size="150,260" scrollbarMode="showOnDemand" />
\r
80 <widget name="streamlist" position="150,120" size="380,260" scrollbarMode="showOnDemand" />
\r
82 <widget name="button_red" position="10,400" size="60,30" backgroundColor=\"red\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
\r
83 <widget name="button_green" position="80,400" size="60,30" backgroundColor=\"green\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\"/>
\r
84 <widget name="button_yellow" position="150,400" size="60,30" backgroundColor=\"yellow\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
\r
85 <widget name="button_blue" position="220,400" size="60,30" backgroundColor=\"blue\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
\r
86 <widget name="infolabel" position="290,400" size="290,30" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
\r
89 noCoverArtPNG = "/usr/share/enigma2/no_coverArt.png"
\r
91 def __init__(self, session, args = 0):
\r
92 self.skin = LastFMScreenMain.skin
\r
93 Screen.__init__(self, session)
\r
94 HelpableScreen.__init__(self)
\r
95 LastFM.__init__(self)
\r
96 self.session = session
\r
97 self.streamplayer = StreamPlayer(session)
\r
98 self.streamplayer.onStateChanged.append(self.updateGUI)
\r
99 self.imageconverter = ImageConverter(116,116,self.setCoverArt)
\r
100 Screen.__init__(self, session)
\r
102 self.tabs=[("personal Stations",self.loadPersonalStations)
\r
103 ,("Global Tags",self.loadGlobalTags)
\r
104 ,("Top Tracks",self.loadTopTracks)
\r
105 ,("Recent Tracks",self.loadRecentTracks)
\r
106 ,("Loved Tracks",self.loadLovedTracks)
\r
107 ,("Banned Tracks",self.loadBannedTracks)
\r
108 ,("Friends",self.loadFriends)
\r
109 ,("Neighbours",self.loadNeighbours)
\r
112 for tab in self.tabs:
\r
113 tablist.append((tab[0],tab))
\r
114 self.tablist = MenuList(tablist)
\r
115 self.tablist.onSelectionChanged.append(self.action_TabChanged)
\r
117 self["artist"] = Label(_("Artist")+":")
\r
118 self["album"] = Label(_("Album")+":")
\r
119 self["track"] = Label(_("Track")+":")
\r
121 self["info_artist"] = Label("N/A")
\r
122 self["info_album"] = Label("N/A")
\r
123 self["info_track"] = Label("N/A")
\r
124 self["info_cover"] = Pixmap()
\r
126 self["tablist"] = self.tablist
\r
127 self["streamlist"] = MenuList([])
\r
129 self["button_red"] = Label(_("play"))
\r
130 self["button_green"] = Label(_("skip"))
\r
131 self["button_yellow"] = Label(_("love"))
\r
132 self["button_blue"] = Label(_("ban"))
\r
133 self["infolabel"] = Label("")
\r
135 self["actions"] = ActionMap(["InfobarChannelSelection","WizardActions", "DirectionActions","MenuActions","ShortcutActions","GlobalActions","HelpActions","NumberActions"],
\r
137 "ok": self.action_ok,
\r
138 "back": self.action_exit,
\r
139 "red": self.action_startstop,
\r
140 "green": self.skip,
\r
141 "yellow": self.love,
\r
143 "historyNext": self.action_nextTab,
\r
144 "historyBack": self.action_prevTab,
\r
146 "menu": self.action_menu,
\r
149 self.helpList.append((self["actions"], "WizardActions", [("ok", _("switch to selected Station"))]))
\r
150 self.helpList.append((self["actions"], "WizardActions", [("back", _("quit Last.FM"))]))
\r
152 self.helpList.append((self["actions"], "MenuActions", [("menu", _("open Configuration"))]))
\r
154 self.helpList.append((self["actions"], "ShortcutActions", [("red", _("start/stop streaming"))]))
\r
155 self.helpList.append((self["actions"], "ShortcutActions", [("green", _("skip current Track"))]))
\r
156 self.helpList.append((self["actions"], "ShortcutActions", [("yellow", _("mark current Track as loved"))]))
\r
157 self.helpList.append((self["actions"], "ShortcutActions", [("blue", _("ban Track, never play again"))]))
\r
158 self.helpList.append((self["actions"], "InfobarChannelSelection", [("historyNext", _("select next Tab"))]))
\r
159 self.helpList.append((self["actions"], "InfobarChannelSelection", [("historyBack", _("select prev Tab"))]))
\r
161 self.onLayoutFinish.append(self.initLastFM)
\r
162 self.onLayoutFinish.append(self.tabchangedtimerFired)
\r
163 self.onLayoutFinish.append(self.setCoverArt)
\r
165 self.guiupdatetimer = eTimer()
\r
166 self.guiupdatetimer.timeout.get().append(self.guiupdatetimerFired)
\r
167 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
\r
169 self.tabchangetimer = eTimer()
\r
170 self.tabchangetimer.timeout.get().append(self.tabchangedtimerFired)
\r
172 self.infolabelcleartimer = eTimer()
\r
173 self.infolabelcleartimer.timeout.get().append(self.clearInfoLabel)
\r
175 self.screensavertimer = eTimer()
\r
176 self.screensavertimer.timeout.get().append(self.startScreensaver)
\r
177 self.onShown.append(self.startScreensaverTimer)
\r
179 def initLastFM(self):
\r
180 self.setInfoLabel("loggin into last.fm")
\r
181 self.connect(config.plugins.LastFM.username.value,config.plugins.LastFM.password.value)
\r
183 def onConnectSuccessful(self,text):
\r
184 self.setInfoLabel("login successful")
\r
186 def onConnectFailed(self,text):
\r
187 self.setInfoLabel("login failed! "+text,timeout=False)
\r
189 def onTrackSkiped(self,reason):
\r
190 self.setInfoLabel("Track skiped")
\r
192 def onTrackLoved(self,reason):
\r
193 self.setInfoLabel("Track loved")
\r
195 def onTrackBaned(self,reason):
\r
196 self.setInfoLabel("Track baned")
\r
198 def onCommandFailed(self,reason):
\r
199 self.setInfoLabel(reason)
\r
201 def onGlobalTagsLoaded(self,tags):
\r
202 self.setInfoLabel("Global Tags loaded")
\r
203 self.buildMenuList(tags)
\r
205 def onTopTracksLoaded(self,tracks):
\r
206 self.setInfoLabel("Top Tracks loaded")
\r
207 self.buildMenuList(tracks)
\r
209 def onRecentTracksLoaded(self,tracks):
\r
210 self.setInfoLabel("recent Tracks loaded")
\r
211 self.buildMenuList(tracks)
\r
213 def onRecentBannedTracksLoaded(self,tracks):
\r
214 self.setInfoLabel("banned Tracks loaded")
\r
215 self.buildMenuList(tracks)
\r
217 def onRecentLovedTracksLoaded(self,tracks):
\r
218 self.setInfoLabel("loved Tracks loaded")
\r
219 self.buildMenuList(tracks)
\r
221 def onNeighboursLoaded(self,user):
\r
222 self.setInfoLabel("Neighbours loaded")
\r
223 self.buildMenuList(user)
\r
225 def onFriendsLoaded(self,user):
\r
226 self.setInfoLabel("Friends loaded")
\r
227 self.buildMenuList(user)
\r
229 def onStationChanged(self,reason):
\r
230 self.setInfoLabel(reason)
\r
232 def onMetadataLoaded(self,metadata):
\r
234 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
\r
236 def action_TabChanged(self):
\r
237 self.tabchangetimer.stop()
\r
238 self.tabchangetimer.start(config.plugins.LastFM.timeouttabselect.value*1000)
\r
240 def guiupdatetimerFired(self):
\r
241 if self.streamplayer.is_playing:
\r
243 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
\r
245 def tabchangedtimerFired(self):
\r
246 self.tablist.getCurrent()[1][1]()
\r
247 self.tabchangetimer.stop()
\r
249 def startScreensaverTimer(self):
\r
250 if config.plugins.LastFM.sreensaver.use.value:
\r
251 self.screensavertimer.start(config.plugins.LastFM.sreensaver.wait.value*1000)
\r
253 def resetScreensaverTimer(self):
\r
254 self.screensavertimer.stop()
\r
255 self.screensavertimer.start(config.plugins.LastFM.sreensaver.wait.value*1000)
\r
257 def startScreensaver(self):
\r
258 self.screensavertimer.stop()
\r
259 self.session.openWithCallback(self.updateGUI, LastFMSaveScreen,self.metadata)
\r
261 def action_nextTab(self):
\r
262 self.tablist.down()
\r
263 self.resetScreensaverTimer()
\r
265 def action_prevTab(self):
\r
267 self.resetScreensaverTimer()
\r
269 def action_menu(self):
\r
270 self.session.open(LastFMConfigScreen)
\r
271 self.resetScreensaverTimer()
\r
273 def action_exit(self):
\r
274 self.screensavertimer.stop()
\r
275 self.guiupdatetimer.stop()
\r
276 self.streamplayer.stop()
\r
279 def action_ok(self):
\r
280 x = self["streamlist"].l.getCurrentSelection()
\r
282 self.changeStation(x[1])
\r
283 self.resetScreensaverTimer()
\r
285 def action_startstop(self):
\r
286 self.resetScreensaverTimer()
\r
287 if self.streamplayer.is_playing:
\r
288 self.streamplayer.stop()
\r
290 self.setInfoLabel("stream stopped")
\r
293 self.setInfoLabel("starting stream",timeout=True)
\r
294 if self.info.has_key("stream_url"):
\r
295 self.streamplayer.play(self.info["stream_url"])
\r
296 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
\r
298 def setInfoLabel(self,text,timeout=True):
\r
299 self.infolabelcleartimer.stop()
\r
300 self["infolabel"].setText(text)
\r
301 if timeout is True:
\r
302 self.infolabelcleartimer.start(config.plugins.LastFM.timeoutstatustext.value*1000)
\r
304 def clearInfoLabel(self):
\r
305 self["infolabel"].setText("")
\r
307 def updateGUI(self):
\r
309 if self.streamplayer.is_playing is True:
\r
310 self["button_red"].setText(_("stop"))
\r
312 self["button_red"].setText(_("play"))
\r
314 if self.streamplayer.is_playing is not True or self.shown is not True:
\r
317 if self.metadata.has_key("station"):
\r
318 self.setTitle("Last.FM: "+self.metadata["station"])
\r
320 self.setTitle("Last.FM")
\r
322 if self.metadata.has_key("artist"):
\r
323 self["info_artist"].setText(self.metadata["artist"])
\r
325 self["info_artist"].setText("N/A")
\r
327 if self.metadata.has_key("album"):
\r
328 self["info_album"].setText(self.metadata["album"])
\r
330 self["info_album"].setText("N/A")
\r
332 if self.metadata.has_key("track"):
\r
333 self["info_track"].setText(self.metadata["track"])
\r
335 self["info_track"].setText("N/A")
\r
337 if self.metadata.has_key("albumcover_large") and config.plugins.LastFM.showcoverart.value:
\r
338 self.imageconverter.convert(self.metadata["albumcover_large"])
\r
339 elif self.metadata.has_key("albumcover_medium") and config.plugins.LastFM.showcoverart.value:
\r
340 self.imageconverter.convert(self.metadata["albumcover_medium"])
\r
341 elif self.metadata.has_key("albumcover_small") and config.plugins.LastFM.showcoverart.value:
\r
342 self.imageconverter.convert(self.metadata["albumcover_small"],self.setCoverArt)
\r
346 if self.streamplayer.is_playing is not True:
\r
347 self.setTitle(myname)
\r
349 self["info_artist"].setText("N/A")
\r
350 self["info_album"].setText("N/A")
\r
351 self["info_track"].setText("N/A")
\r
353 def setCoverArt(self,pixmap=None):
\r
355 self["info_cover"].instance.setPixmapFromFile(self.noCoverArtPNG)
\r
357 self["info_cover"].instance.setPixmap(pixmap.__deref__())
\r
360 def loadPersonalStations(self):
\r
363 x["_display"] = "Personal Radio"
\r
364 x["stationurl"] = self.getPersonalURL(config.plugins.LastFM.username.value,level=config.plugins.LastFM.recommendedlevel.value)
\r
368 x["_display"] = "Neighbours Tracks"
\r
369 x["stationurl"] = self.getNeighboursURL(config.plugins.LastFM.username.value)
\r
373 x["_display"] = "Loved Tracks"
\r
374 x["stationurl"] = self.getLovedURL(config.plugins.LastFM.username.value)
\r
377 if self.metadata.has_key("artist"):
\r
379 x["_display"] = "similar Tracks of current Artist"
\r
380 x["stationurl"] = self.getSimilarArtistsURL()
\r
384 x["_display"] = "Tracks liked by Fans of current Track"
\r
385 x["stationurl"] = self.getArtistsLikedByFans()
\r
389 x["_display"] = "Group of Artist of current Track"
\r
390 x["stationurl"] = self.getArtistGroup()
\r
393 self.buildMenuList(tags)
\r
395 def loadGlobalTags(self):
\r
396 self.setInfoLabel("loading Global Tags")
\r
397 tags = self.getGlobalTags()
\r
399 def loadTopTracks(self):
\r
400 self.setInfoLabel("loading Top Tacks")
\r
401 tracks = self.getTopTracks(config.plugins.LastFM.username.value)
\r
403 def loadRecentTracks(self):
\r
404 self.setInfoLabel("loading recent Tracks")
\r
405 tracks = self.getRecentTracks(config.plugins.LastFM.username.value)
\r
407 def loadLovedTracks(self):
\r
408 self.setInfoLabel("loading loved Tracks")
\r
409 tracks = self.getRecentLovedTracks(config.plugins.LastFM.username.value)
\r
411 def loadBannedTracks(self):
\r
412 self.setInfoLabel("loading loved Tracks")
\r
413 tracks = self.getRecentBannedTracks(config.plugins.LastFM.username.value)
\r
415 def loadNeighbours(self):
\r
416 self.setInfoLabel("loading Neighbours")
\r
417 tracks = self.getNeighbours(config.plugins.LastFM.username.value)
\r
419 def loadFriends(self):
\r
420 self.setInfoLabel("loading Friends")
\r
421 tracks = self.getFriends(config.plugins.LastFM.username.value)
\r
423 def buildMenuList(self,items):
\r
426 menuliste.append((i['_display'],i['stationurl']))
\r
427 self["streamlist"].l.setList(menuliste)
\r
429 class LastFMSaveScreen(Screen):
\r
430 skin = """<screen position="0,0" size="720,576" flags="wfNoBorder" title="LastFMSaveScreen" >
\r
431 <widget name="cover" position="50,50" size="200,200" />
\r
433 noCoverArtPNG = "/usr/share/enigma2/no_coverArt.png"
\r
434 coverartsize= [200,200]
\r
435 def __init__(self,session,initialMetadata):
\r
436 self.skin = """<screen position="0,0" size="720,576" flags="wfNoBorder" title="LastFMSaveScreen" >
\r
437 <widget name="cover" position="50,50" size="%i,%i" />
\r
438 </screen>"""%(self.coverartsize[0],self.coverartsize[1])
\r
440 Screen.__init__(self,session)
\r
441 self.imageconverter = ImageConverter(self.coverartsize[0],self.coverartsize[1],self.setCoverArt)
\r
442 self.session = session
\r
443 self.initialMetadata = initialMetadata
\r
444 self["cover"] = MovingPixmap()
\r
445 self["actions"] = ActionMap(["InfobarChannelSelection","WizardActions", "DirectionActions","MenuActions","ShortcutActions","GlobalActions","HelpActions"],
\r
447 "ok": self.action_exit,
\r
448 "back": self.action_exit,
\r
451 self.onLayoutFinish.append(self.update)
\r
452 self.onLayoutFinish.append(self.registerToMetadataUpdates)
\r
454 if config.plugins.LastFM.sreensaver.coverartanimation.value:
\r
455 self.startmovingtimer = eTimer()
\r
456 self.startmovingtimer.timeout.get().append(self.movePixmap)
\r
457 self.startmovingtimer.start(config.plugins.LastFM.sreensaver.coverartinterval.value*1000)
\r
459 def action_ok(self):
\r
462 def action_exit(self):
\r
463 lastfm_event_register.removeOnMetadataChanged(self.update)
\r
466 def setCoverArt(self,pixmap=None):
\r
468 self["cover"].instance.setPixmapFromFile(self.noCoverArtPNG)
\r
470 self["cover"].instance.setPixmap(pixmap.__deref__())
\r
472 def registerToMetadataUpdates(self):
\r
473 lastfm_event_register.addOnMetadataChanged(self.update)#added here, to make shure that is called after onLayoutFinished
\r
476 def update(self,metadata=None):
\r
478 if metadata is None:
\r
479 metadata = self.initialMetadata
\r
481 if config.plugins.LastFM.sreensaver.showcoverart.value is not True:
\r
483 elif metadata.has_key("albumcover_large") and config.plugins.LastFM.showcoverart.value:
\r
484 self.imageconverter.convert(metadata["albumcover_large"])
\r
485 elif metadata.has_key("albumcover_medium") and config.plugins.LastFM.showcoverart.value:
\r
486 self.imageconverter.convert(metadata["albumcover_medium"])
\r
487 elif metadata.has_key("albumcover_small") and config.plugins.LastFM.showcoverart.value:
\r
488 self.imageconverter.convert(metadata["albumcover_small"],self.setCoverArt)
\r
492 def movePixmap(self):
\r
493 self.startmovingtimer.stop()
\r
494 newX = random.randrange(720-self.coverartsize[0]-1)
\r
495 newY = random.randrange(576-self.coverartsize[1]-1)
\r
496 self["cover"].moveTo(newX, newY, time = config.plugins.LastFM.sreensaver.coverartspeed.value)
\r
497 self["cover"].startMoving()
\r
498 self.startmovingtimer.start(config.plugins.LastFM.sreensaver.coverartinterval.value*1000)
\r
500 class ImageConverter:
\r
504 def __init__(self,width,height,callBack):
\r
505 self.callBack = callBack
\r
507 self.height = height
\r
508 self.targetfile= "/tmp/coverart"+str(random.randrange(5000))
\r
511 def convert(self,sourceURL):
\r
512 if self.lastURL != sourceURL:
\r
513 extension = sourceURL.split(".")[-1]
\r
514 self.tmpfile = self.targetfile+"."+extension
\r
515 host = sourceURL.split("/")[2]
\r
516 path = "/"+"/".join(sourceURL.split("/")[3:])
\r
517 httpclient.getFile(self.tmpfile,host,80,path,callback=self.onImageLoaded)
\r
518 self.lastURL = sourceURL
\r
520 def onImageLoaded(self):
\r
521 self.currPic = loadPic(self.tmpfile, self.width, self.height, 0,1, 0,1)
\r
522 os.remove(self.tmpfile)
\r
523 self.callBack(pixmap=self.currPic)
\r