summaryrefslogtreecommitdiff
path: root/plugin.video.mediathek/mediathek
diff options
context:
space:
mode:
authorChristian Kölpin <raptor2101@mykolab.com>2016-12-16 19:22:24 +0100
committerPhilipp Temminghoff <phil65@kodi.tv>2016-12-16 19:22:24 +0100
commit7bafd9290195ce39adc83531d103a4a2a97d5b7b (patch)
tree67ec57f7d5834fe94f25bcf7a57d0674f4230f8e /plugin.video.mediathek/mediathek
parent82884ecc755da2186f1724e54501b4ac73e573b4 (diff)
[plugin.video.mediathek] 0.7.5 (#756)
[plugin.video.mediathek] 0.7.5
Diffstat (limited to 'plugin.video.mediathek/mediathek')
-rw-r--r--plugin.video.mediathek/mediathek/__init__.py134
-rw-r--r--plugin.video.mediathek/mediathek/ard.py168
-rw-r--r--plugin.video.mediathek/mediathek/arte.py262
-rw-r--r--plugin.video.mediathek/mediathek/dreisat.py177
-rw-r--r--plugin.video.mediathek/mediathek/factory.py42
-rw-r--r--plugin.video.mediathek/mediathek/kika.py140
-rw-r--r--plugin.video.mediathek/mediathek/ndr.py274
-rw-r--r--plugin.video.mediathek/mediathek/orf.py162
-rw-r--r--plugin.video.mediathek/mediathek/wdr.py191
-rw-r--r--plugin.video.mediathek/mediathek/zdf.py152
10 files changed, 1702 insertions, 0 deletions
diff --git a/plugin.video.mediathek/mediathek/__init__.py b/plugin.video.mediathek/mediathek/__init__.py
new file mode 100644
index 0000000..b3aedef
--- /dev/null
+++ b/plugin.video.mediathek/mediathek/__init__.py
@@ -0,0 +1,134 @@
+# -*- coding: utf-8 -*-
+#-------------LicenseHeader--------------
+# plugin.video.Mediathek - Gives access to most video-platforms from German public service broadcasters
+# Copyright (C) 2010 Raptor 2101 [raptor2101@gmx.de]
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import sys, urllib2,urllib, time;
+import socket
+socket.setdefaulttimeout(1);
+
+class SimpleLink(object):
+ def __init__(self, basePath, size):
+ self.basePath = basePath;
+ self.size = size;
+
+class ComplexLink(object):
+ def __init__(self, basePath, playPath, size):
+ self.basePath = basePath;
+ self.playPath = playPath;
+ self.size = size;
+
+class TreeNode(object):
+ def __init__(self,path,name,link,displayElements,childNodes = []):
+ self.name = name;
+ self.path = path;
+ self.link = link;
+ self.displayElements = displayElements;
+ self.childNodes = childNodes;
+
+class DisplayObject(object):
+ def __init__(self,title,subTitle,picture,description,link=[],isPlayable = True, date = None, duration = None):
+ self.title = title
+ self.subTitle = subTitle
+ self.link = link
+ self.picture = picture
+ self.isPlayable = isPlayable
+ self.description = description
+ self.date = date;
+ self.duration = duration;
+
+class Mediathek(object):
+ def loadPage(self,url, values = None, maxTimeout = None):
+ try:
+ safe_url = url.replace( " ", "%20" ).replace("&amp;","&")
+
+ if(values is not None):
+ data = urllib.urlencode(values)
+ req = urllib2.Request(safe_url, data)
+ else:
+ req = urllib2.Request(safe_url)
+ req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20100101 Firefox/15.0.1')
+ req.add_header('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8')
+ req.add_header('Accept-Language', 'de-de,de;q=0.8,en-us;q=0.5,en;q=0.3')
+ req.add_header('Accept-Charset', 'utf-8')
+
+ if maxTimeout == None:
+ maxTimeout = 60;
+
+ waittime = 0;
+ doc = False;
+ while not doc and waittime < maxTimeout:
+ try:
+ if waittime > 0:
+ time.sleep(waittime);
+ self.gui.log("download %s %d"%(safe_url,waittime));
+ sock = urllib2.urlopen( req )
+ doc = sock.read();
+ sock.close()
+ except:
+ if(waittime == 0):
+ waittime = 1;
+ else:
+ waittime *= 2;
+
+ if doc:
+ try:
+ return doc.encode('utf-8');
+ except:
+ return doc;
+ else:
+ return ''
+ except:
+ return ''
+
+ def buildMenu(self, path, treeNode = None):
+ if(isinstance(path, (str,unicode))):
+ path = path.split('.');
+ if(len(path) > 0):
+ index = int(path.pop(0));
+
+ if(treeNode == None):
+ treeNode = self.menuTree[index];
+ else:
+ treeNode = treeNode.childNodes[index];
+ self.buildMenu(path,treeNode);
+ else:
+ if(treeNode == None):
+ treeNode = self.menuTree[0];
+ self.gui.log(treeNode.name);
+ for childNode in treeNode.childNodes:
+ self.gui.buildMenuLink(childNode,self, len(treeNode.childNodes));
+ if(treeNode.displayElements):
+ self.buildPageMenu(treeNode.link,len(treeNode.childNodes));
+
+ def displayCategories(self):
+ if(len(self.menuTree)>1 or not self.menuTree[0].displayElements):
+ for treeNode in self.menuTree:
+ self.gui.buildMenuLink(treeNode,self,len(self.menuTree))
+ else:
+ self.buildPageMenu(self.menuTree[0].link, 0);
+
+ def walkJson(self, path, jsonObject):
+ path = path.split('.');
+ i = 0
+ while(i < len(path)):
+ if(isinstance(jsonObject,list)):
+ index = int(path.pop(0));
+ else:
+ index = path.pop(0);
+ jsonObject = jsonObject[index];
+
+ return jsonObject;
+
diff --git a/plugin.video.mediathek/mediathek/ard.py b/plugin.video.mediathek/mediathek/ard.py
new file mode 100644
index 0000000..6c66ce2
--- /dev/null
+++ b/plugin.video.mediathek/mediathek/ard.py
@@ -0,0 +1,168 @@
+# -*- coding: utf-8 -*-
+#-------------LicenseHeader--------------
+# plugin.video.Mediathek - Gives access to most video-platforms from German public service broadcasters
+# Copyright (C) 2010 Raptor 2101 [raptor2101@gmx.de]
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import re, time, datetime;
+from mediathek import *
+
+class ARDMediathek(Mediathek):
+ def __init__(self, simpleXbmcGui):
+ self.gui = simpleXbmcGui;
+ self.rootLink = "http://www.ardmediathek.de"
+ self.menuTree = (
+ TreeNode("0","Neuste Videos",self.rootLink+"/tv/Neueste-Videos/mehr?documentId=21282466",True),
+ TreeNode("1","Sendungen von A-Z","",False,(
+ TreeNode("1.0","0-9",self.rootLink+"/tv/sendungen-a-z?buchstabe=0-9",True),
+ TreeNode("1.1","A",self.rootLink+"/tv/sendungen-a-z?buchstabe=A",True),
+ TreeNode("1.2","B",self.rootLink+"/tv/sendungen-a-z?buchstabe=B",True),
+ TreeNode("1.3","C",self.rootLink+"/tv/sendungen-a-z?buchstabe=C",True),
+ TreeNode("1.4","D",self.rootLink+"/tv/sendungen-a-z?buchstabe=D",True),
+ TreeNode("1.5","E",self.rootLink+"/tv/sendungen-a-z?buchstabe=E",True),
+ TreeNode("1.6","F",self.rootLink+"/tv/sendungen-a-z?buchstabe=F",True),
+ TreeNode("1.7","G",self.rootLink+"/tv/sendungen-a-z?buchstabe=G",True),
+ TreeNode("1.8","H",self.rootLink+"/tv/sendungen-a-z?buchstabe=H",True),
+ TreeNode("1.9","I",self.rootLink+"/tv/sendungen-a-z?buchstabe=I",True),
+ TreeNode("1.10","J",self.rootLink+"/tv/sendungen-a-z?buchstabe=J",True),
+ TreeNode("1.11","K",self.rootLink+"/tv/sendungen-a-z?buchstabe=K",True),
+ TreeNode("1.12","L",self.rootLink+"/tv/sendungen-a-z?buchstabe=L",True),
+ TreeNode("1.13","M",self.rootLink+"/tv/sendungen-a-z?buchstabe=M",True),
+ TreeNode("1.14","N",self.rootLink+"/tv/sendungen-a-z?buchstabe=N",True),
+ TreeNode("1.15","O",self.rootLink+"/tv/sendungen-a-z?buchstabe=O",True),
+ TreeNode("1.16","P",self.rootLink+"/tv/sendungen-a-z?buchstabe=P",True),
+ TreeNode("1.17","Q",self.rootLink+"/tv/sendungen-a-z?buchstabe=Q",True),
+ TreeNode("1.18","R",self.rootLink+"/tv/sendungen-a-z?buchstabe=R",True),
+ TreeNode("1.19","S",self.rootLink+"/tv/sendungen-a-z?buchstabe=S",True),
+ TreeNode("1.20","T",self.rootLink+"/tv/sendungen-a-z?buchstabe=T",True),
+ TreeNode("1.21","U",self.rootLink+"/tv/sendungen-a-z?buchstabe=U",True),
+ TreeNode("1.22","V",self.rootLink+"/tv/sendungen-a-z?buchstabe=V",True),
+ TreeNode("1.23","W",self.rootLink+"/tv/sendungen-a-z?buchstabe=W",True),
+ TreeNode("1.24","X",self.rootLink+"/tv/sendungen-a-z?buchstabe=X",True),
+ TreeNode("1.25","Y",self.rootLink+"/tv/sendungen-a-z?buchstabe=Y",True),
+ TreeNode("1.26","Z",self.rootLink+"/tv/sendungen-a-z?buchstabe=Z",True),
+ )),
+ TreeNode("2","Ausgewählte Dokus".decode("utf-8"),self.rootLink+"/tv/Ausgew%C3%A4hlte-Dokus/mehr?documentId=33649086",True),
+ TreeNode("3","Ausgewählte Filme".decode("utf-8"),self.rootLink+"/tv/Ausgew%C3%A4hlte-Filme/mehr?documentId=33649088",True),
+ TreeNode("4","Alle Reportagen und Dokus",self.rootLink+"/tv/Alle-Dokus-Reportagen/mehr?documentId=29897596",True),
+ TreeNode("5","Alle Filme",self.rootLink+"/tv/Alle-Filme/mehr?documentId=33594630",True),
+ TreeNode("6","Alle Serien",self.rootLink+"/tv/Serien/mehr?documentId=26402940",True),
+ TreeNode("7","Themen",self.rootLink+"/tv/Themen/mehr?documentId=21301810",True),
+ TreeNode("8","Rubriken","",False,(
+ TreeNode("8.0","Kinder",self.rootLink+"/tv/Kinder/Tipps?documentId=21282542",True),
+ TreeNode("8.1","Unterhaltung & Comedy",self.rootLink+"/tv/Unterhaltung-Comedy/mehr?documentId=21282544",True),
+ TreeNode("8.2","Kultur",self.rootLink+"/tv/Kultur/mehr?documentId=21282546",True),
+ TreeNode("8.3","Wissen",self.rootLink+"/tv/Wissen/mehr?documentId=21282530",True),
+ TreeNode("8.4","Politik",self.rootLink+"/tv/Politik/mehr?documentId=29684598",True),
+ TreeNode("8.5","Ratgeber",self.rootLink+"/tv/Ratgeber/mehr?documentId=27112994",True),
+ TreeNode("8.6","Krimi",self.rootLink+"/tv/Krimi/mehr?documentId=27258656",True),
+ TreeNode("8.7","Reise",self.rootLink+"/tv/Reise/mehr?documentId=29769608",True),
+ )),
+ )
+ self.configLink = self.rootLink+"/play/media/%s?devicetype=pc&feature=flash"
+ #.*Video\?bcastId=\d+&amp;documentId=(\d+)\" class=\"textLink\">\s+?<p class=\"dachzeile\">(.*?)</p>\s+?<h4 class=\"headline\">(.*?)</h4>
+ self.regex_VideoPageLink = re.compile("<a href=\".*Video\?.*?documentId=(\d+).*?\" class=\"textLink\">\s+?<p class=\"dachzeile\">(.*?)<\/p>\s+?<h4 class=\"headline\">(.*?)<\/h4>\s+?<p class=\"subtitle\">(?:(\d+.\d+.\d+) \| )?(\d*) Min.")
+ self.regex_CategoryPageLink = re.compile("<a href=\"(.*(?:Sendung|Thema)\?.*?documentId=\d+.*?)\" class=\"textLink\">(?:.|\n)+?<h4 class=\"headline\">(.*?)<\/h4>")
+ self.pageSelectString = "&mcontent%s=page.%s"
+ self.regex_DetermineSelectedPage = re.compile("&mcontents{0,1}=page.(\d+)");
+
+ self.regex_videoLinks = re.compile("\"_quality\":(\d).*?\"_stream\":\[?\"(.*?)\"");
+ self.regex_pictureLink = re.compile("_previewImage\":\"(.*?)\"");
+
+
+ self.regex_Date = re.compile("\\d{2}\\.\\d{2}\\.\\d{2}");
+
+
+ self.replace_html = re.compile("<.*?>");
+
+ @classmethod
+ def name(self):
+ return "ARD";
+ def isSearchable(self):
+ return False;
+
+ def buildPageMenu(self, link, initCount, subLink = False):
+ self.gui.log("Build Page Menu: %s SubLink: %d"%(link,subLink));
+ mainPage = self.loadPage(link);
+
+ elementCount = 0;
+
+ elementCount = self.extractElements(mainPage);
+
+
+ self.generateNextPageElement(link, elementCount);
+ return elementCount;
+ def generateNextPageElement(self, link, elementCount):
+ marker = "";
+ if("Sendung?documentId" in link):
+ marker = "s";
+
+ numberElement = self.regex_DetermineSelectedPage.search(link);
+ if(numberElement is not None):
+ oldNumber = int(numberElement.group(1));
+ newNumber = oldNumber + 1;
+ link = link.replace(self.pageSelectString%(marker,oldNumber),self.pageSelectString%(marker,newNumber));
+
+ self.gui.buildVideoLink(DisplayObject("Weiter","","","",link,False),self,elementCount);
+ else:
+ link += self.pageSelectString%(marker,2)
+
+ self.gui.buildVideoLink(DisplayObject("Weiter","","","",link,False),self,elementCount);
+
+ def extractElements(self,mainPage):
+ videoElements = list(self.regex_VideoPageLink.finditer(mainPage));
+ if len(videoElements) == 0:
+ linkElements = list(self.regex_CategoryPageLink.finditer(mainPage));
+ else:
+ linkElements = []
+
+ counter = len(videoElements) + len(linkElements);
+ for element in linkElements:
+ link = self.rootLink+element.group(1);
+ title = element.group(2).decode('utf-8');
+ # subTitle = element.group(3).decode('utf-8');
+ subTitle = ""
+ self.gui.buildVideoLink(DisplayObject(title,subTitle,"","",link,False),self,counter);
+ for element in videoElements:
+ videoId = element.group(1);
+ title = element.group(2).decode('utf-8');
+ subTitle = element.group(3).decode('utf-8');
+ if element.group(4):
+ datestring = element.group(4).decode('utf-8');
+ date = datetime.date(*[int(x) for x in datestring.split('.')[::-1]]).timetuple()
+ else:
+ date = None
+ durationstring = element.group(5).decode('utf-8');
+ duration = int(durationstring) * 60;
+ self.decodeVideoInformation(videoId, title, subTitle, counter, date, duration);
+ return counter;
+
+ def decodeVideoInformation(self, videoId, title, subTitle, nodeCount, date, duration):
+ link = self.configLink%videoId;
+ self.gui.log("VideoLink: "+link);
+ videoPage = self.loadPage(link);
+ videoLinks = {}
+ for match in self.regex_videoLinks.finditer(videoPage):
+ quality = int(match.group(1));
+ link = SimpleLink(match.group(2),0);
+
+ if(quality > 0):
+ quality -= 1
+ videoLinks[quality] = link
+ match = self.regex_pictureLink.search(videoPage)
+ picture = None
+ if(match is not None):
+ picture = match.group(1);
+ if(len(videoLinks)>0):
+ self.gui.buildVideoLink(DisplayObject(title, subTitle,picture,"",videoLinks,True,date,duration),self,nodeCount);
diff --git a/plugin.video.mediathek/mediathek/arte.py b/plugin.video.mediathek/mediathek/arte.py
new file mode 100644
index 0000000..e0a158d
--- /dev/null
+++ b/plugin.video.mediathek/mediathek/arte.py
@@ -0,0 +1,262 @@
+## -*- coding: utf-8 -*-
+#-------------LicenseHeader--------------
+# plugin.video.Mediathek - Gives access to most video-platforms from German public service broadcasters
+# Copyright (C) 2010 Raptor 2101 [raptor2101@gmx.de]
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import re, traceback, urllib,json;
+from mediathek import *
+from xml.dom import minidom
+from xml.dom import Node;
+from bs4 import BeautifulSoup;
+
+regex_dateString = re.compile("\\d{1,2} ((\\w{3})|(\\d{2})) \\d{4}");
+month_replacements = {
+ "Jan":"01",
+ "Feb":"02",
+ "Mar":"03",
+ "Apr":"04",
+ "May":"05",
+ "Jun":"06",
+ "Jul":"07",
+ "Aug":"08",
+ "Sep":"09",
+ "Oct":"10",
+ "Nov":"11",
+ "Dec":"12",
+ };
+
+class ARTEMediathek(Mediathek):
+ @classmethod
+ def name(self):
+ return "ARTE";
+ @classmethod
+ def isSearchable(self):
+ return False;
+
+ def __init__(self, simpleXbmcGui):
+ self.gui = simpleXbmcGui;
+ self.rootLink = "http://www.arte.tv";
+ self.basePage = self.rootLink+"/guide/de/plus7";
+ self.jsonLink = "https://api.arte.tv/api/player/v1/config/de/%s"
+
+ self.menuTree = (
+ TreeNode("0","Arte+7","mainPage",True),
+ TreeNode("1","Sendungen von A-Z","showCluster",True),
+ TreeNode("2","Kategorien","showCategories",True),
+ );
+
+ self.selector_videoPages = "li.video > a";
+
+ self.regex_VideoPageLinksHTML = re.compile("href=[\"'](http:\\\\/\\\\/www\\.arte\\.tv\\\\/guide\\\\/de\\\\/\d{6}-\d{3}/.+?)[\"']");
+ self.regex_VideoPageLinksJSON = re.compile("\"url\":\"((http:\\\\/\\\\/www\\.arte\\.tv){0,1}\\\\/guide\\\\/de\\\\/\d{6}-\d{3}\\\\/.+?)\"");
+ self.regex_findVideoIds = re.compile("(\d{6}-\d{3})(-A)");
+ self.regex_JSONPageLink = re.compile("http://arte.tv/papi/tvguide/videos/stream/player/D/\d{6}-\d{3}.+?/ALL/ALL.json");
+ self.regex_JSON_VideoLink = re.compile("\"HTTP_MP4_.+?\":{.*?\"bitrate\":(\d+),.*?\"url\":\"(http://.*?.mp4)\".*?\"versionShortLibelle\":\"([a-zA-Z]{2})\".*?}");
+ self.regex_JSON_ImageLink = re.compile("\"IUR\":\"(http://.*?\\.arte\\.tv/papi/tvguide/images/.*?\\..{3})\"");
+ self.regex_JSON_Detail = re.compile("\"VDE\":\"(.*?)\"");
+ self.regex_JSON_Titel = re.compile("\"VTI\":\"(.*?)\"");
+
+ regexSourceString="%s=\"([\[{].*?[}\]])\"";
+ self.regex_cluster=re.compile(regexSourceString%"data-clusters");
+ self.regex_categories = re.compile(regexSourceString%"data-categoriesVideos");
+ self.regex_playlists = re.compile(regexSourceString%"data-highlightedPlaylists");
+
+ self.categories = {
+ "DailyMostViewed":re.compile(regexSourceString%"data-dailyMostViewedVideos"),
+ "Most Viewed": re.compile(regexSourceString%"data-mostViewedVideos"),
+ "ExpiringVideos":re.compile(regexSourceString%"data-nextExpiringVideos"),
+ }
+
+ self.regex_extractVideoSources = (
+ re.compile(regexSourceString%"data-highlightedVideos"),
+ re.compile(regexSourceString%"data-latestVideos"),
+ re.compile(regexSourceString%"data-categoryVideoSet"),
+ );
+
+
+
+
+ def buildPageMenu(self, link, initCount):
+ if(link == "showCluster"):
+ self.showCluster();
+ elif (link == "mainPage"):
+ self.showMainPage();
+ elif (link == "showCategories"):
+ self.showCategories();
+ else:
+ if(not link.startswith("http")):
+ link = self.rootLink+link;
+ pageContent = self.loadPage(link).decode('UTF-8');
+ linkFound = self.extractVideoLinksFromHtml(pageContent)
+ if(not linkFound):
+ self.extractVideoLinks(pageContent,0);
+
+ def buildJsonMenu(self, path,callhash, initCount):
+ jsonContent=self.gui.loadJsonFile(callhash);
+ if(path == "init"):
+ jsonObject = jsonContent;
+ else:
+ jsonObject=self.walkJson(path,jsonContent);
+ self.gui.log(json.dumps(jsonObject));
+ if("videos" in jsonObject):
+ self.extractVideoLinksFromJson(jsonObject);
+ if(isinstance(jsonObject,list)):
+ for counter,jsonObject in enumerate(jsonObject):
+ if("day" in jsonObject):
+ self.gui.buildJsonLink(self,jsonObject["day"],"%d"%counter,callhash,0)
+
+ def buildJsonLink(self,name,content):
+ content = BeautifulSoup(content);
+ jsonContent = json.loads(content.prettify(formatter=None))
+ callhash = self.gui.storeJsonFile(jsonContent,name);
+ self.gui.buildJsonLink(self,name,"init",callhash,0)
+
+ def showMainPage(self):
+ self.gui.log("buildPageMenu: "+self.basePage);
+ pageContent = self.loadPage(self.basePage).decode('UTF-8');
+
+ for name,regex in self.categories.iteritems():
+ match = regex.search(pageContent);
+ if(match is not None):
+ self.buildJsonLink(name,match.group(1));
+
+ self.extractVideoLinksFromHtml(pageContent)
+
+ def extractVideoLinksFromHtml(self, htmlPage):
+ someMatch = False;
+ for regex in self.regex_extractVideoSources:
+ match = regex.search(htmlPage);
+ if(match is not None):
+ someMatch = True;
+ content = BeautifulSoup(match.group(1));
+ jsonContent = json.loads(content.prettify(formatter=None))
+ self.extractVideoLinksFromJson(jsonContent)
+ return someMatch;
+
+
+ def extractVideoLinksFromJson(self,jsonContent):
+ for jsonObject in jsonContent["videos"]:
+ self.buildVideoEntry(jsonObject);
+
+ def showCluster(self):
+ pageContent = self.loadPage(self.basePage).decode('UTF-8');
+ content = BeautifulSoup(self.regex_cluster.search(pageContent).group(1));
+ jsonContent = json.loads(content.prettify(formatter=None))
+ for menuItem in jsonContent:
+ self.buildMenuEntry(menuItem);
+
+ def showCategories(self):
+ pageContent = self.loadPage(self.basePage).decode('UTF-8');
+ content = BeautifulSoup(self.regex_categories.search(pageContent).group(1));
+ jsonContent = json.loads(content.prettify(formatter=None))
+ for jsonObject in jsonContent:
+ jsonCategorie = jsonObject["category"]
+ title = unicode(jsonCategorie["title"]);
+ link=jsonCategorie["url"];
+ self.gui.buildVideoLink(DisplayObject(title,"","","",link,False,None),self,0);
+
+ def buildMenuEntry(self, menuItem):
+ title = menuItem["title"];
+ subTitle = menuItem["subtitle"];
+ link=menuItem["permalink"];
+ self.gui.buildVideoLink(DisplayObject(title,subTitle,"","",link,False,None),self,0);
+
+ def buildVideoEntry(self, jsonObject):
+ title = jsonObject["title"];
+ subTitle = jsonObject["subtitle"];
+ detail = jsonObject["teaser"];
+ picture = None;
+ for pictureItem in jsonObject["thumbnails"]:
+ if(picture is None or picture["width"]<pictureItem["width"]):
+ picture = pictureItem;
+ link=self.jsonLink%jsonObject["id"];
+ self.gui.buildVideoLink(DisplayObject(title,"",picture["url"],detail,link,"JsonLink", None),self,0);
+
+
+ def playVideoFromJsonLink(self,link):
+ jsonObject = json.loads(self.loadPage(link));
+ links = self.extractLinks(jsonObject["videoJsonPlayer"]);
+ self.gui.play(links);
+
+
+ def extractLinks(self,jsonObject):
+ links={};
+
+ vsrObjects = jsonObject["VSR"];
+ if(not isinstance(vsrObjects,dict)):
+ return links;
+
+ for videoObject in jsonObject["VSR"].itervalues():
+ if videoObject["mediaType"] == "mp4":
+ url = videoObject["url"];
+ quality = videoObject["quality"];
+ self.gui.log("%s %s"%(quality,url))
+ if quality == "MQ":
+ links[0] = SimpleLink(url, -1);
+ if quality == "HQ":
+ links[1] = SimpleLink(url, -1);
+ if quality == "EQ":
+ links[2] = SimpleLink(url, -1);
+ if quality == "SQ":
+ links[3] = SimpleLink(url, -1);
+ return links;
+
+ def extractVideoLinks(self, htmlPage, initCount):
+ links = set();
+ jsonLinks = set();
+ for videoPageLink in self.regex_findVideoIds.finditer(htmlPage):
+ link = self.jsonLink%videoPageLink.group(1)
+ self.gui.log(link);
+ if(link not in jsonLinks):
+ jsonLinks.add(link);
+
+ for videoPageLink in self.regex_VideoPageLinksJSON.finditer(htmlPage):
+ link = videoPageLink.group(1).replace("\\/","/");
+ if(link not in links):
+ links.add(link);
+ for link in self.regex_JSONPageLink.finditer(htmlPage):
+ jsonLinks.add(link.group(0));
+ linkCount = initCount + len(links);
+ for link in links:
+ if(not link.startswith(self.rootLink)):
+ videoPage = self.loadPage(self.rootLink+link);
+ else:
+ videoPage = self.loadPage(link);
+ match = self.regex_JSONPageLink.search(videoPage);
+ if(match is not None):
+ jsonLinks.add(match.group(0));
+
+ linkCount = linkCount + len(jsonLinks);
+
+ self.gui.log("Found %s unique links"%len(jsonLinks));
+ for link in jsonLinks:
+ jsonPage = json.loads(self.loadPage(link));
+ self.extractVideoLinksFromJSONPage(jsonPage["videoJsonPlayer"],linkCount)
+
+ def extractVideoLinksFromJSONPage(self, jsonPage, linkCount):
+
+ videoLinks = self.extractLinks (jsonPage);
+ if(len(videoLinks) == 0):
+ return;
+
+ picture = jsonPage["VTU"]["IUR"];
+ title = jsonPage["VTI"];
+
+ subTitle = ""
+ if("subtitle" in jsonPage):
+ subTitle = jsonPage["subtitle"];
+
+
+ self.gui.buildVideoLink(DisplayObject(title,subTitle,picture,"",videoLinks,True, None),self,linkCount);
diff --git a/plugin.video.mediathek/mediathek/dreisat.py b/plugin.video.mediathek/mediathek/dreisat.py
new file mode 100644
index 0000000..615f88d
--- /dev/null
+++ b/plugin.video.mediathek/mediathek/dreisat.py
@@ -0,0 +1,177 @@
+# -*- coding: utf-8 -*-
+#-------------LicenseHeader--------------
+# plugin.video.Mediathek - Gives access to most video-platforms from German public service broadcasters
+# Copyright (C) 2010 Raptor 2101 [raptor2101@gmx.de]
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import re,time
+from mediathek import *
+from xml.dom import minidom;
+
+
+regex_dateString = re.compile("\\d{2} ((\\w{3})|(\\d{2})) \\d{4}");
+month_replacements = {
+ "Jan":"01",
+ "Feb":"02",
+ "Mar":"03",
+ "Apr":"04",
+ "May":"05",
+ "Jun":"06",
+ "Jul":"07",
+ "Aug":"08",
+ "Sep":"09",
+ "Oct":"10",
+ "Nov":"11",
+ "Dec":"12",
+ };
+
+class DreiSatMediathek(Mediathek):
+ @classmethod
+ def name(self):
+ return "3Sat";
+ def isSearchable(self):
+ return True;
+ def __init__(self, simpleXbmcGui):
+ self.gui = simpleXbmcGui;
+ if(self.gui.preferedStreamTyp == 0):
+ self.baseType = "video/x-ms-asf";
+ elif (self.gui.preferedStreamTyp == 1):
+ self.baseType = "video/x-ms-asf"
+ elif (self.gui.preferedStreamTyp == 2):
+ self.baseType ="video/x-ms-asf";
+ else:
+ self.baseType ="video/quicktime";
+ self.webEmType = "video/webm";
+ self.menuTree = (
+ TreeNode("0","Bauerfeind","http://www.3sat.de/mediathek/rss/mediathek_bauerfeind.xml",True),
+ TreeNode("1","Bookmark","http://www.3sat.de/mediathek/rss/mediathek_bookmark.xml",True),
+ TreeNode("2",u"Börse","http://www.3sat.de/mediathek/rss/mediathek_boerse.xml",True),
+ TreeNode("3","Buchzeit","http://www.3sat.de/mediathek/rss/mediathek_buchzeit.xml",True),
+ TreeNode("4","daVinci","http://www.3sat.de/mediathek/rss/mediathek_davinci.xml",True),
+ TreeNode("5","delta","http://www.3sat.de/mediathek/rss/mediathek_delta.xml",True),
+ TreeNode("6","Film","http://www.3sat.de/mediathek/rss/mediathek_film.xml",True),
+ TreeNode("7","Gero von Boehm","http://www.3sat.de/mediathek/rss/mediathek_gero.xml",True),
+ TreeNode("8","hessenreporter","http://www.3sat.de/mediathek/rss/mediathek_hessenreporter.xml",True),
+ TreeNode("9","hitec","http://www.3sat.de/mediathek/rss/mediathek_hitec.xml",True),
+ TreeNode("10","Kabarett","http://www.3sat.de/mediathek/rss/mediathek_kabarett.xml",True),
+ TreeNode("11","Kinomagazin","http://www.3sat.de/mediathek/rss/mediathek_kinomag.xml",True),
+ TreeNode("12","Kulturzeit","http://www.3sat.de/mediathek/rss/mediathek_Kulturzeit.xml",True),
+ TreeNode("13","makro","http://www.3sat.de/mediathek/rss/mediathek_makro.xml",True),
+ TreeNode("14","Musik","http://www.3sat.de/mediathek/rss/mediathek_musik.xml",True),
+ TreeNode("15","nano","http://www.3sat.de/mediathek/rss/mediathek_nano.xml",True),
+ TreeNode("16","neues","http://www.3sat.de/mediathek/rss/mediathek_neues.xml",True),
+ TreeNode("17",u"Peter Voß fragt","http://www.3sat.de/mediathek/rss/mediathek_begegnungen.xml",True),
+ TreeNode("18","Recht brisant","http://www.3sat.de/mediathek/rss/mediathek_Recht%20brisant.xml",True),
+ TreeNode("19","scobel","http://www.3sat.de/mediathek/rss/mediathek_scobel.xml",True),
+ TreeNode("20","SCHWEIZWEIT","http://www.3sat.de/mediathek/rss/mediathek_schweizweit.xml",True),
+ TreeNode("21","Theater","http://www.3sat.de/mediathek/rss/mediathek_theater.xml",True),
+ TreeNode("22","vivo","http://www.3sat.de/mediathek/rss/mediathek_vivo.xml",True),
+ );
+
+ self.rootLink = "http://www.3sat.de"
+ self.searchLink = 'http://www.3sat.de/mediathek/mediathek';
+ link = "/mediathek/mediathek.php\\?obj=\\d+";
+ self.regex_searchResult = re.compile("href=\""+link+"\" class=\"media_result_thumb\"");
+ self.regex_searchResultLink = re.compile(link)
+ self.regex_searchLink = re.compile("http://(w|f)streaming.zdf.de/.*?(\\.asx|\\.smil)")
+ self.regex_searchTitle = re.compile("<h2>.*</h2>");
+ self.regex_searchDetail = re.compile("<span class=\"text\">.*");
+ self.regex_searchDate = re.compile("\\d{2}.\\d{2}.\\d{4}");
+ self.regex_searchImage = re.compile("(/dynamic/mediathek/stills/|/mediaplayer/stills/)\\d*_big\\.jpg");
+ self.replace_html = re.compile("<.*?>");
+
+ def buildPageMenu(self, link, initCount):
+ self.gui.log("buildPageMenu: "+link);
+ rssFeed = self.loadConfigXml(link);
+ self.extractVideoObjects(rssFeed, initCount);
+ def searchVideo(self, searchText):
+ values ={'mode':'search',
+ 'query':searchText,
+ 'red': '',
+ 'query_time': '',
+ 'query_sort': '',
+ 'query_order':''
+ }
+ mainPage = self.loadPage(self.searchLink,values);
+ results = self.regex_searchResult.findall(mainPage);
+ for result in results:
+ objectLink = self.regex_searchResultLink.search(result).group();
+ infoLink = self.rootLink+objectLink
+ infoPage = self.loadPage(infoLink);
+ title = self.regex_searchTitle.search(infoPage).group();
+ detail = self.regex_searchDetail.search(infoPage).group();
+ image = self.regex_searchImage.search(infoPage).group();
+ title = self.replace_html.sub("", title);
+ detail = self.replace_html.sub("", detail);
+ try:
+ dateString = self.regex_searchDate.search(infoPage).group();
+ pubDate = time.strptime(dateString,"%d.%m.%Y");
+ except:
+ pubDate = time.gmtime();
+ videoLink = self.rootLink+objectLink+"&mode=play";
+ videoPage = self.loadPage(videoLink);
+ video = self.regex_searchLink.search(videoPage).group();
+ video = video.replace("fstreaming","wstreaming").replace(".smil",".asx");
+ links = {}
+ links[2] = SimpleLink(video,0)
+ self.gui.buildVideoLink(DisplayObject(title,"",self.rootLink + image,detail,links,True, pubDate),self,len(results));
+ def readText(self,node,textNode):
+ try:
+ node = node.getElementsByTagName(textNode)[0].firstChild;
+ return unicode(node.data);
+ except:
+ return "";
+ def loadConfigXml(self, link):
+ self.gui.log("load:"+link)
+ xmlPage = self.loadPage(link);
+ return minidom.parseString(xmlPage);
+ def extractVideoObjects(self, rssFeed, initCount):
+ nodes = rssFeed.getElementsByTagName("item");
+ nodeCount = initCount + len(nodes)
+ for itemNode in nodes:
+ try:
+ self.extractVideoInformation(itemNode,nodeCount);
+ except:
+ pass
+
+ def parseDate(self,dateString):
+ dateString = regex_dateString.search(dateString).group();
+ for month in month_replacements.keys():
+ dateString = dateString.replace(month,month_replacements[month]);
+ return time.strptime(dateString,"%d %m %Y");
+
+ def extractVideoInformation(self, itemNode, nodeCount):
+ title = self.readText(itemNode,"title");
+ self.gui.log(title)
+ dateString = self.readText(itemNode,"pubDate");
+ pubDate = self.parseDate(dateString);
+ descriptionNode = itemNode.getElementsByTagName("description")[0].firstChild.data;
+ description = unicode(descriptionNode);
+ picture = "";
+ pictureNodes = itemNode.getElementsByTagName("media:thumbnail");
+ if(len(pictureNodes) > 0):
+ picture = pictureNodes[0].getAttribute("url");
+ links = {};
+ for contentNode in itemNode.getElementsByTagName("media:content"):
+ height = int(contentNode.getAttribute("height"));
+ url = contentNode.getAttribute("url");
+ size = int(contentNode.getAttribute("fileSize"));
+ if(height < 300):
+ links[0] = SimpleLink(url, size);
+ elif (height < 480):
+ links[1] = SimpleLink(url, size);
+ else:
+ links[2] = SimpleLink(url, size);
+ if links:
+ self.gui.buildVideoLink(DisplayObject(title,"",picture,description,links,True, pubDate),self,nodeCount);
diff --git a/plugin.video.mediathek/mediathek/factory.py b/plugin.video.mediathek/mediathek/factory.py
new file mode 100644
index 0000000..7bcdb96
--- /dev/null
+++ b/plugin.video.mediathek/mediathek/factory.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+#-------------LicenseHeader--------------
+# plugin.video.Mediathek - Gives access to most video-platforms from German public service broadcasters
+# Copyright (C) 2010 Raptor 2101 [raptor2101@gmx.de]
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from mediathek.wdr import *
+from mediathek.ard import *
+from mediathek.zdf import *
+from mediathek.arte import *
+from mediathek.dreisat import *
+from mediathek.orf import *
+from mediathek.ndr import *
+from mediathek.kika import *
+
+class MediathekFactory(object):
+ def __init__(self):
+ self.avaibleMediathekes = {
+ ARDMediathek.name():ARDMediathek,
+ ZDFMediathek.name():ZDFMediathek,
+ ARTEMediathek.name():ARTEMediathek,
+ DreiSatMediathek.name():DreiSatMediathek,
+ ORFMediathek.name():ORFMediathek,
+ NDRMediathek.name():NDRMediathek,
+ KIKA.name():KIKA
+ }
+ def getAvaibleMediathekTypes(self):
+ return sorted(self.avaibleMediathekes.keys())
+
+ def getMediathek(self,mediathekName, gui):
+ return self.avaibleMediathekes[mediathekName](gui);
diff --git a/plugin.video.mediathek/mediathek/kika.py b/plugin.video.mediathek/mediathek/kika.py
new file mode 100644
index 0000000..238ba9d
--- /dev/null
+++ b/plugin.video.mediathek/mediathek/kika.py
@@ -0,0 +1,140 @@
+# -*- coding: utf-8 -*-
+#-------------LicenseHeader--------------
+# plugin.video.Mediathek - Gives access to most video-platforms from German public service broadcasters
+# Copyright (C) 2010 Raptor 2101 [raptor2101@gmx.de]
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import re, time;
+from bs4 import BeautifulSoup;
+from mediathek import *
+
+class KIKA(Mediathek):
+ def __init__(self, simpleXbmcGui):
+ self.gui = simpleXbmcGui;
+ self.rootLink = "http://www.kika.de";
+ self.menuTree = (
+ TreeNode("0","Videos",self.rootLink+"/videos/index.html",True),
+ TreeNode("1","Sendungen von A-Z","",False,
+ (
+ TreeNode("1.0","A",self.rootLink+"/sendungen/sendungenabisz100_page-A_zc-05fb1331.html",True),
+ TreeNode("1.1","B",self.rootLink+"/sendungen/sendungenabisz100_page-B_zc-1775e6d8.html",True),
+ TreeNode("1.2","C",self.rootLink+"/sendungen/sendungenabisz100_page-C_zc-6248eba0.html",True),
+ TreeNode("1.3","D",self.rootLink+"/sendungen/sendungenabisz100_page-D_zc-e090a8fb.html",True),
+ TreeNode("1.4","E",self.rootLink+"/sendungen/sendungenabisz100_page-E_zc-ec2376ed.html",True),
+ TreeNode("1.5","F",self.rootLink+"/sendungen/sendungenabisz100_page-F_zc-f76734a0.html",True),
+ TreeNode("1.6","G",self.rootLink+"/sendungen/sendungenabisz100_page-G_zc-34bda7c3.html",True),
+ TreeNode("1.7","H",self.rootLink+"/sendungen/sendungenabisz100_page-H_zc-7e25e70a.html",True),
+ TreeNode("1.8","I",self.rootLink+"/sendungen/sendungenabisz100_page-I_zc-b7f774f5.html",True),
+ TreeNode("1.9","J",self.rootLink+"/sendungen/sendungenabisz100_page-J_zc-3130680a.html",True),
+ TreeNode("1.10","K",self.rootLink+"/sendungen/sendungenabisz100_page-K_zc-c8f76ba1.html",True),
+ TreeNode("1.11","L",self.rootLink+"/sendungen/sendungenabisz100_page-L_zc-bbebc1a7.html",True),
+ TreeNode("1.12","M",self.rootLink+"/sendungen/sendungenabisz100_page-M_zc-00574a43.html",True),
+ TreeNode("1.13","N",self.rootLink+"/sendungen/sendungenabisz100_page-N_zc-b079366f.html",True),
+ TreeNode("1.14","O",self.rootLink+"/sendungen/sendungenabisz100_page-O_zc-febc55f5.html",True),
+ TreeNode("1.15","P",self.rootLink+"/sendungen/sendungenabisz100_page-P_zc-2c1a492f.html",True),
+ TreeNode("1.16","Q",self.rootLink+"/sendungen/sendungenabisz100_page-Q_zc-2cb019d6.html",True),
+ TreeNode("1.17","R",self.rootLink+"/sendungen/sendungenabisz100_page-R_zc-cab3e22b.html",True),
+ TreeNode("1.18","S",self.rootLink+"/sendungen/sendungenabisz100_page-S_zc-e7f420d0.html",True),
+ TreeNode("1.19","T",self.rootLink+"/sendungen/sendungenabisz100_page-T_zc-84a2709f.html",True),
+ TreeNode("1.20","U",self.rootLink+"/sendungen/sendungenabisz100_page-U_zc-a26c1157.html",True),
+ TreeNode("1.21","V",self.rootLink+"/sendungen/sendungenabisz100_page-V_zc-1fc26dc3.html",True),
+ TreeNode("1.22","W",self.rootLink+"/sendungen/sendungenabisz100_page-W_zc-25c5c777.html",True),
+ TreeNode("1.23","Y",self.rootLink+"/sendungen/sendungenabisz100_page-Y_zc-388beba7.html",True),
+ TreeNode("1.24","Z",self.rootLink+"/sendungen/sendungenabisz100_page-Z_zc-e744950d.html",True),
+ TreeNode("1.25","...",self.rootLink+"/sendungen/sendungenabisz100_page-1_zc-43c28d56.html",True)
+ )
+ )
+ )
+
+ self.regex_videoLinks=re.compile("<a href=\"(.*?/videos/video\\d+?)\\.html\"");
+ self.regex_configLinks=re.compile("{dataURL:'http://www.kika.de(/.*?-avCustom.xml)'}");
+ self.selector_videoPages = "div.mod > div.box > div.teaser > a.linkAll";
+ self.selector_seriesPages = "div.modCon > div.mod > div.boxCon > div.boxBroadcastSeries > div.teaser > a.linkAll";
+ self.regex_xml_channel=re.compile("<channelName>(.*?)</channelName>");
+ self.regex_xml_title=re.compile("<title>(.*?)</title>");
+ self.regex_xml_image=re.compile("<teaserimage>\\s*?<url>(.*?)</url>");
+ self.regex_xml_videoLink=re.compile("<asset>\\s*?<profileName>(.*?)</profileName>.*?<progressiveDownloadUrl>(.*?)</progressiveDownloadUrl>\\s*?</asset>",re.DOTALL)
+ self.regex_videoLink=re.compile("rtmp://.*?\.mp4");
+ @classmethod
+ def name(self):
+ return "KI.KA";
+
+ def isSearchable(self):
+ return False;
+
+ def searchVideo(self, searchText):
+ return;
+
+ def buildVideoLink(self,pageLink):
+ xmlPage = self.loadPage(self.rootLink+pageLink);
+ channel = self.regex_xml_channel.search(xmlPage);
+ if(channel is not None):
+ channel = unicode(channel.group(1),"UTF-8");
+ title = unicode(self.regex_xml_title.search(xmlPage).group(1),"UTF-8");
+ image = self.regex_xml_image.search(xmlPage).group(1).replace("**aspectRatio**","tlarge169").replace("**width**","1472");
+
+ self.gui.log("%s %s"%(title,image));
+ links = {};
+ for match in self.regex_xml_videoLink.finditer(xmlPage):
+ profile = match.group(1);
+ directLink = match.group(2);
+ self.gui.log("%s %s"%(profile,directLink));
+ if("MP4 Web S" in profile):
+ links[0] = SimpleLink(directLink, 0);
+ if("MP4 Web L" in profile):
+ links[1] = SimpleLink(directLink, 0);
+ if("MP4 Web L+" in profile):
+ links[2] = SimpleLink(directLink, 0);
+ if("MP4 Web XL" in profile):
+ links[3] = SimpleLink(directLink, 0);
+
+ if(channel is not None):
+ return DisplayObject(channel,title,image,"",links,True, None);
+ else:
+ return DisplayObject(title,"",image,"",links,True, None);
+
+ def buildPageMenu(self, link, initCount):
+ pageContent = self.loadPage(link);
+ htmlPage = BeautifulSoup(pageContent, 'html.parser')
+ htmlElements = htmlPage.select(self.selector_videoPages)
+ videoLinks = set()
+
+ for item in htmlElements:
+ link = self.rootLink+item['href'];
+ videoPage = self.loadPage(link);
+ for match in self.regex_videoLinks.finditer(videoPage):
+ link=match.group(1)+"-avCustom.xml";
+ if(link not in videoLinks):
+ videoLinks.add(link)
+ directLinks = list(self.regex_configLinks.finditer(pageContent));
+ for match in directLinks:
+ link = match.group(1);
+ if(link not in videoLinks):
+ videoLinks.add(link)
+ self.gui.log("found %d video links"%len(videoLinks))
+ count = initCount + len(videoLinks)
+ for link in videoLinks:
+ displayObject = self.buildVideoLink(link);
+ self.gui.buildVideoLink(displayObject,self, count);
+ if(len(videoLinks) > 0):
+ return;
+ htmlElements = htmlPage.select(self.selector_seriesPages);
+ count = count + len(htmlElements)
+ self.gui.log("found %d page links"%len(htmlElements))
+ for item in htmlElements:
+ self.gui.log(item.prettify());
+ link = self.rootLink+item['href'];
+ title = item['title'];
+ displayObject = DisplayObject(title,"",None,"",link,False, None);
+ self.gui.buildVideoLink(displayObject,self, count);
diff --git a/plugin.video.mediathek/mediathek/ndr.py b/plugin.video.mediathek/mediathek/ndr.py
new file mode 100644
index 0000000..cbe57df
--- /dev/null
+++ b/plugin.video.mediathek/mediathek/ndr.py
@@ -0,0 +1,274 @@
+# -*- coding: utf-8 -*-
+# -------------LicenseHeader--------------
+# plugin.video.Mediathek - Gives access to most video-platforms from German public service broadcasters
+# Copyright (C) 2010 Raptor 2101 [raptor2101@gmx.de]
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import re
+import datetime
+import time
+import calendar
+from mediathek import *
+from xml.dom import minidom
+
+
+class NDRMediathek(Mediathek):
+ @classmethod
+ def name(self):
+ return "NDR"
+
+ def isSearchable(self):
+ return True
+
+ def __init__(self, simpleXbmcGui):
+ self.gui = simpleXbmcGui
+
+ self.rootLink = "http://www.ndr.de"
+
+ self.searchLink = self.rootLink+"/suche10.html?search_mediathek=1&"
+
+ # Hauptmenue
+ tmp_menu = []
+ extractBroadcasts = re.compile("<a href=\"/mediathek/mediatheksuche105_broadcast-(.*?).html\" class=\"link_arrow\">(.*?)</a>")
+ htmlPage = self.loadPage("http://www.ndr.de/mediathek/sendungen_a-z/index.html").decode('utf-8')
+
+ x = 0
+ for menuNode in extractBroadcasts.finditer(htmlPage):
+ menuId = menuNode.group(1)
+ menuItem = menuNode.group(2)
+ menuLink = self.rootLink+"/mediatheksuche105_broadcast-"+menuId+"_format-video_page-1.html"
+ tmp_menu.append(TreeNode("0."+str(x), menuItem, menuLink, True))
+ x = x+1
+
+ self.menuTree = [
+ TreeNode("0", "Sendungen von A-Z", "", False, tmp_menu),
+ TreeNode("1", "Sendung verpasst?", "sendungverpasst", True),
+ TreeNode("2","Live","livestream",True),#Livestream ruckelt zu stark :-(
+ ]
+
+ def buildPageMenuSendungVerpasst(self, action):
+ htmlPage = self.loadPage("http://www.ndr.de/mediathek/sendung_verpasst/epg1490_display-onlyvideo.html")
+
+ regex_verpasstNow = re.compile(
+ '<h1 class="viewdate">\n.*?(\\d{2})\.(\\d{2})<span class="notbelow30em">\.(\\d{4})</span>'
+ )
+ verpasstNow = ".".join(regex_verpasstNow.search(htmlPage).groups())
+ try:
+ dateTimeTmp = datetime.datetime.strptime(verpasstNow, "%d.%m.%Y")
+ except TypeError:
+ dateTimeTmp = datetime.datetime(*(time.strptime(verpasstNow, "%d.%m.%Y")[0:6]))
+
+ nodeCount = 0
+
+ if action == "":
+ verpasstHeute = dateTimeTmp.strftime("%Y-%m-%d")
+ dateTimeTmp = dateTimeTmp-datetime.timedelta(1)
+ verpasstGestern = dateTimeTmp.strftime("%Y-%m-%d")
+ dateTimeTmp = dateTimeTmp-datetime.timedelta(1)
+ verpasstVorGestern = dateTimeTmp.strftime("%Y-%m-%d")
+
+ self.gui.buildVideoLink(DisplayObject("Heute", "", "", "description", self.rootLink + "/mediathek/sendung_verpasst/epg1490_date-" + verpasstHeute + "_display-onlyvideo.html", False), self, 1)
+ self.gui.buildVideoLink(DisplayObject("Gestern", "", "", "description", self.rootLink + "/mediathek/sendung_verpasst/epg1490_date-" + verpasstGestern + "_display-onlyvideo.html", False), self, 2)
+ self.gui.buildVideoLink(DisplayObject("Vorgestern", "", "", "description", self.rootLink + "/mediathek/sendung_verpasst/epg1490_date-" + verpasstVorGestern + "_display-onlyvideo.html", False), self, 3)
+ self.gui.buildVideoLink(DisplayObject("Datum waehlen", "", "", "description", "sendungverpasstselect", False), self, 4)
+ elif action == "select":
+ dateTimeTmp = dateTimeTmp-datetime.timedelta(3)
+ verpasstStartYear = int(dateTimeTmp.strftime("%Y"))
+ for verpasstStart in reversed(range(1, int(dateTimeTmp.strftime("%m")))):
+ menu_title = str(verpasstStart)+"."+str(verpasstStartYear)
+ menu_action = "sendungverpasstselectmonth" + str(verpasstStartYear) + str(verpasstStart)
+ self.gui.buildVideoLink(DisplayObject(menu_title, "", "", "description", menu_action, False), self, nodeCount)
+ verpasstStart = verpasstStart - 1
+ nodeCount = nodeCount + 1
+
+ while verpasstStartYear > 2008:
+ verpasstStartYear = verpasstStartYear - 1
+ menu_title = str(verpasstStartYear)
+ self.gui.buildVideoLink(DisplayObject(menu_title, "", "", "description", "sendungverpasstselectyear" + str(verpasstStartYear), False), self, nodeCount)
+ elif action[0:11] == "selectmonth":
+ action = action[11:]
+ action_year = action[0:4]
+ action_month = action[4:]
+
+ try:
+ dateTimeTmp2 = datetime.datetime.strptime(action_year+action_month, "%Y%m")
+ except TypeError:
+ dateTimeTmp2 = datetime.datetime(*(time.strptime(action_year+action_month, "%Y%m")[0:6]))
+
+ if dateTimeTmp.strftime("%Y%m") == dateTimeTmp2.strftime("%Y%m"):
+ startDay = int(dateTimeTmp2.strftime("%d"))
+ else:
+ startDay = calendar.monthrange(int(action_year), int(action_month))[1]
+
+ try:
+ dateTimeTmp2 = datetime.datetime.strptime(action_year + action_month + str(startDay), "%Y%m%d")
+ except TypeError:
+ dateTimeTmp2 = datetime.datetime(*(time.strptime(action_year + action_month + str(startDay), "%Y%m%d")[0:6]))
+
+ for i in reversed(range(1, startDay)):
+ verpasstDatum = dateTimeTmp2.strftime("%Y-%m-%d")
+ menu_title = dateTimeTmp2.strftime("%d.%m.%Y")
+ menu_action = self.rootLink + "/mediathek/sendung_verpasst/epg1490_date-" + verpasstDatum + "_display-onlyvideo.html"
+ self.gui.buildVideoLink(DisplayObject(menu_title, "", "", "description", menu_action, False), self, nodeCount)
+ nodeCount = nodeCount + 1
+ dateTimeTmp2 = dateTimeTmp2-datetime.timedelta(1)
+ elif action[0:10] == "selectyear":
+ action = action[10:]
+ action_year = action[0:4]
+ for startMonth in reversed(range(1, 12)):
+ menu_title = str(startMonth) + "." + action_year
+ menu_action = "sendungverpasstselectmonth" + action_year + str(startMonth)
+ self.gui.buildVideoLink(DisplayObject(menu_title, "", "", "description", menu_action, False), self, nodeCount)
+ nodeCount = nodeCount + 1
+
+ def buildPageMenuLivestream(self):
+ nodeCount = 0
+
+ # Hamburg
+ nodeCount = nodeCount+1
+ links = {}
+ links[0] = SimpleLink("http://ndr_fs-lh.akamaihd.net/i/ndrfs_hh@119223/master.m3u8", 0)
+ self.gui.buildVideoLink(DisplayObject("Hamburg", "", "", "", links, True), self, nodeCount)
+
+ # Mecklenburg-Vorpommern
+ nodeCount = nodeCount+1
+ links = {}
+ links[0] = SimpleLink("http://ndr_fs-lh.akamaihd.net/i/ndrfs_mv@119226/master.m3u8", 0)
+ self.gui.buildVideoLink(DisplayObject("Mecklenburg-Vorpommern", "", "", "", links, True), self, nodeCount)
+
+ # Niedersachsen
+ nodeCount = nodeCount+1
+ links = {}
+ links[0] = SimpleLink("http://ndr_fs-lh.akamaihd.net/i/ndrfs_nds@119224/master.m3u8", 0)
+ self.gui.buildVideoLink(DisplayObject("Niedersachsen", "", "", "", links, True), self, nodeCount)
+
+ # Schleswig-Holstein
+ nodeCount = nodeCount+1
+ links = {}
+ links[0] = SimpleLink("http://ndr_fs-lh.akamaihd.net/i/ndrfs_sh@119225/master.m3u8", 0)
+ self.gui.buildVideoLink(DisplayObject("Schleswig-Holstein", "", "", "", links, True), self, nodeCount)
+
+ def buildPageMenuVideoListVerpasst(self, link, initCount):
+ self.gui.log("buildPageMenuVerpasst: " + link)
+
+ htmlPage = self.loadPage(link)
+
+ re_video_item = re.compile(
+ '<div class="videolinks"><a href="(.*?)" title=".*?" class=\'button epgbutton\' >'
+ )
+ # won't parse "Beiträge", they are only cutted parts of the main
+ # program
+ video_items = re.findall(re_video_item, htmlPage)
+ nodeCount = initCount + len(video_items)
+ for video_link in video_items:
+ if not re.compile("http://www.n-joy.de/.*").search(video_link):
+ print video_link
+ self.extractVideoInformation(video_link, None, nodeCount)
+
+
+ def buildPageMenuVideoList(self, link, initCount):
+ self.gui.log("buildPageMenu: " + link)
+
+ htmlPage = self.loadPage(link)
+
+ regex_extractVideoItems = re.compile(
+ "<div class=\"teaserpadding\">"
+ "(.*?)"
+ "(</p>\n</div>\n</div>|\n</div>\n</div>\n</li>)", re.DOTALL)
+ regex_extractVideoItemHref = re.compile("<a title=\".*?\" href=\"(.*?/[^/]*?\.html)\".*?>", re.DOTALL)
+ regex_extractVideoItemDate = re.compile("<div class=\"subline\" style=\"cursor: pointer;\">.*?(\\d{2}\.\\d{2}\.\\d{4} \\d{2}:\\d{2})</div>")
+
+ videoItems = regex_extractVideoItems.findall(htmlPage)
+ nodeCount = initCount + len(videoItems)
+
+ for videoItem in videoItems:
+ print "link: {0}".format(link)
+ print "videoItem: {0}".format(videoItem[0])
+ if "<div class=\"subline\">" not in videoItem[0]:
+ continue
+ videoLink = regex_extractVideoItemHref.search(videoItem[0]).group(1)
+ try:
+ dateString = regex_extractVideoItemDate.search(videoItem[0]).group(1)
+ dateTime = time.strptime(dateString, "%d.%m.%Y %H:%M")
+ except:
+ dateTime = None
+ # TODO: Some videos from Extra 3 are located on http://www.n-joy.de/
+ # which cannot be parsed by this script, yet.
+ if not re.compile("http://www.n-joy.de/.*").search(videoLink):
+ self.extractVideoInformation(videoLink, dateTime, nodeCount)
+
+ # Pagination (weiter)
+ regex_extractNextPage = re.compile(
+ "<a class=\"square button\" href=\"(.*?)\" title=\"(.*?)\".*?>"
+ )
+ for nextPageHref in regex_extractNextPage.finditer(htmlPage):
+ menuItemName = nextPageHref.group(2).decode("UTF-8")
+ link = self.rootLink+nextPageHref.group(1)
+ self.gui.buildVideoLink(DisplayObject(menuItemName, "", "", "description", link, False), self, nodeCount)
+
+ def buildPageMenu(self, link, initCount):
+
+ print link
+ if link[0:15] == "sendungverpasst":
+ self.buildPageMenuSendungVerpasst(link[15:])
+ elif link == "livestream":
+ self.buildPageMenuLivestream()
+ elif "/sendung_verpasst/" in link:
+ self.buildPageMenuVideoListVerpasst(link, initCount)
+ else:
+ self.buildPageMenuVideoList(link, initCount)
+
+ def searchVideo(self, searchText):
+ searchText = searchText.encode("UTF-8")
+ searchText = urllib.urlencode({"query": searchText})
+ self.buildPageMenu(self.searchLink+searchText, 0)
+
+ def extractVideoInformation(self, videoLink, pubDate, nodeCount):
+
+ regexFindVideoLink = re.compile("http://.*(hq.mp4|hi.mp4|lo.flv)")
+ regexFindImageLink = re.compile("/.*v-ardgalerie.jpg")
+ regexFindMediaData = re.compile(
+ "<div class=\"padding group\">\\s*?<div class=\"textinfo\">\\s*?<h\\d.*?>"
+ "(.*?)"
+ "</h\\d>\\s*?.*?<div class=\"subline\">.*?</div>\\s*?<p.*?>"
+ "(.*?)"
+ "</p>", re.DOTALL
+ )
+ if not videoLink.startswith(self.rootLink):
+ videoLink = self.rootLink+videoLink
+ videoPage = self.loadPage(videoLink)
+
+ self.gui.log("videolink: {0}".format(videoLink))
+ videoLink = {}
+ videoLink[0] = SimpleLink(regexFindVideoLink.search(videoPage).group(0), 0)
+
+ try:
+ pictureLink = self.rootLink+regexFindImageLink.search(videoPage).group(0)
+ except:
+ pictureLink = None
+ if '<article class="w66 ">' not in videoPage:
+ searchResult = regexFindMediaData.search(videoPage)
+ title = searchResult.group(1).decode('utf-8')
+ description = searchResult.group(2).decode('utf-8')
+ else:
+ title = re.search(
+ 'var trackTitle = "(.*?)"',
+ videoPage
+ ).group(1).decode('utf-8')
+ description = re.search(
+ '<meta name="description" content="(.*?)"',
+ videoPage
+ ).group(1).decode('utf-8')
+
+ self.gui.buildVideoLink(DisplayObject(title, "", pictureLink, description, videoLink, True, pubDate, 0), self, nodeCount)
diff --git a/plugin.video.mediathek/mediathek/orf.py b/plugin.video.mediathek/mediathek/orf.py
new file mode 100644
index 0000000..1146abf
--- /dev/null
+++ b/plugin.video.mediathek/mediathek/orf.py
@@ -0,0 +1,162 @@
+# -*- coding: utf-8 -*-
+# -------------LicenseHeader--------------
+# plugin.video.Mediathek - Gives access to most video-platforms from German public service broadcasters
+# Copyright (C) 2010 Raptor 2101 [raptor2101@gmx.de]
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import re,time,urllib
+from xml.dom import Node;
+from xml.dom import minidom;
+from mediathek import *
+
+class ORFMediathek(Mediathek):
+ def __init__(self, simpleXbmcGui):
+
+ self.rootLink = "http://tvthek.orf.at"
+ self.gui = simpleXbmcGui;
+ self.menuTree = [];
+ self.menuTree.append(TreeNode("0","Startseite","http://tvthek.orf.at/",True));
+
+ menuPage = self.loadPage(self.rootLink+"/programs");
+ findMenuLink = re.compile("<li><a href=\"(/programs/.*?)\" title=\".*?\">(.*?)</a></li>");
+ findCategorie = re.compile("<h4>(.*?)</h4>\\s*?<ul>((\\s*?%s\\s*?)+)</ul>"%findMenuLink.pattern)
+ categories = [];
+
+ for categorieMatch in findCategorie.finditer(menuPage):
+ title = categorieMatch.group(1);
+ items = [];
+ for menuMatch in findMenuLink.finditer(categorieMatch.group(2)):
+ items.append(TreeNode("1.%d.%d"%(len(categories),len(items)), menuMatch.group(2),"%s%s"%(self.rootLink,menuMatch.group(1)),True));
+ categories.append(TreeNode("1.%d"%len(categories), title,"",False,items));
+
+ self.menuTree.append(TreeNode("1","Sendungen","",False,categories));
+
+ videoLinkPage = "/programs/.*"
+ imageLink = "http://tvthek.orf.at/assets/.*?.jpeg"
+
+
+ self.regex_extractVideoPageLink = re.compile(videoLinkPage+"?\"");
+ self.regex_extractImageLink = re.compile(imageLink);
+ self.regex_extractTitle = re.compile("<strong>.*<span");
+ self.regex_extractVideoLink = re.compile("/programs/.*.asx");
+ self.regex_extractVideoObject = re.compile("<a href=\""+videoLinkPage+"\" title=\".*\">\\s*<span class=\"spcr\">\\s*<img src=\""+imageLink+"\" title=\".*\" alt=\".*\" />\\s*<span class=\".*\"></span>\\s*<strong>.*<span class=\"nowrap duration\">.*</span></strong>\\s*<span class=\"desc\">.*</span>\\s*</span>\\s*</a>");
+
+ self.regex_extractSearchObject = re.compile("<li class=\"clearfix\">\\s*<a href=\".*\" title=\".*\" class=\".*\"><img src=\".*\" alt=\".*\" /><span class=\"btn_play\">.*</span></a>\\s*<p>.*</p>\\s*<h4><a href=\".*\" title=\".*\">.*</a></h4>\\s*<p><a href=\".*\" title=\".*\"></a></p>\\s*</li>");
+
+ self.regex_extractProgrammLink = re.compile("/programs/.*?\"");
+ self.regex_extractProgrammTitle = re.compile("title=\".*?\"");
+ self.regex_extractProgrammPicture = re.compile("/binaries/asset/segments/\\d*/image1");
+
+ self.regex_extractFlashVars = re.compile("ORF.flashXML = '.*?'");
+ self.regex_extractHiddenDate = re.compile("\d{4}-\d{2}-\d{2}");
+ self.regex_extractXML = re.compile("%3C.*%3E");
+ self.regex_extractReferingSites = re.compile("<li><a href=\"/programs/\d+.*?/episodes/\d+.*?\"");
+
+ self.replace_html = re.compile("<.*?>");
+ self.searchLink = "http://tvthek.orf.at/search?q="
+ @classmethod
+ def name(self):
+ return "ORF";
+
+ def isSearchable(self):
+ return True;
+
+ def createVideoLink(self,title,image,videoPageLink,elementCount):
+ videoPage = self.loadPage(self.rootLink+videoPageLink);
+
+ videoLink = self.regex_extractVideoLink.search(videoPage);
+ if(videoLink == None):
+ return;
+
+ simpleLink = SimpleLink(self.rootLink+videoLink.group(), 0);
+ videoLink = {0:simpleLink};
+ counter = 0
+ playlist = self.loadPage(simpleLink.basePath);
+ for line in playlist:
+ counter+=1;
+
+ if(counter == 1):
+ self.gui.buildVideoLink(DisplayObject(title,"",image,"",videoLink, True, time.gmtime()),self,elementCount);
+ else:
+ self.gui.buildVideoLink(DisplayObject(title,"",image,"",videoLink, "PlayList", time.gmtime()),self,elementCount);
+
+ def searchVideo(self, searchText):
+ link = self.searchLink = "http://tvthek.orf.at/search?q="+searchText;
+ mainPage = self.loadPage(link);
+ result = self.regex_extractSearchObject.findall(mainPage);
+ for searchObject in result:
+ videoLink = self.regex_extractProgrammLink.search(searchObject).group().replace("\"","");
+ title = self.regex_extractProgrammTitle.search(searchObject).group().replace("title=\"","").replace("\"","");
+ title = title.decode("UTF-8");
+ pictureLink = self.regex_extractProgrammPicture.search(searchObject).group();
+
+ print videoLink;
+
+ self.createVideoLink(title,pictureLink,videoLink, len(result));
+
+ def extractLinksFromFlashXml(self, flashXml, date, elementCount):
+ print flashXml.toprettyxml().encode('UTF-8');
+ playlistNode = flashXml.getElementsByTagName("Playlist")[0];
+ linkNode=flashXml.getElementsByTagName("AsxUrl")[0];
+ link=linkNode.firstChild.data;
+ asxLink = SimpleLink(self.rootLink+link,0);
+ videoLink = {0:asxLink};
+ for videoItem in playlistNode.getElementsByTagName("Items")[0].childNodes:
+ if(videoItem.nodeType == Node.ELEMENT_NODE):
+ titleNode=videoItem.getElementsByTagName("Title")[0];
+
+ descriptionNode=videoItem.getElementsByTagName("Description")[0];
+ title=titleNode.firstChild.data;
+
+ stringArray = link.split("mp4:");
+
+ try:
+ description=descriptionNode.firstChild.data;
+ except:
+ description="";
+ self.gui.buildVideoLink(DisplayObject(title,"","",description,videoLink, True, date),self,elementCount);
+ def extractFlashLinks(self, flashVars,videoPageLinks,elementCount):
+ for flashVar in flashVars:
+ encodedXML = self.regex_extractXML.search(flashVar).group();
+ dateString = self.regex_extractHiddenDate.search(flashVar).group();
+ date = time.strptime(dateString,"%Y-%m-%d");
+ parsedXML = minidom.parseString(urllib.unquote(encodedXML));
+ self.extractLinksFromFlashXml(parsedXML, date,elementCount);
+ for videoPageLink in videoPageLinks:
+ videoPageLink = self.rootLink+videoPageLink.replace("<li><a href=\"","").replace("\"","");
+ print videoPageLink;
+ videoPage = self.loadPage(videoPageLink);
+ flashVars = self.regex_extractFlashVars.findall(videoPage);
+ for flashVar in flashVars:
+ encodedXML = self.regex_extractXML.search(flashVar).group();
+ dateString = self.regex_extractHiddenDate.search(flashVar).group();
+ date = time.strptime(dateString,"%Y-%m-%d");
+ parsedXML = minidom.parseString(urllib.unquote(encodedXML));
+ self.extractLinksFromFlashXml(parsedXML,date,elementCount);
+ def buildPageMenu(self, link, initCount):
+ mainPage = self.loadPage(link);
+ videoPageLinks = self.regex_extractReferingSites.findall(mainPage);
+ flashVars = self.regex_extractFlashVars.findall(mainPage);
+ links = self.regex_extractVideoObject.findall(mainPage);
+ elementCount = initCount + len(links)+len(flashVars)+len(videoPageLinks);
+ self.extractFlashLinks(flashVars,videoPageLinks,elementCount);
+ for linkObject in links:
+
+ videoLink = self.regex_extractVideoPageLink.search(linkObject).group().replace("\"","");
+ image = self.regex_extractImageLink.search(linkObject).group();
+ title = self.regex_extractTitle.search(linkObject).group().decode('UTF8');
+ title = self.replace_html.sub("", title);
+ title = title.replace(" <span","");
+ self.createVideoLink(title,image,videoLink, elementCount);
+
diff --git a/plugin.video.mediathek/mediathek/wdr.py b/plugin.video.mediathek/mediathek/wdr.py
new file mode 100644
index 0000000..5c784db
--- /dev/null
+++ b/plugin.video.mediathek/mediathek/wdr.py
@@ -0,0 +1,191 @@
+# -*- coding: utf-8 -*-
+#-------------LicenseHeader--------------
+# plugin.video.Mediathek - Gives access to most video-platforms from German public service broadcasters
+# Copyright (C) 2010 Raptor 2101 [raptor2101@gmx.de]
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import re, time;
+from mediathek import *
+from xml.dom import minidom;
+regex_dateString = re.compile("\\d{4}-\\d{2}-\\d{2}");
+class WDRMediathek(Mediathek):
+ def __init__(self, simpleXbmcGui):
+ self.gui = simpleXbmcGui;
+ self.pageSize = 20; #max 49;
+ self.rootLink = "http://www.wdr.de"
+ self.menuTree = (
+ TreeNode("0","Neuste Videos",self.rootLink+"/mediathek/rdf/regional/index.xml",True),
+ TreeNode("1","Sendungen von A-Z","",False,
+ (
+ TreeNode("1.0",u"A40","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=A40",True),
+ TreeNode("1.1",u"Aktuelle Stunde","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Aktuelle+Stunde",True),
+ TreeNode("1.2",u"Am Sonntag","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+2+-+Der+Sonntag",True),
+ TreeNode("1.3",u"Cosmo","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Funkhaus+Europa+-+Cosmo",True),
+ TreeNode("1.4",u"daheim & unterwegs","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=daheim+%26+unterwegs",True),
+ TreeNode("1.5",u"die story","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=die+story",True),
+ TreeNode("1.6",u"Dittsche","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Dittsche",True),
+ TreeNode("1.7",u"eins zu eins","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=eins+zu+eins",True),
+ TreeNode("1.8",u"frauTV","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=frauTV",True),
+ TreeNode("1.9",u"hier und heute","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Hier+und+Heute",True),
+ TreeNode("1.10",u"Kabarett","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+2+-+Kabarett",True),
+ TreeNode("1.11",u"Lokalzeit aus Aachen","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Lokalzeit+aus+Aachen",True),
+ TreeNode("1.12",u"Lokalzeit aus Düsseldorf","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Lokalzeit+aus+D%FCsseldorf",True),
+ TreeNode("1.13",u"Lokalzeit OWL","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Lokalzeit+OWL+aktuell",True),
+ TreeNode("1.14",u"Lokalzeit aus Bonn","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Lokalzeit+aus+Bonn",True),
+ TreeNode("1.15",u"Lokalzeit aus Köln","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Lokalzeit+aus+K%F6ln",True),
+ TreeNode("1.16",u"Lokalzeit Ruhr","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Lokalzeit+Ruhr",True),
+ TreeNode("1.17",u"Lokalzeit aus Dortmund","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Lokalzeit+aus+Dortmund",True),
+ TreeNode("1.18",u"Lokalzeit Bergisches Land","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Lokalzeit+Bergisches+Land",True),
+ TreeNode("1.19",u"Lokalzeit Südwestfalen","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Lokalzeit+S%FCdwestfalen",True),
+ TreeNode("1.20",u"Lokalzeit aus Duisburg","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Lokalzeit+aus+Duisburg",True),
+ TreeNode("1.21",u"Lokalzeit Münsterland","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Lokalzeit+M%FCnsterland",True),
+ TreeNode("1.22",u"markt","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=markt",True),
+ TreeNode("1.23",u"Menschen hautnah","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Menschen+hautnah",True),
+ TreeNode("1.24",u"Mittagsecho","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+5+-+Mittagsecho",True),
+ TreeNode("1.25",u"Mittagsmagazin","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+2+-+Mittagsmagazin",True),
+ TreeNode("1.26",u"mittwochs live","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=mittwochs+live",True),
+ TreeNode("1.27",u"Morgenecho","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+5+-+Morgenecho",True),
+ TreeNode("1.28",u"Morgenmagazin","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+2+-+Morgenmagazin",True),
+ TreeNode("1.29",u"Mosaik","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+3+-+Mosaik",True),
+ TreeNode("1.30",u"Piazza","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Funkhaus+Europa+-+Piazza",True),
+ TreeNode("1.31",u"Platz der Republik","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+5+-+Platz+der+Republik",True),
+ TreeNode("1.32",u"Quarks & Co","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Quarks+%26+Co",True),
+ TreeNode("1.33",u"Resonanzen","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+3+-+Resonanzen",True),
+ TreeNode("1.34",u"Scala","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+5+-+Scala",True),
+ TreeNode("1.35",u"schön hier","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=sch%F6n+hier",True),
+ TreeNode("1.36",u"Servicezeit","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Servicezeit",True),
+ TreeNode("1.37",u"sport inside","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=sport+inside",True),
+ TreeNode("1.38",u"Stichtag","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+2+-+Stichtag",True),
+ TreeNode("1.39",u"Thema NRW","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+5+-+Thema+NRW",True),
+ TreeNode("1.40",u"WDR aktuell","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+aktuell",True),
+ TreeNode("1.41",u"WDR sport aktuell","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+sport+aktuell",True),
+ TreeNode("1.42",u"west.art","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=West.art",True),
+ TreeNode("1.43",u"Westblick","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+5+-+Westblick",True),
+ TreeNode("1.44",u"WESTPOL","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WESTPOL",True),
+ TreeNode("1.45",u"Westzeit","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+2+-+Westzeit",True),
+ TreeNode("1.46",u"Zeiglers wunderbare Welt des Fußballs","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Zeiglers+wunderbare+Welt+des+Fu%DFballs",True),
+ TreeNode("1.47",u"ZeitZeichen","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+3+%2F+WDR+5+-+ZeitZeichen",True),
+ TreeNode("1.48",u"Zimmer Frei!","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=Zimmer+Frei%21",True),
+ TreeNode("1.49",u"Zwischen Rhein und Weser","http://www.wdr.de/mediathek/html/regional/ergebnisse/sendung.xml?rankingtype=sendung&rankingvalue=WDR+2+-+Zwischen+Rhein+und+Weser",True),
+ )
+ ),
+ TreeNode("2","Themen","",False,
+ (
+ TreeNode("2.0","Politik","http://www.wdr.de/mediathek/html/regional/ergebnisse/schlagwort.xml?rankingvalue=Politik",True),
+ TreeNode("2.1","Wirtschaft","http://www.wdr.de/mediathek/html/regional/ergebnisse/schlagwort.xml?rankingvalue=Wirtschaft",True),
+ TreeNode("2.2","Kultur","http://www.wdr.de/mediathek/html/regional/ergebnisse/schlagwort.xml?rankingvalue=Kultur",True),
+ TreeNode("2.3","Panorama","http://www.wdr.de/mediathek/html/regional/ergebnisse/schlagwort.xml?rankingvalue=Panorama",True),
+ TreeNode("2.4","Service","http://www.wdr.de/mediathek/html/regional/ergebnisse/schlagwort.xml?rankingvalue=Service",True),
+ TreeNode("2.5","Freizeit","http://www.wdr.de/mediathek/html/regional/ergebnisse/schlagwort.xml?rankingvalue=Freizeit",True),
+ TreeNode("2.6","Sport","http://www.wdr.de/mediathek/html/regional/ergebnisse/schlagwort.xml?rankingvalue=Sport",True),
+ )
+ ),
+ )
+ self._regex_extractTitle = re.compile("<h1>.*?<span class=\"inv\">");
+ self._regex_extractDescription = re.compile("<meta name=\"description\" content=\"(.|\\s)*?\" />");
+ self._regex_extractPicture = re.compile("<link rel=\"image_src\" href=\".*?\" />");
+ self._regex_extractDate = re.compile("<meta name=\"DC.Date\" content=\".*?\" />");
+ self._regex_extractDuration = re.compile("\\((.*)\\)<span class=\"inv\">");
+
+ self._regex_extractVideoPage = re.compile("<a href=\"/mediathek/html/.*?\\.xml\" title=\".*?\".*?>");
+ self._regex_extractLink = re.compile("/mediathek/html/.*?\\.xml");
+ self._regex_extractAudioLink = re.compile(self.rootLink+"/mediathek/.*?\\.mp3");
+ self._regex_extractVideoLink = re.compile("(dsl|isdn)Src=rtmp://.*?\\.(mp4|flv)");
+ self.replace_html = re.compile("<.*?>");
+ self.replace_tag = re.compile("(<meta name=\".*?\" content=\"|<link rel=\"image_src\" href=\"|\" />)");
+ self.searchLink = "http://www.wdr.de/mediathek/html/regional/suche/index.xml?wsSucheAusgabe=liste&wsSucheSuchart=volltext&wsSucheMedium=av&suche_submit=Suche+starten&wsSucheBegriff="
+
+ @classmethod
+ def name(self):
+ return "WDR";
+ def isSearchable(self):
+ return True;
+
+ def searchVideo(self, searchText):
+ link = self.searchLink+searchText;
+ self.buildPageMenu(link, 0, False)
+ def buildPageMenu(self, link, initCount, subLink = False):
+ link = link+"&rankingcount="+str(self.pageSize);
+ self.gui.log("MenuLink: %s"%link);
+ mainPage = self.loadPage(link);
+ if(mainPage.startswith("<?xml version=\"1.0\"")):
+ self.parseXml(mainPage);
+ else:
+ self.parseHtml(mainPage);
+ def parseHtml(self, htmlPage):
+ videoPageLinks = list(self._regex_extractVideoPage.finditer(htmlPage));
+
+ for videoPageLink in videoPageLinks:
+ link = self._regex_extractLink.search(videoPageLink.group()).group();
+ print link;
+ displayObject = self.generateDisplayObject(self.rootLink+link);
+ self.gui.buildVideoLink(displayObject,self,len(videoPageLinks));
+
+ def readText(self,node,textNode):
+ try:
+ node = node.getElementsByTagName(textNode)[0].firstChild;
+ return unicode(node.data);
+ except:
+ return "";
+
+ def parseDate(self,dateString):
+ dateString = regex_dateString.search(dateString).group();
+ return time.strptime(dateString,"%Y-%m-%d");
+
+ def parseXml(self, xmlPage):
+ xmlPage = minidom.parseString(xmlPage);
+ items = xmlPage.getElementsByTagName("item");
+ for itemNode in items:
+ link = self.readText(itemNode,"link");
+ displayObject = self.generateDisplayObject(link);
+ self.gui.buildVideoLink(displayObject,self,len(items));
+
+ def generateDisplayObject(self,videoPageLink):
+ mainPage = self.loadPage(videoPageLink);
+ title = unicode(self._regex_extractTitle.search(mainPage).group(),'ISO-8859-1');
+ description = unicode(self._regex_extractDescription.search(mainPage).group(),'ISO-8859-1');
+ picture = unicode(self._regex_extractPicture.search(mainPage).group(),'ISO-8859-1');
+ date = self._regex_extractDate.search(mainPage).group();
+ duration = self._regex_extractDuration.search(mainPage).group(1);
+
+ title = self.replace_html.sub("", title);
+ description = self.replace_tag.sub("",description);
+ picture = self.replace_tag.sub("",picture);
+ date = self.parseDate(self.replace_tag.sub("",date));
+
+ links = {};
+ for linkString in self._regex_extractVideoLink.finditer(mainPage):
+ linkString = linkString.group();
+ if linkString.startswith("dslSrc="):
+ linkString = linkString.replace("dslSrc=","");
+ links[1] = self.extractLink(linkString);
+ else:
+ linkString = linkString.replace("isdnSrc=","");
+ links[0] = self.extractLink(linkString);
+
+ if len(links) == 0:
+ linkString = self._regex_extractAudioLink.search(mainPage).group();
+ links[0] = self.extractLink(linkString);
+
+ return DisplayObject(title,"",picture,description,links,True, date, duration)
+
+ def extractLink(self, linkString):
+ if(linkString.find("mediartmp://")>-1):
+ linkString = linkString.split("mediartmp://")
+ return SimpleLink("rtmp://%s"%linkString[1], 0);
+ elif(linkString.find("mediahttp://")>-1):
+ linkString = linkString.split("mediahttp://")
+ return SimpleLink("http://%s"%linkString[1], 0);
+ else:
+ return SimpleLink(linkString, 0);
diff --git a/plugin.video.mediathek/mediathek/zdf.py b/plugin.video.mediathek/mediathek/zdf.py
new file mode 100644
index 0000000..3ece7a9
--- /dev/null
+++ b/plugin.video.mediathek/mediathek/zdf.py
@@ -0,0 +1,152 @@
+# -*- coding: utf-8 -*-
+#-------------LicenseHeader--------------
+# plugin.video.Mediathek - Gives access to most video-platforms from German public service broadcasters
+# Copyright (C) 2010 Raptor 2101 [raptor2101@gmx.de]
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import re,math,traceback,time
+from mediathek import *
+from datetime import datetime,timedelta
+import json
+
+class ZDFMediathek(Mediathek):
+ def __init__(self, simpleXbmcGui):
+ self.gui = simpleXbmcGui;
+
+ today = datetime.today();
+
+ self.menuTree = (
+ TreeNode("0","Startseite","https://zdf-cdn.live.cellular.de/mediathekV2/start-page",True),
+ TreeNode("1","Kategorien","https://zdf-cdn.live.cellular.de/mediathekV2/categories",True),
+ TreeNode("2","Sendungen von A-Z","https://zdf-cdn.live.cellular.de/mediathekV2/brands-alphabetical",True),
+ TreeNode("3","Sendung verpasst?","",False,(
+ TreeNode("3.0","Heute","https://zdf-cdn.live.cellular.de/mediathekV2/broadcast-missed/%s"%(today.strftime("%Y-%m-%d")),True),
+ TreeNode("3.1","Gestern","https://zdf-cdn.live.cellular.de/mediathekV2/broadcast-missed/%s"%((today-timedelta(days=1)).strftime("%Y-%m-%d")),True),
+ TreeNode("3.2","Vorgestern","https://zdf-cdn.live.cellular.de/mediathekV2/broadcast-missed/%s"%((today-timedelta(days=2)).strftime("%Y-%m-%d")),True),
+ TreeNode("3.3",(today-timedelta(days=3)).strftime("%A"),"https://zdf-cdn.live.cellular.de/mediathekV2/broadcast-missed/%s"%((today-timedelta(days=3)).strftime("%Y-%m-%d")),True),
+ TreeNode("3.4",(today-timedelta(days=4)).strftime("%A"),"https://zdf-cdn.live.cellular.de/mediathekV2/broadcast-missed/%s"%((today-timedelta(days=4)).strftime("%Y-%m-%d")),True),
+ TreeNode("3.5",(today-timedelta(days=5)).strftime("%A"),"https://zdf-cdn.live.cellular.de/mediathekV2/broadcast-missed/%s"%((today-timedelta(days=5)).strftime("%Y-%m-%d")),True),
+ TreeNode("3.6",(today-timedelta(days=6)).strftime("%A"),"https://zdf-cdn.live.cellular.de/mediathekV2/broadcast-missed/%s"%((today-timedelta(days=6)).strftime("%Y-%m-%d")),True),
+ TreeNode("3.7",(today-timedelta(days=7)).strftime("%A"),"https://zdf-cdn.live.cellular.de/mediathekV2/broadcast-missed/%s"%((today-timedelta(days=7)).strftime("%Y-%m-%d")),True),
+ )),
+ TreeNode("4","Live TV","https://zdf-cdn.live.cellular.de/mediathekV2/live-tv/%s"%(today.strftime("%Y-%m-%d")),True)
+ );
+ @classmethod
+ def name(self):
+ return "ZDF";
+
+ def isSearchable(self):
+ return False;
+
+ def searchVideo(self, searchText):
+ return;
+
+ def buildPageMenu(self, link, initCount):
+ self.gui.log("buildPageMenu: "+link);
+ jsonObject = json.loads(self.loadPage(link));
+ callhash = self.gui.storeJsonFile(jsonObject);
+
+ if("stage" in jsonObject):
+ for stageObject in jsonObject["stage"]:
+ if(stageObject["type"]=="video"):
+ self.buildVideoLink(stageObject,initCount);
+
+ if("cluster" in jsonObject):
+ for counter, clusterObject in enumerate(jsonObject["cluster"]):
+ if "teaser" in clusterObject and "name" in clusterObject:
+ path = "cluster.%d.teaser"%(counter)
+ self.gui.buildJsonLink(self,clusterObject["name"],path,callhash,initCount)
+ if("broadcastCluster" in jsonObject):
+ for counter, clusterObject in enumerate(jsonObject["broadcastCluster"]):
+ if clusterObject["type"].startswith("teaser") and "name" in clusterObject:
+ path = "broadcastCluster.%d.teaser"%(counter)
+ self.gui.buildJsonLink(self,clusterObject["name"],path,callhash,initCount)
+ if("epgCluster" in jsonObject):
+ for epgObject in jsonObject["epgCluster"]:
+ if("liveStream" in epgObject and len(epgObject["liveStream"])>0):
+ self.buildVideoLink(epgObject["liveStream"], initCount);
+
+ def buildJsonMenu(self, path,callhash, initCount):
+ jsonObject=self.gui.loadJsonFile(callhash);
+ jsonObject=self.walkJson(path,jsonObject);
+ categoriePages=[];
+ videoObjects=[];
+
+ for entry in jsonObject:
+ if entry["type"] == "brand":
+ categoriePages.append(entry);
+ if entry["type"] == "video":
+ videoObjects.append(entry);
+ self.gui.log("CategoriePages: %d"%len(categoriePages));
+ self.gui.log("VideoPages: %d"%len(videoObjects));
+ for categoriePage in categoriePages:
+ title=categoriePage["titel"];
+ subTitle=categoriePage["beschreibung"];
+ imageLink="";
+ for width,imageObject in categoriePage["teaserBild"].iteritems():
+ if int(width)<=840:
+ imageLink=imageObject["url"];
+ url = categoriePage["url"];
+ self.gui.buildVideoLink(DisplayObject(title,subTitle,imageLink,"",url,False),self,initCount);
+
+ for videoObject in videoObjects:
+ self.buildVideoLink(videoObject,initCount);
+
+ def buildVideoLink(self,videoObject,counter):
+ title=videoObject["headline"];
+ subTitle=videoObject["titel"];
+
+ if(len(title)==0):
+ title = subTitle;
+ subTitle = "";
+ if("beschreibung" in videoObject):
+ description=videoObject["beschreibung"];
+ imageLink="";
+ if("teaserBild" in videoObject):
+ for width,imageObject in videoObject["teaserBild"].iteritems():
+ if int(width)<=840:
+ imageLink=imageObject["url"];
+ if("formitaeten" in videoObject):
+ links = self.extractLinks(videoObject);
+ self.gui.buildVideoLink(DisplayObject(title,subTitle,imageLink,description,links,True,None,videoObject.get('length')),self,counter);
+ else:
+ link = videoObject["url"];
+ self.gui.buildVideoLink(DisplayObject(title,subTitle,imageLink,description,link,"JsonLink",None,videoObject.get('length')),self,counter);
+
+ def playVideoFromJsonLink(self,link):
+ jsonObject = json.loads(self.loadPage(link));
+ links = self.extractLinks(jsonObject["document"]);
+ self.gui.play(links);
+ def extractLinks(self,jsonObject):
+ links={};
+ for formitaete in jsonObject["formitaeten"]:
+ url = formitaete["url"];
+ quality = formitaete["quality"];
+ hd = formitaete["hd"];
+ self.gui.log("quality:%s hd:%s url:%s"%(quality,hd,url));
+ if hd == True:
+ links[4] = SimpleLink(url, -1);
+ else:
+ if quality == "low":
+ links[0] = SimpleLink(url, -1);
+ if quality == "med":
+ links[1] = SimpleLink(url, -1);
+ if quality == "high":
+ links[2] = SimpleLink(url, -1);
+ if quality == "veryhigh":
+ links[3] = SimpleLink(url, -1);
+ if quality == "auto":
+ links[3] = SimpleLink(url, -1);
+ return links;
+