From 56ea3a00eabb45d926a6b993708acf1b9951e23a Mon Sep 17 00:00:00 2001 From: WhatAmISupposedToPutHere Date: Mon, 1 Dec 2025 02:02:58 +0100 Subject: [PATCH] [ie/youtube] Add `request_no_ads` extractor-arg (#15145) Default is `true` for unauthenticated users. Default is `false` if logged-in cookies have been passed to yt-dlp. Using `true` results in a loss of premium formats. Closes #15144 Authored by: WhatAmISupposedToPutHere --- README.md | 1 + yt_dlp/extractor/youtube/_video.py | 23 +++++++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c98c69f418..6a97eb0eb2 100644 --- a/README.md +++ b/README.md @@ -1871,6 +1871,7 @@ The following extractors use this feature: * `pot_trace`: Enable debug logging for PO Token fetching. Either `true` or `false` (default) * `fetch_pot`: Policy to use for fetching a PO Token from providers. One of `always` (always try fetch a PO Token regardless if the client requires one for the given context), `never` (never fetch a PO Token), or `auto` (default; only fetch a PO Token if the client requires one for the given context) * `jsc_trace`: Enable debug logging for JS Challenge fetching. Either `true` or `false` (default) +* `request_no_ads`: Skip preroll ads to eliminate the mandatory wait period before download. Either `true` (the default if unauthenticated) or `false`. The default is `false` when logged-in cookies have been passed to yt-dlp, since `true` will result in a loss of premium formats #### youtube-ejs * `jitless`: Run suported Javascript engines in JIT-less mode. Supported runtimes are `deno`, `node` and `bun`. Provides better security at the cost of performance/speed. Do note that `node` and `bun` are still considered unsecure. Either `true` or `false` (default) diff --git a/yt_dlp/extractor/youtube/_video.py b/yt_dlp/extractor/youtube/_video.py index a792332046..0756ce2c40 100644 --- a/yt_dlp/extractor/youtube/_video.py +++ b/yt_dlp/extractor/youtube/_video.py @@ -2628,18 +2628,29 @@ class YoutubeIE(YoutubeBaseInfoExtractor): def _get_checkok_params(): return {'contentCheckOk': True, 'racyCheckOk': True} - @classmethod - def _generate_player_context(cls, sts=None): + def _generate_player_context(self, sts=None): context = { 'html5Preference': 'HTML5_PREF_WANTS', } if sts is not None: context['signatureTimestamp'] = sts + + playback_context = { + 'contentPlaybackContext': context, + } + + # The 'adPlaybackContext'/'request_no_ads' workaround results in a loss of premium formats. + # Only default to 'true' if the user is unauthenticated, since we can't reliably detect all + # types of premium accounts (e.g. YTMusic Premium), and since premium users don't have ads. + default_arg_value = 'false' if self.is_authenticated else 'true' + if self._configuration_arg('request_no_ads', [default_arg_value])[0] != 'false': + playback_context['adPlaybackContext'] = { + 'pyv': True, + } + return { - 'playbackContext': { - 'contentPlaybackContext': context, - }, - **cls._get_checkok_params(), + 'playbackContext': playback_context, + **self._get_checkok_params(), } def _get_config_po_token(self, client: str, context: _PoTokenContext):