Repository: yt-dlp/yt-dlp
Issue category: Bug Report

Issue:
[youtube] Age-restricted videos now always require sign-in
### 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

_No response_

### Provide a description that is worded well enough to be understood

I'm unable to download any age restricted videos without signing in. Wasn't a problem till a week ago.
I'm on the latest nightly and it fails with or without the AGP plugin.



### 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
C:\Users\Casey>yt-dlp https://www.youtube.com/watch?v=7Do70nztRNE -vU
[debug] Command-line config: ['https://www.youtube.com/watch?v=7Do70nztRNE', '-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.10.19.232833 from yt-dlp/yt-dlp-nightly-builds [679c68240] (pip)
[debug] Python 3.11.2 (CPython AMD64 64bit) - Windows-10-10.0.19044-SP0 (OpenSSL 1.1.1s  1 Nov 2022)
[debug] exe versions: ffmpeg 2023-07-06-git-f00222e81f-essentials_build-www.gyan.dev (setts), ffprobe 2023-07-06-git-f00222e81f-essentials_build-www.gyan.dev
[debug] Optional libraries: Cryptodome-3.19.0, brotli-1.1.0, certifi-2022.12.07, curl_cffi-0.5.10, mutagen-1.47.0, requests-2.32.3, sqlite3-3.39.4, urllib3-1.26.18, websockets-13.1
[debug] Proxy map: {}
[debug] Request Handlers: urllib, requests, websockets, curl_cffi
[debug] Extractor Plugins: AGB (YoutubeIE)
[debug] Plugin directories: ['C:\\Users\\Casey\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\yt_dlp_plugins']
[debug] Loaded 1838 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
Latest version: nightly@2024.10.19.232833 from yt-dlp/yt-dlp-nightly-builds
yt-dlp is up to date (nightly@2024.10.19.232833 from yt-dlp/yt-dlp-nightly-builds)
[youtube+AGB] Extracting URL: https://www.youtube.com/watch?v=7Do70nztRNE
[youtube+AGB] 7Do70nztRNE: Downloading webpage
[youtube+AGB] 7Do70nztRNE: Downloading ios player API JSON
[youtube+AGB] 7Do70nztRNE: This video is age-restricted; some formats may be missing without authentication. 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
[youtube+AGB] 7Do70nztRNE: Downloading tv embedded player API JSON
[youtube+AGB] 7Do70nztRNE: Downloading mweb player API JSON
[youtube+AGB] 7Do70nztRNE: Downloading Zerody API JSON
WARNING: [youtube+AGB] Unable to download JSON metadata: HTTP Error 502: Bad Gateway
ERROR: [youtube+AGB] 7Do70nztRNE: Sign in to confirm your age. This video may be inappropriate for some users.
  File "C:\Users\Casey\AppData\Local\Programs\Python\Python311\Lib\site-packages\yt_dlp\extractor\common.py", line 741, in extract
    ie_result = self._real_extract(url)
                ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Casey\AppData\Local\Programs\Python\Python311\Lib\site-packages\yt_dlp\extractor\youtube.py", line 4468, in _real_extract
    self.raise_no_formats(reason, expected=True)
  File "C:\Users\Casey\AppData\Local\Programs\Python\Python311\Lib\site-packages\yt_dlp\extractor\common.py", line 1275, in raise_no_formats
    raise ExtractorError(msg, expected=expected, video_id=video_id)
```



Hints:
please provide a log without the plugin. run `set YTDLP_NO_PLUGINS=1` and then your download command again
Log without the AGP plugin

```
C:\Users\Casey>yt-dlp https://www.youtube.com/watch?v=7Do70nztRNE -vU
[debug] Command-line config: ['https://www.youtube.com/watch?v=7Do70nztRNE', '-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.10.19.232833 from yt-dlp/yt-dlp-nightly-builds [679c68240] (pip)
[debug] Python 3.11.2 (CPython AMD64 64bit) - Windows-10-10.0.19044-SP0 (OpenSSL 1.1.1s  1 Nov 2022)
[debug] exe versions: ffmpeg 2023-07-06-git-f00222e81f-essentials_build-www.gyan.dev (setts), ffprobe 2023-07-06-git-f00222e81f-essentials_build-www.gyan.dev
[debug] Optional libraries: Cryptodome-3.19.0, brotli-1.1.0, certifi-2022.12.07, curl_cffi-0.5.10, mutagen-1.47.0, requests-2.32.3, sqlite3-3.39.4, urllib3-1.26.18, websockets-13.1
[debug] Proxy map: {}
[debug] Request Handlers: urllib, requests, websockets, curl_cffi
[debug] Loaded 1838 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
Latest version: nightly@2024.10.19.232833 from yt-dlp/yt-dlp-nightly-builds
yt-dlp is up to date (nightly@2024.10.19.232833 from yt-dlp/yt-dlp-nightly-builds)
[youtube] Extracting URL: https://www.youtube.com/watch?v=7Do70nztRNE
[youtube] 7Do70nztRNE: Downloading webpage
[youtube] 7Do70nztRNE: Downloading ios player API JSON
[youtube] 7Do70nztRNE: This video is age-restricted; some formats may be missing without authentication. 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
[youtube] 7Do70nztRNE: Downloading tv embedded player API JSON
[youtube] 7Do70nztRNE: Downloading mweb player API JSON
ERROR: [youtube] 7Do70nztRNE: Sign in to confirm your age. This video may be inappropriate for some users.
  File "C:\Users\Casey\AppData\Local\Programs\Python\Python311\Lib\site-packages\yt_dlp\extractor\common.py", line 741, in extract
    ie_result = self._real_extract(url)
                ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Casey\AppData\Local\Programs\Python\Python311\Lib\site-packages\yt_dlp\extractor\youtube.py", line 4468, in _real_extract
    self.raise_no_formats(reason, expected=True)
  File "C:\Users\Casey\AppData\Local\Programs\Python\Python311\Lib\site-packages\yt_dlp\extractor\common.py", line 1275, in raise_no_formats
    raise ExtractorError(msg, expected=expected, video_id=video_id)
```

> ERROR: [youtube] 7Do70nztRNE: Sign in to confirm your age. This video may be inappropriate for some users.

The `tv_embedded` client that yt-dlp was using to work around the age-restriction now requires sign-in for every video, so it is no longer useful for this purpose.

The [linked pull request that will close this issue](https://github.com/yt-dlp/yt-dlp/pull/11297) merely removes the broken age-gate workaround and now-misleading warning message.

**There will likely not be a solution to this besides authenticating with cookies or oauth.**
(Obligatory mention of the [**risk you would be taking if you use cookies or oauth**](https://github.com/yt-dlp/yt-dlp/issues/10085))

---

> [youtube+AGB] 7Do70nztRNE: Downloading Zerody API JSON
> WARNING: [youtube+AGB] Unable to download JSON metadata: HTTP Error 502: Bad Gateway

As for the plugin error, that is out-of-scope for this issue tracker. It looks like an issue with the AGB API (the server, not the plugin code). There's likely nothing that the maintainer of the yt-dlp plugin can do about that either.
This is disappointing. I've already had an account blocked by Google when using oauth so downloading without signing in was the only real option for me.



Patch:
diff --git a/yt_dlp/extractor/youtube.py b/yt_dlp/extractor/youtube.py
index f41f57ed16a0..728cb06966c3 100644
--- a/yt_dlp/extractor/youtube.py
+++ b/yt_dlp/extractor/youtube.py
@@ -114,6 +114,7 @@
         },
         'INNERTUBE_CONTEXT_CLIENT_NAME': 67,
     },
+    # This client now requires sign-in for every video
     'web_creator': {
         'INNERTUBE_CONTEXT': {
             'client': {
@@ -153,6 +154,7 @@
         'REQUIRE_JS_PLAYER': False,
         'REQUIRE_PO_TOKEN': True,
     },
+    # This client now requires sign-in for every video
     'android_creator': {
         'INNERTUBE_CONTEXT': {
             'client': {
@@ -200,21 +202,6 @@
         'REQUIRE_JS_PLAYER': False,
         'PLAYER_PARAMS': '2AMB',
     },
-    # This client only has legacy formats and storyboards
-    'android_producer': {
-        'INNERTUBE_CONTEXT': {
-            'client': {
-                'clientName': 'ANDROID_PRODUCER',
-                'clientVersion': '0.111.1',
-                'androidSdkVersion': 30,
-                'userAgent': 'com.google.android.apps.youtube.producer/0.111.1 (Linux; U; Android 11) gzip',
-                'osName': 'Android',
-                'osVersion': '11',
-            },
-        },
-        'INNERTUBE_CONTEXT_CLIENT_NAME': 91,
-        'REQUIRE_JS_PLAYER': False,
-    },
     # iOS clients have HLS live streams. Setting device model to get 60fps formats.
     # See: https://github.com/TeamNewPipe/NewPipeExtractor/issues/680#issuecomment-1002724558
     'ios': {
@@ -247,6 +234,7 @@
         'INNERTUBE_CONTEXT_CLIENT_NAME': 26,
         'REQUIRE_JS_PLAYER': False,
     },
+    # This client now requires sign-in for every video
     'ios_creator': {
         'INNERTUBE_CONTEXT': {
             'client': {
@@ -282,8 +270,9 @@
         },
         'INNERTUBE_CONTEXT_CLIENT_NAME': 7,
     },
-    # This client can access age restricted videos (unless the uploader has disabled the 'allow embedding' option)
-    # See: https://github.com/zerodytrash/YouTube-Internal-Clients
+    # This client now requires sign-in for every video
+    # It was previously an age-gate workaround for videos that were `playable_in_embed`
+    # It may still be useful if signed into an EU account that is not age-verified
     'tv_embedded': {
         'INNERTUBE_CONTEXT': {
             'client': {
@@ -1525,6 +1514,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
                 'heatmap': 'count:100',
                 'timestamp': 1401991663,
             },
+            'skip': 'Age-restricted; requires authentication',
         },
         {
             'note': 'Age-gate video with embed allowed in public site',
@@ -1555,6 +1545,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
                 'comment_count': int,
                 'channel_is_verified': True,
             },
+            'skip': 'Age-restricted; requires authentication',
         },
         {
             'note': 'Age-gate video embedable only with clientScreen=EMBED',
@@ -1585,6 +1576,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
                 'uploader_id': '@ProjektMelody',
                 'timestamp': 1577508724,
             },
+            'skip': 'Age-restricted; requires authentication',
         },
         {
             'note': 'Non-Agegated non-embeddable video',
@@ -2356,6 +2348,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
                 'channel_is_verified': True,
                 'timestamp': 1405513526,
             },
+            'skip': 'Age-restricted; requires authentication',
         },
         {
             # restricted location, https://github.com/ytdl-org/youtube-dl/issues/28685
@@ -2726,6 +2719,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
                 'timestamp': 1577508724,
             },
             'params': {'extractor_args': {'youtube': {'player_client': ['tv_embedded']}}, 'format': '251-drc'},
+            'skip': 'Age-restricted; requires authentication',
         },
         {
             'url': 'https://www.youtube.com/live/qVv6vCqciTM',
@@ -3953,26 +3947,15 @@ def append_client(*client_names):
                 else:
                     prs.append(pr)
 
-            # tv_embedded can work around age-gate and age-verification IF the video is embeddable
-            if self._is_agegated(pr) and variant != 'tv_embedded':
-                append_client(f'tv_embedded.{base_client}')
-
-            # Unauthenticated users will only get tv_embedded client formats if age-gated
-            if self._is_agegated(pr) and not self.is_authenticated:
-                self.to_screen(
-                    f'{video_id}: This video is age-restricted; some formats may be missing '
-                    f'without authentication. {self._login_hint()}', only_once=True)
-
             # EU countries require age-verification for accounts to access age-restricted videos
             # If account is not age-verified, _is_agegated() will be truthy for non-embedded clients
-            # If embedding is disabled for the video, _is_unplayable() will be truthy for tv_embedded
-            embedding_is_disabled = variant == 'tv_embedded' and self._is_unplayable(pr)
-            if self.is_authenticated and (self._is_agegated(pr) or embedding_is_disabled):
+            if self.is_authenticated and self._is_agegated(pr):
                 self.to_screen(
                     f'{video_id}: This video is age-restricted and YouTube is requiring '
                     'account age-verification; some formats may be missing', only_once=True)
                 # web_creator and mediaconnect can work around the age-verification requirement
-                # _producer, _testsuite, & _vr variants can also work around age-verification
+                # _testsuite & _vr variants can also work around age-verification
+                # tv_embedded may(?) still work around age-verification if the video is embeddable
                 append_client('web_creator', 'mediaconnect')
 
         prs.extend(deprioritized_prs)


Test patch: