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

Code before:
                video, (('baseUrl', 'base_url'), {self._FORMAT_ID_RE.search}, 1),
                ('id', {str_or_none}), get_all=False),
            'format': format_names.get(video.get('id')),
        } for video in traverse_obj(play_info, ('dash', 'video', ...)))

        if formats:
            self.check_missing_formats(play_info, formats)

        fragments = traverse_obj(play_info, ('durl', lambda _, v: url_or_none(v['url']), {
            'url': ('url', {url_or_none}),
            'duration': ('length', {lambda x: float_or_none(x, scale=1000)}),
            'filesize': ('size', {int_or_none}),
        }))
        if fragments:
            formats.append({
                'url': fragments[0]['url'],
                'filesize': sum(traverse_obj(fragments, (..., 'filesize'))),
                **({
                    'fragments': fragments,
                    'protocol': 'http_dash_segments',
                } if len(fragments) > 1 else {}),
                **traverse_obj(play_info, {
                    'quality': ('quality', {int_or_none}),
                    'format_id': ('quality', {str_or_none}),
                    'format_note': ('quality', {lambda x: format_names.get(x)}),
                    'duration': ('timelength', {lambda x: float_or_none(x, scale=1000)}),
                }),
                **parse_resolution(format_names.get(play_info.get('quality'))),
            })
        return formats

    def _get_wbi_key(self, video_id):
        if time.time() < self._wbi_key_cache.get('ts', 0) + self._WBI_KEY_CACHE_TIMEOUT:
            return self._wbi_key_cache['key']

        session_data = self._download_json(
            'https://api.bilibili.com/x/web-interface/nav', video_id, note='Downloading wbi sign')

        lookup = ''.join(traverse_obj(session_data, (
            'data', 'wbi_img', ('img_url', 'sub_url'),
            {lambda x: x.rpartition('/')[2].partition('.')[0]})))

        mixin_key_enc_tab = [
            46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
            33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
            61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
            36, 20, 34, 44, 52,
        ]

        self._wbi_key_cache.update({
            'key': ''.join(lookup[i] for i in mixin_key_enc_tab)[:32],

Review comment (suggestion):
```suggestion
                    'duration': ('timelength', {functools.partial(float_or_none, scale=1000)}),
```

Code after:
            'quality': int_or_none(video.get('id')),
            'format_id': traverse_obj(
                video, (('baseUrl', 'base_url'), {self._FORMAT_ID_RE.search}, 1),
                ('id', {str_or_none}), get_all=False),
            'format': format_names.get(video.get('id')),
        } for video in traverse_obj(play_info, ('dash', 'video', ...)))

        if formats:
            self._check_missing_formats(play_info, formats)

        fragments = traverse_obj(play_info, ('durl', lambda _, v: url_or_none(v['url']), {
            'url': ('url', {url_or_none}),
            'duration': ('length', {functools.partial(float_or_none, scale=1000)}),
            'filesize': ('size', {int_or_none}),
        }))
        if fragments:
            formats.append({
                'url': fragments[0]['url'],
                'filesize': sum(traverse_obj(fragments, (..., 'filesize'))),
                **({
                    'fragments': fragments,
                    'protocol': 'http_dash_segments',
                } if len(fragments) > 1 else {}),
                **traverse_obj(play_info, {
                    'quality': ('quality', {int_or_none}),
                    'format_id': ('quality', {str_or_none}),
                    'format_note': ('quality', {lambda x: format_names.get(x)}),
                    'duration': ('timelength', {functools.partial(float_or_none, scale=1000)}),
                }),
                **parse_resolution(format_names.get(play_info.get('quality'))),
            })
        return formats

    def _get_wbi_key(self, video_id):
        if time.time() < self._wbi_key_cache.get('ts', 0) + self._WBI_KEY_CACHE_TIMEOUT:
            return self._wbi_key_cache['key']

        session_data = self._download_json(
            'https://api.bilibili.com/x/web-interface/nav', video_id, note='Downloading wbi sign')

        lookup = ''.join(traverse_obj(session_data, (
            'data', 'wbi_img', ('img_url', 'sub_url'),
            {lambda x: x.rpartition('/')[2].partition('.')[0]})))

        # from getMixinKey() in the vendor js
        mixin_key_enc_tab = [
            46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
            33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
            61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
            36, 20, 34, 44, 52,
        ]