]> jfr.im git - yt-dlp.git/commitdiff
[jsinterp, extractor/youtube] Minor fixes
authorpukkandan <redacted>
Tue, 30 Aug 2022 11:53:59 +0000 (17:23 +0530)
committerpukkandan <redacted>
Tue, 30 Aug 2022 12:43:37 +0000 (18:13 +0530)
test/test_jsinterp.py
yt_dlp/cache.py
yt_dlp/extractor/openload.py
yt_dlp/extractor/youtube.py
yt_dlp/jsinterp.py

index 863e52458b47b9f045dd5ca206db6854b72cd9a6..778607fb259a18dec1aa447b8e0ef40502834aab 100644 (file)
@@ -129,6 +129,11 @@ def test_precedence(self):
         self.assertEqual(jsi.call_function('x'), [20, 20, 30, 40, 50])
 
     def test_builtins(self):
+        jsi = JSInterpreter('''
+        function x() { return NaN }
+        ''')
+        self.assertTrue(math.isnan(jsi.call_function('x')))
+
         jsi = JSInterpreter('''
         function x() { return new Date('Wednesday 31 December 1969 18:01:26 MDT') - 0; }
         ''')
index 602cb9edba282ceaba21f4e29589648dadb92b59..4f9fb78d3740455d6e41cce1c256b84873ab6990 100644 (file)
@@ -51,15 +51,15 @@ def store(self, section, key, data, dtype='json'):
             tb = traceback.format_exc()
             self._ydl.report_warning(f'Writing cache to {fn!r} failed: {tb}')
 
-    def _validate(self, data, after):
+    def _validate(self, data, min_ver):
         version = traverse_obj(data, 'yt-dlp_version')
         if not version:  # Backward compatibility
             data, version = {'data': data}, '2022.08.19'
-        if not after or version_tuple(version) > version_tuple(after):
+        if not min_ver or version_tuple(version) >= version_tuple(min_ver):
             return data['data']
-        self._ydl.write_debug(f'Discarding old cache from version {version} (need {after})')
+        self._ydl.write_debug(f'Discarding old cache from version {version} (needs {min_ver})')
 
-    def load(self, section, key, dtype='json', default=None, *, after=None):
+    def load(self, section, key, dtype='json', default=None, *, min_ver=None):
         assert dtype in ('json',)
 
         if not self.enabled:
@@ -70,7 +70,7 @@ def load(self, section, key, dtype='json', default=None, *, after=None):
             try:
                 with open(cache_fn, encoding='utf-8') as cachef:
                     self._ydl.write_debug(f'Loading {section}.{key} from cache')
-                    return self._validate(json.load(cachef), after)
+                    return self._validate(json.load(cachef), min_ver)
             except (ValueError, KeyError):
                 try:
                     file_size = os.path.getsize(cache_fn)
index 4bba7bdd05e1da466d05e82ae2e39408ebbba9ba..d2756a0061c14d396f5478b3e770615c611f2dc3 100644 (file)
@@ -52,6 +52,8 @@ class PhantomJSwrapper:
     This class is experimental.
     """
 
+    INSTALL_HINT = 'Please download it from https://phantomjs.org/download.html'
+
     _BASE_JS = R'''
         phantom.onError = function(msg, trace) {{
           var msgStack = ['PHANTOM ERROR: ' + msg];
@@ -110,8 +112,7 @@ def __init__(self, extractor, required_version=None, timeout=10000):
 
         self.exe = check_executable('phantomjs', ['-v'])
         if not self.exe:
-            raise ExtractorError(
-                'PhantomJS not found, Please download it from https://phantomjs.org/download.html', expected=True)
+            raise ExtractorError(f'PhantomJS not found, {self.INSTALL_HINT}', expected=True)
 
         self.extractor = extractor
 
@@ -237,6 +238,6 @@ def execute(self, jscode, video_id=None, *, note='Executing JS'):
         except Exception as e:
             raise ExtractorError(f'{note} failed: Unable to run PhantomJS binary', cause=e)
         if returncode:
-            raise ExtractorError(f'{note} failed:\n{stderr.strip()}')
+            raise ExtractorError(f'{note} failed with returncode {returncode}:\n{stderr.strip()}')
 
         return stdout
index b30dadf9f0b816e9e6c55347820952d8e0224d01..0498f980d210ef1baa9e1a855cf0a96a89c312fe 100644 (file)
@@ -2670,7 +2670,7 @@ def _extract_n_function_name(self, jscode):
 
     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, after='2022.08.19.1')
+        func_code = self.cache.load('youtube-nsig', player_id, min_ver='2022.08.19.2')
         jscode = func_code or self._load_player(video_id, player_url)
         jsi = JSInterpreter(jscode)
 
@@ -3282,7 +3282,8 @@ def _extract_formats_and_subtitles(self, streaming_data, video_id, player_url, i
                 except ExtractorError as e:
                     phantomjs_hint = ''
                     if isinstance(e, JSInterpreter.Exception):
-                        phantomjs_hint = f'         Install {self._downloader._format_err("PhantomJS", self._downloader.Styles.EMPHASIS)} to workaround the issue\n'
+                        phantomjs_hint = (f'         Install {self._downloader._format_err("PhantomJS", self._downloader.Styles.EMPHASIS)} '
+                                          f'to workaround the issue. {PhantomJSwrapper.INSTALL_HINT}\n')
                     self.report_warning(
                         f'nsig extraction failed: You may experience throttling for some formats\n{phantomjs_hint}'
                         f'         n = {query["n"][0]} ; player = {player_url}', video_id=video_id, only_once=True)
index cadb013a314e4b7e613612457ed5fb892a4f17fb..99bdca9270b2df77c396d25e680171ac86ebfecd 100644 (file)
@@ -172,7 +172,14 @@ def wrap_interpreter(cls, f):
         def interpret_statement(self, stmt, local_vars, allow_recursion, *args, **kwargs):
             if cls.ENABLED and stmt.strip():
                 cls.write(stmt, level=allow_recursion)
-            ret, should_ret = f(self, stmt, local_vars, allow_recursion, *args, **kwargs)
+            try:
+                ret, should_ret = f(self, stmt, local_vars, allow_recursion, *args, **kwargs)
+            except Exception as e:
+                if cls.ENABLED:
+                    if isinstance(e, ExtractorError):
+                        e = e.orig_msg
+                    cls.write('=> Raises:', e, '<-|', stmt, level=allow_recursion)
+                raise
             if cls.ENABLED and stmt.strip():
                 cls.write(['->', '=>'][should_ret], repr(ret), '<-|', stmt, level=allow_recursion)
             return ret, should_ret
@@ -226,7 +233,7 @@ def _regex_flags(cls, expr):
 
     @staticmethod
     def _separate(expr, delim=',', max_split=None):
-        OP_CHARS = '+-*/%&|^=<>!,;{}()[]:'
+        OP_CHARS = '+-*/%&|^=<>!,;{}:'
         if not expr:
             return
         counters = {k: 0 for k in _MATCHING_PARENS.values()}
@@ -504,7 +511,7 @@ def dict_item(key, val):
                 (?P<op>{"|".join(map(re.escape, set(_OPERATORS) - _COMP_OPERATORS))})?
                 =(?!=)(?P<expr>.*)$
             )|(?P<return>
-                (?!if|return|true|false|null|undefined)(?P<name>{_NAME_RE})$
+                (?!if|return|true|false|null|undefined|NaN)(?P<name>{_NAME_RE})$
             )|(?P<indexing>
                 (?P<in>{_NAME_RE})\[(?P<idx>.+)\]$
             )|(?P<attribute>
@@ -539,6 +546,8 @@ def dict_item(key, val):
             raise JS_Continue()
         elif expr == 'undefined':
             return JS_Undefined, should_return
+        elif expr == 'NaN':
+            return float('NaN'), should_return
 
         elif m and m.group('return'):
             return local_vars.get(m.group('name'), JS_Undefined), should_return
@@ -784,7 +793,7 @@ def resf(args, kwargs={}, allow_recursion=100):
             global_stack[0].update(itertools.zip_longest(argnames, args, fillvalue=None))
             global_stack[0].update(kwargs)
             var_stack = LocalNameSpace(*global_stack)
-            ret, should_abort = self.interpret_statement(code.replace('\n', ''), var_stack, allow_recursion - 1)
+            ret, should_abort = self.interpret_statement(code.replace('\n', ' '), var_stack, allow_recursion - 1)
             if should_abort:
                 return ret
         return resf