]> code.delx.au - youtube-cgi/blobdiff - youtube.cgi
fixes to work with recent changes
[youtube-cgi] / youtube.cgi
index fc10e08eeb21a4f5c6fbf37e3b1fc8ae51bb1de5..dfd5d28ad885d2a5bcd6b3626a901080fbac02a1 100755 (executable)
@@ -84,9 +84,10 @@ def urlopen(url, offset=None):
 
     global referrer
     req = urllib2.Request(url)
-    if referrer:
+    if not referrer:
+        referrer = url
+    else:
         req.add_header("Referer", referrer)
-    referrer = url
 
     req.add_header("User-Agent", USER_AGENT)
 
@@ -130,41 +131,75 @@ def get_player_config(doc):
                 if p1 >= 0 and p2 > 0:
                     return json.loads(line[p1:p2])
 
-def extract_function(output, script, func_name):
-    p1 = script.find("function " + func_name + "(")
-    p2 = script.find("}", p1)
-    code = script[p1:p2+1]
-    output.append(code)
-    deps = re.findall(R"[^\.][= ]([\$0-9a-zA-Z]+)\(", code)
-    deps = set(deps)
-    deps.remove(func_name)
-    for dep in deps:
-        extract_function(output, script, dep)
-
-def decode_signature(js_url, s):
-    script = urlopen(js_url).read()
-    func_name = re.search(R"\b([a-zA-Z]+)\([a-zA-Z]+\.s\);", script).groups()[0]
+def extract_js(script):
+    PREFIX = "var _yt_player={};(function(g){var window=this;"
+    SUFFIX = ";})(_yt_player);\n"
+    assert script.startswith(PREFIX)
+    assert script.endswith(SUFFIX)
+
+    return script[len(PREFIX):-len(SUFFIX)]
 
-    codes = []
-    extract_function(codes, script, func_name)
+def find_func_name(script):
+    FUNC_NAME = R"([a-zA-Z0-9$]+)"
+    FUNC_PARAMS = R"(\([a-zA-Z]+\.s\))"
+    PATTERN = FUNC_NAME + FUNC_PARAMS + ";"
+
+    match = re.search(PATTERN, script)
+    func_name = match.groups()[0]
+    return func_name
+
+def decode_signature(js_url, signature):
+    script = urlopen(js_url).read()
+    func_name = find_func_name(script)
 
+    params = {
+        "func_name": func_name,
+        "signature": json.dumps(signature),
+        "code": json.dumps(extract_js(script)),
+    }
     p = subprocess.Popen(
-        "js",
+        "nodejs",
         shell=True,
         close_fds=True,
         stdin=subprocess.PIPE,
         stdout=subprocess.PIPE
     )
-    for code in codes:
-        p.stdin.write(code + "\n")
-    p.stdin.write("console.log(%s('%s'));\n" % (func_name, s))
+    js_decode_script = ("""
+        var vm = require('vm');
+
+        var sandbox = {
+            location: {
+                hash: '',
+                href: '',
+                protocol: 'http:'
+            },
+            history: {
+                pushState: function(){}
+            },
+            document: {},
+            navigator: {
+                userAgent: ''
+            },
+            signature: %(signature)s,
+            transformed_signature: null
+        };
+        sandbox.window = sandbox;
+
+        var code_string = %(code)s + ';';
+        var exec_string = 'transformed_signature = %(func_name)s(signature);';
+        vm.runInNewContext(code_string + exec_string, sandbox);
+
+        console.log(sandbox.transformed_signature);
+    """ % params)
+
+    p.stdin.write(js_decode_script)
     p.stdin.close()
 
-    signature = p.stdout.read().strip()
+    transformed_signature = p.stdout.read().strip()
     if p.wait() != 0:
         raise Exception("js failed to execute: %d" % p.returncode)
 
-    return signature
+    return transformed_signature
 
 def get_best_video(player_config):
     url_data_list = player_config["args"]["url_encoded_fmt_stream_map"].split(",")