# -*- coding: utf-8 -*-
import urllib2,urllib,re,os
from stats import *
import xbmcplugin,xbmcgui,xbmcaddon
import simplejson as json
from hashlib import md5
from time import time
__baseurl__ = 'http://www.stream.cz/API'
_UserAgent_ = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3'
addon = xbmcaddon.Addon('plugin.video.dmd-czech.stream')
profile = xbmc.translatePath(addon.getAddonInfo('profile'))
__settings__ = xbmcaddon.Addon(id='plugin.video.dmd-czech.stream')
home = __settings__.getAddonInfo('path')
REV = os.path.join( profile, 'list_revision')
icon = xbmc.translatePath( os.path.join( home, 'icon.png' ) )
nexticon = xbmc.translatePath( os.path.join( home, 'nextpage.png' ) )
fanart = xbmc.translatePath( os.path.join( home, 'fanart.jpg' ) )
scriptname = addon.getAddonInfo('name')
quality_index = int(addon.getSetting('quality'))
quality_settings = ["ask", "240p", "360p", "480p", "720p", "1080p"]
MODE_LIST_SHOWS = 1
MODE_LIST_SEASON = 2
MODE_LIST_EPISODES = 3
MODE_VIDEOLINK = 10
MODE_RESOLVE_VIDEOLINK = 11
MODE_LIST_NEXT_EPISODES = 12
def replaceWords(text, word_dic):
rc = re.compile('|'.join(map(re.escape, word_dic)))
def translate(match):
return word_dic[match.group(0)]
return rc.sub(translate, text)
WORD_DIC = {
'\u00e1': 'á',
'\u00e9': 'é',
'\u00ed': 'í',
'\u00fd': 'ý',
'\u00f3': 'ó',
'\u00fa': 'ú',
'\u016f': 'ů',
'\u011b': 'ě',
'\u0161': 'š',
'\u0165': 'ť',
'\u010d': 'č',
'\u0159': 'ř',
'\u017e': 'ž',
'\u010f': 'ď',
'\u0148': 'ň',
'\u00C0': 'Á',
'\u00c9': 'É',
'\u00cd': 'Í',
'\u00d3': 'Ó',
'\u00da': 'Ú',
'\u016e': 'Ů',
'\u0115': 'Ě',
'\u0160': 'Š',
'\u010c': 'Č',
'\u0158': 'Ř',
'\u0164': 'Ť',
'\u017d': 'Ž',
'\u010e': 'Ď',
'\u0147': 'Ň',
'\\xc3\\xa1': 'á',
'\\xc4\\x97': 'é',
'\\xc3\\xad': 'í',
'\\xc3\\xbd': 'ý',
'\\xc5\\xaf': 'ů',
'\\xc4\\x9b': 'ě',
'\\xc5\\xa1': 'š',
'\\xc5\\xa4': 'ť',
'\\xc4\\x8d': 'č',
'\\xc5\\x99': 'ř',
'\\xc5\\xbe': 'ž',
'\\xc4\\x8f': 'ď',
'\\xc5\\x88': 'ň',
'\\xc5\\xae': 'Ů',
'\\xc4\\x94': 'Ě',
'\\xc5\\xa0': 'Š',
'\\xc4\\x8c': 'Č',
'\\xc5\\x98': 'Ř',
'\\xc5\\xa4': 'Ť',
'\\xc5\\xbd': 'Ž',
'\\xc4\\x8e': 'Ď',
'\\xc5\\x87': 'Ň',
}
REPL_DICT = {
" ": " ",
"&" : "&",
""": "\"",
"<" : "<",
">" : ">",
"\n" : "",
"\r" : "",
"" : "[/B]",
"": "[CR]",
}
def getLS(strid):
return addon.getLocalizedString(strid)
def notify(msg, timeout = 7000):
xbmc.executebuiltin('Notification(%s, %s, %d, %s)'%(scriptname, msg.encode('utf-8'), timeout, addon.getAddonInfo('icon')))
log(msg, xbmc.LOGINFO)
def log(msg, level=xbmc.LOGDEBUG):
if type(msg).__name__=='unicode':
msg = msg.encode('utf-8')
xbmc.log("[%s] %s"%(scriptname,msg.__str__()), level)
def logDbg(msg):
log(msg,level=xbmc.LOGDEBUG)
def logErr(msg):
log(msg,level=xbmc.LOGERROR)
def makeImageUrl(rawurl):
return 'http:'+rawurl.replace('{width}/{height}','360/360')
def getJsonDataFromUrl(url):
req = urllib2.Request(url)
req.add_header('User-Agent', _UserAgent_)
req.add_header('Api-Password', md5('fb5f58a820353bd7095de526253c14fd'+url.split(__baseurl__)[1]+str(int(round(int(time())/3600.0/24.0)))).hexdigest())
response = urllib2.urlopen(req)
httpdata = response.read()
response.close()
httpdata = replaceWords(httpdata, WORD_DIC)
return json.loads(httpdata)
def html2text(html):
rex = re.compile('|'.join(map(re.escape, REPL_DICT)))
def doReplace(matchobj):
return REPL_DICT[matchobj.group(0)]
text = rex.sub(doReplace, html)
text = re.sub("", "[B]", text)
text = re.sub("
", "[CR]", text)
text = re.sub("
", "[CR]", text)
text = re.sub("
", "[CR]", text)
text = re.sub("<.*?>", "", text)
return text
def listContent():
addDir(u'Nejnovější videa',__baseurl__ + '/timeline/latest',MODE_LIST_EPISODES,icon)
addDir(u'Všechny pořady',__baseurl__ + '/catalogue',MODE_LIST_SHOWS,icon)
addDir(u'Pohádky',__baseurl__ + '/catalogue?channels=3',MODE_LIST_SHOWS,icon)
def listShows(url):
data = getJsonDataFromUrl(url)
for item in data[u'_embedded'][u'stream:show']:
if u'stream:backward' in item[u'_links']:
link = __baseurl__+item[u'_links'][u'stream:backward'][u'href']
else:
link = __baseurl__+item[u'_links'][u'self'][u'href']
image = makeImageUrl(item[u'image'])
name = item[u'name']
addDir(name,link,MODE_LIST_SEASON,image)
if 'next' in data[u'_links'].keys():
listShows(__baseurl__ + data[u'_links'][u'next'][u'href'])
xbmcplugin.addSortMethod( handle=addonHandle, sortMethod=xbmcplugin.SORT_METHOD_LABEL)
def listSeasons(url):
data = getJsonDataFromUrl(url)
seasons = data[u'_embedded'][u'stream:season']
if type(seasons) is dict:
listSeasonEpisodes(seasons)
elif type(seasons) is list:
for season in seasons:
link = __baseurl__+season[u'_links'][u'self'][u'href']
name = u'[B][COLOR blue]' + season[u'name'] + u' >>[/COLOR][/B]'
addDir(name,link,MODE_LIST_EPISODES,nexticon)
for season in seasons:
listSeasonEpisodes(season, season[u'name'])
if (u'_links' in data) and (u'next' in data[u'_links']):
link = __baseurl__+data[u'_links'][u'next'][u'href']
addDir(u'[B][COLOR blue]'+getLS(30004)+u' >>[/COLOR][/B]',link,MODE_LIST_SEASON,nexticon)
def addEpisode(item, season_name='', islatest=False):
link = __baseurl__+item[u'_links'][u'self'][u'href']
image = makeImageUrl(item[u'image'])
name = item[u'name']
if u'order' in item:
name = str(item[u'order']) +'. '+ name
if (len(season_name)==0) and ((u'_embedded' in item) and (u'stream:show' in item[u'_embedded'])) :
season_name = item[u'_embedded'][u'stream:show'][u'name']
if len(season_name):
name = season_name + ' | ' + name
if quality_index == 0:
addDir(name,link,MODE_VIDEOLINK,image)
else:
addUnresolvedLink(name,link,image,islatest)
def listSeasonEpisodes(data, season_name='', islatest=False):
if (u'_embedded' in data) and (u'stream:episode' in data[u'_embedded']):
episodes=data[u'_embedded'][u'stream:episode']
if type(episodes) is dict:
addEpisode(episodes, season_name, islatest)
elif type(episodes) is list:
for item in episodes:
addEpisode(item, season_name, islatest)
if (u'_links' in data) and (u'next' in data[u'_links']):
link = __baseurl__+data[u'_links'][u'next'][u'href']
addDir(u'[B][COLOR blue]'+getLS(30004)+u' >>[/COLOR][/B]',link,MODE_LIST_EPISODES,nexticon)
def listEpisodes(url):
data = getJsonDataFromUrl(url)
islatest='/timeline/latest' in url
listSeasonEpisodes(data, '', islatest)
def listNextEpisodes(url):
data = getJsonDataFromUrl(url)
try:
link = __baseurl__+data[u'_embedded'][u'stream:show'][u'_links'][u'self'][u'href']
listSeasons(link)
except:
logDbg('Další epizody nenalezeny')
def videoLink(url,name):
data = getJsonDataFromUrl(url)
name = data[u'name']
thumb = makeImageUrl(data[u'image'])
popis = html2text(data[u'detail'])
logDbg(url)
subtitles = ''
if 'subtitles_srt' in data:
subtitles = 'http:'+data['subtitles_srt']
for item in data[u'video_qualities']:
try:
for fmt in item[u'formats']:
if fmt[u'type'] == 'video/mp4':
stream_url = fmt[u'source']
quality = fmt[u'quality']
addLink(quality+' '+name,stream_url,thumb,popis,subtitles)
except:
continue
try:
link = __baseurl__+data[u'_embedded'][u'stream:show'][u'_links'][u'self'][u'href']
image = makeImageUrl(data[u'_embedded'][u'stream:show'][u'image'])
name = data[u'_embedded'][u'stream:show'][u'name']
addDir(u'[B][COLOR blue]'+getLS(30004)+u' >>[/COLOR][/B]',link,MODE_LIST_SEASON,image)
except:
logDbg('Další epizody nenalezeny')
def resolveVideoLink(url,name):
data = getJsonDataFromUrl(url)
name = data[u'name']
thumb = makeImageUrl(data[u'image'])
popis = html2text(data[u'detail'])
qa = []
logDbg("Resolving video URL for quality " + quality_settings[quality_index] + " from: " + url)
for item in data[u'video_qualities']:
try:
for fmt in item[u'formats']:
if fmt[u'type'] == 'video/mp4':
stream_url = fmt[u'source']
quality = fmt[u'quality']
qa.append((quality, stream_url))
except:
continue
if len(qa) == 0:
# no video available...
notify(getLS(30003))
xbmcplugin.setResolvedUrl(handle=addonHandle, succeeded=False, listitem=xbmcgui.ListItem(label="video", path=""))
return
# sort available qualities according desired one
quality_sorted = quality_settings[quality_index:0:-1]
quality_sorted += quality_settings[quality_index+1:]
stream_url = ""
for qf in quality_sorted:
match_quality = [q for q in qa if q[0] == qf]
if len(match_quality):
stream_url = match_quality[0][1]
break
if stream_url == "":
logErr("No video stream found!")
xbmcplugin.setResolvedUrl(handle=addonHandle, succeeded=False, listitem=xbmcgui.ListItem(label="video", path=""))
return
logDbg("Resolved URL: "+stream_url)
if match_quality[0][0] != quality_settings[quality_index]:
notify(getLS(30002) % (quality_settings[quality_index], match_quality[0][0]))
liz = xbmcgui.ListItem(path=stream_url, iconImage="DefaultVideo.png")
liz.setInfo( type="Video", infoLabels={ "Title": name, "Plot": popis} )
liz.setProperty('IsPlayable', 'true')
liz.setProperty( "icon", thumb )
if 'subtitles_srt' in data:
logDbg("Subtitles URL: "+data['subtitles_srt'])
liz.setSubtitles([ 'http:'+data['subtitles_srt'] ])
xbmcplugin.setResolvedUrl(handle=addonHandle, succeeded=True, listitem=liz)
def getParams():
param=[]
paramstring=sys.argv[2]
if len(paramstring)>=2:
params=sys.argv[2]
cleanedparams=params.replace('?','')
if (params[len(params)-1]=='/'):
params=params[0:len(params)-2]
pairsofparams=cleanedparams.split('&')
param={}
for i in range(len(pairsofparams)):
splitparams={}
splitparams=pairsofparams[i].split('=')
if (len(splitparams))==2:
param[splitparams[0]]=splitparams[1]
return param
def addLink(name,url,iconimage,popis,subtitles):
logDbg("addLink(): '"+name+"' url='"+url+ "' img='"+iconimage+"' popis='"+popis+"' subtitles='"+subtitles+"'")
ok=True
liz=xbmcgui.ListItem(name, iconImage="DefaultVideo.png", thumbnailImage=iconimage)
liz.setInfo( type="Video", infoLabels={ "Title": name, "Plot": popis} )
liz.setProperty( "Fanart_Image", fanart )
if len(subtitles):
liz.setSubtitles([ subtitles ])
ok=xbmcplugin.addDirectoryItem(handle=addonHandle,url=url,listitem=liz)
return ok
def composePluginUrl(url, mode, name):
return sys.argv[0]+"?url="+urllib.quote_plus(url.encode('utf-8'))+"&mode="+str(mode)+"&name="+urllib.quote_plus(name.encode('utf-8'))
def addItem(name,url,mode,iconimage,isfolder,islatest=False):
u=composePluginUrl(url,mode,name)
ok=True
liz=xbmcgui.ListItem(name, iconImage="DefaultFolder.png", thumbnailImage=iconimage)
liz.setInfo( type="Video", infoLabels={ "Title": name } )
liz.setProperty( "Fanart_Image", fanart )
if not isfolder:
liz.setProperty("IsPlayable", "true")
menuitems = []
if islatest:
next_url = composePluginUrl(url,MODE_LIST_NEXT_EPISODES,name)
menuitems.append(( getLS(30004).encode('utf-8'), 'XBMC.Container.Update('+next_url+')' ))
if quality_index != 0:
select_quality_url = composePluginUrl(url,MODE_VIDEOLINK,name)
menuitems.append(( getLS(30005).encode('utf-8'), 'XBMC.Container.Update('+select_quality_url+')' ))
liz.addContextMenuItems(menuitems)
ok=xbmcplugin.addDirectoryItem(handle=addonHandle,url=u,listitem=liz,isFolder=isfolder)
return ok
def addDir(name,url,mode,iconimage):
logDbg("addDir(): '"+name+"' url='"+url+"' icon='"+iconimage+"' mode='"+str(mode)+"'")
return addItem(name,url,mode,iconimage,True)
def addUnresolvedLink(name,url,iconimage,islatest=False):
mode=MODE_RESOLVE_VIDEOLINK
logDbg("addUnresolvedLink(): '"+name+"' url='"+url+"' icon='"+iconimage+"' mode='"+str(mode)+"'")
return addItem(name,url,mode,iconimage,False,islatest)
addonHandle=int(sys.argv[1])
params=getParams()
url=None
name=None
thumb=None
mode=None
try:
url=urllib.unquote_plus(params["url"])
except:
pass
try:
name=urllib.unquote_plus(params["name"])
except:
pass
try:
mode=int(params["mode"])
except:
pass
logDbg("Mode: "+str(mode))
logDbg("URL: "+str(url))
logDbg("Name: "+str(name))
if mode==None or url==None or len(url)<1:
STATS("OBSAH", "Function")
listContent()
elif mode==MODE_LIST_SHOWS:
STATS("LIST_SHOWS", "Function")
listShows(url)
elif mode==MODE_LIST_SEASON:
STATS("LIST_SEASON", "Function")
listSeasons(url)
elif mode==MODE_LIST_EPISODES:
STATS("LIST_EPISODES", "Function")
listEpisodes(url)
elif mode==MODE_VIDEOLINK:
STATS(name, "Item")
videoLink(url,name)
elif mode==MODE_RESOLVE_VIDEOLINK:
resolveVideoLink(url,name)
STATS(name, "Item")
sys.exit(0)
elif mode==MODE_LIST_NEXT_EPISODES:
STATS("LIST_NEXT_EPISODES", "Function")
listNextEpisodes(url)
xbmcplugin.endOfDirectory(addonHandle)