Last active
April 10, 2020 22:31
-
-
Save darkarnium/023fb8e9c573fa5e7c399a42428f2989 to your computer and use it in GitHub Desktop.
Janky ass patch for plugin.video.plutotv/resources/lib/plutotv.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -w /tmp/a /tmp/b | |
203,205c203,207 | |
< tz = str(timezone()) | |
< start = datetime.datetime.now().strftime('%Y-%m-%dT%H:00:00').replace('T','%20').replace(':00:00','%3A00%3A00.000'+tz) | |
< stop = (datetime.datetime.now() + datetime.timedelta(hours=4)).strftime('%Y-%m-%dT%H:00:00').replace('T','%20').replace(':00:00','%3A00%3A00.000'+tz) | |
--- | |
> tz = timezone() | |
> tz = '{0:04d}'.format(timezone()) | |
> tz = '%2B{}{}:{}{}'.format(*list(tz)) | |
> start = datetime.datetime.now().strftime('%Y-%m-%dT%H:00:00') + tz | |
> stop = (datetime.datetime.now() + datetime.timedelta(hours=4)).strftime('%Y-%m-%dT%H:00:00') + tz | |
474a477,507 | |
> xbmc.log(str(url), xbmc.LOGERROR) | |
> | |
> if 'deviceModel' not in url: | |
> url += '&deviceModel=Chrome' | |
> if 'deviceType' not in url: | |
> url += '&deviceType=web' | |
> if 'deviceMake' not in url: | |
> url += '&deviceMake=Chrome' | |
> if 'appName' not in url: | |
> url += '&appName=web' | |
> if 'appVersion' not in url: | |
> url += '&appVersion=unknown' | |
> if 'deviceDNT' not in url: | |
> url += '&deviceDNT=0' | |
> if 'deviceLat' not in url: | |
> url += '&deviceLat=53.7548428' | |
> if 'deviceLon' not in url: | |
> url += '&deviceLon=-1.4675813' | |
> if 'deviceVersion' not in url: | |
> url += '&deviceVersion=unknown' | |
> if 'deviceId' not in url: | |
> url += '&deviceId=' + str(uuid.uuid4()) | |
> if 'architecture' not in url: | |
> url += '&architecture=' | |
> if 'sid' not in url: | |
> url += '&sid=' + str(uuid.uuid4()) | |
> if 'userId' not in url: | |
> url += '&userId=' | |
> if 'clientTime' not in url: | |
> url += '&clientTime=' | |
> | |
478a512 | |
> xbmc.log(str(liz), xbmc.LOGERROR) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Copyright (C) 2020 Lunatixz | |
# | |
# | |
# This file is part of PlutoTV. | |
# | |
# PlutoTV 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. | |
# | |
# PlutoTV 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 PlutoTV. If not, see <http://www.gnu.org/licenses/>. | |
# -*- coding: utf-8 -*- | |
import os, sys, time, _strptime, datetime, net, re, traceback, uuid | |
import socket, json, collections, inputstreamhelper | |
import xbmc, xbmcgui, xbmcplugin, xbmcvfs, xbmcaddon | |
from six.moves import urllib | |
from itertools import repeat | |
from simplecache import SimpleCache, use_cache | |
try: | |
from multiprocessing import cpu_count | |
from multiprocessing.pool import ThreadPool | |
ENABLE_POOL = True | |
CORES = cpu_count() | |
except: ENABLE_POOL = False | |
# Plugin Info | |
ADDON_ID = 'plugin.video.plutotv' | |
REAL_SETTINGS = xbmcaddon.Addon(id=ADDON_ID) | |
ADDON_NAME = REAL_SETTINGS.getAddonInfo('name') | |
SETTINGS_LOC = REAL_SETTINGS.getAddonInfo('profile') | |
ADDON_PATH = REAL_SETTINGS.getAddonInfo('path') | |
ADDON_VERSION = REAL_SETTINGS.getAddonInfo('version') | |
ICON = REAL_SETTINGS.getAddonInfo('icon') | |
FANART = REAL_SETTINGS.getAddonInfo('fanart') | |
LANGUAGE = REAL_SETTINGS.getLocalizedString | |
## GLOBALS ## | |
TIMEOUT = 15 | |
CONTENT_TYPE = 'files' | |
DISC_CACHE = True | |
USER_EMAIL = REAL_SETTINGS.getSetting('User_Email') | |
PASSWORD = REAL_SETTINGS.getSetting('User_Password') | |
DEBUG = REAL_SETTINGS.getSetting('Enable_Debugging') == 'true' | |
COOKIE_JAR = xbmc.translatePath(os.path.join(SETTINGS_LOC, "cookiejar.lwp")) | |
PTVL_RUN = xbmcgui.Window(10000).getProperty('PseudoTVRunning') == 'True' | |
BASE_API = 'https://api.pluto.tv' | |
BASE_LINEUP = BASE_API + '/v2/channels.json' | |
BASE_GUIDE = BASE_API + '/v2/channels?start=%s&stop=%s&%s' | |
LOGIN_URL = BASE_API + '/v1/auth/local' | |
BASE_CLIPS = BASE_API + '/v2/episodes/%s/clips.json' | |
BASE_VOD = BASE_API + '/v3/vod/categories?includeItems=true&deviceType=web&%s' | |
SEASON_VOD = BASE_API + '/v3/vod/series/%s/seasons?includeItems=true&deviceType=web&%s' | |
PLUTO_MENU = [(LANGUAGE(30011), '', 0), | |
(LANGUAGE(30018), '', 1), | |
(LANGUAGE(30017), '', 2), | |
(LANGUAGE(30012), '', 3), | |
(LANGUAGE(30013), '', 20)] | |
def inputDialog(heading=ADDON_NAME, default='', key=xbmcgui.INPUT_ALPHANUM, opt=0, close=0): | |
retval = xbmcgui.Dialog().input(heading, default, key, opt, close) | |
if len(retval) > 0: return retval | |
def notificationDialog(message, header=ADDON_NAME, show=True, sound=False, time=1000, icon=ICON): | |
try: xbmcgui.Dialog().notification(header, message, icon, time, sound=False) | |
except: xbmc.executebuiltin("Notification(%s, %s, %d, %s)" % (header, message, time, icon)) | |
def yesnoDialog(str1, str2='', str3='', header=ADDON_NAME, yes='', no='', autoclose=0): | |
return xbmcgui.Dialog().yesno(header, str1, str2, str3, no, yes, autoclose) | |
def strpTime(datestring, format='%Y-%m-%d %H:%M:%S'): | |
try: return datetime.datetime.strptime(datestring, format) | |
except TypeError: return datetime.datetime.fromtimestamp(time.mktime(time.strptime(datestring, format))) | |
def timezone(): | |
if time.localtime(time.time()).tm_isdst and time.daylight: return time.altzone / -(60*60) * 100 | |
else: return time.timezone / -(60*60) * 100 | |
def setUUID(): | |
if REAL_SETTINGS.getSetting("sid1"): return | |
log('setUUID, creating uuid') | |
REAL_SETTINGS.setSetting("sid1",str(uuid.uuid1())) | |
REAL_SETTINGS.setSetting("deviceId1",str(uuid.uuid4())) | |
def getUUID(): | |
return REAL_SETTINGS.getSetting("sid1"), REAL_SETTINGS.getSetting("deviceId1") | |
def cookieJar(): | |
if not xbmcvfs.exists(COOKIE_JAR): | |
try: | |
xbmcvfs.mkdirs(SETTINGS_LOC) | |
f = xbmcvfs.File(COOKIE_JAR, 'w') | |
f.close() | |
except: log('login, Unable to create cookie folder', xbmc.LOGERROR) | |
def log(msg, level=xbmc.LOGDEBUG): | |
if DEBUG == False and level != xbmc.LOGERROR: return | |
if level == xbmc.LOGERROR: msg += ' ,' + traceback.format_exc() | |
xbmc.log(ADDON_ID + '-' + ADDON_VERSION + '-' + msg, level) | |
socket.setdefaulttimeout(TIMEOUT) | |
class PlutoTV(object): | |
def __init__(self, sysARG): | |
log('__init__, sysARG = ' + str(sysARG)) | |
self.sysARG = sysARG | |
self.net = net.Net() | |
self.cache = SimpleCache() | |
def login(self): | |
log('login') | |
setUUID() | |
cookieJar() | |
if USER_EMAIL == LANGUAGE(30009): return #ignore, using guest login | |
if len(USER_EMAIL) > 0: | |
header_dict = {} | |
header_dict['Accept'] = 'application/json, text/javascript, */*; q=0.01' | |
header_dict['Host'] = 'api.pluto.tv' | |
header_dict['Connection'] = 'keep-alive' | |
header_dict['Referer'] = 'http://pluto.tv/' | |
header_dict['Origin'] = 'http://pluto.tv' | |
header_dict['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.2; rv:24.0) Gecko/20100101 Firefox/24.0' | |
form_data = ({'optIn': 'true', 'password': PASSWORD,'synced': 'false', 'userIdentity': USER_EMAIL}) | |
self.net.set_cookies(COOKIE_JAR) | |
try: | |
loginlink = json.loads(self.net.http_POST(LOGIN_URL, form_data=form_data, headers=header_dict).content.encode("utf-8").rstrip()) | |
if loginlink and loginlink['email'].lower() == USER_EMAIL.lower(): | |
notificationDialog(LANGUAGE(30006)%(loginlink['displayName']), time=4000) | |
self.net.save_cookies(COOKIE_JAR) | |
else: notificationDialog(LANGUAGE(30007), time=4000) | |
except Exception as e: log('login, failed! ' + str(e), xbmc.LOGERROR) | |
else: | |
#firstrun wizard | |
if yesnoDialog(LANGUAGE(30008),no=LANGUAGE(30009), yes=LANGUAGE(30010)): | |
REAL_SETTINGS.setSetting('User_Email',inputDialog(LANGUAGE(30001))) | |
REAL_SETTINGS.setSetting('User_Password',inputDialog(LANGUAGE(30002))) | |
else: REAL_SETTINGS.setSetting('User_Email',LANGUAGE(30009)) | |
def openURL(self, url, life=datetime.timedelta(minutes=15)): | |
log('openURL, url = ' + url) | |
try: | |
header_dict = {} | |
header_dict['Accept'] = 'application/json, text/javascript, */*; q=0.01' | |
header_dict['Host'] = 'api.pluto.tv' | |
header_dict['Connection'] = 'keep-alive' | |
header_dict['Referer'] = 'http://pluto.tv/' | |
header_dict['Origin'] = 'http://pluto.tv' | |
header_dict['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.2; rv:24.0) Gecko/20100101 Firefox/24.0' | |
self.net.set_cookies(COOKIE_JAR) | |
trans_table = ''.join( [chr(i) for i in range(128)] + [' '] * 128 ) | |
cacheResponse = self.cache.get(ADDON_NAME + '.openURL, url = %s'%url) | |
if not cacheResponse: | |
try: cacheResponse = self.net.http_GET(url, headers=header_dict).content.encode("utf-8", 'ignore') | |
except: cacheResponse = (self.net.http_GET(url, headers=header_dict).content.translate(trans_table)).encode("utf-8") | |
self.net.save_cookies(COOKIE_JAR) | |
self.cache.set(ADDON_NAME + '.openURL, url = %s'%url, cacheResponse, expiration=life) | |
if isinstance(cacheResponse, basestring): cacheResponse = json.loads(cacheResponse) | |
return cacheResponse | |
except Exception as e: | |
log('openURL, Unable to open url ' + str(e), xbmc.LOGERROR) | |
notificationDialog(LANGUAGE(30028), time=4000) | |
return {} | |
def mainMenu(self): | |
log('mainMenu') | |
self.login() | |
for item in PLUTO_MENU: self.addDir(*item) | |
def browseMenu(self): | |
log('browseMenu') | |
categoryMenu = self.getCategories() | |
for item in categoryMenu: self.addDir(*item) | |
def getOndemand(self): | |
return self.openURL(BASE_VOD%(LANGUAGE(30022)%(getUUID())), life=datetime.timedelta(hours=1)) | |
def getVOD(self, epid): | |
return self.openURL(SEASON_VOD%(epid,LANGUAGE(30022)%(getUUID())), life=datetime.timedelta(hours=1)) | |
def getClips(self, epid): | |
return self.openURL(BASE_CLIPS%(epid), life=datetime.timedelta(hours=1)) | |
def getChannels(self): | |
return sorted(self.openURL(BASE_LINEUP, life=datetime.timedelta(hours=1)), key=lambda i: i['number']) | |
def getGuidedata(self): | |
tz = timezone() | |
tz = '{0:04d}'.format(timezone()) | |
tz = '%2B{}{}:{}{}'.format(*list(tz)) | |
start = datetime.datetime.now().strftime('%Y-%m-%dT%H:00:00') + tz | |
stop = (datetime.datetime.now() + datetime.timedelta(hours=4)).strftime('%Y-%m-%dT%H:00:00') + tz | |
return sorted((self.openURL(BASE_GUIDE %(start,stop,'sid=%s&deviceId=%s'%(getUUID())), life=datetime.timedelta(hours=1))), key=lambda i: i['number']) | |
def getCategories(self): | |
log('getCategories') | |
collect= [] | |
data = self.getChannels() | |
for channel in data: collect.append(channel['category']) | |
counter = collections.Counter(collect) | |
for key, value in sorted(counter.iteritems()): yield (key,'categories', 0) | |
def getMediaTypes(self, genre): | |
if type == 'Movies': return 'movie' | |
elif type == 'TV': return 'episode' | |
elif type == 'Music + Radio': return 'musicvideo' | |
else: return 'video' | |
def pagination(self, seq, rowlen): | |
for start in xrange(0, len(seq), rowlen): yield seq[start:start+rowlen] | |
def buildGuide(self, data): | |
channel, name, opt = data | |
log('buildGuide, name=%s,opt=%s'%(name, opt)) | |
urls = [] | |
guidedata = [] | |
newChannel= {} | |
mtype = 'video' | |
chid = channel.get('_id','') | |
chname = channel.get('name','') | |
chnum = channel.get('number','') | |
chplot = (channel.get('description','') or channel.get('summary','')) | |
chgeo = channel.get('visibility','everyone') != 'everyone' | |
chcat = (channel.get('category','') or channel.get('genre','')) | |
chfanart = channel.get('featuredImage',{}).get('path',FANART) | |
chthumb = channel.get('thumbnail',{}).get('path',ICON) | |
chlogo = channel.get('logo',{}).get('path',ICON) | |
ondemand = channel.get('onDemand','false') == 'true' | |
featured = channel.get('featured','false') == 'true' | |
favorite = channel.get('favorite','false') == 'true' | |
timelines = channel.get('timelines',[]) | |
if name == 'featured' and not featured: return None | |
elif name == 'favorite' and not favorite: return None | |
elif name == 'categories' and chcat != opt: return None | |
elif name == 'lineup' and chid != opt: return None | |
elif name == 'live': DISC_CACHE = False | |
if name in ['channels','categories','ondemand','season']: | |
if name == 'season': | |
seasons = (channel.get('seasons',{})) | |
vodimages = channel.get('covers',[]) | |
try: vodlogo = [image.get('url',[]) for image in vodimages if image.get('aspectRatio','') == '1:1'][0] | |
except: vodlogo = ICON | |
try: vodfanart = [image.get('url',[]) for image in vodimages if image.get('aspectRatio','') == '16:9'][0] | |
except: vodfanart = FANART | |
for season in seasons: | |
mtype = 'episode' | |
label = 'Season %s'%(season['number']) | |
infoLabels = {"mediatype":mtype,"label":label,"label2":label,"title":chname,"plot":chplot, "code":chid, "genre":[chcat]} | |
infoArt = {"thumb":vodlogo,"poster":vodlogo,"fanart":vodfanart,"icon":vodlogo,"logo":vodlogo,"clearart":chthumb} | |
self.addDir(label, chid, 5, infoLabels, infoArt) | |
else: | |
if name == 'ondemand': | |
mode = 3 | |
label = chname | |
else: | |
mode = 1 | |
label = '%s| %s'%(chnum,chname) | |
infoLabels = {"mediatype":mtype,"label":label,"label2":label,"title":label,"plot":chplot, "code":chid, "genre":[chcat]} | |
infoArt = {"thumb":chthumb,"poster":chthumb,"fanart":chfanart,"icon":chlogo,"logo":chlogo,"clearart":chthumb} | |
self.addDir(label, chid, mode, infoLabels, infoArt) | |
else: | |
newChannel['channelname'] = chname | |
newChannel['channelnumber'] = chnum | |
newChannel['channellogo'] = chlogo | |
newChannel['isfavorite'] = favorite | |
urls = channel.get('stitched',{}).get('urls',[]) | |
if not timelines: | |
name = 'ondemand' | |
timelines = (channel.get('items',[]) or channel.get('episodes',[])) | |
now = datetime.datetime.now() | |
totstart = now | |
tz = (timezone()//100)*60*60 | |
for item in timelines: | |
episode = (item.get('episode',{}) or item) | |
series = (episode.get('series',{}) or item) | |
epdur = int(episode.get('duration','0') or '0') // 1000 | |
urls = (item.get('stitched',{}).get('urls',[]) or urls) | |
if len(urls) == 0: continue | |
if isinstance(urls, list): urls = [url['url'] for url in urls if url['type'].lower() == 'hls'][0] # todo select quality | |
try: | |
start = strpTime(item['start'],'%Y-%m-%dT%H:%M:00.000Z') + datetime.timedelta(seconds=tz) | |
stop = strpTime(item['stop'],'%Y-%m-%dT%H:%M:00.000Z') + datetime.timedelta(seconds=tz) | |
except: | |
start = totstart | |
stop = start + datetime.timedelta(seconds=epdur) | |
totstart = stop | |
type = series.get('type','') | |
tvtitle = series.get('name','' or chname) | |
title = (item.get('title','')) | |
tvplot = (series.get('description','') or series.get('summary','') or chplot) | |
tvoutline = (series.get('summary','') or series.get('description','') or chplot) | |
tvthumb = (series.get('title',{}).get('path','') or chthumb) | |
tvfanart = (series.get('featuredImage',{}).get('path','') or chfanart) | |
epid = episode['_id'] | |
epnumber = episode.get('number',0) | |
epseason = episode.get('season',0) | |
epname = (episode['name']) | |
epplot = (episode.get('description','') or tvplot or epname) | |
epgenre = (episode.get('genre','') or chcat) | |
eptag = episode.get('subGenre','') | |
epmpaa = episode.get('rating','') | |
vodimages = episode.get('covers',[]) | |
vodposter = vodfanart = vodthumb = vodlogo = '' | |
if vodimages: | |
try: vodposter = [image.get('url',[]) for image in vodimages if image.get('aspectRatio','') == '347:500'][0] | |
except: pass | |
try: vodfanart = [image.get('url',[]) for image in vodimages if image.get('aspectRatio','') == '16:9'][0] | |
except: pass | |
try: vodthumb = [image.get('url',[]) for image in vodimages if image.get('aspectRatio','') == '4:3'][0] | |
except: pass | |
try: vodlogo = [image.get('url',[]) for image in vodimages if image.get('aspectRatio','') == '1:1'][0] | |
except: pass | |
chlogo = (vodlogo or chlogo) | |
epposter = (episode.get('poster',{}).get('path','') or vodlogo or vodposter or vodthumb or tvthumb) | |
epthumb = (episode.get('thumbnail',{}).get('path','') or vodlogo or vodthumb or vodposter or tvthumb) | |
epfanart = (episode.get('featuredImage',{}).get('path','') or vodfanart or tvfanart) | |
epislive = episode.get('liveBroadcast','false') == 'true' | |
label = title | |
thumb = chthumb | |
if type in ['movie','film']: | |
mtype = 'movie' | |
thumb = epposter | |
elif type in ['tv','episode','series']: | |
mtype = 'episode' | |
thumb = epposter | |
if epseason > 0 and epnumber > 0: | |
label = '%sx%s'%(epseason, epnumber) | |
label = '%s - %s'%(label, epname) | |
# else: label = '%s - %s'%(tvtitle, label) | |
else: label = epname | |
epname = label | |
if type == 'music' or epgenre.lower() == 'music': mtype = 'musicvideo' | |
if name == 'live': | |
if stop < now or start > now: continue | |
# epdur = (now - start).seconds | |
label = '%s| %s'%(chnum,chname) | |
if type in ['movie','film']: | |
mtype = 'movie' | |
thumb = epposter | |
label = '%s :[B]%s[/B]'%(label, title) | |
elif type in ['tv','series']: | |
mtype = 'episode' | |
thumb = epposter | |
label = "%s :[B]%s - %s[/B]" % (label, tvtitle, epname) | |
elif len(epname) > 0: label = '%s :[B]%s - %s[/B]'%(label, title, epname) | |
epname = label | |
if type == 'music' or epgenre.lower() == 'music': mtype = 'musicvideo' | |
elif name == 'lineup': | |
if now > stop: continue | |
# elif start >= now and stop < now: epdur = (now - start).seconds | |
if type in ['movie','film']: | |
mtype = 'movie' | |
thumb = epposter | |
label = '%s'%(title) | |
elif type in ['tv','series']: | |
mtype = 'episode' | |
thumb = epposter | |
label = "%s - %s" % (tvtitle, epname) | |
elif len(epname) > 0: label = '%s - %s'%(title, epname) | |
epname = label | |
if type == 'music' or epgenre.lower() == 'music': mtype = 'musicvideo' | |
if now >= start and now < stop: | |
label = '%s - [B]%s[/B]'%(start.strftime('%I:%M %p').lstrip('0'),label) | |
else: | |
label = '%s - %s'%(start.strftime('%I:%M %p').lstrip('0'),label) | |
urls = 'NEXT_SHOW' | |
epname = label | |
tmpdata = {"mediatype":mtype,"label":label,"title":label,'duration':epdur,'plot':epplot,'genre':[epgenre],'season':epseason,'episode':epnumber} | |
tmpdata['starttime'] = time.mktime((start).timetuple()) | |
tmpdata['url'] = self.sysARG[0]+'?mode=9&name=%s&url=%s'%(title,urls) | |
tmpdata['art'] = {"thumb":thumb,"poster":epposter,"fanart":epfanart,"icon":chlogo,"logo":chlogo,"clearart":chthumb} | |
guidedata.append(tmpdata) | |
if name == 'ondemand' and type == "series": | |
mtype = 'season' | |
infoLabels = {"mediatype":mtype,"label":label,"label2":label,"title":label,"plot":epplot, "code":chid, "genre":[epgenre]} | |
infoArt = {"thumb":epthumb,"poster":epposter,"fanart":epfanart,"icon":chlogo,"logo":chlogo,"clearart":chthumb} | |
self.addDir(label, epid, 4, infoLabels, infoArt) | |
elif name != 'guide': | |
infoLabels = {"mediatype":mtype,"label":label,"label2":label,"tvshowtitle":tvtitle,"title":epname,"plot":epplot, "code":epid, "genre":[epgenre], "duration":epdur,'season':epseason,'episode':epnumber} | |
infoArt = {"thumb":thumb,"poster":epposter,"fanart":epfanart,"icon":chlogo,"logo":chlogo,"clearart":chthumb} | |
self.addLink(title, urls, 9, infoLabels, infoArt) | |
CONTENT_TYPE = '%ss'%mtype | |
if len(guidedata) > 0: | |
newChannel['guidedata'] = guidedata | |
return newChannel | |
def uEPG(self): | |
log('uEPG') | |
data = self.getGuidedata() | |
return urllib.parse.quote(json.dumps(list(self.poolList(self.buildGuide, zip(data,repeat('guide'),repeat('')))))) | |
def browseGuide(self, name, opt=None, data=None): | |
log('browseGuide, name=%s, opt=%s'%(name,opt)) | |
if data is None: data = self.getGuidedata() | |
if opt == 'categories': | |
opt = name | |
name = 'categories' | |
self.poolList(self.buildGuide, zip(data,repeat(name.lower()),repeat(opt))) | |
def browseLineup(self, name, opt=None): | |
log('browseLineup, opt=%s'%opt) | |
if opt is None: name = 'channels' | |
else: name = 'lineup' | |
self.browseGuide(name, opt) | |
def browseOndemand(self, opt=None): | |
log('browseOndemand') | |
data = self.getOndemand()['categories'] | |
if opt is None: name = 'ondemand' | |
else: name = 'lineup' | |
self.browseGuide(name, opt, data) | |
def browseSeason(self, opt=None): | |
log('browseSeason') | |
data = [self.getVOD(opt)] | |
self.browseGuide('season', opt, data) | |
def browseEpisodes(self, name, opt=None): | |
log('browseEpisodes') | |
season = int(name.split('Season ')[1]) | |
data = [self.getVOD(opt).get('seasons',[])[season - 1]] | |
self.browseGuide('episode', opt, data) | |
def browseCategories(self): | |
log('browseCategories') | |
data = list(self.getCategories()) | |
for item in data: self.addDir(*item) | |
def playVideo(self, name, url, liz=None): | |
if url.lower() == 'next_show': return notificationDialog(LANGUAGE(30029), time=4000) | |
if url.endswith('?deviceType='): url = url.replace('deviceType=','deviceType=&deviceMake=&deviceModel=&&deviceVersion=unknown&appVersion=unknown&deviceDNT=0&userId=&advertisingId=&app_name=&appName=&buildVersion=&appStoreUrl=&architecture=&includeExtendedEvents=false')#todo lazy fix replace | |
if 'sid' not in url: url = url.replace('deviceModel=&','deviceModel=&' + LANGUAGE(30022)%(getUUID())) | |
url = url.replace('deviceType=&','deviceType=web&').replace('deviceMake=&','deviceMake=Chrome&') .replace('deviceModel=&','deviceModel=Chrome&').replace('appName=&','appName=web&')#todo replace with regex! | |
log('playVideo, url = %s'%url) | |
xbmc.log(str(url), xbmc.LOGERROR) | |
if 'deviceModel' not in url: | |
url += '&deviceModel=Chrome' | |
if 'deviceType' not in url: | |
url += '&deviceType=web' | |
if 'deviceMake' not in url: | |
url += '&deviceMake=Chrome' | |
if 'appName' not in url: | |
url += '&appName=web' | |
if 'appVersion' not in url: | |
url += '&appVersion=unknown' | |
if 'deviceDNT' not in url: | |
url += '&deviceDNT=0' | |
if 'deviceLat' not in url: | |
url += '&deviceLat=53.7548428' | |
if 'deviceLon' not in url: | |
url += '&deviceLon=-1.4675813' | |
if 'deviceVersion' not in url: | |
url += '&deviceVersion=unknown' | |
if 'deviceId' not in url: | |
url += '&deviceId=' + str(uuid.uuid4()) | |
if 'architecture' not in url: | |
url += '&architecture=' | |
if 'sid' not in url: | |
url += '&sid=' + str(uuid.uuid4()) | |
if 'userId' not in url: | |
url += '&userId=' | |
if 'clientTime' not in url: | |
url += '&clientTime=' | |
if liz is None: liz = xbmcgui.ListItem(name, path=url) | |
if 'm3u8' in url.lower() and inputstreamhelper.Helper('hls').check_inputstream() and not DEBUG: | |
liz.setProperty('inputstreamaddon','inputstream.adaptive') | |
liz.setProperty('inputstream.adaptive.manifest_type','hls') | |
xbmc.log(str(liz), xbmc.LOGERROR) | |
xbmcplugin.setResolvedUrl(int(self.sysARG[1]), True, liz) | |
def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0): | |
name = name.encode("utf-8") | |
log('addLink, name = ' + name) | |
liz=xbmcgui.ListItem(name) | |
liz.setProperty('IsPlayable', 'true') | |
if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name}) | |
else: liz.setInfo(type="Video", infoLabels=infoList) | |
if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART}) | |
else: liz.setArt(infoArt) | |
u=self.sysARG[0]+"?url="+urllib.parse.quote(u)+"&mode="+str(mode)+"&name="+urllib.parse.quote(name) | |
xbmcplugin.addDirectoryItem(handle=int(self.sysARG[1]),url=u,listitem=liz,totalItems=total) | |
def addDir(self, name, u, mode, infoList=False, infoArt=False): | |
name = name.encode("utf-8") | |
log('addDir, name = ' + name) | |
liz=xbmcgui.ListItem(name) | |
liz.setProperty('IsPlayable', 'false') | |
if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name} ) | |
else: liz.setInfo(type="Video", infoLabels=infoList) | |
if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART}) | |
else: liz.setArt(infoArt) | |
u=self.sysARG[0]+"?url="+urllib.parse.quote(u)+"&mode="+str(mode)+"&name="+urllib.parse.quote(name) | |
xbmcplugin.addDirectoryItem(handle=int(self.sysARG[1]),url=u,listitem=liz,isFolder=True) | |
def poolList(self, method, items): | |
results = [] | |
if ENABLE_POOL and not DEBUG: | |
pool = ThreadPool(CORES) | |
results = pool.imap_unordered(method, items, chunksize=25) | |
pool.close() | |
pool.join() | |
else: results = [method(item) for item in items] | |
results = filter(None, results) | |
return results | |
def getParams(self): | |
return dict(urllib.parse.parse_qsl(self.sysARG[2][1:])) | |
def run(self): | |
params=self.getParams() | |
try: url=urllib.parse.unquote_plus(params["url"]) | |
except: url=None | |
try: name=urllib.parse.unquote_plus(params["name"]) | |
except: name=None | |
try: mode=int(params["mode"]) | |
except: mode=None | |
log("Mode: "+str(mode)) | |
log("URL : "+str(url)) | |
log("Name: "+str(name)) | |
if mode==None: self.mainMenu() | |
elif mode == 0: self.browseGuide(name, url) | |
elif mode == 1: self.browseLineup(name, url) | |
elif mode == 2: self.browseCategories() | |
elif mode == 3: self.browseOndemand(url) | |
elif mode == 4: self.browseSeason(url) | |
elif mode == 5: self.browseEpisodes(name, url) | |
elif mode == 9: self.playVideo(name, url) | |
elif mode == 20: xbmc.executebuiltin("RunScript(script.module.uepg,json=%s&skin_path=%s&refresh_path=%s&refresh_interval=%s&row_count=%s&include_hdhr=false)"%(self.uEPG(),urllib.parse.quote(ADDON_PATH),urllib.parse.quote(self.sysARG[0]+"?mode=20"),"7200","5")) | |
xbmcplugin.setContent(int(self.sysARG[1]) , CONTENT_TYPE) | |
xbmcplugin.addSortMethod(int(self.sysARG[1]) , xbmcplugin.SORT_METHOD_UNSORTED) | |
xbmcplugin.addSortMethod(int(self.sysARG[1]) , xbmcplugin.SORT_METHOD_NONE) | |
xbmcplugin.addSortMethod(int(self.sysARG[1]) , xbmcplugin.SORT_METHOD_LABEL) | |
xbmcplugin.addSortMethod(int(self.sysARG[1]) , xbmcplugin.SORT_METHOD_TITLE) | |
xbmcplugin.endOfDirectory(int(self.sysARG[1]), cacheToDisc=DISC_CACHE) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment