diff --git a/test/test_utils.py b/test/test_utils.py index 0865b39810..72f0eb7f76 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -1403,6 +1403,9 @@ class TestUtil(unittest.TestCase): self.assertEqual(version_tuple('1'), (1,)) self.assertEqual(version_tuple('10.23.344'), (10, 23, 344)) self.assertEqual(version_tuple('10.1-6'), (10, 1, 6)) # avconv style + self.assertEqual(version_tuple('invalid', lenient=True), (-1,)) + self.assertEqual(version_tuple('1.2.3', lenient=True), (1, 2, 3)) + self.assertEqual(version_tuple('12.34-something', lenient=True), (12, 34, -1)) def test_detect_exe_version(self): self.assertEqual(detect_exe_version('''ffmpeg version 1.2.1 diff --git a/yt_dlp/extractor/youtube/jsc/_builtin/ejs.py b/yt_dlp/extractor/youtube/jsc/_builtin/ejs.py index 52d7ecf170..11c8e7ac52 100644 --- a/yt_dlp/extractor/youtube/jsc/_builtin/ejs.py +++ b/yt_dlp/extractor/youtube/jsc/_builtin/ejs.py @@ -21,6 +21,7 @@ from yt_dlp.extractor.youtube.jsc.provider import ( ) from yt_dlp.extractor.youtube.pot._provider import configuration_arg from yt_dlp.extractor.youtube.pot.provider import provider_bug_report_message +from yt_dlp.utils import version_tuple from yt_dlp.utils._jsruntime import JsRuntimeInfo if _has_ejs: @@ -223,7 +224,8 @@ class EJSBaseJCP(JsChallengeProvider): skipped_components.append(script) continue if not self.is_dev: - if script.version != self._SCRIPT_VERSION: + # Matching patch version is expected to have same hash + if version_tuple(script.version, lenient=True)[:2] != version_tuple(self._SCRIPT_VERSION, lenient=True)[:2]: self.logger.warning( f'Challenge solver {script_type.value} script version {script.version} ' f'is not supported (source: {script.source.value}, variant: {script.variant}, supported version: {self._SCRIPT_VERSION})') diff --git a/yt_dlp/utils/_jsruntime.py b/yt_dlp/utils/_jsruntime.py index 94db52bf19..4ea230da42 100644 --- a/yt_dlp/utils/_jsruntime.py +++ b/yt_dlp/utils/_jsruntime.py @@ -6,12 +6,7 @@ import functools import os.path import sys -from ._utils import _get_exe_version_output, detect_exe_version, int_or_none - - -def _runtime_version_tuple(v): - # NB: will return (0,) if `v` is an invalid version string - return tuple(int_or_none(x, default=0) for x in v.split('.')) +from ._utils import _get_exe_version_output, detect_exe_version, version_tuple _FALLBACK_PATHEXT = ('.COM', '.EXE', '.BAT', '.CMD') @@ -92,7 +87,7 @@ class DenoJsRuntime(JsRuntime): if not out: return None version = detect_exe_version(out, r'^deno (\S+)', 'unknown') - vt = _runtime_version_tuple(version) + vt = version_tuple(version, lenient=True) return JsRuntimeInfo( name='deno', path=path, version=version, version_tuple=vt, supported=vt >= self.MIN_SUPPORTED_VERSION) @@ -107,7 +102,7 @@ class BunJsRuntime(JsRuntime): if not out: return None version = detect_exe_version(out, r'^(\S+)', 'unknown') - vt = _runtime_version_tuple(version) + vt = version_tuple(version, lenient=True) return JsRuntimeInfo( name='bun', path=path, version=version, version_tuple=vt, supported=vt >= self.MIN_SUPPORTED_VERSION) @@ -122,7 +117,7 @@ class NodeJsRuntime(JsRuntime): if not out: return None version = detect_exe_version(out, r'^v(\S+)', 'unknown') - vt = _runtime_version_tuple(version) + vt = version_tuple(version, lenient=True) return JsRuntimeInfo( name='node', path=path, version=version, version_tuple=vt, supported=vt >= self.MIN_SUPPORTED_VERSION) @@ -140,7 +135,7 @@ class QuickJsRuntime(JsRuntime): is_ng = 'QuickJS-ng' in out version = detect_exe_version(out, r'^QuickJS(?:-ng)?\s+version\s+(\S+)', 'unknown') - vt = _runtime_version_tuple(version.replace('-', '.')) + vt = version_tuple(version, lenient=True) if is_ng: return JsRuntimeInfo( name='quickjs-ng', path=path, version=version, version_tuple=vt, diff --git a/yt_dlp/utils/_utils.py b/yt_dlp/utils/_utils.py index 65cd2373ce..b0ca950248 100644 --- a/yt_dlp/utils/_utils.py +++ b/yt_dlp/utils/_utils.py @@ -2895,8 +2895,9 @@ def limit_length(s, length): return s -def version_tuple(v): - return tuple(int(e) for e in re.split(r'[-.]', v)) +def version_tuple(v, *, lenient=False): + parse = int_or_none(default=-1) if lenient else int + return tuple(parse(e) for e in re.split(r'[-.]', v)) def is_outdated_version(version, limit, assume_new=True):