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

Code before:
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        headers = self.geo_verification_headers()
        webpage, urlh = self._download_webpage_handle(url, video_id, headers=headers)
        if not self._match_valid_url(urlh.url):
            return self.url_result(urlh.url)

        headers['Referer'] = url

        initial_state = self._search_json(r'window\.__INITIAL_STATE__\s*=', webpage, 'initial state', video_id, default=None)
        if not initial_state:
            query = {}
            if groups := re.search(r'[bB][vV](?P<id>[^/?#&]+)', url):
                query['bvid'] = 'BV' + groups.group('id')
            elif groups := re.search(r'[aA][vV](?P<id>[^/?#&]+)', url):
                query['aid'] = groups.group('id')
            if query:
                ep_url = traverse_obj(
                    self._download_json('https://api.bilibili.com/x/web-interface/wbi/view/detail', 'vid',
                                        query=self._sign_wbi(query, 'vid'), headers=headers), ('data', 'View', 'redirect_url'))
                if ep_url and BiliBiliBangumiIE._match_valid_url(ep_url):
                    return BiliBiliBangumiIE(self._downloader).extract(ep_url)
            raise ExtractorError('Unable to extract initial state!')

        if traverse_obj(initial_state, ('error', 'trueCode')) == -403:
            self.raise_login_required()
        if traverse_obj(initial_state, ('error', 'trueCode')) == -404:
            raise ExtractorError(
                'This video may be deleted or geo-restricted. '
                'You might want to try a VPN or a proxy server (with --proxy)', expected=True)

        is_festival = 'videoData' not in initial_state
        if is_festival:
            video_data = initial_state['videoInfo']
        else:
            video_data = initial_state['videoData']

        video_id, title = video_data['bvid'], video_data.get('title')

        # Bilibili anthologies are similar to playlists but all videos share the same video ID as the anthology itself.
        page_list_json = (not is_festival and traverse_obj(
            self._download_json(
                'https://api.bilibili.com/x/player/pagelist', video_id,
                fatal=False, query={'bvid': video_id, 'jsonp': 'jsonp'},
                note='Extracting videos in anthology', headers=headers),
            'data', expected_type=list)) or []
        is_anthology = len(page_list_json) > 1


Review comment (refactor):
```diff
-    _VALID_URL = r'https?://(?:www\.)?bilibili\.com/(?:video/|festival/[^/?#]+\?(?:[^#]*&)?bvid=)[aAbB][vV](?P<id>[^/?#&]+)'
+    _VALID_URL = r'https?://(?:www\.)?bilibili\.com/(?:video/|festival/[^/?#]+\?(?:[^#]*&)?bvid=)(?P<prefix>[aAbB][vV])(?P<id>[^/?#&]+)'
```
```diff
     def _real_extract(self, url):
-        video_id = self._match_id(url)
+        video_id, prefix = self._match_valid_url(url).group('id', 'prefix')
```
```suggestion
            query = {'platform': 'web'}
            prefix = prefix.upper()
            if prefix == 'BV':
                query['bvid'] = prefix + video_id
            elif prefix == 'AV':
                query['aid'] = video_id
            detail = self._download_json(
                'https://api.bilibili.com/x/web-interface/wbi/view/detail', video_id,
                query=self._sign_wbi(query, video_id), headers=headers)
            new_url = traverse_obj(detail, ('data', 'View', 'redirect_url', {url_or_none}))
            if new_url and BiliBiliBangumiIE.suitable(new_url):
                return self.url_result(new_url, BiliBiliBangumiIE)
            raise ExtractorError('Unable to extract initial state')
```

Code after:
        'skip': 'supporter-only video',
    }, {
        'url': 'https://www.bilibili.com/video/BV1Ks411f7aQ/',
        'info_dict': {
            'id': 'BV1Ks411f7aQ',
            'title': '【BD1080P】狼与香辛料I【华盟】',
            'ext': 'mp4',
        },
        'skip': 'login required',
    }, {
        'url': 'https://www.bilibili.com/video/BV1GJ411x7h7/',
        'info_dict': {
            'id': 'BV1GJ411x7h7',
            'title': '【官方 MV】Never Gonna Give You Up - Rick Astley',
            'ext': 'mp4',
        },
        'skip': 'geo-restricted',
    }, {
        'note': 'has - in the last path segment of the url',
        'url': 'https://www.bilibili.com/festival/bh3-7th?bvid=BV1tr4y1f7p2&',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id, prefix = self._match_valid_url(url).group('id', 'prefix')
        headers = self.geo_verification_headers()
        webpage, urlh = self._download_webpage_handle(url, video_id, headers=headers)
        if not self._match_valid_url(urlh.url):
            return self.url_result(urlh.url)

        headers['Referer'] = url

        initial_state = self._search_json(r'window\.__INITIAL_STATE__\s*=', webpage, 'initial state', video_id, default=None)
        if not initial_state:
            if self._search_json(r'\bwindow\._riskdata_\s*=', webpage, 'risk', video_id, default={}).get('v_voucher'):
                raise ExtractorError('You have exceeded the rate limit. Try again later', expected=True)
            query = {'platform': 'web'}
            prefix = prefix.upper()
            if prefix == 'BV':
                query['bvid'] = prefix + video_id
            elif prefix == 'AV':
                query['aid'] = video_id
            detail = self._download_json(
                'https://api.bilibili.com/x/web-interface/wbi/view/detail', video_id,
                note='Downloading redirection URL', errnote='Failed to download redirection URL',
                query=self._sign_wbi(query, video_id), headers=headers)
            new_url = traverse_obj(detail, ('data', 'View', 'redirect_url', {url_or_none}))
            if new_url and BiliBiliBangumiIE.suitable(new_url):
                return self.url_result(new_url, BiliBiliBangumiIE)
            raise ExtractorError('Unable to extract initial state')