Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package yt-dlp for openSUSE:Factory checked in at 2024-12-12 21:20:08 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/yt-dlp (Old) and /work/SRC/openSUSE:Factory/.yt-dlp.new.29675 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "yt-dlp" Thu Dec 12 21:20:08 2024 rev:52 rq:1230582 version:2024.12.06 Changes: -------- --- /work/SRC/openSUSE:Factory/yt-dlp/yt-dlp.changes 2024-12-04 15:27:06.313179943 +0100 +++ /work/SRC/openSUSE:Factory/.yt-dlp.new.29675/yt-dlp.changes 2024-12-12 21:21:46.069658381 +0100 @@ -1,0 +2,6 @@ +Thu Dec 12 12:50:03 UTC 2024 - Jan Engelhardt <[email protected]> + +- Update to release 2024.12.06 + * No changelog was provided + +------------------------------------------------------------------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ yt-dlp.spec ++++++ --- /var/tmp/diff_new_pack.mGAJ5H/_old 2024-12-12 21:21:46.613681048 +0100 +++ /var/tmp/diff_new_pack.mGAJ5H/_new 2024-12-12 21:21:46.613681048 +0100 @@ -21,7 +21,7 @@ %define skip_python37 1 %{?sle15_python_module_pythons} Name: yt-dlp -Version: 2024.12.03 +Version: 2024.12.06 Release: 0 Summary: Enhanced fork of youtube-dl, a video site downloader for offline watching License: CC-BY-SA-3.0 AND SUSE-Public-Domain ++++++ _scmsync.obsinfo ++++++ --- /var/tmp/diff_new_pack.mGAJ5H/_old 2024-12-12 21:21:46.641682215 +0100 +++ /var/tmp/diff_new_pack.mGAJ5H/_new 2024-12-12 21:21:46.641682215 +0100 @@ -1,5 +1,5 @@ -mtime: 1733259590 -commit: e67a7c9e7a6281dff155c28431ef9e13edd779ac81e96f287f20727aba1baac6 +mtime: 1734008116 +commit: 1775396c4acf4f889232cd2bf4f310801254679e6dc75883fc0cc73d47b1de46 url: https://src.opensuse.org/jengelh/yt-dlp revision: master ++++++ build.specials.obscpio ++++++ diff: old/*: No such file or directory diff: new/*: No such file or directory ++++++ yt-dlp.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yt-dlp/AUTHORS new/yt-dlp/AUTHORS --- old/yt-dlp/AUTHORS 2024-12-03 21:31:23.000000000 +0100 +++ new/yt-dlp/AUTHORS 2024-12-06 17:07:46.000000000 +0100 @@ -1524,6 +1524,7 @@ vtexier vvto33 wankerer +wesson09 willbeaufoy winterbird-code winwon diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yt-dlp/CONTRIBUTORS new/yt-dlp/CONTRIBUTORS --- old/yt-dlp/CONTRIBUTORS 2024-12-03 21:31:22.000000000 +0100 +++ new/yt-dlp/CONTRIBUTORS 2024-12-06 17:07:45.000000000 +0100 @@ -710,3 +710,4 @@ gitninja1234 jkruse xiaomac +wesson09 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yt-dlp/Changelog.md new/yt-dlp/Changelog.md --- old/yt-dlp/Changelog.md 2024-12-03 21:31:18.000000000 +0100 +++ new/yt-dlp/Changelog.md 2024-12-06 17:07:42.000000000 +0100 @@ -4,6 +4,19 @@ # To create a release, dispatch the https://github.com/yt-dlp/yt-dlp/actions/workflows/release.yml workflow on master --> +### 2024.12.06 + +#### Core changes +- **cookies**: [Add `--cookies-from-browser` support for MS Store Firefox](https://github.com/yt-dlp/yt-dlp/commit/354cb4026cf2191e1a130ec2a627b95cabfbc60a) ([#11731](https://github.com/yt-dlp/yt-dlp/issues/11731)) by [wesson09](https://github.com/wesson09) + +#### Extractor changes +- **bilibili**: [Fix HD formats extraction](https://github.com/yt-dlp/yt-dlp/commit/fca3eb5f8be08d5fab2e18b45b7281a12e566725) ([#11734](https://github.com/yt-dlp/yt-dlp/issues/11734)) by [grqz](https://github.com/grqz) +- **soundcloud**: [Fix formats extraction](https://github.com/yt-dlp/yt-dlp/commit/2feb28028ee48f2185d2d95076e62accb09b9e2e) ([#11742](https://github.com/yt-dlp/yt-dlp/issues/11742)) by [bashonly](https://github.com/bashonly) +- **youtube** + - [Fix `n` sig extraction for player `3bb1f723`](https://github.com/yt-dlp/yt-dlp/commit/a95ee6d8803fca9157adecf63732ab58bf87fd88) ([#11750](https://github.com/yt-dlp/yt-dlp/issues/11750)) by [bashonly](https://github.com/bashonly) (With fixes in [4bd2655](https://github.com/yt-dlp/yt-dlp/commit/4bd2655398aed450456197a6767639114a24eac2)) + - [Fix signature function extraction](https://github.com/yt-dlp/yt-dlp/commit/4c85ccd1366c88cf93982f8350f58eed17355981) ([#11751](https://github.com/yt-dlp/yt-dlp/issues/11751)) by [bashonly](https://github.com/bashonly) + - [Player client maintenance](https://github.com/yt-dlp/yt-dlp/commit/2e49c789d3eebc39af8910705d65a98bca0e4c4f) ([#11724](https://github.com/yt-dlp/yt-dlp/issues/11724)) by [bashonly](https://github.com/bashonly) + ### 2024.12.03 #### Core changes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yt-dlp/README.md new/yt-dlp/README.md --- old/yt-dlp/README.md 2024-12-03 21:31:22.000000000 +0100 +++ new/yt-dlp/README.md 2024-12-06 17:07:45.000000000 +0100 @@ -1860,7 +1860,7 @@ * `cdn`: One or more CDN IDs to use with the API call for stream URLs, e.g. `gcp_cdn`, `gs_cdn_pc_app`, `gs_cdn_mobile_web`, `gs_cdn_pc_web` #### soundcloud -* `formats`: Formats to request from the API. Requested values should be in the format of `{protocol}_{extension}` (omitting the bitrate), e.g. `hls_opus,http_aac`. The `*` character functions as a wildcard, e.g. `*_mp3`, and can be passed by itself to request all formats. Known protocols include `http`, `hls` and `hls-aes`; known extensions include `aac`, `opus` and `mp3`. Original `download` formats are always extracted. Default is `http_aac,hls_aac,http_opus,hls_opus,http_mp3,hls_mp3` +* `formats`: Formats to request from the API. Requested values should be in the format of `{protocol}_{codec}`, e.g. `hls_opus,http_aac`. The `*` character functions as a wildcard, e.g. `*_mp3`, and can be passed by itself to request all formats. Known protocols include `http`, `hls` and `hls-aes`; known codecs include `aac`, `opus` and `mp3`. Original `download` formats are always extracted. Default is `http_aac,hls_aac,http_opus,hls_opus,http_mp3,hls_mp3` #### orfon (orf:on) * `prefer_segments_playlist`: Prefer a playlist of program segments instead of a single complete video when available. If individual segments are desired, use `--concat-playlist never --extractor-args "orfon:prefer_segments_playlist"` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yt-dlp/README.txt new/yt-dlp/README.txt --- old/yt-dlp/README.txt 2024-12-03 21:31:23.000000000 +0100 +++ new/yt-dlp/README.txt 2024-12-06 17:07:46.000000000 +0100 @@ -2350,12 +2350,12 @@ soundcloud - formats: Formats to request from the API. Requested values should be - in the format of {protocol}_{extension} (omitting the bitrate), e.g. - hls_opus,http_aac. The * character functions as a wildcard, e.g. - *_mp3, and can be passed by itself to request all formats. Known - protocols include http, hls and hls-aes; known extensions include - aac, opus and mp3. Original download formats are always extracted. - Default is http_aac,hls_aac,http_opus,hls_opus,http_mp3,hls_mp3 + in the format of {protocol}_{codec}, e.g. hls_opus,http_aac. The * + character functions as a wildcard, e.g. *_mp3, and can be passed by + itself to request all formats. Known protocols include http, hls and + hls-aes; known codecs include aac, opus and mp3. Original download + formats are always extracted. Default is + http_aac,hls_aac,http_opus,hls_opus,http_mp3,hls_mp3 orfon (orf:on) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yt-dlp/test/test_youtube_signature.py new/yt-dlp/test/test_youtube_signature.py --- old/yt-dlp/test/test_youtube_signature.py 2024-12-03 21:30:58.000000000 +0100 +++ new/yt-dlp/test/test_youtube_signature.py 2024-12-06 17:07:34.000000000 +0100 @@ -68,6 +68,11 @@ '2aq0aqSyOoJXtK73m-uME_jv7-pT15gOFC02RFkGMqWpzEICs69VdbwQ0LDp1v7j8xx92efCJlYFYb1sUkkBSPOlPmXgIARw8JQ0qOAOAA', 'AOq0QJ8wRAIgXmPlOPSBkkUs1bYFYlJCfe29xx8j7v1pDL2QwbdV96sCIEzpWqMGkFR20CFOg51Tp-7vj_EMu-m37KtXJoOySqa0', ), + ( + 'https://www.youtube.com/s/player/3bb1f723/player_ias.vflset/en_US/base.js', + '2aq0aqSyOoJXtK73m-uME_jv7-pT15gOFC02RFkGMqWpzEICs69VdbwQ0LDp1v7j8xx92efCJlYFYb1sUkkBSPOlPmXgIARw8JQ0qOAOAA', + 'MyOSJXtKI3m-uME_jv7-pT12gOFC02RFkGoqWpzE0Cs69VdbwQ0LDp1v7j8xx92efCJlYFYb1sUkkBSPOlPmXgIARw8JQ0qOAOAA', + ), ] _NSIG_TESTS = [ @@ -183,6 +188,10 @@ 'https://www.youtube.com/s/player/b12cc44b/player_ias.vflset/en_US/base.js', 'keLa5R2U00sR9SQK', 'N1OGyujjEwMnLw', ), + ( + 'https://www.youtube.com/s/player/3bb1f723/player_ias.vflset/en_US/base.js', + 'gK15nzVyaXE9RsMP3z', 'ZFFWFLPWx9DEgQ', + ), ] @@ -254,8 +263,11 @@ def n_sig(jscode, sig_input): - funcname = YoutubeIE(FakeYDL())._extract_n_function_name(jscode) - return JSInterpreter(jscode).call_function(funcname, sig_input) + ie = YoutubeIE(FakeYDL()) + funcname = ie._extract_n_function_name(jscode) + jsi = JSInterpreter(jscode) + func = jsi.extract_function_from_code(*ie._fixup_n_function_code(*jsi.extract_function_code(funcname))) + return func([sig_input]) make_sig_test = t_factory( Binary files old/yt-dlp/yt-dlp and new/yt-dlp/yt-dlp differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yt-dlp/yt-dlp.1 new/yt-dlp/yt-dlp.1 --- old/yt-dlp/yt-dlp.1 2024-12-03 21:31:24.000000000 +0100 +++ new/yt-dlp/yt-dlp.1 2024-12-06 17:07:47.000000000 +0100 @@ -2883,13 +2883,13 @@ .IP \[bu] 2 \f[C]formats\f[R]: Formats to request from the API. Requested values should be in the format of -\f[C]{protocol}_{extension}\f[R] (omitting the bitrate), e.g. +\f[C]{protocol}_{codec}\f[R], e.g. \f[C]hls_opus,http_aac\f[R]. The \f[C]*\f[R] character functions as a wildcard, e.g. \f[C]*_mp3\f[R], and can be passed by itself to request all formats. Known protocols include \f[C]http\f[R], \f[C]hls\f[R] and -\f[C]hls-aes\f[R]; known extensions include \f[C]aac\f[R], -\f[C]opus\f[R] and \f[C]mp3\f[R]. +\f[C]hls-aes\f[R]; known codecs include \f[C]aac\f[R], \f[C]opus\f[R] +and \f[C]mp3\f[R]. Original \f[C]download\f[R] formats are always extracted. Default is \f[C]http_aac,hls_aac,http_opus,hls_opus,http_mp3,hls_mp3\f[R] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yt-dlp/yt_dlp/cookies.py new/yt-dlp/yt_dlp/cookies.py --- old/yt-dlp/yt_dlp/cookies.py 2024-12-03 21:30:58.000000000 +0100 +++ new/yt-dlp/yt_dlp/cookies.py 2024-12-06 17:07:34.000000000 +0100 @@ -195,7 +195,10 @@ def _firefox_browser_dirs(): if sys.platform in ('cygwin', 'win32'): - yield os.path.expandvars(R'%APPDATA%\Mozilla\Firefox\Profiles') + yield from map(os.path.expandvars, ( + R'%APPDATA%\Mozilla\Firefox\Profiles', + R'%LOCALAPPDATA%\Packages\Mozilla.Firefox_n80bbvh6b1yt2\LocalCache\Roaming\Mozilla\Firefox\Profiles', + )) elif sys.platform == 'darwin': yield os.path.expanduser('~/Library/Application Support/Firefox/Profiles') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yt-dlp/yt_dlp/extractor/bilibili.py new/yt-dlp/yt_dlp/extractor/bilibili.py --- old/yt-dlp/yt_dlp/extractor/bilibili.py 2024-12-03 21:30:58.000000000 +0100 +++ new/yt-dlp/yt_dlp/extractor/bilibili.py 2024-12-06 17:07:34.000000000 +0100 @@ -681,12 +681,6 @@ old_video_id = format_field(aid, None, f'%s_part{part_id or 1}') cid = traverse_obj(video_data, ('pages', part_id - 1, 'cid')) if part_id else video_data.get('cid') - play_info = ( - traverse_obj( - self._search_json(r'window\.__playinfo__\s*=', webpage, 'play info', video_id, default=None), - ('data', {dict})) - or self._download_playinfo(video_id, cid, headers=headers, query={'try_look': 1})) - festival_info = {} if is_festival: festival_info = traverse_obj(initial_state, { @@ -724,6 +718,13 @@ duration=traverse_obj(initial_state, ('videoData', 'duration', {int_or_none})), __post_extractor=self.extract_comments(aid)) + play_info = None + if self.is_logged_in: + play_info = traverse_obj( + self._search_json(r'window\.__playinfo__\s*=', webpage, 'play info', video_id, default=None), + ('data', {dict})) + if not play_info: + play_info = self._download_playinfo(video_id, cid, headers=headers, query={'try_look': 1}) formats = self.extract_formats(play_info) if video_data.get('is_upower_exclusive'): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yt-dlp/yt_dlp/extractor/soundcloud.py new/yt-dlp/yt_dlp/extractor/soundcloud.py --- old/yt-dlp/yt_dlp/extractor/soundcloud.py 2024-12-03 21:30:58.000000000 +0100 +++ new/yt-dlp/yt_dlp/extractor/soundcloud.py 2024-12-06 17:07:34.000000000 +0100 @@ -7,7 +7,6 @@ from ..networking import HEADRequest from ..networking.exceptions import HTTPError from ..utils import ( - KNOWN_EXTENSIONS, ExtractorError, float_or_none, int_or_none, @@ -251,50 +250,15 @@ def invalid_url(url): return not url or url in format_urls - def add_format(f, protocol, is_preview=False): - mobj = re.search(r'\.(?P<abr>\d+)\.(?P<ext>[0-9a-z]{3,4})(?=[/?])', stream_url) - if mobj: - for k, v in mobj.groupdict().items(): - if not f.get(k): - f[k] = v - format_id_list = [] - if protocol: - format_id_list.append(protocol) - ext = f.get('ext') - if ext == 'aac': - f.update({ - 'abr': 256, - 'quality': 5, - 'format_note': 'Premium', - }) - for k in ('ext', 'abr'): - v = str_or_none(f.get(k)) - if v: - format_id_list.append(v) - preview = is_preview or re.search(r'/(?:preview|playlist)/0/30/', f['url']) - if preview: - format_id_list.append('preview') - abr = f.get('abr') - if abr: - f['abr'] = int(abr) - if protocol in ('hls', 'hls-aes'): - protocol = 'm3u8' if ext == 'aac' else 'm3u8_native' - else: - protocol = 'http' - f.update({ - 'format_id': '_'.join(format_id_list), - 'protocol': protocol, - 'preference': -10 if preview else None, - }) - formats.append(f) - # New API - for t in traverse_obj(info, ('media', 'transcodings', lambda _, v: url_or_none(v['url']))): + for t in traverse_obj(info, ('media', 'transcodings', lambda _, v: url_or_none(v['url']) and v['preset'])): if extract_flat: break format_url = t['url'] + preset = t['preset'] + preset_base = preset.partition('_')[0] - protocol = traverse_obj(t, ('format', 'protocol', {str})) + protocol = traverse_obj(t, ('format', 'protocol', {str})) or 'http' if protocol == 'progressive': protocol = 'http' if protocol != 'hls' and '/hls' in format_url: @@ -302,32 +266,54 @@ if protocol == 'encrypted-hls' or '/encrypted-hls' in format_url: protocol = 'hls-aes' - ext = None - if preset := traverse_obj(t, ('preset', {str_or_none})): - ext = preset.split('_')[0] - if ext not in KNOWN_EXTENSIONS: - ext = mimetype2ext(traverse_obj(t, ('format', 'mime_type', {str}))) - - identifier = join_nonempty(protocol, ext, delim='_') - if not self._is_requested(identifier): - self.write_debug(f'"{identifier}" is not a requested format, skipping') + short_identifier = f'{protocol}_{preset_base}' + if preset_base == 'abr': + self.write_debug(f'Skipping broken "{short_identifier}" format') + continue + if not self._is_requested(short_identifier): + self.write_debug(f'"{short_identifier}" is not a requested format, skipping') continue # XXX: if not extract_flat, 429 error must be caught where _extract_info_dict is called stream_url = traverse_obj(self._call_api( - format_url, track_id, f'Downloading {identifier} format info JSON', + format_url, track_id, f'Downloading {short_identifier} format info JSON', query=query, headers=self._HEADERS), ('url', {url_or_none})) - if invalid_url(stream_url): continue format_urls.add(stream_url) - add_format({ + + mime_type = traverse_obj(t, ('format', 'mime_type', {str})) + codec = self._search_regex(r'codecs="([^"]+)"', mime_type, 'codec', default=None) + ext = { + 'mp4a': 'm4a', + 'opus': 'opus', + }.get(codec[:4] if codec else None) or mimetype2ext(mime_type, default=None) + if not ext or ext == 'm3u8': + ext = preset_base + + is_premium = t.get('quality') == 'hq' + abr = int_or_none( + self._search_regex(r'(\d+)k$', preset, 'abr', default=None) + or self._search_regex(r'\.(\d+)\.(?:opus|mp3)[/?]', stream_url, 'abr', default=None) + or (256 if (is_premium and 'aac' in preset) else None)) + + is_preview = (t.get('snipped') + or '/preview/' in format_url + or re.search(r'/(?:preview|playlist)/0/30/', stream_url)) + + formats.append({ + 'format_id': join_nonempty(protocol, preset, is_preview and 'preview', delim='_'), 'url': stream_url, 'ext': ext, - }, protocol, t.get('snipped') or '/preview/' in format_url) - - for f in formats: - f['vcodec'] = 'none' + 'acodec': codec, + 'vcodec': 'none', + 'abr': abr, + 'protocol': 'm3u8_native' if protocol in ('hls', 'hls-aes') else 'http', + 'container': 'm4a_dash' if ext == 'm4a' else None, + 'quality': 5 if is_premium else 0 if (abr and abr >= 160) else -1, + 'format_note': 'Premium' if is_premium else None, + 'preference': -10 if is_preview else None, + }) if not formats and info.get('policy') == 'BLOCK': self.raise_geo_restricted(metadata_available=True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yt-dlp/yt_dlp/extractor/youtube.py new/yt-dlp/yt_dlp/extractor/youtube.py --- old/yt-dlp/yt_dlp/extractor/youtube.py 2024-12-03 21:30:58.000000000 +0100 +++ new/yt-dlp/yt_dlp/extractor/youtube.py 2024-12-06 17:07:34.000000000 +0100 @@ -78,7 +78,7 @@ 'INNERTUBE_CONTEXT': { 'client': { 'clientName': 'WEB', - 'clientVersion': '2.20240726.00.00', + 'clientVersion': '2.20241126.01.00', }, }, 'INNERTUBE_CONTEXT_CLIENT_NAME': 1, @@ -90,7 +90,7 @@ 'INNERTUBE_CONTEXT': { 'client': { 'clientName': 'WEB', - 'clientVersion': '2.20240726.00.00', + 'clientVersion': '2.20241126.01.00', 'userAgent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15,gzip(gfe)', }, }, @@ -102,7 +102,7 @@ 'INNERTUBE_CONTEXT': { 'client': { 'clientName': 'WEB_EMBEDDED_PLAYER', - 'clientVersion': '1.20240723.01.00', + 'clientVersion': '1.20241201.00.00', }, }, 'INNERTUBE_CONTEXT_CLIENT_NAME': 56, @@ -113,7 +113,7 @@ 'INNERTUBE_CONTEXT': { 'client': { 'clientName': 'WEB_REMIX', - 'clientVersion': '1.20240724.00.00', + 'clientVersion': '1.20241127.01.00', }, }, 'INNERTUBE_CONTEXT_CLIENT_NAME': 67, @@ -124,7 +124,7 @@ 'INNERTUBE_CONTEXT': { 'client': { 'clientName': 'WEB_CREATOR', - 'clientVersion': '1.20240723.03.00', + 'clientVersion': '1.20241203.01.00', }, }, 'INNERTUBE_CONTEXT_CLIENT_NAME': 62, @@ -257,7 +257,8 @@ 'INNERTUBE_CONTEXT': { 'client': { 'clientName': 'MWEB', - 'clientVersion': '2.20240726.01.00', + 'clientVersion': '2.20241202.07.00', + 'userAgent': 'Mozilla/5.0 (iPad; CPU OS 16_7_10 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1,gzip(gfe)', }, }, 'INNERTUBE_CONTEXT_CLIENT_NAME': 2, @@ -267,7 +268,7 @@ 'INNERTUBE_CONTEXT': { 'client': { 'clientName': 'TVHTML5', - 'clientVersion': '7.20240724.13.00', + 'clientVersion': '7.20241201.18.00', }, }, 'INNERTUBE_CONTEXT_CLIENT_NAME': 7, @@ -3118,19 +3119,26 @@ self.to_screen('Extracted signature function:\n' + code) def _parse_sig_js(self, jscode): + # Examples where `sig` is funcname: + # sig=function(a){a=a.split(""); ... ;return a.join("")}; + # ;c&&(c=sig(decodeURIComponent(c)),a.set(b,encodeURIComponent(c)));return a}; + # {var l=f,m=h.sp,n=sig(decodeURIComponent(h.s));l.set(m,encodeURIComponent(n))} + # sig=function(J){J=J.split(""); ... ;return J.join("")}; + # ;N&&(N=sig(decodeURIComponent(N)),J.set(R,encodeURIComponent(N)));return J}; + # {var H=u,k=f.sp,v=sig(decodeURIComponent(f.s));H.set(k,encodeURIComponent(v))} funcname = self._search_regex( - (r'\b[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(', + (r'\b(?P<var>[a-zA-Z0-9$]+)&&\((?P=var)=(?P<sig>[a-zA-Z0-9$]{2,})\(decodeURIComponent\((?P=var)\)\)', + r'(?P<sig>[a-zA-Z0-9$]+)\s*=\s*function\(\s*(?P<arg>[a-zA-Z0-9$]+)\s*\)\s*{\s*(?P=arg)\s*=\s*(?P=arg)\.split\(\s*""\s*\)\s*;\s*[^}]+;\s*return\s+(?P=arg)\.join\(\s*""\s*\)', + r'(?:\b|[^a-zA-Z0-9$])(?P<sig>[a-zA-Z0-9$]{2,})\s*=\s*function\(\s*a\s*\)\s*{\s*a\s*=\s*a\.split\(\s*""\s*\)(?:;[a-zA-Z0-9$]{2}\.[a-zA-Z0-9$]{2}\(a,\d+\))?', + # Old patterns + r'\b[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(', r'\b[a-zA-Z0-9]+\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(', r'\bm=(?P<sig>[a-zA-Z0-9$]{2,})\(decodeURIComponent\(h\.s\)\)', - r'\bc&&\(c=(?P<sig>[a-zA-Z0-9$]{2,})\(decodeURIComponent\(c\)\)', - r'(?:\b|[^a-zA-Z0-9$])(?P<sig>[a-zA-Z0-9$]{2,})\s*=\s*function\(\s*a\s*\)\s*{\s*a\s*=\s*a\.split\(\s*""\s*\)(?:;[a-zA-Z0-9$]{2}\.[a-zA-Z0-9$]{2}\(a,\d+\))?', - r'(?P<sig>[a-zA-Z0-9$]+)\s*=\s*function\(\s*a\s*\)\s*{\s*a\s*=\s*a\.split\(\s*""\s*\)', # Obsolete patterns r'("|\')signature\1\s*,\s*(?P<sig>[a-zA-Z0-9$]+)\(', r'\.sig\|\|(?P<sig>[a-zA-Z0-9$]+)\(', r'yt\.akamaized\.net/\)\s*\|\|\s*.*?\s*[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*(?:encodeURIComponent\s*\()?\s*(?P<sig>[a-zA-Z0-9$]+)\(', r'\b[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*(?P<sig>[a-zA-Z0-9$]+)\(', - r'\b[a-zA-Z0-9]+\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*(?P<sig>[a-zA-Z0-9$]+)\(', r'\bc\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*\([^)]*\)\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\('), jscode, 'Initial JS player signature function name', group='sig') @@ -3204,6 +3212,7 @@ # * a.D&&(b="nn"[+a.D],c=a.get(b))&&(c=narray[idx](c),a.set(b,c),narray.length||nfunc("") # * a.D&&(PL(a),b=a.j.n||null)&&(b=narray[0](b),a.set("n",b),narray.length||nfunc("") # * a.D&&(b="nn"[+a.D],vL(a),c=a.j[b]||null)&&(c=narray[idx](c),a.set(b,c),narray.length||nfunc("") + # * J.J="";J.url="";J.Z&&(R="nn"[+J.Z],mW(J),N=J.K[R]||null)&&(N=narray[idx](N),J.set(R,N))}}; funcname, idx = self._search_regex( r'''(?x) (?: @@ -3220,7 +3229,7 @@ )\)&&\(c=| \b(?P<var>[a-zA-Z0-9_$]+)= )(?P<nfunc>[a-zA-Z0-9_$]+)(?:\[(?P<idx>\d+)\])?\([a-zA-Z]\) - (?(var),[a-zA-Z0-9_$]+\.set\("n"\,(?P=var)\),(?P=nfunc)\.length)''', + (?(var),[a-zA-Z0-9_$]+\.set\((?:"n+"|[a-zA-Z0-9_$]+)\,(?P=var)\))''', jscode, 'n function name', group=('nfunc', 'idx'), default=(None, None)) if not funcname: self.report_warning(join_nonempty( @@ -3229,7 +3238,7 @@ return self._search_regex( r'''(?xs) ;\s*(?P<name>[a-zA-Z0-9_$]+)\s*=\s*function\([a-zA-Z0-9_$]+\) - \s*\{(?:(?!};).)+?["']enhanced_except_''', + \s*\{(?:(?!};).)+?return\s*(?P<q>["'])[\w-]+_w8_(?P=q)\s*\+\s*[a-zA-Z0-9_$]+''', jscode, 'Initial JS player n function name', group='name') elif not idx: return funcname @@ -3238,6 +3247,11 @@ rf'var {re.escape(funcname)}\s*=\s*(\[.+?\])\s*[,;]', jscode, f'Initial JS player n function list ({funcname}.{idx})')))[int(idx)] + def _fixup_n_function_code(self, argnames, code): + return argnames, re.sub( + rf';\s*if\s*\(\s*typeof\s+[a-zA-Z0-9_$]+\s*===?\s*(["\'])undefined\1\s*\)\s*return\s+{argnames[0]};', + ';', code) + def _extract_n_function_code(self, video_id, player_url): player_id = self._extract_player_info(player_url) func_code = self.cache.load('youtube-nsig', player_id, min_ver='2024.07.09') @@ -3249,7 +3263,8 @@ func_name = self._extract_n_function_name(jscode, player_url=player_url) - func_code = jsi.extract_function_code(func_name) + # XXX: Workaround for the `typeof` gotcha + func_code = self._fixup_n_function_code(*jsi.extract_function_code(func_name)) self.cache.store('youtube-nsig', player_id, func_code) return jsi, player_id, func_code @@ -3265,7 +3280,7 @@ except Exception as e: raise JSInterpreter.Exception(traceback.format_exc(), cause=e) - if ret.startswith('enhanced_except_'): + if ret.startswith('enhanced_except_') or ret.endswith(s): raise JSInterpreter.Exception('Signature function returned an exception') return ret diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yt-dlp/yt_dlp/version.py new/yt-dlp/yt_dlp/version.py --- old/yt-dlp/yt_dlp/version.py 2024-12-03 21:31:18.000000000 +0100 +++ new/yt-dlp/yt_dlp/version.py 2024-12-06 17:07:41.000000000 +0100 @@ -1,8 +1,8 @@ # Autogenerated by devscripts/update-version.py -__version__ = '2024.12.03' +__version__ = '2024.12.06' -RELEASE_GIT_HEAD = '2b67ac300ac8b44368fb121637d1743cea8c5b6b' +RELEASE_GIT_HEAD = '4bd2655398aed450456197a6767639114a24eac2' VARIANT = None @@ -12,4 +12,4 @@ ORIGIN = 'yt-dlp/yt-dlp' -_pkg_version = '2024.12.03' +_pkg_version = '2024.12.06'
