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

Code before:
            headers.update({
                'x-twitter-auth-type': 'OAuth2Session',
                'x-twitter-client-language': 'en',
                'x-twitter-active-user': 'yes',
            })

        for first_attempt in (True, False):
            if not self.is_logged_in:
                if not self._token:
                    headers.pop('x-guest-token', None)
                    self._token = traverse_obj(self._download_json(
                        self._API_BASE + 'guest/activate.json', video_id,
                        'Downloading guest token', data=b'', headers=headers), 'guest_token')
                    if not self._token:
                        raise ExtractorError('Could not retrieve guest token')
                headers['x-guest-token'] = self._token

            allowed_status = {400, 403, 404} if graphql else {403}
            result = self._download_json(
                (self._GRAPHQL_API_BASE if graphql else self._API_BASE) + path,
                video_id, headers=headers, query=query, expected_status=allowed_status,
                note=f'Downloading {"GraphQL" if graphql else "legacy API"} JSON')

            if result.get('errors'):
                errors = traverse_obj(result, ('errors', ..., 'message', {str}))
                if first_attempt and any('bad guest token' in error.lower() for error in errors):
                    self.to_screen('Guest token has expired. Refreshing guest token')
                    self._token = None
                    continue

                error_message = ', '.join(set(errors)) or 'Unknown error'
                raise ExtractorError(f'Error(s) while querying API: {error_message}', expected=True)

            return result

    def _build_graphql_query(self, media_id):
        raise NotImplementedError('Method must be implemented to support GraphQL')

    def _call_graphql_api(self, endpoint, media_id):
        data = self._build_graphql_query(media_id)
        query = {key: json.dumps(value, separators=(',', ':')) for key, value in data.items()}
        return traverse_obj(self._call_api(endpoint, media_id, query=query, graphql=True), 'data')


class TwitterCardIE(InfoExtractor):
    IE_NAME = 'twitter:card'
    _VALID_URL = TwitterBaseIE._BASE_REGEX + r'i/(?:cards/tfw/v1|videos(?:/tweet)?)/(?P<id>\d+)'
    _TESTS = [
        {
            'url': 'https://twitter.com/i/cards/tfw/v1/560070183650213889',
            # MD5 checksums are different in different places

Review comment (suggestion):
```suggestion
                if first_attempt and not self.is_logged_in and any('bad guest token' in error.lower() for error in errors):
```
correct? Otherwise it may unnecessarily try twice when logged in.

Code after:
            headers.update({
                'x-twitter-auth-type': 'OAuth2Session',
                'x-twitter-client-language': 'en',
                'x-twitter-active-user': 'yes',
            })

        for first_attempt in (True, False):
            if not self.is_logged_in and not self._guest_token:
                headers.pop('x-guest-token', None)
                self._guest_token = traverse_obj(self._download_json(
                    f'{self._API_BASE}guest/activate.json', video_id,
                    'Downloading guest token', data=b'', headers=headers), 'guest_token')
            if self._guest_token:
                headers['x-guest-token'] = self._guest_token
            elif not self.is_logged_in:
                raise ExtractorError('Could not retrieve guest token')

            allowed_status = {400, 401, 403, 404} if graphql else {403}
            result = self._download_json(
                (self._GRAPHQL_API_BASE if graphql else self._API_BASE) + path,
                video_id, headers=headers, query=query, expected_status=allowed_status,
                note=f'Downloading {"GraphQL" if graphql else "legacy API"} JSON')

            if result.get('errors'):
                errors = ', '.join(set(traverse_obj(result, ('errors', ..., 'message', {str}))))
                if not self.is_logged_in and first_attempt and 'bad guest token' in errors.lower():
                    self.to_screen('Guest token has expired. Refreshing guest token')
                    self._guest_token = None
                    continue

                raise ExtractorError(
                    f'Error(s) while querying API: {errors or "Unknown error"}', expected=True)

            return result

    def _build_graphql_query(self, media_id):
        raise NotImplementedError('Method must be implemented to support GraphQL')

    def _call_graphql_api(self, endpoint, media_id):
        data = self._build_graphql_query(media_id)
        query = {key: json.dumps(value, separators=(',', ':')) for key, value in data.items()}
        return traverse_obj(self._call_api(endpoint, media_id, query=query, graphql=True), 'data')


class TwitterCardIE(InfoExtractor):
    IE_NAME = 'twitter:card'
    _VALID_URL = TwitterBaseIE._BASE_REGEX + r'i/(?:cards/tfw/v1|videos(?:/tweet)?)/(?P<id>\d+)'
    _TESTS = [
        {
            'url': 'https://twitter.com/i/cards/tfw/v1/560070183650213889',
            # MD5 checksums are different in different places