1 from enigma import eTimer, loadPic
2 from Screens.Screen import Screen
3 from Screens.HelpMenu import HelpableScreen
4 from Components.Pixmap import Pixmap, MovingPixmap
5 from Components.Label import Label
6 from Components.MenuList import MenuList
7 from Components.ActionMap import ActionMap
8 from Components.config import config, ConfigSubsection, ConfigInteger, ConfigYesNo, ConfigText
9 from Plugins.Plugin import PluginDescriptor
11 from StreamPlayer import StreamPlayer
12 from LastFMConfig import LastFMConfigScreen
13 from LastFM import LastFM, lastfm_event_register
14 from httpclient import getFile
15 from os import remove as os_remove
16 from random import randrange
18 ###############################################################################
21 ###############################################################################
23 config.plugins.LastFM = ConfigSubsection()
24 config.plugins.LastFM.showcoverart = ConfigYesNo(default = True)
25 config.plugins.LastFM.username = ConfigText("user",fixed_size=False)
26 config.plugins.LastFM.password = ConfigText("passwd",fixed_size=False)
27 config.plugins.LastFM.timeoutstatustext = ConfigInteger(3,limits = (0, 10))
28 config.plugins.LastFM.timeouttabselect = ConfigInteger(2,limits = (0, 10))
29 config.plugins.LastFM.metadatarefreshinterval = ConfigInteger(1,limits = (0, 100))
30 config.plugins.LastFM.recommendedlevel = ConfigInteger(3,limits = (0, 100))
31 config.plugins.LastFM.sendSubmissions = ConfigYesNo(default = False)
33 config.plugins.LastFM.sreensaver = ConfigSubsection()
34 config.plugins.LastFM.sreensaver.use = ConfigYesNo(default = True)
35 config.plugins.LastFM.sreensaver.wait = ConfigInteger(30,limits = (0, 1000))
36 config.plugins.LastFM.sreensaver.showcoverart = ConfigYesNo(default = True)
37 config.plugins.LastFM.sreensaver.coverartanimation = ConfigYesNo(default = True)
38 config.plugins.LastFM.sreensaver.coverartspeed = ConfigInteger(10,limits = (0, 100))
39 config.plugins.LastFM.sreensaver.coverartinterval = ConfigInteger(10,limits = (0, 100))
41 ###############################################################################
42 def main(session,**kwargs):
43 session.open(LastFMScreenMain)
45 def startScrobbler(reason, **kwargs):
46 if "session" in kwargs and config.plugins.LastFM.sendSubmissions.value:
47 from scrobbler import EventListener
48 evl = EventListener(kwargs["session"])
49 evl.startListenToEvents()
51 def Plugins(path,**kwargs):
54 return [PluginDescriptor(
56 description="the social music revolution",
57 where = PluginDescriptor.WHERE_PLUGINMENU,
60 PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc = startScrobbler)
62 ###############################################################################
63 class LastFMScreenMain(Screen,HelpableScreen,LastFM):
65 <screen position="110,83" size="530,430" title="Last.FM" >
67 <widget name="artist" position="0,0" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
68 <widget name="album" position="0,40" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
69 <widget name="track" position="0,80" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
71 <widget name="info_artist" position="70,0" size="284,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
72 <widget name="duration" position="354,0" size="60,30" valign=\"center\" halign=\"right\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
73 <widget name="info_album" position="70,40" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
74 <widget name="info_track" position="70,80" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
75 <widget name="info_cover" position="414,0" size="116,116" />
77 <widget name="tablist" position="0,120" size="150,260" scrollbarMode="showOnDemand" backgroundColor="#55cccccc"/>
78 <widget name="streamlist" position="150,120" size="380,260" scrollbarMode="showOnDemand" />
80 <widget name="button_red" position="10,400" size="60,30" backgroundColor=\"red\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
81 <widget name="button_green" position="80,400" size="60,30" backgroundColor=\"green\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\"/>
82 <widget name="button_yellow" position="150,400" size="60,30" backgroundColor=\"yellow\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
83 <widget name="button_blue" position="220,400" size="60,30" backgroundColor=\"blue\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
84 <widget name="infolabel" position="290,400" size="290,30" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
87 noCoverArtPNG = "/usr/share/enigma2/no_coverArt.png"
89 def __init__(self, session, args = 0):
90 self.skin = LastFMScreenMain.skin
91 Screen.__init__(self, session)
92 HelpableScreen.__init__(self)
94 self.session = session
95 self.streamplayer = StreamPlayer(session)
96 self.streamplayer.onStateChanged.append(self.onStreamplayerStateChanged)
97 self.imageconverter = ImageConverter(116,116,self.setCoverArt)
98 Screen.__init__(self, session)
100 self.tabs=[("personal Stations",self.loadPersonalStations)
101 ,("Global Tags",self.loadGlobalTags)
102 ,("Top Tracks",self.loadTopTracks)
103 ,("Recent Tracks",self.loadRecentTracks)
104 ,("Loved Tracks",self.loadLovedTracks)
105 ,("Banned Tracks",self.loadBannedTracks)
106 ,("Friends",self.loadFriends)
107 ,("Neighbours",self.loadNeighbours)
110 for tab in self.tabs:
111 tablist.append((tab[0],tab))
112 self.tablist = MenuList(tablist)
113 self.tablist.onSelectionChanged.append(self.action_TabChanged)
115 self["artist"] = Label(_("Artist")+":")
116 self["duration"] = Label("-00:00")
117 self["album"] = Label(_("Album")+":")
118 self["track"] = Label(_("Track")+":")
120 self["info_artist"] = Label("N/A")
121 self["info_album"] = Label("N/A")
122 self["info_track"] = Label("N/A")
123 self["info_cover"] = Pixmap()
125 self["tablist"] = self.tablist
126 self["streamlist"] = MenuList([])
128 self["button_red"] = Label(_("play"))
129 self["button_green"] = Label(_("skip"))
130 self["button_yellow"] = Label(_("love"))
131 self["button_blue"] = Label(_("ban"))
132 self["infolabel"] = Label("")
134 self["actions"] = ActionMap(["InfobarChannelSelection","WizardActions", "DirectionActions","MenuActions","ShortcutActions","GlobalActions","HelpActions","NumberActions"],
136 "ok": self.action_ok,
137 "back": self.action_exit,
138 "red": self.action_startstop,
139 "green": self.skipTrack,
141 "blue": self.banTrack ,
142 "historyNext": self.action_nextTab,
143 "historyBack": self.action_prevTab,
145 "menu": self.action_menu,
148 self.helpList.append((self["actions"], "WizardActions", [("ok", _("switch to selected Station"))]))
149 self.helpList.append((self["actions"], "WizardActions", [("back", _("quit Last.FM"))]))
151 self.helpList.append((self["actions"], "MenuActions", [("menu", _("open Configuration"))]))
153 self.helpList.append((self["actions"], "ShortcutActions", [("red", _("start/stop streaming"))]))
154 self.helpList.append((self["actions"], "ShortcutActions", [("green", _("skip current Track"))]))
155 self.helpList.append((self["actions"], "ShortcutActions", [("yellow", _("mark current Track as loved"))]))
156 self.helpList.append((self["actions"], "ShortcutActions", [("blue", _("ban Track, never play again"))]))
157 self.helpList.append((self["actions"], "InfobarChannelSelection", [("historyNext", _("select next Tab"))]))
158 self.helpList.append((self["actions"], "InfobarChannelSelection", [("historyBack", _("select prev Tab"))]))
160 self.onLayoutFinish.append(self.initLastFM)
161 self.onLayoutFinish.append(self.tabchangedtimerFired)
162 self.onLayoutFinish.append(self.setCoverArt)
164 self.guiupdatetimer = eTimer()
165 self.guiupdatetimer.timeout.get().append(self.guiupdatetimerFired)
166 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
168 self.tabchangetimer = eTimer()
169 self.tabchangetimer.timeout.get().append(self.tabchangedtimerFired)
171 self.infolabelcleartimer = eTimer()
172 self.infolabelcleartimer.timeout.get().append(self.clearInfoLabel)
174 self.screensavertimer = eTimer()
175 self.screensavertimer.timeout.get().append(self.startScreensaver)
176 self.onShown.append(self.startScreensaverTimer)
178 def initLastFM(self):
179 self.setInfoLabel("loggin into last.fm")
180 self.connect(config.plugins.LastFM.username.value,config.plugins.LastFM.password.value)
182 def onStreamplayerStateChanged(self,reason):
183 if reason is self.streamplayer.STATE_PLAYLISTENDS:
187 def onConnectSuccessful(self,text):
188 self.setInfoLabel("login successful")
190 def onConnectFailed(self,text):
191 self.setInfoLabel("login failed! "+text,timeout=False)
193 def onTrackSkiped(self,reason):
194 self.setInfoLabel("Track skiped")
196 def onTrackLoved(self,reason):
197 self.setInfoLabel("Track loved")
199 def onTrackBanned(self,reason):
200 self.setInfoLabel("Track baned")
203 def onCommandFailed(self,reason):
204 self.setInfoLabel(reason)
206 def onGlobalTagsLoaded(self,tags):
207 self.setInfoLabel("Global Tags loaded")
208 self.buildMenuList(tags)
210 def onTopTracksLoaded(self,tracks):
211 self.setInfoLabel("Top Tracks loaded")
212 self.buildMenuList(tracks)
214 def onRecentTracksLoaded(self,tracks):
215 self.setInfoLabel("recent Tracks loaded")
216 self.buildMenuList(tracks)
218 def onRecentBannedTracksLoaded(self,tracks):
219 self.setInfoLabel("banned Tracks loaded")
220 self.buildMenuList(tracks)
222 def onRecentLovedTracksLoaded(self,tracks):
223 self.setInfoLabel("loved Tracks loaded")
224 self.buildMenuList(tracks)
226 def onNeighboursLoaded(self,user):
227 self.setInfoLabel("Neighbours loaded")
228 self.buildMenuList(user)
230 def onFriendsLoaded(self,user):
231 self.setInfoLabel("Friends loaded")
232 self.buildMenuList(user)
234 def onStationChanged(self,reason):
235 self.setInfoLabel(reason)
238 def onMetadataLoaded(self,metadata):
240 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
242 def onPlaylistLoaded(self,reason):
243 self.streamplayer.setPlaylist(self.playlist)
244 self.streamplayer.play()
247 self.streamplayer.skip()
252 self.streamplayer.skip()
255 def action_TabChanged(self):
256 self.tabchangetimer.stop()
257 self.tabchangetimer.start(config.plugins.LastFM.timeouttabselect.value*1000)
259 def guiupdatetimerFired(self):
261 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
263 def tabchangedtimerFired(self):
264 self.tablist.getCurrent()[1][1]()
265 self.tabchangetimer.stop()
267 def startScreensaverTimer(self):
268 if config.plugins.LastFM.sreensaver.use.value:
269 self.screensavertimer.start(config.plugins.LastFM.sreensaver.wait.value*1000)
271 def resetScreensaverTimer(self):
272 self.screensavertimer.stop()
273 self.screensavertimer.start(config.plugins.LastFM.sreensaver.wait.value*1000)
275 def startScreensaver(self):
276 self.screensavertimer.stop()
277 self.session.openWithCallback(self.updateGUI, LastFMSaveScreen,self.streamplayer)
279 def action_nextTab(self):
281 self.resetScreensaverTimer()
283 def action_prevTab(self):
285 self.resetScreensaverTimer()
287 def action_menu(self):
288 self.session.open(LastFMConfigScreen)
289 self.resetScreensaverTimer()
291 def action_exit(self):
292 self.screensavertimer.stop()
293 self.guiupdatetimer.stop()
294 self.streamplayer.stop(force=True)
295 self.streamplayer.onStateChanged=[]
300 x = self["streamlist"].l.getCurrentSelection()
304 self.changeStation(x[1])
305 self.resetScreensaverTimer()
307 def action_startstop(self):
308 self.resetScreensaverTimer()
309 if self.streamplayer.is_playing:
310 self.streamplayer.stop(force=True)
311 self.setInfoLabel("stream stopped")
313 self.setInfoLabel("starting stream",timeout=True)
315 self.updateGUI() #forcing guiupdate, so we dont wait till guiupdatetimer fired
316 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
318 def setInfoLabel(self,text,timeout=True):
319 self.infolabelcleartimer.stop()
320 self["infolabel"].setText(text)
322 self.infolabelcleartimer.start(config.plugins.LastFM.timeoutstatustext.value*1000)
324 def clearInfoLabel(self):
325 self["infolabel"].setText("")
328 if self.streamplayer.is_playing is True:
329 self["duration"].setText(self.streamplayer.getRemaining())
331 self["duration"].setText("00:00")
334 if self.streamplayer.is_playing is True:
335 self["button_red"].setText(_("stop"))
337 self["button_red"].setText(_("play"))
339 if self.streamplayer.is_playing is not True or self.shown is not True:
342 if self.streamplayer.is_playing is True:
343 self.setTitle("Last.FM: "+self.streamplayer.getMetadata("station"))
345 self.setTitle("Last.FM")
347 if self.streamplayer.is_playing is True:
348 self["info_artist"].setText(self.streamplayer.getMetadata("creator"))
350 self["info_artist"].setText("N/A")
352 if self.streamplayer.is_playing is True:
353 self["info_album"].setText(self.streamplayer.getMetadata("album"))
355 self["info_album"].setText("N/A")
357 if self.streamplayer.is_playing is True:
358 self["info_track"].setText(self.streamplayer.getMetadata("title"))
360 self["info_track"].setText("N/A")
362 if self.streamplayer.getMetadata("image").startswith("http") and config.plugins.LastFM.showcoverart.value:
363 self.imageconverter.convert(self.streamplayer.getMetadata("image"))
367 if self.streamplayer.is_playing is not True:
368 self.setTitle(myname)
370 self["info_artist"].setText("N/A")
371 self["info_album"].setText("N/A")
372 self["info_track"].setText("N/A")
374 def setCoverArt(self,pixmap=None):
376 self["info_cover"].instance.setPixmapFromFile(self.noCoverArtPNG)
378 self["info_cover"].instance.setPixmap(pixmap.__deref__())
381 def loadPersonalStations(self):
384 x["_display"] = "Personal Radio"
385 x["stationurl"] = self.getPersonalURL(config.plugins.LastFM.username.value,level=config.plugins.LastFM.recommendedlevel.value)
389 x["_display"] = "Neighbours Tracks"
390 x["stationurl"] = self.getNeighboursURL(config.plugins.LastFM.username.value)
394 x["_display"] = "Loved Tracks"
395 x["stationurl"] = self.getLovedURL(config.plugins.LastFM.username.value)
398 creator = self.streamplayer.getMetadata("creator")
399 if creator != "no creator" and creator != "N/A":
401 x["_display"] = "Tracks similar to "+self.streamplayer.getMetadata("creator")
402 x["stationurl"] = self.getSimilarArtistsURL(artist=creator)
406 x["_display"] = "Tracks liked by Fans of "+self.streamplayer.getMetadata("creator")
407 x["stationurl"] = self.getArtistsLikedByFans(artist=creator)
411 x["_display"] = "Group of "+self.streamplayer.getMetadata("creator")
412 x["stationurl"] = self.getArtistGroup(artist=creator)
415 self.buildMenuList(tags)
417 def loadGlobalTags(self):
418 self.setInfoLabel("loading Global Tags")
419 tags = self.getGlobalTags()
421 def loadTopTracks(self):
422 self.setInfoLabel("loading Top Tacks")
423 tracks = self.getTopTracks(config.plugins.LastFM.username.value)
425 def loadRecentTracks(self):
426 self.setInfoLabel("loading recent Tracks")
427 tracks = self.getRecentTracks(config.plugins.LastFM.username.value)
429 def loadLovedTracks(self):
430 self.setInfoLabel("loading loved Tracks")
431 tracks = self.getRecentLovedTracks(config.plugins.LastFM.username.value)
433 def loadBannedTracks(self):
434 self.setInfoLabel("loading loved Tracks")
435 tracks = self.getRecentBannedTracks(config.plugins.LastFM.username.value)
437 def loadNeighbours(self):
438 self.setInfoLabel("loading Neighbours")
439 tracks = self.getNeighbours(config.plugins.LastFM.username.value)
441 def loadFriends(self):
442 self.setInfoLabel("loading Friends")
443 tracks = self.getFriends(config.plugins.LastFM.username.value)
445 def buildMenuList(self,items):
448 menuliste.append((i['_display'],i['stationurl']))
449 self["streamlist"].l.setList(menuliste)
451 class LastFMSaveScreen(Screen):
452 skin = """<screen position="0,0" size="720,576" flags="wfNoBorder" title="LastFMSaveScreen" >
453 <widget name="cover" position="50,50" size="200,200" />
455 noCoverArtPNG = "/usr/share/enigma2/no_coverArt.png"
456 coverartsize= [200,200]
458 def __init__(self,session,streamplayer):
459 self.skin = """<screen position="0,0" size="720,576" flags="wfNoBorder" title="LastFMSaveScreen" >
460 <widget name="cover" position="50,50" size="%i,%i" />
461 </screen>"""%(self.coverartsize[0],self.coverartsize[1])
463 Screen.__init__(self,session)
464 self.imageconverter = ImageConverter(self.coverartsize[0],self.coverartsize[1],self.setCoverArt)
465 self.session = session
466 self.streamplayer = streamplayer
467 self["cover"] = MovingPixmap()
468 self["actions"] = ActionMap(["InfobarChannelSelection","WizardActions", "DirectionActions","MenuActions","ShortcutActions","GlobalActions","HelpActions"],
470 "ok": self.action_exit,
471 "back": self.action_exit,
474 self.onLayoutFinish.append(self.update)
475 self.updatetimer = eTimer()
476 self.updatetimer.timeout.get().append(self.update)
477 self.updatetimer.start(1000)
479 if config.plugins.LastFM.sreensaver.coverartanimation.value:
480 self.startmovingtimer = eTimer()
481 self.startmovingtimer.timeout.get().append(self.movePixmap)
482 self.startmovingtimer.start(config.plugins.LastFM.sreensaver.coverartinterval.value*1000)
487 def action_exit(self):
490 def setCoverArt(self,pixmap=None):
492 self["cover"].instance.setPixmapFromFile(self.noCoverArtPNG)
494 self["cover"].instance.setPixmap(pixmap.__deref__())
497 if self.streamplayer.getMetadata("creator") == self.lastcreator:
500 self.lastcreator = self.streamplayer.getMetadata("creator")
501 if config.plugins.LastFM.sreensaver.showcoverart.value is not True:
503 elif self.streamplayer.getMetadata("image").startswith("http") and config.plugins.LastFM.showcoverart.value:
504 self.imageconverter.convert(self.streamplayer.getMetadata("image"))
507 self.updatetimer.start(1000)
509 def movePixmap(self):
510 self.startmovingtimer.stop()
511 newX = randrange(720-self.coverartsize[0]-1)
512 newY = randrange(576-self.coverartsize[1]-1)
513 self["cover"].moveTo(newX, newY, time = config.plugins.LastFM.sreensaver.coverartspeed.value)
514 self["cover"].startMoving()
515 self.startmovingtimer.start(config.plugins.LastFM.sreensaver.coverartinterval.value*1000)
517 class ImageConverter:
521 def __init__(self,width,height,callBack):
522 self.callBack = callBack
525 self.targetfile= "/tmp/coverart"+str(randrange(5000))
528 def convert(self,sourceURL):
529 if self.lastURL != sourceURL:
530 extension = sourceURL.split(".")[-1]
531 self.tmpfile = self.targetfile+"."+extension
532 getFile(self.tmpfile,sourceURL,callback=self.onImageLoaded)
533 self.lastURL = sourceURL
535 def onImageLoaded(self,dummy):
536 self.currPic = loadPic(self.tmpfile, self.width, self.height, 0,1, 0,1)
537 os_remove(self.tmpfile)
538 self.callBack(pixmap=self.currPic)