예제 #1
0
    def _get_new_xvrttoken(self, login_json, token_variant=None):
        """Get new X-VRT-Token from VRT NU website"""

        if token_variant == 'roaming':
            xvrttoken = self._get_roaming_xvrttoken()
        else:
            login_token = login_json.get('sessionInfo', {}).get('login_token')
            if not login_token:
                return None

            from json import dumps
            login_cookie = 'glt_{api_key}={token}'.format(api_key=self._API_KEY, token=login_token)
            payload = dict(
                uid=login_json.get('UID'),
                uidsig=login_json.get('UIDSignature'),
                ts=login_json.get('signatureTimestamp'),
                email=from_unicode(get_setting('username')),
            )
            data = dumps(payload).encode()
            headers = {'Content-Type': 'application/json', 'Cookie': login_cookie}
            log(2, 'URL post: {url}', url=unquote(self._TOKEN_GATEWAY_URL))
            req = Request(self._TOKEN_GATEWAY_URL, data=data, headers=headers)
            try:  # Python 3
                setcookie_header = urlopen(req).info().get('Set-Cookie')
            except AttributeError:  # Python 2
                setcookie_header = urlopen(req).info().getheader('Set-Cookie')
            xvrttoken = TokenResolver._create_token_dictionary(setcookie_header)

        if xvrttoken is None:
            return None
        self._set_cached_token(xvrttoken, token_variant)
        notification(message=localize(30952))  # Login succeeded.
        return xvrttoken.get('X-VRT-Token')
예제 #2
0
 def _get_xvrttoken(self, login_json=None):
     """Get a one year valid X-VRT-Token"""
     from json import dumps
     if not login_json:
         login_json = self._get_login_json()
     login_token = login_json.get('sessionInfo', {}).get('login_token')
     if not login_token:
         return None
     login_cookie = 'glt_{api_key}={token}'.format(api_key=self._API_KEY,
                                                   token=login_token)
     payload = dict(uid=login_json.get('UID'),
                    uidsig=login_json.get('UIDSignature'),
                    ts=login_json.get('signatureTimestamp'),
                    email=from_unicode(get_setting('username')))
     data = dumps(payload).encode()
     headers = {'Content-Type': 'application/json', 'Cookie': login_cookie}
     response = open_url(self._TOKEN_GATEWAY_URL,
                         data=data,
                         headers=headers)
     if response is None:
         return None
     setcookie_header = response.info().get('Set-Cookie')
     xvrttoken = TokenResolver._create_token_dictionary(setcookie_header)
     if xvrttoken is None:
         return None
     notification(message=localize(30952))  # Login succeeded.
     return xvrttoken
예제 #3
0
 def watchlater(self, episode_id, title):
     """Watch an episode later"""
     succeeded = self.update_watchlater(episode_id=episode_id,
                                        title=title,
                                        watch_later=True)
     if succeeded:
         notification(message=localize(30403, title=title))
         container_refresh()
 def unfollow(self, program_name, title, program_id=None, move_down=False):
     """Unfollow your favorite program"""
     succeeded = self.update(program_name, title, program_id, False)
     if succeeded:
         notification(message=localize(30412, title=title))
         # If the current item is selected and we need to move down before removing
         if move_down:
             input_down()
         container_refresh()
예제 #5
0
 def watchlater(self, uuid, title, url):
     ''' Watch an episode later '''
     succeeded = self.update(uuid=uuid,
                             title=title,
                             url=url,
                             watch_later=True)
     if succeeded:
         notification(message=localize(30403, title=title))
         container_refresh()
예제 #6
0
 def watchlater(self, asset_id, title, url):
     """Watch an episode later"""
     succeeded = self.update(asset_id=asset_id,
                             title=title,
                             url=url,
                             watch_later=True)
     if succeeded:
         notification(message=localize(30403, title=title))
         container_refresh()
 def unwatchlater(self, asset_id, title, url, move_down=False):
     """Unwatch an episode later"""
     succeeded = self.update(asset_id=asset_id, title=title, url=url, watch_later=False)
     if succeeded:
         notification(message=localize(30404, title=title))
         # If the current item is selected and we need to move down before removing
         if move_down:
             input_down()
         container_refresh()
 def update_online(self, asset_id, title, url, payload):
     """Update resumepoint online"""
     from json import dumps
     try:
         get_url_json('https://video-user-data.vrt.be/resume_points/{asset_id}'.format(asset_id=asset_id),
                      headers=self.resumepoint_headers(url), data=dumps(payload).encode())
     except HTTPError as exc:
         log_error('Failed to (un)watch episode {title} at VRT NU ({error})', title=title, error=exc)
         notification(message=localize(30977, title=title))
         return False
     return True
예제 #9
0
 def resumepoints_headers():
     """Generate http headers for VRT NU Resumepoint API"""
     from tokenresolver import TokenResolver
     vrtlogin_at = TokenResolver().get_token('vrtlogin-at')
     headers = {}
     if vrtlogin_at:
         headers = {
             'Authorization': 'Bearer ' + vrtlogin_at,
             'Content-Type': 'application/json',
         }
     else:
         log_error('Failed to get access token from VRT NU')
         notification(message=localize(30975))
     return headers
예제 #10
0
 def delete_tokens():
     """Delete all cached tokens"""
     # Remove old tokens
     # FIXME: Deprecate and simplify this part in a future version
     _, files = listdir(addon_profile())
     token_files = [item for item in files if item.endswith('.tkn')]
     # Empty userdata/tokens/ directory
     if exists(get_tokens_path()):
         _, files = listdir(get_tokens_path())
         token_files += ['tokens/' + item for item in files]
     if token_files:
         for item in token_files:
             delete(addon_profile() + item)
         notification(message=localize(30985))
예제 #11
0
 def delete_tokens():
     ''' Delete all cached tokens '''
     # Remove old tokens
     # FIXME: Deprecate and simplify this part in a future version
     dirs, files = listdir(get_userdata_path())  # pylint: disable=unused-variable
     token_files = [item for item in files if item.endswith('.tkn')]
     # Empty userdata/tokens/ directory
     if exists(get_tokens_path()):
         dirs, files = listdir(get_tokens_path())  # pylint: disable=unused-variable
         token_files += ['tokens/' + item for item in files]
     if token_files:
         for item in token_files:
             delete(get_userdata_path() + item)
         notification(message=localize(30985))
예제 #12
0
def login(username, password):
    resp = requests.post(
        "https://api.jio.com/v3/dip/user/unpw/verify",
        headers={"x-api-key": "l7xx938b6684ee9e4bbe8831a9a682b8e19f"},
        json={
            "identifier": username if '@' in username else "+91" + username,
            "password": password,
            "rememberUser": "******",
            "upgradeAuth": "Y",
            "returnSessionDetails": "T",
            "deviceInfo": {
                "consumptionDeviceName": "Jio",
                "info": {
                    "type": "android",
                    "platform": {
                        "name": "vbox86p",
                        "version": "8.0.0"
                    },
                    "androidId": "6fcadeb7b4b10d77"
                }
            }
        })
    if resp.status_code == 200 and resp.json()['ssoToken']:
        data = resp.json()
        _CREDS = urlencode({
            "ssotoken":
            data['ssoToken'],
            "userId":
            data['sessionAttributes']['user']['uid'],
            "uniqueId":
            data['sessionAttributes']['user']['unique'],
            "crmid":
            data['sessionAttributes']['user']['subscriberId']
        })
        with open(
                xbmc.translatePath(
                    'special://home/addons/plugin.video.jiotv/resources/extra/channels.json'
                ), 'r') as f:
            raw = json.load(f)
        with open(ADDONDATA + 'channels.json', 'w+') as f:
            for cid, itm in raw.items():
                if int(cid) in _STAR_CHANNELS.keys():
                    raw[cid]['url'] = itm['url'] + \
                        "?hdnea={token}|User-Agent=Hotstar%3Bin.startv.hotstar%2F8.2.4+%28Linux%3BAndroid+8.0.0%29+ExoPlayerLib%2F2.9.5&"+_CREDS
                else:
                    raw[cid]['url'] = itm[
                        'url'] + "?{token}|appkey=NzNiMDhlYzQyNjJm&lbcookie=1&devicetype=phone&deviceId=6fcadeb7b4b10d77&srno=200206173037&usergroup=tvYR7NSNn7rymo3F&versionCode=226&channelid=100&os=android&User-Agent=plaYtv%2F5.4.0+%28Linux%3BAndroid+8.0.0%29+ExoPlayerLib%2F2.3.0&" + _CREDS
            json.dump(raw, f, indent=2)
    else:
        kodiutils.notification('Login Failed', 'Invalid credentials')
예제 #13
0
    def update(self, program, title, value=True):
        """Set a program as favorite, and update local copy"""

        # Survive any recent updates
        self.refresh(ttl=5)

        if value is self.is_favorite(program):
            # Already followed/unfollowed, nothing to do
            return True

        from tokenresolver import TokenResolver
        xvrttoken = TokenResolver().get_xvrttoken(token_variant='user')
        if xvrttoken is None:
            log_error('Failed to get favorites token from VRT NU')
            notification(message=localize(30975))
            return False

        headers = {
            'authorization': 'Bearer ' + xvrttoken,
            'content-type': 'application/json',
            'Referer': 'https://www.vrt.be/vrtnu',
        }

        from json import dumps
        from utils import program_to_url
        payload = dict(isFavorite=value,
                       programUrl=program_to_url(program, 'short'),
                       title=title)
        data = dumps(payload).encode('utf-8')
        program_id = program_to_id(program)
        try:
            get_url_json(
                'https://video-user-data.vrt.be/favorites/{program_id}'.format(
                    program_id=program_id),
                headers=headers,
                data=data)
        except HTTPError as exc:
            log_error(
                "Failed to (un)follow program '{program}' at VRT NU ({error})",
                program=program,
                error=exc)
            notification(message=localize(30976, program=program))
            return False
        # NOTE: Updates to favorites take a longer time to take effect, so we keep our own cache and use it
        self._data[program_id] = dict(value=payload)
        update_cache('favorites.json', dumps(self._data))
        invalidate_caches('my-offline-*.json', 'my-recent-*.json')
        return True
예제 #14
0
def login(username, password):
    resp = requests.post(
        "https://api.jio.com/v3/dip/user/unpw/verify",
        headers={"x-api-key": "l7xx938b6684ee9e4bbe8831a9a682b8e19f"},
        json={
            "identifier": username if '@' in username else "+91" + username,
            "password": password,
            "rememberUser": "******",
            "upgradeAuth": "Y",
            "returnSessionDetails": "T",
            "deviceInfo": {
                "consumptionDeviceName": "Jio",
                "info": {
                    "type": "android",
                    "platform": {
                        "name": "vbox86p",
                        "version": "8.0.0"
                    },
                    "androidId": "6fcadeb7b4b10d77"
                }
            }
        })
    if resp.status_code == 200 and resp.json()['ssoToken']:
        data = resp.json()
        _CREDS = {
            "ssotoken": data['ssoToken'],
            "userId": data['sessionAttributes']['user']['uid'],
            "uniqueId": data['sessionAttributes']['user']['unique'],
            "crmid": data['sessionAttributes']['user']['subscriberId']
        }
        headers = {
            "User-Agent": "JioTV Kodi",
            "os": "Kodi",
            "deviceId": str(uuid.uuid4()),
            "versionCode": "226",
            "devicetype": "Kodi",
            "srno":
            datetime.today().strftime("%y%m%d%H%M%S"),  # "200206173037",
            "appkey": "NzNiMDhlYzQyNjJm",
            "channelid": str(random.randint(100, 200)),
            "usergroup": "tvYR7NSNn7rymo3F",
            "lbcookie": "1"
        }
        headers.update(_CREDS)
        with open(TOKEN_FILE_PATH, 'w+') as f:
            json.dump(headers, f, indent=4)
    else:
        kodiutils.notification('Login Failed', 'Invalid credentials')
예제 #15
0
 def watchlater_headers(url=None):
     """Generate http headers for VRT NU watchLater API"""
     from tokenresolver import TokenResolver
     xvrttoken = TokenResolver().get_token('X-VRT-Token', variant='user')
     headers = {}
     if xvrttoken:
         url = 'https://www.vrt.be' + url if url else 'https://www.vrt.be/vrtnu'
         headers = {
             'Authorization': 'Bearer ' + xvrttoken,
             'Content-Type': 'application/json',
             'Referer': url,
         }
     else:
         log_error('Failed to get usertoken from VRT NU')
         notification(message=localize(30975))
     return headers
예제 #16
0
 def resumepoint_headers(url=None):
     """Generate http headers for VRT NU Resumepoints API"""
     from tokenresolver import TokenResolver
     xvrttoken = TokenResolver().get_xvrttoken(token_variant='user')
     headers = {}
     if xvrttoken:
         url = 'https://www.vrt.be' + url if url else 'https://www.vrt.be/vrtnu'
         headers = {
             'authorization': 'Bearer ' + xvrttoken,
             'content-type': 'application/json',
             'Referer': url,
         }
     else:
         log_error('Failed to get usertoken from VRT NU')
         notification(message=localize(30975))
     return headers
예제 #17
0
def check_login():
    username = kodiutils.get_setting('username')
    password = kodiutils.get_setting('password')

    if os.path.isfile(ADDONDATA + 'headers.json'):
        return True
    elif username and password and not os.path.isfile(ADDONDATA +
                                                      'headers.json'):
        login(username, password)
        return True
    else:
        kodiutils.notification(
            'Login Error',
            'You need to login with Jio Username and password to use this plugin'
        )
        kodiutils.show_settings()
        return False
예제 #18
0
def check_login():
    username = kodiutils.get_setting('username')
    password = kodiutils.get_setting('password')

    # token is 5 days old ?
    if os.path.isfile(TOKEN_FILE_PATH) and time.time(
    ) < os.path.getmtime(TOKEN_FILE_PATH) + 432000000:
        return True
    elif username and password:
        login(username, password)
        return True
    else:
        kodiutils.notification(
            'Login Error',
            'You need to login with Jio Username and password to use this add-on'
        )
        kodiutils.show_settings()
        return False
예제 #19
0
    def update(self, program, title, value=True):
        ''' Set a program as favorite, and update local copy '''

        self.refresh(ttl=60)
        if value is self.is_favorite(program):
            # Already followed/unfollowed, nothing to do
            return True

        from tokenresolver import TokenResolver
        xvrttoken = TokenResolver().get_xvrttoken(token_variant='user')
        if xvrttoken is None:
            log_error('Failed to get favorites token from VRT NU')
            notification(message=localize(30975))
            return False

        headers = {
            'authorization': 'Bearer ' + xvrttoken,
            'content-type': 'application/json',
            'Referer': 'https://www.vrt.be/vrtnu',
        }

        from statichelper import program_to_url
        payload = dict(isFavorite=value, programUrl=program_to_url(program, 'short'), title=title)
        from json import dumps
        data = dumps(payload).encode('utf-8')
        program_uuid = self.program_to_uuid(program)
        log(2, 'URL post: https://video-user-data.vrt.be/favorites/{uuid}', uuid=program_uuid)
        req = Request('https://video-user-data.vrt.be/favorites/%s' % program_uuid, data=data, headers=headers)
        result = urlopen(req)
        if result.getcode() != 200:
            log_error("Failed to (un)follow program '{program}' at VRT NU", program=program)
            notification(message=localize(30976, program=program))
            return False
        # NOTE: Updates to favorites take a longer time to take effect, so we keep our own cache and use it
        self._favorites[program_uuid] = dict(value=payload)
        update_cache('favorites.json', self._favorites)
        invalidate_caches('my-offline-*.json', 'my-recent-*.json')
        return True
예제 #20
0
    def update(self,
               uuid,
               title,
               url,
               watch_later=None,
               position=None,
               total=None):
        ''' Set program resumepoint or watchLater status and update local copy '''

        # The video has no assetPath, so we cannot update resumepoints
        if uuid is None:
            return True

        if position is not None and position >= total - 30:
            watch_later = False

        self.refresh(ttl=0)
        if watch_later is not None and position is None and total is None and watch_later is self.is_watchlater(
                uuid):
            # watchLater status is not changed, nothing to do
            return True

        if watch_later is None and position == self.get_position(
                uuid) and total == self.get_total(uuid):
            # resumepoint is not changed, nothing to do
            return True

        # Collect header info for POST Request
        from tokenresolver import TokenResolver
        xvrttoken = TokenResolver().get_xvrttoken(token_variant='user')
        if xvrttoken is None:
            log_error('Failed to get usertoken from VRT NU')
            notification(message=localize(30975) + title)
            return False

        headers = {
            'authorization': 'Bearer ' + xvrttoken,
            'content-type': 'application/json',
            'Referer': 'https://www.vrt.be' + url,
        }

        if uuid in self._resumepoints:
            # Update existing resumepoint values
            payload = self._resumepoints[uuid]['value']
            payload['url'] = url
        else:
            # Create new resumepoint values
            payload = dict(position=0, total=100, url=url, watchLater=False)

        if position is not None:
            payload['position'] = position

        if total is not None:
            payload['total'] = total

        removes = []
        if position is not None or total is not None:
            removes.append('continue-*.json')

        if watch_later is not None:
            # Add watchLater status to payload
            payload['watchLater'] = watch_later
            removes.append('watchlater-*.json')

        from json import dumps
        data = dumps(payload).encode()
        log(2,
            'URL post: https://video-user-data.vrt.be/resume_points/{uuid}',
            uuid=uuid)
        log(2, 'URL post data:: {data}', data=data)
        try:
            req = Request('https://video-user-data.vrt.be/resume_points/%s' %
                          uuid,
                          data=data,
                          headers=headers)
            urlopen(req)
        except HTTPError as exc:
            log_error('Failed to (un)watch episode at VRT NU ({error})',
                      error=exc)
            notification(message=localize(30977))
            return False

        # NOTE: Updates to resumepoints take a longer time to take effect, so we keep our own cache and use it
        self._resumepoints[uuid] = dict(value=payload)
        update_cache('resume_points.json', self._resumepoints)
        invalidate_caches(*removes)
        return True
예제 #21
0
    def update_resumepoint(self,
                           video_id,
                           asset_str,
                           title,
                           position=None,
                           total=None,
                           path=None,
                           episode_id=None,
                           episode_title=None):
        """Set episode resumepoint and update local copy"""

        if video_id is None:
            return True

        menu_caches = []
        self.refresh_resumepoints(ttl=5)

        # Add existing position and total if None
        if video_id in self._resumepoints and position is None and total is None:
            position = self.get_position(video_id)
            total = self.get_total(video_id)

        # Update
        if (self.still_watching(position, total) or
            (path
             and path.startswith('plugin://plugin.video.vrt.nu/play/upnext'))):
            # Normally, VRT NU resumepoints are deleted when an episode is (un)watched and Kodi GUI automatically sets
            # the (un)watched status when Kodi Player exits. This mechanism doesn't work with "Up Next" episodes because
            # these episodes are not initiated from a ListItem in Kodi GUI.
            # For "Up Next" episodes, we should never delete the VRT NU resumepoints to make sure the watched status
            # can be forced in Kodi GUI using the playcount infolabel.
            log(3,
                "[Resumepoints] Update resumepoint '{video_id}' {position}/{total}",
                video_id=video_id,
                position=position,
                total=total)

            if position == self.get_position(
                    video_id) and total == self.get_total(video_id):
                # Resumepoint is not changed, nothing to do
                return True

            menu_caches.append('continue-*.json')

            # Update online
            gdpr = '{asset_str} gekeken tot {at} seconden.'.format(
                asset_str=asset_str, at=position)
            payload = dict(
                at=position,
                total=total,
                gdpr=gdpr,
            )
            from json import dumps
            try:
                resumepoint_json = get_url_json(
                    '{api}/{video_id}'.format(api=self.RESUMEPOINTS_URL,
                                              video_id=video_id),
                    headers=self.resumepoints_headers(),
                    data=dumps(payload).encode())
            except HTTPError as exc:
                log_error(
                    'Failed to update resumepoint of {title} at VRT NU ({error})',
                    title=title,
                    error=exc)
                notification(message=localize(30977, title=title))
                return False

            # Update local
            for idx, item in enumerate(self._resumepoints.get('items')):
                if item.get('mediaId') == video_id:
                    self._resumepoints.get('items')[idx] = resumepoint_json
                    break
            update_cache(self.RESUMEPOINTS_CACHE_FILE,
                         dumps(self._resumepoints))
            if menu_caches:
                invalidate_caches(*menu_caches)
        else:

            # Delete
            log(3,
                "[Resumepoints] Delete resumepoint '{asset_str}' {position}/{total}",
                asset_str=asset_str,
                position=position,
                total=total)

            # Delete watchlater
            self.update_watchlater(episode_id,
                                   episode_title,
                                   watch_later=False)

            # Do nothing if there is no resumepoint for this video_id
            from json import dumps
            if video_id not in dumps(self._resumepoints):
                log(3,
                    "[Resumepoints] '{video_id}' not present, nothing to delete",
                    video_id=video_id)
                return True

            # Add menu caches
            menu_caches.append('continue-*.json')

            # Delete online
            try:
                result = open_url('{api}/{video_id}'.format(
                    api=self.RESUMEPOINTS_URL, video_id=video_id),
                                  headers=self.resumepoints_headers(),
                                  method='DELETE',
                                  raise_errors='all')
                log(3,
                    "[Resumepoints] '{video_id}' online deleted: {code}",
                    video_id=video_id,
                    code=result.getcode())
            except HTTPError as exc:
                log_error(
                    "Failed to remove resumepoint of '{video_id}': {error}",
                    video_id=video_id,
                    error=exc)
                return False

            # Delete local representation and cache
            for item in self._resumepoints.get('items'):
                if item.get('mediaId') == video_id:
                    self._resumepoints.get('items').remove(item)
                    break

            update_cache(self.RESUMEPOINTS_CACHE_FILE,
                         dumps(self._resumepoints))
            if menu_caches:
                invalidate_caches(*menu_caches)
        return True
예제 #22
0
 def follow(self, program, title):
     ''' Follow your favorite program '''
     succeeded = self.update(program, title, True)
     if succeeded:
         notification(message=localize(30411, title=title))
         container_refresh()
예제 #23
0
def favorites_refresh():
    ''' The API interface to refresh the favorites cache '''
    from favorites import Favorites
    Favorites().refresh(ttl=0)
    notification(message=localize(30982))
예제 #24
0
def resumepoints_refresh():
    ''' The API interface to refresh the resumepoints cache '''
    from resumepoints import ResumePoints
    ResumePoints().refresh(ttl=0)
    notification(message=localize(30983))
예제 #25
0
 def follow(self, program_name, title, program_id=None):
     """Follow your favorite program"""
     succeeded = self.update(program_name, title, program_id, True)
     if succeeded:
         notification(message=localize(30411, title=title))
         container_refresh()