## -*- 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 . import re, traceback,json; from mediathek import *; 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 True; 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.serachLink = self.rootLink+"/guide/de/search?q=%s&scope=plus7&kind=plus7" 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.searchContent = re.compile(regexSourceString%"data-results"); self.regex_extractVideoSources = ( re.compile(regexSourceString%"data-highlightedVideos"), re.compile(regexSourceString%"data-latestVideos"), re.compile(regexSourceString%"data-categoryVideoSet"), re.compile(regexSourceString%"data-videoSet") ); def searchVideo(self, searchText): link = self.serachLink%searchText; pageContent = self.loadPage(link).decode('UTF-8'); content = self.searchContent.search(pageContent).group(1); content = BeautifulSoup(content); jsonContent = json.loads(content.prettify(formatter=None)); linkCount = len(jsonContent["programs"]); for jsonObject in jsonContent["programs"]: link = self.jsonLink%jsonObject["id"]; jsonPage = json.loads(self.loadPage(link)); self.extractVideoLinksFromJSONPage(jsonPage["videoJsonPlayer"],linkCount) 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); if("videos" in jsonObject): self.extractVideoLinksFromJson(jsonObject); if(isinstance(jsonObject,list)): for jsonObject in jsonObject: if("day" in jsonObject): name = jsonObject["day"]; link = jsonObject["collection_url"]; self.gui.buildVideoLink(DisplayObject(name,"","","",link,False,None),self,0); def buildJsonLink(self,name,jsonContent): 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): content = BeautifulSoup(match.group(1)); jsonContent = json.loads(content.prettify(formatter=None)) if(isinstance(jsonContent,list)): self.buildJsonLink(name,jsonContent) elif("collection_url" in jsonContent): link = jsonContent["collection_url"]; self.gui.buildVideoLink(DisplayObject(name,"","","",link,False,None),self,0); 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)); self.gui.log(content.prettify(formatter=None)); 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),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): self.gui.log(json.dumps(jsonObject)); title = unicode(jsonObject["title"]); if(jsonObject["subtitle"] is not None): subTitle = unicode(jsonObject["subtitle"]); else: subTitle = None; detail = unicode(jsonObject["teaser"]); picture = None; for pictureItem in jsonObject["thumbnails"]: if(picture is None or picture["width"]