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

Code before:
                'standardized_nudges_misinfo': True,
                'tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled': False,
                'vibe_api_enabled': True,
            },
        }

    def _real_extract(self, url):
        space_id = self._match_id(url)
        space_data = self._call_graphql_api('HPEisOmj1epUNLCWTYhUWw/AudioSpaceById', space_id)

        if not space_data:
            self.raise_no_formats('Twitter Space not found', expected=True)

        info = self._parse_spaces_data(space_data.get('audioSpace'), space_id)

        formats = []
        media_key = info.pop('media_key')

        if info['live_status'] == 'is_upcoming':
            self.raise_no_formats('Twitter Space not started yet', expected=True)
        elif info['live_status'] == 'post_live':
            self.raise_no_formats('Twitter Space ended but not downloadable yet', expected=True)
        else:
            source = self._call_api(
                f'live_video_stream/status/{media_key}', media_key)['source']
            m3u8_url = source.get('noRedirectPlaybackUrl') or source['location']
            m3u8_id = 'live' if info['is_live'] else 'replay'

            # force entry_protocol to m3u8 because m3u8_native is broken
            formats = self._extract_m3u8_formats(
                m3u8_url, media_key, 'm4a',
                m3u8_id=m3u8_id, entry_protocol='m3u8',
                live=info['is_live'])
            # force audio-only
            for fmt in formats:
                fmt.update({
                    'vcodec': 'none',
                    'acodec': 'aac',
                })

        return {
            **info,
            'formats': formats,
        }


class TwitterShortenerIE(TwitterBaseIE):
    IE_NAME = 'twitter:shortener'
    _VALID_URL = r'https?://t.co/(?P<id>[^?]+)|tco:(?P<eid>[^?]+)'
    _BASE_URL = 'https://t.co/'


Review comment (suggestion):
```suggestion
            m3u8_url = traverse_obj(source, 'noRedirectPlaybackUrl', 'location', expected_type=str)
```

Code after:
                'responsive_web_edit_tweet_api_enabled': True,
                'responsive_web_enhance_cards_enabled': True,
                'responsive_web_uc_gql_enabled': True,
                'spaces_2022_h2_clipping': True,
                'spaces_2022_h2_spaces_communities': False,
                'standardized_nudges_misinfo': True,
                'tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled': False,
                'vibe_api_enabled': True,
            },
        }

    def _real_extract(self, url):
        space_id = self._match_id(url)
        space_data = self._call_graphql_api('HPEisOmj1epUNLCWTYhUWw/AudioSpaceById', space_id)['audioSpace']
        if not space_data:
            raise ExtractorError('Twitter Space not found', expected=True)

        metadata = space_data['metadata']
        live_status = try_call(lambda: self.SPACE_STATUS[metadata['state'].lower()])

        formats = []
        if live_status == 'is_upcoming':
            self.raise_no_formats('Twitter Space not started yet', expected=True)
        elif live_status == 'post_live':
            self.raise_no_formats('Twitter Space ended but not downloadable yet', expected=True)
        else:
            source = self._call_api(
                f'live_video_stream/status/{metadata["media_key"]}', metadata['media_key'])['source']

            # XXX: Native downloader does not work
            formats = self._extract_m3u8_formats(
                traverse_obj(source, 'noRedirectPlaybackUrl', 'location'),
                metadata['media_key'], 'm4a', 'm3u8', live=live_status == 'is_live')
            for fmt in formats:
                fmt.update({'vcodec': 'none', 'acodec': 'aac'})

        participants = ', '.join(traverse_obj(
            space_data, ('participants', 'speakers', ..., 'display_name'))) or 'nobody yet'
        return {
            'id': space_id,
            'title': metadata.get('title'),
            'description': f'Twitter Space participated by {participants}',
            'uploader': traverse_obj(
                metadata, ('creator_results', 'result', 'legacy', 'name')),
            'uploader_id': traverse_obj(
                metadata, ('creator_results', 'result', 'legacy', 'screen_name')),
            'live_status': live_status,
            'timestamp': metadata.get('created_at'),
            'formats': formats,
        }