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