diff options
Diffstat (limited to 'plugin.video.psvue/resources/lib/ps_vue.py')
-rw-r--r-- | plugin.video.psvue/resources/lib/ps_vue.py | 403 |
1 files changed, 403 insertions, 0 deletions
diff --git a/plugin.video.psvue/resources/lib/ps_vue.py b/plugin.video.psvue/resources/lib/ps_vue.py new file mode 100644 index 0000000..333d652 --- /dev/null +++ b/plugin.video.psvue/resources/lib/ps_vue.py @@ -0,0 +1,403 @@ +import sys, os +import xbmc, xbmcplugin, xbmcgui, xbmcaddon +import random +import cookielib, urllib +import json +import requests +import time, calendar +from datetime import date, datetime, timedelta +from sony import SONY + + +def main_menu(): + addDir(LOCAL_STRING(30100), 50, ICON) + addDir(LOCAL_STRING(30101), 100, ICON) + addDir(LOCAL_STRING(30102), 200, ICON) + addDir(LOCAL_STRING(30103), 300, ICON) + addDir(LOCAL_STRING(30104), 400, ICON) + addDir(LOCAL_STRING(30105), 500, ICON) + addDir(LOCAL_STRING(30106), 600, ICON) + addDir(LOCAL_STRING(30107), 700, ICON) + + +def timeline(): + list_timeline() + + +def my_shows(): + json_source = get_json(EPG_URL + '/browse/items/favorites/filter/shows/sort/title/offset/0/size/100') + list_shows(json_source['body']['items']) + + +def favorite_channels(): + json_source = get_json(EPG_URL + '/browse/items/favorites/filter/channels/sort/name/offset/0/size/100') + list_channels(json_source['body']['items']) + + +def live_tv(): + json_source = get_json(EPG_URL + '/browse/items/now_playing/filter/all/sort/channel/offset/0/size/100') + list_channels(json_source['body']['items']) + + +def sports(): + json_source = get_json(EPG_URL + '/programs?size=10&offset=0&filter=ds-sports') + list_shows(json_source['body']['items']) + + +def kids(): + json_source = get_json(EPG_URL + '/programs?size=10&offset=0&filter=ds-kids') + list_shows(json_source['body']['items']) + + +def recently_watched(): + json_source = get_json(EPG_URL + '/browse/items/recently_watched/filter/shows/sort/watched_date/offset/0/size/35') + list_shows(json_source['body']['items']) + + +def featured(): + json_source = get_json(EPG_URL + '/browse/items/featured/filter/shows/sort/featured/offset/0/size/100') + list_shows(json_source['body']['items']) + + +def list_timeline(): + url = 'https://sentv-user-ext.totsuko.tv/sentv_user_ext/ws/v2/profile/ids' + airing_id = get_json(url)['body']['launch_program']['airing_id'] + + json_source = get_json(EPG_URL + '/timeline/' + str(airing_id)) + + for strand in json_source['body']['strands']: + if strand['id'] == 'now_playing': + addDir('[B][I][COLOR=FFFFFF66]Now Playing[/COLOR][/B][/I]', 998, ICON) + for program in strand['programs']: + #list_channel(program) + list_episode(program) + elif strand['id'] == 'watched_episodes': + addDir('[B][I][COLOR=FFFFFF66]Watched Episodes[/COLOR][/B][/I]', 998, ICON) + for program in reversed(strand['programs']): + list_episode(program) + elif strand['id'] == 'coming_up': + addDir('[B][I][COLOR=FFFFFF66]Coming Up[/COLOR][/B][/I]', 998, ICON) + for program in strand['programs']: + list_episode(program) + + +def list_shows(json_source): + for show in json_source: + list_show(show) + + +def list_show(show): + fanart = FANART + icon = ICON + for image in show['urls']: + if 'width' in image: + if image['width'] == 600: icon = image['src'] + if image['width'] >= 1080: fanart = image['src'] + if icon != ICON and fanart != FANART: break + title = show['title'] + show_id = str(show['id']) + + genre = '' + for item in show['genres']: + if genre != '': genre += ', ' + genre += item['genre'] + + plot = get_dict_item('series_synopsis', show) + if plot == '': plot = get_dict_item('synopsis', show) + + + # if watched = true look in airing for last time code + # "last_timecode": "00:10:54", + + # channel_url = CHANNEL_URL+'/'+show_id + # show_url = 'https://media-framework.totsuko.tv/media-framework/media/v2.1/stream/airing/'+airing_id + + info = {'plot': plot, 'tvshowtitle': title, 'title': title, 'originaltitle': title, 'genre': genre} + # addStream(title,show_url,title,icon,fanart,info) + addDir(title, 150, icon, fanart, info, show_id) + + +def list_episodes(show_id): + url = EPG_URL + '/details/items/program/' + show_id + '/episodes/offset/0/size/20' + + json_source = get_json(url) + + # Sort by airing_date newest to oldest + json_source = json_source['body']['items'] + json_source = sorted(json_source, key=lambda k: k['airing_date'], reverse=True) + + for show in json_source: + list_episode(show) + + +def list_episode(show): + # if str(show['playable']).upper() == 'FALSE': return + fanart = FANART + icon = ICON + for image in show['urls']: + if 'width' in image: + if image['width'] == 600: icon = image['src'] + if image['width'] >= 1080: fanart = image['src'] + if icon != ICON and fanart != FANART: break + + # Set variables from json + show_title = show['title'] + title = show['display_episode_title'] + airing_id = str(show['airings'][0]['airing_id']) + airing_date = show['airing_date'] + airing_date = stringToDate(airing_date, "%Y-%m-%dT%H:%M:%S.%fZ") + airing_date = UTCToLocal(airing_date) + broadcast_date = '' + if 'broadcast_date' in show: + broadcast_date = show['broadcast_date'] + broadcast_date = stringToDate(broadcast_date, "%Y-%m-%dT%H:%M:%S.%fZ") + broadcast_date = UTCToLocal(broadcast_date) + + genre = '' + for item in show['genres']: + if genre != '': genre += ', ' + genre += item['genre'] + + plot = get_dict_item('synopsis', show) + + if str(show['playable']).upper() == 'FALSE': + # Add airing date/time to title + # airing = airing.strftime('%H:%M') + title = title + ' ' + airing_date.strftime('%m/%d/%y') + ' ' + airing_date.strftime('%I:%M %p').lstrip('0') + + + # if watched = true look in airing for last time code + # "last_timecode": "00:10:54", + + # channel_url = CHANNEL_URL+'/'+show_id + show_url = 'https://media-framework.totsuko.tv/media-framework/media/v2.1/stream/airing/' + airing_id + + info = {'plot': plot, 'tvshowtitle': show_title, 'title': title, 'originaltitle': title, 'genre': genre, + 'aired': airing_date.strftime('%Y-%m-%d'), 'premiered': broadcast_date.strftime('%Y-%m-%d')} + + + addStream(title, show_url, title, icon, fanart, info) + + +def list_channels(json_source): + for channel in json_source: + list_channel(channel) + + +def list_channel(channel): + fanart = FANART + icon = ICON + for image in channel['urls']: + if 'width' in image: + if image['width'] == 600 or image['width'] == 440: icon = image['src'] + if image['width'] == 1920: fanart = image['src'] + if icon != ICON and fanart != FANART: break + + if 'channel' in channel: + title = channel['channel']['name'] + channel_id = str(channel['channel']['channel_id']) + else: + title = channel['title'] + channel_id = str(channel['id']) + + genre = '' + for item in channel['genres']: + if genre != '': genre += ', ' + genre += item['genre'] + + plot = get_dict_item('synopsis', channel) + season = get_dict_item('season_num', channel) + episode = get_dict_item('episode_num', channel) + + channel_url = CHANNEL_URL + '/' + channel_id + + info = {'season':season, 'episode':episode, 'plot': plot, 'tvshowtitle': title, 'title': title, 'originaltitle': title, 'genre': genre} + + addStream(title, channel_url, title, icon, fanart, info) + + +def get_dict_item(key, dictionary): + if key in dictionary: + return dictionary[key] + else: + return '' + + +def get_stream(url): + headers = {"Accept": "*/*", + "Content-type": "application/x-www-form-urlencoded", + "Origin": "https://vue.playstation.com", + "Accept-Language": "en-US,en;q=0.8", + "Referer": "https://vue.playstation.com/watch/live", + "Accept-Encoding": "deflate", + "User-Agent": UA_ANDROID, + "Connection": "Keep-Alive", + 'reqPayload': ADDON.getSetting(id='reqPayload') + } + + r = requests.get(url, headers=headers, cookies=load_cookies(), verify=VERIFY) + json_source = r.json() + stream_url = json_source['body']['video'] + stream_url = stream_url + '|User-Agent=Dalvik/2.1.0 (Linux; U; Android 6.0.1 Build/MOB31H)&Cookie=reqPayload=' + urllib.quote('"' + ADDON.getSetting(id='reqPayload') + '"') + + listitem = xbmcgui.ListItem(path=stream_url) + # listitem.setProperty('ResumeTime', '600') + # listitem.setProperty('setResumePoint', '600') + + xbmcplugin.setResolvedUrl(addon_handle, True, listitem) + + # Seek to time + ''' + monitor = xbmc.Monitor() + monitor.waitForAbort(3000) + if xbmc.Player().isPlayingVideo(): + xbmc.Player().seekTime(600) + ''' + + +def get_json(url): + headers = {'Accept': '*/*', + 'reqPayload': ADDON.getSetting(id='reqPayload'), + 'User-Agent': UA_ANDROID, + 'Accept-Encoding': 'gzip, deflate', + 'Accept-Language': 'en-US', + 'X-Requested-With': 'com.snei.vue.android' + } + + r = requests.get(url, headers=headers, cookies=load_cookies(), verify=VERIFY) + + if r.status_code != 200: + dialog = xbmcgui.Dialog() + msg = 'The request could not be completed.' + try: + json_source = r.json() + msg = json_source['header']['error']['message'] + except: + pass + dialog.notification('Error '+str(r.status_code), msg, xbmcgui.NOTIFICATION_INFO, 5000) + sys.exit() + + return r.json() + + +def load_cookies(): + filename = os.path.join(ADDON_PATH_PROFILE, 'cookies.lwp') + lwp_cookiejar = cookielib.LWPCookieJar() + try: + lwp_cookiejar.load(filename, ignore_discard=True) + except: + pass + + return lwp_cookiejar + + +def stringToDate(string, date_format): + try: + date = datetime.strptime(str(string), date_format) + except TypeError: + date = datetime(*(time.strptime(str(string), date_format)[0:6])) + + return date + + +def create_device_id(): + android_id = ''.join(random.choice('0123456789abcdef') for i in range(16)) + android_id = android_id.rjust(30, '0') + manufacturer = 'ASUS' + model = 'Nexus 7' + manf_model = ":%s:%s" % (manufacturer.rjust(10, ' '), model.rjust(10, ' ')) + manf_model = manf_model.encode("hex") + zero = '0' + device_id = "0000%s%s01a8%s%s" % ("0007", "0002", android_id, manf_model + zero.ljust(32, '0')) + + ADDON.setSetting(id='deviceId', value=device_id) + + +def findString(source, start_str, end_str): + start = source.find(start_str) + end = source.find(end_str, start + len(start_str)) + + if start != -1: + return source[start + len(start_str):end] + else: + return '' + + +def UTCToLocal(utc_dt): + # get integer timestamp to avoid precision lost + timestamp = calendar.timegm(utc_dt.timetuple()) + local_dt = datetime.fromtimestamp(timestamp) + assert utc_dt.resolution >= timedelta(microseconds=1) + return local_dt.replace(microsecond=utc_dt.microsecond) + + +def addDir(name, mode, icon, fanart=None, info=None, show_id=None): + u = sys.argv[0] + "?mode=" + str(mode) + if show_id != None: u += '&show_id=' + show_id + + liz = xbmcgui.ListItem(name) + if fanart == None: fanart = FANART + liz.setArt({'icon': icon, 'thumb': icon, 'fanart': fanart}) + if info != None: + liz.setInfo(type="Video", infoLabels=info) + + ok = xbmcplugin.addDirectoryItem(handle=addon_handle, url=u, listitem=liz, isFolder=True) + xbmcplugin.setContent(addon_handle, 'tvshows') + return ok + + +def addStream(name, link_url, title, icon, fanart, info=None): + u = sys.argv[0] + "?url=" + urllib.quote_plus(link_url) + "&mode=" + str(900) + liz = xbmcgui.ListItem(name) + liz.setArt({'icon': icon, 'thumb': icon, 'fanart': fanart}) + liz.setProperty("IsPlayable", "true") + # liz.setProperty('setResumePoint', '1200') + liz.setInfo(type="Video", infoLabels={"Title": title, 'mediatype': 'episode'}) + if info != None: + liz.setInfo(type="Video", infoLabels=info) + ok = xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=u, listitem=liz, isFolder=False) + xbmcplugin.setContent(addon_handle, 'tvshows') + return ok + + +def get_params(): + 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 + + +addon_handle = int(sys.argv[1]) +ADDON = xbmcaddon.Addon() +ROOTDIR = ADDON.getAddonInfo('path') +LOCAL_STRING = ADDON.getLocalizedString +FANART = os.path.join(ROOTDIR, "resources", "fanart.jpg") +ICON = os.path.join(ROOTDIR, "resources", "icon.png") + +ADDON_PATH_PROFILE = xbmc.translatePath(ADDON.getAddonInfo('profile')) +DEVICE_ID = ADDON.getSetting(id='deviceId') + +amazon_device = 'Amazon' +amazon_device = amazon_device.encode("hex") +if amazon_device in DEVICE_ID: DEVICE_ID = '' + +if DEVICE_ID == '': + create_device_id() + DEVICE_ID = ADDON.getSetting(id='deviceId') + +UA_ANDROID = 'Mozilla/5.0 (Linux; Android 6.0.1; Build/MOB31H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/44.0.2403.119 Safari/537.36' +CHANNEL_URL = 'https://media-framework.totsuko.tv/media-framework/media/v2.1/stream/channel' +EPG_URL = 'https://epg-service.totsuko.tv/epg_service_sony/service/v2' +VERIFY = False |