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, system as os_system
16 from random import randrange
18 ###############################################################################
20 ###############################################################################
22 config.plugins.LastFM = ConfigSubsection()
23 config.plugins.LastFM.showcoverart = ConfigYesNo(default = True)
24 config.plugins.LastFM.username = ConfigText("user",fixed_size=False)
25 config.plugins.LastFM.password = ConfigText("passwd",fixed_size=False)
26 config.plugins.LastFM.timeoutstatustext = ConfigInteger(3,limits = (0, 10))
27 config.plugins.LastFM.timeouttabselect = ConfigInteger(2,limits = (0, 10))
28 config.plugins.LastFM.metadatarefreshinterval = ConfigInteger(1,limits = (0, 100))
29 config.plugins.LastFM.recommendedlevel = ConfigInteger(3,limits = (0, 100))
30 config.plugins.LastFM.sendSubmissions = ConfigYesNo(default = False)
32 config.plugins.LastFM.useproxy = ConfigYesNo(default = False)
33 config.plugins.LastFM.proxyport = ConfigInteger(6676,limits = (1, 65536))
35 config.plugins.LastFM.sreensaver = ConfigSubsection()
36 config.plugins.LastFM.sreensaver.use = ConfigYesNo(default = True)
37 config.plugins.LastFM.sreensaver.wait = ConfigInteger(30,limits = (0, 1000))
38 config.plugins.LastFM.sreensaver.showcoverart = ConfigYesNo(default = True)
39 config.plugins.LastFM.sreensaver.coverartanimation = ConfigYesNo(default = True)
40 config.plugins.LastFM.sreensaver.coverartspeed = ConfigInteger(10,limits = (0, 100))
41 config.plugins.LastFM.sreensaver.coverartinterval = ConfigInteger(10,limits = (0, 100))
43 ###############################################################################
45 from LastFMproxyStarter import ProxyStarter
47 proxy = ProxyStarter()
51 def main(session,**kwargs):
53 if proxy is not False:
55 session.openWithCallback(LastFMScreenMainCB,LastFMScreenMain)
57 def LastFMScreenMainCB():
59 if proxy is not False:
62 proxy = ProxyStarter()
64 def startScrobbler(reason, **kwargs):
65 if "session" in kwargs and config.plugins.LastFM.sendSubmissions.value:
66 from scrobbler import EventListener
67 evl = EventListener(kwargs["session"])
68 evl.startListenToEvents()
70 def Plugins(path,**kwargs):
73 return [PluginDescriptor(
75 description="the social music revolution",
76 where = PluginDescriptor.WHERE_PLUGINMENU,
79 PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc = startScrobbler)
81 ###############################################################################
82 class LastFMScreenMain(Screen,HelpableScreen,LastFM):
84 <screen position="110,83" size="530,430" title="Last.FM" >
86 <widget name="artist" position="0,0" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
87 <widget name="album" position="0,40" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
88 <widget name="track" position="0,80" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
90 <widget name="info_artist" position="70,0" size="284,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
91 <widget name="duration" position="354,0" size="60,30" valign=\"center\" halign=\"right\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
92 <widget name="info_album" position="70,40" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
93 <widget name="info_track" position="70,80" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
94 <widget name="info_cover" position="414,0" size="116,116" />
96 <widget name="tablist" position="0,120" size="150,260" scrollbarMode="showOnDemand" backgroundColor="#55cccccc"/>
97 <widget name="streamlist" position="150,120" size="380,260" scrollbarMode="showOnDemand" />
99 <widget name="button_red" position="10,400" size="60,30" backgroundColor=\"red\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
100 <widget name="button_green" position="80,400" size="60,30" backgroundColor=\"green\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\"/>
101 <widget name="button_yellow" position="150,400" size="60,30" backgroundColor=\"yellow\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
102 <widget name="button_blue" position="220,400" size="60,30" backgroundColor=\"blue\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
103 <widget name="infolabel" position="290,400" size="290,30" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
106 noCoverArtPNG = "/usr/share/enigma2/no_coverArt.png"
108 def __init__(self, session, args = 0):
109 self.skin = LastFMScreenMain.skin
110 Screen.__init__(self, session)
111 HelpableScreen.__init__(self)
112 LastFM.__init__(self)
113 self.session = session
114 self.streamplayer = StreamPlayer(session)
115 self.streamplayer.onStateChanged.append(self.onStreamplayerStateChanged)
116 self.imageconverter = ImageConverter(116,116,self.setCoverArt)
117 Screen.__init__(self, session)
119 self.tabs=[("personal Stations",self.loadPersonalStations)
120 ,("Global Tags",self.loadGlobalTags)
121 ,("Top Tracks",self.loadTopTracks)
122 ,("Recent Tracks",self.loadRecentTracks)
123 ,("Loved Tracks",self.loadLovedTracks)
124 ,("Banned Tracks",self.loadBannedTracks)
125 ,("Friends",self.loadFriends)
126 ,("Neighbours",self.loadNeighbours)
129 for tab in self.tabs:
130 tablist.append((tab[0],tab))
131 self.tablist = MenuList(tablist)
132 self.tablist.onSelectionChanged.append(self.action_TabChanged)
134 self["artist"] = Label(_("Artist")+":")
135 self["duration"] = Label("-00:00")
136 self["album"] = Label(_("Album")+":")
137 self["track"] = Label(_("Track")+":")
139 self["info_artist"] = Label("N/A")
140 self["info_album"] = Label("N/A")
141 self["info_track"] = Label("N/A")
142 self["info_cover"] = Pixmap()
144 self["tablist"] = self.tablist
145 self["streamlist"] = MenuList([])
147 self["button_red"] = Label(_("play"))
148 self["button_green"] = Label(_("skip"))
149 self["button_yellow"] = Label(_("love"))
150 self["button_blue"] = Label(_("ban"))
151 self["infolabel"] = Label("")
153 self["actions"] = ActionMap(["InfobarChannelSelection","WizardActions", "DirectionActions","MenuActions","ShortcutActions","GlobalActions","HelpActions","NumberActions"],
155 "ok": self.action_ok,
156 "back": self.action_exit,
157 "red": self.action_startstop,
158 "green": self.skipTrack,
160 "blue": self.banTrack ,
161 "historyNext": self.action_nextTab,
162 "historyBack": self.action_prevTab,
164 "menu": self.action_menu,
167 self.helpList.append((self["actions"], "WizardActions", [("ok", _("switch to selected Station"))]))
168 self.helpList.append((self["actions"], "WizardActions", [("back", _("quit Last.FM"))]))
170 self.helpList.append((self["actions"], "MenuActions", [("menu", _("open Configuration"))]))
172 self.helpList.append((self["actions"], "ShortcutActions", [("red", _("start/stop streaming"))]))
173 self.helpList.append((self["actions"], "ShortcutActions", [("green", _("skip current Track"))]))
174 self.helpList.append((self["actions"], "ShortcutActions", [("yellow", _("mark current Track as loved"))]))
175 self.helpList.append((self["actions"], "ShortcutActions", [("blue", _("ban Track, never play again"))]))
176 self.helpList.append((self["actions"], "InfobarChannelSelection", [("historyNext", _("select next Tab"))]))
177 self.helpList.append((self["actions"], "InfobarChannelSelection", [("historyBack", _("select prev Tab"))]))
179 self.onLayoutFinish.append(self.initLastFM)
180 self.onLayoutFinish.append(self.tabchangedtimerFired)
181 self.onLayoutFinish.append(self.setCoverArt)
183 self.guiupdatetimer = eTimer()
184 self.guiupdatetimer.timeout.get().append(self.guiupdatetimerFired)
185 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
187 self.tabchangetimer = eTimer()
188 self.tabchangetimer.timeout.get().append(self.tabchangedtimerFired)
190 self.infolabelcleartimer = eTimer()
191 self.infolabelcleartimer.timeout.get().append(self.clearInfoLabel)
193 self.screensavertimer = eTimer()
194 self.screensavertimer.timeout.get().append(self.startScreensaver)
195 self.onShown.append(self.startScreensaverTimer)
198 def initLastFM(self):
199 self.setInfoLabel("loggin into last.fm")
200 self.connect(config.plugins.LastFM.username.value,config.plugins.LastFM.password.value)
202 def onStreamplayerStateChanged(self,reason):
203 if reason is self.streamplayer.STATE_PLAYLISTENDS:
207 def onConnectSuccessful(self,text):
208 self.setInfoLabel("login successful")
210 def onConnectFailed(self,text):
211 self.setInfoLabel("login failed! "+text,timeout=False)
213 def onTrackSkiped(self,reason):
214 self.setInfoLabel("Track skiped")
216 def onTrackLoved(self,reason):
217 self.setInfoLabel("Track loved")
219 def onTrackBanned(self,reason):
220 self.setInfoLabel("Track baned")
223 def onCommandFailed(self,reason):
224 self.setInfoLabel(reason)
226 def onGlobalTagsLoaded(self,tags):
227 self.setInfoLabel("Global Tags loaded")
228 self.buildMenuList(tags)
230 def onTopTracksLoaded(self,tracks):
231 self.setInfoLabel("Top Tracks loaded")
232 self.buildMenuList(tracks)
234 def onRecentTracksLoaded(self,tracks):
235 self.setInfoLabel("recent Tracks loaded")
236 self.buildMenuList(tracks)
238 def onRecentBannedTracksLoaded(self,tracks):
239 self.setInfoLabel("banned Tracks loaded")
240 self.buildMenuList(tracks)
242 def onRecentLovedTracksLoaded(self,tracks):
243 self.setInfoLabel("loved Tracks loaded")
244 self.buildMenuList(tracks)
246 def onNeighboursLoaded(self,user):
247 self.setInfoLabel("Neighbours loaded")
248 self.buildMenuList(user)
250 def onFriendsLoaded(self,user):
251 self.setInfoLabel("Friends loaded")
252 self.buildMenuList(user)
254 def onStationChanged(self,reason):
255 self.setInfoLabel(reason)
258 def onMetadataLoaded(self,metadata):
260 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
262 def onPlaylistLoaded(self,reason):
263 self.streamplayer.setPlaylist(self.playlist)
264 self.streamplayer.play()
267 self.streamplayer.skip()
272 self.streamplayer.skip()
275 def action_TabChanged(self):
276 self.tabchangetimer.stop()
277 self.tabchangetimer.start(config.plugins.LastFM.timeouttabselect.value*1000)
279 def guiupdatetimerFired(self):
281 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
283 def tabchangedtimerFired(self):
284 self.tablist.getCurrent()[1][1]()
285 self.tabchangetimer.stop()
287 def startScreensaverTimer(self):
288 self.screensavertimer.start(config.plugins.LastFM.sreensaver.wait.value*1000)
290 def resetScreensaverTimer(self):
291 self.screensavertimer.stop()
292 self.screensavertimer.start(config.plugins.LastFM.sreensaver.wait.value*1000)
294 def startScreensaver(self):
295 if config.plugins.LastFM.sreensaver.use.value:
296 self.screensavertimer.stop()
297 self.session.openWithCallback(self.updateGUI, LastFMSaveScreen,self.streamplayer)
299 def action_nextTab(self):
301 self.resetScreensaverTimer()
303 def action_prevTab(self):
305 self.resetScreensaverTimer()
307 def action_menu(self):
308 self.session.open(LastFMConfigScreen)
309 self.resetScreensaverTimer()
311 def action_exit(self):
312 self.screensavertimer.stop()
313 self.guiupdatetimer.stop()
314 self.streamplayer.stop(force=True)
315 self.streamplayer.onStateChanged=[]
320 x = self["streamlist"].l.getCurrentSelection()
324 self.changeStation(x[1])
325 self.resetScreensaverTimer()
327 def action_startstop(self):
328 self.resetScreensaverTimer()
329 if self.streamplayer.is_playing:
330 self.streamplayer.stop(force=True)
331 self.setInfoLabel("stream stopped")
333 self.setInfoLabel("starting stream",timeout=True)
335 self.updateGUI() #forcing guiupdate, so we dont wait till guiupdatetimer fired
336 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
338 def setInfoLabel(self,text,timeout=True):
339 self.infolabelcleartimer.stop()
340 self["infolabel"].setText(text)
342 self.infolabelcleartimer.start(config.plugins.LastFM.timeoutstatustext.value*1000)
344 def clearInfoLabel(self):
345 self["infolabel"].setText("")
348 if self.streamplayer.is_playing is True:
349 self["duration"].setText(self.streamplayer.getRemaining())
351 self["duration"].setText("00:00")
354 if self.streamplayer.is_playing is True:
355 self["button_red"].setText(_("stop"))
357 self["button_red"].setText(_("play"))
359 if self.streamplayer.is_playing is not True or self.shown is not True:
362 if self.streamplayer.is_playing is True:
363 self.setTitle("Last.FM: "+self.streamplayer.getMetadata("station"))
365 self.setTitle("Last.FM")
367 if self.streamplayer.is_playing is True:
368 self["info_artist"].setText(self.streamplayer.getMetadata("creator"))
370 self["info_artist"].setText("N/A")
372 if self.streamplayer.is_playing is True:
373 self["info_album"].setText(self.streamplayer.getMetadata("album"))
375 self["info_album"].setText("N/A")
377 if self.streamplayer.is_playing is True:
378 self["info_track"].setText(self.streamplayer.getMetadata("title"))
380 self["info_track"].setText("N/A")
382 if self.streamplayer.getMetadata("image").startswith("http") and config.plugins.LastFM.showcoverart.value:
383 self.imageconverter.convert(self.streamplayer.getMetadata("image"))
387 if self.streamplayer.is_playing is not True:
388 self.setTitle(myname)
390 self["info_artist"].setText("N/A")
391 self["info_album"].setText("N/A")
392 self["info_track"].setText("N/A")
394 def setCoverArt(self,pixmap=None):
396 self["info_cover"].instance.setPixmapFromFile(self.noCoverArtPNG)
398 self["info_cover"].instance.setPixmap(pixmap.__deref__())
401 def loadPersonalStations(self):
404 x["_display"] = "Personal Radio"
405 x["stationurl"] = self.getPersonalURL(config.plugins.LastFM.username.value,level=config.plugins.LastFM.recommendedlevel.value)
409 x["_display"] = "Neighbours Tracks"
410 x["stationurl"] = self.getNeighboursURL(config.plugins.LastFM.username.value)
414 x["_display"] = "Loved Tracks"
415 x["stationurl"] = self.getLovedURL(config.plugins.LastFM.username.value)
418 creator = self.streamplayer.getMetadata("creator")
419 if creator != "no creator" and creator != "N/A":
421 x["_display"] = "Tracks similar to "+self.streamplayer.getMetadata("creator")
422 x["stationurl"] = self.getSimilarArtistsURL(artist=creator)
426 x["_display"] = "Tracks liked by Fans of "+self.streamplayer.getMetadata("creator")
427 x["stationurl"] = self.getArtistsLikedByFans(artist=creator)
431 x["_display"] = "Group of "+self.streamplayer.getMetadata("creator")
432 x["stationurl"] = self.getArtistGroup(artist=creator)
435 self.buildMenuList(tags)
437 def loadGlobalTags(self):
438 self.setInfoLabel("loading Global Tags")
439 tags = self.getGlobalTags()
441 def loadTopTracks(self):
442 self.setInfoLabel("loading Top Tacks")
443 tracks = self.getTopTracks(config.plugins.LastFM.username.value)
445 def loadRecentTracks(self):
446 self.setInfoLabel("loading recent Tracks")
447 tracks = self.getRecentTracks(config.plugins.LastFM.username.value)
449 def loadLovedTracks(self):
450 self.setInfoLabel("loading loved Tracks")
451 tracks = self.getRecentLovedTracks(config.plugins.LastFM.username.value)
453 def loadBannedTracks(self):
454 self.setInfoLabel("loading loved Tracks")
455 tracks = self.getRecentBannedTracks(config.plugins.LastFM.username.value)
457 def loadNeighbours(self):
458 self.setInfoLabel("loading Neighbours")
459 tracks = self.getNeighbours(config.plugins.LastFM.username.value)
461 def loadFriends(self):
462 self.setInfoLabel("loading Friends")
463 tracks = self.getFriends(config.plugins.LastFM.username.value)
465 def buildMenuList(self,items):
468 menuliste.append((i['_display'],i['stationurl']))
469 self["streamlist"].l.setList(menuliste)
471 class LastFMSaveScreen(Screen):
472 skin = """<screen position="0,0" size="720,576" flags="wfNoBorder" title="LastFMSaveScreen" >
473 <widget name="cover" position="50,50" size="200,200" />
475 noCoverArtPNG = "/usr/share/enigma2/no_coverArt.png"
476 coverartsize= [200,200]
478 def __init__(self,session,streamplayer):
479 self.skin = """<screen position="0,0" size="720,576" flags="wfNoBorder" title="LastFMSaveScreen" >
480 <widget name="cover" position="50,50" size="%i,%i" />
481 </screen>"""%(self.coverartsize[0],self.coverartsize[1])
483 Screen.__init__(self,session)
484 self.imageconverter = ImageConverter(self.coverartsize[0],self.coverartsize[1],self.setCoverArt)
485 self.session = session
486 self.streamplayer = streamplayer
487 self["cover"] = MovingPixmap()
488 self["actions"] = ActionMap(["InfobarChannelSelection","WizardActions", "DirectionActions","MenuActions","ShortcutActions","GlobalActions","HelpActions"],
490 "ok": self.action_exit,
491 "back": self.action_exit,
494 self.onLayoutFinish.append(self.update)
495 self.updatetimer = eTimer()
496 self.updatetimer.timeout.get().append(self.update)
497 self.updatetimer.start(1000)
499 if config.plugins.LastFM.sreensaver.coverartanimation.value:
500 self.startmovingtimer = eTimer()
501 self.startmovingtimer.timeout.get().append(self.movePixmap)
502 self.startmovingtimer.start(config.plugins.LastFM.sreensaver.coverartinterval.value*1000)
507 def action_exit(self):
510 def setCoverArt(self,pixmap=None):
512 self["cover"].instance.setPixmapFromFile(self.noCoverArtPNG)
514 self["cover"].instance.setPixmap(pixmap.__deref__())
517 if self.streamplayer.getMetadata("creator") == self.lastcreator:
520 self.lastcreator = self.streamplayer.getMetadata("creator")
521 if config.plugins.LastFM.sreensaver.showcoverart.value is not True:
523 elif self.streamplayer.getMetadata("image").startswith("http") and config.plugins.LastFM.showcoverart.value:
524 self.imageconverter.convert(self.streamplayer.getMetadata("image"))
527 self.updatetimer.start(1000)
529 def movePixmap(self):
530 self.startmovingtimer.stop()
531 newX = randrange(720-self.coverartsize[0]-1)
532 newY = randrange(576-self.coverartsize[1]-1)
533 self["cover"].moveTo(newX, newY, time = config.plugins.LastFM.sreensaver.coverartspeed.value)
534 self["cover"].startMoving()
535 self.startmovingtimer.start(config.plugins.LastFM.sreensaver.coverartinterval.value*1000)
537 class ImageConverter:
541 def __init__(self,width,height,callBack):
542 self.callBack = callBack
545 self.targetfile= "/tmp/coverart"+str(randrange(5000))
548 def convert(self,sourceURL):
549 if self.lastURL != sourceURL:
550 extension = sourceURL.split(".")[-1]
551 self.tmpfile = self.targetfile+"."+extension
552 getFile(self.tmpfile,sourceURL,callback=self.onImageLoaded)
553 self.lastURL = sourceURL
555 def onImageLoaded(self,dummy):
556 self.currPic = loadPic(self.tmpfile, self.width, self.height, 0,1, 0,1)
557 os_remove(self.tmpfile)
558 self.callBack(pixmap=self.currPic)