Repository: yt-dlp/yt-dlp

Issue:
[Boosty] No videos found
### 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

_No response_

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

The post https://boosty.to/alexandrshtefanov/posts/25e4d10b-bb04-43be-aa56-11c2ae4c0d39 definitely has a video, because if I provide a direct link to the video (https://ok.ru/videoembed/7262749665958), then it downloads correctly.

### 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://boosty.to/alexandrshtefanov/posts/25e4d10b-bb04-43be-aa56-11c2ae4c0d39']
[debug] Encodings: locale cp1252, fs utf-8, pref cp1252, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version nightly@2024.03.08.232718 from yt-dlp/yt-dlp-nightly-builds [f4f9f6d00] (win_exe)
[debug] Python 3.8.10 (CPython AMD64 64bit) - Windows-10-10.0.22631-SP0 (OpenSSL 1.1.1k  25 Mar 2021)
[debug] exe versions: none
[debug] Optional libraries: Cryptodome-3.20.0, brotli-1.1.0, certifi-2024.02.02, mutagen-1.47.0, requests-2.31.0, sqlite3-3.35.5, urllib3-2.2.1, websockets-12.0
[debug] Proxy map: {}
[debug] Request Handlers: urllib, requests, websockets
[debug] Loaded 1836 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
Latest version: nightly@2024.03.08.232718 from yt-dlp/yt-dlp-nightly-builds
yt-dlp is up to date (nightly@2024.03.08.232718 from yt-dlp/yt-dlp-nightly-builds)
[Boosty] Extracting URL: https://boosty.to/alexandrshtefanov/posts/25e4d10b-bb04-43be-aa56-11c2ae4c0d39
[Boosty] 25e4d10b-bb04-43be-aa56-11c2ae4c0d39: Downloading post data
ERROR: [Boosty] No videos found
  File "yt_dlp\extractor\common.py", line 732, in extract
  File "yt_dlp\extractor\boosty.py", line 206, in _real_extract
```



Discussion:
The video is behind an auth-wall for me. Does passing cookies work?
If you are talking about a video at the link https://ok.ru/videoembed/7262749665958, then just change the Referer Request Header to `https://boosty.to/` for URL, that contains `ok.ru/videoembed/` via for example Requestly extension.
No, I am talking about the boosty.to link
![image](https://github.com/yt-dlp/yt-dlp/assets/4618135/993cf2ae-ea92-4c19-8dff-3ac0504a766d)
> The video is behind an auth-wall for me. Does passing cookies work?

No, still the same error.

<details><summary>Verbouse Output</summary>

```sh
[debug] Command-line config: ['https://boosty.to/alexandrshtefanov/posts/25e4d10b-bb04-43be-aa56-11c2ae4c0d39', '--cookies', '.\\cookies.txt', '-vU']
[debug] Encodings: locale cp1252, fs utf-8, pref cp1252, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version nightly@2024.03.08.232718 from yt-dlp/yt-dlp-nightly-builds [f4f9f6d00] (win_exe)
[debug] Python 3.8.10 (CPython AMD64 64bit) - Windows-10-10.0.22631-SP0 (OpenSSL 1.1.1k  25 Mar 2021)
[debug] exe versions: none
[debug] Optional libraries: Cryptodome-3.20.0, brotli-1.1.0, certifi-2024.02.02, mutagen-1.47.0, requests-2.31.0, sqlite3-3.35.5, urllib3-2.2.1, websockets-12.0
[debug] Proxy map: {}
[debug] Request Handlers: urllib, requests, websockets
[debug] Loaded 1836 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
Latest version: nightly@2024.03.08.232718 from yt-dlp/yt-dlp-nightly-builds
yt-dlp is up to date (nightly@2024.03.08.232718 from yt-dlp/yt-dlp-nightly-builds)
[Boosty] Extracting URL: https://boosty.to/alexandrshtefanov/posts/25e4d10b-bb04-43be-aa56-11c2ae4c0d39
[Boosty] 25e4d10b-bb04-43be-aa56-11c2ae4c0d39: Downloading post data
ERROR: [Boosty] No videos found
  File "yt_dlp\extractor\common.py", line 732, in extract
  File "yt_dlp\extractor\boosty.py", line 206, in _real_extract
```

</details>
Could the problem be due to the fact that in addition to the video, there is also an audio file in the post? As far as I understand, [now the extractor](https://github.com/yt-dlp/yt-dlp/pull/9144) has an option when there are several videos, but the problem may be due to additional audio.

<details><summary>Screenshot</summary>

![image](https://github.com/yt-dlp/yt-dlp/assets/19418601/5a02fbef-e598-4f30-9d91-27e4941c07d7)

</details>

If cookies don't work, then probably the site uses some other authentication method, like HTTP Headers. Someone with access to these posts would need to add support.

I would not expect there to be a problem due to the audio file, but someone with an account would have to check and potentially update the extractor.
I looked into it because I've been trying to download a video myself and apparently the video links are not returned by the API for paywalled posts. They are instead taken from a JSON object embedded in the HTML.
Cookies won't work because the API uses `Authorization` header authentication with `Bearer` token. This token can be extracted from `auth` cookie:

```
{"accessToken":"<TOKEN>","refreshToken":"...","expiresAt":...}
```

Then we can use it to authenticate the API request:

```
Authorization: Bearer <TOKEN>
```

If there is no way to get the `auth` cookie in the extractor code to extract the token, then we should either pass the token manually (probably as a `--password` argument) or stop using API and extract the post data from the web page.
> If there is no way to get the `auth` cookie in the extractor code

    self._get_cookies(url).get('auth')

Resolving patch:
diff --git a/yt_dlp/extractor/boosty.py b/yt_dlp/extractor/boosty.py
--- a/yt_dlp/extractor/boosty.py
+++ b/yt_dlp/extractor/boosty.py
@@ -1,7 +1,11 @@
+import json
+import urllib.parse
+
 from .common import InfoExtractor
 from .youtube import YoutubeIE
 from ..utils import (
     ExtractorError,
+    bug_reports_message,
     int_or_none,
     qualities,
     str_or_none,
@@ -162,9 +166,19 @@ def _extract_formats(self, player_urls, video_id):
 
     def _real_extract(self, url):
         user, post_id = self._match_valid_url(url).group('user', 'post_id')
+
+        auth_headers = {}
+        auth_cookie = self._get_cookies('https://boosty.to/').get('auth')
+        if auth_cookie is not None:
+            try:
+                auth_data = json.loads(urllib.parse.unquote(auth_cookie.value))
+                auth_headers['Authorization'] = f'Bearer {auth_data["accessToken"]}'
+            except (json.JSONDecodeError, KeyError):
+                self.report_warning(f'Failed to extract token from auth cookie{bug_reports_message()}')
+
         post = self._download_json(
             f'https://api.boosty.to/v1/blog/{user}/post/{post_id}', post_id,
-            note='Downloading post data', errnote='Unable to download post data')
+            note='Downloading post data', errnote='Unable to download post data', headers=auth_headers)
 
         post_title = post.get('title')
         if not post_title:
@@ -202,7 +216,9 @@ def _real_extract(self, url):
                         'thumbnail': (('previewUrl', 'defaultPreview'), {url_or_none}),
                     }, get_all=False)})
 
-        if not entries:
+        if not entries and not post.get('hasAccess'):
+            self.raise_login_required('This post requires a subscription', metadata_available=True)
+        elif not entries:
             raise ExtractorError('No videos found', expected=True)
         if len(entries) == 1:
             return entries[0]


Test patch: