diff --git a/yt_dlp/extractor/bilibili.py b/yt_dlp/extractor/bilibili.py
index 91619d9d5ca9..2db951a6084d 100644
--- a/yt_dlp/extractor/bilibili.py
+++ b/yt_dlp/extractor/bilibili.py
@@ -681,12 +681,6 @@ def _real_extract(self, url):
         old_video_id = format_field(aid, None, f'%s_part{part_id or 1}')
         cid = traverse_obj(video_data, ('pages', part_id - 1, 'cid')) if part_id else video_data.get('cid')

-        play_info = (
-            traverse_obj(
-                self._search_json(r'window\.__playinfo__\s*=', webpage, 'play info', video_id, default=None),
-                ('data', {dict}))
-            or self._download_playinfo(video_id, cid, headers=headers, query={'try_look': 1}))
-
         festival_info = {}
         if is_festival:
             festival_info = traverse_obj(initial_state, {
@@ -724,6 +718,13 @@ def _real_extract(self, url):
                 duration=traverse_obj(initial_state, ('videoData', 'duration', {int_or_none})),
                 __post_extractor=self.extract_comments(aid))

+        play_info = None
+        if self.is_logged_in:
+            play_info = traverse_obj(
+                self._search_json(r'window\.__playinfo__\s*=', webpage, 'play info', video_id, default=None),
+                ('data', {dict}))
+        if not play_info:
+            play_info = self._download_playinfo(video_id, cid, headers=headers, query={'try_look': 1})
         formats = self.extract_formats(play_info)

         if video_data.get('is_upower_exclusive'):

[BiliBili] extract 720p/1080p format without logging in by passing `'try_look': 1` to the api
### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE

- [X] I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field

### Checklist

- [X] I'm requesting a site-specific feature
- [X] I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
- [X] I've checked that all provided URLs are playable in a browser with the same IP and same login details
- [X] I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues **including closed ones**. DO NOT post duplicates
- [X] I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
- [ ] I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and I'm willing to share it if required

### Region

China/Out of China

### Example URLs

https://www.bilibili.com/video/BV1fK4y1t7hj/?spm_id_from=333.337.search-card.all.click&vd_source=...c145ee572cfa536d2947

### Provide a description that is worded well enough to be understood

As mentioned in https://github.com/yt-dlp/yt-dlp/pull/9117#discussion_r1608974583, it is possible to extract 720p/1080p formats(`80`&`64`) without logging in by passing the parameter `'try_look': 1` to the API.
(though premium formats `120`&`116` are still not accessible)

### Provide verbose output that clearly demonstrates the problem

- [X] Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- [ ] If using API, add `'verbose': True` to `YoutubeDL` params instead
- [X] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
[BiliBili] Extracting URL: https://www.bilibili.com/video/BV1fK4y1t7hj/?spm_id_from=333.337.search-card.all.click&vd_source=...c145ee572cfa536d2947
[BiliBili] 1fK4y1t7hj: Downloading webpage
[BiliBili] BV1fK4y1t7hj: Extracting videos in anthology
[BiliBili] BV1fK4y1t7hj: Downloading wbi sign
[BiliBili] BV1fK4y1t7hj: Downloading video formats for cid 196018899
[BiliBili] Format(s) 4K 超清, 1080P 60帧, 1080P 高清, 720P 高清 are missing; you have to login or become a premium member to download them. Use --cookies-from-browser or --cookies for the authentication. See  https://github.com/yt-dlp/yt-dlp/wiki/FAQ#how-do-i-pass-cookies-to-yt-dlp  for how to manually pass cookies
[BiliBili] 883362563: Extracting chapters
[info] Available formats for BV1fK4y1t7hj:
ID     EXT RESOLUTION FPS │  FILESIZE  TBR PROTO │ VCODEC         VBR ACODEC      ABR
─────────────────────────────────────────────────────────────────────────────────────
30216  m4a audio only     │ ≈ 1.71MiB  49k https │ audio only         mp4a.40.5   49k
30232  m4a audio only     │ ≈ 4.72MiB 134k https │ audio only         mp4a.40.2  134k
30280  m4a audio only     │ ≈10.10MiB 287k https │ audio only         mp4a.40.2  287k
30016  mp4 640x290     29 │ ≈12.24MiB 348k https │ avc1.64001E   348k video only
100022 mp4 792x360     30 │ ≈ 7.11MiB 202k https │ av01.0.04M.08 202k video only
30011  mp4 792x360     30 │ ≈10.98MiB 312k https │ hev1.1.6.L120 312k video only
30032  mp4 854x388     29 │ ≈24.20MiB 688k https │ avc1.64001E   688k video only
100023 mp4 1056x480    30 │ ≈15.72MiB 447k https │ av01.0.04M.08 447k video only
30033  mp4 1056x480    30 │ ≈10.57MiB 300k https │ hev1.1.6.L120 300k video only
```

With `'try_look': 1` passed to the api, it gives:
```
[BiliBili] Extracting URL: https://www.bilibili.com/video/BV1fK4y1t7hj/?spm_id_from=333.337.search-card.all.click&vd_source=...c145ee572cfa536d2947
[BiliBili] 1fK4y1t7hj: Downloading webpage
[BiliBili] BV1fK4y1t7hj: Extracting videos in anthology
[BiliBili] BV1fK4y1t7hj: Downloading wbi sign
[BiliBili] BV1fK4y1t7hj: Downloading video formats for cid 196018899
[BiliBili] Format(s) 4K 超清, 1080P 60帧 are missing; you have to login or become a premium member to download them. Use --cookies-from-browser or --cookies for the authentication. See  https://github.com/yt-dlp/yt-dlp/wiki/FAQ#how-do-i-pass-cookies-to-yt-dlp  for how to manually pass cookies
[BiliBili] 883362563: Extracting chapters
[info] Available formats for BV1fK4y1t7hj:
ID     EXT RESOLUTION FPS │  FILESIZE   TBR PROTO │ VCODEC          VBR ACODEC      ABR
───────────────────────────────────────────────────────────────────────────────────────
30216  m4a audio only     │ ≈ 1.71MiB   49k https │ audio only          mp4a.40.5   49k
30232  m4a audio only     │ ≈ 4.72MiB  134k https │ audio only          mp4a.40.2  134k
30280  m4a audio only     │ ≈10.10MiB  287k https │ audio only          mp4a.40.2  287k
30016  mp4 640x290     29 │ ≈12.24MiB  348k https │ avc1.64001E    348k video only
100022 mp4 792x360     30 │ ≈ 7.11MiB  202k https │ av01.0.04M.08  202k video only
30011  mp4 792x360     30 │ ≈10.98MiB  312k https │ hev1.1.6.L120  312k video only
30032  mp4 854x388     29 │ ≈24.20MiB  688k https │ avc1.64001E    688k video only
100023 mp4 1056x480    30 │ ≈15.72MiB  447k https │ av01.0.04M.08  447k video only
30033  mp4 1056x480    30 │ ≈10.57MiB  300k https │ hev1.1.6.L120  300k video only
30064  mp4 1280x580    29 │ ≈48.29MiB 1373k https │ avc1.64001F   1373k video only
100024 mp4 1584x720    30 │ ≈35.36MiB 1005k https │ av01.0.08M.08 1005k video only
30066  mp4 1584x720    30 │ ≈17.87MiB  508k https │ hev1.1.6.L120  508k video only
30080  mp4 1920x872    29 │ ≈70.08MiB 1992k https │ avc1.640032   1992k video only
100026 mp4 2378x1080   30 │ ≈50.91MiB 1447k https │ av01.0.12M.08 1447k video only
30077  mp4 2378x1080   30 │ ≈42.76MiB 1215k https │ hev1.1.6.L150 1215k video only
```

* When passing a normal logged-in(non-premium account) cookie, the premium formats are still not provided.

My patch:
```diff
diff --git a/yt_dlp/extractor/bilibili.py b/yt_dlp/extractor/bilibili.py
index a84b7a6f7..8e53f59dc 100644
--- a/yt_dlp/extractor/bilibili.py
+++ b/yt_dlp/extractor/bilibili.py
@@ -164,14 +164,12 @@ def _sign_wbi(self, params, video_id):
         params['w_rid'] = hashlib.md5(f'{query}{self._get_wbi_key(video_id)}'.encode()).hexdigest()
         return params

-    def _download_playinfo(self, bvid, cid, headers=None, qn=None):
-        params = {'bvid': bvid, 'cid': cid, 'fnval': 4048}
-        if qn:
-            params['qn'] = qn
+    def _download_playinfo(self, bvid, cid, headers=None, **kwargs):
+        params = {'bvid': bvid, 'cid': cid, 'fnval': 4048, **kwargs}
         return self._download_json(
             'https://api.bilibili.com/x/player/wbi/playurl', bvid,
             query=self._sign_wbi(params, bvid), headers=headers,
-            note=f'Downloading video formats for cid {cid} {qn or ""}')['data']
+            note=f'Downloading video formats for cid {cid} {kwargs.get("qn", "")}')['data']

     def json2srt(self, json_data):
         srt_data = ''
@@ -723,6 +721,7 @@ def _real_extract(self, url):
                 duration=traverse_obj(initial_state, ('videoData', 'duration', {int_or_none})),
                 __post_extractor=self.extract_comments(aid))
         else:
+            play_info = self._download_playinfo(video_id, cid, headers=headers, try_look=1)
             formats = self.extract_formats(play_info)

             if not traverse_obj(play_info, ('dash')):
```
seems like bilibili has added `window.__playinfo__` back onto the webpage. That explains https://github.com/yt-dlp/yt-dlp/issues/11665#issuecomment-2516376014
Should we always use the API even when playinfo is embedded?
Is there any benefit to using the `window.__playinfo__` JSON object besides saving a request?
> Is there any benefit to using the `window.__playinfo__` JSON object besides saving a request?

For BilibiliIE, No
<details><summary>

patch: remove playinfo extraction from `window.__playinfo__` and always download it _after_ the `is_interactive` check(`_get_interactive_entries` doesn't need playinfo)

</summary>

```diff
diff --git a/yt_dlp/extractor/bilibili.py b/yt_dlp/extractor/bilibili.py
index 91619d9d5..b121324de 100644
--- a/yt_dlp/extractor/bilibili.py
+++ b/yt_dlp/extractor/bilibili.py
@@ -681,12 +681,6 @@ def _real_extract(self, url):
         old_video_id = format_field(aid, None, f'%s_part{part_id or 1}')
         cid = traverse_obj(video_data, ('pages', part_id - 1, 'cid')) if part_id else video_data.get('cid')

-        play_info = (
-            traverse_obj(
-                self._search_json(r'window\.__playinfo__\s*=', webpage, 'play info', video_id, default=None),
-                ('data', {dict}))
-            or self._download_playinfo(video_id, cid, headers=headers, query={'try_look': 1}))
-
         festival_info = {}
         if is_festival:
             festival_info = traverse_obj(initial_state, {
@@ -724,6 +718,7 @@ def _real_extract(self, url):
                 duration=traverse_obj(initial_state, ('videoData', 'duration', {int_or_none})),
                 __post_extractor=self.extract_comments(aid))

+        play_info = self._download_playinfo(video_id, cid, headers=headers, query={'try_look': 1})
         formats = self.extract_formats(play_info)

         if video_data.get('is_upower_exclusive'):
```

</details>

<details><summary>test log</summary>

```log
[debug] Command-line config: ['-vF', '--no-simulate', '--test', '--no-playlist', 'https://www.bilibili.com/video/BV1jL41167ZG/', 'bilisearch:4k60', 'https://www.bilibili.com/video/BV1GJ411x7h7/?']
[debug] Encodings: locale UTF-8, fs utf-8, pref UTF-8, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version stable@2024.12.03 from yt-dlp/yt-dlp [2b67ac300] (source)
[debug] Lazy loading extractors is disabled
[debug] Git HEAD: cfa76f35d
[debug] Python 3.13.0 (CPython x86_64 64bit) - Linux-5.15.167.4-microsoft-standard-WSL2-x86_64-with-glibc2.35 (OpenSSL 3.0.2 15 Mar 2022, glibc 2.35)
[debug] exe versions: ffmpeg 4.4.2 (setts), ffprobe 4.4.2
[debug] Optional libraries: Cryptodome-3.21.0, brotli-1.1.0, certifi-2024.08.30, curl_cffi-0.7.1, mutagen-1.47.0, requests-2.32.3, secretstorage-3.3.3, sqlite3-3.37.2, urllib3-2.2.3, websockets-13.1
[debug] Proxy map: {}
[debug] Request Handlers: urllib, requests, websockets, curl_cffi
[debug] Loaded 1837 extractors
[BiliBili] Extracting URL: https://www.bilibili.com/video/BV1jL41167ZG/
[BiliBili] 1jL41167ZG: Downloading webpage
[BiliBili] BV1jL41167ZG: Extracting videos in anthology
[BiliBili] BV1jL41167ZG: Downloading wbi sign
mutagen-1.47.0[BiliBili] BV1jL41167ZG: Downloading video formats for cid 1131949939
WARNING: [BiliBili] BV1jL41167ZG: This is a supporter-only video, only the preview will be extracted: 该视频为「高级充电回馈」专属视频，开通「18元档包月充电」即可观看. Use --cookies-from-browser or --cookies for the authentication. See  https://github.com/yt-dlp/yt-dlp/wiki/FAQ#how-do-i-pass-cookies-to-yt-dlp  for how to manually pass cookies
[BiliBili] 443708639: Extracting chapters
[debug] Formats sorted by: hasvid, ie_pref, lang, quality, res, fps, hdr:12(7), vcodec, channels, acodec, size, br, asr, proto, vext, aext, hasaud, source, id
[info] Available formats for BV1jL41167ZG:
ID EXT RESOLUTION │   FILESIZE PROTO │ VCODEC  ACODEC  MORE INFO
────────────────────────────────────────────────────────────────
32 mp4 unknown    │  517.19KiB https │ unknown unknown 试看
[debug] Default format spec: bestvideo*+bestaudio/best
[info] BV1jL41167ZG: Downloading 1 format(s): 32
[debug] Invoking http downloader on "https://upos-sz-mirroraliov.bilivideo.com/upgcxcode/39/99/1131949939/1131949939_da4-1-29.mp4?e=ig8euxZM2rNcNbRVhwdVhwdlhWdVhwdVhoNvNC8BqJIzNbfqXBvEqxTEto8BTrNvN0GvT90W5JZMkX_YN0MvXg8gNEV4NC8xNEV4N03eN0B5tZlqNxTEto8BTrNvNeZVuJ10Kj_g2UB02J0mN0B5tZlqNCNEto8BTrNvNC7MTX502C8f2jmMQJ6mqF2fka1mqx6gqj0eN0B599M=&uipk=5&nbs=1&deadline=1733350193&gen=playurlv2&os=aliovbv&oi=3526874561&trid=77bba2f6fdcf4782b811b76b64d3fe25u&mid=0&platform=pc&og=cos&upsig=70dd6bf862a0de04001044100002d805&uparams=e,uipk,nbs,deadline,gen,os,oi,trid,mid,platform,og&bvc=vod&nettype=0&orderid=0,2&buvid=BDC5BB95-117A-73BD-2A2C-4F150EBDC1A690723infoc&build=0&f=u_0_0&agrr=1&bw=52960&logo=80000000"
[download] 一场大火引发的离奇死亡！古典推理经典短篇集《不可能犯罪诊断书》！ [BV1jL41167ZG].mp4 has already been downloaded
[download] 100% of   10.00KiB
[BiliBiliSearch] Extracting URL: bilisearch:4k60
[download] Downloading playlist: 4k60
[BiliBiliSearch] 4k60: Extracting results from page 1
[BiliBiliSearch] Playlist 4k60: Downloading 1 items of 1
[download] Downloading item 1 of 1
[BiliBili] Extracting URL: http://www.bilibili.com/video/av286406916
[BiliBili] 286406916: Downloading webpage
[BiliBili] BV1yf4y1R7mU: Extracting videos in anthology
[BiliBili] Downloading just the video BV1yf4y1R7mU because of --no-playlist
[BiliBili] BV1yf4y1R7mU: Downloading video formats for cid 214423511
[BiliBili] Format(s) 4K 超清, 1080P 60帧 are missing; you have to become a premium member to download them. Use --cookies-from-browser or --cookies for the authentication. See  https://github.com/yt-dlp/yt-dlp/wiki/FAQ#how-do-i-pass-cookies-to-yt-dlp  for how to manually pass cookies
[BiliBili] 286406916: Extracting chapters
[debug] Formats sorted by: hasvid, ie_pref, lang, quality, res, fps, hdr:12(7), vcodec, channels, acodec, size, br, asr, proto, vext, aext, hasaud, source, id
[info] Available formats for BV1yf4y1R7mU_p1:
ID     EXT RESOLUTION FPS │  FILESIZE   TBR PROTO │ VCODEC          VBR ACODEC      ABR
───────────────────────────────────────────────────────────────────────────────────────
30216  m4a audio only     │ ≈ 2.66MiB   51k https │ audio only          mp4a.40.5   51k
30232  m4a audio only     │ ≈ 5.93MiB  113k https │ audio only          mp4a.40.2  113k
30280  m4a audio only     │ ≈ 5.93MiB  113k https │ audio only          mp4a.40.2  113k
30016  mp4 490x360     29 │ ≈13.50MiB  258k https │ avc1.64001E    258k video only
100109 mp4 490x360     30 │ ≈ 9.30MiB  178k https │ hev1.1.6.L120  178k video only
100022 mp4 490x360     30 │ ≈10.64MiB  203k https │ av01.0.01M.08  203k video only
30032  mp4 654x480     29 │ ≈23.25MiB  444k https │ avc1.64001E    444k video only
100023 mp4 654x480     30 │ ≈21.79MiB  416k https │ av01.0.04M.08  416k video only
100110 mp4 654x480     30 │ ≈12.79MiB  244k https │ hev1.1.6.L120  244k video only
30064  mp4 982x720     29 │ ≈43.64MiB  833k https │ avc1.64001F    833k video only
100024 mp4 982x720     30 │ ≈41.55MiB  793k https │ av01.0.05M.08  793k video only
100111 mp4 982x720     30 │ ≈20.49MiB  391k https │ hev1.1.6.L120  391k video only
30080  mp4 1472x1080   29 │ ≈70.07MiB 1337k https │ avc1.640032   1337k video only
100026 mp4 1472x1080   30 │ ≈55.07MiB 1051k https │ av01.0.08M.08 1051k video only
100113 mp4 1472x1080   30 │ ≈43.98MiB  839k https │ hev1.1.6.L120  839k video only
[debug] Default format spec: bestvideo*+bestaudio/best
[info] BV1yf4y1R7mU_p1: Downloading 1 format(s): 100113+30280
[debug] Invoking http downloader on "https://upos-sz-mirroraliov.bilivideo.com/upgcxcode/11/35/214423511/214423511-1-100113.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEqxTEto8BTrNvN0GvT90W5JZMkX_YN0MvXg8gNEV4NC8xNEV4N03eN0B5tZlqNxTEto8BTrNvNeZVuJ10Kj_g2UB02J0mN0B5tZlqNCNEto8BTrNvNC7MTX502C8f2jmMQJ6mqF2fka1mqx6gqj0eN0B599M=&uipk=5&nbs=1&deadline=1733350196&gen=playurlv2&os=aliovbv&oi=3526874561&trid=1a192ecbe746440fb857d62727058149u&mid=0&platform=pc&og=hw&upsig=a024db055bba6ef60c8e86a21523f86f&uparams=e,uipk,nbs,deadline,gen,os,oi,trid,mid,platform,og&bvc=vod&nettype=0&orderid=0,2&buvid=BDC5BB95-117A-73BD-2A2C-4F150EBDC1A690723infoc&build=0&f=u_0_0&agrr=1&bw=105008&logo=80000000"
[download] Destination: 【4K60帧】群星《北京欢迎你》2008原版+宽屏版 AI修复高清收藏版 p01 【AI修复】08年原版4_3比例 [BV1yf4y1R7mU_p1].f100113.mp4
[download] 100% of   10.00KiB in 00:00:00 at 17.48KiB/s
[debug] Invoking http downloader on "https://upos-sz-mirroraliov.bilivideo.com/upgcxcode/11/35/214423511/214423511_nb3-1-30280.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEqxTEto8BTrNvN0GvT90W5JZMkX_YN0MvXg8gNEV4NC8xNEV4N03eN0B5tZlqNxTEto8BTrNvNeZVuJ10Kj_g2UB02J0mN0B5tZlqNCNEto8BTrNvNC7MTX502C8f2jmMQJ6mqF2fka1mqx6gqj0eN0B599M=&uipk=5&nbs=1&deadline=1733350196&gen=playurlv2&os=aliovbv&oi=3526874561&trid=1a192ecbe746440fb857d62727058149u&mid=0&platform=pc&og=hw&upsig=a4cb8ca94574f8425cb20fece02eb6f5&uparams=e,uipk,nbs,deadline,gen,os,oi,trid,mid,platform,og&bvc=vod&nettype=0&orderid=0,2&buvid=BDC5BB95-117A-73BD-2A2C-4F150EBDC1A690723infoc&build=0&f=u_0_0&agrr=1&bw=14173&logo=80000000"
[download] Destination: 【4K60帧】群星《北京欢迎你》2008原版+宽屏版 AI修复高清收藏版 p01 【AI修复】08年原版4_3比例 [BV1yf4y1R7mU_p1].f30280.m4a
[download] 100% of   10.00KiB in 00:00:00 at 38.68KiB/s
[Merger] Merging formats into "【4K60帧】群星《北京欢迎你》2008原版+宽屏版 AI修复高清收藏版 p01 【AI修复】08年原版4_3比例 [BV1yf4y1R7mU_p1].mp4"
[debug] ffmpeg command line: ffmpeg -y -loglevel repeat+info -i 'file:【4K60帧】群星《北京欢迎你》2008原版+宽屏版 AI修复高清收藏版 p01 【AI修复】08年原版4_3比例 [BV1yf4y1R7mU_p1].f100113.mp4' -i 'file:【4K60帧】群星《北京欢迎你》2008原版+宽屏版 AI修复高清收藏版 p01 【AI修复】08年原版4_3比例 [BV1yf4y1R7mU_p1].f30280.m4a' -c copy -map 0:v:0 -map 1:a:0 -movflags +faststart 'file:【4K60帧】群星《北京欢迎你》2008原版+宽屏版 AI修复高清收藏版 p01 【AI修复】08年原版4_3比例 [BV1yf4y1R7mU_p1].temp.mp4'
Deleting original file 【4K60帧】群星《北京欢迎你》2008原版+宽屏版 AI修复高清收藏版 p01 【AI修复】08年原版4_3比例 [BV1yf4y1R7mU_p1].f30280.m4a (pass -k to keep)
Deleting original file 【4K60帧】群星《北京欢迎你》2008原版+宽屏版 AI修复高清收藏版 p01 【AI修复】08年原版4_3比例 [BV1yf4y1R7mU_p1].f100113.mp4 (pass -k to keep)
[download] Finished downloading playlist: 4k60
[BiliBili] Extracting URL: https://www.bilibili.com/video/BV1GJ411x7h7/?
[BiliBili] 1GJ411x7h7: Downloading webpage
ERROR: [BiliBili] 1GJ411x7h7: This video may be deleted or geo-restricted. You might want to try a VPN or a proxy server (with --proxy)
  File "/home/user/yt-dlp_dev/yt-dlp-fork/yt_dlp/extractor/common.py", line 742, in extract
    ie_result = self._real_extract(url)
  File "/home/user/yt-dlp_dev/yt-dlp-fork/yt_dlp/extractor/bilibili.py", line 649, in _real_extract
    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)
```

</details>


diff --git a/yt_dlp/extractor/vk.py b/yt_dlp/extractor/vk.py
index 6ccc701a2b2b..4b36e41ffbb5 100644
--- a/yt_dlp/extractor/vk.py
+++ b/yt_dlp/extractor/vk.py
@@ -17,10 +17,10 @@
     get_element_html_by_id,
     int_or_none,
     join_nonempty,
+    parse_qs,
     parse_resolution,
     str_or_none,
     str_to_int,
-    traverse_obj,
     try_call,
     unescapeHTML,
     unified_timestamp,
@@ -29,6 +29,7 @@
     urlencode_postdata,
     urljoin,
 )
+from ..utils.traversal import require, traverse_obj

 class VKBaseIE(InfoExtractor):
@@ -91,17 +92,17 @@ def _download_payload(self, path, video_id, data, fatal=True):
 class VKIE(VKBaseIE):
     IE_NAME = 'vk'
     IE_DESC = 'VK'
-    _EMBED_REGEX = [r'<iframe[^>]+?src=(["\'])(?P<url>https?://vk\.com/video_ext\.php.+?)\1']
+    _EMBED_REGEX = [r'<iframe[^>]+?src=(["\'])(?P<url>https?://vk(?:(?:video)?\.ru|\.com)/video_ext\.php.+?)\1']
     _VALID_URL = r'''(?x)
                     https?://
                         (?:
                             (?:
-                                (?:(?:m|new)\.)?vk\.com/video_|
+                                (?:(?:m|new)\.)?vk(?:(?:video)?\.ru|\.com)/video_|
                                 (?:www\.)?daxab\.com/
                             )
                             ext\.php\?(?P<embed_query>.*?\boid=(?P<oid>-?\d+).*?\bid=(?P<id>\d+).*)|
                             (?:
-                                (?:(?:m|new)\.)?vk\.com/(?:.+?\?.*?z=)?(?:video|clip)|
+                                (?:(?:m|new)\.)?vk(?:(?:video)?\.ru|\.com)/(?:.+?\?.*?z=)?(?:video|clip)|
                                 (?:www\.)?daxab\.com/embed/
                             )
                             (?P<videoid>-?\d+_\d+)(?:.*\blist=(?P<list_id>([\da-f]+)|(ln-[\da-zA-Z]+)))?
@@ -110,7 +111,7 @@ class VKIE(VKBaseIE):

     _TESTS = [
         {
-            'url': 'http://vk.com/videos-77521?z=video-77521_162222515%2Fclub77521',
+            'url': 'https://vk.com/videos-77521?z=video-77521_162222515%2Fclub77521',
             'info_dict': {
                 'id': '-77521_162222515',
                 'ext': 'mp4',
@@ -127,7 +128,7 @@ class VKIE(VKBaseIE):
             'params': {'skip_download': 'm3u8'},
         },
         {
-            'url': 'http://vk.com/video205387401_165548505',
+            'url': 'https://vk.com/video205387401_165548505',
             'info_dict': {
                 'id': '205387401_165548505',
                 'ext': 'mp4',
@@ -182,10 +183,10 @@ class VKIE(VKBaseIE):
                 'ext': 'mp4',
                 'title': "DSWD Awards 'Children's Joy Foundation, Inc.' Certificate of Registration and License to Operate",
                 'description': 'md5:bf9c26cfa4acdfb146362682edd3827a',
-                'duration': 178,
+                'duration': 179,
                 'upload_date': '20130117',
                 'uploader': "Children's Joy Foundation Inc.",
-                'uploader_id': 'thecjf',
+                'uploader_id': '@CJFIofficial',
                 'view_count': int,
                 'channel_id': 'UCgzCNQ11TmR9V97ECnhi3gw',
                 'availability': 'public',
@@ -193,7 +194,7 @@ class VKIE(VKBaseIE):
                 'live_status': 'not_live',
                 'playable_in_embed': True,
                 'channel': 'Children\'s Joy Foundation Inc.',
-                'uploader_url': 'http://www.youtube.com/user/thecjf',
+                'uploader_url': 'https://www.youtube.com/@CJFIofficial',
                 'thumbnail': r're:https?://.+\.jpg$',
                 'tags': 'count:27',
                 'start_time': 0.0,
@@ -201,6 +202,7 @@ class VKIE(VKBaseIE):
                 'channel_url': 'https://www.youtube.com/channel/UCgzCNQ11TmR9V97ECnhi3gw',
                 'channel_follower_count': int,
                 'age_limit': 0,
+                'timestamp': 1358394935,
             },
         },
         {
@@ -222,6 +224,7 @@ class VKIE(VKBaseIE):
                 'thumbnail': r're:https?://.+x1080$',
                 'tags': list,
             },
+            'skip': 'This video has been deleted and is no longer available.',
         },
         {
             'url': 'https://vk.com/clips-74006511?z=clip-74006511_456247211',
@@ -235,13 +238,13 @@ class VKIE(VKBaseIE):
                 'timestamp': 1664995597,
                 'title': 'Clip by @madempress',
                 'upload_date': '20221005',
-                'uploader': 'Шальная императрица',
+                'uploader': 'Шальная Императрица',
                 'uploader_id': '-74006511',
             },
         },
         {
             # video key is extra_data not url\d+
-            'url': 'http://vk.com/video-110305615_171782105',
+            'url': 'https://vk.com/video-110305615_171782105',
             'md5': 'e13fcda136f99764872e739d13fac1d1',
             'info_dict': {
                 'id': '-110305615_171782105',
@@ -273,6 +276,7 @@ class VKIE(VKBaseIE):
             'params': {
                 'skip_download': True,
             },
+            'skip': 'No formats found',
         },
         {
             # live stream, hls and rtmp links, most likely already finished live
@@ -312,7 +316,16 @@ class VKIE(VKBaseIE):
         {
             'url': 'https://vk.com/clip30014565_456240946',
             'only_matching': True,
-        }]
+        },
+        {
+            'url': 'https://vkvideo.ru/video-127553155_456242961',
+            'only_matching': True,
+        },
+        {
+            'url': 'https://vk.ru/video-220754053_456242564',
+            'only_matching': True,
+        },
+    ]

     def _real_extract(self, url):
         mobj = self._match_valid_url(url)
@@ -338,7 +351,7 @@ def _real_extract(self, url):
             video_id = '{}_{}'.format(mobj.group('oid'), mobj.group('id'))

             info_page = self._download_webpage(
-                'http://vk.com/video_ext.php?' + mobj.group('embed_query'), video_id)
+                'https://vk.com/video_ext.php?' + mobj.group('embed_query'), video_id)

             error_message = self._html_search_regex(
                 [r'(?s)<!><div[^>]+class="video_layer_message"[^>]*>(.+?)</div>',
@@ -432,7 +445,7 @@ def _real_extract(self, url):
             if m_opts_url:
                 opts_url = m_opts_url.group(1)
                 if opts_url.startswith('//'):
-                    opts_url = 'http:' + opts_url
+                    opts_url = 'https:' + opts_url
                 return self.url_result(opts_url)

         data = player['params'][0]
@@ -512,8 +525,11 @@ def _real_extract(self, url):
 class VKUserVideosIE(VKBaseIE):
     IE_NAME = 'vk:uservideos'
     IE_DESC = "VK - User's Videos"
-    _VALID_URL = r'https?://(?:(?:m|new)\.)?vk\.com/video/(?:playlist/)?(?P<id>[^?$#/&]+)(?!\?.*\bz=video)(?:[/?#&](?:.*?\bsection=(?P<section>\w+))?|$)'
-    _TEMPLATE_URL = 'https://vk.com/videos'
+    _BASE_URL_RE = r'https?://(?:(?:m|new)\.)?vk(?:video\.ru|\.com/video)'
+    _VALID_URL = [
+        rf'{_BASE_URL_RE}/playlist/(?P<id>-?\d+_\d+)',
+        rf'{_BASE_URL_RE}/(?P<id>@[^/?#]+)(?:/all)?/?(?!\?.*\bz=video)(?:[?#]|$)',
+    ]
     _TESTS = [{
         'url': 'https://vk.com/video/@mobidevices',
         'info_dict': {
@@ -527,12 +543,20 @@ class VKUserVideosIE(VKBaseIE):
         },
         'playlist_mincount': 182,
     }, {
-        'url': 'https://vk.com/video/playlist/-174476437_2',
+        'url': 'https://vkvideo.ru/playlist/-204353299_426',
         'info_dict': {
-            'id': '-174476437_playlist_2',
-            'title': 'Анонсы',
+            'id': '-204353299_playlist_426',
         },
-        'playlist_mincount': 108,
+        'playlist_mincount': 33,
+    }, {
+        'url': 'https://vk.com/video/@gorkyfilmstudio/all',
+        'only_matching': True,
+    }, {
+        'url': 'https://vkvideo.ru/@mobidevices',
+        'only_matching': True,
+    }, {
+        'url': 'https://vk.com/video/playlist/-174476437_2',
+        'only_matching': True,
     }]
     _VIDEO = collections.namedtuple('Video', ['owner_id', 'id'])

@@ -552,7 +576,7 @@ def _entries(self, page_id, section):
                 v = self._VIDEO._make(video[:2])
                 video_id = '%d_%d' % (v.owner_id, v.id)
                 yield self.url_result(
-                    'http://vk.com/video' + video_id, VKIE.ie_key(), video_id)
+                    'https://vk.com/video' + video_id, VKIE.ie_key(), video_id)
             if count >= total:
                 break
             video_list_json = self._download_payload('al_video', page_id, {
@@ -561,23 +585,25 @@ def _entries(self, page_id, section):
                 'oid': page_id,
                 'section': section,
             })[0][section]
-            count += video_list_json['count']
+            new_count = video_list_json['count']
+            if not new_count:
+                self.to_screen(f'{page_id}: Skipping {total - count} unavailable videos')
+                break
+            count += new_count
             video_list = video_list_json['list']

     def _real_extract(self, url):
-        u_id, section = self._match_valid_url(url).groups()
+        u_id = self._match_id(url)
         webpage = self._download_webpage(url, u_id)

         if u_id.startswith('@'):
-            page_id = self._search_regex(r'data-owner-id\s?=\s?"([^"]+)"', webpage, 'page_id')
-        elif '_' in u_id:
-            page_id, section = u_id.split('_', 1)
-            section = f'playlist_{section}'
+            page_id = traverse_obj(
+                self._search_json(r'\bvar newCur\s*=', webpage, 'cursor data', u_id),
+                ('oid', {int}, {str_or_none}, {require('page id')}))
+            section = traverse_obj(parse_qs(url), ('section', 0)) or 'all'
         else:
-            raise ExtractorError('Invalid URL', expected=True)
-
-        if not section:
-            section = 'all'
+            page_id, _, section = u_id.partition('_')
+            section = f'playlist_{section}'

         playlist_title = clean_html(get_element_by_class('VideoInfoPanel__title', webpage))
         return self.playlist_result(self._entries(page_id, section), f'{page_id}_{section}', playlist_title)
@@ -717,7 +743,7 @@ def _real_extract(self, url):

 class VKPlayBaseIE(InfoExtractor):
-    _BASE_URL_RE = r'https?://(?:vkplay\.live|live\.vkplay\.ru)/'
+    _BASE_URL_RE = r'https?://(?:vkplay\.live|live\.vk(?:play|video)\.ru)/'
     _RESOLUTIONS = {
         'tiny': '256x144',
         'lowest': '426x240',
@@ -797,6 +823,9 @@ class VKPlayIE(VKPlayBaseIE):
     }, {
         'url': 'https://live.vkplay.ru/lebwa/record/33a4e4ce-e3ef-49db-bb14-f006cc6fabc9/records',
         'only_matching': True,
+    }, {
+        'url': 'https://live.vkvideo.ru/lebwa/record/33a4e4ce-e3ef-49db-bb14-f006cc6fabc9/records',
+        'only_matching': True,
     }]

     def _real_extract(self, url):
@@ -839,6 +868,9 @@ class VKPlayLiveIE(VKPlayBaseIE):
     }, {
         'url': 'https://live.vkplay.ru/lebwa',
         'only_matching': True,
+    }, {
+        'url': 'https://live.vkvideo.ru/panterka',
+        'only_matching': True,
     }]

     def _real_extract(self, url):

vk.com/video playlist dowload with Error: Unable to extract page_id
### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE

- [X] I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field

### Checklist

- [X] I'm reporting that yt-dlp is broken on a **supported** site
- [X] I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
- [X] I've checked that all provided URLs are playable in a browser with the same IP and same login details
- [X] I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#video-url-contains-an-ampersand--and-im-getting-some-strange-output-1-2839-or-v-is-not-recognized-as-an-internal-or-external-command)
- [X] I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues **including closed ones**. DO NOT post duplicates
- [X] I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
- [X] I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and I'm willing to share it if required

### Region

Russia

### Provide a description that is worded well enough to be understood

When I try to download the playlist I get error:

yt-dlp -vU --flat-playlist https://vk.com/video/@otvetoshnaya

ERROR: [vk:uservideos] @otvetoshnaya: Unable to extract page_id; please report this issue on  https://github.com/yt-dlp/yt-dlp/issues?q= , filling out the appropriate issue template. Confirm you are on the latest version using  yt-dlp -U

### Provide verbose output that clearly demonstrates the problem

- [X] Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- [X] If using API, add `'verbose': True` to `YoutubeDL` params instead
- [X] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
$ yt-dlp -vU --flat-playlist https://vk.com/video/@otvetoshnaya
[debug] Command-line config: ['-vU', '--flat-playlist', 'https://vk.com/video/@otvetoshnaya']
[debug] Encodings: locale UTF-8, fs utf-8, pref UTF-8, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version nightly@2024.11.27.232921 from yt-dlp/yt-dlp-nightly-builds [00dcde728] (pip)
[debug] Python 3.10.12 (CPython x86_64 64bit) - Linux-5.15.0-126-generic-x86_64-with-glibc2.35 (OpenSSL 3.0.2 15 Mar 2022, glibc 2.35)
[debug] exe versions: none
[debug] Optional libraries: Cryptodome-3.21.0, brotli-1.1.0, certifi-2020.06.20, mutagen-1.46.0, requests-2.32.3, secretstorage-3.3.1, sqlite3-3.37.2, urllib3-2.2.1, websockets-13.1
[debug] Proxy map: {}
[debug] Request Handlers: urllib, requests, websockets
[debug] Loaded 1837 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
Latest version: nightly@2024.11.27.232921 from yt-dlp/yt-dlp-nightly-builds
yt-dlp is up to date (nightly@2024.11.27.232921 from yt-dlp/yt-dlp-nightly-builds)
[vk:uservideos] Extracting URL: https://vk.com/video/@otvetoshnaya
[vk:uservideos] @otvetoshnaya: Downloading webpage
ERROR: [vk:uservideos] @otvetoshnaya: Unable to extract page_id; please report this issue on  https://github.com/yt-dlp/yt-dlp/issues?q= , filling out the appropriate issue template. Confirm you are on the latest version using  yt-dlp -U
  File "/home/iam/.local/lib/python3.10/site-packages/yt_dlp/extractor/common.py", line 742, in extract
    ie_result = self._real_extract(url)
  File "/home/iam/.local/lib/python3.10/site-packages/yt_dlp/extractor/vk.py", line 572, in _real_extract
    page_id = self._search_regex(r'data-owner-id\s?=\s?"([^"]+)"', webpage, 'page_id')
  File "/home/iam/.local/lib/python3.10/site-packages/yt_dlp/extractor/common.py", line 1346, in _search_regex
    raise RegexNotFoundError(f'Unable to extract {_name}')
```

VK seems to be protecting itself against yt-dlp in fact. The extractor didn't work for a single video in a playlist either,
> VK seems to be protecting itself against yt-dlp in fact. The extractor didn't work for a single video in a playlist either,

It was working a few days ago. Last time in my logging is 2024-11-25 18:13:17+03:00
Direct file downloads stoped working as well, it comes back as:
`Failed to parse JSON (caused by JSONDecodeError("Expecting value in '': line 1 column 1 (char 0)"));`

First vkvideo.ru/videoXXXX went down, then vk.com/videoXXXX

UPD,

Lol, putting url in ""'s just worked fine (: for example

> yt-dlp -v --print-traffic "https://vk.com/video-220754053_456242564"


diff --git a/yt_dlp/extractor/bilibili.py b/yt_dlp/extractor/bilibili.py
index 72d5f20cf36b..e538e5308946 100644
--- a/yt_dlp/extractor/bilibili.py
+++ b/yt_dlp/extractor/bilibili.py
@@ -652,13 +652,6 @@ def _real_extract(self, url):
         else:
             video_data = initial_state['videoData']

-        if video_data.get('is_upower_exclusive'):
-            high_level = traverse_obj(initial_state, ('elecFullInfo', 'show_info', 'high_level', {dict})) or {}
-            raise ExtractorError(
-                'This is a supporter-only video: '
-                f'{join_nonempty("title", "sub_title", from_dict=high_level, delim="，")}. '
-                f'{self._login_hint()}', expected=True)
-
         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.
@@ -726,62 +719,72 @@ def _real_extract(self, url):
                 self._get_interactive_entries(video_id, cid, metainfo, headers=headers), **metainfo,
                 duration=traverse_obj(initial_state, ('videoData', 'duration', {int_or_none})),
                 __post_extractor=self.extract_comments(aid))
-        else:
-            formats = self.extract_formats(play_info)
-
-            if not traverse_obj(play_info, ('dash')):
-                # we only have legacy formats and need additional work
-                has_qn = lambda x: x in traverse_obj(formats, (..., 'quality'))
-                for qn in traverse_obj(play_info, ('accept_quality', lambda _, v: not has_qn(v), {int})):
-                    formats.extend(traverse_obj(
-                        self.extract_formats(self._download_playinfo(video_id, cid, headers=headers, qn=qn)),
-                        lambda _, v: not has_qn(v['quality'])))
-                self._check_missing_formats(play_info, formats)
-                flv_formats = traverse_obj(formats, lambda _, v: v['fragments'])
-                if flv_formats and len(flv_formats) < len(formats):
-                    # Flv and mp4 are incompatible due to `multi_video` workaround, so drop one
-                    if not self._configuration_arg('prefer_multi_flv'):
-                        dropped_fmts = ', '.join(
-                            f'{f.get("format_note")} ({f.get("format_id")})' for f in flv_formats)
-                        formats = traverse_obj(formats, lambda _, v: not v.get('fragments'))
-                        if dropped_fmts:
-                            self.to_screen(
-                                f'Dropping incompatible flv format(s) {dropped_fmts} since mp4 is available. '
-                                'To extract flv, pass --extractor-args "bilibili:prefer_multi_flv"')
-                    else:
-                        formats = traverse_obj(
-                            # XXX: Filtering by extractor-arg is for testing purposes
-                            formats, lambda _, v: v['quality'] == int(self._configuration_arg('prefer_multi_flv')[0]),
-                        ) or [max(flv_formats, key=lambda x: x['quality'])]
-
-            if traverse_obj(formats, (0, 'fragments')):
-                # We have flv formats, which are individual short videos with their own timestamps and metainfo
-                # Binary concatenation corrupts their timestamps, so we need a `multi_video` workaround
-                return {
-                    **metainfo,
-                    '_type': 'multi_video',
-                    'entries': [{
-                        'id': f'{metainfo["id"]}_{idx}',
-                        'title': metainfo['title'],
-                        'http_headers': metainfo['http_headers'],
-                        'formats': [{
-                            **fragment,
-                            'format_id': formats[0].get('format_id'),
-                        }],
-                        'subtitles': self.extract_subtitles(video_id, cid) if idx == 0 else None,
-                        '__post_extractor': self.extract_comments(aid) if idx == 0 else None,
-                    } for idx, fragment in enumerate(formats[0]['fragments'])],
-                    'duration': float_or_none(play_info.get('timelength'), scale=1000),
-                }
-            else:
-                return {
-                    **metainfo,
-                    'formats': formats,
-                    'duration': float_or_none(play_info.get('timelength'), scale=1000),
-                    'chapters': self._get_chapters(aid, cid),
-                    'subtitles': self.extract_subtitles(video_id, cid),
-                    '__post_extractor': self.extract_comments(aid),
-                }
+
+        formats = self.extract_formats(play_info)
+
+        if video_data.get('is_upower_exclusive'):
+            high_level = traverse_obj(initial_state, ('elecFullInfo', 'show_info', 'high_level', {dict})) or {}
+            msg = f'{join_nonempty("title", "sub_title", from_dict=high_level, delim="，")}. {self._login_hint()}'
+            if not formats:
+                raise ExtractorError(f'This is a supporter-only video: {msg}', expected=True)
+            if '试看' in traverse_obj(play_info, ('accept_description', ..., {str})):
+                self.report_warning(
+                    f'This is a supporter-only video, only the preview will be extracted: {msg}',
+                    video_id=video_id)
+
+        if not traverse_obj(play_info, 'dash'):
+            # we only have legacy formats and need additional work
+            has_qn = lambda x: x in traverse_obj(formats, (..., 'quality'))
+            for qn in traverse_obj(play_info, ('accept_quality', lambda _, v: not has_qn(v), {int})):
+                formats.extend(traverse_obj(
+                    self.extract_formats(self._download_playinfo(video_id, cid, headers=headers, qn=qn)),
+                    lambda _, v: not has_qn(v['quality'])))
+            self._check_missing_formats(play_info, formats)
+            flv_formats = traverse_obj(formats, lambda _, v: v['fragments'])
+            if flv_formats and len(flv_formats) < len(formats):
+                # Flv and mp4 are incompatible due to `multi_video` workaround, so drop one
+                if not self._configuration_arg('prefer_multi_flv'):
+                    dropped_fmts = ', '.join(
+                        f'{f.get("format_note")} ({f.get("format_id")})' for f in flv_formats)
+                    formats = traverse_obj(formats, lambda _, v: not v.get('fragments'))
+                    if dropped_fmts:
+                        self.to_screen(
+                            f'Dropping incompatible flv format(s) {dropped_fmts} since mp4 is available. '
+                            'To extract flv, pass --extractor-args "bilibili:prefer_multi_flv"')
+                else:
+                    formats = traverse_obj(
+                        # XXX: Filtering by extractor-arg is for testing purposes
+                        formats, lambda _, v: v['quality'] == int(self._configuration_arg('prefer_multi_flv')[0]),
+                    ) or [max(flv_formats, key=lambda x: x['quality'])]
+
+        if traverse_obj(formats, (0, 'fragments')):
+            # We have flv formats, which are individual short videos with their own timestamps and metainfo
+            # Binary concatenation corrupts their timestamps, so we need a `multi_video` workaround
+            return {
+                **metainfo,
+                '_type': 'multi_video',
+                'entries': [{
+                    'id': f'{metainfo["id"]}_{idx}',
+                    'title': metainfo['title'],
+                    'http_headers': metainfo['http_headers'],
+                    'formats': [{
+                        **fragment,
+                        'format_id': formats[0].get('format_id'),
+                    }],
+                    'subtitles': self.extract_subtitles(video_id, cid) if idx == 0 else None,
+                    '__post_extractor': self.extract_comments(aid) if idx == 0 else None,
+                } for idx, fragment in enumerate(formats[0]['fragments'])],
+                'duration': float_or_none(play_info.get('timelength'), scale=1000),
+            }
+
+        return {
+            **metainfo,
+            'formats': formats,
+            'duration': float_or_none(play_info.get('timelength'), scale=1000),
+            'chapters': self._get_chapters(aid, cid),
+            'subtitles': self.extract_subtitles(video_id, cid),
+            '__post_extractor': self.extract_comments(aid),
+        }

 class BiliBiliBangumiIE(BilibiliBaseIE):

[bilibili] supporter-only videos broken after 239f5f3
### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE

- [X] I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field

### Checklist

- [X] I'm reporting that yt-dlp is broken on a **supported** site
- [X] I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
- [X] I've checked that all provided URLs are playable in a browser with the same IP and same login details
- [X] I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#video-url-contains-an-ampersand--and-im-getting-some-strange-output-1-2839-or-v-is-not-recognized-as-an-internal-or-external-command)
- [X] I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues **including closed ones**. DO NOT post duplicates
- [X] I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
- [ ] I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and I'm willing to share it if required

### Region

CN

### Provide a description that is worded well enough to be understood

[account-needed]
after 239f5f3 , yt-dlp raises an `ExtractorError` on every supporter-only video regardless of whether the user has logged in as a supporter. But I don't have a supporter's account. An account with access to _any_ supporter-only video on the site would help

### Provide verbose output that clearly demonstrates the problem

- [X] Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- [ ] If using API, add `'verbose': True` to `YoutubeDL` params instead
- [X] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
[debug] Command-line config: ['--test', 'https://www.bilibili.com/video/BV1jL41167ZG/', '-vF', '--no-simulate']
[debug] Encodings: locale UTF-8, fs utf-8, pref UTF-8, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version stable@2024.11.18 from yt-dlp/yt-dlp [7ea278792] (source)
[debug] Lazy loading extractors is disabled
[debug] Git HEAD: 62cba8a1b
[debug] Python 3.13.0 (CPython x86_64 64bit) - Linux-5.15.167.4-microsoft-standard-WSL2-x86_64-with-glibc2.35 (OpenSSL 3.0.2 15 Mar 2022, glibc 2.35)
[debug] exe versions: ffmpeg 4.4.2 (setts), ffprobe 4.4.2
[debug] Optional libraries: Cryptodome-3.21.0, brotli-1.1.0, certifi-2024.08.30, curl_cffi-0.7.1, mutagen-1.47.0, requests-2.32.3, secretstorage-3.3.3, sqlite3-3.37.2, urllib3-2.2.3, websockets-13.1
[debug] Proxy map: {}
[debug] Request Handlers: urllib, requests, websockets, curl_cffi
[debug] Loaded 1837 extractors
[BiliBili] Extracting URL: https://www.bilibili.com/video/BV1jL41167ZG/
[BiliBili] 1jL41167ZG: Downloading webpage
ERROR: [BiliBili] 1jL41167ZG: This is a supporter-only video: 该视频为「高级充电回馈」专属视频，开通「18元档包月充电」即可观看. Use --cookies-from-browser or --cookies for the authentication. See  https://github.com/yt-dlp/yt-dlp/wiki/FAQ#how-do-i-pass-cookies-to-yt-dlp  for how to manually pass cookies
  File "/home/user/yt-dlp_dev/yt-dlp-fork/yt_dlp/extractor/common.py", line 742, in extract
    ie_result = self._real_extract(url)
  File "/home/user/yt-dlp_dev/yt-dlp-fork/yt_dlp/extractor/bilibili.py", line 657, in _real_extract
    raise ExtractorError(
    ...<2 lines>...
        f'{self._login_hint()}', expected=True)
```

Well, there's the problem. If you don't have a supporter account, of course it can't download a video meant for supporters only.


diff --git a/yt_dlp/extractor/mitele.py b/yt_dlp/extractor/mitele.py
index 3573a2a3fd72..76fef337a2ea 100644
--- a/yt_dlp/extractor/mitele.py
+++ b/yt_dlp/extractor/mitele.py
@@ -80,9 +80,9 @@ class MiTeleIE(TelecincoBaseIE):
     def _real_extract(self, url):
         display_id = self._match_id(url)
         webpage = self._download_webpage(url, display_id)
-        pre_player = self._parse_json(self._search_regex(
-            r'window\.\$REACTBASE_STATE\.prePlayer_mtweb\s*=\s*({.+})',
-            webpage, 'Pre Player'), display_id)['prePlayer']
+        pre_player = self._search_json(
+            r'window\.\$REACTBASE_STATE\.prePlayer_mtweb\s*=',
+            webpage, 'Pre Player', display_id)['prePlayer']
         title = pre_player['title']
         video_info = self._parse_content(pre_player['video'], url)
         content = pre_player.get('content') or {}

[MiTele]: Failed to parse JSON (caused by JSONDecodeError('Extra data in \'d":false}}</script> \': line 1 column 9378 (char 9377)'));
### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE

- [X] I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field

### Checklist

- [X] I'm reporting that yt-dlp is broken on a **supported** site
- [X] I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
- [X] I've checked that all provided URLs are playable in a browser with the same IP and same login details
- [X] I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#video-url-contains-an-ampersand--and-im-getting-some-strange-output-1-2839-or-v-is-not-recognized-as-an-internal-or-external-command)
- [X] I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues **including closed ones**. DO NOT post duplicates
- [X] I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
- [X] I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and I'm willing to share it if required

### Region

Spain

### Provide a description that is worded well enough to be understood

Similar to some other allowed websites, mitele is also having an issue (not able to test entire site selection of TV shows) with downloading a TV show. it is geo restricted but user is in Spain. the error follows:
_Failed to parse JSON (caused by JSONDecodeError('Extra data in \'d":false}}</script> \': line 1 column 9378 (char 9377)'));_

### Provide verbose output that clearly demonstrates the problem

- [X] Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- [ ] If using API, add `'verbose': True` to `YoutubeDL` params instead
- [X] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
[debug] Command-line config: ['-vU', 'https://www.mitele.es/programas-tv/horizonte/temporada-5/programa-181-40_014084253/player/']
[debug] Encodings: locale UTF-8, fs utf-8, pref UTF-8, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version nightly@2024.11.27.232921 from yt-dlp/yt-dlp-nightly-builds [00dcde728] (zip)
[debug] Python 3.10.12 (CPython x86_64 64bit) - Linux-6.8.0-49-generic-x86_64-with-glibc2.35 (OpenSSL 3.0.2 15 Mar 2022, glibc 2.35)
[debug] exe versions: ffmpeg 4.4.2 (setts), ffprobe 4.4.2
[debug] Optional libraries: Cryptodome-3.11.0, brotli-1.0.9, certifi-2020.06.20, mutagen-1.45.1, requests-2.32.3, secretstorage-3.3.1, sqlite3-3.37.2, urllib3-1.26.5, websockets-9.1
[debug] Proxy map: {}
[debug] Request Handlers: urllib
[debug] Loaded 1837 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
Latest version: nightly@2024.11.27.232921 from yt-dlp/yt-dlp-nightly-builds
yt-dlp is up to date (nightly@2024.11.27.232921 from yt-dlp/yt-dlp-nightly-builds)
[MiTele] Extracting URL: https://www.mitele.es/programas-tv/horizonte/temporada-5/programa-181-40_014084253/player/
[MiTele] programa-181-40_014084253: Downloading webpage
ERROR: [MiTele] programa-181-40_014084253: programa-181-40_014084253: Failed to parse JSON (caused by JSONDecodeError('Extra data in \'d":false}}</script> \': line 1 column 9378 (char 9377)')); please report this issue on  https://github.com/yt-dlp/yt-dlp/issues?q= , filling out the appropriate issue template. Confirm you are on the latest version using  yt-dlp -U
  File "/usr/local/bin/yt-dlp/yt_dlp/extractor/common.py", line 742, in extract
    ie_result = self._real_extract(url)
  File "/usr/local/bin/yt-dlp/yt_dlp/extractor/mitele.py", line 83, in _real_extract
    pre_player = self._parse_json(self._search_regex(
  File "/usr/local/bin/yt-dlp/yt_dlp/extractor/common.py", line 1094, in _parse_json
    self.__print_error('Failed to parse JSON' if errnote is None else errnote, fatal, video_id, ve)
  File "/usr/local/bin/yt-dlp/yt_dlp/extractor/common.py", line 1077, in __print_error
    raise ExtractorError(f'{video_id}: {errnote}', cause=err)

  File "/usr/local/bin/yt-dlp/yt_dlp/utils/_utils.py", line 565, in decode
  File "/usr/lib/python3.10/json/decoder.py", line 340, in decode
    raise JSONDecodeError("Extra data", s, end)
json.decoder.JSONDecodeError: Extra data: line 1 column 9378 (char 9377)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/bin/yt-dlp/yt_dlp/extractor/common.py", line 1091, in _parse_json
    return json.loads(
  File "/usr/lib/python3.10/json/__init__.py", line 359, in loads
    return cls(**kw).decode(s)
  File "/usr/local/bin/yt-dlp/yt_dlp/utils/_utils.py", line 573, in decode
json.decoder.JSONDecodeError: Extra data in 'd":false}}</script> ': line 1 column 9378 (char 9377)
```


diff --git a/yt_dlp/extractor/bilibili.py b/yt_dlp/extractor/bilibili.py
index 02ea67707fcd..f01befcc0b6f 100644
--- a/yt_dlp/extractor/bilibili.py
+++ b/yt_dlp/extractor/bilibili.py
@@ -18,7 +18,6 @@
     InAdvancePagedList,
     OnDemandPagedList,
     bool_or_none,
-    clean_html,
     determine_ext,
     filter_dict,
     float_or_none,
@@ -639,31 +638,27 @@ def _real_extract(self, url):
         headers['Referer'] = url

         initial_state = self._search_json(r'window\.__INITIAL_STATE__\s*=', webpage, 'initial state', video_id)
+
+        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:
-            play_info_obj = self._search_json(
-                r'window\.__playinfo__\s*=', webpage, 'play info', video_id, fatal=False)
-            if not play_info_obj:
-                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)
-            play_info = traverse_obj(play_info_obj, ('data', {dict}))
-            if not play_info:
-                if traverse_obj(play_info_obj, 'code') == 87007:
-                    toast = get_element_by_class('tips-toast', webpage) or ''
-                    msg = clean_html(
-                        f'{get_element_by_class("belongs-to", toast) or ""}，'
-                        + (get_element_by_class('level', toast) or ''))
-                    raise ExtractorError(
-                        f'This is a supporter-only video: {msg}. {self._login_hint()}', expected=True)
-                raise ExtractorError('Failed to extract play info')
             video_data = initial_state['videoData']

+        if video_data.get('is_upower_exclusive'):
+            high_level = traverse_obj(initial_state, ('elecFullInfo', 'show_info', 'high_level', {dict})) or {}
+            raise ExtractorError(
+                'This is a supporter-only video: '
+                f'{join_nonempty("title", "sub_title", from_dict=high_level, delim="，")}. '
+                f'{self._login_hint()}', expected=True)
+
         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.
@@ -689,10 +684,14 @@ def _real_extract(self, url):
         old_video_id = format_field(aid, None, f'%s_part{part_id or 1}')
         cid = traverse_obj(video_data, ('pages', part_id - 1, 'cid')) if part_id else video_data.get('cid')

+        play_info = (
+            traverse_obj(
+                self._search_json(r'window\.__playinfo__\s*=', webpage, 'play info', video_id, default=None),
+                ('data', {dict}))
+            or self._download_playinfo(video_id, cid, headers=headers))
+
         festival_info = {}
         if is_festival:
-            play_info = self._download_playinfo(video_id, cid, headers=headers)
-
             festival_info = traverse_obj(initial_state, {
                 'uploader': ('videoInfo', 'upName'),
                 'uploader_id': ('videoInfo', 'upMid', {str_or_none}),

[BiliBili] unable to extract play info
### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE

- [X] I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field

### Checklist

- [X] I'm reporting that yt-dlp is broken on a **supported** site
- [X] I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
- [X] I've checked that all provided URLs are playable in a browser with the same IP and same login details
- [X] I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#video-url-contains-an-ampersand--and-im-getting-some-strange-output-1-2839-or-v-is-not-recognized-as-an-internal-or-external-command)
- [X] I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues **including closed ones**. DO NOT post duplicates
- [X] I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
- [X] I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and I'm willing to share it if required

### Region

China

### Provide a description that is worded well enough to be understood

I was able to download videos normally at first, but this afternoon I found that the video download started to report errors. I tested a video on three different IP hosts, and this video was able to download correctly yesterday, but today it fails with an error. I tried different types of URLs and also attempted to add cookies to download the video, but none of them worked. I suspect that Bilibili may have updated its anti-scraping mechanism.And I am very sure that my yt-dlp is the latest version.

### Provide verbose output that clearly demonstrates the problem

- [X] Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- [X] If using API, add `'verbose': True` to `YoutubeDL` params instead
- [X] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
yt-dlp -Uv --extract-audio --audio-format mp3 -o "%(id)s-%(title)s.%(ext)s" "https://www.bilibi
li.com/video/BV1HB4y1N7CY/" --ffmpeg-location "D:\workhome\ffmpeg\ffmpeg-master-latest-win64-gpl\bin"
[debug] Command-line config: ['-Uv', '--extract-audio', '--audio-format', 'mp3', '-o', '%(id)s-%(title)s.%(ext)s', 'https://www.bilibili.com/video/BV1HB4y1N7CY/', '--ffmpeg-location', 'D:\\workhome\\ffmpeg\\ffmpeg-master-latest-win64-gpl\\bin']
[debug] Encodings: locale cp936, fs utf-8, pref cp936, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version stable@2024.11.18 from yt-dlp/yt-dlp [7ea278792] (pip)
[debug] Python 3.11.0 (CPython AMD64 64bit) - Windows-10-10.0.22631-SP0 (OpenSSL 1.1.1w  11 Sep 2023)
[debug] exe versions: ffmpeg N-117770-g322b240cea-20241114 (setts), ffprobe N-117770-g322b240cea-20241114
[debug] Optional libraries: Cryptodome-3.20.0, brotli-1.1.0, certifi-2024.08.30, requests-2.32.3, sqlite3-3.45.3, urllib3-1.26.20, websockets-10.4
[debug] Proxy map: {}
[debug] Request Handlers: urllib, requests
[debug] Loaded 1837 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Latest version: stable@2024.11.18 from yt-dlp/yt-dlp
yt-dlp is up to date (stable@2024.11.18 from yt-dlp/yt-dlp)
[BiliBili] Extracting URL: https://www.bilibili.com/video/BV1HB4y1N7CY/
[BiliBili] 1HB4y1N7CY: Downloading webpage
WARNING: [BiliBili] unable to extract play info; please report this issue on  https://github.com/yt-dlp/yt-dlp/issues?q= , filling out the appropriate issue template. Confirm you are on the latest version using  yt-dlp -U
ERROR: [BiliBili] 1HB4y1N7CY: Failed to extract play info; please report this issue on  https://github.com/yt-dlp/yt-dlp/issues?q= , filling out the appropriate issue template. Confirm you are on the latest version using  yt-dlp -U
  File "D:\workhome\anaconda3\envs\crawl11\Lib\site-packages\yt_dlp\extractor\common.py", line 742, in extract
    ie_result = self._real_extract(url)
                ^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\workhome\anaconda3\envs\crawl11\Lib\site-packages\yt_dlp\extractor\bilibili.py", line 664, in _real_extract
    raise ExtractorError('Failed to extract play info')
```

I also encountered the same problem
> I also encountered the same problem

My cue is this.
```
[BiliBili] Extracting URL: https://www.bilibili.com/video/BV1ALzVYUEZf
[BiliBili] 1ALzVYUEZf: Downloading webpage
WARNING: [BiliBili] unable to extract play info; please report this issue on  https://github.com/yt-dlp/yt-dlp/issues?q= , filling out the appropriate issue template. Confirm you are on the latest version using  yt-dlp -U
ERROR: [BiliBili] 1ALzVYUEZf: Failed to extract play info; please report this issue on  https://github.com/yt-dlp/yt-dlp/issues?q= , filling out the appropriate issue template. Confirm you are on the latest version using  yt-dlp -U
```
seems like `window.__playinfo__` is removed from the page source now