Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/vrt.py (Python)

Code before:
            'duration': 33.08,
            'episode': '0',
            'episode_id': '3179360900145',
            'episode_number': 0,
            'ext': 'mp4',
            'id': 'pbs-pub-aa9397e9-ec2b-45f9-9148-7ce71b690b45$vid-04c67438-4866-4f5c-8978-51d173c0074b',
            'release_timestamp': 1699160400,
            'release_date': '20231105',
            'season': 'Trailer',
            'season_id': '/vrtnu/a-z/factcheckers/trailer/#tvseason',
            'season_number': 2023,
            'series': 'Factcheckers',
            'timestamp': 1699160400,
            'title': 'Factcheckers - Nieuwe afleveringen vanaf 15 november - Trailer | VRT MAX',
            'thumbnail': 'https://images.vrt.be/orig/2023/11/07/37d244f0-7d8a-11ee-91d7-02b7b76bf47f.jpg',
            'upload_date': '20231105',
        },
    },
    ]
    _VALID_URL = r'https?://(?:www\.)?vrt\.be/(vrtmax|vrtnu)/a-z/(?:[^/]+/){2}(?P<id>[^/?#&]+)'

    _VIDEOPAGE_QUERY = '''
    query VideoPage($pageId: ID!) {
        page(id: $pageId) {
            ... on EpisodePage {
                id
                title
                seo {
                    ... on SeoProperties {
                        __typename
                        description
                        title
                    }
                    __typename
                }
                ldjson
                episode {
                    ageRaw
                    episodeNumberRaw
                    program {
                        title
                        __typename
                    }
                    name
                    onTimeRaw
                    watchAction {
                        streamId
                        __typename
                    }
                    __typename
                }

Review comment (suggestion):
All `/vrtnu/a-z` links are redirecting to `/vrtmax/a-z`, so if wanted I can fully remove support for those URLs as well

Code after:
        if has_credentials:
            self.cache.store(self._NETRC_MACHINE, 'token_data', (access_token, video_token))

        return access_token, video_token

    def _get_vrt_cookie(self, cookie_name):
        # Refresh token cookie is scoped to /vrtmax/sso, others are scoped to /
        return try_call(lambda: self._get_cookies('https://www.vrt.be/vrtmax/sso')[cookie_name].value)

    @staticmethod
    def _is_jwt_token_expired(token):
        return jwt_decode_hs256(token)['exp'] - time.time() < 300

    def _perform_login(self, username, password):
        refresh_token = self._get_vrt_cookie(self._REFRESH_TOKEN_COOKIE_NAME)
        if refresh_token and not self._is_jwt_token_expired(refresh_token):
            self.write_debug('Using refresh token from logged-in cookies; skipping login with credentials')
            return

        refresh_token = self.cache.load(self._NETRC_MACHINE, 'refresh_token', default=None)
        if refresh_token and not self._is_jwt_token_expired(refresh_token):
            self.write_debug('Restored refresh token from cache')
            self._set_cookie(self._TOKEN_COOKIE_DOMAIN, self._REFRESH_TOKEN_COOKIE_NAME, refresh_token, path='/vrtmax/sso')
            return

        self._request_webpage(
            'https://www.vrt.be/vrtmax/sso/login', None,
            note='Getting session cookies', errnote='Failed to get session cookies')

        login_data = self._download_json(
            'https://login.vrt.be/perform_login', None, data=json.dumps({
                'clientId': 'vrtnu-site',
                'loginID': username,
                'password': password,
            }).encode(), headers={
                'Content-Type': 'application/json',
                'Oidcxsrf': self._get_cookies('https://login.vrt.be')['OIDCXSRF'].value,
            }, note='Logging in', errnote='Login failed', expected_status=403)
        if login_data.get('errorCode'):
            raise ExtractorError(f'Login failed: {login_data.get("errorMessage")}', expected=True)

        self._request_webpage(
            login_data['redirectUrl'], None,
            note='Getting access token', errnote='Failed to get access token')

        access_token = self._get_vrt_cookie(self._ACCESS_TOKEN_COOKIE_NAME)
        video_token = self._get_vrt_cookie(self._VIDEO_TOKEN_COOKIE_NAME)
        refresh_token = self._get_vrt_cookie(self._REFRESH_TOKEN_COOKIE_NAME)

        if not all((access_token, video_token, refresh_token)):
            raise ExtractorError('Unable to extract token cookie values')