From 7f5d9f8543d19590eeec9473d54fa00151afa78a Mon Sep 17 00:00:00 2001 From: sepro Date: Tue, 23 Sep 2025 07:07:28 +0200 Subject: [PATCH] [ie/youtube] Force player `0004de42` (#14398) Closes #14400 Authored by: seproDev --- README.md | 3 ++- yt_dlp/extractor/youtube/_video.py | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8cd9d892f6..17cd6bc577 100644 --- a/README.md +++ b/README.md @@ -1821,7 +1821,8 @@ The following extractors use this feature: * `player_skip`: Skip some network requests that are generally needed for robust extraction. One or more of `configs` (skip client configs), `webpage` (skip initial webpage), `js` (skip js player), `initial_data` (skip initial data/next ep request). While these options can help reduce the number of requests needed or avoid some rate-limiting, they could cause issues such as missing formats or metadata. See [#860](https://github.com/yt-dlp/yt-dlp/pull/860) and [#12826](https://github.com/yt-dlp/yt-dlp/issues/12826) for more details * `webpage_skip`: Skip extraction of embedded webpage data. One or both of `player_response`, `initial_data`. These options are for testing purposes and don't skip any network requests * `player_params`: YouTube player parameters to use for player requests. Will overwrite any default ones set by yt-dlp. -* `player_js_variant`: The player javascript variant to use for signature and nsig deciphering. The known variants are: `main`, `tce`, `tv`, `tv_es6`, `phone`, `tablet`. The default is `main`, and the others are for debugging purposes. You can use `actual` to go with what is prescribed by the site +* `player_js_variant`: The player javascript variant to use for n/sig deciphering. The known variants are: `main`, `tcc`, `tce`, `es5`, `es6`, `tv`, `tv_es6`, `phone`, `tablet`. The default is `main`, and the others are for debugging purposes. You can use `actual` to go with what is prescribed by the site +* `player_js_version`: The player javascript version to use for n/sig deciphering, in the format of `signature_timestamp@hash`. Currently, the default is to force `20348@0004de42`. You can use `actual` to go with what is prescribed by the site * `comment_sort`: `top` or `new` (default) - choose comment sorting mode (on YouTube's side) * `max_comments`: Limit the amount of comments to gather. Comma-separated list of integers representing `max-comments,max-parents,max-replies,max-replies-per-thread`. Default is `all,all,all,all` * E.g. `all,all,1000,10` will get a maximum of 1000 replies total, with up to 10 replies per thread. `1000,all,100` will get a maximum of 1000 comments, with a maximum of 100 replies total diff --git a/yt_dlp/extractor/youtube/_video.py b/yt_dlp/extractor/youtube/_video.py index 8c5486c4c2..6dba724cee 100644 --- a/yt_dlp/extractor/youtube/_video.py +++ b/yt_dlp/extractor/youtube/_video.py @@ -2015,16 +2015,28 @@ class YoutubeIE(YoutubeBaseInfoExtractor): time.sleep(max(0, FETCH_SPAN + fetch_time - time.time())) + def _get_player_js_version(self): + player_js_version = self._configuration_arg('player_js_version', [''])[0] or '20348@0004de42' + if player_js_version == 'actual': + return None, None + if not re.fullmatch(r'[0-9]{5,}@[0-9a-f]{8,}', player_js_version): + self.report_warning( + f'Invalid player JS version "{player_js_version}" specified. ' + f'It should be "actual" or in the format of STS@HASH', only_once=True) + return None, None + return player_js_version.split('@') + def _extract_player_url(self, *ytcfgs, webpage=None): player_url = traverse_obj( ytcfgs, (..., 'PLAYER_JS_URL'), (..., 'WEB_PLAYER_CONTEXT_CONFIGS', ..., 'jsUrl'), get_all=False, expected_type=str) if not player_url: return + player_id_override = self._get_player_js_version()[1] requested_js_variant = self._configuration_arg('player_js_variant', [''])[0] or 'main' if requested_js_variant in self._PLAYER_JS_VARIANT_MAP: - player_id = self._extract_player_info(player_url) + player_id = player_id_override or self._extract_player_info(player_url) original_url = player_url player_url = f'/s/player/{player_id}/{self._PLAYER_JS_VARIANT_MAP[requested_js_variant]}' if original_url != player_url: @@ -2387,6 +2399,10 @@ class YoutubeIE(YoutubeBaseInfoExtractor): Extract signatureTimestamp (sts) Required to tell API what sig/player version is in use. """ + player_sts_override = self._get_player_js_version()[0] + if player_sts_override: + return int(player_sts_override) + if sts := traverse_obj(ytcfg, ('STS', {int_or_none})): return sts