1 # -*- coding: UTF-8 -*-
2 # ARD 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
17 from time import sleep
18 from Tools.BoundFunction import boundFunction
19 from Tools.Directories import resolveFilename, SCOPE_PLUGINS
20 from Tools.LoadPixmap import LoadPixmap
\r
21 from twisted.web.client import downloadPage, getPage
\r
24 ###################################################
26 MAIN_PAGE = "http://www.ardmediathek.de"
28 PNG_PATH = resolveFilename(SCOPE_PLUGINS)+"/Extensions/ARDMediathek/"
31 from LT.LTStreamPlayer import streamplayer
34 from Plugins.Extensions.LTMediaCenter.LTStreamPlayer import streamplayer
39 from Plugins.Extensions.VlcPlayer.VlcServerConfig import vlcServerConfig
41 vlcServerConfig = None
43 ###################################################
46 html = html.replace("&", "&")
47 html = html.replace("<", "<")
48 html = html.replace(">", ">")
49 html = html.replace("'", "'")
50 html = html.replace(""", '"')
51 html = html.replace("*", "*")
52 html = html.replace("|", "|")
53 html = html.replace(""", '"')
54 html = html.replace("'", "'")
57 ###################################################
59 class ChangedMoviePlayer(MoviePlayer):
60 def __init__(self, session, service):
61 MoviePlayer.__init__(self, session, service)
62 self.skinName = "MoviePlayer"
64 def leavePlayer(self):
65 self.session.openWithCallback(self.leavePlayerConfirmed, MessageBox, "Abspielen beenden?")
67 def leavePlayerConfirmed(self, answer):
71 def doEofInternal(self, playing):
74 def getPluginList(self):
76 for p in plugins.getPlugins(where=PluginDescriptor.WHERE_EXTENSIONSMENU):
77 if p.name != "ARD Mediathek":
78 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
84 ###################################################
86 def getCategories(html):
88 start = """<div class="mt-reset mt-categories">"""
90 if start and end in html:
91 idx = html.index(start)
95 reonecat = re.compile(r'<li><a href="(.+?)" title="">(.+?)</a></li>', re.DOTALL)
96 for url, name in reonecat.findall(html):
97 list.append([MAIN_PAGE + url, encodeHtml(name)])
102 start = '<li class="zelle'
104 if (start in html) and (end in html):
105 while (start in html) and (end in html):
106 idx = html.index(start)
108 idx = html.index(end)
111 reonecat = re.compile(r'<img src="(.+?)"', re.DOTALL)
112 thumbs = reonecat.findall(div)
114 thumb = MAIN_PAGE + thumbs[0]
115 if thumb.endswith("drop.jpg") and len(thumbs) > 1:
116 thumb = MAIN_PAGE + thumbs[1]
119 reonecat = re.compile(r'<a href="(.+?)"', re.DOTALL)
120 urls = reonecat.findall(div)
122 url = MAIN_PAGE + urls[0]
125 reonecat = re.compile(r'<span class="beitragstitel"><strong>(.+?)</strong></span>', re.DOTALL)
126 titles = reonecat.findall(div)
128 title = encodeHtml(titles[0])
131 reonecat = re.compile(r'<span class="infotext">(.+?)</span><br />', re.DOTALL)
132 infos = reonecat.findall(div)
134 info = encodeHtml(infos[0])
137 reonecat = re.compile(r'<span class="cliplaenge">(.+?)</span>', re.DOTALL)
138 lengths = reonecat.findall(div)
143 if title and info and length and url and thumb:
144 list.append([title, info, length, url, thumb])
147 def getMovieUrls(url):
149 f = urllib2.urlopen(url)
\r
155 if 'player.avaible_url' in html:
156 content = html.split("\n")
158 if 'player.avaible_url' in line:
159 reonecat = re.compile(r'player.avaible_url(.+?) = "(.+?)";', re.DOTALL)
160 for tmp, url in reonecat.findall(line):
161 if 'flashmedia' in tmp:
163 elif 'microsoftmedia' in tmp:
167 if not url.startswith("rtmpt"):
168 list.append([type, url])
171 def getPageNavigation(html):
173 start = '<!-- ANFANG navigation folge seiten -->'
174 end = '<!-- ENDE navigation folgeseiten -->'
175 if (start in html) and (end in html):
176 idx = html.index(start)
177 idx2 = html.index(end)
178 lines = html[idx:idx2].split("\n")
180 if ('<strong>' in line) and ('</strong>' in line):
181 reonecat = re.compile(r'<strong>(.+?)</strong>', re.DOTALL)
182 pages = reonecat.findall(line)
185 if 'left aktiv' in line:
186 list.append([page, None])
188 reonecat = re.compile(r'<a href="(.+?)"><strong>', re.DOTALL)
189 urls = reonecat.findall(line)
191 list.append([page, urls[0]])
194 ###################################################
196 class ARDMediathekCache(Screen):
198 <screen position="center,center" size="76,76" flags="wfNoBorder" backgroundColor="#ffffff" >
199 <eLabel position="2,2" zPosition="1" size="72,72" font="Regular;18" backgroundColor="#252525" />
200 <widget name="spinner" position="14,14" zPosition="2" size="48,48" alphatest="on" />
203 def __init__(self, session):
204 self.session = session
205 Screen.__init__(self, session)
207 self["spinner"] = Pixmap()
211 self.timer = eTimer()
212 self.timer.callback.append(self.showNextSpinner)
217 self.timer.start(200, False)
227 def showNextSpinner(self):
231 png = LoadPixmap(cached=True, path=PNG_PATH + str(self.curr) + ".png")
232 self["spinner"].instance.setPixmap(png)
234 ###################################################
236 class ARDMenuList(MenuList):
238 MenuList.__init__(self, [], False, eListboxPythonMultiContent)
239 self.l.setItemHeight(25)
240 self.l.setFont(0, gFont("Regular", 20))
242 def ARDMenuListEntry(url, name):
244 res.append(MultiContentEntryText(pos=(0, 0), size=(580, 20), font=0, text=name, color=0xffffff))
247 def ARDMenuListSubEntry(movie, thumb):
248 res = [(movie[3], movie)]
250 res.append(MultiContentEntryPixmapAlphaTest(pos=(0, 0), size=(75, 50), png=thumb))
251 res.append(MultiContentEntryText(pos=(80, 0), size=(500, 25), font=0, text=movie[2] + " - " + movie[0]))
252 res.append(MultiContentEntryText(pos=(80, 25), size=(500, 25), font=0, text=movie[1]))
255 ###################################################
257 class ARDMediathek(Screen):
258 def __init__(self, session):
259 self.session = session
261 desktop = getDesktop(0)
262 size = desktop.size()
266 self.skin = """<screen position="0,0" size="720,576" flags="wfNoBorder" >"""
268 self.skin = """<screen position="center,center" size="720,576" title="ARD Mediathek" >"""
269 self.skin += """<ePixmap position="0,0" zPosition="-1" size="720,576" pixmap="%s" />
270 <widget name="list" position="70,100" size="580,400" backgroundColor="#064b99" backgroundColorSelected="#003579" scrollbarMode="showOnDemand" />
271 <ePixmap pixmap="skin_default/buttons/key_menu.png" position="70,520" size="35,25" transparent="1" alphatest="on" />
272 <widget name="pageNavigation" position="260,520" size="380,400" halign="right" font="Regular;20" backgroundColor="#2666ad" foregroundColor="#ffffff" />
273 <widget name="serverName" position="120,520" size="250,20" font="Regular;20" backgroundColor="#2666ad" foregroundColor="#ffffff" />
274 </screen>""" % (PNG_PATH+"background.png")
276 Screen.__init__(self, session)
278 self["list"] = ARDMenuList()
279 self["pageNavigation"] = Label()
280 self["serverName"] = Label("Server")
282 self["actions"] = ActionMap(["ARDMediathekActions"],
290 "menu": self.selectServer,
291 "mainpage": self.mainpage,
292 "previousPage": self.previousPage,
293 "nextPage": self.nextPage
296 self.cacheDialog = self.session.instantiateDialog(ARDMediathekCache)
301 self.transcodeServer = None
305 self.cacheTimer = eTimer()
306 self.cacheTimer.callback.append(self.chechCachedFile)
308 self.onLayoutFinish.append(self.getPage)
313 def getPage(self, url=None):
315 self.cacheDialog.start()
316 self.mainpage = False
319 url = MAIN_PAGE + "/ard/servlet/"
320 getPage(url).addCallback(self.gotPage).addErrback(self.error)
322 def error(self, err=""):
323 print "[ARD Mediathek] Error:", err
325 self.deactivateCacheDialog()
327 def gotPage(self, html=""):
329 if not self.mainpage:
333 self.movies = getMovies(html)
334 self["list"].l.setItemHeight(50)
335 self.pages = getPageNavigation(html)
337 for page in self.pages:
339 txt = txt + page[0] + " "
341 txt = txt + "|" + page[0] + "| "
342 self["pageNavigation"].setText(txt)
343 self["pageNavigation"].show()
346 categories = getCategories(html)
347 for category in categories:
348 list.append(ARDMenuListEntry(category[0], category[1]))
349 self["list"].l.setItemHeight(25)
350 self["list"].setList(list)
352 self["pageNavigation"].setText("")
353 self["pageNavigation"].hide()
354 self.deactivateCacheDialog()
358 movie = self.movies[0]
361 req = urllib2.Request(thumbUrl)
362 url_handle = urllib2.urlopen(req)
\r
363 headers = url_handle.info()
\r
364 contentType = headers.getheader("content-type")
368 if 'image/jpeg' in contentType:
369 self.thumb = "/tmp/ard.jpg"
370 elif 'image/gif' in contentType:
371 self.thumb = "/tmp/ard.gif"
372 elif 'image/png' in contentType:
373 self.thumb = "/tmp/ard.png"
375 print "[ARD Mediathek] Unknown thumbnail content-type:", contentType
380 downloadPage(thumbUrl, self.thumb).addCallback(self.downloadThumbnailCallback).addErrback(self.downloadThumbnailError)
382 self.buildEntry(None)
384 self["list"].setList(self.listMovies)
385 self.deactivateCacheDialog()
387 def downloadThumbnailError(self, err):
388 print "[ARD Mediathek] Error:", err
389 self.buildEntry(None)
391 def downloadThumbnailCallback(self, txt=""):
392 sc = AVSwitch().getFramebufferScale()
393 self.picload = ePicLoad()
394 self.picload.PictureData.get().append(self.buildEntry)
395 self.picload.setPara((75, 50, sc[0], sc[1], False, 1, "#00000000"))
396 self.picload.startDecode(self.thumb)
398 def buildEntry(self, picInfo=None):
399 movie = self.movies[0]
402 ptr = self.picload.getData()
405 self.listMovies.append(ARDMenuListSubEntry(movie, thumb))
409 def chechCachedFile(self):
411 f = open ("/tmp/mpstream/progress.txt")
414 list = content.split("-")
415 cacheMB = int(list[0])
416 if cacheMB > 5: # Starte nach 5 MB Bufferung
417 self.cacheTimer.stop()
418 self.playCachedFile()
422 def deactivateCacheDialog(self):
423 self.cacheDialog.stop()
426 def playCachedFile(self):
427 self.deactivateCacheDialog()
428 ref = eServiceReference(1, 0, "/tmp/mpstream/MPStream.ts")
429 self.session.openWithCallback(self.stopStream2Dream, ChangedMoviePlayer, ref)
431 def stopStream2Dream(self, callback=None):
435 def selectServer(self):
438 list.append(("LT Stream2Dream", "LT Stream2Dream"))
440 serverList = vlcServerConfig.getServerlist()
442 list.append((x.getName(), x))
444 self.session.openWithCallback(self.serverChosen, ChoiceBox, title="Waehle den Server...", list=list)
446 def serverChosen(self, callback):
449 if server == "LT Stream2Dream":
450 if not streamplayer.connected:
451 self.transcodeServer = "LT Stream2Dream"
452 self["serverName"].setText("LT Stream2Dream")
453 self.connectToStream2Dream()
456 if streamplayer.connected:
457 streamplayer.logout()
458 self.transcodeServer = server
459 self["serverName"].setText(server.getName())
461 def connectToStream2Dream(self):
464 list = listdir("/tmp/mp")
468 self.session.open(MessageBox, "Die Verbindung zu LT Stream2Dream konnte nicht hergestellt werden!", MessageBox.TYPE_ERROR)
469 streamplayer.logout()
470 self.transcodeServer = None
471 self["serverName"].setText("Server")
475 if self.cacheDialog.isShown() == False:
477 if streamplayer.connected:
478 streamplayer.logout()
479 self.session.deleteDialog(self.cacheDialog)
483 if streamplayer.connected:
486 self.deactivateCacheDialog()
490 if self.cacheDialog.isShown() == False:
491 curr = self["list"].getCurrent()
493 if not self.mainpage:
494 movies = getMovieUrls(curr[0][0])
497 list.append((x[0], x[1]))
499 self.session.openWithCallback(self.play, ChoiceBox, title="Selektiere...", list=list)
501 self.getPage(curr[0][0])
504 if streamplayer.connected:
505 if streamplayer.caching or streamclient.streaming:
506 self.playCachedFile()
508 def play(self, callback):
509 if callback is not None:
511 if self.transcodeServer is not None:
512 if self.transcodeServer == "LT Stream2Dream":
513 r = streamplayer.play(url)
516 self.cacheDialog.start()
517 self.cacheTimer.start(1000, False)
519 self.session.open(MessageBox, "LT Stream2Dream konnte den Stream nicht starten!", MessageBox.TYPE_ERROR)
521 self.transcodeServer.play(self.session, url, self["list"].getCurrent()[0][1][1])
523 self.session.open(MessageBox, "Es wurde kein Server ausgewählt!", MessageBox.TYPE_ERROR)
527 self["list"].pageUp()
531 self["list"].pageDown()
541 def removeSessionId(self, url):
543 start = ';jsessionid='
545 idx = url.index(start)
551 return encodeHtml(ret)
553 def previousPage(self):
563 self.getPage(self.removeSessionId(MAIN_PAGE + page[1]))
578 self.getPage(self.removeSessionId(MAIN_PAGE + page[1]))
580 ###################################################
582 def start(session, **kwargs):
583 session.open(ARDMediathek)
585 def Plugins(**kwargs):
586 return PluginDescriptor(name="ARD Mediathek", description="Streame von der ARD Mediathek", where=[PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_PLUGINMENU], fnc=start)