From 0bb07e55f5a59b5ccb7c5392faaf523abd71ae4b Mon Sep 17 00:00:00 2001 From: Omar Roth Date: Tue, 17 Jul 2018 10:53:17 -0500 Subject: [PATCH] Add ability to automatically extract video signature funtion --- src/invidious.cr | 25 ++++++++++++----- src/invidious/helpers.cr | 58 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/src/invidious.cr b/src/invidious.cr index 618386ea..0e135af7 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -173,7 +173,6 @@ video_threads.times do |i| end top_videos = [] of Video - spawn do if CONFIG.dl_api_key DetectLanguage.configure do |config| @@ -213,6 +212,20 @@ spawn do end end +# Refresh decrypt function +decrypt_function = [] of {name: String, value: Int32} +spawn do + loop do + begin + client = make_client(YT_URL) + decrypt_function = update_decrypt_function(client) + rescue ex + end + + Fiber.yield + end +end + before_all do |env| if env.request.cookies.has_key? "SID" headers = HTTP::Headers.new @@ -296,11 +309,11 @@ get "/watch" do |env| if adaptive_fmts[0]? && adaptive_fmts[0]["s"]? adaptive_fmts.each do |fmt| - fmt["url"] += "&signature=" + decrypt_signature(fmt["s"]) + fmt["url"] += "&signature=" + decrypt_signature(fmt["s"], decrypt_function) end fmt_stream.each do |fmt| - fmt["url"] += "&signature=" + decrypt_signature(fmt["s"]) + fmt["url"] += "&signature=" + decrypt_signature(fmt["s"], decrypt_function) end end @@ -433,11 +446,11 @@ get "/embed/:id" do |env| if adaptive_fmts[0]? && adaptive_fmts[0]["s"]? adaptive_fmts.each do |fmt| - fmt["url"] += "&signature=" + decrypt_signature(fmt["s"]) + fmt["url"] += "&signature=" + decrypt_signature(fmt["s"], decrypt_function) end fmt_stream.each do |fmt| - fmt["url"] += "&signature=" + decrypt_signature(fmt["s"]) + fmt["url"] += "&signature=" + decrypt_signature(fmt["s"], decrypt_function) end end @@ -1044,7 +1057,7 @@ get "/api/manifest/dash/id/:id" do |env| if adaptive_fmts[0]? && adaptive_fmts[0]["s"]? adaptive_fmts.each do |fmt| - fmt["url"] += "&signature=" + decrypt_signature(fmt["s"]) + fmt["url"] += "&signature=" + decrypt_signature(fmt["s"], decrypt_function) end end diff --git a/src/invidious/helpers.cr b/src/invidious/helpers.cr index 692c1d29..923b6d1c 100644 --- a/src/invidious/helpers.cr +++ b/src/invidious/helpers.cr @@ -324,16 +324,66 @@ def splice(a, b) return a end -def decrypt_signature(a) +def decrypt_signature(a, code) a = a.split("") - a.reverse! - a.delete_at(0..0) - a = splice(a, 11) + code.each do |item| + case item[:name] + when "a" + a.reverse! + when "b" + a.delete_at(0..(item[:value] - 1)) + when "c" + a = splice(a, item[:value]) + end + end return a.join("") end +def update_decrypt_function(client) + # Video with signature + document = client.get("/watch?v=CvFH_6DNRCY").body + url = document.match(/src="(?\/yts\/jsbin\/player-.{9}\/en_US\/base.js)"/).not_nil!["url"] + player = client.get(url).body + + function_name = player.match(/\(b\|\|\(b="signature"\),d.set\(b,(?[a-zA-Z]{2})\(c\)\)\)/).not_nil!["name"] + function_body = player.match(/#{function_name}=function\(a\){(?[^}]+)}/).not_nil!["body"] + function_body = function_body.split(";")[1..-2] + + var_name = function_body[0][0, 2] + + operations = {} of String => String + matches = player.delete("\n").match(/var #{var_name}={((?[a-zA-Z]{2}:[^}]+})),((?[a-zA-Z]{2}:[^}]+})),((?[a-zA-Z]{2}:[^}]+}))};/).not_nil! + 3.times do |i| + operation = matches["op#{i + 1}"] + op_name = operation[0, 2] + + op_body = operation.match(/\{[^}]+\}/).not_nil![0] + case op_body + when "{a.reverse()}" + operations[op_name] = "a" + when "{a.splice(0,b)}" + operations[op_name] = "b" + else + operations[op_name] = "c" + end + end + + decrypt_function = [] of {name: String, value: Int32} + function_body.each do |function| + function = function.lchop(var_name + ".") + op_name = function[0, 2] + + function = function.lchop(op_name + "(a,") + value = function.rchop(")").to_i + + decrypt_function << {name: operations[op_name], value: value} + end + + return decrypt_function +end + def rank_videos(db, n, filter, url) top = [] of {Float64, String}