1 from enigma import eListbox
2 from enigma import eListboxPythonMultiContent
3 from enigma import ePicLoad
4 from enigma import loadPNG
5 from enigma import gFont
7 from Screens.Screen import Screen
8 from Screens.MessageBox import MessageBox
9 from Screens.InputBox import InputBox
10 from Screens.ChoiceBox import ChoiceBox
11 from Components.ActionMap import ActionMap
12 from Components.Label import Label
13 from Components.MenuList import MenuList
14 from Components.FileList import EXTENSIONS
16 from Components.config import config, ConfigSubsection,ConfigSelection,ConfigText,ConfigYesNo
18 from Components.Input import Input
19 from Components.Pixmap import Pixmap
20 from Plugins.Plugin import PluginDescriptor
23 from re import compile
25 from pyexpat import ExpatError
26 import xml.dom.minidom
27 from Tools.XMLTools import elementsWithTag
30 from WebcamViewConfig import WebcamViewerMenu
31 from PictureScreen import PictureScreen
33 myname = "Webcam/Picture Viewer"
36 config.plugins.pictureviewer = ConfigSubsection()
37 config.plugins.pictureviewer.slideshowtime = ConfigSelection(default="5000", choices = [("5000", _("5 Sekunden")), ("10000", _("10 Sekunden")), ("20000", _("20 Sekunden")), ("60000", _("1 Minute"))])
38 config.plugins.pictureviewer.slideshowmode = ConfigSelection(default="0", choices = [("0", _("normal")), ("1", _("endlos"))])
40 config.plugins.pictureviewer.slideshowext = ConfigText(default=".3ssl")
41 config.plugins.pictureviewer.matchingPattern = ConfigText(default="(?i)^.*\.(jpeg|jpg|jpe|png|bmp|gif)")
42 config.plugins.pictureviewer.slideshowdir = ConfigText(default="/media/hdd/slideshows/")
43 config.plugins.pictureviewer.rootdir = ConfigText(default="/media/")
44 config.plugins.pictureviewer.stopserviceonstart = ConfigYesNo(default = False)
45 SLIDESHOWMODE_NORMAL = 0
46 SLIDESHOWMODE_REPEAT = 1
48 originalservice = None
51 def main1(session, **kwargs):
52 global originalservice, mysession
54 originalservice = session.nav.getCurrentlyPlayingServiceReference()
55 if config.plugins.pictureviewer.stopserviceonstart.value:
56 session.nav.stopService()
57 session.openWithCallback(mainCB, PictureViewer)
59 def main2(session, **kwargs):
60 global originalservice, mysession
62 originalservice = session.nav.getCurrentlyPlayingServiceReference()
63 if config.plugins.pictureviewer.stopserviceonstart.value:
64 session.nav.stopService()
65 xmlfile = "/usr/lib/enigma2/python/Plugins/Extensions/WebcamViewer/webcam.xml"
66 if os.path.isfile(xmlfile):
68 xmlnode = xml.dom.minidom.parse(open(xmlfile))
69 session.openWithCallback(mainCB, WebcamViewer, xmlnode.childNodes[1])
73 _("Loading config file failed!\n\n%s") % e,
74 MessageBox.TYPE_WARNING
79 _("Loading config file failed!\n\nconfigfile not found!"),
80 MessageBox.TYPE_WARNING
84 global originalservice, mysession
85 if config.plugins.pictureviewer.stopserviceonstart.value:
86 mysession.nav.playService(originalservice)
88 def Plugins(path, **kwargs):
92 description="browse your local pictures",
93 where = PluginDescriptor.WHERE_PLUGINMENU,
95 icon="pictureviewer.png"
99 description="view webcams around the world",
100 where = PluginDescriptor.WHERE_PLUGINMENU,
102 icon="webcamviewer.png"
110 currentslideshowitem = 0
113 def __init__(self, session, callback):
114 self.session = session
115 self.callback = callback
117 def setfiles(self, filelist):
118 self.filelist = filelist
121 if len(self.filelist) > 0:
122 self.currentslideshowitem = -1
123 self.nextSlideshowItem()
125 def nextSlideshowItem(self, prev = False):
126 currentslideshowitem = self.currentslideshowitem
128 currentslideshowitem -= 2
129 if currentslideshowitem < 0:
130 currentslideshowitem = -1
131 if currentslideshowitem is not (len(self.filelist) - 1):
132 currentslideshowitem += 1
133 filetoshow = self.filelist[currentslideshowitem][1]
134 if not self.wbviewer:
135 self.wbviewer = self.session.openWithCallback(
138 filetoshow.split("/")[-1],
140 slideshowcallback = self.nextSlideshowItem
143 self.wbviewer.filename = filetoshow
145 self.currentslideshowitem = currentslideshowitem
146 elif int(config.plugins.pictureviewer.slideshowmode.value) is SLIDESHOWMODE_REPEAT:
147 print "["+myname+"] restarting slideshow"
150 print "["+myname+"] slideshow finished"
157 class PictureViewer(Screen):
160 currList = "slideshowlist"
162 loadedslideshowlistlistname = False
164 def __init__(self, session, args = 0):
165 skin = """<screen position="93,70" size="550,450" title="%s">
166 <widget name="menu" position="1,1" size="275,400" scrollbarMode="showOnDemand" />
167 <widget name="pixmap" position="550,450" size="275,200" backgroundColor="red" />
168 <widget name="slist" position="275,200" size="275,200" scrollbarMode="showOnDemand" />
169 <widget name="buttonred" position="6,405" size="130,40" backgroundColor="red" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
170 <widget name="buttongreen" position="142,405" size="130,40" backgroundColor="green" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
171 <widget name="buttonyellow" position="278,405" size="130,40" backgroundColor="yellow" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
172 <widget name="buttonblue" position="414,405" size="130,40" backgroundColor="blue" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
173 </screen>""" % config.plugins.pictureviewer.rootdir.value
175 Screen.__init__(self, session)
177 self.filelist = PictureList(config.plugins.pictureviewer.rootdir.value, matchingPattern = config.plugins.pictureviewer.matchingPattern.value)
178 self["menu"] = self.filelist
180 self.picload = ePicLoad()
181 self.picload.PictureData.get().append(self.updateInfoPanelCB)
182 self.picload.setPara((275, 200, 1, 1, False, 1, "#ff000000"))
183 self.preview = Pixmap()
184 self["pixmap"] = self.preview
186 self.slideshowfiles = []
187 self.slideshowlist =MenuList(self.slideshowfiles)
188 self["slist"] = self.slideshowlist
190 self["buttonred"] = Label("")
191 self["buttongreen"] = Label("")
192 self["buttonyellow"] = Label("")
193 self["buttonblue"] = Label("")
195 self["actions"] = ActionMap(["WizardActions", "MenuActions", "DirectionActions", "ShortcutActions"],
199 "menu": self.openMenu,
203 "right": self.rightUp,
205 "green": self.KeyGreen,
206 "yellow": self.KeyYellow,
207 "blue": self.switchList,
210 self.onLayoutFinish.append(self.switchList)
211 self.onLayoutFinish.append(self.updateInfoPanel)
214 if self.currList is "filelist":
215 # adding all files in current dir to slideshowlist
216 dirname = self["menu"].getCurrentDir()
217 if os.path.isdir(dirname):
218 s = os.listdir(dirname)
221 if compile(config.plugins.pictureviewer.matchingPattern.value).search(dirname + file):
222 self.slideshowfiles.append((_(file),dirname + file))
223 self["slist"].l.setList(self.slideshowfiles)
228 for file in os.listdir(config.plugins.pictureviewer.slideshowdir.value):
229 if file.endswith(config.plugins.pictureviewer.slideshowext.value):
230 list.append((_(file.split("/")[-1]),file))
231 self.session.openWithCallback(
232 self.fileToLoadFilelistEntered,
234 _("select List to load"),
238 print "["+myname+"] IOError:",e
240 print "["+myname+"] OSError:",e
243 if self.currList is "filelist" :
246 x = Slideshow(self.session, self.show)
247 x.setfiles(self.slideshowfiles)
251 if not self.loadedslideshowlistlistname:
252 newname = "slideshowlist"
254 newname = self.loadedslideshowlistlistname
255 self.session.openWithCallback(
256 self.fileToSaveFilelistEntered,
258 title = _("Enter filename to save the List:"),
264 def fileToLoadFilelistEntered(self, fileselection):
265 if fileselection is not None:
267 filename = fileselection[1]
268 fp = open(config.plugins.pictureviewer.slideshowdir.value + filename)
270 for x in fp.readlines():
271 file = x.replace("\n","")
272 if x.startswith("#"):
274 elif not os.path.exists(file):
275 print "["+myname+"] loaded file from filelist isnt avaible! ignoreing ->", file
277 list.append((_(file.split("/")[-1]), file))
278 self.slideshowfiles = list
279 self["slist"].l.setList(self.slideshowfiles)
280 self.loadedslideshowlistlistname = filename.replace(config.plugins.pictureviewer.slideshowext.value, "")
282 print "["+myname+"] error:", e
284 def fileToSaveFilelistEntered(self, filename):
285 if filename is not None:
286 print "["+myname+"] saving list to ", config.plugins.pictureviewer.slideshowdir.value+filename + config.plugins.pictureviewer.slideshowext.value
288 if not os.path.exists(config.plugins.pictureviewer.slideshowdir.value):
289 print "+" * 10, os.path.basename(filename)
290 os.mkdir(config.plugins.pictureviewer.slideshowdir.value)
291 fp = open(config.plugins.pictureviewer.slideshowdir.value + filename+config.plugins.pictureviewer.slideshowext.value, "w")
292 fp.write("# this is a slideshow file for "+myname+" made by V"+myversion+"\n")
293 fp.write("# you can make your own... each line with full path of the imagefile\n")
294 fp.write("# by importing this file,we will ignoring a file if is doesnt exist\n")
295 for x in self.slideshowfiles:
296 fp.write(x[1] + "\n")
299 print "["+myname+"] error:", e
302 if self.currList is "filelist":
303 # add picture to list
304 fullfile = self["menu"].getSelection()[0]
305 if os.path.isfile(fullfile):
306 self.slideshowfiles.append((_(fullfile.split("/")[-1]), fullfile))
307 self["slist"].l.setList(self.slideshowfiles)
309 # deleting an Picture
310 if len(self.slideshowfiles) >= 1:
311 indexinlist = self["slist"].l.getCurrentSelectionIndex()
312 self.slideshowfiles.pop(indexinlist)
313 self["slist"].l.setList(self.slideshowfiles)
315 def switchList(self):
316 if self.currList is "filelist" :
317 # Slideshow activieren
318 self.filelist.selectionEnabled(0)
319 self.slideshowlist.selectionEnabled(1)
320 self["buttonred"].setText("speichern")
321 self["buttongreen"].setText("laden")
322 self["buttonyellow"].setText("loeschen")
323 self["buttonblue"].setText("Dateien")
324 self.currList = "slideshowlist"
326 # filelist activieren
327 self.filelist.selectionEnabled(1)
328 self.slideshowlist.selectionEnabled(0)
329 self["buttonred"].setText("starte Slideshow")
330 self["buttongreen"].setText("alle hinzufuegen")
331 self["buttonyellow"].setText("hinzufuegen")
332 self["buttonblue"].setText("Slideshow bearbeiten")
333 self.currList = "filelist"
336 if self.currList is "filelist" :
337 selection = self["menu"].getSelection()
338 if self.filelist.canDescent():
339 self.setTitle(selection[0])
340 self.filelist.descent()
342 if selection[1] == True: # isDir
345 print "["+myname+"] file selected ", selection[0]
346 if os.path.isfile(selection[0]):
347 self.session.open(PictureScreen,selection[0].split("/")[-1], selection[0])
349 print "["+myname+"] file not found ", selection[0]
351 self.updateInfoPanel()
354 if self.currList is "filelist":
356 self.updateInfoPanel()
358 self.slideshowlist.up()
361 if self.currList is "filelist":
362 self.filelist.pageUp()
363 self.updateInfoPanel()
365 self.slideshowlist.pageUp()
368 if self.currList is "filelist":
369 self.filelist.pageDown()
370 self.updateInfoPanel()
372 self.slideshowlist.pageDown()
375 if self.currList is "filelist":
377 self.updateInfoPanel()
379 self.slideshowlist.down()
381 def updateInfoPanel(self):
382 if self.currList is "filelist":
383 selectedfile = self["menu"].getSelection()[0]
385 selectedfile = self["slist"].l.getCurrentSelection()[1]
386 self.picload.startDecode(selectedfile)
388 def updateInfoPanelCB(self, picInfo = None):
389 ptr = self.picload.getData()
391 self["pixmap"].instance.setPixmap(ptr.__deref__())
392 self["pixmap"].move(275,0)
396 def output(self,str):
400 self.session.open(WebcamViewerMenu)
402 class WebcamViewer(Screen):
405 def __init__(self, session,xmlnode, args = 0):
406 self.xmlnode = xmlnode
411 pos_x = (screen_x/2)-(size_x/2)
412 pos_y = (screen_y/2)-(size_y/2)
414 <screen position="%i,%i" size="%i,%i" title="%s">
415 <widget name="menu" position="1,1" size="%i,%i" scrollbarMode="showOnDemand"/>
416 </screen>""" % (pos_x,pos_y,size_x,size_y,myname,size_x,size_y)
418 Screen.__init__(self, session)
420 self.filelist = MenuList(self.getMenuData())
421 self["menu"] = self.filelist
422 self["actions"] = ActionMap(["WizardActions", "DirectionActions"],
427 self.onLayoutFinish.append(self.settingTitle)
429 def settingTitle(self):
430 self.setTitle(myname + ": " + self.menutitle)
433 selected = self["menu"].l.getCurrentSelection()[1]
434 menuitemtitle = self["menu"].l.getCurrentSelection()[0]
437 if type.startswith("cam"):
438 self.session.open(PictureScreen, menuitemtitle, data)
441 self.session.openWithCallback(self.cb, WebcamViewer, data)
446 def getMenuData(self):
447 xloader = XMLloader()
448 self.menutitle = xloader.getScreenXMLTitle(self.xmlnode)
450 for node in elementsWithTag(self.xmlnode._get_childNodes(), 'menu'):
452 nodex['name'] = xloader.get_txt(node, "name", "no name")
453 data.append((_("*" + nodex['name']), ["node", node]))
455 for node in elementsWithTag(self.xmlnode._get_childNodes(), 'cam'):
457 nodex['name'] = xloader.get_txt(node, "name", "no name")
458 nodex['url'] =xloader.get_txt(node, "url", "no url")
459 data.append((_(nodex['name']), ["cam", nodex['url']]))
464 class PictureList(MenuList):
465 def __init__(self, directory, matchingPattern = None, enableWrapAround = False):
466 MenuList.__init__(self, None, enableWrapAround, eListboxPythonMultiContent)
467 self.showDirectories = True
468 self.showFiles = True
470 self.matchingPattern = matchingPattern
471 self.changeDir(directory)
472 self.l.setFont(0, gFont("Regular", 18))
473 self.currentDir = directory
475 def getCurrentDir(self):
476 return self.currentDir
478 def getSelection(self):
479 return self.l.getCurrentSelection()[0]
481 def getFileList(self):
484 def changeDir(self, directory):
485 self.currentDir = directory
490 files = os.listdir(directory)
494 if os.path.isdir(directory + "/" + x):
495 directories.append(x)
499 if directory != "/" and self.showDirectories and not self.isTop:
500 self.list.append(self.getPictureEntryComponent("..", '/'.join(directory.split('/')[:-2]) + '/', True))
502 if self.showDirectories:
503 for x in directories:
504 name = (directory+x).split('/')[-1]
505 self.list.append(self.getPictureEntryComponent(name, '/'.join(directory.split('/')[:-1]) + '/' + x + '/', True))
511 if self.matchingPattern is not None:
512 if compile(self.matchingPattern).search(path):
513 self.list.append(self.getPictureEntryComponent(name,path, False))
517 self.l.setList(self.list)
519 def canDescent(self):
520 return self.getSelection()[1]
523 self.changeDir(self.getSelection()[0])
525 def getFilename(self):
526 return self.getSelection()[0].getPath()
528 def getServiceRef(self):
529 return self.getSelection()[0]
531 def postWidgetCreate(self, instance):
532 MenuList.postWidgetCreate(self, instance)
533 instance.setItemHeight(23)
535 def getPictureEntryComponent(self,name, absolute, isDir):
536 """ name={angezeigter Name}, absolute={vollstaendiger Pfad}, isDir={True,False} """
537 res = [ (absolute, isDir) ]
538 res.append((eListboxPythonMultiContent.TYPE_TEXT, 35, 1, 200, 20, 0, 0, name))
540 png = loadPNG("/usr/share/enigma2/extensions/directory.png")
542 extension = name.split('.')
543 extension = extension[-1].lower()
544 if EXTENSIONS.has_key(extension):
545 png = loadPNG("/usr/share/enigma2/extensions/" + EXTENSIONS[extension] + ".png")
549 res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, 10, 2, 20, 20, png))
555 DEFAULT_NAMESPACES = (
556 None, # RSS 0.91, 0.92, 0.93, 0.94, 2.0
557 'http://purl.org/rss/1.0/', # RSS 1.0
558 'http://my.netscape.com/rdf/simple/0.9/' # RSS 0.90
560 DUBLIN_CORE = ('http://purl.org/dc/elements/1.1/',)
561 def getElementsByTagName(self, node, tagName, possibleNamespaces = DEFAULT_NAMESPACES):
562 for namespace in possibleNamespaces:
563 children = node.getElementsByTagNameNS(namespace, tagName)
568 def node_data(self, node, tagName, possibleNamespaces = DEFAULT_NAMESPACES):
569 children = self.getElementsByTagName(node, tagName, possibleNamespaces)
570 node = len(children) and children[0] or None
571 return node and "".join([child.data.encode("utf-8") for child in node.childNodes]) or None
573 def get_txt(self, node, tagName, default_txt = ""):
575 Liefert den Inhalt >tagName< des >node< zurueck, ist dieser nicht
576 vorhanden, wird >default_txt< zurueck gegeben.
578 return self.node_data(node, tagName) or self.node_data(node, tagName, self.DUBLIN_CORE) or default_txt
580 def getScreenXMLTitle(self,node):
581 return self.get_txt(node, "name", "no title")