give user the chance to cancel the start of recording by pressing exit in recording...
[enigma2-plugins.git] / shoutcast / src / plugin.py
1 #
2 #  SHOUTcast E2
3 #
4 #  $Id$
5 #
6 #  Coded by Dr.Best (c) 2010
7 #  Support: www.dreambox-tools.info
8 #
9 #  This plugin is licensed under the Creative Commons 
10 #  Attribution-NonCommercial-ShareAlike 3.0 Unported 
11 #  License. To view a copy of this license, visit
12 #  http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
13 #  Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
14 #
15 #  Alternatively, this plugin may be distributed and executed on hardware which
16 #  is licensed by Dream Multimedia GmbH.
17
18 #  This plugin is NOT free software. It is open source, you are allowed to
19 #  modify it (if you keep the license), but it may not be commercially 
20 #  distributed other than under the conditions noted above.
21 #
22
23
24 from Plugins.Plugin import PluginDescriptor
25 from Screens.Screen import Screen
26 from Components.ActionMap import ActionMap
27 from Components.Label import Label
28 from enigma import eServiceReference
29 from enigma import eListboxPythonMultiContent, eListbox, gFont, \
30         RT_HALIGN_LEFT, RT_HALIGN_RIGHT, RT_VALIGN_CENTER
31 from Tools.LoadPixmap import LoadPixmap
32 import xml.etree.cElementTree
33 from Screens.InfoBarGenerics import InfoBarAudioSelection, InfoBarSeek
34 from Components.ServiceEventTracker import ServiceEventTracker
35 from enigma import iPlayableService, iServiceInformation
36
37 from twisted.internet import reactor, defer
38 from twisted.web import client
39 from twisted.web.client import HTTPClientFactory
40 from Components.Pixmap import Pixmap
41 from enigma import ePicLoad
42 from Components.ScrollLabel import ScrollLabel
43 import string
44 import os
45 from enigma import getDesktop
46 from Components.config import config, ConfigSubsection, ConfigSelection, ConfigDirectory, ConfigYesNo, Config, ConfigInteger, ConfigSubList, ConfigText, getConfigListEntry, configfile
47 from Components.ConfigList import ConfigListScreen
48 from Screens.MessageBox import MessageBox
49 from Components.GUIComponent import GUIComponent
50 from Components.Sources.StaticText import StaticText
51 from urllib import quote
52 from twisted.web.client import downloadPage
53 from Screens.ChoiceBox import ChoiceBox
54 from Screens.VirtualKeyBoard import VirtualKeyBoard
55 from enigma import eTimer
56 from enigma import eConsoleAppContainer
57 from Components.Input import Input
58 from Screens.InputBox import InputBox
59 from Components.FileList import FileList
60
61
62 containerStreamripper = None
63
64 config.plugins.shoutcast = ConfigSubsection()
65 config.plugins.shoutcast.streamingrate = ConfigSelection(default="0", choices = [("0",_("All")), ("64",_(">= 64 kbps")), ("128",_(">= 128 kbps")), ("192",_(">= 192 kbps")), ("256",_(">= 256 kbps"))])
66 config.plugins.shoutcast.reloadstationlist = ConfigSelection(default="0", choices = [("0",_("Off")), ("1",_("every minute")), ("3",_("every three minutes")), ("5",_("every five minutes"))])
67 config.plugins.shoutcast.dirname = ConfigDirectory(default = "/hdd/streamripper/")
68 config.plugins.shoutcast.riptosinglefile = ConfigYesNo(default = False)
69 config.plugins.shoutcast.createdirforeachstream = ConfigYesNo(default = True)
70 config.plugins.shoutcast.addsequenceoutputfile = ConfigYesNo(default = False)
71
72
73 class SHOUTcastGenre:
74         def __init__(self, name = ""):
75                 self.name = name
76
77 class SHOUTcastStation:
78         def __init__(self, name = "", mt = "", id = "", br = "", genre = "", ct = "", lc = ""):
79                 self.name = name
80                 self.mt = mt
81                 self.id = id
82                 self.br = br
83                 self.genre = genre
84                 self.ct = ct
85                 self.lc = lc
86
87 class Favorite:
88         def __init__(self, configItem = None):
89                 self.configItem = configItem
90
91 class myHTTPClientFactory(HTTPClientFactory):
92         def __init__(self, url, method='GET', postdata=None, headers=None,
93         agent="SHOUTcast", timeout=0, cookies=None,
94         followRedirect=1, lastModified=None, etag=None):
95                 HTTPClientFactory.__init__(self, url, method=method, postdata=postdata,
96                 headers=headers, agent=agent, timeout=timeout, cookies=cookies,followRedirect=followRedirect)
97
98 def sendUrlCommand(url, contextFactory=None, timeout=60, *args, **kwargs):
99         scheme, host, port, path = client._parse(url)
100         factory = myHTTPClientFactory(url, *args, **kwargs)
101         reactor.connectTCP(host, port, factory, timeout=timeout)
102         return factory.deferred
103
104
105 def main(session,**kwargs):
106         session.open(SHOUTcastWidget)
107
108 def Plugins(**kwargs):
109         list = [PluginDescriptor(name="SHOUTcast", description=_("listen to shoutcast internet-radio"), where = [PluginDescriptor.WHERE_EXTENSIONSMENU], fnc=main)]
110         return list
111
112 class SHOUTcastWidget(Screen, InfoBarSeek):
113
114         GENRELIST = 0
115         STATIONLIST = 1
116         FAVORITELIST = 2
117         SEARCHLIST = 3
118
119         STREAMRIPPER_BIN = '/usr/bin/streamripper'
120
121         sz_w = getDesktop(0).size().width()
122         if sz_w == 1280:
123                 skin = """
124                         <screen name="SHOUTcastWidget" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="SHOUTcast">
125                                 <ePixmap position="50,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
126                                 <ePixmap position="200,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
127                                 <ePixmap position="350,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
128                                 <ePixmap position="500,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
129                                 <widget render="Label" source="key_red" position="50,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
130                                 <widget render="Label" source="key_green" position="200,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
131                                 <widget render="Label" source="key_yellow" position="350,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
132                                 <widget render="Label" source="key_blue" position="500,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
133                                 <widget name="headertext" position="50,77" zPosition="1" size="1180,23" font="Regular;20" transparent="1"  backgroundColor="#00000000"/>
134                                 <widget name="statustext" position="20,270" zPosition="1" size="1240,90" font="Regular;20" halign="center" valign="center" transparent="0"  backgroundColor="#00000000"/>
135                                 <widget name="list" position="50,110" zPosition="2" size="1180,445" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
136                                 <widget name="titel" position="160,580" zPosition="1" size="900,20" font="Regular;18" transparent="1"  backgroundColor="#00000000"/>
137                                 <widget name="station" position="160,600" zPosition="1" size="900,40" font="Regular;18" transparent="1"  backgroundColor="#00000000"/>
138                                 <widget name="console" position="160,650" zPosition="1" size="900,50" font="Regular;18" transparent="1"  backgroundColor="#00000000"/>
139                                 <widget name="cover" zPosition="2" position="50,580" size="102,110" alphatest="blend" />
140                                 <ePixmap position="1100,35" zPosition="4" size="120,35" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/SHOUTcast/shoutcast-logo1-fs8.png" transparent="1" alphatest="on" />
141                         </screen>"""
142
143         elif sz_w == 1024:
144                 skin = """
145                         <screen name="SHOUTcastWidget" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="SHOUTcast">
146                                 <ePixmap position="50,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
147                                 <ePixmap position="200,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
148                                 <ePixmap position="350,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
149                                 <ePixmap position="500,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
150                                 <widget render="Label" source="key_red" position="50,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
151                                 <widget render="Label" source="key_green" position="200,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
152                                 <widget render="Label" source="key_yellow" position="350,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
153                                 <widget render="Label" source="key_blue" position="500,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
154                                 <widget name="headertext" position="50,77" zPosition="1" size="900,23" font="Regular;20" transparent="1"  backgroundColor="#00000000"/>
155                                 <widget name="statustext" position="20,270" zPosition="1" size="1004,90" font="Regular;20" halign="center" valign="center" transparent="0"  backgroundColor="#00000000"/>
156                                 <widget name="list" position="50,110" zPosition="2" size="940,313" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
157                                 <widget name="titel" position="160,450" zPosition="1" size="800,20" font="Regular;18" transparent="1"  backgroundColor="#00000000"/>
158                                 <widget name="station" position="160,470" zPosition="1" size="800,40" font="Regular;18" transparent="1"  backgroundColor="#00000000"/>
159                                 <widget name="console" position="160,520" zPosition="1" size="800,50" font="Regular;18" transparent="1"  backgroundColor="#00000000"/>
160                                 <widget name="cover" zPosition="2" position="50,450" size="102,110" alphatest="blend" />
161                                 <ePixmap position="870,35" zPosition="4" size="120,35" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/SHOUTcast/shoutcast-logo1-fs8.png" transparent="1" alphatest="on" />
162                         </screen>"""
163         else:
164
165                 skin = """
166                         <screen name="SHOUTcastWidget" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="SHOUTcast">
167                                 <ePixmap position="20,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
168                                 <ePixmap position="160,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
169                                 <ePixmap position="300,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
170                                 <ePixmap position="440,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
171                                 <widget render="Label" source="key_red" position="20,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
172                                 <widget render="Label" source="key_green" position="160,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
173                                 <widget render="Label" source="key_yellow" position="300,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
174                                 <widget render="Label" source="key_blue" position="440,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
175                                 <widget name="headertext" position="20,77" zPosition="1" size="680,23" font="Regular;20" transparent="1"  backgroundColor="#00000000"/>
176                                 <widget name="statustext" position="20,270" zPosition="1" size="680,90" font="Regular;20" halign="center" valign="center" transparent="0"  backgroundColor="#00000000"/>
177                                 <widget name="list" position="20,110" zPosition="2" size="680,313" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
178                                 <widget name="titel" position="130,450" zPosition="1" size="550,20" font="Regular;18" transparent="1"  backgroundColor="#00000000"/>
179                                 <widget name="station" position="130,470" zPosition="1" size="550,40" font="Regular;18" transparent="1"  backgroundColor="#00000000"/>
180                                 <widget name="console" position="130,520" zPosition="1" size="550,50" font="Regular;18" transparent="1"  backgroundColor="#00000000"/>
181                                 <widget name="cover" zPosition="2" position="20,450" size="102,110" alphatest="blend" />
182                                 <ePixmap position="590,35" zPosition="4" size="120,35" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/SHOUTcast/shoutcast-logo1-fs8.png" transparent="1" alphatest="on" />
183                         </screen>"""
184
185         
186         def __init__(self, session):
187                 self.session = session
188                 Screen.__init__(self, session)
189                 self.CurrentService = self.session.nav.getCurrentlyPlayingServiceReference()
190                 self.session.nav.stopService()
191                 self["cover"] = Cover()
192                 self["key_red"] = StaticText(_("Record"))
193                 self["key_green"] = StaticText(_("Genres"))
194                 self["key_yellow"] = StaticText(_("Stations"))
195                 self["key_blue"] = StaticText(_("Favorites"))
196                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
197                         {
198                                 iPlayableService.evUpdatedInfo: self.__evUpdatedInfo,
199                                 iPlayableService.evUser+10: self.__evAudioDecodeError,
200                                 iPlayableService.evUser+12: self.__evPluginError
201                         })
202                 InfoBarSeek.__init__(self, actionmap = "MediaPlayerSeekActions")
203                 self.mode = self.FAVORITELIST
204                 self["list"] = SHOUTcastList()
205                 self["list"].connectSelChanged(self.onSelectionChanged)
206                 self["statustext"] = Label(_("Getting SHOUTcast genre list..."))
207                 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"],
208                 {
209                         "ok": self.ok_pressed,
210                         "back": self.close,
211                         "input_date_time": self.menu_pressed,
212                         "red": self.red_pressed,
213                         "green": self.green_pressed,
214                         "yellow": self.yellow_pressed,
215                         "blue": self.blue_pressed,
216                         
217                 }, -1)
218                 self.stationList = []
219                 self.stationListIndex = 0
220                 self.genreList = []
221                 self.genreListIndex = 0
222                 self.favoriteList = []
223                 self.favoriteListIndex = 0
224
225                 self.favoriteConfigFile = "/usr/lib/enigma2/python/Plugins/Extensions/SHOUTcast/favorites"
226                 self.favoriteConfig = Config()
227                 if os.path.exists(self.favoriteConfigFile):
228                         self.favoriteConfig.loadFromFile(self.favoriteConfigFile)
229                 self.favoriteConfig.entriescount =  ConfigInteger(0)
230                 self.favoriteConfig.Entries = ConfigSubList()
231                 self.initFavouriteConfig()
232
233                 self.stationListXML = ""
234                 self["titel"] = Label()
235                 self["station"] = Label()
236                 self["headertext"] = Label()
237                 self["console"] = Label()
238                 self.headerTextString = ""
239                 self.stationListHeader = ""
240                 self.tunein = ""
241                 self.searchSHOUTcastString = ""
242                 self.currentStreamingURL = ""
243                 self.currentStreamingStation = ""
244                 self.stationListURL = ""
245                 self.onClose.append(self.__onClose)
246                 self.onLayoutFinish.append(self.getFavoriteList)
247
248                 self.reloadStationListTimer = eTimer()
249                 self.reloadStationListTimer.timeout.get().append(self.reloadStationListTimerTimeout)
250                 self.reloadStationListTimerVar = int(config.plugins.shoutcast.reloadstationlist.value)
251
252                 self.visible = True
253
254                 global containerStreamripper
255                 if containerStreamripper is None:
256                         containerStreamripper = eConsoleAppContainer()
257
258                 containerStreamripper.dataAvail.append(self.streamripperDataAvail)
259                 containerStreamripper.appClosed.append(self.streamripperClosed)
260
261                 if containerStreamripper.running():
262                         self["key_red"].setText(_("Stop record"))
263                         # just to hear to recording music when starting the plugin...
264                         self.currentStreamingStation = _("Recording stream station")
265                         self.playServiceStream("http://localhost:9191")
266
267         def streamripperClosed(self, retval):
268                 if retval == 0:
269                         self["console"].setText("")
270                 self["key_red"].setText(_("Record"))
271
272         def streamripperDataAvail(self, data):
273                 sData = data.replace('\n','')
274                 self["console"].setText(sData)
275
276         def stopReloadStationListTimer(self):
277                 if self.reloadStationListTimer.isActive():
278                         self.reloadStationListTimer.stop()
279
280         def reloadStationListTimerTimeout(self):
281                 self.stopReloadStationListTimer()
282                 if self.mode == self.STATIONLIST:
283                         print "[SHOUTcast] reloadStationList: %s " % self.stationListURL
284                         sendUrlCommand(self.stationListURL, None,10).addCallback(self.callbackStationList).addErrback(self.callbackStationListError)
285
286         def InputBoxStartRecordingCallback(self, returnValue = None):
287                 if returnValue:
288                         recordingLength =  int(returnValue) * 60
289                         if not os.path.exists(config.plugins.shoutcast.dirname.value):
290                                 os.mkdir(config.plugins.shoutcast.dirname.value)
291                         args = []
292                         args.append(self.currentStreamingURL)
293                         args.append('-d')
294                         args.append(config.plugins.shoutcast.dirname.value)
295                         args.append('-r')
296                         args.append('9191')
297                         if recordingLength != 0:
298                                 args.append('-l')
299                                 args.append("%d" % int(recordingLength))
300                         if config.plugins.shoutcast.riptosinglefile.value:
301                                 args.append('-a')
302                                 args.append('-A')
303                         if not config.plugins.shoutcast.createdirforeachstream.value:
304                                 args.append('-s')
305                         if config.plugins.shoutcast.addsequenceoutputfile.value:
306                                 args.append('-q')
307                         cmd = [self.STREAMRIPPER_BIN, self.STREAMRIPPER_BIN] + args
308                         containerStreamripper.execute(*cmd)
309                         self["key_red"].setText(_("Stop record"))
310
311         def deleteRecordingConfirmed(self,val):
312                 if val:
313                         containerStreamripper.sendCtrlC()
314
315         def red_pressed(self):
316                 if containerStreamripper.running():
317                         self.session.openWithCallback(self.deleteRecordingConfirmed, MessageBox, _("Do you really want to stop the recording?"))
318                 else:
319                         if len(self.currentStreamingURL) != 0:
320                                 self.session.openWithCallback(self.InputBoxStartRecordingCallback, InputBox, windowTitle = _("Recording length"),  title=_("Enter in minutes (0 means unlimited)"), text="0", type=Input.NUMBER)
321                         else:
322                                 self.session.open(MessageBox, _("Only running streamings can be recorded!"), type = MessageBox.TYPE_INFO,timeout = 20 )
323
324         def green_pressed(self):
325                 if self.mode != self.GENRELIST:
326                         self.stopReloadStationListTimer()
327                         self.mode = self.GENRELIST
328                         if len(self.genreList):
329                                 self["headertext"].setText("SHOUTcast genre-list")
330                                 self["list"].setMode(self.mode)
331                                 self["list"].setList([ (x,) for x in self.genreList])
332                                 self["list"].moveToIndex(self.genreListIndex)
333                         else:
334                                 self.getGenreList()
335                 else:
336                         self.getGenreList()
337
338         def yellow_pressed(self):
339                 if self.mode != self.STATIONLIST:
340                         if len(self.stationList):
341                                 self.mode = self.STATIONLIST
342                                 self.headerTextString = _("SHOUTcast station list for %s") % self.stationListHeader
343                                 self["headertext"].setText(self.headerTextString)
344                                 self["list"].setMode(self.mode)
345                                 self["list"].setList([ (x,) for x in self.stationList])
346                                 self["list"].moveToIndex(self.stationListIndex)
347                                 if self.reloadStationListTimerVar != 0:
348                                         self.reloadStationListTimer.start(60000 * self.reloadStationListTimerVar)
349
350         def blue_pressed(self):
351                 if self.mode != self.FAVORITELIST:
352                         self.stopReloadStationListTimer()
353                         self.getFavoriteList(self.favoriteListIndex)
354
355         def getFavoriteList(self, favoriteListIndex = 0):
356                 self["statustext"].setText("")
357                 self.headerTextString = _("Favorite list")
358                 self["headertext"].setText(self.headerTextString)
359                 self.mode = self.FAVORITELIST
360                 self["list"].setMode(self.mode)
361                 favoriteList = []
362                 for item in self.favoriteConfig.Entries:
363                         favoriteList.append(Favorite(configItem=item))
364                 self["list"].setList([ (x,) for x in favoriteList])
365                 if len(favoriteList):
366                         self["list"].moveToIndex(favoriteListIndex)
367                 self["list"].show()
368
369         def getGenreList(self):
370                 self["headertext"].setText("")
371                 self["statustext"].setText(_("Getting SHOUTcast genre list..."))
372                 self["list"].hide()
373                 url = "http://yp.shoutcast.com/sbin/newxml.phtml"
374                 sendUrlCommand(url, None,10).addCallback(self.callbackGenreList).addErrback(self.callbackGenreListError)
375
376         def callbackGenreList(self, xmlstring):
377                 self["headertext"].setText("SHOUTcast genre list")
378                 self.genreListIndex = 0
379                 self.mode = self.GENRELIST
380                 self["list"].setMode(self.mode)
381                 self.genreList = self.fillGenreList(xmlstring)
382                 self["statustext"].setText("")
383                 self["list"].setList([ (x,) for x in self.genreList])
384                 if len(self.genreList):
385                         self["list"].moveToIndex(self.genreListIndex)
386                 self["list"].show()
387
388         def callbackGenreListError(self, error = None):
389                 if error is not None:
390                         try:
391                                 self["list"].hide()
392                                 self["statustext"].setText(_("%s\nPress green-button to try again...") % str(error.getErrorMessage()))
393                         except: pass
394         
395                 
396         def fillGenreList(self,xmlstring):
397                 genreList = []
398                 try:
399                         root = xml.etree.cElementTree.fromstring(xmlstring)
400                 except: return []
401                 for childs in root.findall("genre"):
402                         genreList.append(SHOUTcastGenre(name = childs.get("name")))
403                 return genreList
404
405         
406         def onSelectionChanged(self):
407                 pass
408                 # till I find a better solution
409 #               if self.mode == self.STATIONLIST:
410 #                       self.stationListIndex = self["list"].getCurrentIndex()
411 #               elif self.mode == self.FAVORITELIST:
412 #                       self.favoriteListIndex = self["list"].getCurrentIndex()
413 #               elif self.mode == self.GENRELIST:
414 #                       self.genreListIndex = self["list"].getCurrentIndex()
415
416         def ok_pressed(self):
417                 if self.visible:
418                         sel = None
419                         try:
420                                 sel = self["list"].l.getCurrentSelection()[0]
421                         except:return
422                         if sel is None:
423                                 return
424                         else:
425                                 if self.mode == self.GENRELIST:
426                                         self.genreListIndex = self["list"].getCurrentIndex()
427                                         self.getStationList(sel.name)
428                                 elif self.mode == self.STATIONLIST:
429                                         self.stationListIndex = self["list"].getCurrentIndex()
430                                         self.stopPlaying()
431                                         url = "http://yp.shoutcast.com%s?id=%s" % (self.tunein, sel.id)
432                                         self["list"].hide()
433                                         self["statustext"].setText("Getting streaming data from\n%s" % sel.name)
434                                         self.currentStreamingStation = sel.name
435                                         sendUrlCommand(url, None,10).addCallback(self.callbackPLS).addErrback(self.callbackStationListError)
436                                 elif self.mode == self.FAVORITELIST:
437                                         self.favoriteListIndex = self["list"].getCurrentIndex()
438                                         if sel.configItem.type.value == "url":
439                                                 self.stopPlaying()
440                                                 self["headertext"].setText(self.headerTextString)
441                                                 self.currentStreamingStation = sel.configItem.name.value
442                                                 self.playServiceStream(sel.configItem.text.value)
443                                         elif sel.configItem.type.value == "pls":
444                                                 self.stopPlaying()
445                                                 url = sel.configItem.text.value
446                                                 self["list"].hide()
447                                                 self["statustext"].setText(_("Getting streaming data from\n%s") % sel.configItem.name.value)
448                                                 self.currentStreamingStation = sel.configItem.name.value
449                                                 sendUrlCommand(url, None,10).addCallback(self.callbackPLS).addErrback(self.callbackStationListError)
450                                         elif sel.configItem.type.value == "genre":
451                                                 self.getStationList(sel.configItem.name.value)
452                                 elif self.mode == self.SEARCHLIST and self.searchSHOUTcastString != "":
453                                         self.searchSHOUTcast(self.searchSHOUTcastString)
454                 else:
455                         self.showWindow()
456
457         def stopPlaying(self):
458                 self.currentStreamingURL = ""
459                 self.currentStreamingStation = ""
460                 self["headertext"].setText("")
461                 self["titel"].setText("")
462                 self["station"].setText("")
463                 self.summaries.setText("")
464                 self["cover"].hide()
465                 self.session.nav.stopService()
466
467         def callbackPLS(self, result):
468                 self["headertext"].setText(self.headerTextString)
469                 found = False
470                 parts = string.split(result,"\n")
471                 for lines in parts:
472                         if lines.find("File1=") != -1:
473                                 line = string.split(lines,"File1=")
474                                 found = True
475                                 self.playServiceStream(line[-1])
476                                 
477                 if found:
478                         self["statustext"].setText("")
479                         self["list"].show()
480                 else:
481                         self.currentStreamingStation = ""
482                         self["statustext"].setText(_("No streaming data found..."))
483
484         def getStationList(self,genre):
485                 self.stationListHeader = "genre %s" % genre
486                 self.headerTextString = _("SHOUTcast station list for %s") % self.stationListHeader
487                 self["headertext"].setText("")
488                 self["statustext"].setText(_("Getting %s") %  self.headerTextString)
489                 self["list"].hide()
490                 self.stationListURL = "http://yp.shoutcast.com/sbin/newxml.phtml?genre=%s" % genre
491                 self.stationListIndex = 0
492                 sendUrlCommand(self.stationListURL, None,10).addCallback(self.callbackStationList).addErrback(self.callbackStationListError)
493
494         def callbackStationList(self, xmlstring):
495                 self.searchSHOUTcastString = ""
496                 self.stationListXML = xmlstring
497                 self["headertext"].setText(self.headerTextString)
498                 self.mode = self.STATIONLIST
499                 self["list"].setMode(self.mode)
500                 self.stationList = self.fillStationList(xmlstring)
501                 self["statustext"].setText("")
502                 self["list"].setList([ (x,) for x in self.stationList])
503                 if len(self.stationList):
504                         self["list"].moveToIndex(self.stationListIndex)
505                 self["list"].show()
506                 if self.reloadStationListTimerVar != 0:
507                         self.reloadStationListTimer.start(1000 * 60)
508
509         def fillStationList(self,xmlstring):
510                 stationList = []
511                 try:
512                         root = xml.etree.cElementTree.fromstring(xmlstring)
513                 except: return []
514                 config_bitrate = int(config.plugins.shoutcast.streamingrate.value)
515                 for childs in root.findall("tunein"):
516                         self.tunein = childs.get("base")
517                 for childs in root.findall("station"):
518                         try: bitrate = int(childs.get("br"))
519                         except: bitrate = 0
520                         if bitrate >= config_bitrate:
521                                 stationList.append(SHOUTcastStation(name = childs.get("name"), 
522                                                                         mt = childs.get("mt"), id = childs.get("id"), br = childs.get("br"), 
523                                                                         genre = childs.get("genre"), ct = childs.get("ct"), lc = childs.get("lc")))
524                 return stationList
525
526         def menu_pressed(self):
527                 if not self.visible:
528                         self.showWindow()
529                 options = [(_("Config"), self.config),(_("Search"), self.search),]
530                 if self.mode == self.FAVORITELIST and self.getSelectedItem() is not None:
531                         options.extend(((_("rename current selected favorite"), self.renameFavorite),))
532                         options.extend(((_("remove current selected favorite"), self.removeFavorite),))
533                 elif self.mode == self.GENRELIST and self.getSelectedItem() is not None:
534                         options.extend(((_("Add current selected genre to favorite"), self.addGenreToFavorite),))
535                 elif self.mode == self.STATIONLIST and self.getSelectedItem() is not None:
536                         options.extend(((_("Add current selected station to favorite"), self.addStationToFavorite),))
537                 if len(self.currentStreamingURL) != 0:
538                         options.extend(((_("Add current playing stream to favorite"), self.addCurrentStreamToFavorite),))
539                 options.extend(((_("Hide"), self.hideWindow),))
540                 self.session.openWithCallback(self.menuCallback, ChoiceBox,list = options)
541
542         def menuCallback(self, ret):
543                 ret and ret[1]()
544
545         def hideWindow(self):
546                 self.visible = False
547                 self.hide()
548
549         def showWindow(self):
550                 self.visible = True
551                 self.show()
552
553         def addGenreToFavorite(self):
554                 sel = self.getSelectedItem()
555                 if sel is not None:
556                         self.addFavorite(name = sel.name, text = sel.name, favoritetype = "genre")                      
557
558         def addStationToFavorite(self):
559                 sel = self.getSelectedItem()
560                 if sel is not None:
561                         self.addFavorite(name = sel.name, text = "http://yp.shoutcast.com%s?id=%s" % (self.tunein, sel.id), favoritetype = "pls", audio = sel.mt, bitrate = sel.br)                     
562
563         def addCurrentStreamToFavorite(self):
564                 self.addFavorite(name = self.currentStreamingStation, text = self.currentStreamingURL, favoritetype = "url")
565
566         def addFavorite(self, name = "", text = "", favoritetype = "", audio = "", bitrate = ""):
567                 self.favoriteConfig.entriescount.value = self.favoriteConfig.entriescount.value + 1
568                 self.favoriteConfig.entriescount.save()
569                 newFavorite = self.initFavouriteEntryConfig()
570                 newFavorite.name.value = name
571                 newFavorite.text.value = text
572                 newFavorite.type.value = favoritetype
573                 newFavorite.audio.value = audio
574                 newFavorite.bitrate.value = bitrate
575                 newFavorite.save()
576                 self.favoriteConfig.saveToFile(self.favoriteConfigFile)
577
578         def renameFavorite(self):
579                 sel = self.getSelectedItem()
580                 if sel is not None:
581                         self.session.openWithCallback(self.renameFavoriteFinished, VirtualKeyBoard, title = _("Enter new name for favorite item"), text = sel.configItem.name.value)
582
583         def renameFavoriteFinished(self, text = None):
584                 if text:
585                         sel = self.getSelectedItem()
586                         sel.configItem.name.value = text
587                         sel.configItem.save()
588                         self.favoriteConfig.saveToFile(self.favoriteConfigFile)
589                         self.favoriteListIndex = 0
590                         self.getFavoriteList()
591
592
593         def removeFavorite(self):
594                 sel = self.getSelectedItem()
595                 if sel is not None:
596                         self.favoriteConfig.entriescount.value = self.favoriteConfig.entriescount.value - 1
597                         self.favoriteConfig.entriescount.save()
598                         self.favoriteConfig.Entries.remove(sel.configItem)
599                         self.favoriteConfig.Entries.save()
600                         self.favoriteConfig.saveToFile(self.favoriteConfigFile)
601                         self.favoriteListIndex = 0
602                         self.getFavoriteList()
603
604         def search(self):
605                 self.session.openWithCallback(self.searchSHOUTcast, VirtualKeyBoard, title = _("Enter text to search for"))
606
607         def searchSHOUTcast(self, searchstring = None):
608                 if searchstring:
609                         self.stopReloadStationListTimer()
610                         self.stationListHeader = _("search-cirteria %s") % searchstring
611                         self.headerTextString = _("(SHOUTcast station list for %s") % self.stationListHeader
612                         self["headertext"].setText("")
613                         self["statustext"].setText(_("Searching SHOUTcast for %s...") % searchstring)
614                         self["list"].hide()
615                         self.stationListURL = "http://yp.shoutcast.com/sbin/newxml.phtml?search=%s" % searchstring
616                         self.mode = self.SEARCHLIST
617                         self.searchSHOUTcastString = searchstring
618                         self.stationListIndex = 0
619                         sendUrlCommand(self.stationListURL, None,10).addCallback(self.callbackStationList).addErrback(self.callbackStationListError)
620
621         def config(self):
622                 self.stopReloadStationListTimer()
623                 self.session.openWithCallback(self.setupFinished, SHOUTcastSetup)
624
625         def setupFinished(self, result):
626                 if result:
627                         if self.mode == self.STATIONLIST:
628                                 self.reloadStationListTimerVar = int(config.plugins.shoutcast.reloadstationlist.value)
629                                 self.stationListIndex = 0
630                                 self.callbackStationList(self.stationListXML)
631
632         def callbackStationListError(self, error = None):
633                 if error is not None:
634                         try:
635                                 self["list"].hide()
636                                 self["statustext"].setText(_("%s\nPress OK to try again...") % str(error.getErrorMessage()))
637                         except: pass
638
639         def Error(self, error = None):
640                 if error is not None:
641                         try:
642                                 self["list"].hide()
643                                 self["statustext"].setText(str(error.getErrorMessage()))
644                         except: pass
645         
646         def __onClose(self):
647                 self.stopReloadStationListTimer()
648                 self.session.nav.playService(self.CurrentService)
649                 containerStreamripper.dataAvail.remove(self.streamripperDataAvail)
650                 containerStreamripper.appClosed.remove(self.streamripperClosed)
651
652         def GoogleImageCallback(self, result):
653                 foundPos = result.find("imgres?imgurl=")
654                 foundPos2 = result.find("&imgrefurl=")
655                 if foundPos != -1 and foundPos2 != -1:
656                         print "[SHOUTcast] downloading cover from %s " % result[foundPos+14:foundPos2]
657                         downloadPage(result[foundPos+14:foundPos2] ,"/tmp/.cover").addCallback(self.coverDownloadFinished).addErrback(self.coverDownloadFailed)
658
659         def coverDownloadFailed(self,result):
660                 print "[SHOUTcast] cover download failed: %s " % result
661                 self["cover"].hide()
662
663         def coverDownloadFinished(self,result):
664                 print "[SHOUTcast] cover download finished"
665                 self["cover"].updateIcon("/tmp/.cover")
666                 self["cover"].show()
667                 
668         def __evUpdatedInfo(self):
669                 sTitle = ""
670                 currPlay = self.session.nav.getCurrentService()
671                 if currPlay is not None:
672                         sTitle = currPlay.info().getInfoString(iServiceInformation.sTagTitle)
673                         if (len(sTitle) !=0):
674                                 url = "http://images.google.de/images?q=%s&btnG=Bilder-Suche" % quote(sTitle)
675                                 sendUrlCommand(url, None,10).addCallback(self.GoogleImageCallback).addErrback(self.Error)
676                 if len(sTitle) == 0:
677                         sTitle = "n/a"
678                 title = _("Title: %s") % sTitle
679                 self["titel"].setText(title)
680                 self.summaries.setText(title)
681
682
683         def __evAudioDecodeError(self):
684                 currPlay = self.session.nav.getCurrentService()
685                 sAudioType = currPlay.info().getInfoString(iServiceInformation.sUser+10)
686                 print "[SHOUTcast __evAudioDecodeError] audio-codec %s can't be decoded by hardware" % (sAudioType)
687                 self.session.open(MessageBox, _("This Dreambox can't decode %s streams!") % sAudioType, type = MessageBox.TYPE_INFO,timeout = 20 )
688
689         def __evPluginError(self):
690                 currPlay = self.session.nav.getCurrentService()
691                 message = currPlay.info().getInfoString(iServiceInformation.sUser+12)
692                 print "[SHOUTcast __evPluginError]" , message
693                 self.session.open(MessageBox, message, type = MessageBox.TYPE_INFO,timeout = 20 )
694
695         def doEofInternal(self, playing):
696                 self.stopPlaying()
697
698         def checkSkipShowHideLock(self):
699                 # nothing to do here
700                 pass
701         
702         def playServiceStream(self, url):
703                 self.session.nav.stopService()
704                 sref = eServiceReference(4097, 0, url)
705                 self.session.nav.playService(sref)
706                 self.currentStreamingURL = url
707                 self["titel"].setText(_("Title: n/a"))
708                 self["station"].setText(_("Station: %s") % self.currentStreamingStation)
709
710         def createSummary(self):
711                 return SHOUTcastLCDScreen
712
713         def initFavouriteEntryConfig(self):
714                 self.favoriteConfig.Entries.append(ConfigSubsection())
715                 i = len(self.favoriteConfig.Entries) -1
716                 self.favoriteConfig.Entries[i].name = ConfigText(default = "")
717                 self.favoriteConfig.Entries[i].text = ConfigText(default = "")
718                 self.favoriteConfig.Entries[i].type = ConfigText(default = "")
719                 self.favoriteConfig.Entries[i].audio = ConfigText(default = "")
720                 self.favoriteConfig.Entries[i].bitrate = ConfigText(default = "")
721                 return self.favoriteConfig.Entries[i]
722
723         def initFavouriteConfig(self):
724                 count = self.favoriteConfig.entriescount.value
725                 if count != 0:
726                         i = 0
727                         while i < count:
728                                 self.initFavouriteEntryConfig()
729                                 i += 1
730
731         def getSelectedItem(self):
732                 sel = None
733                 try:
734                         sel = self["list"].l.getCurrentSelection()[0]
735                 except:return None
736                 return sel
737
738 class Cover(Pixmap):
739         def __init__(self):
740                 Pixmap.__init__(self)
741                 self.picload = ePicLoad()
742                 self.picload.PictureData.get().append(self.paintIconPixmapCB)
743
744         def onShow(self):
745                 Pixmap.onShow(self)
746                 self.picload.setPara((self.instance.size().width(), self.instance.size().height(), 1, 1, False, 1, "#00000000"))
747
748         def paintIconPixmapCB(self, picInfo=None):
749                 ptr = self.picload.getData()
750                 if ptr != None:
751                         self.instance.setPixmap(ptr.__deref__())
752
753         def updateIcon(self, filename):
754                 self.picload.startDecode(filename)
755
756 class SHOUTcastList(GUIComponent, object):
757         def buildEntry(self, item):
758                 width = self.l.getItemSize().width()
759                 res = [ None ]
760                 if self.mode == 0: # GENRELIST
761                         res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width, 20, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, item.name))
762                 elif self.mode == 1: # STATIONLIST
763                         res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width, 20, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, item.name))
764                         res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 23, width, 20, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, item.ct))
765                         res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 43, width / 2, 20, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, _("Audio: %s") % item.mt))
766                         res.append((eListboxPythonMultiContent.TYPE_TEXT,  width / 2, 43, width / 2, 20, 1, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, _("Bit rate: %s kbps") % item.br))
767                 elif self.mode == 2: # FAVORITELIST
768                         res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width, 20, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, item.configItem.name.value))
769                         res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 23, width, 20, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s (%s)" % (item.configItem.text.value, item.configItem.type.value)))
770                         if len(item.configItem.audio.value) != 0:
771                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 43, width / 2, 20, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, _("Audio: %s") % item.configItem.audio.value))
772                         if len(item.configItem.bitrate.value) != 0:
773                                 res.append((eListboxPythonMultiContent.TYPE_TEXT,  width / 2, 43, width / 2, 20, 1, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, _("Bit rate: %s kbps") % item.configItem.bitrate.value))
774                 return res
775
776         def __init__(self):
777                 GUIComponent.__init__(self)
778                 self.l = eListboxPythonMultiContent()
779                 self.l.setFont(0, gFont("Regular", 20))
780                 self.l.setFont(1, gFont("Regular", 18))
781                 self.l.setBuildFunc(self.buildEntry)
782                 self.l.setItemHeight(22)
783                 self.onSelectionChanged = [ ]
784                 self.mode = 0
785
786         def setMode(self, mode):
787                 self.mode = mode
788                 if mode == 0: # GENRELIST
789                         self.l.setItemHeight(22)
790                 elif mode == 1 or mode == 2: # STATIONLIST OR FAVORITELIST
791                         self.l.setItemHeight(63)
792
793         def connectSelChanged(self, fnc):
794                 if not fnc in self.onSelectionChanged:
795                         self.onSelectionChanged.append(fnc)
796
797         def disconnectSelChanged(self, fnc):
798                 if fnc in self.onSelectionChanged:
799                         self.onSelectionChanged.remove(fnc)
800
801         def selectionChanged(self):
802                 for x in self.onSelectionChanged:
803                         x()
804         
805         def getCurrent(self):
806                 cur = self.l.getCurrentSelection()
807                 return cur and cur[0]
808         
809         GUI_WIDGET = eListbox
810         
811         def postWidgetCreate(self, instance):
812                 instance.setContent(self.l)
813                 instance.selectionChanged.get().append(self.selectionChanged)
814
815         def preWidgetRemove(self, instance):
816                 instance.setContent(None)
817                 instance.selectionChanged.get().remove(self.selectionChanged)
818
819         def moveToIndex(self, index):
820                 self.instance.moveSelectionTo(index)
821
822         def getCurrentIndex(self):
823                 return self.instance.getCurrentIndex()
824
825         currentIndex = property(getCurrentIndex, moveToIndex)
826         currentSelection = property(getCurrent)
827
828         def setList(self, list):
829                 self.l.setList(list)
830
831 class SHOUTcastLCDScreen(Screen):
832         skin = """
833         <screen position="0,0" size="132,64" title="SHOUTcast">
834                 <widget name="text1" position="4,0" size="132,14" font="Regular;12" halign="center" valign="center"/>
835                 <widget name="text2" position="4,14" size="132,49" font="Regular;10" halign="center" valign="center"/>
836         </screen>"""
837
838         def __init__(self, session, parent):
839                 Screen.__init__(self, session)
840                 self["text1"] = Label("SHOUTcast")
841                 self["text2"] = Label("")
842
843         def setText(self, text):
844                 self["text2"].setText(text)
845
846
847 class SHOUTcastSetup(Screen, ConfigListScreen):
848
849         skin = """
850                 <screen position="center,center" size="560,400" title="SHOUTcast Setup" >
851                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
852                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
853                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
854                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
855                         <widget render="Label" source="key_red" position="0,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
856                         <widget render="Label" source="key_green" position="140,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
857                         <widget name="config" position="20,50" size="520,330" scrollbarMode="showOnDemand" />
858                 </screen>"""
859
860         def __init__(self, session):
861                 Screen.__init__(self, session)
862
863                 self["key_red"] = StaticText(_("Cancel"))
864                 self["key_green"] = StaticText(_("OK"))
865
866
867                 self.list = [ ]
868                 self.list.append(getConfigListEntry(_("Streaming rate:"), config.plugins.shoutcast.streamingrate))
869                 self.list.append(getConfigListEntry(_("Reload station list:"), config.plugins.shoutcast.reloadstationlist))
870                 self.list.append(getConfigListEntry(_("Rip to single file, name is timestamped"), config.plugins.shoutcast.riptosinglefile))
871                 self.list.append(getConfigListEntry(_("Create a directory for each stream"), config.plugins.shoutcast.createdirforeachstream))
872                 self.list.append(getConfigListEntry(_("Add sequence number to output file"), config.plugins.shoutcast.addsequenceoutputfile))
873                 self.dirname = getConfigListEntry(_("Recording location:"), config.plugins.shoutcast.dirname)
874                 self.list.append(self.dirname)
875                 ConfigListScreen.__init__(self, self.list, session)
876                 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
877                 {
878                         "green": self.keySave,
879                         "cancel": self.keyClose,
880                         "ok": self.keySelect,
881                 }, -2)
882
883         def keySelect(self):
884                 cur = self["config"].getCurrent()
885                 if cur == self.dirname:
886                         self.session.openWithCallback(self.pathSelected,SHOUTcastStreamripperRecordingPath,config.plugins.shoutcast.dirname.value)
887
888         def pathSelected(self, res):
889                 if res is not None:
890                         config.plugins.shoutcast.dirname.value = res
891
892         def keySave(self):
893                 for x in self["config"].list:
894                         x[1].save()
895                 configfile.save()
896                 self.close(True)
897
898         def keyClose(self):
899                 for x in self["config"].list:
900                         x[1].cancel()
901                 self.close(False)
902
903
904 class SHOUTcastStreamripperRecordingPath(Screen):
905         skin = """<screen name="SHOUTcastStreamripperRecordingPath" position="center,center" size="560,320" title="Select record path for streamripper">
906                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
907                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
908                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
909                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
910                         <widget name="target" position="0,60" size="540,22" valign="center" font="Regular;22" />
911                         <widget name="filelist" position="0,100" zPosition="1" size="560,220" scrollbarMode="showOnDemand"/>
912                         <widget render="Label" source="key_red" position="0,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
913                         <widget render="Label" source="key_green" position="140,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
914                 </screen>"""
915         def __init__(self, session, initDir):
916                 Screen.__init__(self, session)
917                 inhibitDirs = ["/bin", "/boot", "/dev", "/etc", "/lib", "/proc", "/sbin", "/sys", "/usr", "/var"]
918                 inhibitMounts = []
919                 self["filelist"] = FileList(initDir, showDirectories = True, showFiles = False, inhibitMounts = inhibitMounts, inhibitDirs = inhibitDirs)
920                 self["target"] = Label()
921                 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"],
922                 {
923                         "back": self.cancel,
924                         "left": self.left,
925                         "right": self.right,
926                         "up": self.up,
927                         "down": self.down,
928                         "ok": self.ok,
929                         "green": self.green,
930                         "red": self.cancel
931                         
932                 }, -1)
933                 self["key_red"] = StaticText(_("Cancel"))
934                 self["key_green"] = StaticText(_("OK"))
935
936         def cancel(self):
937                 self.close(None)
938
939         def green(self):
940                 self.close(self["filelist"].getSelection()[0])
941
942         def up(self):
943                 self["filelist"].up()
944                 self.updateTarget()
945
946         def down(self):
947                 self["filelist"].down()
948                 self.updateTarget()
949
950         def left(self):
951                 self["filelist"].pageUp()
952                 self.updateTarget()
953
954         def right(self):
955                 self["filelist"].pageDown()
956                 self.updateTarget()
957
958         def ok(self):
959                 if self["filelist"].canDescent():
960                         self["filelist"].descent()
961                         self.updateTarget()
962
963         def updateTarget(self):
964                 currFolder = self["filelist"].getSelection()[0]
965                 if currFolder is not None:
966                         self["target"].setText(currFolder)
967                 else:
968                         self["target"].setText(_("Invalid Location"))
969