1 # -*- coding: UTF-8 -*-
\r
2 # ZDF Mediathek by AliAbdul
\r
3 from Components.ActionMap import HelpableActionMap
\r
4 from Components.AVSwitch import AVSwitch
\r
5 from Components.Label import Label
\r
6 from Components.Sources.List import List
\r
7 from Components.MenuList import MenuList
\r
8 from Components.MultiContent import MultiContentEntryText, MultiContentEntryPixmapAlphaTest
\r
9 from Components.Pixmap import Pixmap
\r
10 from Components.PluginComponent import plugins
\r
11 from enigma import eListboxPythonMultiContent, ePicLoad, eServiceReference, eTimer, getDesktop, gFont
\r
12 from os import listdir, path as os_path, remove as os_remove
\r
13 from Plugins.Plugin import PluginDescriptor
\r
14 from Screens.ChoiceBox import ChoiceBox
\r
15 from Screens.HelpMenu import HelpableScreen
\r
16 from Screens.InfoBar import MoviePlayer
\r
17 from Screens.MessageBox import MessageBox
\r
18 from Screens.Screen import Screen
\r
19 from Screens.VirtualKeyBoard import VirtualKeyBoard
\r
20 from time import sleep
\r
21 from Tools.BoundFunction import boundFunction
\r
22 from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_CURRENT_PLUGIN
\r
23 from Tools.HardwareInfo import HardwareInfo
\r
24 from Tools.LoadPixmap import LoadPixmap
\r
25 from twisted.web.client import downloadPage, getPage
\r
26 import htmlentitydefs, re, urllib2
\r
27 from urllib2 import Request, URLError, urlopen as urlopen2
\r
28 from socket import error
\r
29 from httplib import HTTPConnection, HTTPException
\r
31 HTTPConnection.debuglevel = 1
\r
34 'User-Agent': 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100627 Firefox/3.6.6',
\r
35 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
\r
36 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
\r
37 'Accept-Language': 'en-us,en;q=0.5',
\r
40 ###################################################
\r
42 MAIN_PAGE = "http://www.zdf.de"
\r
44 PNG_PATH = resolveFilename(SCOPE_PLUGINS)+"/Extensions/ZDFMediathek/"
\r
49 TYPE_MOVIELIST_CATEGORY = 3
\r
55 deviceName = HardwareInfo().get_device_name()
\r
60 if not deviceName.startswith("dm7025"):
\r
62 if deviceName.startswith("dm7020hd"):
\r
65 from LT.LTStreamPlayer import streamplayer
\r
68 from Plugins.Extensions.LTMediaCenter.LTStreamPlayer import streamplayer
\r
73 from Plugins.Extensions.VlcPlayer.VlcServerConfig import vlcServerConfig
\r
75 vlcServerConfig = None
\r
77 ###################################################
\r
80 pat = re.compile(r'\\u(....)')
\r
82 return unichr(fromHex(mo.group(1)))
\r
83 return pat.sub(sub, unicode(line))
\r
86 pat = re.compile(r'&#(\d+);')
\r
88 return unichr(int(mo.group(1)))
\r
89 return decode3(pat.sub(sub, unicode(line)))
\r
92 dic = htmlentitydefs.name2codepoint
\r
93 for key in dic.keys():
\r
94 entity = "&" + key + ";"
\r
95 line = line.replace(entity, unichr(dic[key]))
\r
101 ###################################################
\r
103 class ChangedMoviePlayer(MoviePlayer):
\r
104 def __init__(self, session, service):
\r
105 MoviePlayer.__init__(self, session, service)
\r
106 self.skinName = "MoviePlayer"
\r
108 def leavePlayer(self):
\r
109 self.session.openWithCallback(self.leavePlayerConfirmed, MessageBox, "Abspielen beenden?")
\r
111 def leavePlayerConfirmed(self, answer):
\r
115 def doEofInternal(self, playing):
\r
118 def getPluginList(self):
\r
120 for p in plugins.getPlugins(where=PluginDescriptor.WHERE_EXTENSIONSMENU):
\r
121 if p.name != "ZDF Mediathek":
\r
122 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
\r
125 def showMovies(self):
\r
128 ###################################################
\r
130 def getMovieDetails(div):
\r
133 reonecat = re.compile(r'<p class="grey"><a href="(.+?)">(.+?)</a></p>', re.DOTALL)
\r
134 content = reonecat.findall(div)
\r
136 broadcast = decode2(decode(content[0][1])).encode("UTF-8")
\r
137 list.append(content[0][0])
\r
138 if broadcast.startswith("<"):
\r
140 list.append(broadcast)
\r
142 reonecat = re.compile(r'<p><b><a href=".+?">(.+?)</a></b></p>', re.DOTALL)
\r
143 titles = reonecat.findall(div)
\r
146 if '<br/>' in title:
\r
147 idx = title.index('<br/>')
\r
148 title = title[:idx]
\r
149 if '<br />' in title:
\r
150 idx = title.index('<br />')
\r
151 title = title[:idx]
\r
152 title = decode2(decode(title)).encode("UTF-8")
\r
154 # Lese Thumbnail-URL...
\r
155 reonecat = re.compile(r'<img src="(.+?)"', re.DOTALL)
\r
156 thumbnails = reonecat.findall(div)
\r
157 if len(thumbnails):
\r
158 list.append(thumbnails[0])
\r
159 # Lese Videolänge...
\r
160 if ('VIDEO, ' in div):
\r
161 reonecat = re.compile(r'>VIDEO, (.+?)</a></p>', re.DOTALL)
\r
162 lengths = reonecat.findall(div)
\r
164 list.append(lengths[0])
\r
166 list.append("Live")
\r
173 def getCounts(counts):
\r
176 while '">' in count:
\r
177 idx = count.index('">')
\r
178 count = count[idx+2:]
\r
180 while '"/>' in count:
\r
181 idx = count.index('"/>')
\r
182 count = count[idx+3:]
\r
185 def getCategoryDetails(div):
\r
188 reonecat = re.compile(r'<p class="grey"><a href="(.+?)">(.+?)</a></p>', re.DOTALL)
\r
189 content = reonecat.findall(div)
\r
191 broadcast = decode2(decode(content[0][1])).encode("UTF-8")
\r
192 list.append(content[0][0])
\r
193 if broadcast.startswith("<"):
\r
195 list.append(broadcast)
\r
197 reonecat = re.compile(r'<p><b><a href=".+?">(.+?)</a></b></p>', re.DOTALL)
\r
198 titles = reonecat.findall(div)
\r
201 if '<br/>' in title:
\r
202 idx = title.index('<br/>')
\r
203 title = title[:idx]
\r
204 if '<br />' in title:
\r
205 idx = title.index('<br />')
\r
206 title = title[:idx]
\r
207 title = decode2(decode(title)).encode("UTF-8")
\r
209 # Lese Thumbnail-URL...
\r
210 reonecat = re.compile(r'<img src="(.+?)"', re.DOTALL)
\r
211 thumbnails = reonecat.findall(div)
\r
212 if len(thumbnails):
\r
213 list.append(thumbnails[0])
\r
214 # Lese Beitragsanzahl...
\r
215 reonecat = re.compile(r'">(.+?)BEITRÄGE ZUR SENDUNG</a></p>', re.DOTALL)
\r
216 counts = reonecat.findall(div)
\r
218 count = getCounts(counts)
\r
219 list.append("%sBeitraege"%count)
\r
221 reonecat = re.compile(r'">(.+?)BEITRÄGE ZUM THEMA</a></p>', re.DOTALL)
\r
222 counts = reonecat.findall(div)
\r
224 count = getCounts(counts)
\r
225 list.append("%sBeitraege"%count)
\r
227 reonecat = re.compile(r'">(.+?)BEITRÄGE ZUR RUBRIK</a></p>', re.DOTALL)
\r
228 counts = reonecat.findall(div)
\r
230 count = getCounts(counts)
\r
231 list.append("%sBeitraege"%count)
\r
233 reonecat = re.compile(r'">(.+?)BEITRÄGE</a></p>', re.DOTALL)
\r
234 counts = reonecat.findall(div)
\r
236 count = getCounts(counts)
\r
237 list.append("%sBeitraege"%count)
\r
244 ###################################################
\r
246 def getMovieUrl(url):
\r
247 req = Request(url, None, std_headers)
\r
249 txt = urlopen2(req).read()
\r
250 except (URLError, HTTPException, error), err:
\r
251 print "[ZDFMediaThek] Error: Unable to retrieve videopage - Error code: ", str(err)
\r
254 if ('rtsp' in txt) and ('.mp4' in txt):
\r
255 idx = txt.index('rtsp')
\r
256 idx2 = txt.index('.mp4')
\r
257 return txt[idx:idx2+4]
\r
258 if ('rtsp' in txt) and ('.sdp' in txt):
\r
259 idx = txt.index('rtsp')
\r
260 idx2 = txt.index('.sdp')
\r
261 return txt[idx:idx2+4]
\r
262 elif ('mms' in txt) and ('.wmv' in txt):
\r
263 idx = txt.index('mms')
\r
264 idx2 = txt.index('.wmv')
\r
265 return txt[idx:idx2+4]
\r
266 elif ('http' in txt) and ('.asx?' in txt):
\r
267 idx = txt.index('http')
\r
268 idx2 = txt.index('.asx?')
\r
269 return txt[idx:idx2+4]
\r
270 elif ('mms' in txt) and ('reflector:' in txt):
\r
271 idx = txt.index('mms')
\r
272 idx2 = txt.index('" />')
\r
273 return txt[idx:idx2]
\r
277 def getTitleLinks(html):
\r
279 start = '<div id="breadcrumbContainer">'
\r
282 idx = html.index(start)
\r
284 idx = html.index(end)
\r
286 reonecat = re.compile(r'<a href="(.+?)">(.+?)</a>', re.DOTALL)
\r
287 for url, name in reonecat.findall(html):
\r
288 name = decode2(decode(name)).encode("UTF-8")
\r
289 links.append([url, name])
\r
292 def getLeftMenu(html):
\r
294 reonecat = re.compile(r'<div id="navigationContainer">(.+?)</div>', re.DOTALL)
\r
295 leftMenu = reonecat.findall(html)
\r
297 reonecat = re.compile(r'<li><a href="(.+?)"(.+?)</a>', re.DOTALL)
\r
298 for url, name in reonecat.findall(leftMenu[0]):
\r
299 if name.startswith(' class="active">'):
\r
305 if (name != "Hilfe") and (not 'Podcasts' in name): # TODO: Podcasts brauchen noch etwas Arbeit... derzeit deaktiviert
\r
306 list.append([url, name, active])
\r
309 def getRightMenu(html):
\r
311 print "# Suche Filme..."
\r
312 if '" class="play" target="_blank">Abspielen</a></li>' in html:
\r
313 reonecat = re.compile(r'<li>(.+?) <a href="(.+?)" class="play" target="_blank">Abspielen</a></li>', re.DOTALL)
\r
314 for speed, movie in reonecat.findall(html):
\r
315 list.append([speed, movie])
\r
317 return [TYPE_MOVIE, list]
\r
318 print "# Suche podcasts..."
\r
319 if '<!-- Start:Podcasts -->' in html:
\r
320 reonecat = re.compile(r'<!-- Start:Podcasts -->(.+?)<!-- Ende:Podcasts -->', re.DOTALL)
\r
321 tmp = reonecat.findall(html)
\r
323 reonecat = re.compile(r'<p><b><a href="(.+?)".+?">(.+?)</a></b></p>', re.DOTALL)
\r
324 podcasts = reonecat.findall(tmp[0])
\r
325 for podcast in podcasts:
\r
326 list.append([podcast[0], podcast[1]])
\r
328 return [TYPE_PODCAST, list]
\r
329 print "# Suche Videos und Rubriken..."
\r
330 start = '<div class="beitragListe">'
\r
331 if '<div class="beitragFooterSuche">' in html:
\r
332 end = '<div class="beitragFooterSuche">'
\r
334 end = '<div class="beitragFooter">'
\r
335 if (start in html) and (end in html):
\r
336 while (start in html) and (end in html):
\r
337 idx = html.index(start)
\r
339 reonecat = re.compile(r'%s(.+?)%s'%(start, end), re.DOTALL)
\r
340 blocks = reonecat.findall(html)
\r
342 reonecat = re.compile(r'<div class="image">(.+?)</li>', re.DOTALL)
\r
343 divs = reonecat.findall(blocks[0])
\r
346 if ('VIDEO, ' in div) or ('>LIVE<' in div):
\r
347 details = getMovieDetails(div)
\r
348 elif 'BEITRÄGE' in div:
\r
349 details = getCategoryDetails(div)
\r
351 list.append([details[0], details[1], details[2], details[3], details[4]])
\r
353 reonecat = re.compile(r'<a href="(.+?)" class="weitereBeitraege"', re.DOTALL)
\r
354 more = reonecat.findall(html)
\r
357 if 'href="' in more:
\r
358 while 'href="' in more:
\r
359 idx = more.index('href="')
\r
360 more = more[idx+6:]
\r
361 list.append([more, "", "", "", "Weitere Beitraege laden."])
\r
363 return [TYPE_MOVIELIST_CATEGORY, list]
\r
365 return [TYPE_NOTHING, list]
\r
367 ###################################################
\r
369 class LeftMenuList(MenuList):
\r
370 def __init__(self):
\r
371 MenuList.__init__(self, [], False, eListboxPythonMultiContent)
\r
372 self.l.setItemHeight(20)
\r
373 self.l.setFont(0, gFont("Regular", 18))
\r
378 def setActive(self, active):
\r
379 self.active = active
\r
380 self.SetList(self.menu, True)
\r
382 def entry(self, text, active, selected):
\r
384 if text.startswith("- Heute"):
\r
386 elif text.startswith("- Gestern"):
\r
388 elif text.startswith("- Morgen"):
\r
391 res.append(MultiContentEntryPixmapAlphaTest(pos=(0, 0), size=(20, 20), png=LoadPixmap(cached=True, path=PNG_PATH+"active.png")))
\r
393 res.append(MultiContentEntryText(pos=(25, 0), size=(175, 20), font=0, text=text, color=0xf47d19))
\r
395 res.append(MultiContentEntryText(pos=(25, 0), size=(175, 20), font=0, text=text, color=0xffffff))
\r
398 def SetList(self, l, moveCursor=False):
\r
410 if (idx == self.current) and self.active:
\r
414 list.append(self.entry(x[1], x[2], selected))
\r
418 def getCurrentUrl(self):
\r
420 return self.menu[self.current][0]
\r
424 def select(self, index):
\r
426 if (index > -1) and (index < len(self.menu)):
\r
427 self.current = index
\r
428 self.SetList(self.menu)
\r
434 self.select(len(self.menu)-1)
\r
436 def previous(self):
\r
438 self.select(self.current-1)
\r
442 self.select(self.current+1)
\r
444 ###################################################
\r
446 def RightMenuEntryPixmap(thumbID, png_cache):
\r
447 png = png_cache.get(thumbID, None)
\r
449 png = png_cache.get("missing", None)
\r
451 png = LoadPixmap(resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/ZDFMediathek/logo.png"))
\r
452 png_cache["missing"] = png
\r
456 class RightMenuList(List):
\r
460 def __init__(self, list = [ ], enableWrapAround=False):
\r
461 List.__init__(self, list, enableWrapAround, item_height = 50 )
\r
462 self.pixmaps_to_load = []
\r
464 self.listCompleted = []
\r
465 self.lastListLength = 0
\r
467 self.callback = None
\r
471 self.ListUpdate = False
\r
473 def setActive(self, active):
\r
474 self.active = active
\r
476 def buildEntries(self):
\r
477 if self.type == TYPE_PODCAST:
\r
479 for x in self.list:
\r
481 if '<br/>' in title:
\r
482 idx = title.index('<br/>')
\r
483 title = title[:idx]
\r
484 title = decode2(decode(title)).encode("UTF-8")
\r
485 res = [(x[0], title)]
\r
486 res.append(MultiContentEntryText(pos=(0, 0), size=(430, 20), font=0, text=title))
\r
491 elif self.type == TYPE_MOVIELIST_CATEGORY:
\r
492 for entry in self.list:
\r
493 if entry[4] != "Weitere Beitraege laden.":
\r
494 self.listCompleted.append(( entry[0],entry[1],entry[2],entry[3],entry[4],entry[3].rsplit("/",1)[1]))
\r
496 self.listCompleted.append(( entry[0],entry[1],entry[2],entry[3],entry[4], None))
\r
498 def buildEntry(self, vurl, txt1, title, turl, txt2, thumbid):
\r
499 #print "[ZDF Mediathek - buildEntry ] --> ", txt1, title, txt2, thumbid
\r
501 if self.png_cache.get(thumbid, None) is None:
\r
502 if thumbid is not None:
\r
503 self.pixmaps_to_load.append(thumbid)
\r
504 self.downloadThumbnail(turl)
\r
506 menupng = RightMenuEntryPixmap(thumbid, self.png_cache)
\r
508 menupng = RightMenuEntryPixmap(thumbid, self.png_cache)
\r
509 return(( vurl, txt1, title, turl, txt2, thumbid, menupng ))
\r
511 def getMovieCategoryIndexByThumbID(self, ThumbID):
\r
513 for entry in self.listCompleted:
\r
514 if entry[5] == ThumbID:
\r
519 def downloadThumbnail(self,thumbUrl):
\r
520 if thumbUrl is not None:
\r
521 thumbID = thumbUrl.rsplit("/",1)[1]
\r
523 if not thumbUrl.startswith("http://"):
\r
524 thumbUrl = "%s%s"%(MAIN_PAGE, thumbUrl)
\r
526 req = urllib2.Request(thumbUrl)
\r
527 url_handle = urllib2.urlopen(req)
\r
528 headers = url_handle.info()
\r
529 contentType = headers.getheader("content-type")
\r
534 if 'image/jpeg' in contentType:
\r
535 thumbFile = "/tmp/" + thumbID + ".jpg"
\r
536 elif 'image/gif' in contentType:
\r
538 # thumbFile = "/tmp/" + thumbID + ".gif"
\r
539 elif 'image/png' in contentType:
\r
540 thumbFile = "/tmp/" + thumbID + ".png"
\r
542 print "[ZDF Mediathek] Unknown thumbnail content-type:", contentType
\r
543 if thumbFile is not None:
\r
544 if (os_path.exists(thumbFile) == True): #already downloaded
\r
545 self.downloadThumbnailCallback(None, thumbFile, thumbID)
\r
547 if self.png_cache.get(thumbID, None) is None:
\r
548 downloadPage(thumbUrl, thumbFile).addCallback(self.downloadThumbnailCallback, thumbFile, thumbID).addErrback(self.downloadThumbnailError, thumbID)
\r
550 self.updateEntry(thumbID, thumbFile)
\r
552 def downloadThumbnailError(self, err, thumbID):
\r
553 self.pixmaps_to_load.remove(thumbID)
\r
554 print "[ZDF Mediathek] downloadThumbnailError:", thumbID, err.getErrorMessage()
\r
556 def downloadThumbnailCallback(self, txt, thumbFile, thumbID):
\r
557 if (os_path.exists( thumbFile) == True):
\r
558 self.pixmaps_to_load.remove(thumbID)
\r
559 sc = AVSwitch().getFramebufferScale()
\r
560 self.picloads[thumbID] = ePicLoad()
\r
561 self.picloads[thumbID].PictureData.get().append(boundFunction(self.finishedThumbnailDecode, thumbID, thumbFile))
\r
562 self.picloads[thumbID].setPara((94, 60, sc[0], sc[1], False, 1, "#00000000"))
\r
563 self.picloads[thumbID].startDecode(thumbFile)
\r
565 def finishedThumbnailDecode(self, thumbID = "", thumbFile = "", picInfo = None):
\r
566 ptr = self.picloads[thumbID].getData()
\r
568 self.png_cache[thumbID] = ptr
\r
569 del self.picloads[thumbID]
\r
570 self.updateEntry(thumbID, thumbFile)
\r
572 def updateEntry(self, thumbID, thumbFile):
\r
573 if (os_path.exists(thumbFile) == True):
\r
574 os_remove(thumbFile)
\r
575 idx = self.getMovieCategoryIndexByThumbID(thumbID)
\r
576 if idx is not None:
\r
577 print "[ZDF Mediathek] updateEntry", thumbID, thumbFile, idx
\r
578 self.entry_changed(idx)
\r
580 def SetList(self, l):
\r
581 if self.ListUpdate:
\r
582 self.lastIndex = self.index
\r
583 self.lastListLength = len(self.list)
\r
586 self.lastListLength = len(l[1])
\r
589 if self.type == TYPE_PODCAST:
\r
590 self.buildEntries()
\r
591 elif self.type == TYPE_MOVIELIST_CATEGORY:
\r
592 del self.listCompleted
\r
593 self.listCompleted = []
\r
595 self.buildEntries()
\r
596 if len(self.listCompleted):
\r
597 if self.ListUpdate:
\r
598 if len(self.list) > self.lastListLength:
\r
599 self.updateList(self.listCompleted)
\r
600 self.setIndex(self.lastIndex)
\r
602 self.setBuildFunc(self.buildEntry)
\r
603 self.setList(self.listCompleted)
\r
604 self.ListUpdate = False
\r
606 self.setBuildFunc(self.buildEntry)
\r
607 self.setList(self.listCompleted)
\r
615 ###################################################
\r
617 class ZDFMediathekCache(Screen):
\r
619 <screen position="center,center" size="76,76" flags="wfNoBorder" backgroundColor="#ffffff" >
\r
620 <eLabel position="2,2" zPosition="1" size="72,72" font="Regular;18" backgroundColor="#252525" />
\r
621 <widget name="spinner" position="14,14" zPosition="2" size="48,48" alphatest="on" />
\r
624 def __init__(self, session):
\r
625 self.session = session
\r
626 Screen.__init__(self, session)
\r
628 self["spinner"] = Pixmap()
\r
631 self.timer = eTimer()
\r
632 self.timer.callback.append(self.showNextSpinner)
\r
636 self.timer.start(200, False)
\r
642 def showNextSpinner(self):
\r
646 png = LoadPixmap(cached=True, path=PNG_PATH + str(self.curr) + ".png")
\r
647 self["spinner"].instance.setPixmap(png)
\r
649 ###################################################
\r
654 TYPE_MOVIELIST_CATEGORY = 3
\r
660 class ZDFMediathek(Screen, HelpableScreen):
\r
661 desktop = getDesktop(0)
\r
662 size = desktop.size()
\r
663 width = size.width()
\r
665 skin = """<screen name="ZDFMediathek" position="0,0" size="720,576" title="ZDF Mediathek" flags="wfNoBorder" backgroundColor="#252525" >
\r
666 <ePixmap position="20,30" size="133,40" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/ZDFMediathek/logo.png" />
\r
667 <widget name="navigationTitle" position="250,40" size="430,25" font="Regular;18" backgroundColor="#252525" foregroundColor="#f47d19" noWrap="1" />
\r
668 <widget name="leftList" position="20,70" size="220,440" transparent="1" selectionDisabled="1" />
\r
669 <widget source="rightList" render="Listbox" position="250,70" size="430,480" backgroundColor="#3d3c3c" backgroundColorSelected="#565656" scrollbarMode="showOnDemand">
\r
670 <convert type="TemplatedMultiContent">
\r
673 MultiContentEntryPixmapAlphaTest(pos = (0,0), size = (94,60), png = 6),
\r
674 MultiContentEntryText(pos = (100, 0), size = (430, 20), font = 0, text = 2),
\r
675 MultiContentEntryText(pos = (100, 20), size = (430, 20), font = 0, text = 4),
\r
676 MultiContentEntryText(pos = (100, 40), size = (430, 20), font = 1, text = 1),
\r
679 "fonts": [gFont("Regular", 20), gFont("Regular", 18)],
\r
684 <ePixmap pixmap="skin_default/buttons/key_menu.png" position="20,520" size="35,25" transparent="1" alphatest="on" />
\r
685 <widget name="serverName" position="60,520" size="160,20" font="Regular;18" backgroundColor="#252525" foregroundColor="#f47d19" />
\r
686 <widget name="fakeList" position="0,0" size="0,0" />
\r
689 skin = """<screen name="ZDFMediathek" position="center,center" size="900,580" title="ZDF Mediathek" backgroundColor="#252525" >
\r
690 <ePixmap position="20,30" size="133,40" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/ZDFMediathek/logo.png" />
\r
691 <widget name="navigationTitle" position="250,40" size="430,25" font="Regular;18" backgroundColor="#252525" foregroundColor="#f47d19" noWrap="1" />
\r
692 <widget name="leftList" position="20,70" size="220,440" transparent="1" selectionDisabled="1" />
\r
693 <widget source="rightList" render="Listbox" position="250,70" size="600,496" backgroundColor="#3d3c3c" backgroundColorSelected="#565656" scrollbarMode="showOnDemand">
\r
694 <convert type="TemplatedMultiContent">
\r
697 MultiContentEntryPixmapAlphaTest(pos = (2,1), size = (94,60), png = 6),
\r
698 MultiContentEntryText(pos = (100, 0), size = (500, 20), font = 0, text = 2),
\r
699 MultiContentEntryText(pos = (100, 20), size = (500, 20), font = 0, text = 4),
\r
700 MultiContentEntryText(pos = (100, 40), size = (500, 20), font = 1, text = 1),
\r
703 "fonts": [gFont("Regular", 20), gFont("Regular", 18)],
\r
708 <ePixmap pixmap="skin_default/buttons/key_menu.png" position="20,540" size="35,25" transparent="1" alphatest="on" />
\r
709 <widget name="serverName" position="60,540" size="160,20" font="Regular;18" backgroundColor="#252525" foregroundColor="#f47d19" />
\r
710 <widget name="fakeList" position="0,0" size="0,0" />
\r
713 def __init__(self, session):
\r
714 self.session = session
\r
716 Screen.__init__(self, session)
\r
718 self["navigationTitle"] = Label(" ")
\r
719 self["leftList"] = LeftMenuList()
\r
720 self["rightList"] = RightMenuList()
\r
721 self["fakeList"] = MenuList([])
\r
722 self["serverName"] = Label("Server")
\r
724 HelpableScreen.__init__(self)
\r
726 self["actions"] = HelpableActionMap(self, "ZDFMediathekActions",
\r
728 "back": (self.exit, "Beenden"),
\r
729 "ok": (self.ok, "Selektieren"),
\r
730 "left": (self.left, "Seite hoch"),
\r
731 "right": (self.right, "Seite runter"),
\r
732 "up": (self.up, "Hoch"),
\r
733 "down": (self.down, "Runter"),
\r
734 "previousList": (self.toggleList, "Liste umschalten"),
\r
735 "nextList": (self.toggleList, "Liste umschalten"),
\r
736 "menu": (self.selectServer, "Selektiere Server"),
\r
737 "search": (self.search, "Suche"),
\r
738 "previousPage": (self.previousPage, "Vorherige Seite")
\r
741 self.cacheDialog = self.session.instantiateDialog(ZDFMediathekCache)
\r
742 self["rightList"].callback = self.deactivateCacheDialog
\r
743 self.working = False
\r
744 self.currentList = LIST_RIGHT
\r
745 self.linkPreviousPage = ""
\r
747 self.transcodeServer = None
\r
748 self.cacheTimer = eTimer()
\r
749 self.cacheTimer.callback.append(self.chechCachedFile)
\r
751 self.onLayoutFinish.append(self.getPage)
\r
752 self.onClose.append(self.__onClose)
\r
754 def __onClose(self):
\r
755 del self.cacheTimer
\r
756 self["rightList"].png_cache = {}
\r
758 def getPage(self, page=None):
\r
759 self.working = True
\r
761 page = "/ZDFmediathek/hauptnavigation/startseite?flash=off"
\r
762 url = "%s%s"%(MAIN_PAGE, page)
\r
763 getPage(url).addCallback(self.gotPage).addErrback(self.error)
\r
765 def error(self, err=""):
\r
766 print "[ZDF Mediathek] Error:", err
\r
767 self.working = False
\r
768 self.deactivateCacheDialog()
\r
770 def gotPage(self, html=""):
\r
771 rightMenu = getRightMenu(html)
\r
772 if rightMenu[0] == TYPE_MOVIE:
\r
774 for x in rightMenu[1]:
\r
776 if x[1].endswith(".asx"):
\r
778 x[0] = x[0].split("<li>")[-1]
\r
779 tmplist.append(("%s %s"%(x[0], x[1].split(".")[-1]), x[1]))
\r
780 if x[1].endswith(".mov"):
\r
783 if x[1].endswith(".asx"):
\r
785 tmplist.append(("%s %s"%(x[0], x[1].split(".")[-1]), x[1]))
\r
787 if len(tmplist) == 1: #only one entry, play directly.
\r
788 self.play(tmplist[0])
\r
792 if "DSL 2000" in x[0]:
\r
797 self.session.openWithCallback(self.play, ChoiceBox, title="Selektiere...", list=tmplist)
\r
799 self.working = False
\r
801 self.cacheDialog.start()
\r
802 self.currentList = LIST_NONE
\r
803 links = getTitleLinks(html)
\r
806 txt = txt + x[1] + " / "
\r
809 if (len(links) > 1):
\r
810 self.linkPreviousPage = links[-2][0]
\r
812 self.linkPreviousPage = ""
\r
814 self.linkPreviousPage = ""
\r
815 self["navigationTitle"].setText(txt)
\r
816 self["leftList"].SetList(getLeftMenu(html), True)
\r
817 self["rightList"].SetList(rightMenu)
\r
818 self["leftList"].selectionEnabled(0)
\r
819 self["rightList"].setSelectionEnabled(1)
\r
820 self["rightList"].setActive(True)
\r
821 self["fakeList"].selectionEnabled(0)
\r
822 self["leftList"].setActive(False)
\r
824 def previousPage(self):
\r
825 self.getPage(self.linkPreviousPage)
\r
828 self.session.openWithCallback(self.searchCallback, VirtualKeyBoard, title="Suche nach:")
\r
830 def searchCallback(self, callback):
\r
831 if callback and (callback != ""):
\r
832 self.getPage("/ZDFmediathek/suche?sucheText=%s&offset=0&flash=off"%(callback.replace(" ", "+")))
\r
834 def play(self, callback):
\r
835 self.working = False
\r
836 if callback is not None:
\r
838 if url.endswith(".mov") or url.endswith(".asx"):
\r
839 url = getMovieUrl(url)
\r
840 if url and url.endswith(".asx"):
\r
841 newurl = getMovieUrl(url)
\r
844 print "[ZDFMediathek]->PLAY:",url
\r
846 if PLAY_MP4 and url.endswith(".mp4"):
\r
847 ref = eServiceReference(4097, 0, url)
\r
848 self.session.open(ChangedMoviePlayer, ref)
\r
849 elif PLAY_MP4 and url.startswith("rtsp") and url.endswith(".sdp"):
\r
850 ref = eServiceReference(4097, 0, url)
\r
851 self.session.open(ChangedMoviePlayer, ref)
\r
852 elif PLAY_WMV and url.endswith(".wmv"):
\r
853 ref = eServiceReference(4097, 0, url)
\r
854 self.session.open(ChangedMoviePlayer, ref)
\r
855 elif PLAY_WMV and url.startswith("mms") and "reflector:" in url:
\r
856 ref = eServiceReference(4097, 0, url)
\r
857 self.session.open(ChangedMoviePlayer, ref)
\r
858 else: # Die Hardware kann das Format nicht direkt abspielen, mit Stream2Dream oder vlc Server probieren...
\r
859 if self.transcodeServer is not None:
\r
860 if self.transcodeServer == "LT Stream2Dream":
\r
861 r = streamplayer.play(url)
\r
864 self.currentList = LIST_NONE
\r
865 self.cacheDialog.start()
\r
866 self.cacheTimer.start(1000, False)
\r
868 self.transcodeServer.play(self.session, url, self["rightList"].getCurrent()[1])
\r
870 self.session.open(MessageBox, "Es wurde kein Server ausgewählt!", MessageBox.TYPE_ERROR)
\r
872 self.session.open(MessageBox, "Fehler beim Ermitteln der Film-URL!", MessageBox.TYPE_ERROR)
\r
874 def chechCachedFile(self):
\r
876 f = open ("/tmp/mpstream/progress.txt")
\r
879 list = content.split("-")
\r
880 cacheMB = int(list[0])
\r
881 if cacheMB > 10: # Starte nach 10 MB Bufferung
\r
882 self.cacheTimer.stop()
\r
883 self.playCachedFile()
\r
887 def deactivateCacheDialog(self):
\r
888 self.cacheDialog.stop()
\r
889 self.currentList = LIST_RIGHT
\r
890 self.working = False
\r
892 def playCachedFile(self):
\r
893 self.deactivateCacheDialog()
\r
894 ref = eServiceReference(1, 0, "/tmp/mpstream/MPStream.ts")
\r
895 self.session.openWithCallback(self.stopStream2Dream, ChangedMoviePlayer, ref)
\r
897 def stopStream2Dream(self, callback=None):
\r
898 streamplayer.stop()
\r
901 def toggleList(self):
\r
902 if not self.working:
\r
903 if self.currentList == LIST_LEFT:
\r
904 self.currentList = LIST_RIGHT
\r
905 self["leftList"].setActive(False)
\r
906 self["fakeList"].selectionEnabled(0)
\r
907 self["rightList"].setSelectionEnabled(1)
\r
908 self["rightList"].setActive(True)
\r
909 self["rightList"].ListUpdate = False
\r
910 elif self.currentList == LIST_RIGHT:
\r
911 self.currentList = LIST_LEFT
\r
912 self["leftList"].setActive(True)
\r
913 self["rightList"].setSelectionEnabled(0)
\r
914 self["rightList"].setActive(False)
\r
915 self["rightList"].ListUpdate = False
\r
916 self["fakeList"].selectionEnabled(1)
\r
918 def selectServer(self):
\r
921 list.append(("LT Stream2Dream", "LT Stream2Dream"))
\r
922 if vlcServerConfig:
\r
923 serverList = vlcServerConfig.getServerlist()
\r
924 for x in serverList:
\r
925 list.append((x.getName(), x))
\r
927 self.session.openWithCallback(self.serverChosen, ChoiceBox, title="Waehle den Server...", list=list)
\r
929 def serverChosen(self, callback):
\r
931 server = callback[1]
\r
932 if server == "LT Stream2Dream":
\r
933 if not streamplayer.connected:
\r
934 self.transcodeServer = "LT Stream2Dream"
\r
935 self["serverName"].setText("LT Stream2Dream")
\r
936 self.connectToStream2Dream()
\r
939 if streamplayer.connected:
\r
940 streamplayer.logout()
\r
941 self.transcodeServer = server
\r
942 self["serverName"].setText(server.getName())
\r
944 def connectToStream2Dream(self):
\r
945 streamplayer.login()
\r
947 list = listdir("/tmp/mp")
\r
951 self.session.open(MessageBox, "Die Verbindung zu LT Stream2Dream konnte nicht hergestellt werden!", MessageBox.TYPE_ERROR)
\r
952 streamplayer.logout()
\r
953 self.transcodeServer = None
\r
954 self["serverName"].setText("Server")
\r
957 if not self.working:
\r
958 if self.currentList == LIST_LEFT:
\r
960 elif self.currentList == LIST_RIGHT:
\r
962 if streamplayer.connected:
\r
963 streamplayer.logout()
\r
964 self.session.deleteDialog(self.cacheDialog)
\r
968 if streamplayer.connected:
\r
969 streamplayer.stop()
\r
971 self.deactivateCacheDialog()
\r
974 if not self.working:
\r
975 if self.currentList == LIST_LEFT:
\r
976 self.getPage(self["leftList"].getCurrentUrl())
\r
977 elif self.currentList == LIST_RIGHT:
\r
978 curr = self["rightList"].getCurrent()
\r
980 if curr[4] == "Weitere Beitraege laden.":
\r
981 self["rightList"].ListUpdate = True
\r
983 self["rightList"].ListUpdate = False
\r
984 self.getPage(curr[0])
\r
986 if streamplayer.connected:
\r
987 if streamplayer.caching or streamplayer.streaming:
\r
988 self.playCachedFile()
\r
991 if not self.working:
\r
992 if self.currentList == LIST_LEFT:
\r
993 self["leftList"].first()
\r
994 elif self.currentList == LIST_RIGHT and self["rightList"].active:
\r
995 self["rightList"].pageUp()
\r
998 if not self.working:
\r
999 if self.currentList == LIST_LEFT:
\r
1000 self["leftList"].last()
\r
1001 elif self.currentList == LIST_RIGHT and self["rightList"].active:
\r
1002 self["rightList"].pageDown()
\r
1005 if not self.working:
\r
1006 if self.currentList == LIST_LEFT:
\r
1007 self["leftList"].previous()
\r
1008 elif self.currentList == LIST_RIGHT and self["rightList"].active:
\r
1009 self["rightList"].selectPrevious()
\r
1012 if not self.working:
\r
1013 if self.currentList == LIST_LEFT:
\r
1014 self["leftList"].next()
\r
1015 elif self.currentList == LIST_RIGHT and self["rightList"].active:
\r
1016 self["rightList"].selectNext()
\r
1018 ###################################################
\r
1020 def start(session, **kwargs):
\r
1021 session.open(ZDFMediathek)
\r
1023 def Plugins(**kwargs):
\r
1024 return PluginDescriptor(name="ZDF Mediathek", description="Streame von der ZDF Mediathek", where=[PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_PLUGINMENU], fnc=start)
\r