def get_player_config(scripts):
config_strings = [
- ("ytplayer.config = {", 1, "};", 1),
("ytcfg.set({\"", 2, "});", 1),
+ ("ytInitialPlayerResponse = {\"", 2, "};", 1),
]
player_config = {}
for script in scripts:
func_name = match.groups()[0]
return func_name
-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 construct_url_from_cipher_result(cipher_result):
+ for k, v in cipher_result.items():
+ if isinstance(v, str) and v.startswith("https://"):
+ temp_url = v
+ break
+ else:
+ raise Exception("Could not find URL-like string in cipher result!")
+
+ for k, v in cipher_result.items():
+ if isinstance(v, dict):
+ params = {}
+ for k2, v2 in v.items():
+ params[k2] = urllib.parse.unquote(v2)
+ return append_to_qs(temp_url, params)
+ else:
+ raise Exception("Could not find params-like structure in cipher result!")
def decode_cipher_url(js_url, cipher):
cipher = urllib.parse.parse_qs(cipher)
f.close()
cipher_func_name = find_cipher_func(script)
- url_func_name = find_url_func(script)
params = {
"cipher_func_name": cipher_func_name,
- "url_func_name": url_func_name,
"args": json.dumps(args),
"code": json.dumps(extract_js(script)),
}
};
fakeGlobal.XMLHttpRequest = class XMLHttpRequest {};
fakeGlobal.matchMedia = () => ({matches: () => {}, media: ''});
- fakeGlobal.result_url = null;
+ fakeGlobal.result = null;
fakeGlobal.g = function(){}; // this is _yt_player
fakeGlobal.TimeRanges = function(){};
const code_string = %(code)s + ';';
- const exec_string = 'result_url = %(url_func_name)s(%(cipher_func_name)s(...%(args)s));';
+ const exec_string = 'result = %(cipher_func_name)s(...%(args)s);';
vm.runInNewContext(code_string + exec_string, fakeGlobal);
- console.log(fakeGlobal.result_url);
+ console.log(JSON.stringify(fakeGlobal.result));
""" % params)
p.stdin.write(js_decode_script.encode("utf-8"))
p.stdin.close()
- result_url = p.stdout.read().decode("utf-8").strip()
+ result = json.load(p.stdout)
if p.wait() != 0:
raise Exception("js failed to execute: %d" % p.returncode)
+ result_url = construct_url_from_cipher_result(result)
return result_url
def get_best_video(player_config):
- player_args = player_config["args"]
- player_response = json.loads(player_args["player_response"])
- formats = player_response["streamingData"]["formats"]
+ formats = player_config["streamingData"]["formats"]
best_url = None
best_quality = None
if not video_url:
return None, None
- title = player_config["args"].get("title", None)
- if not title:
- title = json.loads(player_config["args"]["player_response"])["videoDetails"]["title"]
+ title = player_config["videoDetails"].get("title", None)
if not title:
title = "Unknown title"