Videos: Convert URL before putting result into cache (#4850)

Closes issue 4837
This commit is contained in:
Samantaz Fox 2024-10-08 17:52:34 +02:00
commit 3cfcc16403
No known key found for this signature in database
GPG Key ID: F42821059186176E
2 changed files with 57 additions and 68 deletions

View File

@ -26,12 +26,6 @@ struct Video
@[DB::Field(ignore: true)] @[DB::Field(ignore: true)]
@captions = [] of Invidious::Videos::Captions::Metadata @captions = [] of Invidious::Videos::Captions::Metadata
@[DB::Field(ignore: true)]
property adaptive_fmts : Array(Hash(String, JSON::Any))?
@[DB::Field(ignore: true)]
property fmt_stream : Array(Hash(String, JSON::Any))?
@[DB::Field(ignore: true)] @[DB::Field(ignore: true)]
property description : String? property description : String?
@ -98,72 +92,24 @@ struct Video
# Methods for parsing streaming data # Methods for parsing streaming data
def convert_url(fmt) def fmt_stream : Array(Hash(String, JSON::Any))
if cfr = fmt["signatureCipher"]?.try { |json| HTTP::Params.parse(json.as_s) } if formats = info.dig?("streamingData", "formats")
sp = cfr["sp"] return formats
url = URI.parse(cfr["url"]) .as_a.map(&.as_h)
params = url.query_params .sort_by! { |f| f["width"]?.try &.as_i || 0 }
LOGGER.debug("Videos: Decoding '#{cfr}'")
unsig = DECRYPT_FUNCTION.try &.decrypt_signature(cfr["s"])
params[sp] = unsig if unsig
else else
url = URI.parse(fmt["url"].as_s) return [] of Hash(String, JSON::Any)
params = url.query_params end
end end
n = DECRYPT_FUNCTION.try &.decrypt_nsig(params["n"]) def adaptive_fmts : Array(Hash(String, JSON::Any))
params["n"] = n if n if formats = info.dig?("streamingData", "adaptiveFormats")
return formats
if token = CONFIG.po_token .as_a.map(&.as_h)
params["pot"] = token .sort_by! { |f| f["width"]?.try &.as_i || 0 }
else
return [] of Hash(String, JSON::Any)
end end
params["host"] = url.host.not_nil!
if region = self.info["region"]?.try &.as_s
params["region"] = region
end
url.query_params = params
LOGGER.trace("Videos: new url is '#{url}'")
return url.to_s
rescue ex
LOGGER.debug("Videos: Error when parsing video URL")
LOGGER.trace(ex.inspect_with_backtrace)
return ""
end
def fmt_stream
return @fmt_stream.as(Array(Hash(String, JSON::Any))) if @fmt_stream
fmt_stream = info.dig?("streamingData", "formats")
.try &.as_a.map &.as_h || [] of Hash(String, JSON::Any)
fmt_stream.each do |fmt|
fmt["url"] = JSON::Any.new(self.convert_url(fmt))
end
fmt_stream.sort_by! { |f| f["width"]?.try &.as_i || 0 }
@fmt_stream = fmt_stream
return @fmt_stream.as(Array(Hash(String, JSON::Any)))
end
def adaptive_fmts
return @adaptive_fmts.as(Array(Hash(String, JSON::Any))) if @adaptive_fmts
fmt_stream = info.dig("streamingData", "adaptiveFormats")
.try &.as_a.map &.as_h || [] of Hash(String, JSON::Any)
fmt_stream.each do |fmt|
fmt["url"] = JSON::Any.new(self.convert_url(fmt))
end
fmt_stream.sort_by! { |f| f["width"]?.try &.as_i || 0 }
@adaptive_fmts = fmt_stream
return @adaptive_fmts.as(Array(Hash(String, JSON::Any)))
end end
def video_streams def video_streams

View File

@ -142,10 +142,21 @@ def extract_video_info(video_id : String)
params.delete("reason") params.delete("reason")
end end
{"captions", "playabilityStatus", "playerConfig", "storyboards", "streamingData"}.each do |f| {"captions", "playabilityStatus", "playerConfig", "storyboards"}.each do |f|
params[f] = player_response[f] if player_response[f]? params[f] = player_response[f] if player_response[f]?
end end
# Convert URLs, if those are present
if streaming_data = player_response["streamingData"]?
%w[formats adaptiveFormats].each do |key|
streaming_data.as_h[key]?.try &.as_a.each do |format|
format.as_h["url"] = JSON::Any.new(convert_url(format))
end
end
params["streamingData"] = streaming_data
end
# Data structure version, for cache control # Data structure version, for cache control
params["version"] = JSON::Any.new(Video::SCHEMA_VERSION.to_i64) params["version"] = JSON::Any.new(Video::SCHEMA_VERSION.to_i64)
@ -454,3 +465,35 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any
return params return params
end end
private def convert_url(fmt)
if cfr = fmt["signatureCipher"]?.try { |json| HTTP::Params.parse(json.as_s) }
sp = cfr["sp"]
url = URI.parse(cfr["url"])
params = url.query_params
LOGGER.debug("convert_url: Decoding '#{cfr}'")
unsig = DECRYPT_FUNCTION.try &.decrypt_signature(cfr["s"])
params[sp] = unsig if unsig
else
url = URI.parse(fmt["url"].as_s)
params = url.query_params
end
n = DECRYPT_FUNCTION.try &.decrypt_nsig(params["n"])
params["n"] = n if n
if token = CONFIG.po_token
params["pot"] = token
end
url.query_params = params
LOGGER.trace("convert_url: new url is '#{url}'")
return url.to_s
rescue ex
LOGGER.debug("convert_url: Error when parsing video URL")
LOGGER.trace(ex.inspect_with_backtrace)
return ""
end