Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix live streams (revert manifest_update_parameter=full) and other improvements #8

Merged
merged 17 commits into from
Aug 5, 2020
Merged
2 changes: 1 addition & 1 deletion addon.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<import addon="script.module.pytz" version="2014.2"/>
<import addon="script.module.six" version="1.9.0"/>
<import addon="script.module.pil" version="1.1.7"/>
<import addon="script.module.inputstreamhelper" version="0.3.3"/>
<import addon="script.module.inputstreamhelper" version="0.5.0"/>
</requires>
<extension point="xbmc.python.pluginsource" library="main.py">
<provides>video</provides>
Expand Down
18 changes: 12 additions & 6 deletions src/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,31 @@
from utils import *


PROTOCOL = 'mpd'
DRM = 'com.widevine.alpha'
PROTOCOL = 'mpd' # TODO Handle other INPUTSTREAM_PROTOCOLS
DRM = 'com.widevine.alpha' # TODO Handle other DRM_SCHEMES
MIME_TYPE = 'application/dash+xml'
LICENSE_URL = 'https://shield-twoproxy.imggaming.com/proxy'


def get_playable_item(video):
def play(video):
item = None
if 'url' in video:
item = xbmcgui.ListItem(path=video['url'])
if '.%s' % PROTOCOL in video['url']:
from inputstreamhelper import Helper
is_helper = Helper(PROTOCOL, drm=DRM)
if is_helper.check_inputstream():
item.setProperty('inputstreamaddon', is_helper.inputstream_addon)
item.setMimeType(MIME_TYPE)
item.setContentLookup(False)
item.setProperty('inputstreamaddon', is_helper.inputstream_addon) # TODO Kodi version dep
item.setProperty('inputstream.adaptive.manifest_type', PROTOCOL)
item.setProperty('inputstream.adaptive.license_type', DRM)
item.setProperty('inputstream.adaptive.manifest_update_parameter', 'full')
license_key = '%s|authorization=bearer %s|R{SSM}|' % (LICENSE_URL, video['drm'])
item.setProperty('inputstream.adaptive.license_key', license_key)
return item

if item is not None:
xbmcplugin.setResolvedUrl(handle=int(sys.argv[1]), succeeded=True, listitem=item)

def updateFavTeam():
vars.fav_team_abbrs = None
Expand Down Expand Up @@ -73,7 +79,7 @@ def get_date(default='', heading='Please enter date (YYYY/MM/DD)', hidden=False)
keyboard.doModal()
ret = datetime.date.today()
if keyboard.isConfirmed():
sDate = unicode(keyboard.getText(), "utf-8")
sDate = unicode(keyboard.getText(), 'utf-8')
temp = sDate.split("/")
ret = datetime.date(int(temp[0]), int(temp[1]), int(temp[2]))
return ret
Expand Down
18 changes: 8 additions & 10 deletions src/games.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import vars


def getGameUrl(video_id, video_type, video_ishomefeed, start_time, duration):
def get_game(video_id, video_type, video_ishomefeed, start_time, duration):
utils.log("cookies: %s %s" % (video_type, vars.cookies), xbmc.LOGDEBUG)

# video_type could be archive, live, condensed or oldseason
Expand All @@ -31,7 +31,7 @@ def getGameUrl(video_id, video_type, video_ishomefeed, start_time, duration):
'type': 'game',
'extid': str(video_id),
'drmtoken': True,
'deviceid': xbmc.getInfoLabel('Network.MacAddress'),
'deviceid': xbmc.getInfoLabel('Network.MacAddress'), # TODO
'gt': gt,
'gs': vars.params.get('game_state', 3),
'pcid': vars.player_id,
Expand All @@ -43,7 +43,7 @@ def getGameUrl(video_id, video_type, video_ishomefeed, start_time, duration):
line2 = "Go LIVE"
ret = xbmcgui.Dialog().select("Game Options", [line1, line2])
if ret == -1:
return
return None
elif ret == 0:
if start_time:
body['st'] = str(start_time)
Expand Down Expand Up @@ -79,7 +79,7 @@ def getGameUrl(video_id, video_type, video_ishomefeed, start_time, duration):
except urllib2.HTTPError as err:
utils.logHttpException(err, url)
utils.littleErrorPopup(xbmcaddon.Addon().getLocalizedString(50020))
return ''
return None

xml = parseString(str(content))
url = xml.getElementsByTagName("path")[0].childNodes[0].nodeValue
Expand Down Expand Up @@ -289,7 +289,7 @@ def addGamesLinks(date='', video_type="archive"):
utils.log(traceback.format_exc(), xbmc.LOGDEBUG)
pass

def playGame():
def play_game():
# Authenticate
if vars.cookies == '':
vars.cookies = common.login()
Expand All @@ -303,12 +303,10 @@ def playGame():
currentvideo_ishomefeed = vars.params.get("video_ishomefeed", "1")
currentvideo_ishomefeed = currentvideo_ishomefeed == "1"

# Get the video url.
# Authentication is needed over this point!
currentvideo = getGameUrl(currentvideo_id, currentvideo_type, currentvideo_ishomefeed, start_time, duration)
item = common.get_playable_item(currentvideo)
if item is not None:
xbmcplugin.setResolvedUrl(handle=int(sys.argv[1]), succeeded=True, listitem=item)
game = get_game(currentvideo_id, currentvideo_type, currentvideo_ishomefeed, start_time, duration)
if game is not None:
common.play(game)

def chooseGameVideoMenu():
video_id = vars.params.get("video_id")
Expand Down
2 changes: 1 addition & 1 deletion src/leaguepass.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def previousSeasonMenu():
elif mode == "archive":
archiveMenu()
elif mode == "playgame":
playGame()
play_game()
elif mode == "gamechoosevideo":
chooseGameVideoMenu()
elif mode == "oldseason":
Expand Down
13 changes: 6 additions & 7 deletions src/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,16 @@ def __init__(self):

def refreshLiveUrl(self):
if self.shared_data.get('playing.what') == 'nba_tv_live':
video_url = TV.get_live_url(force_login=True)
video = TV.get_live(force_login=True)
elif self.shared_data.get('playing.what') == 'nba_tv_episode':
start_timestamp = self.shared_data.get('playing.data.start_timestamp')
duration = self.shared_data.get('playing.data.duration')
video_url = TV.get_episode_url(start_timestamp, duration, force_login=True)
video = TV.get_episode(start_timestamp, duration, force_login=True)

if video_url:
self.readExpiresFromUrl(video_url)
utils.log("Updating live url from service, new url (%s) and expire (%d)" % (video_url, self.expires))

self.player.play(video_url)
if video is not None:
self.readExpiresFromUrl(video)
utils.log("Updating live url from service, new url (%s) and expire (%d)" % (video, self.expires))
self.player.play(video)

def readExpiresFromUrl(self, url):
url_parts = urlparse(url)
Expand Down
111 changes: 58 additions & 53 deletions src/shareddata.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,56 +9,61 @@

class SharedData:

def __init__(self):
self.folder = xbmc.translatePath(xbmcaddon.Addon().getAddonInfo('profile')).decode("utf-8")
if not xbmcvfs.exists(self.folder):
xbmcvfs.mkdir(self.folder)
self.file_path = self.folder + "shared_data.json"
with open(self.file_path, "w") as file:
file.write("{}")

def __getFileContent(self):
try:
with open(self.file_path) as file:
file_content = file.read()
except IOError:
file_content = "{}"

json_content = json.loads(file_content)
return json_content

def set(self, key, value):
json_content = self.__getFileContent()

#Simple "json-path"-like set algorithm
keys = key.split('.')
keys_length = len(keys)
item = json_content
for index, key in enumerate(keys):
if key not in item:
item[key] = {}

if index+1 < keys_length:
if not isinstance(item[key], dict):
item[key] = {}
item = item[key]
else:
item[key] = value

file_content = json.dumps(json_content)
with open(self.file_path, "w") as file:
file.write(file_content)

def get(self, key):
json_content = self.__getFileContent()

#Simple "json-path"-like get algorithm
keys = key.split(".")
item = json_content
try:
for key in keys:
item = item.get(key, {})
except:
return None

return item
__DEFAULT_JSON_CONTENT = {}

def __init__(self):
self.__folder = xbmc.translatePath(xbmcaddon.Addon().getAddonInfo('profile')).decode('utf-8')
if not xbmcvfs.exists(self.__folder):
xbmcvfs.mkdir(self.__folder)
self.__file_path = self.__folder + "shared_data.json"

self.__save_json_content(self.__DEFAULT_JSON_CONTENT)

def __save_json_content(self, json_content):
file_content = json.dumps(json_content)
with open(self.__file_path, 'w') as file_obj:
file_obj.write(file_content)

def __load_json_content(self):
try:
with open(self.__file_path, 'r') as file_obj:
file_content = file_obj.read()
json_content = json.loads(file_content)
except: # TODO
json_content = self.__DEFAULT_JSON_CONTENT

return json_content

def set(self, path, value):
json_content = self.__load_json_content()

# Simple "json-path"-like set algorithm # TODO
keys = path.split('.')
keys_length = len(keys)
item = json_content
for index, key in enumerate(keys):
if key not in item:
item[key] = {}

if index + 1 < keys_length:
if not isinstance(item[key], dict):
item[key] = {}
item = item[key]
else:
item[key] = value

self.__save_json_content(json_content)

def get(self, path):
json_content = self.__load_json_content()

# Simple "json-path"-like get algorithm # TODO
keys = path.split('.')
item = json_content
try:
for key in keys:
item = item.get(key, {})
except: # TODO
return None

return item
26 changes: 10 additions & 16 deletions src/tv.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,23 +65,20 @@ def episode_menu():

@staticmethod
def play_live():
video_url = TV.get_live_url()
if video_url is not None:
live = TV.get_live()
if live is not None:
shared_data = SharedData()
shared_data.set('playing', {
'what': 'nba_tv_live',
})

item = common.get_playable_item(video_url)
if item is not None:
xbmcplugin.setResolvedUrl(handle=int(sys.argv[1]), succeeded=True, listitem=item)
common.play(live)

@staticmethod
def play_episode():
start_timestamp = vars.params.get('start_timestamp')
duration = vars.params.get('duration')
video_url = TV.get_episode_url(start_timestamp, duration)
if video_url is not None:
episode = TV.get_episode(start_timestamp, duration)
if episode is not None:
shared_data = SharedData()
shared_data.set('playing', {
'what': 'nba_tv_episode',
Expand All @@ -90,13 +87,10 @@ def play_episode():
'duration': duration,
},
})

item = common.get_playable_item(video_url)
if item is not None:
xbmcplugin.setResolvedUrl(handle=int(sys.argv[1]), succeeded=True, listitem=item)
common.play(episode)

@staticmethod
def get_episode_url(start_timestamp, duration, force_login=False):
def get_episode(start_timestamp, duration, force_login=False):
if not vars.cookies or force_login:
common.login()
if not vars.cookies:
Expand All @@ -112,7 +106,7 @@ def get_episode_url(start_timestamp, duration, force_login=False):
'type': 'channel',
'id': 1,
'drmtoken': True,
'deviceid': xbmc.getInfoLabel('Network.MacAddress'),
'deviceid': xbmc.getInfoLabel('Network.MacAddress'), # TODO
'st': start_timestamp,
'dur': duration,
'pcid': vars.player_id,
Expand Down Expand Up @@ -140,7 +134,7 @@ def get_episode_url(start_timestamp, duration, force_login=False):
return {'url': url, 'drm': drm}

@staticmethod
def get_live_url(force_login=False):
def get_live(force_login=False):
if not vars.cookies or force_login:
common.login()
if not vars.cookies:
Expand All @@ -156,7 +150,7 @@ def get_live_url(force_login=False):
'type': 'channel',
'id': 1,
'drmtoken': True,
'deviceid': xbmc.getInfoLabel('Network.MacAddress'),
'deviceid': xbmc.getInfoLabel('Network.MacAddress'), # TODO
'pcid': vars.player_id,
'format': 'xml',
}
Expand Down
2 changes: 1 addition & 1 deletion src/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def prepareSingleThumbnail(im, width, height):
return im

def generateCombinedThumbnail(v, h, width=2*500, height=500, padding=10):
thumbnails_path = os.path.join(xbmc.translatePath(xbmcaddon.Addon().getAddonInfo('profile')).decode("utf-8"), "thumbnails")
thumbnails_path = os.path.join(xbmc.translatePath(xbmcaddon.Addon().getAddonInfo('profile')).decode('utf-8'), "thumbnails")
if not xbmcvfs.exists(thumbnails_path):
xbmcvfs.mkdir(thumbnails_path)
combined_thumbnail_fullname = os.path.join(thumbnails_path, ("%s-%s.png" % (v.lower(), h.lower())))
Expand Down