From: James Bunton Date: Fri, 2 Aug 2013 14:27:17 +0000 (+1000) Subject: support for decoding YouTube's new video signature stuff X-Git-Url: https://code.delx.au/youtube-cgi/commitdiff_plain/c8c1dd3e28a11753a9e49b6c377a0e332180b77d?ds=sidebyside support for decoding YouTube's new video signature stuff --- diff --git a/youtube.cgi b/youtube.cgi index 2d3fcee..263259c 100755 --- a/youtube.cgi +++ b/youtube.cgi @@ -145,18 +145,39 @@ def get_player_config(doc): convert_from_old_itag(player_config) return player_config +def decode_signature(js_url, s): + script = urlopen(js_url).read() + func_name = re.search(R"\b([a-z]+)\([a-z]+\.s\);", script).groups()[0] + p1 = script.find("function " + func_name) + p2 = script.find("}", p1) + func_block = script[p1:p2+1] + + p = subprocess.Popen( + ["js"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE + ) + p.stdin.write(func_block + "\n") + p.stdin.write("console.log(%s('%s'));\n" % (func_name, s)) + p.stdin.close() + + signature = p.stdout.read().strip() + if p.wait() != 0: + raise Exception("js failed to execute: %d" % p.returncode) + + return signature + def get_best_video(player_config): url_data_list = player_config["args"]["url_encoded_fmt_stream_map"].split(",") + js_url = player_config["assets"]["js"] best_url = None best_quality = None best_extension = None for url_data in url_data_list: url_data = urlparse.parse_qs(url_data) - video_url = url_data["url"][0] mimetype = url_data["type"][0].split(";")[0] quality = url_data["quality"][0] - signature = url_data["sig"][0] if quality not in QUALITIES: continue @@ -165,12 +186,20 @@ def get_best_video(player_config): extension = MIMETYPES[mimetype] quality = QUALITIES.get(quality, -1) + + if best_quality is not None and quality < best_quality: + continue + + video_url = url_data["url"][0] + if "sig" in url_data: + signature = url_data["sig"][0] + else: + signature = decode_signature(js_url, url_data["s"][0]) video_url = append_to_qs(video_url, {"signature": signature}) - if best_quality is None or quality > best_quality: - best_url = video_url - best_quality = quality - best_extension = extension + best_url = video_url + best_quality = quality + best_extension = extension return best_url, best_extension @@ -327,7 +356,7 @@ def main(): if __name__ == "__main__": - resource.setrlimit(resource.RLIMIT_AS, (MAX_MEMORY_BYTES, MAX_MEMORY_BYTES)) +### resource.setrlimit(resource.RLIMIT_AS, (MAX_MEMORY_BYTES, MAX_MEMORY_BYTES)) if os.environ.has_key("SCRIPT_NAME"): cgimain() else: