From 03c05f9c858e46d6caa63d4ca465375e153494ca Mon Sep 17 00:00:00 2001 From: James Bunton Date: Sat, 15 Aug 2020 23:16:25 +1000 Subject: [PATCH] Fix for Google changes --- youtube.cgi | 90 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 38 deletions(-) diff --git a/youtube.cgi b/youtube.cgi index c88ad8e..33bb29a 100755 --- a/youtube.cgi +++ b/youtube.cgi @@ -148,7 +148,7 @@ def extract_js(script): return script[len(PREFIX):-len(SUFFIX)] -def find_func_name(script): +def find_cipher_func(script): FUNC_NAME = R"([a-zA-Z0-9$]+)" DECODE_URI_COMPONENT = R"(\(decodeURIComponent)?" FUNC_PARAMS = R"(\([a-zA-Z,\.]+\.s\))" @@ -159,16 +159,33 @@ def find_func_name(script): func_name = match.groups()[0] return func_name -def decode_signature(js_url, signature): +def find_url_func(script): + FUNC_NAME = R"([a-zA-Z0-9$]+)" + PATTERN = R"this\.url\s*=\s*" + FUNC_NAME + R"\s*\(\s*this\s*\)" + + match = re.search(PATTERN, script) + func_name = match.groups()[0] + return func_name + +def decode_cipher_url(js_url, cipher): + cipher = urllib.parse.parse_qs(cipher) + args = [ + cipher["url"][0], + cipher["sp"][0], + cipher["s"][0], + ] + f = urlopen(js_url) script = f.read().decode("utf-8") f.close() - func_name = find_func_name(script) + cipher_func_name = find_cipher_func(script) + url_func_name = find_url_func(script) params = { - "func_name": func_name, - "signature": json.dumps(signature), + "cipher_func_name": cipher_func_name, + "url_func_name": url_func_name, + "args": json.dumps(args), "code": json.dumps(extract_js(script)), } p = subprocess.Popen( @@ -181,43 +198,47 @@ def decode_signature(js_url, signature): js_decode_script = (""" const vm = require('vm'); - const sandbox = { - location: { - hash: '', - href: '', - protocol: 'http:' - }, - history: { - pushState: function(){} - }, - document: {}, - navigator: { - userAgent: '' - }, - XMLHttpRequest: class XMLHttpRequest {}, - matchMedia: () => ({matches: () => {}, media: ''}), - signature: %(signature)s, - transformed_signature: null, - g: function(){} // this is _yt_player + const fakeGlobal = {}; + fakeGlobal.window = fakeGlobal; + fakeGlobal.location = { + hash: '', + host: 'www.youtube.com', + hostname: 'www.youtube.com', + href: 'https://www.youtube.com', + origin: 'https://www.youtube.com', + pathname: '/', + protocol: 'https:' + }; + fakeGlobal.history = { + pushState: function(){} + }; + fakeGlobal.document = { + location: fakeGlobal.location + }; + fakeGlobal.document = {}; + fakeGlobal.navigator = { + userAgent: '' }; - sandbox.window = sandbox; + fakeGlobal.XMLHttpRequest = class XMLHttpRequest {}; + fakeGlobal.matchMedia = () => ({matches: () => {}, media: ''}); + fakeGlobal.result_url = null; + fakeGlobal.g = function(){}; // this is _yt_player const code_string = %(code)s + ';'; - const exec_string = 'transformed_signature = %(func_name)s(signature);'; - vm.runInNewContext(code_string + exec_string, sandbox); + const exec_string = 'result_url = %(url_func_name)s(%(cipher_func_name)s(...%(args)s));'; + vm.runInNewContext(code_string + exec_string, fakeGlobal); - console.log(sandbox.transformed_signature); + console.log(fakeGlobal.result_url); """ % params) p.stdin.write(js_decode_script.encode("utf-8")) p.stdin.close() - transformed_signature = p.stdout.read().decode("utf-8").strip() - transformed_signature = urllib.parse.unquote(transformed_signature) + result_url = p.stdout.read().decode("utf-8").strip() if p.wait() != 0: raise Exception("js failed to execute: %d" % p.returncode) - return transformed_signature + return result_url def get_best_video(player_config): js_url = player_config["assets"]["js"] @@ -245,14 +266,7 @@ def get_best_video(player_config): continue if "signatureCipher" in format_data: - cipher = urllib.parse.parse_qs(format_data["signatureCipher"]) - video_url = cipher["url"][0] - if "sig" in cipher: - signature = cipher["sig"][0] - elif "s" in cipher: - signature = decode_signature(js_url, cipher["s"][0]) - sp = cipher.get("sp", ["signature"])[0] - video_url = append_to_qs(video_url, {sp: signature}) + video_url = decode_cipher_url(js_url, format_data["signatureCipher"]) else: video_url = format_data["url"] -- 2.39.2