1 from enigma import eTimer
2 from enigma import eConsoleAppContainer
3 from enigma import loadPic
5 from Screens.Screen import Screen
6 from Screens.MessageBox import MessageBox
7 from Screens.HelpMenu import HelpableScreen , HelpMenu
9 from Components.Pixmap import Pixmap,MovingPixmap
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
17 from Tools import Notifications
19 from Plugins.Plugin import PluginDescriptor
21 from StreamPlayer import StreamPlayer
22 from LastFMConfig import LastFMConfigScreen
23 from LastFM import LastFM, lastfm_event_register
30 ###############################################################################
33 ###############################################################################
35 config.plugins.LastFM = ConfigSubsection()
36 config.plugins.LastFM.showcoverart = ConfigYesNo(default = True)
37 config.plugins.LastFM.username = ConfigText("user",fixed_size=False)
38 config.plugins.LastFM.password = ConfigText("passwd",fixed_size=False)
39 config.plugins.LastFM.timeoutstatustext = ConfigInteger(3,limits = (0, 10))
40 config.plugins.LastFM.timeouttabselect = ConfigInteger(2,limits = (0, 10))
41 config.plugins.LastFM.metadatarefreshinterval = ConfigInteger(5,limits = (0, 100))
42 config.plugins.LastFM.recommendedlevel = ConfigInteger(3,limits = (0, 100))
43 config.plugins.LastFM.sendSubmissions = ConfigYesNo(default = False)
45 config.plugins.LastFM.sreensaver = ConfigSubsection()
46 config.plugins.LastFM.sreensaver.use = ConfigYesNo(default = True)
47 config.plugins.LastFM.sreensaver.wait = ConfigInteger(30,limits = (0, 1000))
48 config.plugins.LastFM.sreensaver.showcoverart = ConfigYesNo(default = True)
49 config.plugins.LastFM.sreensaver.coverartanimation = ConfigYesNo(default = True)
50 config.plugins.LastFM.sreensaver.coverartspeed = ConfigInteger(10,limits = (0, 100))
51 config.plugins.LastFM.sreensaver.coverartinterval = ConfigInteger(10,limits = (0, 100))
53 ###############################################################################
54 def main(session,**kwargs):
55 session.open(LastFMScreenMain)
57 def startScrobbler(reason, **kwargs):
58 if "session" in kwargs and config.plugins.LastFM.sendSubmissions.value:
59 from scrobbler import EventListener
60 evl = EventListener(kwargs["session"])
61 evl.startListenToEvents()
63 def Plugins(path,**kwargs):
66 return [PluginDescriptor(
68 description="the social music revolution",
69 where = PluginDescriptor.WHERE_PLUGINMENU,
72 PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc = startScrobbler)
74 ###############################################################################
75 class LastFMScreenMain(Screen,HelpableScreen,LastFM):
77 <screen position="110,83" size="530,430" title="Last.FM" >
79 <widget name="artist" position="0,0" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
80 <widget name="album" position="0,40" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
81 <widget name="track" position="0,80" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
83 <widget name="info_artist" position="70,0" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
84 <widget name="info_album" position="70,40" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
85 <widget name="info_track" position="70,80" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
86 <widget name="info_cover" position="414,0" size="116,116" />
88 <widget name="tablist" position="0,120" size="150,260" scrollbarMode="showOnDemand" />
89 <widget name="streamlist" position="150,120" size="380,260" scrollbarMode="showOnDemand" />
91 <widget name="button_red" position="10,400" size="60,30" backgroundColor=\"red\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
92 <widget name="button_green" position="80,400" size="60,30" backgroundColor=\"green\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\"/>
93 <widget name="button_yellow" position="150,400" size="60,30" backgroundColor=\"yellow\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
94 <widget name="button_blue" position="220,400" size="60,30" backgroundColor=\"blue\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
95 <widget name="infolabel" position="290,400" size="290,30" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
98 noCoverArtPNG = "/usr/share/enigma2/no_coverArt.png"
100 def __init__(self, session, args = 0):
101 self.skin = LastFMScreenMain.skin
102 Screen.__init__(self, session)
103 HelpableScreen.__init__(self)
104 LastFM.__init__(self)
105 self.session = session
106 self.streamplayer = StreamPlayer(session)
107 self.streamplayer.onStateChanged.append(self.updateGUI)
108 self.imageconverter = ImageConverter(116,116,self.setCoverArt)
109 Screen.__init__(self, session)
111 self.tabs=[("personal Stations",self.loadPersonalStations)
112 ,("Global Tags",self.loadGlobalTags)
113 ,("Top Tracks",self.loadTopTracks)
114 ,("Recent Tracks",self.loadRecentTracks)
115 ,("Loved Tracks",self.loadLovedTracks)
116 ,("Banned Tracks",self.loadBannedTracks)
117 ,("Friends",self.loadFriends)
118 ,("Neighbours",self.loadNeighbours)
121 for tab in self.tabs:
122 tablist.append((tab[0],tab))
123 self.tablist = MenuList(tablist)
124 self.tablist.onSelectionChanged.append(self.action_TabChanged)
126 self["artist"] = Label(_("Artist")+":")
127 self["album"] = Label(_("Album")+":")
128 self["track"] = Label(_("Track")+":")
130 self["info_artist"] = Label("N/A")
131 self["info_album"] = Label("N/A")
132 self["info_track"] = Label("N/A")
133 self["info_cover"] = Pixmap()
135 self["tablist"] = self.tablist
136 self["streamlist"] = MenuList([])
138 self["button_red"] = Label(_("play"))
139 self["button_green"] = Label(_("skip"))
140 self["button_yellow"] = Label(_("love"))
141 self["button_blue"] = Label(_("ban"))
142 self["infolabel"] = Label("")
144 self["actions"] = ActionMap(["InfobarChannelSelection","WizardActions", "DirectionActions","MenuActions","ShortcutActions","GlobalActions","HelpActions","NumberActions"],
146 "ok": self.action_ok,
147 "back": self.action_exit,
148 "red": self.action_startstop,
152 "historyNext": self.action_nextTab,
153 "historyBack": self.action_prevTab,
155 "menu": self.action_menu,
158 self.helpList.append((self["actions"], "WizardActions", [("ok", _("switch to selected Station"))]))
159 self.helpList.append((self["actions"], "WizardActions", [("back", _("quit Last.FM"))]))
161 self.helpList.append((self["actions"], "MenuActions", [("menu", _("open Configuration"))]))
163 self.helpList.append((self["actions"], "ShortcutActions", [("red", _("start/stop streaming"))]))
164 self.helpList.append((self["actions"], "ShortcutActions", [("green", _("skip current Track"))]))
165 self.helpList.append((self["actions"], "ShortcutActions", [("yellow", _("mark current Track as loved"))]))
166 self.helpList.append((self["actions"], "ShortcutActions", [("blue", _("ban Track, never play again"))]))
167 self.helpList.append((self["actions"], "InfobarChannelSelection", [("historyNext", _("select next Tab"))]))
168 self.helpList.append((self["actions"], "InfobarChannelSelection", [("historyBack", _("select prev Tab"))]))
170 self.onLayoutFinish.append(self.initLastFM)
171 self.onLayoutFinish.append(self.tabchangedtimerFired)
172 self.onLayoutFinish.append(self.setCoverArt)
174 self.guiupdatetimer = eTimer()
175 self.guiupdatetimer.timeout.get().append(self.guiupdatetimerFired)
176 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
178 self.tabchangetimer = eTimer()
179 self.tabchangetimer.timeout.get().append(self.tabchangedtimerFired)
181 self.infolabelcleartimer = eTimer()
182 self.infolabelcleartimer.timeout.get().append(self.clearInfoLabel)
184 self.screensavertimer = eTimer()
185 self.screensavertimer.timeout.get().append(self.startScreensaver)
186 self.onShown.append(self.startScreensaverTimer)
188 def initLastFM(self):
189 self.setInfoLabel("loggin into last.fm")
190 self.connect(config.plugins.LastFM.username.value,config.plugins.LastFM.password.value)
192 def onConnectSuccessful(self,text):
193 self.setInfoLabel("login successful")
195 def onConnectFailed(self,text):
196 self.setInfoLabel("login failed! "+text,timeout=False)
198 def onTrackSkiped(self,reason):
199 self.setInfoLabel("Track skiped")
201 def onTrackLoved(self,reason):
202 self.setInfoLabel("Track loved")
204 def onTrackBaned(self,reason):
205 self.setInfoLabel("Track baned")
207 def onCommandFailed(self,reason):
208 self.setInfoLabel(reason)
210 def onGlobalTagsLoaded(self,tags):
211 self.setInfoLabel("Global Tags loaded")
212 self.buildMenuList(tags)
214 def onTopTracksLoaded(self,tracks):
215 self.setInfoLabel("Top Tracks loaded")
216 self.buildMenuList(tracks)
218 def onRecentTracksLoaded(self,tracks):
219 self.setInfoLabel("recent Tracks loaded")
220 self.buildMenuList(tracks)
222 def onRecentBannedTracksLoaded(self,tracks):
223 self.setInfoLabel("banned Tracks loaded")
224 self.buildMenuList(tracks)
226 def onRecentLovedTracksLoaded(self,tracks):
227 self.setInfoLabel("loved Tracks loaded")
228 self.buildMenuList(tracks)
230 def onNeighboursLoaded(self,user):
231 self.setInfoLabel("Neighbours loaded")
232 self.buildMenuList(user)
234 def onFriendsLoaded(self,user):
235 self.setInfoLabel("Friends loaded")
236 self.buildMenuList(user)
238 def onStationChanged(self,reason):
239 self.setInfoLabel(reason)
241 def onMetadataLoaded(self,metadata):
243 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
245 def action_TabChanged(self):
246 self.tabchangetimer.stop()
247 self.tabchangetimer.start(config.plugins.LastFM.timeouttabselect.value*1000)
249 def guiupdatetimerFired(self):
250 if self.streamplayer.is_playing:
252 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
254 def tabchangedtimerFired(self):
255 self.tablist.getCurrent()[1][1]()
256 self.tabchangetimer.stop()
258 def startScreensaverTimer(self):
259 if config.plugins.LastFM.sreensaver.use.value:
260 self.screensavertimer.start(config.plugins.LastFM.sreensaver.wait.value*1000)
262 def resetScreensaverTimer(self):
263 self.screensavertimer.stop()
264 self.screensavertimer.start(config.plugins.LastFM.sreensaver.wait.value*1000)
266 def startScreensaver(self):
267 self.screensavertimer.stop()
268 self.session.openWithCallback(self.updateGUI, LastFMSaveScreen,self.metadata)
270 def action_nextTab(self):
272 self.resetScreensaverTimer()
274 def action_prevTab(self):
276 self.resetScreensaverTimer()
278 def action_menu(self):
279 self.session.open(LastFMConfigScreen)
280 self.resetScreensaverTimer()
282 def action_exit(self):
283 self.screensavertimer.stop()
284 self.guiupdatetimer.stop()
285 self.streamplayer.stop()
286 self.streamplayer.onStateChanged=[]
291 x = self["streamlist"].l.getCurrentSelection()
295 self.changeStation(x[1])
296 self.resetScreensaverTimer()
298 def action_startstop(self):
299 self.resetScreensaverTimer()
300 if self.streamplayer.is_playing:
301 self.streamplayer.stop()
303 self.setInfoLabel("stream stopped")
306 self.setInfoLabel("starting stream",timeout=True)
307 if self.info.has_key("stream_url"):
308 self.streamplayer.play(self.info["stream_url"])
309 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
311 def setInfoLabel(self,text,timeout=True):
312 self.infolabelcleartimer.stop()
313 self["infolabel"].setText(text)
315 self.infolabelcleartimer.start(config.plugins.LastFM.timeoutstatustext.value*1000)
317 def clearInfoLabel(self):
318 self["infolabel"].setText("")
322 if self.streamplayer.is_playing is True:
323 self["button_red"].setText(_("stop"))
325 self["button_red"].setText(_("play"))
327 if self.streamplayer.is_playing is not True or self.shown is not True:
330 if self.metadata.has_key("station"):
331 self.setTitle("Last.FM: "+self.metadata["station"])
333 self.setTitle("Last.FM")
335 if self.metadata.has_key("artist"):
336 self["info_artist"].setText(self.metadata["artist"])
338 self["info_artist"].setText("N/A")
340 if self.metadata.has_key("album"):
341 self["info_album"].setText(self.metadata["album"])
343 self["info_album"].setText("N/A")
345 if self.metadata.has_key("track"):
346 self["info_track"].setText(self.metadata["track"])
348 self["info_track"].setText("N/A")
350 if self.metadata.has_key("albumcover_large") and config.plugins.LastFM.showcoverart.value:
351 self.imageconverter.convert(self.metadata["albumcover_large"])
352 elif self.metadata.has_key("albumcover_medium") and config.plugins.LastFM.showcoverart.value:
353 self.imageconverter.convert(self.metadata["albumcover_medium"])
354 elif self.metadata.has_key("albumcover_small") and config.plugins.LastFM.showcoverart.value:
355 self.imageconverter.convert(self.metadata["albumcover_small"],self.setCoverArt)
359 if self.streamplayer.is_playing is not True:
360 self.setTitle(myname)
362 self["info_artist"].setText("N/A")
363 self["info_album"].setText("N/A")
364 self["info_track"].setText("N/A")
366 def setCoverArt(self,pixmap=None):
368 self["info_cover"].instance.setPixmapFromFile(self.noCoverArtPNG)
370 self["info_cover"].instance.setPixmap(pixmap.__deref__())
373 def loadPersonalStations(self):
376 x["_display"] = "Personal Radio"
377 x["stationurl"] = self.getPersonalURL(config.plugins.LastFM.username.value,level=config.plugins.LastFM.recommendedlevel.value)
381 x["_display"] = "Neighbours Tracks"
382 x["stationurl"] = self.getNeighboursURL(config.plugins.LastFM.username.value)
386 x["_display"] = "Loved Tracks"
387 x["stationurl"] = self.getLovedURL(config.plugins.LastFM.username.value)
390 if self.metadata.has_key("artist"):
392 x["_display"] = "similar Tracks of current Artist"
393 x["stationurl"] = self.getSimilarArtistsURL()
397 x["_display"] = "Tracks liked by Fans of current Track"
398 x["stationurl"] = self.getArtistsLikedByFans()
402 x["_display"] = "Group of Artist of current Track"
403 x["stationurl"] = self.getArtistGroup()
406 self.buildMenuList(tags)
408 def loadGlobalTags(self):
409 self.setInfoLabel("loading Global Tags")
410 tags = self.getGlobalTags()
412 def loadTopTracks(self):
413 self.setInfoLabel("loading Top Tacks")
414 tracks = self.getTopTracks(config.plugins.LastFM.username.value)
416 def loadRecentTracks(self):
417 self.setInfoLabel("loading recent Tracks")
418 tracks = self.getRecentTracks(config.plugins.LastFM.username.value)
420 def loadLovedTracks(self):
421 self.setInfoLabel("loading loved Tracks")
422 tracks = self.getRecentLovedTracks(config.plugins.LastFM.username.value)
424 def loadBannedTracks(self):
425 self.setInfoLabel("loading loved Tracks")
426 tracks = self.getRecentBannedTracks(config.plugins.LastFM.username.value)
428 def loadNeighbours(self):
429 self.setInfoLabel("loading Neighbours")
430 tracks = self.getNeighbours(config.plugins.LastFM.username.value)
432 def loadFriends(self):
433 self.setInfoLabel("loading Friends")
434 tracks = self.getFriends(config.plugins.LastFM.username.value)
436 def buildMenuList(self,items):
439 menuliste.append((i['_display'],i['stationurl']))
440 self["streamlist"].l.setList(menuliste)
442 class LastFMSaveScreen(Screen):
443 skin = """<screen position="0,0" size="720,576" flags="wfNoBorder" title="LastFMSaveScreen" >
444 <widget name="cover" position="50,50" size="200,200" />
446 noCoverArtPNG = "/usr/share/enigma2/no_coverArt.png"
447 coverartsize= [200,200]
448 def __init__(self,session,initialMetadata):
449 self.skin = """<screen position="0,0" size="720,576" flags="wfNoBorder" title="LastFMSaveScreen" >
450 <widget name="cover" position="50,50" size="%i,%i" />
451 </screen>"""%(self.coverartsize[0],self.coverartsize[1])
453 Screen.__init__(self,session)
454 self.imageconverter = ImageConverter(self.coverartsize[0],self.coverartsize[1],self.setCoverArt)
455 self.session = session
456 self.initialMetadata = initialMetadata
457 self["cover"] = MovingPixmap()
458 self["actions"] = ActionMap(["InfobarChannelSelection","WizardActions", "DirectionActions","MenuActions","ShortcutActions","GlobalActions","HelpActions"],
460 "ok": self.action_exit,
461 "back": self.action_exit,
464 self.onLayoutFinish.append(self.update)
465 self.onLayoutFinish.append(self.registerToMetadataUpdates)
467 if config.plugins.LastFM.sreensaver.coverartanimation.value:
468 self.startmovingtimer = eTimer()
469 self.startmovingtimer.timeout.get().append(self.movePixmap)
470 self.startmovingtimer.start(config.plugins.LastFM.sreensaver.coverartinterval.value*1000)
475 def action_exit(self):
476 lastfm_event_register.removeOnMetadataChanged(self.update)
479 def setCoverArt(self,pixmap=None):
481 self["cover"].instance.setPixmapFromFile(self.noCoverArtPNG)
483 self["cover"].instance.setPixmap(pixmap.__deref__())
485 def registerToMetadataUpdates(self):
486 lastfm_event_register.addOnMetadataChanged(self.update)#added here, to make shure that is called after onLayoutFinished
489 def update(self,metadata=None):
492 metadata = self.initialMetadata
494 if config.plugins.LastFM.sreensaver.showcoverart.value is not True:
496 elif metadata.has_key("albumcover_large") and config.plugins.LastFM.showcoverart.value:
497 self.imageconverter.convert(metadata["albumcover_large"])
498 elif metadata.has_key("albumcover_medium") and config.plugins.LastFM.showcoverart.value:
499 self.imageconverter.convert(metadata["albumcover_medium"])
500 elif metadata.has_key("albumcover_small") and config.plugins.LastFM.showcoverart.value:
501 self.imageconverter.convert(metadata["albumcover_small"],self.setCoverArt)
505 def movePixmap(self):
506 self.startmovingtimer.stop()
507 newX = random.randrange(720-self.coverartsize[0]-1)
508 newY = random.randrange(576-self.coverartsize[1]-1)
509 self["cover"].moveTo(newX, newY, time = config.plugins.LastFM.sreensaver.coverartspeed.value)
510 self["cover"].startMoving()
511 self.startmovingtimer.start(config.plugins.LastFM.sreensaver.coverartinterval.value*1000)
513 class ImageConverter:
517 def __init__(self,width,height,callBack):
518 self.callBack = callBack
521 self.targetfile= "/tmp/coverart"+str(random.randrange(5000))
524 def convert(self,sourceURL):
525 if self.lastURL != sourceURL:
526 extension = sourceURL.split(".")[-1]
527 self.tmpfile = self.targetfile+"."+extension
528 httpclient.getFile(self.tmpfile,sourceURL,callback=self.onImageLoaded)
529 self.lastURL = sourceURL
531 def onImageLoaded(self,dummy):
532 self.currPic = loadPic(self.tmpfile, self.width, self.height, 0,1, 0,1)
533 os.remove(self.tmpfile)
534 self.callBack(pixmap=self.currPic)