]>
Raphaƫl G. Git Repositories - youtubedl/blob - youtube_dl/jsinterp.py
1 from __future__
import unicode_literals
10 class JSInterpreter(object):
11 def __init__(self
, code
):
15 def interpret_statement(self
, stmt
, local_vars
, allow_recursion
=20):
16 if allow_recursion
< 0:
17 raise ExtractorError('Recursion limit reached')
19 if stmt
.startswith('var '):
20 stmt
= stmt
[len('var '):]
21 ass_m
= re
.match(r
'^(?P<out>[a-z]+)(?:\[(?P<index>[^\]]+)\])?' +
22 r
'=(?P<expr>.*)$', stmt
)
24 if ass_m
.groupdict().get('index'):
26 lvar
= local_vars
[ass_m
.group('out')]
27 idx
= self
.interpret_expression(
28 ass_m
.group('index'), local_vars
, allow_recursion
)
29 assert isinstance(idx
, int)
32 expr
= ass_m
.group('expr')
35 local_vars
[ass_m
.group('out')] = val
37 expr
= ass_m
.group('expr')
38 elif stmt
.startswith('return '):
40 expr
= stmt
[len('return '):]
43 'Cannot determine left side of statement in %r' % stmt
)
45 v
= self
.interpret_expression(expr
, local_vars
, allow_recursion
)
48 def interpret_expression(self
, expr
, local_vars
, allow_recursion
):
53 return local_vars
[expr
]
55 m
= re
.match(r
'^(?P<in>[a-z]+)\.(?P<member>.*)$', expr
)
57 member
= m
.group('member')
58 val
= local_vars
[m
.group('in')]
59 if member
== 'split("")':
61 if member
== 'join("")':
63 if member
== 'length':
65 if member
== 'reverse()':
67 slice_m
= re
.match(r
'slice\((?P<idx>.*)\)', member
)
69 idx
= self
.interpret_expression(
70 slice_m
.group('idx'), local_vars
, allow_recursion
- 1)
74 r
'^(?P<in>[a-z]+)\[(?P<idx>.+)\]$', expr
)
76 val
= local_vars
[m
.group('in')]
77 idx
= self
.interpret_expression(
78 m
.group('idx'), local_vars
, allow_recursion
- 1)
81 m
= re
.match(r
'^(?P<a>.+?)(?P<op>[%])(?P<b>.+?)$', expr
)
83 a
= self
.interpret_expression(
84 m
.group('a'), local_vars
, allow_recursion
)
85 b
= self
.interpret_expression(
86 m
.group('b'), local_vars
, allow_recursion
)
90 r
'^(?P<func>[a-zA-Z$]+)\((?P<args>[a-z0-9,]+)\)$', expr
)
92 fname
= m
.group('func')
93 if fname
not in self
._functions
:
94 self
._functions
[fname
] = self
.extract_function(fname
)
95 argvals
= [int(v
) if v
.isdigit() else local_vars
[v
]
96 for v
in m
.group('args').split(',')]
97 return self
._functions
[fname
](argvals
)
98 raise ExtractorError('Unsupported JS expression %r' % expr
)
100 def extract_function(self
, funcname
):
102 (r
'(?:function %s|%s\s*=\s*function)' % (
103 re
.escape(funcname
), re
.escape(funcname
))) +
104 r
'\((?P<args>[a-z,]+)\){(?P<code>[^}]+)}',
107 raise ExtractorError('Could not find JS function %r' % funcname
)
108 argnames
= func_m
.group('args').split(',')
111 local_vars
= dict(zip(argnames
, args
))
112 for stmt
in func_m
.group('code').split(';'):
113 res
= self
.interpret_statement(stmt
, local_vars
)