syeopite bf2eccbcaf
Connection pool: ensure response is fully read
The streaming API of HTTP::Client has an internal buffer
that will continue to persist onto the next request unless
the response is fully read.

This commit privatizes the #client method of Pool and instead
expose various HTTP request methods that will call and yield
the underlying request and response.

This way, we can ensure that the resposne is fully read before
the client is passed back into the pool for another request.
2025-05-13 05:18:51 -07:00

217 lines
6.5 KiB
Crystal

{% skip_file if flag?(:api_only) %}
module Invidious::Routes::Embed
def self.redirect(env)
locale = env.get("preferences").as(Preferences).locale
if plid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "")
begin
playlist = get_playlist(plid)
offset = env.params.query["index"]?.try &.to_i? || 0
videos = get_playlist_videos(playlist, offset: offset)
if videos.empty?
url = "/playlist?list=#{plid}"
raise NotFoundException.new(translate(locale, "error_video_not_in_playlist", url))
end
rescue ex : NotFoundException
return error_template(404, ex)
rescue ex
return error_template(500, ex)
end
url = "/embed/#{videos[0].id}?#{env.params.query}"
if env.params.query.size > 0
url += "?#{env.params.query}"
end
else
url = "/"
end
env.redirect url
end
def self.show(env)
locale = env.get("preferences").as(Preferences).locale
id = env.params.url["id"]
plid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "")
continuation = process_continuation(env.params.query, plid, id)
if md = env.params.query["playlist"]?
.try &.match(/[a-zA-Z0-9_-]{11}(,[a-zA-Z0-9_-]{11})*/)
video_series = md[0].split(",")
env.params.query.delete("playlist")
end
preferences = env.get("preferences").as(Preferences)
if id.includes?("%20") || id.includes?("+") || env.params.query.to_s.includes?("%20") || env.params.query.to_s.includes?("+")
id = env.params.url["id"].gsub("%20", "").delete("+")
url = "/embed/#{id}"
if env.params.query.size > 0
url += "?#{env.params.query.to_s.gsub("%20", "").delete("+")}"
end
return env.redirect url
end
# YouTube embed supports `videoseries` with either `list=PLID`
# or `playlist=VIDEO_ID,VIDEO_ID`
case id
when "videoseries"
url = ""
if plid
begin
playlist = get_playlist(plid)
offset = env.params.query["index"]?.try &.to_i? || 0
videos = get_playlist_videos(playlist, offset: offset)
if videos.empty?
url = "/playlist?list=#{plid}"
raise NotFoundException.new(translate(locale, "error_video_not_in_playlist", url))
end
rescue ex : NotFoundException
return error_template(404, ex)
rescue ex
return error_template(500, ex)
end
url = "/embed/#{videos[0].id}"
elsif video_series
url = "/embed/#{video_series.shift}"
env.params.query["playlist"] = video_series.join(",")
else
return env.redirect "/"
end
if env.params.query.size > 0
url += "?#{env.params.query}"
end
return env.redirect url
when "live_stream"
response = YT_POOL.get("/embed/live_stream?channel=#{env.params.query["channel"]? || ""}")
video_id = response.body.match(/"video_id":"(?<video_id>[a-zA-Z0-9_-]{11})"/).try &.["video_id"]
env.params.query.delete_all("channel")
if !video_id || video_id == "live_stream"
return error_template(500, "Video is unavailable.")
end
url = "/embed/#{video_id}"
if env.params.query.size > 0
url += "?#{env.params.query}"
end
return env.redirect url
when id.size > 11
url = "/embed/#{id[0, 11]}"
if env.params.query.size > 0
url += "?#{env.params.query}"
end
return env.redirect url
else nil # Continue
end
params = process_video_params(env.params.query, preferences)
user = env.get?("user").try &.as(User)
if user
subscriptions = user.subscriptions
watched = user.watched
notifications = user.notifications
end
subscriptions ||= [] of String
begin
video = get_video(id, region: params.region)
rescue ex : NotFoundException
return error_template(404, ex)
rescue ex
return error_template(500, ex)
end
if preferences.annotations_subscribed &&
subscriptions.includes?(video.ucid) &&
(env.params.query["iv_load_policy"]? || "1") == "1"
params.annotations = true
end
# if watched && !watched.includes? id
# PG_DB.exec("UPDATE users SET watched = array_append(watched, $1) WHERE email = $2", id, user.as(User).email)
# end
if CONFIG.enable_user_notifications && notifications && notifications.includes? id
Invidious::Database::Users.remove_notification(user.as(User), id)
env.get("user").as(User).notifications.delete(id)
notifications.delete(id)
end
fmt_stream = video.fmt_stream
adaptive_fmts = video.adaptive_fmts
if params.local
fmt_stream.each { |fmt| fmt["url"] = JSON::Any.new(HttpServer::Utils.proxy_video_url(fmt["url"].as_s)) }
end
# Always proxy DASH streams, otherwise youtube CORS headers will prevent playback
adaptive_fmts.each { |fmt| fmt["url"] = JSON::Any.new(HttpServer::Utils.proxy_video_url(fmt["url"].as_s)) }
video_streams = video.video_streams
audio_streams = video.audio_streams
if audio_streams.empty? && !video.live_now
if params.quality == "dash"
env.params.query.delete_all("quality")
return env.redirect "/embed/#{id}?#{env.params.query}"
elsif params.listen
env.params.query.delete_all("listen")
env.params.query["listen"] = "0"
return env.redirect "/embed/#{id}?#{env.params.query}"
end
end
captions = video.captions
preferred_captions = captions.select { |caption|
params.preferred_captions.includes?(caption.name) ||
params.preferred_captions.includes?(caption.language_code.split("-")[0])
}
preferred_captions.sort_by! { |caption|
(params.preferred_captions.index(caption.name) ||
params.preferred_captions.index(caption.language_code.split("-")[0])).not_nil!
}
captions = captions - preferred_captions
aspect_ratio = nil
thumbnail = "/vi/#{video.id}/maxres.jpg"
if params.raw
url = fmt_stream[0]["url"].as_s
fmt_stream.each do |fmt|
url = fmt["url"].as_s if fmt["quality"].as_s == params.quality
end
return env.redirect url
end
if CONFIG.invidious_companion.present?
invidious_companion = CONFIG.invidious_companion.sample
env.response.headers["Content-Security-Policy"] =
env.response.headers["Content-Security-Policy"]
.gsub("media-src", "media-src #{invidious_companion.public_url}")
.gsub("connect-src", "connect-src #{invidious_companion.public_url}")
end
rendered "embed"
end
end