mirror of
https://github.com/ytdl-org/youtube-dl
synced 2025-10-03 23:08:36 +09:00
[YouTube] Implement player JS override for player 0004de42
* based on yt-dlp/yt-dlp#14398, thx seproDev * adds --youtube-player-js-variant option * adds --youtube-player-js-version option * sets defaults to main variant of player `0004de42` * fixes #33187, for now
This commit is contained in:
@@ -409,6 +409,8 @@ def _real_main(argv=None):
|
|||||||
'include_ads': opts.include_ads,
|
'include_ads': opts.include_ads,
|
||||||
'default_search': opts.default_search,
|
'default_search': opts.default_search,
|
||||||
'youtube_include_dash_manifest': opts.youtube_include_dash_manifest,
|
'youtube_include_dash_manifest': opts.youtube_include_dash_manifest,
|
||||||
|
'youtube_player_js_version': opts.youtube_player_js_version,
|
||||||
|
'youtube_player_js_variant': opts.youtube_player_js_variant,
|
||||||
'encoding': opts.encoding,
|
'encoding': opts.encoding,
|
||||||
'extract_flat': opts.extract_flat,
|
'extract_flat': opts.extract_flat,
|
||||||
'mark_watched': opts.mark_watched,
|
'mark_watched': opts.mark_watched,
|
||||||
|
@@ -1625,6 +1625,19 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
self._code_cache = {}
|
self._code_cache = {}
|
||||||
self._player_cache = {}
|
self._player_cache = {}
|
||||||
|
|
||||||
|
def _get_player_js_version(self):
|
||||||
|
player_js_version = self.get_param('youtube_player_js_version') or '20348@0004de42'
|
||||||
|
sts_hash = self._search_regex(
|
||||||
|
('^actual$(^)?(^)?', r'^([0-9]{5,})@([0-9a-f]{8,})$'),
|
||||||
|
player_js_version, 'player_js_version', group=(1, 2), default=None)
|
||||||
|
if sts_hash:
|
||||||
|
return sts_hash
|
||||||
|
self.report_warning(
|
||||||
|
'Invalid player JS version "{0}" specified. '
|
||||||
|
'It should be "{1}" or in the format of {2}'.format(
|
||||||
|
player_js_version, 'actual', 'SignatureTimeStamp@Hash'), only_once=True)
|
||||||
|
return None, None
|
||||||
|
|
||||||
# *ytcfgs, webpage=None
|
# *ytcfgs, webpage=None
|
||||||
def _extract_player_url(self, *ytcfgs, **kw_webpage):
|
def _extract_player_url(self, *ytcfgs, **kw_webpage):
|
||||||
if ytcfgs and not isinstance(ytcfgs[0], dict):
|
if ytcfgs and not isinstance(ytcfgs[0], dict):
|
||||||
@@ -1635,19 +1648,43 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
webpage or '', 'player URL', fatal=False)
|
webpage or '', 'player URL', fatal=False)
|
||||||
if player_url:
|
if player_url:
|
||||||
ytcfgs = ytcfgs + ({'PLAYER_JS_URL': player_url},)
|
ytcfgs = ytcfgs + ({'PLAYER_JS_URL': player_url},)
|
||||||
return traverse_obj(
|
player_url = traverse_obj(
|
||||||
ytcfgs, (Ellipsis, 'PLAYER_JS_URL'), (Ellipsis, 'WEB_PLAYER_CONTEXT_CONFIGS', Ellipsis, 'jsUrl'),
|
ytcfgs, (Ellipsis, 'PLAYER_JS_URL'), (Ellipsis, 'WEB_PLAYER_CONTEXT_CONFIGS', Ellipsis, 'jsUrl'),
|
||||||
get_all=False, expected_type=lambda u: urljoin('https://www.youtube.com', u))
|
get_all=False, expected_type=lambda u: urljoin('https://www.youtube.com', u))
|
||||||
|
|
||||||
|
player_id_override = self._get_player_js_version()[1]
|
||||||
|
|
||||||
|
requested_js_variant = self.get_param('youtube_player_js_variant') or 'main'
|
||||||
|
variant_js = next(
|
||||||
|
(v for k, v in self._PLAYER_JS_VARIANT_MAP if k == requested_js_variant),
|
||||||
|
None)
|
||||||
|
if variant_js:
|
||||||
|
player_id = player_id_override or self._extract_player_info(player_url)
|
||||||
|
original_url = player_url
|
||||||
|
player_url = '/s/player/{0}/{1}'.format(player_id, variant_js)
|
||||||
|
if original_url != player_url:
|
||||||
|
self.write_debug(
|
||||||
|
'Forcing "{0}" player JS variant for player {1}\n'
|
||||||
|
' original url = {2}'.format(
|
||||||
|
requested_js_variant, player_id, original_url),
|
||||||
|
only_once=True)
|
||||||
|
elif requested_js_variant != 'actual':
|
||||||
|
self.report_warning(
|
||||||
|
'Invalid player JS variant name "{0}" requested. '
|
||||||
|
'Valid choices are: {1}'.format(
|
||||||
|
requested_js_variant, ','.join(k for k, _ in self._PLAYER_JS_VARIANT_MAP)),
|
||||||
|
only_once=True)
|
||||||
|
|
||||||
|
return urljoin('https://www.youtube.com', player_url)
|
||||||
|
|
||||||
def _download_player_url(self, video_id, fatal=False):
|
def _download_player_url(self, video_id, fatal=False):
|
||||||
res = self._download_webpage(
|
res = self._download_webpage(
|
||||||
'https://www.youtube.com/iframe_api',
|
'https://www.youtube.com/iframe_api',
|
||||||
note='Downloading iframe API JS', video_id=video_id, fatal=fatal)
|
note='Downloading iframe API JS', video_id=video_id, fatal=fatal)
|
||||||
player_version = self._search_regex(
|
player_version = self._search_regex(
|
||||||
r'player\\?/([0-9a-fA-F]{8})\\?/', res or '', 'player version', fatal=fatal,
|
r'player\\?/([0-9a-fA-F]{8})\\?/', res or '', 'player version', fatal=fatal,
|
||||||
default=NO_DEFAULT if res else None)
|
default=NO_DEFAULT if res else None) or None
|
||||||
if player_version:
|
return player_version and 'https://www.youtube.com/s/player/{0}/player_ias.vflset/en_US/base.js'.format(player_version)
|
||||||
return 'https://www.youtube.com/s/player/{0}/player_ias.vflset/en_US/base.js'.format(player_version)
|
|
||||||
|
|
||||||
def _signature_cache_id(self, example_sig):
|
def _signature_cache_id(self, example_sig):
|
||||||
""" Return a string representation of a signature """
|
""" Return a string representation of a signature """
|
||||||
@@ -2034,9 +2071,15 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
def _extract_signature_timestamp(self, video_id, player_url, ytcfg=None, fatal=False):
|
def _extract_signature_timestamp(self, video_id, player_url, ytcfg=None, fatal=False):
|
||||||
"""
|
"""
|
||||||
Extract signatureTimestamp (sts)
|
Extract signatureTimestamp (sts)
|
||||||
|
|
||||||
Required to tell API what sig/player version is in use.
|
Required to tell API what sig/player version is in use.
|
||||||
"""
|
"""
|
||||||
sts = traverse_obj(ytcfg, 'STS', expected_type=int)
|
sts = traverse_obj(
|
||||||
|
(self._get_player_js_version(), ytcfg),
|
||||||
|
(0, 0),
|
||||||
|
(1, 'STS'),
|
||||||
|
expected_type=int_or_none)
|
||||||
|
|
||||||
if sts:
|
if sts:
|
||||||
return sts
|
return sts
|
||||||
|
|
||||||
|
@@ -412,6 +412,17 @@ def parseOpts(overrideArguments=None):
|
|||||||
'--youtube-skip-dash-manifest',
|
'--youtube-skip-dash-manifest',
|
||||||
action='store_false', dest='youtube_include_dash_manifest',
|
action='store_false', dest='youtube_include_dash_manifest',
|
||||||
help='Do not download the DASH manifests and related data on YouTube videos')
|
help='Do not download the DASH manifests and related data on YouTube videos')
|
||||||
|
video_format.add_option(
|
||||||
|
'--youtube-player-js-variant',
|
||||||
|
action='store', dest='youtube_player_js_variant',
|
||||||
|
help='For YouTube, the player javascript variant to use for n/sig deciphering; `actual` to follow the site; default `%default`.',
|
||||||
|
choices=('actual', 'main', 'tcc', 'tce', 'es5', 'es6', 'tv', 'tv_es6', 'phone', 'tablet'),
|
||||||
|
default='main', metavar='VARIANT')
|
||||||
|
video_format.add_option(
|
||||||
|
'--youtube-player-js-version',
|
||||||
|
action='store', dest='youtube_player_js_version',
|
||||||
|
help='For YouTube, the player javascript version to use for n/sig deciphering, specified as `signature_timestamp@hash`, or `actual` to follow the site; default `%default`',
|
||||||
|
default='20348@0004de42', metavar='STS@HASH')
|
||||||
video_format.add_option(
|
video_format.add_option(
|
||||||
'--merge-output-format',
|
'--merge-output-format',
|
||||||
action='store', dest='merge_output_format', metavar='FORMAT', default=None,
|
action='store', dest='merge_output_format', metavar='FORMAT', default=None,
|
||||||
|
Reference in New Issue
Block a user