@ -11,6 +11,7 @@ from functools import update_wrapper, wraps
from . utils import (
error_to_compat_str ,
ExtractorError ,
float_or_none ,
js_to_json ,
remove_quotes ,
unified_timestamp ,
@ -81,35 +82,47 @@ def _js_bit_op(op):
return wrapped
def _js_arith_op ( op ):
def _js_arith_op ( op , div = False ):
@wraps_op ( op )
def wrapped ( a , b ) :
if JS_Undefined in ( a , b ) :
return _NaN
return op ( a or 0 , b or 0 )
# null, "" --> 0
a , b = ( float_or_none (
( x . strip ( ) if isinstance ( x , compat_basestring ) else x ) or 0 ,
default = _NaN ) for x in ( a , b ) )
if _NaN in ( a , b ) :
return _NaN
try :
return op ( a , b )
except ZeroDivisionError :
return _NaN if not ( div and ( a or b ) ) else _Infinity
return wrapped
def _js_div ( a , b ) :
if JS_Undefined in ( a , b ) or not ( a or b ) :
return _NaN
return operator . truediv ( a or 0 , b ) if b else _Infinity
_js_arith_add = _js_arith_op ( operator . add )
def _js_add ( a , b ) :
if not ( isinstance ( a , compat_basestring ) or isinstance ( b , compat_basestring ) ) :
return _js_arith_add ( a , b )
if not isinstance ( a , compat_basestring ) :
a = _js_toString ( a )
elif not isinstance ( b , compat_basestring ) :
b = _js_toString ( b )
return operator . concat ( a , b )
def _js_mod ( a , b ) :
if JS_Undefined in ( a , b ) or not b :
return _NaN
return ( a or 0 ) % b
_js_mod = _js_arith_op ( operator . mod )
__js_exp = _js_arith_op ( operator . pow )
def _js_exp ( a , b ) :
if not b :
return 1 # even 0 ** 0 !!
elif JS_Undefined in ( a , b ) :
return _NaN
return ( a or 0 ) * * b
return __js_exp ( a , b )
def _js_to_primitive ( v ) :
@ -117,7 +130,7 @@ def _js_to_primitive(v):
' , ' . join ( map ( _js_toString , v ) ) if isinstance ( v , list )
else ' [object Object] ' if isinstance ( v , dict )
else compat_str ( v ) if not isinstance ( v , (
compat_numeric_types , compat_basestring , bool ))
compat_numeric_types , compat_basestring ))
else v
)
@ -128,7 +141,9 @@ def _js_toString(v):
else ' Infinity ' if v == _Infinity
else ' NaN ' if v is _NaN
else ' null ' if v is None
else compat_str ( v ) if isinstance ( v , compat_numeric_types )
# bool <= int: do this first
else ( ' false ' , ' true ' ) [ v ] if isinstance ( v , bool )
else ' {0:.7f} ' . format ( v ) . rstrip ( ' .0 ' ) if isinstance ( v , compat_numeric_types )
else _js_to_primitive ( v ) )
@ -240,11 +255,11 @@ def _js_typeof(expr):
_OPERATORS = (
( ' >> ' , _js_bit_op ( operator . rshift ) ) ,
( ' << ' , _js_bit_op ( operator . lshift ) ) ,
( ' + ' , _js_a rith_op( operator . a dd) ) ,
( ' + ' , _js_a dd) ,
( ' - ' , _js_arith_op ( operator . sub ) ) ,
( ' * ' , _js_arith_op ( operator . mul ) ) ,
( ' % ' , _js_mod ) ,
( ' / ' , _js_ div) ,
( ' / ' , _js_ arith_op( operator . true div, div = True ) ) ,
( ' ** ' , _js_exp ) ,
)
@ -873,7 +888,7 @@ class JSInterpreter(object):
start , end = m . span ( )
sign = m . group ( ' pre_sign ' ) or m . group ( ' post_sign ' )
ret = local_vars [ var ]
local_vars [ var ] + = 1 if sign [ 0 ] == ' + ' else - 1
local_vars [ var ] = _js_add ( ret , 1 if sign [ 0 ] == ' + ' else - 1 )
if m . group ( ' pre_sign ' ) :
ret = local_vars [ var ]
expr = expr [ : start ] + self . _dump ( ret , local_vars ) + expr [ end : ]
@ -1023,7 +1038,7 @@ class JSInterpreter(object):
if obj is compat_str :
if member == ' fromCharCode ' :
assertion ( argvals , ' takes one or more arguments ' )
return ' ' . join ( map ( compat_chr , argvals ) )
return ' ' . join ( compat_chr ( int ( n ) ) for n in argvals )
raise self . Exception ( ' Unsupported string method ' + member , expr = expr )
elif obj is float :
if member == ' pow ' :