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 selectedTag = self["streamlist"].l.getCurrentSelection()[1]
\r
281 self.changeStation(selectedTag)
\r
282 self.resetScreensaverTimer()
\r
284 def action_startstop(self):
\r
285 self.resetScreensaverTimer()
\r
286 if self.streamplayer.is_playing:
\r
287 self.streamplayer.stop()
\r
289 self.setInfoLabel("stream stopped")
\r
292 self.setInfoLabel("starting stream",timeout=True)
\r
293 if self.info.has_key("stream_url"):
\r
294 self.streamplayer.play(self.info["stream_url"])
\r
295 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
\r
297 def setInfoLabel(self,text,timeout=True):
\r
298 self.infolabelcleartimer.stop()
\r
299 self["infolabel"].setText(text)
\r
300 if timeout is True:
\r
301 self.infolabelcleartimer.start(config.plugins.LastFM.timeoutstatustext.value*1000)
\r
303 def clearInfoLabel(self):
\r
304 self["infolabel"].setText("")
\r
306 def updateGUI(self):
\r
307 if self.streamplayer.is_playing is not True or self.shown is not True:
\r
310 if self.streamplayer.is_playing:
\r
311 self["button_red"].setText(_("stop"))
\r
313 self["button_red"].setText(_("play"))
\r
315 if self.metadata.has_key("station"):
\r
316 self.setTitle("Last.FM: "+self.metadata["station"])
\r
318 self.setTitle("Last.FM")
\r
320 if self.metadata.has_key("artist"):
\r
321 self["info_artist"].setText(self.metadata["artist"])
\r
323 self["info_artist"].setText("N/A")
\r
325 if self.metadata.has_key("album"):
\r
326 self["info_album"].setText(self.metadata["album"])
\r
328 self["info_album"].setText("N/A")
\r
330 if self.metadata.has_key("track"):
\r
331 self["info_track"].setText(self.metadata["track"])
\r
333 self["info_track"].setText("N/A")
\r
335 if self.metadata.has_key("albumcover_large") and config.plugins.LastFM.showcoverart.value:
\r
336 self.imageconverter.convert(self.metadata["albumcover_large"])
\r
337 elif self.metadata.has_key("albumcover_medium") and config.plugins.LastFM.showcoverart.value:
\r
338 self.imageconverter.convert(self.metadata["albumcover_medium"])
\r
339 elif self.metadata.has_key("albumcover_small") and config.plugins.LastFM.showcoverart.value:
\r
340 self.imageconverter.convert(self.metadata["albumcover_small"],self.setCoverArt)
\r
344 if self.streamplayer.is_playing is not True:
\r
345 self.setTitle(myname)
\r
347 self["info_artist"].setText("N/A")
\r
348 self["info_album"].setText("N/A")
\r
349 self["info_track"].setText("N/A")
\r
351 def setCoverArt(self,pixmap=None):
\r
353 self["info_cover"].instance.setPixmapFromFile(self.noCoverArtPNG)
\r
355 self["info_cover"].instance.setPixmap(pixmap.__deref__())
\r
358 def loadPersonalStations(self):
\r
361 x["_display"] = "Personal Radio"
\r
362 x["stationurl"] = self.getPersonalURL(config.plugins.LastFM.username.value,level=config.plugins.LastFM.recommendedlevel.value)
\r
366 x["_display"] = "Neighbours Tracks"
\r
367 x["stationurl"] = self.getNeighboursURL(config.plugins.LastFM.username.value)
\r
371 x["_display"] = "Loved Tracks"
\r
372 x["stationurl"] = self.getLovedURL(config.plugins.LastFM.username.value)
\r
375 if self.metadata.has_key("artist"):
\r
377 x["_display"] = "similar Tracks of current Artist"
\r
378 x["stationurl"] = self.getSimilarArtistsURL()
\r
382 x["_display"] = "Tracks liked by Fans of current Track"
\r
383 x["stationurl"] = self.getArtistsLikedByFans()
\r
387 x["_display"] = "Group of Artist of current Track"
\r
388 x["stationurl"] = self.getArtistGroup()
\r
391 self.buildMenuList(tags)
\r
393 def loadGlobalTags(self):
\r
394 self.setInfoLabel("loading Global Tags")
\r
395 tags = self.getGlobalTags()
\r
397 def loadTopTracks(self):
\r
398 self.setInfoLabel("loading Top Tacks")
\r
399 tracks = self.getTopTracks(config.plugins.LastFM.username.value)
\r
401 def loadRecentTracks(self):
\r
402 self.setInfoLabel("loading recent Tracks")
\r
403 tracks = self.getRecentTracks(config.plugins.LastFM.username.value)
\r
405 def loadLovedTracks(self):
\r
406 self.setInfoLabel("loading loved Tracks")
\r
407 tracks = self.getRecentLovedTracks(config.plugins.LastFM.username.value)
\r
409 def loadBannedTracks(self):
\r
410 self.setInfoLabel("loading loved Tracks")
\r
411 tracks = self.getRecentBannedTracks(config.plugins.LastFM.username.value)
\r
413 def loadNeighbours(self):
\r
414 self.setInfoLabel("loading Neighbours")
\r
415 tracks = self.getNeighbours(config.plugins.LastFM.username.value)
\r
417 def loadFriends(self):
\r
418 self.setInfoLabel("loading Friends")
\r
419 tracks = self.getFriends(config.plugins.LastFM.username.value)
\r
421 def buildMenuList(self,items):
\r
424 menuliste.append((i['_display'],i['stationurl']))
\r
425 self["streamlist"].l.setList(menuliste)
\r
427 class LastFMSaveScreen(Screen):
\r
428 skin = """<screen position="0,0" size="720,576" flags="wfNoBorder" title="LastFMSaveScreen" >
\r
429 <widget name="cover" position="50,50" size="200,200" />
\r
431 noCoverArtPNG = "/usr/share/enigma2/no_coverArt.png"
\r
432 coverartsize= [200,200]
\r
433 def __init__(self,session,initialMetadata):
\r
434 self.skin = """<screen position="0,0" size="720,576" flags="wfNoBorder" title="LastFMSaveScreen" >
\r
435 <widget name="cover" position="50,50" size="%i,%i" />
\r
436 </screen>"""%(self.coverartsize[0],self.coverartsize[1])
\r
438 Screen.__init__(self,session)
\r
439 self.imageconverter = ImageConverter(self.coverartsize[0],self.coverartsize[1],self.setCoverArt)
\r
440 self.session = session
\r
441 self.initialMetadata = initialMetadata
\r
442 self["cover"] = MovingPixmap()
\r
443 self["actions"] = ActionMap(["InfobarChannelSelection","WizardActions", "DirectionActions","MenuActions","ShortcutActions","GlobalActions","HelpActions"],
\r
445 "ok": self.action_exit,
\r
446 "back": self.action_exit,
\r
449 self.onLayoutFinish.append(self.update)
\r
450 self.onLayoutFinish.append(self.registerToMetadataUpdates)
\r
452 if config.plugins.LastFM.sreensaver.coverartanimation.value:
\r
453 self.startmovingtimer = eTimer()
\r
454 self.startmovingtimer.timeout.get().append(self.movePixmap)
\r
455 self.startmovingtimer.start(config.plugins.LastFM.sreensaver.coverartinterval.value*1000)
\r
457 def action_ok(self):
\r
460 def action_exit(self):
\r
461 lastfm_event_register.removeOnMetadataChanged(self.update)
\r
464 def setCoverArt(self,pixmap=None):
\r
466 self["cover"].instance.setPixmapFromFile(self.noCoverArtPNG)
\r
468 self["cover"].instance.setPixmap(pixmap.__deref__())
\r
470 def registerToMetadataUpdates(self):
\r
471 lastfm_event_register.addOnMetadataChanged(self.update)#added here, to make shure that is called after onLayoutFinished
\r
474 def update(self,metadata=None):
\r
476 if metadata is None:
\r
477 metadata = self.initialMetadata
\r
479 if config.plugins.LastFM.sreensaver.showcoverart.value is not True:
\r
481 elif metadata.has_key("albumcover_large") and config.plugins.LastFM.showcoverart.value:
\r
482 self.imageconverter.convert(metadata["albumcover_large"])
\r
483 elif metadata.has_key("albumcover_medium") and config.plugins.LastFM.showcoverart.value:
\r
484 self.imageconverter.convert(metadata["albumcover_medium"])
\r
485 elif metadata.has_key("albumcover_small") and config.plugins.LastFM.showcoverart.value:
\r
486 self.imageconverter.convert(metadata["albumcover_small"],self.setCoverArt)
\r
490 def movePixmap(self):
\r
491 self.startmovingtimer.stop()
\r
492 newX = random.randrange(720-self.coverartsize[0]-1)
\r
493 newY = random.randrange(576-self.coverartsize[1]-1)
\r
494 self["cover"].moveTo(newX, newY, time = config.plugins.LastFM.sreensaver.coverartspeed.value)
\r
495 self["cover"].startMoving()
\r
496 self.startmovingtimer.start(config.plugins.LastFM.sreensaver.coverartinterval.value*1000)
\r
498 class ImageConverter:
\r
502 def __init__(self,width,height,callBack):
\r
503 self.callBack = callBack
\r
505 self.height = height
\r
506 self.targetfile= "/tmp/coverart"+str(random.randrange(5000))
\r
509 def convert(self,sourceURL):
\r
510 if self.lastURL != sourceURL:
\r
511 extension = sourceURL.split(".")[-1]
\r
512 self.tmpfile = self.targetfile+"."+extension
\r
513 host = sourceURL.split("/")[2]
\r
514 path = "/"+"/".join(sourceURL.split("/")[3:])
\r
515 httpclient.getFile(self.tmpfile,host,80,path,callback=self.onImageLoaded)
\r
516 self.lastURL = sourceURL
\r
518 def onImageLoaded(self):
\r
519 self.currPic = loadPic(self.tmpfile, self.width, self.height, 0,1, 0,1)
\r
520 os.remove(self.tmpfile)
\r
521 self.callBack(pixmap=self.currPic)
\r