Compare commits

...

3 Commits

Author SHA1 Message Date
SparseOrnament15
f2bd3202c0
[ie/youtube] Fix web_embedded player client (#16177)
Closes #16077
Authored by: SparseOrnament15, bashonly

Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com>
2026-03-10 23:25:13 +00:00
bashonly
7e145ac1ca
[ie/youtube] Fix use_ad_playback_context extractor-arg (#16196)
Authored by: bashonly
2026-03-10 23:24:03 +00:00
gamer191
ff459e5fc0
[ie/youtube] Fix android_vr player client (#16168)
Closes #16150
Authored by: gamer191
2026-03-10 22:08:13 +00:00
3 changed files with 23 additions and 9 deletions

View File

@ -1880,7 +1880,7 @@ The following extractors use this feature:
* `pot_trace`: Enable debug logging for PO Token fetching. Either `true` or `false` (default) * `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) * `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) * `jsc_trace`: Enable debug logging for JS Challenge fetching. Either `true` or `false` (default)
* `use_ad_playback_context`: Skip preroll ads to eliminate the mandatory wait period before download. Do NOT use this when passing premium account cookies to yt-dlp, as it will result in a loss of premium formats. Only effective with the `web`, `web_safari`, `web_music` and `mweb` player clients. Either `true` or `false` (default) * `use_ad_playback_context`: Skip preroll ads to eliminate the mandatory wait period before download. Do NOT use this when passing premium account cookies to yt-dlp, as it will result in a loss of premium formats. Only effective with the `mweb` and `web_music` player clients. Either `true` or `false` (default)
#### youtube-ejs #### youtube-ejs
* `jitless`: Run supported 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 insecure. Either `true` or `false` (default) * `jitless`: Run supported 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 insecure. Either `true` or `false` (default)

View File

@ -104,7 +104,6 @@ INNERTUBE_CLIENTS = {
}, },
'INNERTUBE_CONTEXT_CLIENT_NAME': 1, 'INNERTUBE_CONTEXT_CLIENT_NAME': 1,
'SUPPORTS_COOKIES': True, 'SUPPORTS_COOKIES': True,
'SUPPORTS_AD_PLAYBACK_CONTEXT': True,
**WEB_PO_TOKEN_POLICIES, **WEB_PO_TOKEN_POLICIES,
}, },
# Safari UA returns pre-merged video+audio 144p/240p/360p/720p/1080p HLS formats # Safari UA returns pre-merged video+audio 144p/240p/360p/720p/1080p HLS formats
@ -118,7 +117,6 @@ INNERTUBE_CLIENTS = {
}, },
'INNERTUBE_CONTEXT_CLIENT_NAME': 1, 'INNERTUBE_CONTEXT_CLIENT_NAME': 1,
'SUPPORTS_COOKIES': True, 'SUPPORTS_COOKIES': True,
'SUPPORTS_AD_PLAYBACK_CONTEXT': True,
**WEB_PO_TOKEN_POLICIES, **WEB_PO_TOKEN_POLICIES,
}, },
'web_embedded': { 'web_embedded': {
@ -223,16 +221,17 @@ INNERTUBE_CLIENTS = {
}, },
'PLAYER_PO_TOKEN_POLICY': PlayerPoTokenPolicy(required=False, recommended=True), 'PLAYER_PO_TOKEN_POLICY': PlayerPoTokenPolicy(required=False, recommended=True),
}, },
# YouTube Kids videos aren't returned on this client for some reason # "Made for kids" videos aren't available with this client
# Using a clientVersion>1.65 may return SABR streams only
'android_vr': { 'android_vr': {
'INNERTUBE_CONTEXT': { 'INNERTUBE_CONTEXT': {
'client': { 'client': {
'clientName': 'ANDROID_VR', 'clientName': 'ANDROID_VR',
'clientVersion': '1.71.26', 'clientVersion': '1.65.10',
'deviceMake': 'Oculus', 'deviceMake': 'Oculus',
'deviceModel': 'Quest 3', 'deviceModel': 'Quest 3',
'androidSdkVersion': 32, 'androidSdkVersion': 32,
'userAgent': 'com.google.android.apps.youtube.vr.oculus/1.71.26 (Linux; U; Android 12L; eureka-user Build/SQ3A.220605.009.A1) gzip', 'userAgent': 'com.google.android.apps.youtube.vr.oculus/1.65.10 (Linux; U; Android 12L; eureka-user Build/SQ3A.220605.009.A1) gzip',
'osName': 'Android', 'osName': 'Android',
'osVersion': '12L', 'osVersion': '12L',
}, },
@ -369,7 +368,7 @@ def short_client_name(client_name):
def _fix_embedded_ytcfg(ytcfg): def _fix_embedded_ytcfg(ytcfg):
ytcfg['INNERTUBE_CONTEXT'].setdefault('thirdParty', {}).update({ ytcfg['INNERTUBE_CONTEXT'].setdefault('thirdParty', {}).update({
'embedUrl': 'https://www.youtube.com/', # Can be any valid URL 'embedUrl': 'https://www.reddit.com/', # Can be any valid non-YouTube URL
}) })
@ -968,6 +967,7 @@ class YoutubeBaseInfoExtractor(InfoExtractor):
url, video_id, note=f'Downloading {client.replace("_", " ").strip()} client config', url, video_id, note=f'Downloading {client.replace("_", " ").strip()} client config',
headers=traverse_obj(self._get_default_ytcfg(client), { headers=traverse_obj(self._get_default_ytcfg(client), {
'User-Agent': ('INNERTUBE_CONTEXT', 'client', 'userAgent', {str}), 'User-Agent': ('INNERTUBE_CONTEXT', 'client', 'userAgent', {str}),
'Referer': ('INNERTUBE_CONTEXT', 'thirdParty', 'embedUrl', {str}),
})) }))
ytcfg = self.extract_ytcfg(video_id, webpage) or {} ytcfg = self.extract_ytcfg(video_id, webpage) or {}

View File

@ -2680,12 +2680,14 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
return {'contentCheckOk': True, 'racyCheckOk': True} return {'contentCheckOk': True, 'racyCheckOk': True}
@classmethod @classmethod
def _generate_player_context(cls, sts=None, use_ad_playback_context=False): def _generate_player_context(cls, sts=None, use_ad_playback_context=False, encrypted_context=None):
context = { context = {
'html5Preference': 'HTML5_PREF_WANTS', 'html5Preference': 'HTML5_PREF_WANTS',
} }
if sts is not None: if sts is not None:
context['signatureTimestamp'] = sts context['signatureTimestamp'] = sts
if encrypted_context:
context['encryptedHostFlags'] = encrypted_context
playback_context = { playback_context = {
'contentPlaybackContext': context, 'contentPlaybackContext': context,
@ -2930,7 +2932,19 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
self._configuration_arg('use_ad_playback_context', ['false'])[0] != 'false' self._configuration_arg('use_ad_playback_context', ['false'])[0] != 'false'
and traverse_obj(INNERTUBE_CLIENTS, (client, 'SUPPORTS_AD_PLAYBACK_CONTEXT', {bool}))) and traverse_obj(INNERTUBE_CLIENTS, (client, 'SUPPORTS_AD_PLAYBACK_CONTEXT', {bool})))
yt_query.update(self._generate_player_context(sts, use_ad_playback_context)) # web_embedded player requests may need to include encryptedHostFlags in its contentPlaybackContext.
# This can be detected with the embeds_enable_encrypted_host_flags_enforcement experiemnt flag,
# but there is no harm in including encryptedHostFlags with all web_embedded player requests.
encrypted_context = None
if client == 'web_embedded':
encrypted_context = traverse_obj(player_ytcfg, (
'WEB_PLAYER_CONTEXT_CONFIGS', 'WEB_PLAYER_CONTEXT_CONFIG_ID_EMBEDDED_PLAYER', 'encryptedHostFlags'))
yt_query.update(
self._generate_player_context(
sts=sts,
use_ad_playback_context=use_ad_playback_context,
encrypted_context=encrypted_context))
return self._extract_response( return self._extract_response(
item_id=video_id, ep='player', query=yt_query, item_id=video_id, ep='player', query=yt_query,