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

Code before:
                    raise
                raise ExtractorError(re.sub(r'\s+', ' ', error_msg), expected=True)

        club_joined = traverse_obj(api_data, ('channel', 'viewer', 'follow', 'isFollowed', {bool}))
        if club_joined is None:
            fail_msg = self._html_search_regex(
                r'<p[^>]+\bclass="fail-message"[^>]*>(?P<msg>.+)</p>',
                webpage, 'fail message', default=None, group='msg')
            if fail_msg:
                self.raise_login_required(re.sub(r'\s+', ' ', fail_msg), metadata_available=True)
        elif not club_joined:
            self.raise_login_required('This video is for members only', metadata_available=True)

        formats = []

        def get_video_info(*items, get_first=True, **kwargs):
            return traverse_obj(api_data, ('video', *items), get_all=not get_first, **kwargs)

        dmc_data = traverse_obj(api_data, (
            'media', 'delivery', 'movie', {
                'audios': 'audios',
                'videos': 'videos',
                'protocols': ('session', 'protocols'),
            }, {lambda data: data if all(key in data for key in ['audios', 'videos', 'protocols']) else None},
        ))
        if dmc_data:
            for (audio_quality, video_quality, protocol) in itertools.product(
                    dmc_data['audios'], dmc_data['videos'], dmc_data['protocols']):
                fmt = self._extract_format_for_quality(video_id, audio_quality, video_quality, protocol)
                if fmt:
                    formats.append(fmt)

        dms_data = traverse_obj(api_data, ({
            'videos': ('media', 'domand', 'videos', ..., {
                lambda item: item['id'] if item['isAvailable'] else None
            }),
            'audios': ('media', 'domand', 'audios', ..., {
                lambda item: (item['id'], {
                    'format_id': str(parse_bitrate(item['id'])),
                    'abr': float_or_none(item['bitRate'], scale=1000),
                    'asr': item['samplingRate'],
                    'acodec': 'aac',
                    'ext': 'm4a',
                }) if item['isAvailable'] else None
            }),
            'accessRightKey': ('media', 'domand', 'accessRightKey'),
            'track_id': ('client', 'watchTrackId'),
        }, {
            'videos': 'videos',
            'audios': ('audios', {lambda items: dict(items)}),
            'accessRightKey': 'accessRightKey',

Review comment (refactor):
are `videos`/`audios` supposed to be a list of dicts and `protocols` supposed to be list of strings? we could do this, and simplify the key checking:
```suggestion
        dmc_data = traverse_obj(api_data, ('media', 'delivery', 'movie', {
            'audios': ('audios', ..., {dict}),
            'videos': ('videos', ..., {dict}),
            'protocols': ('session', 'protocols', ..., {str}),
        }))
        if len(dmc_data) == 3:
```

Code after:
                'x-frontend-version': 0,
                'x-request-with': 'https://www.nicovideo.jp',
            })['data']['contentUrl']
        # Getting all audio formats results in duplicate video formats which we filter out later
        dms_fmts = self._extract_m3u8_formats(dms_m3u8_url, video_id)

        # m3u8 extraction does not provide audio bitrates, so extract from the API data and fix
        for audio_fmt in traverse_obj(dms_fmts, lambda _, v: v['vcodec'] == 'none'):
            yield {
                **audio_fmt,
                **traverse_obj(audios, (lambda _, v: audio_fmt['format_id'].startswith(v['id']), {
                    'format_id': ('id', {str}),
                    'abr': ('bitRate', {functools.partial(float_or_none, scale=1000)}),
                    'asr': ('samplingRate', {int_or_none}),
                }), get_all=False),
                'acodec': 'aac',
                'ext': 'm4a',
            }

        # Sort before removing dupes to keep the format dicts with the lowest tbr
        video_fmts = sorted((fmt for fmt in dms_fmts if fmt['vcodec'] != 'none'), key=lambda f: f['tbr'])
        self._remove_duplicate_formats(video_fmts)
        # Calculate the true vbr/tbr by subtracting the lowest abr
        min_abr = min(traverse_obj(audios, (..., 'bitRate', {float_or_none})), default=0) / 1000
        for video_fmt in video_fmts:
            video_fmt['tbr'] -= min_abr
            video_fmt['format_id'] = f'video-{video_fmt["tbr"]:.0f}'
            yield video_fmt

    def _real_extract(self, url):
        video_id = self._match_id(url)

        try:
            webpage, handle = self._download_webpage_handle(
                'https://www.nicovideo.jp/watch/' + video_id, video_id)
            if video_id.startswith('so'):
                video_id = self._match_id(handle.url)

            api_data = self._parse_json(self._html_search_regex(
                'data-api-data="([^"]+)"', webpage,
                'API data', default='{}'), video_id)
        except ExtractorError as e:
            try:
                api_data = self._download_json(
                    'https://www.nicovideo.jp/api/watch/v3/%s?_frontendId=6&_frontendVersion=0&actionTrackId=AAAAAAAAAA_%d' % (video_id, round(time.time() * 1000)), video_id,
                    note='Downloading API JSON', errnote='Unable to fetch data')['data']
            except ExtractorError:
                if not isinstance(e.cause, HTTPError):
                    raise
                webpage = e.cause.response.read().decode('utf-8', 'replace')
                error_msg = self._html_search_regex(