added zdf mediathek plugin
[enigma2-plugins.git] / zdfmediathek / src / plugin.py
1 # -*- coding: UTF-8 -*-
2 # ZDF Mediathek by AliAbdul\r
3 from Components.ActionMap import ActionMap
4 from Components.AVSwitch import AVSwitch\r
5 from Components.Label import Label\r
6 from Components.MenuList import MenuList\r
7 from Components.MultiContent import MultiContentEntryText, MultiContentEntryPixmapAlphaTest
8 from Components.Pixmap import Pixmap
9 from Components.PluginComponent import plugins\r
10 from enigma import eListboxPythonMultiContent, ePicLoad, eServiceReference, eTimer, getDesktop, gFont
11 from os import listdir
12 from Plugins.Plugin import PluginDescriptor
13 from Screens.ChoiceBox import ChoiceBox
14 from Screens.InfoBar import MoviePlayer
15 from Screens.MessageBox import MessageBox\r
16 from Screens.Screen import Screen\r
17 from Screens.VirtualKeyBoard import VirtualKeyBoard
18 from time import sleep
19 from Tools.BoundFunction import boundFunction
20 from Tools.Directories import resolveFilename, SCOPE_PLUGINS
21 from Tools.HardwareInfo import HardwareInfo
22 from Tools.LoadPixmap import LoadPixmap\r
23 from twisted.web.client import downloadPage, getPage\r
24 import htmlentitydefs, re, urllib2
25
26 ###################################################
27
28 MAIN_PAGE = "http://www.zdf.de"
29
30 PNG_PATH = resolveFilename(SCOPE_PLUGINS)+"/Extensions/ZDFMediathek/"
31
32 TYPE_NOTHING = 0
33 TYPE_MOVIE = 1
34 TYPE_PODCAST = 2
35 TYPE_MOVIELIST_CATEGORY = 3
36
37 LIST_LEFT = 0
38 LIST_RIGHT = 1
39 LIST_NONE = 2
40
41 if HardwareInfo().get_device_name().startswith("dm800"):
42         PLAY_MP4 = False # TODO: Benutze 'True' wenn RTSP-Streaming mit gstreamer funktioniert, es wird dann kein PC mehr benötigt
43 else:
44         PLAY_MP4 = False
45
46 try:
47         from LT.LTStreamPlayer import streamplayer
48 except ImportError:
49         try:
50                 from Plugins.Extensions.LTMediaCenter.LTStreamPlayer import streamplayer
51         except ImportError:
52                 streamplayer = None
53
54 try:
55         from Plugins.Extensions.VlcPlayer.VlcServerConfig import vlcServerConfig
56 except ImportError:
57         vlcServerConfig = None
58
59 ###################################################
60
61 def decode(line):\r
62         pat = re.compile(r'\\u(....)')\r
63         def sub(mo):\r
64                 return unichr(fromHex(mo.group(1)))\r
65         return pat.sub(sub, unicode(line))\r
66 \r
67 def decode2(line):\r
68         pat = re.compile(r'&#(\d+);')\r
69         def sub(mo):\r
70                 return unichr(int(mo.group(1)))\r
71         return decode3(pat.sub(sub, unicode(line)))\r
72 \r
73 def decode3(line):\r
74         dic = htmlentitydefs.name2codepoint\r
75         for key in dic.keys():\r
76                 entity = "&" + key + ";"\r
77                 line = line.replace(entity, unichr(dic[key]))\r
78         return line\r
79 \r
80 def fromHex(h):\r
81         return int(h, 16)
82
83 ###################################################
84
85 class ChangedMoviePlayer(MoviePlayer):
86         def __init__(self, session, service):
87                 MoviePlayer.__init__(self, session, service)
88                 self.skinName = "MoviePlayer"
89
90         def leavePlayer(self):
91                 self.session.openWithCallback(self.leavePlayerConfirmed, MessageBox, "Abspielen beenden?")
92
93         def leavePlayerConfirmed(self, answer):
94                 if answer:
95                         self.close()
96
97         def doEofInternal(self, playing):
98                 pass
99
100         def getPluginList(self):
101                 list = []
102                 for p in plugins.getPlugins(where=PluginDescriptor.WHERE_EXTENSIONSMENU):
103                         if p.name != "ZDF Mediathek":
104                                 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
105                 return list
106
107         def showMovies(self):
108                 pass
109
110 ###################################################
111
112 def getMovieDetails(div):
113         list = []
114         # Lese Sendung...
115         reonecat = re.compile(r'<p class="grey"><a href="(.+?)">(.+?)</a></p>', re.DOTALL)
116         content = reonecat.findall(div)
117         if len(content):
118                 broadcast = decode2(decode(content[0][1])).encode("UTF-8")
119                 list.append(content[0][0])
120                 if broadcast.startswith("<"):
121                         broadcast = ""
122                 list.append(broadcast)
123         # Lese Titel...
124         reonecat = re.compile(r'<p><b><a href=".+?">(.+?)</a></b></p>', re.DOTALL)
125         titles = reonecat.findall(div)
126         if len(titles):
127                 title = titles[0]
128                 if '<br/>' in title:
129                         idx = title.index('<br/>')
130                         title = title[:idx]
131                 if '<br />' in title:
132                         idx = title.index('<br />')
133                         title = title[:idx]
134                 title = decode2(decode(title)).encode("UTF-8")
135                 list.append(title)
136         # Lese Thumbnail-URL...
137         reonecat = re.compile(r'<img src="(.+?)"', re.DOTALL)
138         thumbnails = reonecat.findall(div)
139         if len(thumbnails):
140                 list.append(thumbnails[0])
141         # Lese Videolänge...
142         if ('VIDEO, ' in div):
143                 reonecat = re.compile(r'>VIDEO, (.+?)</a></p>', re.DOTALL)
144                 lengths = reonecat.findall(div)
145                 if len(lengths):
146                         list.append(lengths[0])
147         else:
148                 list.append("Live")
149         # Alles gefunden?
150         if len(list) == 5:
151                 return list
152         else:
153                 return None
154
155 def getCategoryDetails(div):
156         list = []
157         # Lese Rubrik...
158         reonecat = re.compile(r'<p class="grey"><a href="(.+?)">(.+?)</a></p>', re.DOTALL)
159         content = reonecat.findall(div)
160         if len(content):
161                 broadcast = decode2(decode(content[0][1])).encode("UTF-8")
162                 list.append(content[0][0])
163                 if broadcast.startswith("<"):
164                         broadcast = ""
165                 list.append(broadcast)
166         # Lese Titel...
167         reonecat = re.compile(r'<p><b><a href=".+?">(.+?)</a></b></p>', re.DOTALL)
168         titles = reonecat.findall(div)
169         if len(titles):
170                 title = titles[0]
171                 if '<br/>' in title:
172                         idx = title.index('<br/>')
173                         title = title[:idx]
174                 if '<br />' in title:
175                         idx = title.index('<br />')
176                         title = title[:idx]
177                 title = decode2(decode(title)).encode("UTF-8")
178                 list.append(title)
179         # Lese Thumbnail-URL...
180         reonecat = re.compile(r'<img src="(.+?)"', re.DOTALL)
181         thumbnails = reonecat.findall(div)
182         if len(thumbnails):
183                 list.append(thumbnails[0])
184         # Lese Beitragsanzahl...
185         reonecat = re.compile(r'">(.+?)BEITR&Auml;GE ZUR SENDUNG</a></p>', re.DOTALL)
186         counts = reonecat.findall(div)
187         if len(counts):
188                 count = counts[0]
189                 if '">' in count:
190                         while '">' in count:
191                                 idx = count.index('">')
192                                 count = count[idx+2:]
193                 if '"/>' in count:
194                         while '"/>' in count:
195                                 idx = count.index('"/>')
196                                 count = count[idx+3:]
197                 list.append("%sBeitraege"%count)
198         else:
199                 reonecat = re.compile(r'">(.+?)BEITR&Auml;GE ZUM THEMA</a></p>', re.DOTALL)
200                 counts = reonecat.findall(div)
201                 if len(counts):
202                         count = counts[0]
203                         if '">' in count:
204                                 while '">' in count:
205                                         idx = count.index('">')
206                                         count = count[idx+2:]
207                         if '"/>' in count:
208                                 while '"/>' in count:
209                                         idx = count.index('"/>')
210                                         count = count[idx+3:]
211                         list.append("%sBeitraege"%count)
212                 else:
213                         reonecat = re.compile(r'">(.+?)BEITR&Auml;GE ZUR RUBRIK</a></p>', re.DOTALL)
214                         counts = reonecat.findall(div)
215                         if len(counts):
216                                 count = counts[0]
217                                 if '">' in count:
218                                         while '">' in count:
219                                                 idx = count.index('">')
220                                                 count = count[idx+2:]
221                                 if '"/>' in count:
222                                         while '"/>' in count:
223                                                 idx = count.index('"/>')
224                                                 count = count[idx+3:]
225                                 list.append("%sBeitraege"%count)
226         # Alles gefunden?
227         if len(list) == 5:
228                 return list
229         else:
230                 return None
231
232 ###################################################
233
234 def getMovieUrl(url):
235         try:\r
236                 f = urllib2.urlopen(url)\r
237                 txt = f.read()\r
238                 f.close()
239         except:
240                 txt = ""
241         if ('rtsp' in txt) and ('.mp4' in txt):
242                 idx = txt.index('rtsp')
243                 idx2 = txt.index('.mp4')
244                 return txt[idx:idx2+4]
245         else:
246                 return None
247
248 def getTitleLinks(html):
249         links = []
250         start = '<div id="breadcrumbContainer">'
251         end = '</div>'
252         if start in html:
253                 idx = html.index(start)
254                 html = html[idx:]
255                 idx = html.index(end)
256                 html = html[:idx]
257                 reonecat = re.compile(r'<a href="(.+?)">(.+?)</a>', re.DOTALL)
258                 for url, name in reonecat.findall(html):
259                         name = decode2(decode(name)).encode("UTF-8")
260                         links.append([url, name])
261         return links
262
263 def getLeftMenu(html):
264         list = []
265         reonecat = re.compile(r'<div id="navigationContainer">(.+?)</div>', re.DOTALL)
266         leftMenu = reonecat.findall(html)
267         if len(leftMenu):
268                 reonecat = re.compile(r'<li><a href="(.+?)"(.+?)</a>', re.DOTALL)
269                 for url, name in reonecat.findall(leftMenu[0]):
270                         if name.startswith(' class="active">'):
271                                 active = True
272                                 name = name[16:]
273                         else:
274                                 active = False
275                                 name = name[1:]
276                         if (name != "Hilfe") and (not 'Podcasts' in name): # TODO: Podcasts brauchen noch etwas Arbeit... derzeit deaktiviert
277                                 list.append([url, name, active])
278         return list
279
280 def getRightMenu(html):
281         list = []
282         # Suche Filme...
283         if '" class="play" target="_blank">Abspielen</a></li>' in html:
284                 reonecat = re.compile(r'<li>(.+?)<a href="(.+?)" class="play" target="_blank">Abspielen</a></li>', re.DOTALL)
285                 for speed, movie in reonecat.findall(html):
286                         list.append([speed, movie])
287                 if len(list):
288                         return [TYPE_MOVIE, list]
289         # Suche podcasts...
290         if '<!-- Start:Podcasts -->' in html:
291                 reonecat = re.compile(r'<!-- Start:Podcasts -->(.+?)<!-- Ende:Podcasts -->', re.DOTALL)
292                 tmp = reonecat.findall(html)
293                 if len(tmp):
294                         reonecat = re.compile(r'<p><b><a href="(.+?)".+?">(.+?)</a></b></p>', re.DOTALL)
295                         podcasts = reonecat.findall(tmp[0])
296                         for podcast in podcasts:
297                                 list.append([podcast[0], podcast[1]])
298                 if len(list):
299                         return [TYPE_PODCAST, list]
300         # Suche Videos und Rubriken...
301         start = '<div class="beitragListe">'
302         if '<div class="beitragFooterSuche">' in html:
303                 end = '<div class="beitragFooterSuche">'
304         else:
305                 end = '<div class="beitragFooter">'
306         if (start in html) and (end in html):
307                 while (start in html) and (end in html):
308                         idx = html.index(start)
309                         html = html[idx:]
310                         reonecat = re.compile(r'%s(.+?)%s'%(start, end), re.DOTALL)
311                         blocks = reonecat.findall(html)
312                         if blocks:
313                                 reonecat = re.compile(r'<div class="image">(.+?)</li>', re.DOTALL)
314                                 divs = reonecat.findall(blocks[0])
315                                 for div in divs:
316                                         details = None
317                                         if ('VIDEO, ' in div) or ('>LIVE<' in div):
318                                                 details = getMovieDetails(div)
319                                         elif 'BEITR&Auml;GE ZU' in div:
320                                                 details = getCategoryDetails(div)
321                                         if details:
322                                                 list.append([details[0], details[1], details[2], details[3], details[4]])
323                         html = html[1:]
324                 reonecat = re.compile(r'<a href="(.+?)" class="weitereBeitraege"', re.DOTALL)
325                 more = reonecat.findall(html)
326                 if len(more):
327                         more = more[0]
328                         if 'href="' in more:
329                                 while 'href="' in more:
330                                         idx = more.index('href="')
331                                         more = more[idx+6:]
332                         list.append([more, "", "", "", "Weitere  Beitraege laden."])
333         if len(list):
334                 return [TYPE_MOVIELIST_CATEGORY, list]
335         # Nichts :(
336         return [TYPE_NOTHING, list]
337
338 ###################################################
339
340 class LeftMenuList(MenuList):
341         def __init__(self):
342                 MenuList.__init__(self, [], False, eListboxPythonMultiContent)
343                 self.l.setItemHeight(20)
344                 self.l.setFont(0, gFont("Regular", 18))
345                 self.menu = []
346                 self.active = True
347                 self.current = 0
348
349         def setActive(self, active):
350                 self.active = active
351                 self.SetList(self.menu, True)
352
353         def entry(self, text, active, selected):
354                 res = [(text)]
355                 if text.startswith("- Heute"):
356                         text = "- Heute"
357                 elif text.startswith("- Gestern"):
358                         text = "- Gestern"
359                 elif text.startswith("- Morgen"):
360                         text = "- Morgen"
361                 if selected:
362                         res.append(MultiContentEntryPixmapAlphaTest(pos=(0, 0), size=(20, 20), png=LoadPixmap(cached=True, path=PNG_PATH+"active.png")))
363                 if active:
364                         res.append(MultiContentEntryText(pos=(25, 0), size=(175, 20), font=0, text=text, color=0xf47d19))
365                 else:
366                         res.append(MultiContentEntryText(pos=(25, 0), size=(175, 20), font=0, text=text, color=0xffffff))
367                 return res
368
369         def SetList(self, l, moveCursor=False):
370                 del self.menu
371                 self.menu = l
372                 if moveCursor:
373                         idx = 0
374                         for x in l:
375                                 if x[2]:
376                                         self.current = idx
377                                 idx += 1
378                 list = []
379                 idx = 0
380                 for x in l:
381                         if (idx == self.current) and self.active:
382                                 selected = True
383                         else:
384                                 selected = False
385                         list.append(self.entry(x[1], x[2], selected))
386                         idx += 1
387                 self.setList(list)
388
389         def getCurrentUrl(self):
390                 if len(self.menu):
391                         return self.menu[self.current][0]
392                 else:
393                         return None
394
395         def select(self, index):
396                 if len(self.menu):
397                         if (index > -1) and (index < len(self.menu)):
398                                 self.current = index
399                                 self.SetList(self.menu)
400
401         def first(self):
402                 self.select(0)
403
404         def last(self):
405                 self.select(len(self.menu)-1)
406
407         def previous(self):
408                 if len(self.menu):
409                         self.select(self.current-1)
410
411         def next(self):
412                 if len(self.menu):
413                         self.select(self.current+1)
414
415 ###################################################
416
417 class RightMenuList(MenuList):
418         def __init__(self):
419                 MenuList.__init__(self, [], False, eListboxPythonMultiContent)
420                 self.l.setFont(0, gFont("Regular", 18))
421                 self.l.setFont(1, gFont("Regular", 16))
422                 self.listCompleted = []
423                 self.callback = None
424                 self.idx = 0
425                 self.thumb = ""
426
427         def buildEntries(self):
428                 if self.type == TYPE_PODCAST:
429                         list = []
430                         for x in self.list:
431                                 title = x[1]
432                                 if '<br/>' in title:
433                                         idx = title.index('<br/>')
434                                         title = title[:idx]
435                                 title = decode2(decode(title)).encode("UTF-8")
436                                 res = [(x[0], title)]
437                                 res.append(MultiContentEntryText(pos=(0, 0), size=(430, 20), font=0, text=title))
438                                 list.append(res)
439                         self.setList(list)
440                         if self.callback:
441                                 self.callback()
442                 elif self.type == TYPE_MOVIELIST_CATEGORY:
443                         if self.idx == len(self.list):
444                                 self.setList(self.listCompleted)
445                                 if self.callback:
446                                         self.callback()
447                         else:
448                                 self.downloadThumbnail()
449
450         def downloadThumbnail(self):
451                 thumbUrl = self.list[self.idx][3]
452                 if not thumbUrl.startswith("http://"):
453                         thumbUrl = "%s%s"%(MAIN_PAGE, thumbUrl)
454                 try:
455                         req = urllib2.Request(thumbUrl)
456                         url_handle = urllib2.urlopen(req)\r
457                         headers = url_handle.info()\r
458                         contentType = headers.getheader("content-type")
459                 except:
460                         contentType = None
461                 if contentType:
462                         if 'image/jpeg' in contentType:
463                                 self.thumb = "/tmp/zdf.jpg"
464                         elif 'image/gif' in contentType:
465                                 self.thumb = "/tmp/zdf.gif"
466                         elif 'image/png' in contentType:
467                                 self.thumb = "/tmp/zdf.png"
468                         else:
469                                 print "[ZDF Mediathek] Unknown thumbnail content-type:", contentType
470                                 self.thumb = None
471                 else:
472                         self.thumb = None
473                 if self.thumb:
474                         downloadPage(thumbUrl, self.thumb).addCallback(self.downloadThumbnailCallback).addErrback(self.downloadThumbnailError)
475                 else:
476                         self.buildEntry(None)
477
478         def downloadThumbnailError(self, err):
479                 print "[ZDF Mediathek] Error:", err
480                 self.buildEntry(None)
481
482         def downloadThumbnailCallback(self, txt=""):
483                 sc = AVSwitch().getFramebufferScale()
484                 self.picload = ePicLoad()
485                 self.picload.PictureData.get().append(self.buildEntry)
486                 self.picload.setPara((94, 60, sc[0], sc[1], False, 1, "#00000000"))
487                 self.picload.startDecode(self.thumb)
488
489         def buildEntry(self, picInfo=None):
490                 x = self.list[self.idx]
491                 res = [(x[0], x[2])]
492                 if picInfo:
493                         ptr = self.picload.getData()
494                         if ptr != None:
495                                 res.append(MultiContentEntryPixmapAlphaTest(pos=(0, 0), size=(94, 60), png=ptr))
496                 res.append(MultiContentEntryText(pos=(100, 0), size=(430, 20), font=0, text=x[2]))
497                 res.append(MultiContentEntryText(pos=(100, 20), size=(430, 20), font=0, text=x[4]))
498                 res.append(MultiContentEntryText(pos=(100, 40), size=(430, 20), font=1, text=x[1]))
499                 self.listCompleted.append(res)
500                 self.idx += 1
501                 self.buildEntries()
502
503         def SetList(self, l):
504                 self.type = l[0]
505                 self.list = l[1]
506                 if self.type == TYPE_PODCAST:
507                         self.l.setItemHeight(20)
508                         self.buildEntries()
509                 elif self.type == TYPE_MOVIELIST_CATEGORY:
510                         self.l.setItemHeight(60)
511                         del self.listCompleted
512                         self.listCompleted = []
513                         self.idx = 0
514                         self.buildEntries()
515                 else:
516                         self.setList([])
517                         if self.callback:
518                                 self.callback()
519
520 ###################################################
521
522 class ZDFMediathekCache(Screen):
523         skin = """
524                 <screen position="center,center" size="76,76" flags="wfNoBorder" backgroundColor="#ffffff" >
525                         <eLabel position="2,2" zPosition="1" size="72,72" font="Regular;18" backgroundColor="#252525" />
526                         <widget name="spinner" position="14,14" zPosition="2" size="48,48" alphatest="on" />
527                 </screen>"""
528
529         def __init__(self, session):
530                 self.session = session
531                 Screen.__init__(self, session)
532                 
533                 self["spinner"] = Pixmap()
534                 self.curr = 0
535                 
536                 self.timer = eTimer()
537                 self.timer.callback.append(self.showNextSpinner)
538
539         def start(self):
540                 self.show()
541                 self.timer.start(200, False)
542
543         def stop(self):
544                 self.hide()
545                 self.timer.stop()
546
547         def showNextSpinner(self):
548                 self.curr += 1
549                 if self.curr > 10:
550                         self.curr = 0
551                 png = LoadPixmap(cached=True, path=PNG_PATH + str(self.curr) + ".png")
552                 self["spinner"].instance.setPixmap(png)
553
554 ###################################################
555
556 class ZDFMediathek(Screen):
557         def __init__(self, session):
558                 self.session = session
559                 
560                 desktop = getDesktop(0)
561                 size = desktop.size()
562                 width = size.width()
563                 
564                 if width == 720:
565                         self.skin = """<screen position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#252525" >"""
566                 else:
567                         self.skin = """<screen position="center,center" size="720,576" title="ZDF Mediathek" backgroundColor="#252525" >"""
568                 self.skin += """<ePixmap position="40,30" size="133,40" pixmap="%s" />
569                                 <widget name="navigationTitle" position="250,40" size="430,25" font="Regular;18" backgroundColor="#252525" foregroundColor="#f47d19" noWrap="1" />
570                                 <widget name="leftList" position="40,70" size="200,440" transparent="1" selectionDisabled="1" />
571                                 <widget name="rightList" position="250,70" size="430,480" backgroundColor="#3d3c3c" backgroundColorSelected="#565656" selectionDisabled="1" scrollbarMode="showOnDemand" />
572                                 <ePixmap pixmap="skin_default/buttons/key_menu.png" position="40,520" size="35,25" transparent="1" alphatest="on" />
573                                 <widget name="serverName" position="80,520" size="160,20" font="Regular;18" backgroundColor="#252525" foregroundColor="#f47d19" />
574                                 <widget name="fakeList" position="0,0" size="0,0" />
575                         </screen>""" % (PNG_PATH+"logo.png")
576                 
577                 Screen.__init__(self, session)
578                 
579                 self["navigationTitle"] = Label(" ")
580                 self["leftList"] = LeftMenuList()
581                 self["rightList"] = RightMenuList()
582                 self["fakeList"] = MenuList([])
583                 self["serverName"] = Label("Server")
584                 
585                 self["actions"] = ActionMap(["ZDFMediathekActions"],
586                         {
587                                 "back": self.exit,
588                                 "ok": self.ok,
589                                 "left": self.left,
590                                 "right": self.right,
591                                 "up": self.up,
592                                 "down": self.down,
593                                 "previousList": self.toggleList,
594                                 "nextList": self.toggleList,
595                                 "menu": self.selectServer,
596                                 "search": self.search,
597                                 "previousPage": self.previousPage
598                         }, -1)
599                 
600                 self.cacheDialog = self.session.instantiateDialog(ZDFMediathekCache)
601                 self["rightList"].callback = self.deactivateCacheDialog
602                 self.working = False
603                 self.currentList = LIST_RIGHT
604                 self.linkPreviousPage = ""
605                 
606                 self.transcodeServer = None
607                 self.cacheTimer = eTimer()
608                 self.cacheTimer.callback.append(self.chechCachedFile)
609                 
610                 self.onLayoutFinish.append(self.getPage)
611
612         def getPage(self, page=None):
613                 self.working = True
614                 if not page:
615                         page = "/ZDFmediathek/hauptnavigation/startseite?flash=off"
616                 url = "%s%s"%(MAIN_PAGE, page)
617                 getPage(url).addCallback(self.gotPage).addErrback(self.error)
618
619         def error(self, err=""):
620                 print "[ZDF Mediathek] Error:", err
621                 self.working = False
622                 self.deactivateCacheDialog()
623
624         def gotPage(self, html=""):
625                 rightMenu = getRightMenu(html)
626                 if rightMenu[0] == TYPE_MOVIE:
627                         list = []
628                         for x in rightMenu[1]:
629                                 list.append(("%s %s"%(x[0], x[1].split(".")[-1]), x[1]))
630                         if len(list):
631                                 self.session.openWithCallback(self.play, ChoiceBox, title="Selektiere...", list=list)
632                         else:
633                                 self.working = False
634                 else:
635                         self.cacheDialog.start()
636                         self.currentList = LIST_NONE
637                         links = getTitleLinks(html)
638                         txt = ""
639                         for x in links:
640                                 txt = txt + x[1] + " / "
641                         if len(txt) > 1:
642                                 txt = txt[:-3]
643                                 if (len(links) > 1):
644                                         self.linkPreviousPage = links[-2][0]
645                                 else:
646                                         self.linkPreviousPage = ""
647                         else:
648                                 self.linkPreviousPage = ""
649                         self["navigationTitle"].setText(txt)
650                         self["leftList"].SetList(getLeftMenu(html), True)
651                         self["rightList"].SetList(rightMenu)
652                         self["leftList"].selectionEnabled(0)
653                         self["rightList"].selectionEnabled(1)
654                         self["fakeList"].selectionEnabled(0)
655                         self["leftList"].setActive(False)
656
657         def previousPage(self):
658                 self.getPage(self.linkPreviousPage)
659
660         def search(self):
661                 self.session.openWithCallback(self.searchCallback, VirtualKeyBoard, title="Suche nach:")
662
663         def searchCallback(self, callback):
664                 if callback and (callback != ""):
665                         self.getPage("/ZDFmediathek/suche?sucheText=%s&offset=0&flash=off"%(callback.replace(" ", "+")))
666
667         def play(self, callback):
668                 self.working = False
669                 if callback is not None:
670                         url = callback[1]
671                         if url.endswith(".mov"):
672                                 url = getMovieUrl(url)
673                         if url:
674                                 if PLAY_MP4 and url.endswith(".mp4"):
675                                         ref = eServiceReference(4097, 0, url)
676                                         self.session.open(ChangedMoviePlayer, ref)
677                                 else: # Die Hardware kann das Format nicht direkt abspielen, mit Stream2Dream oder vlc Server probieren...
678                                         if self.transcodeServer is not None:
679                                                 if self.transcodeServer == "LT Stream2Dream":
680                                                         r = streamplayer.play(url)
681                                                         if r == "ok":
682                                                                 sleep(6)
683                                                                 self.currentList = LIST_NONE
684                                                                 self.cacheDialog.start()
685                                                                 self.cacheTimer.start(1000, False)
686                                                 else:
687                                                         self.transcodeServer.play(self.session, url, self["rightList"].getCurrent()[0][1])
688                                         else:
689                                                 self.session.open(MessageBox, "Es wurde kein Server ausgewählt!", MessageBox.TYPE_ERROR)
690                         else:
691                                 self.session.open(MessageBox, "Fehler beim Ermitteln der Film-URL!", MessageBox.TYPE_ERROR)
692
693         def chechCachedFile(self):
694                 try:
695                         f = open ("/tmp/mpstream/progress.txt")
696                         content = f.read()
697                         f.close()
698                         list = content.split("-")
699                         cacheMB = int(list[0])
700                         if cacheMB > 10: # Starte nach 10 MB Bufferung
701                                 self.cacheTimer.stop()
702                                 self.playCachedFile()
703                 except:
704                         pass
705
706         def deactivateCacheDialog(self):
707                 self.cacheDialog.stop()
708                 self.currentList = LIST_RIGHT
709                 self.working = False
710
711         def playCachedFile(self):
712                 self.deactivateCacheDialog()
713                 ref = eServiceReference(1, 0, "/tmp/mpstream/MPStream.ts")
714                 self.session.openWithCallback(self.stopStream2Dream, ChangedMoviePlayer, ref)
715
716         def stopStream2Dream(self, callback=None):
717                 streamplayer.stop()
718                 sleep(4)
719
720         def toggleList(self):
721                 if not self.working:
722                         if self.currentList == LIST_LEFT:
723                                 self.currentList = LIST_RIGHT
724                                 self["leftList"].setActive(False)
725                                 self["fakeList"].selectionEnabled(0)
726                                 self["rightList"].selectionEnabled(1)
727                         elif self.currentList == LIST_RIGHT:
728                                 self.currentList = LIST_LEFT
729                                 self["leftList"].setActive(True)
730                                 self["rightList"].selectionEnabled(0)
731                                 self["fakeList"].selectionEnabled(1)
732
733         def selectServer(self):
734                 list = []
735                 if streamplayer:
736                         list.append(("LT Stream2Dream", "LT Stream2Dream"))
737                 if vlcServerConfig:
738                         serverList = vlcServerConfig.getServerlist()
739                         for x in serverList:
740                                 list.append((x.getName(), x))
741                 if len(list):
742                         self.session.openWithCallback(self.serverChosen, ChoiceBox, title="Waehle den Server...", list=list)
743
744         def serverChosen(self, callback):
745                 if callback:
746                         server = callback[1]
747                         if server == "LT Stream2Dream":
748                                 if not streamplayer.connected:
749                                         self.transcodeServer = "LT Stream2Dream"
750                                         self["serverName"].setText("LT Stream2Dream")
751                                         self.connectToStream2Dream()
752                         else:
753                                 if streamplayer:
754                                         if streamplayer.connected:
755                                                 streamplayer.logout()
756                                 self.transcodeServer = server
757                                 self["serverName"].setText(server.getName())
758
759         def connectToStream2Dream(self):
760                 streamplayer.login()
761                 try:
762                         list = listdir("/tmp/mp")
763                 except:
764                         list = []
765                 if len(list) < 2:
766                         self.session.open(MessageBox, "Die Verbindung zu LT Stream2Dream konnte nicht hergestellt werden!", MessageBox.TYPE_ERROR)
767                         streamplayer.logout()
768                         self.transcodeServer = None
769                         self["serverName"].setText("Server")
770
771         def exit(self):
772                 if not self.working:
773                         if self.currentList == LIST_LEFT:
774                                 self.toggleList()
775                         elif self.currentList == LIST_RIGHT:
776                                 if streamplayer:
777                                         if streamplayer.connected:
778                                                 streamplayer.logout()
779                                 self.session.deleteDialog(self.cacheDialog)
780                                 self.close()
781                         else:
782                                 if streamplayer:
783                                         if streamplayer.connected:
784                                                 streamplayer.stop()
785                                                 sleep(4)
786                                 self.deactivateCacheDialog()
787
788         def ok(self):
789                 if not self.working:
790                         if self.currentList == LIST_LEFT:
791                                 self.getPage(self["leftList"].getCurrentUrl())
792                         elif self.currentList == LIST_RIGHT:
793                                 curr = self["rightList"].getCurrent()
794                                 if curr:
795                                         self.getPage(curr[0][0])
796                         elif streamplayer:
797                                 if streamplayer.connected:
798                                         if streamplayer.caching or streamclient.streaming:
799                                                 self.playCachedFile()
800
801         def left(self):
802                 if not self.working:
803                         if self.currentList == LIST_LEFT:
804                                 self["leftList"].first()
805                         elif self.currentList == LIST_RIGHT:
806                                 self["rightList"].pageUp()
807
808         def right(self):
809                 if not self.working:
810                         if self.currentList == LIST_LEFT:
811                                 self["leftList"].last()
812                         elif self.currentList == LIST_RIGHT:
813                                 self["rightList"].pageDown()
814
815         def up(self):
816                 if not self.working:
817                         if self.currentList == LIST_LEFT:
818                                 self["leftList"].previous()
819                         elif self.currentList == LIST_RIGHT:
820                                 self["rightList"].up()
821
822         def down(self):
823                 if not self.working:
824                         if self.currentList == LIST_LEFT:
825                                 self["leftList"].next()
826                         elif self.currentList == LIST_RIGHT:
827                                 self["rightList"].down()
828
829 ###################################################
830
831 def start(session, **kwargs):
832         session.open(ZDFMediathek)
833
834 def Plugins(**kwargs):
835         return PluginDescriptor(name="ZDF Mediathek", description="Streame von der ZDF Mediathek", where=[PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_PLUGINMENU], fnc=start)