Repository: yt-dlp/yt-dlp

Issue:
Odysee members-only videos using cookies results in "authentication required"
### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE

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

### Checklist

- [X] I'm reporting a broken site
- [X] I've verified that I'm running yt-dlp version **2022.10.04** ([update instructions](https://github.com/yt-dlp/yt-dlp#update)) or later (specify commit)
- [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 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

Unknown, but the target audience is USA and worldwide

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

Members only content on Odysee is not getting authenticated from cookies file exported from either Firefox or Chrome (from a login session where it works fine in either browser), giving the error:  "ERROR: [lbry] @QuodVerumTV:3/VIP_01NOV22_Nobody:5: lbry said: -32603 - authentication required"

(Using -u and -p says that website isn't supported.)

Since the browsers work fine, I don't blame this on Odysee.

### 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] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
$ yt-dlp  -vU --cookies odysee.com_cookies.txt https://odysee.com/@QuodVerumTV:3/VIP_01NOV22_Nobody:5
[debug] Command-line config: ['-vU', '--cookies', 'odysee.com_cookies.txt', 'https://odysee.com/@QuodVerumTV:3/VIP_01NOV22_Nobody:5']
[debug] Encodings: locale UTF-8, fs utf-8, pref UTF-8, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version 2022.10.04 [4e0511f] (pip) API
[debug] Python 3.10.8 (CPython 64bit) - macOS-10.14.6-x86_64-i386-64bit 
[debug] Checking exe version: ffmpeg -bsfs
[debug] Checking exe version: ffprobe -bsfs
[debug] exe versions: rtmpdump 2.4
[debug] Optional libraries: Cryptodome-3.15.0, brotli-1.0.9, certifi-2022.09.24, mutagen-1.45.1, sqlite3-2.6.0, websockets-10.3
[debug] Proxy map: {}
[debug] Loaded 1690 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Latest version: 2022.10.04, Current version: 2022.10.04
yt-dlp is up to date (2022.10.04)
[debug] [lbry] Extracting URL: https://odysee.com/@QuodVerumTV:3/VIP_01NOV22_Nobody:5
[lbry] @QuodVerumTV#3/VIP_01NOV22_Nobody#5: Downloading stream JSON metadata
[lbry] 50560a01f771155f4db5a75d0b7b79767d30f7dd: Downloading streaming url JSON metadata
ERROR: [lbry] @QuodVerumTV:3/VIP_01NOV22_Nobody:5: lbry said: -32603 - authentication required
  File "/usr/local/Cellar/yt-dlp/2022.10.4/libexec/lib/python3.10/site-packages/yt_dlp/extractor/common.py", line 672, in extract
    ie_result = self._real_extract(url)
  File "/usr/local/Cellar/yt-dlp/2022.10.4/libexec/lib/python3.10/site-packages/yt_dlp/extractor/lbry.py", line 202, in _real_extract
    streaming_url = self._call_api_proxy(
  File "/usr/local/Cellar/yt-dlp/2022.10.4/libexec/lib/python3.10/site-packages/yt_dlp/extractor/lbry.py", line 37, in _call_api_proxy
    raise ExtractorError(

$
```



Discussion:
If there are no yt-dlp developers who have memberships to membership only content on Odysee, let me know your integrity profile, so I can help you experiment with my situation.
This seems like a problem with lenient cookie parsing, do the cookies contain any special characters? Maybe it is considered invalid and therefore dropped.

Resolving patch:
diff --git a/yt_dlp/extractor/lbry.py b/yt_dlp/extractor/lbry.py
--- a/yt_dlp/extractor/lbry.py
+++ b/yt_dlp/extractor/lbry.py
@@ -24,10 +24,14 @@ class LBRYBaseIE(InfoExtractor):
     _SUPPORTED_STREAM_TYPES = ['video', 'audio']
 
     def _call_api_proxy(self, method, display_id, params, resource):
+        headers = {'Content-Type': 'application/json-rpc'}
+        token = try_get(self._get_cookies('https://odysee.com'), lambda x: x['auth_token'].value)
+        if token:
+            headers['x-lbry-auth-token'] = token
         response = self._download_json(
             'https://api.lbry.tv/api/v1/proxy',
             display_id, 'Downloading %s JSON metadata' % resource,
-            headers={'Content-Type': 'application/json-rpc'},
+            headers=headers,
             data=json.dumps({
                 'method': method,
                 'params': params,
@@ -159,6 +163,29 @@ class LBRYIE(LBRYBaseIE):
             'thumbnail': 'https://thumbnails.lbry.com/AgHSc_HzrrE',
             'license': 'Copyrighted (contact publisher)',
         }
+    }, {
+        # HLS live stream (might expire)
+        'url': 'https://odysee.com/@RT:fd/livestream_RT:d',
+        'info_dict': {
+            'id': 'fdd11cb3ab75f95efb7b3bc2d726aa13ac915b66',
+            'ext': 'mp4',
+            'live_status': 'is_live',
+            'title': 'startswith:RT News | Livestream 24/7',
+            'description': 'md5:fe68d0056dfe79c1a6b8ce8c34d5f6fa',
+            'timestamp': int,
+            'upload_date': str,
+            'release_timestamp': int,
+            'release_date': str,
+            'tags': list,
+            'duration': None,
+            'channel': 'RT',
+            'channel_id': 'fdd11cb3ab75f95efb7b3bc2d726aa13ac915b66',
+            'channel_url': 'https://odysee.com/@RT:fdd11cb3ab75f95efb7b3bc2d726aa13ac915b66',
+            'formats': 'mincount:1',
+            'thumbnail': 'startswith:https://thumb',
+            'license': 'None',
+        },
+        'params': {'skip_download': True}
     }, {
         'url': 'https://odysee.com/@BrodieRobertson:5/apple-is-tracking-everything-you-do-on:e',
         'only_matching': True,
@@ -197,22 +224,24 @@ def _real_extract(self, url):
         display_id = compat_urllib_parse_unquote(display_id)
         uri = 'lbry://' + display_id
         result = self._resolve_url(uri, display_id, 'stream')
+        headers = {'Referer': 'https://odysee.com/'}
         if result['value'].get('stream_type') in self._SUPPORTED_STREAM_TYPES:
-            claim_id, is_live, headers = result['claim_id'], False, {}
+            claim_id, is_live = result['claim_id'], False
             streaming_url = self._call_api_proxy(
                 'get', claim_id, {'uri': uri}, 'streaming url')['streaming_url']
             final_url = self._request_webpage(
-                HEADRequest(streaming_url), display_id,
+                HEADRequest(streaming_url), display_id, headers=headers,
                 note='Downloading streaming redirect url info').geturl()
         elif result.get('value_type') == 'stream':
             claim_id, is_live = result['signing_channel']['claim_id'], True
-            headers = {'referer': 'https://player.odysee.live/'}
             live_data = self._download_json(
                 'https://api.odysee.live/livestream/is_live', claim_id,
                 query={'channel_claim_id': claim_id},
                 note='Downloading livestream JSON metadata')['data']
             streaming_url = final_url = live_data.get('VideoURL')
-            if not final_url and not live_data.get('Live'):
+            # Upcoming videos may still give VideoURL
+            if not live_data.get('Live'):
+                streaming_url = final_url = None
                 self.raise_no_formats('This stream is not live', True, claim_id)
         else:
             raise UnsupportedError(url)


Test patch: