mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-11-21 20:46:36 -05:00
parent
5da42f2b9b
commit
a1c5bd82ec
2 changed files with 26 additions and 15 deletions
|
@ -4,7 +4,7 @@
|
||||||
import operator
|
import operator
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from .utils import ExtractorError, remove_quotes
|
from .utils import ExtractorError, remove_quotes, truncate_string
|
||||||
|
|
||||||
_NAME_RE = r'[a-zA-Z_$][\w$]*'
|
_NAME_RE = r'[a-zA-Z_$][\w$]*'
|
||||||
_OPERATORS = {
|
_OPERATORS = {
|
||||||
|
@ -53,6 +53,12 @@ def __init__(self, code, objects=None):
|
||||||
self.code, self._functions = code, {}
|
self.code, self._functions = code, {}
|
||||||
self._objects = {} if objects is None else objects
|
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):
|
def _named_object(self, namespace, obj):
|
||||||
self.__named_object_counter += 1
|
self.__named_object_counter += 1
|
||||||
name = f'__yt_dlp_jsinterp_obj{self.__named_object_counter}'
|
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):
|
def _separate_at_paren(cls, expr, delim):
|
||||||
separated = list(cls._separate(expr, delim, 1))
|
separated = list(cls._separate(expr, delim, 1))
|
||||||
if len(separated) < 2:
|
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()
|
return separated[0][1:].strip(), separated[1].strip()
|
||||||
|
|
||||||
def interpret_statement(self, stmt, local_vars, allow_recursion=100):
|
def interpret_statement(self, stmt, local_vars, allow_recursion=100):
|
||||||
if allow_recursion < 0:
|
if allow_recursion < 0:
|
||||||
raise ExtractorError('Recursion limit reached')
|
raise self.Exception('Recursion limit reached')
|
||||||
|
|
||||||
should_abort = False
|
should_abort = False
|
||||||
sub_statements = list(self._separate(stmt, ';')) or ['']
|
sub_statements = list(self._separate(stmt, ';')) or ['']
|
||||||
|
@ -177,8 +183,7 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
|
||||||
body, expr = remaining, ''
|
body, expr = remaining, ''
|
||||||
start, cndn, increment = self._separate(constructor, ';')
|
start, cndn, increment = self._separate(constructor, ';')
|
||||||
if self.interpret_statement(start, local_vars, allow_recursion - 1)[1]:
|
if self.interpret_statement(start, local_vars, allow_recursion - 1)[1]:
|
||||||
raise ExtractorError(
|
raise self.Exception('Premature return in the initialization of a for loop', constructor)
|
||||||
f'Premature return in the initialization of a for loop in {constructor!r}')
|
|
||||||
while True:
|
while True:
|
||||||
if not self.interpret_expression(cndn, local_vars, allow_recursion):
|
if not self.interpret_expression(cndn, local_vars, allow_recursion):
|
||||||
break
|
break
|
||||||
|
@ -191,8 +196,7 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
|
||||||
except JS_Continue:
|
except JS_Continue:
|
||||||
pass
|
pass
|
||||||
if self.interpret_statement(increment, local_vars, allow_recursion - 1)[1]:
|
if self.interpret_statement(increment, local_vars, allow_recursion - 1)[1]:
|
||||||
raise ExtractorError(
|
raise self.Exception('Premature return in the initialization of a for loop', constructor)
|
||||||
f'Premature return in the initialization of a for loop in {constructor!r}')
|
|
||||||
return self.interpret_statement(expr, local_vars, allow_recursion - 1)[0]
|
return self.interpret_statement(expr, local_vars, allow_recursion - 1)[0]
|
||||||
|
|
||||||
elif m and m.group('switch'):
|
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)
|
local_vars[m.group('out')] = opfunc(left_val, right_val)
|
||||||
return local_vars[m.group('out')]
|
return local_vars[m.group('out')]
|
||||||
elif left_val is None:
|
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)
|
idx = self.interpret_expression(m.group('index'), local_vars, allow_recursion)
|
||||||
if not isinstance(idx, int):
|
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)
|
left_val[idx] = opfunc(left_val[idx], right_val)
|
||||||
return left_val[idx]
|
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, should_abort = self.interpret_statement(
|
||||||
left_val, local_vars, allow_recursion - 1)
|
left_val, local_vars, allow_recursion - 1)
|
||||||
if should_abort:
|
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, should_abort = self.interpret_statement(
|
||||||
right_val, local_vars, allow_recursion - 1)
|
right_val, local_vars, allow_recursion - 1)
|
||||||
if should_abort:
|
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)
|
return opfunc(left_val or 0, right_val)
|
||||||
|
|
||||||
if m and m.group('attribute'):
|
if m and m.group('attribute'):
|
||||||
|
@ -322,7 +326,7 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
|
||||||
def assertion(cndn, msg):
|
def assertion(cndn, msg):
|
||||||
""" assert, but without risk of getting optimized out """
|
""" assert, but without risk of getting optimized out """
|
||||||
if not cndn:
|
if not cndn:
|
||||||
raise ExtractorError(f'{member} {msg}: {expr}')
|
raise self.Exception(f'{member} {msg}', expr)
|
||||||
|
|
||||||
def eval_method():
|
def eval_method():
|
||||||
if variable == 'String':
|
if variable == 'String':
|
||||||
|
@ -349,7 +353,7 @@ def eval_method():
|
||||||
if member == 'fromCharCode':
|
if member == 'fromCharCode':
|
||||||
assertion(argvals, 'takes one or more arguments')
|
assertion(argvals, 'takes one or more arguments')
|
||||||
return ''.join(map(chr, argvals))
|
return ''.join(map(chr, argvals))
|
||||||
raise ExtractorError(f'Unsupported string method {member}')
|
raise self.Exception(f'Unsupported string method {member}', expr)
|
||||||
|
|
||||||
if member == 'split':
|
if member == 'split':
|
||||||
assertion(argvals, 'takes one or more arguments')
|
assertion(argvals, 'takes one or more arguments')
|
||||||
|
@ -430,7 +434,7 @@ def eval_method():
|
||||||
self._functions[fname] = self.extract_function(fname)
|
self._functions[fname] = self.extract_function(fname)
|
||||||
return self._functions[fname](argvals)
|
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):
|
def extract_object(self, objname):
|
||||||
_FUNC_NAME_RE = r'''(?:[a-zA-Z$0-9]+|"[a-zA-Z$0-9]+"|'[a-zA-Z$0-9]+')'''
|
_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)
|
self.code)
|
||||||
code, _ = self._separate_at_paren(func_m.group('code'), '}') # refine the match
|
code, _ = self._separate_at_paren(func_m.group('code'), '}') # refine the match
|
||||||
if func_m is None:
|
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
|
return func_m.group('args').split(','), code
|
||||||
|
|
||||||
def extract_function(self, funcname):
|
def extract_function(self, funcname):
|
||||||
|
|
|
@ -5759,6 +5759,13 @@ def make_archive_id(ie, video_id):
|
||||||
return f'{ie_key.lower()} {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
|
# Deprecated
|
||||||
has_certifi = bool(certifi)
|
has_certifi = bool(certifi)
|
||||||
has_websockets = bool(websockets)
|
has_websockets = bool(websockets)
|
||||||
|
|
Loading…
Reference in a new issue