decrypt n

This commit is contained in:
putara 2021-06-28 00:00:14 +12:00
parent 67a18dcff6
commit a533888830
4 changed files with 46 additions and 0 deletions

View File

@ -4,6 +4,10 @@ shards:
git: https://github.com/crystal-lang/crystal-db.git
version: 0.10.1
duktape:
git: https://github.com/jessedoyle/duktape.cr.git
version: 1.0.0
exception_page:
git: https://github.com/crystal-loot/exception_page.git
version: 0.1.5

View File

@ -25,6 +25,9 @@ dependencies:
lsquic:
github: iv-org/lsquic.cr
version: ~> 2.18.1-2
duktape:
github: jessedoyle/duktape.cr
version: ~> 1.0.0
crystal: 1.0.0

View File

@ -1,9 +1,14 @@
require "duktape/runtime"
alias SigProc = Proc(Array(String), Int32, Array(String))
struct DecryptFunction
@decrypt_function = [] of {SigProc, Int32}
@decrypt_time = Time.monotonic
@playerjs_decrypt_n_function = {} of String => String
@last_decrypted_n = {id: "", n: "", dec_n: ""}
def initialize(@use_polling = true)
end
@ -70,4 +75,36 @@ struct DecryptFunction
return "&#{sp}=#{sig.join("")}"
end
def overwrite_n(id : String, fmt : Hash(String, JSON::Any))
uri = URI.parse(fmt["url"].as_s)
params = HTTP::Params.parse(uri.query.not_nil!)
return fmt["url"].as_s unless params["n"]?
n = params["n"]
function_name = "(cache #1)"
if (@last_decrypted_n[:id] == id && @last_decrypted_n[:n] == n)
dec_n = @last_decrypted_n[:dec_n]
else
document = YT_POOL.client &.get("/watch?v=#{id}&gl=US&hl=en").body
playerjs = document.match(/src="(?<url>\/s\/player\/[^\/]+\/player_ias[^\/]+\/en_US\/base.js)"/).not_nil!["url"]
function_name = "(cache #2)"
function_body = @playerjs_decrypt_n_function[playerjs]?
if (!function_body)
player = YT_POOL.client &.get(playerjs).body
function_name = player.match(/a\.get\("n"\)\)&&\(b=(?<nfunc>[a-zA-Z0-9]+)\(b\)/m).not_nil!["nfunc"]
function_body = player.match(/^#{Regex.escape(function_name)}=(?<body>function\(\w\)\{.*?"enhanced_except_[^\}]+\}[^\}]+\})/m).not_nil!["body"]
@playerjs_decrypt_n_function[playerjs] = function_body
end
rt = Duktape::Runtime.new do |sbx|
sbx.eval! "var dec=#{function_body}"
end
dec_n = rt.call("dec", n).to_s
@last_decrypted_n = {id: id, n: n, dec_n: dec_n}
end
LOGGER.debug("decrypt_n: #{id} fn = #{function_name} n = #{n} -> #{dec_n}")
params["n"] = dec_n
return URI.new(uri.scheme, uri.host, uri.port, uri.path, params).to_s
end
end

View File

@ -586,6 +586,7 @@ struct Video
fmt["url"] = JSON::Any.new("#{fmt["url"]}#{DECRYPT_FUNCTION.decrypt_signature(fmt)}")
end
fmt["url"] = JSON::Any.new(DECRYPT_FUNCTION.overwrite_n(self.id, fmt))
fmt["url"] = JSON::Any.new("#{fmt["url"]}&host=#{URI.parse(fmt["url"].as_s).host}")
fmt["url"] = JSON::Any.new("#{fmt["url"]}&region=#{self.info["region"]}") if self.info["region"]?
end
@ -605,6 +606,7 @@ struct Video
fmt["url"] = JSON::Any.new("#{fmt["url"]}#{DECRYPT_FUNCTION.decrypt_signature(fmt)}")
end
fmt["url"] = JSON::Any.new(DECRYPT_FUNCTION.overwrite_n(self.id, fmt))
fmt["url"] = JSON::Any.new("#{fmt["url"]}&host=#{URI.parse(fmt["url"].as_s).host}")
fmt["url"] = JSON::Any.new("#{fmt["url"]}&region=#{self.info["region"]}") if self.info["region"]?
end