## -*- 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+"/de/";
self.jsonLink = "https://api.arte.tv/api/player/v1/config/de/%s?lifeCycle=1"
self.serachLink = self.rootLink+"/de/search/?q=%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_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("\"kind\":\"MAGAZINE\",\"programId\":\"RC-\d+\",\"language\":\"\w{2}\",\"url\":\"(http.*?)\",\"title\":\"(.*?)\",\"subtitle\":(\"(.*?)\"|null),\"images\"");
self.regex_categories = re.compile("\"link\":{\"page\":\"\w{3}\",\"title\":\"(.*?)\",\"url\":\"(http.*?)\"}");
self.regex_playlists = re.compile(regexSourceString%"data-highlightedPlaylists");
self.searchContent = re.compile(regexSourceString%"data-results");
self.regex_ExtractJson = re.compile("__INITIAL_STATE__ = ({.*});");
def searchVideo(self, searchText):
link = self.serachLink%searchText;
pageContent = self.loadPage(link).decode('UTF-8');
self.extractVideoLinks(pageContent,0);
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;
self.parsePage(link);
def extractJsonFromPage(self,link):
pageContent = self.loadPage(link).decode('UTF-8');
pageContent = BeautifulSoup(self.regex_ExtractJson.search(pageContent).group(1),"html.parser");
return json.loads(pageContent.prettify(formatter=None))
def parsePage(self, link):
jsonContent = self.extractJsonFromPage(link);
for video in jsonContent["collection"]["videos"]:
self.buildVideoEntry(video);
def showMainPage(self):
self.gui.log("buildPageMenu: "+self.basePage);
jsonContent = self.extractJsonFromPage(self.basePage);
for zone in jsonContent["page"]["zones"]:
if(zone["type"] in ("highlight","playlist") ):
for teaser in zone["teasers"]:
self.buildVideoEntry(teaser);
def buildJsonMenu(self, path,callhash, initCount):
jsonContent=self.gui.loadJsonFile(callhash);
for teaser in jsonContent["teasers"]:
self.buildVideoEntry(teaser);
def buildJsonLink(self,name,jsonContent):
callhash = self.gui.storeJsonFile(jsonContent,name);
self.gui.buildJsonLink(self,name,"init",callhash,0)
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),"html.parser");
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 showCategories(self):
jsonContent = self.extractJsonFromPage(self.basePage);
for zone in jsonContent["page"]["zones"]:
if(zone["type"] == "category" ):
self.buildJsonLink(zone["title"],zone);
def showCluster(self):
jsonContent = self.extractJsonFromPage(self.basePage);
for zone in jsonContent["page"]["zones"]:
if(zone["type"] == "magazine" ):
for teaser in zone["teasers"]:
self.buildVideoEntry(teaser);
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 = unicode(jsonObject["title"]);
if(jsonObject["subtitle"] is not None):
subTitle = unicode(jsonObject["subtitle"]);
else:
subTitle = None;
if("teaser" in jsonObject):
detail = unicode(jsonObject["teaser"]);
else:
detail = "";
pictures = None;
pictureUrl = None;
if("thumbnails" in jsonObject):
pictures = jsonObject["thumbnails"];
if("images" in jsonObject):
pictures = jsonObject["images"];
if(pictures is not None):
picture = None;
for pictureItem in pictures:
if(picture is None or picture["width"]