[ie/youtube] Player client maintenance (#17261)

* Add visionos to logged-out default clients
* Add POT policy for android_vr
* Use tv_downgraded for VR fallback client
* Move back to web from web_safari in defaults

Closes #14997
Closes #15583
Closes #15756
Closes #15798
Closes #16064
Closes #17143
Closes #17232
Closes #17252

Authored by: bashonly
This commit is contained in:
bashonly
2026-07-20 23:36:39 +00:00
committed by GitHub
parent 93ceb95cdf
commit 69ea200067
3 changed files with 33 additions and 9 deletions
+20 -1
View File
@@ -107,6 +107,7 @@ INNERTUBE_CLIENTS = {
**WEB_PO_TOKEN_POLICIES,
},
# Safari UA returns pre-merged video+audio 144p/240p/360p/720p/1080p HLS formats
# Since 2026.07, HLS formats are only returned with some logged-in or "trusted" sessions
'web_safari': {
'INNERTUBE_CONTEXT': {
'client': {
@@ -223,6 +224,7 @@ INNERTUBE_CLIENTS = {
},
# "Made for kids" videos aren't available with this client
# Using a clientVersion>1.65 may return SABR streams only
# Since 2026.07, intermittent/selective POT enforcement has been observed for non-HLS formats
'android_vr': {
'INNERTUBE_CONTEXT': {
'client': {
@@ -238,6 +240,24 @@ INNERTUBE_CLIENTS = {
},
'INNERTUBE_CONTEXT_CLIENT_NAME': 28,
'REQUIRE_JS_PLAYER': False,
'GVS_PO_TOKEN_POLICY': {
StreamingProtocol.HTTPS: GvsPoTokenPolicy(
required=True,
recommended=True,
not_required_with_player_token=True,
),
StreamingProtocol.DASH: GvsPoTokenPolicy(
required=True,
recommended=True,
not_required_with_player_token=True,
),
StreamingProtocol.HLS: GvsPoTokenPolicy(
required=False,
recommended=True,
not_required_with_player_token=True,
),
},
'PLAYER_PO_TOKEN_POLICY': PlayerPoTokenPolicy(required=False, recommended=True),
},
# iOS clients have HLS live streams. Setting device model to get 60fps formats.
# See: https://github.com/TeamNewPipe/NewPipeExtractor/issues/680#issuecomment-1002724558
@@ -340,7 +360,6 @@ INNERTUBE_CLIENTS = {
},
},
'INNERTUBE_CONTEXT_CLIENT_NAME': 7,
'REQUIRE_AUTH': True,
'SUPPORTS_COOKIES': True,
},
'tv_simply': {
+12 -7
View File
@@ -140,13 +140,13 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
_RETURN_TYPE = 'video' # XXX: How to handle multifeed?
_SUBTITLE_FORMATS = ('json3', 'srv1', 'srv2', 'srv3', 'ttml', 'srt', 'vtt')
_DEFAULT_CLIENTS = ('android_vr', 'web_safari')
_DEFAULT_JSLESS_CLIENTS = ('android_vr',)
_DEFAULT_AUTHED_CLIENTS = ('tv_downgraded', 'web_safari')
_DEFAULT_CLIENTS = ('visionos', 'android_vr', 'web')
_DEFAULT_JSLESS_CLIENTS = ('visionos', 'android_vr')
_DEFAULT_AUTHED_CLIENTS = ('tv_downgraded', 'web')
# Premium does not require POT (except for subtitles)
_DEFAULT_PREMIUM_CLIENTS = ('tv_downgraded', 'web_creator')
_DEFAULT_PREMIUM_CLIENTS = ('tv_downgraded', 'web_creator', 'web')
_WEBPAGE_CLIENTS = ('web', 'web_safari')
_DEFAULT_WEBPAGE_CLIENT = 'web_safari'
_DEFAULT_WEBPAGE_CLIENT = 'web'
_GEO_BYPASS = False
@@ -2904,6 +2904,10 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
def _is_unplayable(player_response):
return traverse_obj(player_response, ('playabilityStatus', 'status')) == 'UNPLAYABLE'
@staticmethod
def _is_error_response(player_response):
return traverse_obj(player_response, ('playabilityStatus', 'status')) == 'ERROR'
def _extract_player_response(self, client, video_id, webpage_ytcfg, player_ytcfg, player_url, initial_pr, visitor_data, data_sync_id, po_token):
headers = self.generate_api_headers(
ytcfg=player_ytcfg,
@@ -3137,12 +3141,13 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
if (
# Is this a "made for kids" video that can't be downloaded with android_vr/visionos?
client in {'android_vr', 'visionos'} and self._is_unplayable(pr)
client in {'android_vr', 'visionos'}
and (self._is_unplayable(pr) or self._is_error_response(pr))
and webpage and 'made for kids' in webpage
# ...and is a JS runtime is available?
and any(p.is_available() for p in self._jsc_director.providers.values())
):
append_client('web_embedded')
append_client('tv_downgraded')
# web_embedded can work around age-gate and age-verification for some embeddable videos
if self._is_agegated(pr) and variant != 'web_embedded':