Merge remote-tracking branch 'origin/master' into master
[enigma2-plugins.git] / webcamviewer / src / plugin.py
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
6 from enigma import eEnv
7 ### Picturelist
8 from Screens.Screen import Screen
9 from Screens.MessageBox import MessageBox
10 from Screens.InputBox import InputBox
11 from Screens.ChoiceBox import ChoiceBox
12 from Screens.InfoBarGenerics import InfoBarNotifications
13 from Components.ActionMap import ActionMap
14 from Components.Label import Label
15 from Components.MenuList import MenuList
16 from Components.FileList import EXTENSIONS
17 from Components.AVSwitch import AVSwitch
18 ## configmenu
19 from Components.config import config, ConfigSubsection,ConfigSelection,ConfigText,ConfigYesNo
20 ####
21 from Components.Input import Input
22 from Components.Pixmap import Pixmap
23 from Plugins.Plugin import PluginDescriptor
24 from Tools.Notifications import AddPopup
25 ### System
26 import os
27 from re import compile
28 from itertools import chain
29 ## XML
30 from pyexpat import ExpatError
31 import xml.dom.minidom
32
33 ### my
34 from WebcamViewConfig import WebcamViewerMenu
35 from PictureScreen import PictureScreen
36 from WebcamTravel import TravelWebcamviewer
37 ###
38 myname = "Webcam/Picture Viewer"
39 myversion = "1.1"
40
41 config.plugins.pictureviewer = ConfigSubsection()
42 config.plugins.pictureviewer.slideshowtime = ConfigSelection(default="5000", choices = [("5000", _("5 Seconds")), ("10000", _("10 Seconds")), ("20000", _("20 Seconds")), ("60000", _("1 Minute"))])
43 config.plugins.pictureviewer.slideshowmode = ConfigSelection(default="0", choices = [("0", _("normal")), ("1", _("endless"))])
44 #not editable configs
45 config.plugins.pictureviewer.slideshowext = ConfigText(default=".3ssl")
46 config.plugins.pictureviewer.matchingPattern = ConfigText(default="(?i)^.*\.(jpeg|jpg|jpe|png|bmp|gif)")
47 config.plugins.pictureviewer.slideshowdir = ConfigText(default="/media/hdd/slideshows/")
48 config.plugins.pictureviewer.rootdir = ConfigText(default="/media/")
49 config.plugins.pictureviewer.stopserviceonstart = ConfigYesNo(default = False)
50 SLIDESHOWMODE_NORMAL = 0
51 SLIDESHOWMODE_REPEAT = 1
52
53 originalservice = None
54 mysession = None
55
56
57 def startPictureviewer(session, **kwargs):
58         global originalservice, mysession
59         mysession = session
60         originalservice = session.nav.getCurrentlyPlayingServiceReference()
61         if config.plugins.pictureviewer.stopserviceonstart.value:
62                 session.nav.stopService()
63         session.openWithCallback(mainCB, PictureViewer)
64
65 def startWebcamviewer(session, **kwargs):
66         global originalservice, mysession
67         mysession = session
68         originalservice = session.nav.getCurrentlyPlayingServiceReference()
69         if config.plugins.pictureviewer.stopserviceonstart.value:
70                 session.nav.stopService()
71         xmlpaths = [
72                 eEnv.resolve("${sysconfdir}/enigma2/webcam.xml"),
73                 eEnv.resolve("${libdir}/enigma2/python/Plugins/Extensions/WebcamViewer/webcam.xml"),
74         ]
75         warnmsgs = []
76         errmsgs = []
77         while xmlpaths:
78                 path = xmlpaths.pop(0)
79                 if not os.path.isfile(path):
80                         warnmsgs.append(_("Config file %s not found.") % (path))
81                         continue
82                 with open(path) as fp:
83                         try:
84                                 xmlnode = xml.dom.minidom.parse(fp)
85                                 session.openWithCallback(mainCB, WebcamViewer, xmlnode.childNodes[1])
86
87                                 # show errors in a popup and cleanup pending messages
88                                 if errmsgs:
89                                         AddPopup(
90                                                 '\n'.join(errmsgs),
91                                                 MessageBox.TYPE_WARNING,
92                                                 -1
93                                         )
94                                 del errmsgs[:]
95                                 del warnmsgs[:]
96                                 break
97                         except ExpatError as e:
98                                 errmsgs.append(_("Loading config file %s failed: %s") % (path, e))
99         if errmsgs or warnmsgs:
100                 session.open(
101                         MessageBox,
102                         '\n'.join(chain(warnmsgs, errmsgs)),
103                         MessageBox.TYPE_WARNING
104                 )
105
106
107
108
109 def mainCB():
110         global originalservice, mysession
111         if config.plugins.pictureviewer.stopserviceonstart.value:
112                 mysession.nav.playService(originalservice)
113
114 def Plugins(path, **kwargs):
115         p = [
116                         PluginDescriptor(
117                                                         name="PictureViewer",
118                                                         description="browse your local pictures",
119                                                         where = PluginDescriptor.WHERE_PLUGINMENU,
120                                                         fnc = startPictureviewer,
121                                                         icon="pictureviewer.png"
122                           ),
123                         PluginDescriptor(
124                                                         name="WebcamViewer",
125                                                         description="view webcams around the world",
126                                                         where = PluginDescriptor.WHERE_PLUGINMENU,
127                                                         fnc = startWebcamviewer,
128                                                         icon="webcamviewer.png"
129                         )
130                  ]
131         return p
132
133 ###################
134 class ViewerSelectScreen(Screen):
135         skin = ""
136         def __init__(self, session, args = 0):
137                 skin =  """<screen position="93,70" size="550,450">
138                 <widget name="list" position="0,0" size="550,450"  />
139                 </screen>"""
140                 self.skin = skin
141                 Screen.__init__(self, session)
142                 self.slideshowfiles = []
143                 self.slideshowfiles.append((_("WebcamViewer"),STARTWEBCAMVIEWER))
144                 self.slideshowfiles.append((_("online webcam.travel"),STARTWEBCAMTRAVEL))
145                 self["list"] = MenuList(self.slideshowfiles)
146                 self["actions"] = ActionMap(["WizardActions", "MenuActions", "DirectionActions", "ShortcutActions"],
147                         {
148                          "ok": self.go,
149                          "back": self.close
150                          }, -1)
151
152         def go(self):
153                 selection = self["list"].getCurrent()
154                 if selection:
155                         self.close(self.session,selection[1])
156
157
158 ###################
159 class Slideshow:
160         filelist = []
161         currentslideshowitem = 0
162         wbviewer = False
163
164         def __init__(self, session, callback):
165                 self.session = session
166                 self.callback = callback
167
168         def setfiles(self, filelist):
169                 self.filelist = filelist
170
171         def start(self):
172                 if len(self.filelist) > 0:
173                         self.currentslideshowitem = -1
174                         self.nextSlideshowItem()
175
176         def nextSlideshowItem(self, prev = False):
177                 currentslideshowitem = self.currentslideshowitem
178                 if prev:
179                         currentslideshowitem -= 2
180                 if currentslideshowitem < 0:
181                         currentslideshowitem = -1
182                 if currentslideshowitem is not (len(self.filelist) - 1):
183                         currentslideshowitem += 1
184                         filetoshow = self.filelist[currentslideshowitem][1]
185                         if not self.wbviewer:
186                                 self.wbviewer = self.session.openWithCallback(
187                                                                         self.cb,
188                                                                         PictureScreen,
189                                                                         filetoshow.split("/")[-1],
190                                                                         filetoshow,
191                                                                         slideshowcallback = self.nextSlideshowItem
192                                 )
193                         else:
194                                 self.wbviewer.filename = filetoshow
195                                 self.wbviewer.do()
196                         self.currentslideshowitem = currentslideshowitem
197                 elif int(config.plugins.pictureviewer.slideshowmode.value) is SLIDESHOWMODE_REPEAT:
198                         print "["+myname+"] restarting slideshow"
199                         self.start()
200                 else:
201                         print "["+myname+"] slideshow finished"
202                         self.wbviewer.exit()
203                         self.cb()
204
205         def cb(self):
206                 self.callback()
207 ###################
208 class PictureViewer(Screen):
209         skin = ""
210         filelist = []
211         currList = "slideshowlist"
212         wbviewer = False
213         loadedslideshowlistlistname = False
214
215         def __init__(self, session, args = 0):
216                 skin =  """<screen position="93,70" size="550,450" title="%s">
217                 <widget name="menu" position="1,1" size="275,400"  scrollbarMode="showOnDemand" />
218                 <widget name="pixmap" position="275,1" size="275,200" backgroundColor="red" />
219                 <widget name="slist" position="275,200" size="275,200"  scrollbarMode="showOnDemand" />
220                 <widget name="buttonred" position="6,405" size="130,40" backgroundColor="red" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
221                 <widget name="buttongreen" position="142,405" size="130,40" backgroundColor="green" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
222                 <widget name="buttonyellow" position="278,405" size="130,40" backgroundColor="yellow" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
223                 <widget name="buttonblue" position="414,405" size="130,40" backgroundColor="blue" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
224                 </screen>""" % config.plugins.pictureviewer.rootdir.value
225                 self.skin = skin
226                 Screen.__init__(self, session)
227
228                 self.filelist = PictureList(config.plugins.pictureviewer.rootdir.value, matchingPattern = config.plugins.pictureviewer.matchingPattern.value)
229                 self["menu"] = self.filelist
230
231                 self.preview = Pixmap()
232                 self["pixmap"] = self.preview
233
234                 self.slideshowfiles = []
235                 self.slideshowlist =MenuList(self.slideshowfiles)
236                 self["slist"] = self.slideshowlist
237
238                 self["buttonred"] = Label("")
239                 self["buttongreen"] = Label("")
240                 self["buttonyellow"] = Label("")
241                 self["buttonblue"] = Label("")
242
243                 self["actions"] = ActionMap(["WizardActions", "MenuActions", "DirectionActions", "ShortcutActions"],
244                         {
245                          "ok": self.go,
246                          "back": self.close,
247                          "menu": self.openMenu,
248                          "up": self.up,
249                          "down": self.down,
250                          "left": self.leftUp,
251                          "right": self.rightUp,
252                          "red": self.KeyRed,
253                          "green": self.KeyGreen,
254                          "yellow": self.KeyYellow,
255                          "blue": self.switchList,
256                          }, -1)
257
258                 self.onLayoutFinish.append(self.switchList)
259                 self.onLayoutFinish.append(self.updateInfoPanel)
260
261         def KeyGreen(self):
262                 if self.currList is "filelist":
263                         # adding all files in current dir to slideshowlist
264                         dirname = self["menu"].getCurrentDir()
265                         if os.path.isdir(dirname):
266                                 s = os.listdir(dirname)
267                                 s.sort()
268                                 for file in s:
269                                         if compile(config.plugins.pictureviewer.matchingPattern.value).search(dirname + file):
270                                                 self.slideshowfiles.append((_(file),dirname + file))
271                                 self["slist"].l.setList(self.slideshowfiles)
272                 else:
273                         #loading list
274                         list = []
275                         try:
276                                 for file in os.listdir(config.plugins.pictureviewer.slideshowdir.value):
277                                         if file.endswith(config.plugins.pictureviewer.slideshowext.value):
278                                                 list.append((_(file.split("/")[-1]),file))
279                                 self.session.openWithCallback(
280                                                 self.fileToLoadFilelistEntered,
281                                                 ChoiceBox,
282                                                 _("select List to load"),
283                                                 list
284                                 )
285                         except IOError,e:
286                                 print "["+myname+"] IOError:",e
287                         except OSError,e:
288                                 print "["+myname+"] OSError:",e
289
290         def KeyRed(self):
291                 if self.currList is "filelist" :
292                         #do slideshow
293                         self.hide()
294                         x = Slideshow(self.session, self.show)
295                         x.setfiles(self.slideshowfiles)
296                         x.start()
297                 else:
298                         # save filelist
299                         if not self.loadedslideshowlistlistname:
300                                 newname = "slideshowlist"
301                         else:
302                                 newname = self.loadedslideshowlistlistname
303                         self.session.openWithCallback(
304                                         self.fileToSaveFilelistEntered,
305                                         InputBox,
306                                         title = _("Enter filename to save the List:"),
307                                         text = newname,
308                                         maxSize = False,
309                                         type = Input.TEXT
310                         )
311
312         def fileToLoadFilelistEntered(self, fileselection):
313                 if fileselection is not None:
314                            try:
315                                    filename = fileselection[1]
316                                    fp = open(config.plugins.pictureviewer.slideshowdir.value + filename)
317                                    list = []
318                                    for x in fp.readlines():
319                                            file = x.replace("\n","")
320                                            if x.startswith("#"):
321                                                    pass
322                                            elif not os.path.exists(file):
323                                                    print "["+myname+"] loaded file from filelist isnt avaible! ignoreing ->", file
324                                            else:
325                                                    list.append((_(file.split("/")[-1]), file))
326                                    self.slideshowfiles = list
327                                    self["slist"].l.setList(self.slideshowfiles)
328                                    self.loadedslideshowlistlistname = filename.replace(config.plugins.pictureviewer.slideshowext.value, "")
329                            except IOError, e:
330                                    print "["+myname+"] error:", e
331
332         def fileToSaveFilelistEntered(self, filename):
333                 if filename is not None:
334                         print "["+myname+"] saving list to ", config.plugins.pictureviewer.slideshowdir.value+filename + config.plugins.pictureviewer.slideshowext.value
335                         try:
336                                 if not os.path.exists(config.plugins.pictureviewer.slideshowdir.value):
337                                         print "+" * 10, os.path.basename(filename)
338                                         os.mkdir(config.plugins.pictureviewer.slideshowdir.value)
339                                 fp = open(config.plugins.pictureviewer.slideshowdir.value + filename+config.plugins.pictureviewer.slideshowext.value, "w")
340                                 fp.write("# this is a slideshow file for "+myname+" made by V"+myversion+"\n")
341                                 fp.write("# you can make your own... each line with full path of the imagefile\n")
342                                 fp.write("# by importing this file,we will ignoring a file if is doesnt exist\n")
343                                 for x in self.slideshowfiles:
344                                         fp.write(x[1] + "\n")
345                                 fp.close()
346                         except IOError, e:
347                                 print "["+myname+"] error:", e
348
349         def KeyYellow(self):
350                 if self.currList is "filelist":
351                         # add picture to list
352                         fullfile = self["menu"].getSelection()[0]
353                         if os.path.isfile(fullfile):
354                                 self.slideshowfiles.append((_(fullfile.split("/")[-1]), fullfile))
355                                 self["slist"].l.setList(self.slideshowfiles)
356                 else:
357                         # deleting an Picture
358                         if len(self.slideshowfiles) >= 1:
359                                 indexinlist = self["slist"].l.getCurrentSelectionIndex()
360                                 self.slideshowfiles.pop(indexinlist)
361                                 self["slist"].l.setList(self.slideshowfiles)
362
363         def switchList(self):
364                 if self.currList is "filelist" :
365                         # Slideshow activieren
366                         self.filelist.selectionEnabled(0)
367                         self.slideshowlist.selectionEnabled(1)
368                         self["buttonred"].setText("speichern")
369                         self["buttongreen"].setText("laden")
370                         self["buttonyellow"].setText("loeschen")
371                         self["buttonblue"].setText("Dateien")
372                         self.currList = "slideshowlist"
373                 else:
374                         # filelist activieren
375                         self.filelist.selectionEnabled(1)
376                         self.slideshowlist.selectionEnabled(0)
377                         self["buttonred"].setText("starte Slideshow")
378                         self["buttongreen"].setText("alle hinzufuegen")
379                         self["buttonyellow"].setText("hinzufuegen")
380                         self["buttonblue"].setText("Slideshow bearbeiten")
381                         self.currList = "filelist"
382
383         def go(self):
384                 if self.currList is "filelist" :
385                         selection = self["menu"].getSelection()
386                         if self.filelist.canDescent():
387                                 self.setTitle(selection[0])
388                                 self.filelist.descent()
389                         else:
390                                 if selection[1] == True: # isDir
391                                         pass
392                                 else:
393                                         print "["+myname+"] file selected ", selection[0]
394                                         if os.path.isfile(selection[0]):
395                                                 self.session.open(PictureScreen,selection[0].split("/")[-1], selection[0])
396                                         else:
397                                                 print "["+myname+"] file not found ", selection[0]
398                 else:
399                         self.updateInfoPanel()
400
401         def up(self):
402                  if self.currList is "filelist":
403                          self.filelist.up()
404                          self.updateInfoPanel()
405                  else:
406                          self.slideshowlist.up()
407
408         def leftUp(self):
409                  if self.currList is "filelist":
410                          self.filelist.pageUp()
411                          self.updateInfoPanel()
412                  else:
413                          self.slideshowlist.pageUp()
414
415         def rightUp(self):
416                 if self.currList is "filelist":
417                          self.filelist.pageDown()
418                          self.updateInfoPanel()
419                 else:
420                          self.slideshowlist.pageDown()
421
422         def down(self):
423                  if self.currList is "filelist":
424                          self.filelist.down()
425                          self.updateInfoPanel()
426                  else:
427                          self.slideshowlist.down()
428
429         def updateInfoPanel(self):
430                 if self.currList is "filelist":
431                         selectedfile = self["menu"].getSelection()[0]
432                 else:
433                         selectedfile = self["slist"].l.getCurrentSelection()[1]
434                 sc=AVSwitch().getFramebufferScale()
435                 self.picload = ePicLoad()
436                 self.picload_conn = self.picload.PictureData.connect(self.updateInfoPanelCB)
437                 self.picload.setPara((self["pixmap"].instance.size().width(), self["pixmap"].instance.size().height(), sc[0], sc[1], False, 1, "#FF000000"))
438                 self.picload.startDecode(selectedfile)
439
440
441         def updateInfoPanelCB(self, picInfo = None):
442                 ptr = self.picload.getData()
443                 if ptr is not None:
444                         self["pixmap"].instance.setPixmap(ptr)
445                 else:
446                         pass
447
448         def output(self,str):
449                 print "+" * 10, str
450
451         def openMenu(self):
452                 self.session.open(WebcamViewerMenu)
453 ###################
454 class WebcamViewer(Screen, InfoBarNotifications):
455         skin = ""
456         filelist = []
457         def __init__(self, session,xmlnode, args = 0):
458                 self.xmlnode = xmlnode
459                 screen_x = 736
460                 screen_y = 576
461                 size_x = 350
462                 size_y = 250
463                 pos_x = (screen_x/2)-(size_x/2)
464                 pos_y = (screen_y/2)-(size_y/2)
465                 skin = """
466                 <screen position="%i,%i" size="%i,%i" title="%s">
467                         <widget name="menu" position="1,1" size="%i,%i"  scrollbarMode="showOnDemand"/>
468                 </screen>""" % (pos_x,pos_y,size_x,size_y,myname,size_x,size_y)
469                 self.skin = skin
470                 Screen.__init__(self, session)
471                 InfoBarNotifications.__init__(self)
472
473                 self.filelist = MenuList(self.getMenuData())
474                 self["menu"] = self.filelist
475                 self["actions"] = ActionMap(["WizardActions", "DirectionActions"],
476                         {
477                          "ok": self.go,
478                          "back": self.close,
479                          }, -1)
480                 self.onLayoutFinish.append(self.settingTitle)
481
482         def settingTitle(self):
483                 self.setTitle(myname + ": " + self.menutitle)
484
485         def go(self):
486                 selected = self["menu"].l.getCurrentSelection()[1]
487                 menuitemtitle = self["menu"].l.getCurrentSelection()[0]
488                 type = selected[0]
489                 data = selected[1]
490                 if menuitemtitle.startswith("webcam.travel"):
491                         self.session.openWithCallback(self.cb, TravelWebcamviewer)
492                 elif type.startswith("cam"):
493                         self.session.open(PictureScreen, menuitemtitle, data)
494                 else:
495                         self.hide()
496                         self.session.openWithCallback(self.cb, WebcamViewer, data)
497
498         def cb(self):
499                 self.show()
500
501         def getMenuData(self):
502                 xloader = XMLloader()
503                 self.menutitle = xloader.getScreenXMLTitle(self.xmlnode)
504                 data =[]
505                 if self.menutitle =="Mainmenu":
506                         data.append((_("webcam.travel"), "webcam.travel"))
507                 for node in self.xmlnode.childNodes:
508                         if node.nodeType != xml.dom.minidom.Element.nodeType or node.tagName != 'menu':
509                                 continue
510                         nodex = {}
511                         nodex['name'] = xloader.get_txt(node, "name", "no name")
512                         data.append((_("*" + nodex['name']), ["node", node]))
513
514                 for node in self.xmlnode.childNodes:
515                         if node.nodeType != xml.dom.minidom.Element.nodeType or node.tagName != 'cam':
516                                 continue
517                         nodex = {}
518                         nodex['name'] = xloader.get_txt(node, "name", "no name")
519                         nodex['url'] =xloader.get_txt(node, "url", "no url")
520                         data.append((_(nodex['name']), ["cam", nodex['url']]))
521                 return data
522 ###################
523
524 ##################
525 class PictureList(MenuList):
526         def __init__(self, directory, matchingPattern = None, enableWrapAround = False):
527                 MenuList.__init__(self, None, enableWrapAround, eListboxPythonMultiContent)
528                 self.showDirectories = True
529                 self.showFiles = True
530                 self.isTop = False
531                 self.matchingPattern = matchingPattern
532                 self.changeDir(directory)
533                 self.l.setFont(0, gFont("Regular", 18))
534                 self.currentDir = directory
535
536         def getCurrentDir(self):
537                 return self.currentDir
538
539         def getSelection(self):
540                 return self.l.getCurrentSelection()[0]
541
542         def getFileList(self):
543                 return self.list
544
545         def changeDir(self, directory):
546                 self.currentDir = directory
547                 self.list = []
548
549                 directories = []
550                 files = []
551                 files = os.listdir(directory)
552                 files.sort()
553                 tmpfiles = files[:]
554                 for x in tmpfiles:
555                         if os.path.isdir(directory + "/" + x):
556                                 directories.append(x)
557                                 files.remove(x)
558                 directories.sort()
559                 files.sort()
560                 if directory != "/" and self.showDirectories and not self.isTop:
561                         self.list.append(self.getPictureEntryComponent("..", '/'.join(directory.split('/')[:-2]) + '/', True))
562
563                 if self.showDirectories:
564                         for x in directories:
565                                 name = (directory+x).split('/')[-1]
566                                 self.list.append(self.getPictureEntryComponent(name, '/'.join(directory.split('/')[:-1]) + '/' + x + '/', True))
567
568                 if self.showFiles:
569                         for x in files:
570                                 path = directory + x
571                                 name = x
572                                 if self.matchingPattern is not None:
573                                         if compile(self.matchingPattern).search(path):
574                                                 self.list.append(self.getPictureEntryComponent(name,path, False))
575                                 else:
576                                         pass
577
578                 self.l.setList(self.list)
579
580         def canDescent(self):
581                 return self.getSelection()[1]
582
583         def descent(self):
584                 self.changeDir(self.getSelection()[0])
585
586         def getFilename(self):
587                 return self.getSelection()[0].getPath()
588
589         def getServiceRef(self):
590                 return self.getSelection()[0]
591
592         def postWidgetCreate(self, instance):
593                 MenuList.postWidgetCreate(self, instance)
594                 instance.setItemHeight(23)
595
596         def getPictureEntryComponent(self,name, absolute, isDir):
597                 """ name={angezeigter Name}, absolute={vollstaendiger Pfad}, isDir={True,False} """
598                 res = [ (absolute, isDir) ]
599                 res.append((eListboxPythonMultiContent.TYPE_TEXT, 35, 1, 200, 20, 0, 0, name))
600                 if isDir:
601                         png = loadPNG("/usr/share/enigma2/extensions/directory.png")
602                 else:
603                         extension = name.split('.')
604                         extension = extension[-1].lower()
605                         if EXTENSIONS.has_key(extension):
606                                 png = loadPNG("/usr/share/enigma2/extensions/" + EXTENSIONS[extension] + ".png")
607                         else:
608                                 png = None
609                 if png is not None:
610                         res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, 10, 2, 20, 20, png))
611                 return res
612
613
614 ##################
615 class XMLloader:
616         DEFAULT_NAMESPACES = (
617                   None, # RSS 0.91, 0.92, 0.93, 0.94, 2.0
618                   'http://purl.org/rss/1.0/', # RSS 1.0
619                   'http://my.netscape.com/rdf/simple/0.9/' # RSS 0.90
620                 )
621         DUBLIN_CORE = ('http://purl.org/dc/elements/1.1/',)
622         def getElementsByTagName(self, node, tagName, possibleNamespaces = DEFAULT_NAMESPACES):
623                 for namespace in possibleNamespaces:
624                         children = node.getElementsByTagNameNS(namespace, tagName)
625                         if len(children):
626                                 return children
627                 return []
628
629         def node_data(self, node, tagName, possibleNamespaces = DEFAULT_NAMESPACES):
630                 children = self.getElementsByTagName(node, tagName, possibleNamespaces)
631                 node = len(children) and children[0] or None
632                 return node and "".join([child.data.encode("utf-8") for child in node.childNodes]) or None
633
634         def get_txt(self, node, tagName, default_txt = ""):
635                 """
636                 Liefert den Inhalt >tagName< des >node< zurueck, ist dieser nicht
637                 vorhanden, wird >default_txt< zurueck gegeben.
638                 """
639                 return self.node_data(node, tagName) or self.node_data(node, tagName, self.DUBLIN_CORE) or default_txt
640
641         def getScreenXMLTitle(self,node):
642                 return self.get_txt(node, "name", "no title")
643