2 from enigma import eTimer
3 from enigma import eConsoleAppContainer
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
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
16 from Tools import Notifications
18 from Plugins.Plugin import PluginDescriptor
21 from StreamPlayer import StreamPlayer
22 from LastFMConfig import LastFMConfigScreen
23 from LastFM import LastFM
26 ###############################################################################
32 ###############################################################################
34 config.plugins.LastFM = ConfigSubsection()
35 config.plugins.LastFM.showcoverart = ConfigYesNo(default = False)
36 config.plugins.LastFM.username = ConfigText("user",fixed_size=False)
37 config.plugins.LastFM.password = ConfigText("passwd",fixed_size=False)
38 config.plugins.LastFM.timeoutstatustext = ConfigInteger(3,limits = (0, 10))
39 config.plugins.LastFM.timeouttabselect = ConfigInteger(2,limits = (0, 10))
40 config.plugins.LastFM.metadatarefreshinterval = ConfigInteger(5,limits = (0, 100))
41 config.plugins.LastFM.recommendedlevel = ConfigInteger(3,limits = (0, 100))
43 ###############################################################################
44 def main(session,**kwargs):
45 session.open(LastFMScreenMain)
47 def Plugins(path,**kwargs):
50 return PluginDescriptor(
52 description="the social music revolution",
53 where = PluginDescriptor.WHERE_PLUGINMENU,
56 ###############################################################################
57 class LastFMScreenMain(Screen,HelpableScreen):
59 <screen position="110,83" size="530,430" title="Last.FM" >
61 <widget name="artist" position="0,0" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
62 <widget name="album" position="0,40" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
63 <widget name="track" position="0,80" size="70,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
65 <widget name="info_artist" position="70,0" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
66 <widget name="info_album" position="70,40" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
67 <widget name="info_track" position="70,80" size="344,30" valign=\"center\" halign=\"left\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
68 <widget name="info_cover" position="414,0" size="116,116" />
70 <widget name="tablist" position="0,120" size="150,260" scrollbarMode="showOnDemand" />
71 <widget name="streamlist" position="150,120" size="380,260" scrollbarMode="showOnDemand" />
73 <widget name="button_red" position="10,400" size="60,30" backgroundColor=\"red\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
74 <widget name="button_green" position="80,400" size="60,30" backgroundColor=\"green\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\"/>
75 <widget name="button_yellow" position="150,400" size="60,30" backgroundColor=\"yellow\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
76 <widget name="button_blue" position="220,400" size="60,30" backgroundColor=\"blue\" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
77 <widget name="infolabel" position="290,400" size="290,30" valign=\"center\" halign=\"center\" zPosition=\"2\" foregroundColor=\"white\" font=\"Regular;18\" />
80 noCoverArtPNG = "/usr/share/enigma2/no_coverArt.png"
82 def __init__(self, session, args = 0):
83 Screen.__init__(self, session)
84 HelpableScreen.__init__(self)
85 self.skin = LastFMScreenMain.skin
86 self.session = session
87 self.lastfm = LastFM()
88 self.streamplayer = StreamPlayer(session)
89 self.imageconverter = ImageConverter(self.setCoverArt)
90 Screen.__init__(self, session)
91 self.tabs=[("personal Stations",self.loadPersonalStations)
92 ,("Global Tags",self.loadGlobalTags)
93 ,("Top Tracks",self.loadTopTracks)
94 ,("Recent Tracks",self.loadRecentTracks)
95 ,("Loved Tracks",self.loadLovedTracks)
96 ,("Banned Tracks",self.loadBannedTracks)
97 ,("Friends",self.loadFriends)
98 ,("Neighbours",self.loadNeighbours)
101 for tab in self.tabs:
102 tablist.append((tab[0],tab))
103 self.tablist = MenuList(tablist)
104 self.tablist.onSelectionChanged.append(self.action_TabChanged)
106 self["artist"] = Label(_("Artist")+":")
107 self["album"] = Label(_("Album")+":")
108 self["track"] = Label(_("Track")+":")
110 self["info_artist"] = Label("N/A")
111 self["info_album"] = Label("N/A")
112 self["info_track"] = Label("N/A")
113 self["info_cover"] = Pixmap()
115 self["tablist"] = self.tablist
116 self["streamlist"] = MenuList([])
118 self["button_red"] = Label(_("play"))
119 self["button_green"] = Label(_("skip"))
120 self["button_yellow"] = Label(_("love"))
121 self["button_blue"] = Label(_("ban"))
122 self["infolabel"] = Label("")
124 self["actions"] = ActionMap(["InfobarChannelSelection","WizardActions", "DirectionActions","MenuActions","ShortcutActions","GlobalActions","HelpActions"],
126 "ok": self.action_ok,
127 "back": self.action_exit,
128 "red": self.action_startstop,
129 "green": self.action_green,
130 "yellow": self.action_yellow,
131 "blue": self.action_blue ,
132 "historyNext": self.action_nextTab,
133 "historyBack": self.action_prevTab,
135 "menu": self.action_menu,
137 self.helpList.append((self["actions"], "WizardActions", [("ok", _("switch to selected Station"))]))
138 self.helpList.append((self["actions"], "WizardActions", [("back", _("quit Last.FM"))]))
140 self.helpList.append((self["actions"], "MenuActions", [("menu", _("open Configuration"))]))
142 self.helpList.append((self["actions"], "ShortcutActions", [("red", _("start/stop streaming"))]))
143 self.helpList.append((self["actions"], "ShortcutActions", [("green", _("skip current Track"))]))
144 self.helpList.append((self["actions"], "ShortcutActions", [("yellow", _("mark current Track as loved"))]))
145 self.helpList.append((self["actions"], "ShortcutActions", [("blue", _("ban Track, never play again"))]))
146 self.helpList.append((self["actions"], "InfobarChannelSelection", [("historyNext", _("select next Tab"))]))
147 self.helpList.append((self["actions"], "InfobarChannelSelection", [("historyBack", _("select prev Tab"))]))
149 self.onLayoutFinish.append(self.initLastFM)
150 self.onLayoutFinish.append(self.tabchangedtimerFired)
151 self.onLayoutFinish.append(self.setCoverArt)
153 self.guiupdatetimer = eTimer()
154 self.guiupdatetimer.timeout.get().append(self.updateGUI)
156 self.tabchangetimer = eTimer()
157 self.tabchangetimer.timeout.get().append(self.tabchangedtimerFired)
159 self.infolabelcleartimer = eTimer()
160 self.infolabelcleartimer.timeout.get().append(self.clearInfoLabel)
163 def action_TabChanged(self):
164 self.tabchangetimer.stop()
165 self.tabchangetimer.start(config.plugins.LastFM.timeouttabselect.value*1000)
167 def tabchangedtimerFired(self):
168 self.tablist.getCurrent()[1][1]()
169 self.tabchangetimer.stop()
171 def action_nextTab(self):
174 def action_prevTab(self):
177 def showTab(self,tabnumber):
178 self.currenttab=tabnumber
179 print "showing tab",tabnumber
180 print self.tabs[tabnumber]
182 def action_menu(self):
183 self.session.open(LastFMConfigScreen)
185 def action_exit(self):
187 self.guiupdatetimer.stop()
188 self.streamplayer.stop()
193 selectedTag = self["streamlist"].l.getCurrentSelection()[1]
194 self.lastfm.changestation(selectedTag)
196 def action_startstop(self):
197 if self.streamplayer.is_playing:
198 self.streamplayer.stop()
199 self.lastfm.metadata = {}
200 self.setInfoLabel("stream stopped")
203 self.setInfoLabel("starting stream",timeout=True)
204 if self.lastfm.info.has_key("stream_url"):
205 self.streamplayer.play(self.lastfm.info["stream_url"])
206 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
208 def action_green(self):
210 self.setInfoLabel("Track skipped",timeout=True)
212 def action_yellow(self):
214 self.setInfoLabel("Track loved",timeout=True)
216 def action_blue(self):
218 self.setInfoLabel("Track banned",timeout=True)
220 def setInfoLabel(self,text,timeout=True):
221 self.infolabelcleartimer.stop()
222 self["infolabel"].setText(text)
224 self.infolabelcleartimer.start(config.plugins.LastFM.timeoutstatustext.value*1000)
226 def clearInfoLabel(self):
227 self["infolabel"].setText("")
230 if self.streamplayer.is_playing is not True:
234 if self.lastfm.state:
235 self.lastfm.getmetadata()
237 if self.streamplayer.is_playing:
238 self["button_red"].setText(_("stop"))
240 self["button_red"].setText(_("play"))
242 if self.lastfm.metadata.has_key("station"):
243 self.setTitle(myname+": "+self.lastfm.metadata["station"])
245 self.setTitle(myname)
247 if self.lastfm.metadata.has_key("artist"):
248 self["info_artist"].setText(self.lastfm.metadata["artist"])
250 self["info_artist"].setText("N/A")
252 if self.lastfm.metadata.has_key("album"):
253 self["info_album"].setText(self.lastfm.metadata["album"])
255 self["info_album"].setText("N/A")
257 if self.lastfm.metadata.has_key("track"):
258 self["info_track"].setText(self.lastfm.metadata["track"])
260 self["info_track"].setText("N/A")
262 if self.lastfm.metadata.has_key("albumcover_large") and config.plugins.LastFM.showcoverart.value:
263 self.imageconverter.convert(self.lastfm.metadata["albumcover_large"])
264 elif self.lastfm.metadata.has_key("albumcover_medium") and config.plugins.LastFM.showcoverart.value:
265 self.imageconverter.convert(self.lastfm.metadata["albumcover_medium"])
266 elif self.lastfm.metadata.has_key("albumcover_small") and config.plugins.LastFM.showcoverart.value:
267 self.imageconverter.convert(self.lastfm.metadata["albumcover_small"],self.setCoverArt)
271 if self.streamplayer.is_playing:
272 self.guiupdatetimer.start(config.plugins.LastFM.metadatarefreshinterval.value*1000)
274 self.setTitle(myname)
276 self["info_artist"].setText("N/A")
277 self["info_album"].setText("N/A")
278 self["info_track"].setText("N/A")
280 def setCoverArt(self,filename=None):
281 #print "coverart from file",filename
282 if filename is None or os.path.isfile(filename) is False:
283 self["info_cover"].instance.setPixmapFromFile(self.noCoverArtPNG)
285 self["info_cover"].instance.setPixmapFromFile(filename)
287 def initLastFM(self):
288 self.setInfoLabel("loggin into last.fm")
289 (result,resulttext) = self.lastfm.connect(config.plugins.LastFM.username.value,config.plugins.LastFM.password.value)
291 self.setInfoLabel("login failed")
292 Notifications.AddPopup("Login to Last.FM failed!", resulttext,MessageBox.TYPE_INFO, 5)
294 # self.session.open(MessageBox, resulttext, MessageBox.TYPE_ERROR)
296 self.setInfoLabel("login successful",timeout=True)
298 def loadPersonalStations(self):
301 x["_display"] = "Personal Radio"
302 x["stationurl"] = self.lastfm.getPersonalURL(config.plugins.LastFM.username.value,level=config.plugins.LastFM.recommendedlevel.value)
306 x["_display"] = "Neighbours Tracks"
307 x["stationurl"] = self.lastfm.getNeighboursURL(config.plugins.LastFM.username.value)
311 x["_display"] = "Loved Tracks"
312 x["stationurl"] = self.lastfm.getLovedURL(config.plugins.LastFM.username.value)
315 if self.lastfm.metadata.has_key("artist"):
317 x["_display"] = "similar Tracks of current Artist"
318 x["stationurl"] = self.lastfm.getSimilarArtistsURL()
322 x["_display"] = "Tracks liked by Fans of current Track"
323 x["stationurl"] = self.lastfm.getArtistsLikedByFans()
327 x["_display"] = "Group of Artist of current Track"
328 x["stationurl"] = self.lastfm.getArtistGroup()
332 self.buildMenuList(tags)
334 def loadGlobalTags(self):
335 self.setInfoLabel("loading Global Tags")
336 tags = self.lastfm.getGlobalTags()
337 self.buildMenuList(tags)
339 def loadTopTracks(self):
340 self.setInfoLabel("loading Top Tacks")
341 tracks = self.lastfm.getTopTracks(config.plugins.LastFM.username.value)
342 self.buildMenuList(tracks)
344 def loadRecentTracks(self):
345 self.setInfoLabel("loading recent Tracks")
346 tracks = self.lastfm.getRecentTracks(config.plugins.LastFM.username.value)
347 self.buildMenuList(tracks)
349 def loadLovedTracks(self):
350 self.setInfoLabel("loading loved Tracks")
351 tracks = self.lastfm.getRecentLovedTracks(config.plugins.LastFM.username.value)
352 self.buildMenuList(tracks)
354 def loadBannedTracks(self):
355 self.setInfoLabel("loading loved Tracks")
356 tracks = self.lastfm.getRecentBannedTracks(config.plugins.LastFM.username.value)
357 self.buildMenuList(tracks)
359 def loadNeighbours(self):
360 self.setInfoLabel("loading Neighbours")
361 tracks = self.lastfm.getNeighbours(config.plugins.LastFM.username.value)
362 self.buildMenuList(tracks)
364 def loadFriends(self):
365 self.setInfoLabel("loading Friends")
366 tracks = self.lastfm.getFriends(config.plugins.LastFM.username.value)
367 self.buildMenuList(tracks)
369 def buildMenuList(self,items):
372 menuliste.append((i['_display'],i['stationurl']))
373 self["streamlist"].l.setList(menuliste)
376 class ImageConverter:
378 targetfile= "/tmp/coverart.png"
381 def __init__(self,callBack):
382 self.callBack = callBack
383 self.container = eConsoleAppContainer()
384 self.container.appClosed.get().append(self.appClosed)
385 self.container.dataAvail.get().append(self.dataAvail)
387 def dataAvail(self,text):
388 print "imageconverter:",text
390 def convert(self,sourceURL):
391 #print "start converting coverart",sourceURL
392 try: # this is not nice... i have to implement a function to check it while activating CoverArts
397 if self.lastURL == sourceURL:
398 pass #self.callBack(filename=self.targetfile)
400 cmd = "/usr/bin/python "+plugin_path+"/imageconverter.py '"+sourceURL+"' '"+self.targetfile+"' "
401 self.container.execute(cmd)
402 self.lastURL = sourceURL
404 def appClosed(self,text):
405 #print "appClosed",text
406 self.callBack(filename=self.targetfile)