Skip to content

Commit b2133c6

Browse files
committed
Videos: Convert URL before putting result into cache
1 parent e319c35 commit b2133c6

File tree

2 files changed

+57
-68
lines changed

2 files changed

+57
-68
lines changed

src/invidious/videos.cr

Lines changed: 13 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,6 @@ struct Video
2626
@[DB::Field(ignore: true)]
2727
@captions = [] of Invidious::Videos::Captions::Metadata
2828

29-
@[DB::Field(ignore: true)]
30-
property adaptive_fmts : Array(Hash(String, JSON::Any))?
31-
32-
@[DB::Field(ignore: true)]
33-
property fmt_stream : Array(Hash(String, JSON::Any))?
34-
3529
@[DB::Field(ignore: true)]
3630
property description : String?
3731

@@ -98,72 +92,24 @@ struct Video
9892

9993
# Methods for parsing streaming data
10094

101-
def convert_url(fmt)
102-
if cfr = fmt["signatureCipher"]?.try { |json| HTTP::Params.parse(json.as_s) }
103-
sp = cfr["sp"]
104-
url = URI.parse(cfr["url"])
105-
params = url.query_params
106-
107-
LOGGER.debug("Videos: Decoding '#{cfr}'")
108-
109-
unsig = DECRYPT_FUNCTION.try &.decrypt_signature(cfr["s"])
110-
params[sp] = unsig if unsig
95+
def fmt_stream : Array(Hash(String, JSON::Any))
96+
if formats = info.dig?("streamingData", "formats")
97+
return formats
98+
.as_a.map(&.as_h)
99+
.sort_by! { |f| f["width"]?.try &.as_i || 0 }
111100
else
112-
url = URI.parse(fmt["url"].as_s)
113-
params = url.query_params
114-
end
115-
116-
n = DECRYPT_FUNCTION.try &.decrypt_nsig(params["n"])
117-
params["n"] = n if n
118-
119-
if token = CONFIG.po_token
120-
params["pot"] = token
121-
end
122-
123-
params["host"] = url.host.not_nil!
124-
if region = self.info["region"]?.try &.as_s
125-
params["region"] = region
126-
end
127-
128-
url.query_params = params
129-
LOGGER.trace("Videos: new url is '#{url}'")
130-
131-
return url.to_s
132-
rescue ex
133-
LOGGER.debug("Videos: Error when parsing video URL")
134-
LOGGER.trace(ex.inspect_with_backtrace)
135-
return ""
136-
end
137-
138-
def fmt_stream
139-
return @fmt_stream.as(Array(Hash(String, JSON::Any))) if @fmt_stream
140-
141-
fmt_stream = info.dig?("streamingData", "formats")
142-
.try &.as_a.map &.as_h || [] of Hash(String, JSON::Any)
143-
144-
fmt_stream.each do |fmt|
145-
fmt["url"] = JSON::Any.new(self.convert_url(fmt))
101+
return [] of Hash(String, JSON::Any)
146102
end
147-
148-
fmt_stream.sort_by! { |f| f["width"]?.try &.as_i || 0 }
149-
@fmt_stream = fmt_stream
150-
return @fmt_stream.as(Array(Hash(String, JSON::Any)))
151103
end
152104

153-
def adaptive_fmts
154-
return @adaptive_fmts.as(Array(Hash(String, JSON::Any))) if @adaptive_fmts
155-
156-
fmt_stream = info.dig("streamingData", "adaptiveFormats")
157-
.try &.as_a.map &.as_h || [] of Hash(String, JSON::Any)
158-
159-
fmt_stream.each do |fmt|
160-
fmt["url"] = JSON::Any.new(self.convert_url(fmt))
105+
def adaptive_fmts : Array(Hash(String, JSON::Any))
106+
if formats = info.dig?("streamingData", "adaptiveFormats")
107+
return formats
108+
.as_a.map(&.as_h)
109+
.sort_by! { |f| f["width"]?.try &.as_i || 0 }
110+
else
111+
return [] of Hash(String, JSON::Any)
161112
end
162-
163-
fmt_stream.sort_by! { |f| f["width"]?.try &.as_i || 0 }
164-
@adaptive_fmts = fmt_stream
165-
166-
return @adaptive_fmts.as(Array(Hash(String, JSON::Any)))
167113
end
168114

169115
def video_streams

src/invidious/videos/parser.cr

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,21 @@ def extract_video_info(video_id : String)
132132
params.delete("reason")
133133
end
134134

135-
{"captions", "playabilityStatus", "playerConfig", "storyboards", "streamingData"}.each do |f|
135+
{"captions", "playabilityStatus", "playerConfig", "storyboards"}.each do |f|
136136
params[f] = player_response[f] if player_response[f]?
137137
end
138138

139+
# Convert URLs, if those are present
140+
if streaming_data = player_response["streamingData"]?
141+
%w[formats adaptiveFormats].each do |key|
142+
streaming_data.as_h[key]?.try &.as_a.each do |format|
143+
format.as_h["url"] = JSON::Any.new(convert_url(format))
144+
end
145+
end
146+
147+
params["streamingData"] = streaming_data
148+
end
149+
139150
# Data structure version, for cache control
140151
params["version"] = JSON::Any.new(Video::SCHEMA_VERSION.to_i64)
141152

@@ -443,3 +454,35 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any
443454

444455
return params
445456
end
457+
458+
private def convert_url(fmt)
459+
if cfr = fmt["signatureCipher"]?.try { |json| HTTP::Params.parse(json.as_s) }
460+
sp = cfr["sp"]
461+
url = URI.parse(cfr["url"])
462+
params = url.query_params
463+
464+
LOGGER.debug("convert_url: Decoding '#{cfr}'")
465+
466+
unsig = DECRYPT_FUNCTION.try &.decrypt_signature(cfr["s"])
467+
params[sp] = unsig if unsig
468+
else
469+
url = URI.parse(fmt["url"].as_s)
470+
params = url.query_params
471+
end
472+
473+
n = DECRYPT_FUNCTION.try &.decrypt_nsig(params["n"])
474+
params["n"] = n if n
475+
476+
if token = CONFIG.po_token
477+
params["pot"] = token
478+
end
479+
480+
url.query_params = params
481+
LOGGER.trace("convert_url: new url is '#{url}'")
482+
483+
return url.to_s
484+
rescue ex
485+
LOGGER.debug("convert_url: Error when parsing video URL")
486+
LOGGER.trace(ex.inspect_with_backtrace)
487+
return ""
488+
end

0 commit comments

Comments
 (0)