]> jfr.im git - yt-dlp.git/commitdiff
[jsinterp] Truncate error messages
authorpukkandan <redacted>
Fri, 12 Aug 2022 13:23:53 +0000 (18:53 +0530)
committerpukkandan <redacted>
Fri, 12 Aug 2022 13:45:16 +0000 (19:15 +0530)
Related: #4635

yt_dlp/jsinterp.py
yt_dlp/utils.py

index c95a0ff57b9904e8b833bc2906c1a432bc852350..e85371574c804d711f9cf46a00ef005d5939dde2 100644 (file)
@@ -4,7 +4,7 @@
 import operator
 import re
 
-from .utils import ExtractorError, remove_quotes
+from .utils import ExtractorError, remove_quotes, truncate_string
 
 _NAME_RE = r'[a-zA-Z_$][\w$]*'
 _OPERATORS = {
@@ -53,6 +53,12 @@ def __init__(self, code, objects=None):
         self.code, self._functions = code, {}
         self._objects = {} if objects is None else objects
 
+    class Exception(ExtractorError):
+        def __init__(self, msg, expr=None, *args, **kwargs):
+            if expr is not None:
+                msg += f' in: {truncate_string(expr, 50, 50)}'
+            super().__init__(msg, *args, **kwargs)
+
     def _named_object(self, namespace, obj):
         self.__named_object_counter += 1
         name = f'__yt_dlp_jsinterp_obj{self.__named_object_counter}'
@@ -92,12 +98,12 @@ def _separate(expr, delim=',', max_split=None):
     def _separate_at_paren(cls, expr, delim):
         separated = list(cls._separate(expr, delim, 1))
         if len(separated) < 2:
-            raise ExtractorError(f'No terminating paren {delim} in {expr}')
+            raise cls.Exception(f'No terminating paren {delim}', expr)
         return separated[0][1:].strip(), separated[1].strip()
 
     def interpret_statement(self, stmt, local_vars, allow_recursion=100):
         if allow_recursion < 0:
-            raise ExtractorError('Recursion limit reached')
+            raise self.Exception('Recursion limit reached')
 
         should_abort = False
         sub_statements = list(self._separate(stmt, ';')) or ['']
@@ -177,8 +183,7 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
                     body, expr = remaining, ''
             start, cndn, increment = self._separate(constructor, ';')
             if self.interpret_statement(start, local_vars, allow_recursion - 1)[1]:
-                raise ExtractorError(
-                    f'Premature return in the initialization of a for loop in {constructor!r}')
+                raise self.Exception('Premature return in the initialization of a for loop', constructor)
             while True:
                 if not self.interpret_expression(cndn, local_vars, allow_recursion):
                     break
@@ -191,8 +196,7 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
                 except JS_Continue:
                     pass
                 if self.interpret_statement(increment, local_vars, allow_recursion - 1)[1]:
-                    raise ExtractorError(
-                        f'Premature return in the initialization of a for loop in {constructor!r}')
+                    raise self.Exception('Premature return in the initialization of a for loop', constructor)
             return self.interpret_statement(expr, local_vars, allow_recursion - 1)[0]
 
         elif m and m.group('switch'):
@@ -267,11 +271,11 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
                 local_vars[m.group('out')] = opfunc(left_val, right_val)
                 return local_vars[m.group('out')]
             elif left_val is None:
-                raise ExtractorError(f'Cannot index undefined variable: {m.group("out")}')
+                raise self.Exception(f'Cannot index undefined variable {m.group("out")}', expr)
 
             idx = self.interpret_expression(m.group('index'), local_vars, allow_recursion)
             if not isinstance(idx, int):
-                raise ExtractorError(f'List indices must be integers: {idx}')
+                raise self.Exception(f'List index {idx} must be integer', expr)
             left_val[idx] = opfunc(left_val[idx], right_val)
             return left_val[idx]
 
@@ -303,11 +307,11 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
             left_val, should_abort = self.interpret_statement(
                 left_val, local_vars, allow_recursion - 1)
             if should_abort:
-                raise ExtractorError(f'Premature left-side return of {op} in {expr!r}')
+                raise self.Exception(f'Premature left-side return of {op}', expr)
             right_val, should_abort = self.interpret_statement(
                 right_val, local_vars, allow_recursion - 1)
             if should_abort:
-                raise ExtractorError(f'Premature right-side return of {op} in {expr!r}')
+                raise self.Exception(f'Premature right-side return of {op}', expr)
             return opfunc(left_val or 0, right_val)
 
         if m and m.group('attribute'):
@@ -322,7 +326,7 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
             def assertion(cndn, msg):
                 """ assert, but without risk of getting optimized out """
                 if not cndn:
-                    raise ExtractorError(f'{member} {msg}: {expr}')
+                    raise self.Exception(f'{member} {msg}', expr)
 
             def eval_method():
                 if variable == 'String':
@@ -349,7 +353,7 @@ def eval_method():
                     if member == 'fromCharCode':
                         assertion(argvals, 'takes one or more arguments')
                         return ''.join(map(chr, argvals))
-                    raise ExtractorError(f'Unsupported string method {member}')
+                    raise self.Exception(f'Unsupported string method {member}', expr)
 
                 if member == 'split':
                     assertion(argvals, 'takes one or more arguments')
@@ -430,7 +434,7 @@ def eval_method():
                 self._functions[fname] = self.extract_function(fname)
             return self._functions[fname](argvals)
 
-        raise ExtractorError(f'Unsupported JS expression {expr!r}')
+        raise self.Exception('Unsupported JS expression', expr)
 
     def extract_object(self, objname):
         _FUNC_NAME_RE = r'''(?:[a-zA-Z$0-9]+|"[a-zA-Z$0-9]+"|'[a-zA-Z$0-9]+')'''
@@ -469,7 +473,7 @@ def extract_function_code(self, funcname):
             self.code)
         code, _ = self._separate_at_paren(func_m.group('code'), '}')  # refine the match
         if func_m is None:
-            raise ExtractorError(f'Could not find JS function "{funcname}"')
+            raise self.Exception(f'Could not find JS function "{funcname}"')
         return func_m.group('args').split(','), code
 
     def extract_function(self, funcname):
index 3a33cad2e77533125357ec3ba190301967eedb7c..17d6e733519a27b5fcf44b8729fd08a4c5ef2c36 100644 (file)
@@ -5759,6 +5759,13 @@ def make_archive_id(ie, video_id):
     return f'{ie_key.lower()} {video_id}'
 
 
+def truncate_string(s, left, right=0):
+    assert left > 3 and right >= 0
+    if s is None or len(s) <= left + right:
+        return s
+    return f'{s[:left-3]}...{s[-right:]}'
+
+
 # Deprecated
 has_certifi = bool(certifi)
 has_websockets = bool(websockets)