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

Code before:
            'channel': 'tjpw',
            'location': '東京・両国国技館',
            'duration': 18044,
            'timestamp': 1647665400,
            'upload_date': '20220319',
            'thumbnail': 'https://image.asset.wrestle-universe.com/i8jxSTCHPfdAKD4zN41Psx/i8jxSTCHPfdAKD4zN41Psx',
            'thumbnails': 'count:3',
        },
        'params': {
            'skip_download': 'm3u8',
        },
    }]

    _API_PATH = 'events'

    def _real_extract(self, url):
        lang, video_id = self._match_valid_url(url).group('lang', 'id')
        metadata = self._download_metadata(url, video_id, lang, 'eventFallbackData')

        info = traverse_obj(metadata, {
            'title': {lambda v: v.get('displayName') or ''},
            'description': ('description', {str}),
            'channel': ('labels', 'group', {str}),
            'location': ('labels', 'venue', {str}),
            'timestamp': ('startTime', {int_or_none}),
            'thumbnails': (('keyVisualUrl', 'alterKeyVisualUrl', 'heroKeyVisualUrl'), {url_or_none}, {'url': None}),
        })

        ended_time = traverse_obj(metadata, ('endedTime', {int_or_none}))
        if info.get('timestamp') and ended_time:
            info['duration'] = ended_time - info['timestamp']

        video_data, decrypt = self._call_encrypted_api(
            video_id, ':watchArchive', 'watch archive', data={'method': 1})
        formats = self._get_formats(video_data, (
            ('hls', None), ('urls', 'chromecastUrls'), ..., {url_or_none}), video_id)
        for f in formats:
            # bitrates are exaggerated in PPV playlists, so avoid wrong/huge filesize_approx values
            if f.get('tbr'):
                f['tbr'] = int(f['tbr'] / 2.5)

        hls_aes_key = traverse_obj(video_data, ('hls', 'key', {decrypt}))
        if not hls_aes_key and traverse_obj(video_data, ('hls', 'encryptType', {int}), default=0) > 0:
            self.report_warning('HLS AES-128 key was not found in API response')

        return {
            'id': video_id,
            'formats': formats,
            'hls_aes_key': hls_aes_key,
            'hls_aes_iv': traverse_obj(video_data, ('hls', 'iv', {decrypt})),
            **info,

Review comment (bug):
```suggestion
            # FIXME: Bug in traverse_obj
            # 'thumbnails': (('keyVisualUrl', 'alterKeyVisualUrl', 'heroKeyVisualUrl'), {'url': {url_or_none}}),
            'thumbnails': (('keyVisualUrl', 'alterKeyVisualUrl', 'heroKeyVisualUrl'), {url_or_none}, {'url': None}),
```

Code after:
            'channel': 'tjpw',
            'location': '東京・両国国技館',
            'duration': 18044,
            'timestamp': 1647665400,
            'upload_date': '20220319',
            'thumbnail': 'https://image.asset.wrestle-universe.com/i8jxSTCHPfdAKD4zN41Psx/i8jxSTCHPfdAKD4zN41Psx',
            'thumbnails': 'count:3',
        },
        'params': {
            'skip_download': 'm3u8',
        },
    }]

    _API_PATH = 'events'

    def _real_extract(self, url):
        lang, video_id = self._match_valid_url(url).group('lang', 'id')
        metadata = self._download_metadata(url, video_id, lang, 'eventFallbackData')

        info = traverse_obj(metadata, {
            'title': ('displayName', {str}),
            'description': ('description', {str}),
            'channel': ('labels', 'group', {str}),
            'location': ('labels', 'venue', {str}),
            'timestamp': ('startTime', {int_or_none}),
            'thumbnails': (('keyVisualUrl', 'alterKeyVisualUrl', 'heroKeyVisualUrl'), {'url': {url_or_none}}),
        })

        ended_time = traverse_obj(metadata, ('endedTime', {int_or_none}))
        if info.get('timestamp') and ended_time:
            info['duration'] = ended_time - info['timestamp']

        video_data, decrypt = self._call_encrypted_api(
            video_id, ':watchArchive', 'watch archive', data={'method': 1})
        formats = self._get_formats(video_data, (
            ('hls', None), ('urls', 'chromecastUrls'), ..., {url_or_none}), video_id)
        for f in formats:
            # bitrates are exaggerated in PPV playlists, so avoid wrong/huge filesize_approx values
            if f.get('tbr'):
                f['tbr'] = int(f['tbr'] / 2.5)

        hls_aes_key = traverse_obj(video_data, ('hls', 'key', {decrypt}))
        if not hls_aes_key and traverse_obj(video_data, ('hls', 'encryptType', {int}), default=0) > 0:
            self.report_warning('HLS AES-128 key was not found in API response')

        return {
            'id': video_id,
            'formats': formats,
            'hls_aes': {
                'key': hls_aes_key,
                'iv': traverse_obj(video_data, ('hls', 'iv', {decrypt})),