def get_secure_token(secure_url, video_id):
    """send our embed token back with a few other url encoded parameters"""
    res = sess.get(secure_url)
    try:
        parsed_json = json.loads(res.text)
    except ValueError:
        utils.log('Failed to load JSON. Data is: {0}'.format(res.text))
        if '<html' in res.text:  # smart DNS redirects
            raise AussieAddonsException(
                'Failed to get authorization token. Please ensure any smart '
                'DNS service is disabled.')
        else:
            raise Exception('Failed to get authorization token.')
    if parsed_json.get('authorized') is False:
        raise AussieAddonsException('Failed to get authorization token: {0}'
                                    ''.format(parsed_json.get('message')))

    auth_data = parsed_json.get('authorization_data')

    utils.log('auth_data: %s' % auth_data)
    video = auth_data.get(video_id)

    if video.get('authorized') is False:
        raise AussieAddonsException('Failed to obtain secure token: {0}.\n'
                                    'Check your subscription is valid.'.format(
                                        video.get('message')))
    try:
        streams = video.get('streams')
        ios_token = streams[0]['url']['data']
        return base64.b64decode(ios_token)
    except Exception as e:
        raise AussieAddonsException('Failed to get stream URL: {0}'.format(e))
def get_embed_token(pai, bearer, video_id):
    """
    send our user token to get our embed token, including api key
    """
    url = config.TELSTRA_AUTH_URL.format(code=video_id, pai=pai)
    sess.headers = {}
    sess.headers.update({'Authorization': 'Bearer {0}'.format(bearer)})
    try:
        req = sess.get(url)
        data = req.text
        json_data = json.loads(data)
        if json_data.get('ErrorCode') is not None:
            raise AussieAddonsException()
        embed_token = json_data.get('token')
    except requests.exceptions.HTTPError as e:
        utils.log('Error getting embed token. '
                  'Response: {0}'.format(e.response.text))
        cache.delete('SOCCERTICKET')
        if e.response.status_code == 401:
            raise AussieAddonsException('Login token has expired, '
                                        'please try again.')
        else:
            raise e

    return urllib.quote_plus(embed_token)
Пример #3
0
def get_embed_token(user_token, video_id):
    """
    send our user token to get our embed token, including api key
    """
    url = config.EMBED_TOKEN_URL.format(video_id)
    sess.headers.update({
        'X-YinzCam-Ticket': user_token,
        'Accept': 'application/json'
    })
    try:
        req = sess.get(url)
        data = req.text
        json_data = json.loads(data)
        if json_data.get('ErrorCode') is not None:
            raise AussieAddonsException()
        video_token = json_data.get('VideoToken')
    except requests.exceptions.HTTPError as e:
        utils.log('Error getting embed token. '
                  'Response: {0}'.format(e.response.text))
        cache.delete('NETBALLTICKET')
        if e.response.status_code == 401:
            raise AussieAddonsException('Login token has expired, '
                                        'please try again.')
        else:
            raise e
    return urllib.quote(video_token)
def get_media_auth_token(pai, video_id):
    """
    send our user token to get our embed token, including api key
    """
    url = config.MEDIA_AUTH_URL.format(code=video_id, pai=pai)

    try:
        data = comm.fetch_url(url, request_token=True)
        json_data = json.loads(data)
        if json_data.get('Fault'):
            raise AussieAddonsException(
                json_data.get('fault').get('faultstring'))
        media_auth_token = json_data.get('urlSigningToken')
    except requests.exceptions.HTTPError as e:
        utils.log('Error getting embed token. '
                  'Response: {0}'.format(e.response.text))
        cache.delete('AFLTOKEN')
        if e.response.status_code in [400, 401]:
            raise AussieAddonsException('Login token has expired, '
                                        'please try again.')
        elif e.response.status_code == 404:
            raise AussieAddonsException(
                'Unknown error, please wait a few moments and try again.')
        else:
            raise e
    return media_auth_token
Пример #5
0
def get_media_auth_token(ticket, video_id):
    """
    send our user token to get our embed token, including api key
    """
    url = config.MEDIA_AUTH_URL.format(video_id=video_id)
    sess.headers = {}
    sess.headers.update({
        'X-YinzCam-Ticket': ticket,
        'Accept': 'application/json'
    })
    try:
        req = sess.get(url)
        data = req.text
        json_data = json.loads(data)
        if json_data.get('Fault'):
            raise AussieAddonsException(
                json_data.get('fault').get('faultstring'))
        media_auth_token = json_data.get('VideoToken')
    except requests.exceptions.HTTPError as e:
        utils.log('Error getting embed token. '
                  'Response: {0}'.format(e.response.text))
        cache.delete('NETBALLTICKET')
        if e.response.status_code == 401:
            raise AussieAddonsException('Login token has expired, '
                                        'please try again.')
        else:
            raise e
    return media_auth_token
    def request(self, method, url, *args, **kwargs):
        """Send the request after generating the complete URL."""
        utils.log("Performing {0} for {1}".format(method, url))
        try:
            req = super(Session, self).request(method, url, *args, **kwargs)
            req.raise_for_status()
        except SSLError as e:
            msg = ('SSL Error: {0}. This is usually due to an old version of '
                   'Kodi. Please upgrade to Kodi v17 or later.'.format(e))
            raise AussieAddonsException(msg)
        except requests.exceptions.HTTPError as e:
            raise e
        except Exception as e:
            raise AussieAddonsException('Error: {0}'.format(e))

        return req
Пример #7
0
def get_embed_token(login_ticket, videoId):
    """
    send our user token to get our embed token, including api key
    """
    data = create_nrl_userid_xml(userToken)
    url = config.EMBED_TOKEN_URL.format(videoId)
    try:
        req = sess.post(url,
                        data=data,
                        headers=config.YINZCAM_AUTH_HEADERS,
                        verify=False)
        xml = req.text[1:]
        try:
            tree = ET.fromstring(xml)
        except ET.ParseError as e:
            utils.log('Embed token response is: {0}'.format(xml))
            cache.delete('NRLTOKEN')
            raise e
        if tree.find('ErrorCode') is not None:
            utils.log('Errorcode found: {0}'.format(xml))
            raise AussieAddonsException()
        token = tree.find('Token').text
    except AussieAddonsException:
        cache.delete('NRLTOKEN')
        raise Exception('Login token has expired, please try again')
    return token
def get_secure_token(secure_url, videoId):
    """send our embed token back with a few other url encoded parameters"""
    res = session.get(secure_url)
    data = res.text
    try:
        parsed_json = json.loads(data)
        for stream in parsed_json['authorization_data'][videoId]['streams']:
            if stream.get('delivery_type') == 'dash':
                dash_url = stream['url'].get('data')
                wv_lic = stream.get('widevine_server_path')
    except KeyError:
        utils.log('Parsed json data: {0}'.format(parsed_json))
        try:
            auth_msg = parsed_json['authorization_data'][videoId]['message']
            if auth_msg == 'unauthorizedlocation':
                country = parsed_json['user_info']['country']
                raise AussieAddonsException('Unauthorised location for '
                                            'streaming. '
                                            'Detected location is: {0}. '
                                            'Please check VPN/smart DNS '
                                            'settings and try again'
                                            ''.format(country))
        except Exception as e:
            raise e
    return {'dash_url': base64.b64decode(dash_url), 'wv_lic': wv_lic}
Пример #9
0
def get_secure_token(secure_url, videoId):
    """
    send our embed token back with a few other url encoded parameters
    """
    res = sess.get(secure_url)
    data = res.text
    try:
        parsed_json = json.loads(data)
        token = (parsed_json['authorization_data'][videoId]['streams'][0]
                 ['url']['data'])
    except KeyError:
        utils.log('Parsed json data: {0}'.format(parsed_json))
        try:
            auth_msg = parsed_json['authorization_data'][videoId]['message']
            if auth_msg == 'unauthorized location':
                country = parsed_json['user_info']['country']
                raise AussieAddonsException('Unauthorised location for '
                                            'streaming. '
                                            'Detected location is: {0}. '
                                            'Please check VPN/smart DNS '
                                            'settings '
                                            ' and try again'.format(country))
        except Exception as e:
            raise e
    return base64.b64decode(token)
Пример #10
0
def get_embed_token(login_ticket, videoId):
    """
    send our user token to get our embed token, including api key
    """
    url = config.EMBED_TOKEN_URL.format(videoId)
    try:
        headers = {}
        headers.update({
            'X-YinzCam-AppID': 'NRL_LIVE',
            'X-YinzCam-Ticket': login_ticket,
            'Content-Type': 'application/xml',
            'Accept': 'application/xml',
            'Accept-Encoding': 'gzip',
            'User-Agent': config.USER_AGENT,
            'Connection': 'close'
        })
        sess.headers = headers
        try:
            req = sess.get(url, verify=False)
            xml = req.text
        except requests.exceptions.HTTPError as e:
            if e.response.status_code == 401:
                cache.delete('NRLTICKET')
                raise AussieAddonsException('Login token has expired, '
                                            'please try again.')
            elif e.response.status_code == 403:
                cache.delete('NRLTICKET')
                tree = ET.fromstring(e.response.text)
                msg = str(tree.find('UserMessage').find('Content').text)
                raise AussieAddonsException(msg)
            else:
                raise e
        try:
            tree = ET.fromstring(xml)
        except ET.ParseError as e:
            utils.log('Embed token response is: {0}'.format(xml))
            cache.delete('NRLTICKET')
            raise e
        if tree.find('ErrorCode') is not None:
            utils.log('Errorcode found: {0}'.format(xml))
            raise AussieAddonsException('Login token has expired, '
                                        'please try again.')
        token = tree.find('VideoToken').text
    except AussieAddonsException as e:
        cache.delete('NRLTICKET')
        raise e
    return token
def get_paid_token(username, password):
    """
    Obtain a valid token from Telstra/Yinzcam, will be used to make
    requests for Ooyala embed tokens
    """
    session = custom_session.Session(force_tlsv1=False)
    auth_resp = session.get(config.NRL_AUTH, allow_redirects=False)

    xsrf = auth_resp.cookies['XSRF-TOKEN']
    session.headers.update({'x-xsrf-token': xsrf})

    data = {'emailAddress': '{0}'.format(username),
            'password': '******'.format(password)}
    login_resp = session.post(config.NRL_LOGIN, json=data)
    login_resp_json = json.loads(login_resp.text)
    if not login_resp_json.get('success') == True:  # noqa: E712
        raise AussieAddonsException(
            'Login failed for nrl.com: {0}'.format(
                login_resp_json.get('error')))

    auth2_resp = session.get(config.NRL_AUTH, allow_redirects=False)
    redirect_url = auth2_resp.headers.get('Location')
    redirect_pieces = urlparse.urlsplit(redirect_url)
    redirect_query = dict(urlparse.parse_qsl(redirect_pieces.query))
    code = redirect_query.get('code')
    token_form = {'code': code}
    token_form.update(config.TOKEN_DATA)
    session.headers = {}
    session.cookies.clear()
    token_resp = session.post(config.NRL_TOKEN, data=token_form)
    refresh_token = json.loads(token_resp.text).get('refresh_token')
    session.headers.update({'Content-Type': 'application/xml',
                            'Accept': 'application/json, text/plain, */*'})
    ticket_signon = session.post(
        config.YINZCAM_AUTH_URL,
        data=config.NEW_LOGIN_DATA2.format(refresh_token))
    ticket = json.loads(ticket_signon.text).get('Ticket')

    # check validity of subscription
    session.headers.update({'X-YinzCam-Ticket': ticket})
    sub_status = session.get(config.STATUS_URL)
    status_json = json.loads(sub_status.text)
    if status_json.get('Valid') != 'true':
        raise AussieAddonsException('NRL.com login failed: {0}'.format(
            status_json.get('Reason')))
    return ticket
Пример #12
0
def get_embed_token(user_token, video_id):
    """send our user token to get our embed token, including api key"""
    try:
        comm.update_token(sess)
        embed_token_url = config.EMBED_TOKEN_URL.format(user_token, video_id)
        utils.log("Fetching embed token: {0}".format(embed_token_url))
        try:
            res = sess.get(embed_token_url)
        except requests.exceptions.SSLError:
            cache.delete('AFLTOKEN')
            raise AussieAddonsException(
                'Your version of Kodi is too old to support live streaming. '
                'Please upgrade to the latest version.')
    except requests.exceptions.HTTPError as e:
        subscription_type = get_sub_type()
        if subscription_type == 0:  # paid afl.com.au/linked
            cache.delete('AFLTOKEN')
            raise AussieAddonsException(
                'Paid or linked subscription not found for supplied username '
                'and password. Please check the subscription type in settings '
                'is correct or your subscription has been linked to your '
                'Telstra ID in the Android/iOS app')
        elif subscription_type in [1, 3]:  # free/mobile sub
            cache.delete('AFLTOKEN')
            utils.log(e.response.text)
            if e.response.status_code == 400:
                raise AussieAddonsException(
                    'Stored login token has expired, please try to play this '
                    'item again. If this error persists please submit an '
                    'issue on our github (github.com/aussieaddons/plugin.'
                    'video.afl-video')
            else:
                raise e
        else:  # in-app purchase/manual
            raise AussieAddonsException(
                'mis-uuid token is invalid, please check the token in '
                'the settings is correct and try again')

    data = json.loads(res.text)
    return quote(data.get('token'))
Пример #13
0
def make_list(params):
    utils.log('Making video list...')
    cache = True
    try:
        if 'team' in params:
            videos = comm.get_team_videos(params.get('team'))
        elif 'round_id' in params:
            videos = comm.get_round_videos(params.get('round_id'))
        elif params.get('category') == 'Live Matches':
            videos = comm.get_live_videos()
            cache = False
        elif params.get('category') == 'AFLW':
            videos = comm.get_aflw_videos()
        else:
            try:
                category = config.CATEGORY_LOOKUP[params.get('category')]
            except KeyError as e:
                xbmcgui.Dialog().ok(
                    'Outdated Favourites Link',
                    'The Kodi Favourite item being accessed was created with '
                    'an earlier version of the AFL Video add-on and is no '
                    'longer compatible. Please remove this link and update '
                    'with a new one.')
                raise AussieAddonsException(e)
            videos = comm.get_category_videos(category)

        ok = True
        for v in videos:
            listitem = xbmcgui.ListItem(label=v.get_title())
            thumb = v.get_thumbnail()
            listitem.setArt({'icon': thumb, 'thumb': thumb})
            listitem.setInfo('video', v.get_kodi_list_item())
            listitem.addStreamInfo('video', v.get_kodi_stream_info())
            if not v.isdummy:
                listitem.setProperty('IsPlayable', 'true')

            # Build the URL for the program, including the list_info
            url = "%s?%s" % (sys.argv[0], v.make_kodi_url())

            # Add the program item to the list
            ok = xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),
                                             url=url,
                                             listitem=listitem,
                                             isFolder=False)

        xbmcplugin.endOfDirectory(handle=int(sys.argv[1]),
                                  succeeded=ok,
                                  cacheToDisc=cache)
        xbmcplugin.setContent(handle=int(sys.argv[1]), content='episodes')
    except Exception:
        utils.handle_error('Unable to fetch video list')
Пример #14
0
def fetch_bc_url(url, headers={}):
    """
    Use fetch_url and catch Brightcove API errors
    """
    try:
        data = cache.getData(url=url, headers=headers, noCache=True)
        return data
    except requests.exceptions.HTTPError as e:
        utils.log(e.response.text)
        if e.response.status_code == 403:
            try:
                error_data = json.loads(e.response.text)
                if error_data[0].get('error_subcode') == 'CLIENT_GEO':
                    raise AussieAddonsException(
                        'Content is geoblocked, your detected country is: {0}'
                        ''.format(error_data[0].get('client_geo')))
                else:
                    raise e
            except IndexError:
                raise e
            except ValueError:
                raise
        else:
            raise e
def get_user_token():
    """Send user login info and retrieve token for session"""
    # in-app purchase/manual
    if subscription_type == 2:
        iap_token = addon.getSetting('IAP_TOKEN').lower()
        try:
            int(iap_token, 16)
        except ValueError:
            raise AussieAddonsException(
                'mis-uuid token must be 32 characters in length, and only '
                'contain numbers 0-9 and letters a-f')
        if len(iap_token) != 32:
            raise AussieAddonsException(
                'mis-uuid token must be 32 characters in length, and only '
                'contain numbers 0-9 and letters a-f')
        token = 'mis-uuid-{0}'.format(iap_token)
        utils.log('Using manual token: {0}******'.format(token[:-6]))
        return token

    stored_token = cache.get('AFLTOKEN')
    if stored_token:
        utils.log('Using token: {0}******'.format(stored_token[:-6]))
        return stored_token

    if addon.getSetting('LIVE_SUBSCRIPTION') == 'true':
        username = addon.getSetting('LIVE_USERNAME')
        password = addon.getSetting('LIVE_PASSWORD')

        if subscription_type == 1:  # free subscription
            token = telstra_auth.get_token(username, password)
        else:  # paid afl.com.au
            login_data = {
                'userIdentifier': addon.getSetting('LIVE_USERNAME'),
                'authToken': addon.getSetting('LIVE_PASSWORD'),
                'userIdentifierType': 'EMAIL'
            }
            login_json = fetch_session_id(config.LOGIN_URL, login_data)
            data = json.loads(login_json)
            if data.get('responseCode') != 0:
                raise AussieAddonsException('Invalid Telstra ID login/'
                                            'password for paid afl.com.au '
                                            'subscription.')
            session_id = data['data'].get('artifactValue')

            try:
                sess.headers.update({'Authorization': None})
                encoded_session_id = urllib.quote(session_id)
                session_url = config.SESSION_URL.format(encoded_session_id)
                res = sess.get(session_url)
                data = json.loads(res.text)
                token = data.get('uuid')

            except requests.exceptions.HTTPError as e:
                utils.log(e.response.text)
                raise e
        cache.set('AFLTOKEN', token)
        utils.log('Using token: {0}******'.format(token[:-6]))
        return token
    else:
        raise AussieAddonsException('AFL Live Pass subscription is required '
                                    'for this content. Please open the '
                                    'add-on settings to enable and configure.')
def get_free_token(username, password):
    """
    Obtain a valid token from Telstra/Yinzcam, will be used to make
    requests for Ooyala embed tokens
    """
    session = custom_session.Session(force_tlsv1=False)
    prog_dialog = xbmcgui.DialogProgress()
    prog_dialog.create('Logging in with Telstra ID')

    # Send our first login request to Yinzcam, recieve (unactivated) ticket
    prog_dialog.update(1, 'Obtaining oauth token')
    userid = uuid.uuid4()
    config.OAUTH_DATA.update({'x-user-id': userid})
    oauth_resp = session.post(config.OAUTH_URL, data=config.OAUTH_DATA)
    oauth_json = json.loads(oauth_resp.text)
    access_token = oauth_json.get('access_token')
    session.headers = {}
    session.headers.update(
        {'Authorization': 'Bearer {0}'.format(access_token)})

    # Check entitlements (not sure if needed)
    session.get(config.ENTITLEMENTS_URL)

    prog_dialog.update(16, 'Getting SSO Client ID')
    # GET to our spc url and receive SSO client ID
    session.headers = config.SPC_HEADERS  # check if needed
    spc_url = config.SPC_URL.format(userid)
    spc_resp = session.get(spc_url)
    sso_token_match = re.search('ssoClientId = "(\w+)"', spc_resp.text)
    try:
        sso_token = sso_token_match.group(1)
    except AttributeError as e:
        utils.log('SPC login response: {0}'.format(spc_resp.text))
        raise e

    # Sign in to telstra.com with our SSO client id to get the url
    # for retrieving the bearer token for media orders
    prog_dialog.update(33, 'Signing on to telstra.com')
    sso_params = config.SSO_PARAMS
    sso_params.update({
        'client_id': sso_token,
        'state': binascii.b2a_hex(os.urandom(16)),
        'nonce': binascii.b2a_hex(os.urandom(16))
    })

    sso_auth_resp = session.get(config.SSO_URL, params=sso_params)
    sso_url = dict(urlparse.parse_qsl(urlparse.urlsplit(
        sso_auth_resp.url)[3])).get('goto')

    # login to telstra.com.au and get our BPSESSION cookie
    session.headers.update(config.SIGNON_HEADERS)
    signon_data = config.SIGNON_DATA
    signon_data = {'username': username, 'password': password, 'goto': sso_url}
    signon = session.post(config.SIGNON_URL,
                          data=signon_data,
                          allow_redirects=False)
    bp_session = session.cookies.get_dict().get('BPSESSION')

    # check signon is valid (correct username/password)

    signon_pieces = urlparse.urlsplit(signon.headers.get('Location'))
    signon_query = dict(urlparse.parse_qsl(signon_pieces.query))

    utils.log('Sign-on result: %s' % signon_query)

    if 'errorcode' in signon_query:
        if signon_query['errorcode'] == '0':
            raise TelstraAuthException('Please enter your username '
                                       'in the settings')
        if signon_query['errorcode'] == '1':
            raise TelstraAuthException('Please enter your password '
                                       'in the settings')
        if signon_query['errorcode'] == '2':
            raise TelstraAuthException('Please enter your username and '
                                       'password in the settings')
        if signon_query['errorcode'] == '3':
            raise TelstraAuthException('Invalid Telstra ID username/password. '
                                       'Please check your username and '
                                       'password in the settings')

    # Use BPSESSION cookie to ask for bearer token
    sso_headers = config.SSO_HEADERS
    sso_headers.update({'Cookie': 'BPSESSION={0}'.format(bp_session)})
    session.headers = sso_headers
    sso_token_resp = session.get(sso_url)
    bearer_token = dict(
        urlparse.parse_qsl(urlparse.urlsplit(
            sso_token_resp.url)[4]))['access_token']

    # First check if there are any eligible services attached to the account
    prog_dialog.update(50, 'Determining eligible services')
    offer_id = dict(urlparse.parse_qsl(
        urlparse.urlsplit(spc_url)[3]))['offerId']
    media_order_headers = config.MEDIA_ORDER_HEADERS
    media_order_headers.update(
        {'Authorization': 'Bearer {0}'.format(bearer_token)})
    session.headers = media_order_headers
    try:
        offers = session.get(config.OFFERS_URL)
    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 404:
            message = json.loads(e.response.text).get('userMessage')
            message += (' Please visit {0} '.format(config.HUB_URL) +
                        'for further instructions to link your mobile '
                        'service to the supplied Telstra ID')
            raise TelstraAuthException(message)
        else:
            raise TelstraAuthException(e)
    try:
        offer_data = json.loads(offers.text)
        offers_list = offer_data['data']['offers']
        ph_no = None
        for offer in offers_list:
            if offer.get('name') != 'My Football Live Pass':
                continue
            data = offer.get('productOfferingAttributes')
            ph_no = [x['value'] for x in data if x['name'] == 'ServiceId'][0]
        if not ph_no:
            raise TelstraAuthException(
                'Unable to determine if you have any eligible services. '
                'Please ensure there is an eligible service linked to '
                'your Telstra ID to redeem the free offer. Please visit '
                '{0} for further instructions'.format(config.HUB_URL))
    except Exception as e:
        raise e

    # 'Order' the subscription package to activate the service
    prog_dialog.update(66, 'Activating live pass on service')
    order_data = config.MEDIA_ORDER_JSON.format(ph_no, offer_id, userid)
    order = session.post(config.MEDIA_ORDER_URL, data=order_data)

    # check to make sure order has been placed correctly
    if order.status_code == 201:
        try:
            order_json = json.loads(order.text)
            status = order_json['data'].get('status') == 'COMPLETE'
            if status:
                utils.log('Order status complete')
        except:
            utils.log('Unable to check status of order, continuing anyway')

    # Confirm activation
    prog_dialog.update(83, 'Confirming activation')
    session.headers = {}
    session.headers.update(
        {'Authorization': 'Bearer {0}'.format(access_token)})
    confirm = json.loads(session.get(config.ENTITLEMENTS_URL).text)
    if len(confirm.get('entitlements')) < 1:
        raise AussieAddonsException('Telstra ID activation failed')

    session.close()
    prog_dialog.update(100, 'Finished!')
    prog_dialog.close()
    return json.dumps({'pai': str(userid), 'bearer': access_token})
Пример #17
0
def play(url):
    try:
        # Remove cookies.dat for Kodi < 17.0 - causes issues with playback
        addon = xbmcaddon.Addon()
        cookies_dat = xbmc.translatePath('special://home/cache/cookies.dat')
        if os.path.isfile(cookies_dat):
            os.remove(cookies_dat)
        p = classes.Program()
        p.parse_kodi_url(url)
        stream_data = comm.get_stream_url(p.get_house_number(), p.get_url())
        stream_url = stream_data.get('stream_url')
        if not stream_url:
            utils.log('Not Playable: {0}'.format(repr(stream_data)))
            raise AussieAddonsException(
                'Not available: {0}\n{1}'.format(stream_data.get('msg'),
                                                 stream_data.get(
                                                     'availability')))
        use_ia = addon.getSetting('USE_IA') == 'true'
        if use_ia:
            if addon.getSetting('IGNORE_DRM') == 'false':
                try:
                    import drmhelper
                    if not drmhelper.check_inputstream(drm=False):
                        return
                except ImportError:
                    utils.log("Failed to import drmhelper")
                    utils.dialog_message(
                        'DRM Helper is needed for inputstream.adaptive '
                        'playback. Disable "Use inputstream.adaptive for '
                        'playback" in settings or install drmhelper. For '
                        'more information, please visit: '
                        'http://aussieaddons.com/drm')
                    return
            hdrs = stream_url[stream_url.find('|') + 1:]

        listitem = xbmcgui.ListItem(label=p.get_list_title(),
                                    path=stream_url)
        thumb = p.get_thumb()
        listitem.setArt({'icon': thumb,
                         'thumb': thumb})
        if use_ia:
            listitem.setProperty('inputstreamaddon', 'inputstream.adaptive')
            listitem.setProperty('inputstream.adaptive.manifest_type', 'hls')
            listitem.setProperty('inputstream.adaptive.stream_headers', hdrs)
            listitem.setProperty('inputstream.adaptive.license_key',
                                 stream_url)
        listitem.setInfo('video', p.get_kodi_list_item())

        # Add subtitles if available

        if p.is_captions():
            captions_url = stream_data.get('captions_url')
            profile = xbmcaddon.Addon().getAddonInfo('profile')
            path = xbmc.translatePath(profile)
            if not os.path.isdir(path):
                os.makedirs(path)
            caption_file = os.path.join(path, 'subtitles.eng.srt')
            if os.path.isfile(caption_file):
                os.remove(caption_file)

            try:
                sess = session.Session()
                webvtt_data = sess.get(captions_url).text
                if webvtt_data:
                    with io.BytesIO() as buf:
                        webvtt_captions = WebVTTReader().read(webvtt_data)
                        srt_captions = SRTWriter().write(webvtt_captions)
                        srt_unicode = srt_captions.encode('utf-8')
                        buf.write(srt_unicode)
                        with io.open(caption_file, "wb") as f:
                            f.write(buf.getvalue())
                if hasattr(listitem, 'setSubtitles'):
                    listitem.setSubtitles([caption_file])
            except Exception as e:
                utils.log(
                    'Subtitles not available for this program: {0}'.format(e))

        if hasattr(listitem, 'addStreamInfo'):
            listitem.addStreamInfo('audio', p.get_kodi_audio_stream_info())
            listitem.addStreamInfo('video', p.get_kodi_video_stream_info())

        xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem=listitem)

    except Exception:
        utils.handle_error('Unable to play video')
def get_mobile_token():
    session = custom_session.Session(force_tlsv1=False)
    prog_dialog = xbmcgui.DialogProgress()
    prog_dialog.create('Logging in with mobile service')
    prog_dialog.update(1, 'Obtaining oauth token')
    userid = str(uuid.uuid4())
    config.OAUTH_DATA.update({'x-user-id': userid})
    oauth_resp = session.post(config.OAUTH_URL, data=config.OAUTH_DATA)
    oauth_json = json.loads(oauth_resp.text)
    access_token = oauth_json.get('access_token')

    prog_dialog.update(20, 'Obtaining mobile token')
    mobile_userid_cookies = session.get(
        config.MOBILE_ID_URL).cookies.get_dict()
    mobile_userid = mobile_userid_cookies.get('GUID_S')
    if not mobile_userid or mobile_userid_cookies.get('nouid'):
        raise TelstraAuthException('Not connected to Telstra Mobile network. '
                                   'Please disable WiFi and enable mobile '
                                   'data if on a Telstra mobile device, or '
                                   "connect this device's WiFi to a device "
                                   'that is on the Telstra Mobile network '
                                   'and try again.')
    data = config.OAUTH_DATA
    data.update({'x-user-id': mobile_userid, 'x-user-idp': 'NGP'})
    mobile_token_resp = session.post(config.OAUTH_URL, data=data)
    bearer_token = json.loads(mobile_token_resp.text).get('access_token')

    # First check if there are any eligible services attached to the account
    prog_dialog.update(40, 'Determining eligible services')
    media_order_headers = {}
    media_order_headers.update(
        {'Authorization': 'Bearer {0}'.format(bearer_token)})
    session.headers = media_order_headers
    try:
        offers = session.get(config.OFFERS_URL)
    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 404:
            message = json.loads(e.response.text).get('userMessage')
            message += (' Please visit {0} '.format(config.HUB_URL) +
                        'for further instructions to link your mobile '
                        'service to the supplied Telstra ID')
            raise TelstraAuthException(message)
        else:
            raise TelstraAuthException(e)
    try:
        offer_data = json.loads(offers.text)
        offers_list = offer_data['data']['offers']
        ph_no = None
        for offer in offers_list:
            if offer.get('name') != 'My Football Live Pass':
                continue
            data = offer.get('productOfferingAttributes')
            ph_no = [x['value'] for x in data if x['name'] == 'ServiceId'][0]
        if not ph_no:
            raise TelstraAuthException(
                'Unable to determine if you have any eligible services. '
                'Please ensure there is an eligible service linked to '
                'your Telstra ID to redeem the free offer. Please visit '
                '{0} for further instructions'.format(config.HUB_URL))
    except Exception as e:
        raise e

    # 'Order' the subscription package to activate the service
    prog_dialog.update(60, 'Activating live pass on service')
    order_data = config.MOBILE_ORDER_JSON
    order_data.update({'serviceId': ph_no, 'pai': userid})
    try:
        order = session.post(config.MEDIA_ORDER_URL, json=order_data)
    except requests.exceptions.HTTPError as e:
        raise e

    # check to make sure order has been placed correctly
    if order.status_code == 201:
        try:
            order_json = json.loads(order.text)
            status = order_json['data'].get('status') == 'COMPLETE'
            if status:
                utils.log('Order status complete')
        except:
            utils.log('Unable to check status of order, continuing anyway')

    # Confirm activation
    prog_dialog.update(80, 'Confirming activation')
    session.headers = {}
    session.headers.update(
        {'Authorization': 'Bearer {0}'.format(access_token)})
    confirm = json.loads(session.get(config.ENTITLEMENTS_URL).text)
    if len(confirm.get('entitlements')) < 1:
        raise AussieAddonsException('Telstra ID activation failed')

    session.close()
    prog_dialog.update(100, 'Finished!')
    prog_dialog.close()
    return json.dumps({'pai': userid, 'bearer': access_token})
def get_free_token(username, password):
    """
    Obtain a valid token from Telstra/Yinzcam, will be used to make
    requests for Ooyala embed tokens
    """
    session = custom_session.Session(force_tlsv1=False)
    prog_dialog = xbmcgui.DialogProgress()
    prog_dialog.create('Logging in with Telstra ID')

    # Send our first login request to Yinzcam, recieve (unactivated) ticket
    prog_dialog.update(1, 'Obtaining user ticket')
    adid = uuid.uuid4()
    deviceid = uuid.uuid4()
    session.headers = config.YINZCAM_AUTH_HEADERS
    ticket_resp = session.post(config.YINZCAM_AUTH_URL,
                               data=config.NEW_LOGIN_DATA1.format(
                                adid=adid, deviceid=deviceid))
    ticket_xml = ET.fromstring(ticket_resp.text)
    ticket = ticket_xml.find('Ticket').text
    session.headers = {'Accept': 'application/json, text/plain, */*'}
    session.headers.update({'X-YinzCam-Ticket': ticket})

    # Send ticket back and get 'sports pass confirmation' URL and 'TpUid'
    yinz_resp = session.get(config.YINZCAM_AUTH_URL2)
    jsondata = json.loads(yinz_resp.text)
    token = jsondata.get('TpUid')
    spc_url = jsondata.get('Url')
    if not token or not spc_url:
        raise TelstraAuthException('Unable to get token/spc url from NRL API')

    prog_dialog.update(16, 'Getting SSO Client ID')
    # GET to our spc url and receive SSO client ID
    session.headers = config.SPC_HEADERS
    spc_resp = session.get(spc_url)
    sso_token_match = re.search('ssoClientId = "(\w+)"', spc_resp.text)
    try:
        sso_token = sso_token_match.group(1)
    except AttributeError as e:
        utils.log('SPC login response: {0}'.format(spc_resp.text))
        raise e

    # Sign in to telstra.com with our SSO client id to get the url
    # for retrieving the bearer token for media orders
    prog_dialog.update(33, 'Signing on to telstra.com')
    sso_params = config.SSO_PARAMS
    sso_params.update({'client_id': sso_token,
                       'state': binascii.b2a_hex(os.urandom(16)),
                       'nonce': binascii.b2a_hex(os.urandom(16))})

    sso_auth_resp = session.get(config.SSO_URL, params=sso_params)
    sso_url = dict(urlparse.parse_qsl(
                   urlparse.urlsplit(sso_auth_resp.url)[3])).get('goto')

    # login to telstra.com.au and get our BPSESSION cookie
    session.headers.update(config.SIGNON_HEADERS)
    signon_data = config.SIGNON_DATA
    signon_data = {'username': username, 'password': password, 'goto': sso_url}
    signon = session.post(config.SIGNON_URL,
                          data=signon_data,
                          allow_redirects=False)
    bp_session = session.cookies.get_dict().get('BPSESSION')

    # check signon is valid (correct username/password)

    signon_pieces = urlparse.urlsplit(signon.headers.get('Location'))
    signon_query = dict(urlparse.parse_qsl(signon_pieces.query))

    utils.log('Sign-on result: %s' % signon_query)

    if 'errorcode' in signon_query:
        if signon_query['errorcode'] == '0':
            raise TelstraAuthException('Please enter your username '
                                       'in the settings')
        if signon_query['errorcode'] == '1':
            raise TelstraAuthException('Please enter your password '
                                       'in the settings')
        if signon_query['errorcode'] == '2':
            raise TelstraAuthException('Please enter your username and '
                                       'password in the settings')
        if signon_query['errorcode'] == '3':
            raise TelstraAuthException('Invalid Telstra ID username/password. '
                                       'Please check your username and '
                                       'password in the settings')

    # Use BPSESSION cookie to ask for bearer token
    sso_headers = config.SSO_HEADERS
    sso_headers.update({'Cookie': 'BPSESSION={0}'.format(bp_session)})
    session.headers = sso_headers
    sso_token_resp = session.get(sso_url)
    bearer_token = dict(urlparse.parse_qsl(
                    urlparse.urlsplit(sso_token_resp.url)[4]))['access_token']

    # First check if there are any eligible services attached to the account
    prog_dialog.update(50, 'Determining eligible services')
    offer_id = dict(urlparse.parse_qsl(
                    urlparse.urlsplit(spc_url)[3]))['offerId']
    media_order_headers = config.MEDIA_ORDER_HEADERS
    media_order_headers.update(
        {'Authorization': 'Bearer {0}'.format(bearer_token)})
    session.headers = media_order_headers
    try:
        offers = session.get(config.OFFERS_URL)
    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 404:
            message = json.loads(e.response.text).get('userMessage')
            message += (' Please visit {0} '.format(config.HUB_URL) +
                        'for further instructions to link your mobile '
                        'service to the supplied Telstra ID')
            raise TelstraAuthException(message)
        else:
            raise TelstraAuthException(e.response.status_code)
    try:
        offer_data = json.loads(offers.text)
        offers_list = offer_data['data']['offers']
        ph_no = None
        for offer in offers_list:
            if offer.get('name') != 'NRL Live Pass':
                continue
            data = offer.get('productOfferingAttributes')
            ph_no = [x['value'] for x in data if x['name'] == 'ServiceId'][0]
        if not ph_no:
            raise TelstraAuthException(
                'Unable to determine if you have any eligible services. '
                'Please ensure there is an eligible service linked to '
                'your Telstra ID to redeem the free offer. Please visit '
                '{0} for further instructions'.format(config.HUB_URL))
    except Exception as e:
        raise e

    # 'Order' the subscription package to activate the service
    prog_dialog.update(66, 'Activating live pass on service')
    order_data = config.MEDIA_ORDER_JSON.format(ph_no, offer_id, token)
    order = session.post(config.MEDIA_ORDER_URL, data=order_data)

    # check to make sure order has been placed correctly
    if order.status_code == 201:
        try:
            order_json = json.loads(order.text)
            status = order_json['data'].get('status') == 'COMPLETE'
            if status:
                utils.log('Order status complete')
        except:
            utils.log('Unable to check status of order, continuing anyway')

    # Register the ticket
    prog_dialog.update(83, 'Registering live pass with ticket')
    session.headers = {'Accept': 'application/json',
                       'Accept-Encoding': 'gzip',
                       'Connection': 'Keep-Alive',
                       'User-Agent': 'okhttp/3.4.1',
                       'X-YinzCam-AppID': 'NRL_LIVE',
                       'X-YinzCam-Ticket': ticket}
    session.get(config.YINZ_CALLBACK_URL.format(token), allow_redirects=False)

    # Confirm everything has gone well
    prog_dialog.update(100, 'Checking status of Live Pass')
    sub_status = session.get(config.STATUS_URL)
    status_json = json.loads(sub_status.text)
    if status_json.get('Valid') != 'true':
        raise AussieAddonsException('Telstra ID activation failed: {0}'.format(
            status_json.get('Reason')))
    session.close()
    prog_dialog.update(100, 'Finished!')
    prog_dialog.close()
    return ticket
def get_mobile_token():
    session = custom_session.Session(force_tlsv1=False)
    prog_dialog = xbmcgui.DialogProgress()
    prog_dialog.create('Logging in with Telstra ID')

    # Send our first login request to Yinzcam, recieve (unactivated) ticket
    prog_dialog.update(1, 'Obtaining user ticket')
    adid = uuid.uuid4()
    deviceid = uuid.uuid4()
    session.headers = config.YINZCAM_AUTH_HEADERS
    ticket_resp = session.post(config.YINZCAM_AUTH_URL,
                               data=config.NEW_LOGIN_DATA1.format(
                                adid=adid, deviceid=deviceid))
    ticket_xml = ET.fromstring(ticket_resp.text)
    ticket = ticket_xml.find('Ticket').text
    session.headers = {'Accept': 'application/json, text/plain, */*',
                       'X-YinzCam-Ticket': ticket}

    # Send ticket back and get 'sports pass confirmation' URL and 'TpUid'
    yinz_resp = session.get(config.YINZCAM_AUTH_URL2)
    jsondata = json.loads(yinz_resp.text)
    token = jsondata.get('TpUid')
    spc_url = jsondata.get('Url')
    if not token or not spc_url:
        raise TelstraAuthException('Unable to get token/spc url from NRL API')

    prog_dialog.update(20, 'Obtaining mobile token')
    mobile_userid_cookies = session.get(
        config.MOBILE_ID_URL).cookies.get_dict()
    mobile_userid = mobile_userid_cookies.get('GUID_S')

    if not mobile_userid or mobile_userid_cookies.get('nouid'):
        raise TelstraAuthException('Not connected to Telstra Mobile network. '
                                   'Please disable WiFi and enable mobile '
                                   'data if on a Telstra mobile device, or '
                                   "connect this device's WiFi to a device "
                                   'that is on the Telstra Mobile network '
                                   'and try again.')

    data = config.MOBILE_TOKEN_PARAMS
    data.update({'x-user-id': mobile_userid})
    mobile_token_resp = session.post(config.OAUTH_URL, data=data)
    bearer_token = json.loads(mobile_token_resp.text).get('access_token')

    # First check if there are any eligible services attached to the account
    prog_dialog.update(40, 'Determining eligible services')
    session.headers = config.OAUTH_HEADERS
    session.headers.update(
        {'Authorization': 'Bearer {0}'.format(bearer_token)})
    try:
        offers = session.get(config.OLD_OFFERS_URL)
    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 404:
            message = json.loads(e.response.text).get('userMessage')
            message += (' Please visit {0} '.format(config.HUB_URL) +
                        'for further instructions to link your mobile '
                        'service to the supplied Telstra ID')
            raise TelstraAuthException(message)
        else:
            raise TelstraAuthException(e)
    try:
        offer_data = json.loads(offers.text)
        offers_list = offer_data['data']['offers']
        ph_no = None
        for offer in offers_list:
            if offer.get('name') != 'NRL Live Pass':
                continue
            data = offer.get('productOfferingAttributes')
            ph_no = [x['value'] for x in data if x['name'] == 'ServiceId'][0]
        if not ph_no:
            raise TelstraAuthException(
                'Unable to determine if you have any eligible services. '
                'Please ensure there is an eligible service linked to '
                'your Telstra ID to redeem the free offer. Please visit '
                '{0} for further instructions'.format(config.HUB_URL))
    except Exception as e:
        raise e

    # 'Order' the subscription package to activate the service
    prog_dialog.update(60, 'Activating live pass on service')
    order_data = config.MOBILE_ORDER_JSON
    order_data.update({'serviceId': ph_no, 'pai': token})
    order = session.post(config.OLD_MEDIA_ORDER_URL, json=order_data)

    # check to make sure order has been placed correctly
    prog_dialog.update(80, 'Confirming activation')
    if order.status_code == 201:
        try:
            order_json = json.loads(order.text)
            status = order_json['data'].get('status') == 'COMPLETE'
            if status:
                utils.log('Order status complete')
        except:
            utils.log('Unable to check status of order, continuing anyway')
    # Register the ticket
    prog_dialog.update(83, 'Registering live pass with ticket')
    session.headers = {'Accept': 'application/json',
                       'Accept-Encoding': 'gzip',
                       'Connection': 'Keep-Alive',
                       'User-Agent': 'okhttp/3.4.1',
                       'X-YinzCam-AppID': 'NRL_LIVE',
                       'X-YinzCam-Ticket': ticket}
    session.get(config.YINZ_CALLBACK_URL.format(token), allow_redirects=False)

    # Confirm everything has gone well
    prog_dialog.update(100, 'Checking status of Live Pass')
    sub_status = session.get(config.STATUS_URL)
    status_json = json.loads(sub_status.text)
    if status_json.get('Valid') != 'true':
        raise AussieAddonsException('Telstra ID activation failed: {0}'.format(
            status_json.get('Reason')))
    session.close()
    prog_dialog.update(100, 'Finished!')
    prog_dialog.close()
    return ticket