diff --git a/src/invidious/frontend/watch_page.cr b/src/invidious/frontend/watch_page.cr
index c8cb7110..21f2197e 100644
--- a/src/invidious/frontend/watch_page.cr
+++ b/src/invidious/frontend/watch_page.cr
@@ -4,9 +4,9 @@ module Invidious::Frontend::WatchPage
# A handy structure to pass many elements at
# once to the download widget function
struct VideoAssets
- getter full_videos : Array(Hash(String, JSON::Any))
- getter video_streams : Array(Hash(String, JSON::Any))
- getter audio_streams : Array(Hash(String, JSON::Any))
+ getter full_videos : Array(Videos::ProgressiveHttpStream)
+ getter video_streams : Array(Videos::AdaptativeVideoStream)
+ getter audio_streams : Array(Videos::AdaptativeAudioStream)
getter captions : Array(Invidious::Videos::Captions::Metadata)
def initialize(
@@ -47,38 +47,33 @@ module Invidious::Frontend::WatchPage
# Non-DASH videos (audio+video)
video_assets.full_videos.each do |option|
- mimetype = option["mimeType"].as_s.split(";")[0]
+ height = Invidious::Videos::Formats.itag_to_metadata?(option.itag).try &.["height"]?
- height = Invidious::Videos::Formats.itag_to_metadata?(option["itag"]).try &.["height"]?
-
- value = {"itag": option["itag"], "ext": mimetype.split("/")[1]}.to_json
+ value = {"itag": option.itag, "ext": option.mime_type.split("/")[1]}.to_json
str << "\t\t\t\n"
end
# DASH video streams
video_assets.video_streams.each do |option|
- mimetype = option["mimeType"].as_s.split(";")[0]
-
- value = {"itag": option["itag"], "ext": mimetype.split("/")[1]}.to_json
+ value = {"itag": option.itag, "ext": option.mime_type.split("/")[1]}.to_json
str << "\t\t\t\n"
end
# DASH audio streams
video_assets.audio_streams.each do |option|
- mimetype = option["mimeType"].as_s.split(";")[0]
-
- value = {"itag": option["itag"], "ext": mimetype.split("/")[1]}.to_json
+ value = {"itag": option.itag, "ext": option.mime_type.split("/")[1]}.to_json
str << "\t\t\t\n"
end
diff --git a/src/invidious/jsonify/api_v1/video_json.cr b/src/invidious/jsonify/api_v1/video_json.cr
index 08cd533f..4ac95c57 100644
--- a/src/invidious/jsonify/api_v1/video_json.cr
+++ b/src/invidious/jsonify/api_v1/video_json.cr
@@ -81,78 +81,62 @@ module Invidious::JSONify::APIv1
video.adaptive_fmts.each do |fmt|
json.object do
# Only available on regular videos, not livestreams/OTF streams
- if init_range = fmt["initRange"]?
- json.field "init", "#{init_range["start"]}-#{init_range["end"]}"
- end
- if index_range = fmt["indexRange"]?
- json.field "index", "#{index_range["start"]}-#{index_range["end"]}"
- end
+ json.field "init", fmt.init_range.to_s if fmt.init_range
+ json.field "index", fmt.index_range.to_s if fmt.index_range
# Not available on MPEG-4 Timed Text (`text/mp4`) streams (livestreams only)
- json.field "bitrate", fmt["bitrate"].as_i.to_s if fmt["bitrate"]?
+ json.field "bitrate", fmt.bitrate.to_s if fmt.responds_to?(:bitrate)
if proxy
- json.field "url", Invidious::HttpServer::Utils.proxy_video_url(
- fmt["url"].to_s, absolute: true
- )
+ json.field "url", HttpServer::Utils.proxy_video_url(fmt.url, absolute: true)
else
- json.field "url", fmt["url"]
+ json.field "url", fmt.url
end
- json.field "itag", fmt["itag"].as_i.to_s
- json.field "type", fmt["mimeType"]
- json.field "clen", fmt["contentLength"]? || "-1"
+ json.field "itag", fmt.itag.to_s
+ json.field "type", fmt.raw_mime_type
+ json.field "clen", fmt.content_length if fmt.responds_to?(:content_length)
+
# Last modified is a unix timestamp with µS, with the dot omitted.
# E.g: 1638056732(.)141582
#
# On livestreams, it's not present, so always fall back to the
# current unix timestamp (up to mS precision) for compatibility.
- last_modified = fmt["lastModified"]?
- last_modified ||= "#{Time.utc.to_unix_ms}000"
- json.field "lmt", last_modified
+ last_modified = fmt.last_modified || Time.utc
+ json.field "lmt", "#{last_modified.to_unix_ms}000"
- json.field "projectionType", fmt["projectionType"]
+ json.field "projectionType", fmt.projection_type.to_s.upcase
- height = fmt["height"]?.try &.as_i
- width = fmt["width"]?.try &.as_i
-
- fps = fmt["fps"]?.try &.as_i
-
- if fps
- json.field "fps", fps
+ # Video-related data
+ if fmt.is_a?(Videos::AdaptativeVideoStream)
+ json.field "size", "#{fmt.video_width}x#{fmt.video_height}"
+ json.field "resolution", "#{fmt.video_height}p"
+ json.field "fps", fmt.video_fps
end
- if height && width
- json.field "size", "#{width}x#{height}"
- json.field "resolution", "#{height}p"
+ json.field "qualityLabel", fmt.label
- quality_label = "#{width > height ? height : width}p"
-
- if fps && fps > 30
- quality_label += fps.to_s
- end
-
- json.field "qualityLabel", quality_label
- end
-
- if fmt_info = Invidious::Videos::Formats.itag_to_metadata?(fmt["itag"])
+ if fmt_info = Invidious::Videos::Formats.itag_to_metadata?(fmt.itag)
json.field "container", fmt_info["ext"]
- json.field "encoding", fmt_info["vcodec"]? || fmt_info["acodec"]
end
- # Livestream chunk infos
- json.field "targetDurationSec", fmt["targetDurationSec"].as_i if fmt.has_key?("targetDurationSec")
- json.field "maxDvrDurationSec", fmt["maxDvrDurationSec"].as_i if fmt.has_key?("maxDvrDurationSec")
+ json.field "encoding", fmt.codecs
+
+ # Livestream chunk infos. Should be present when `init` and `index` aren't
+ json.field "targetDurationSec", fmt.target_duration if fmt.target_duration
+ json.field "maxDvrDurationSec", fmt.max_dvr_duration if fmt.max_dvr_duration
# Audio-related data
- json.field "audioQuality", fmt["audioQuality"] if fmt.has_key?("audioQuality")
- json.field "audioSampleRate", fmt["audioSampleRate"].as_s.to_i if fmt.has_key?("audioSampleRate")
- json.field "audioChannels", fmt["audioChannels"] if fmt.has_key?("audioChannels")
+ if fmt.is_a?(Videos::AdaptativeAudioStream)
+ json.field "audioQuality", fmt.audio_quality
+ json.field "audioSampleRate", fmt.audio_sample_rate
+ json.field "audioChannels", fmt.audio_channels
+ end
# Extra misc stuff
- json.field "colorInfo", fmt["colorInfo"] if fmt.has_key?("colorInfo")
- json.field "captionTrack", fmt["captionTrack"] if fmt.has_key?("captionTrack")
+ # json.field "colorInfo", fmt["colorInfo"] if fmt.has_key?("colorInfo")
+ # json.field "captionTrack", fmt["captionTrack"] if fmt.has_key?("captionTrack")
end
end
end
@@ -163,44 +147,27 @@ module Invidious::JSONify::APIv1
video.fmt_stream.each do |fmt|
json.object do
if proxy
- json.field "url", Invidious::HttpServer::Utils.proxy_video_url(
- fmt["url"].to_s, absolute: true
- )
+ json.field "url", HttpServer::Utils.proxy_video_url(fmt.url, absolute: true)
else
- json.field "url", fmt["url"]
- end
- json.field "itag", fmt["itag"].as_i.to_s
- json.field "type", fmt["mimeType"]
- json.field "quality", fmt["quality"]
-
- json.field "bitrate", fmt["bitrate"].as_i.to_s if fmt["bitrate"]?
-
- height = fmt["height"]?.try &.as_i
- width = fmt["width"]?.try &.as_i
-
- fps = fmt["fps"]?.try &.as_i
-
- if fps
- json.field "fps", fps
+ json.field "url", fmt.url
end
- if height && width
- json.field "size", "#{width}x#{height}"
- json.field "resolution", "#{height}p"
+ json.field "itag", fmt.itag.to_s
+ json.field "type", fmt.raw_mime_type
+ json.field "quality", fmt.label
- quality_label = "#{width > height ? height : width}p"
+ json.field "bitrate", fmt.bitrate
- if fps && fps > 30
- quality_label += fps.to_s
- end
+ json.field "size", "#{fmt.video_width}x#{fmt.video_height}"
+ json.field "resolution", "#{fmt.video_height}p"
+ json.field "fps", fmt.video_fps
- json.field "qualityLabel", quality_label
- end
-
- if fmt_info = Invidious::Videos::Formats.itag_to_metadata?(fmt["itag"])
+ if fmt_info = Videos::Formats.itag_to_metadata?(fmt.itag)
json.field "container", fmt_info["ext"]
- json.field "encoding", fmt_info["vcodec"]? || fmt_info["acodec"]
end
+
+ json.field "qualityLabel", fmt.label
+ json.field "encoding", fmt.codecs
end
end
end
diff --git a/src/invidious/routes/api/manifest.cr b/src/invidious/routes/api/manifest.cr
index d89e752c..377a4888 100644
--- a/src/invidious/routes/api/manifest.cr
+++ b/src/invidious/routes/api/manifest.cr
@@ -4,7 +4,7 @@ module Invidious::Routes::API::Manifest
env.response.headers.add("Access-Control-Allow-Origin", "*")
env.response.content_type = "application/dash+xml"
- local = env.params.query["local"]?.try &.== "true"
+ local = (env.params.query["local"]? == "true")
id = env.params.url["id"]
region = env.params.query["region"]?
@@ -44,18 +44,18 @@ module Invidious::Routes::API::Manifest
return manifest
end
- adaptive_fmts = video.adaptive_fmts
-
+ # Transform URLs for proxying
if local
- adaptive_fmts.each do |fmt|
- fmt["url"] = JSON::Any.new("#{HOST_URL}#{URI.parse(fmt["url"].as_s).request_target}")
+ video.adaptive_fmts.each do |fmt|
+ fmt.url = "#{HOST_URL}#{URI.parse(fmt.url).request_target}"
end
end
- audio_streams = video.audio_streams.sort_by { |stream| {stream["bitrate"].as_i} }.reverse!
- video_streams = video.video_streams.sort_by { |stream| {stream["width"].as_i, stream["fps"].as_i} }.reverse!
+ audio_streams = video.audio_streams.sort_by(&.bitrate).reverse!
+ video_streams = video.video_streams.sort_by { |fmt| {fmt.video_width, fmt.video_fps} }.reverse!
- manifest = XML.build(indent: " ", encoding: "UTF-8") do |xml|
+ # Build the manifest
+ return XML.build(indent: " ", encoding: "UTF-8") do |xml|
xml.element("MPD", "xmlns": "urn:mpeg:dash:schema:mpd:2011",
"profiles": "urn:mpeg:dash:profile:full:2011", minBufferTime: "PT1.5S", type: "static",
mediaPresentationDuration: "PT#{video.length_seconds}S") do
@@ -63,34 +63,28 @@ module Invidious::Routes::API::Manifest
i = 0
{"audio/mp4"}.each do |mime_type|
- mime_streams = audio_streams.select { |stream| stream["mimeType"].as_s.starts_with? mime_type }
- next if mime_streams.empty?
+ formats = audio_streams.select(&.mime_type.== mime_type)
+ next if formats.empty?
- mime_streams.each do |fmt|
+ formats.each do |fmt|
# OTF streams aren't supported yet (See https://github.com/TeamNewPipe/NewPipe/issues/2415)
- next if !(fmt.has_key?("indexRange") && fmt.has_key?("initRange"))
+ next if (fmt.index_range.nil? || fmt.init_range.nil?)
# Different representations of the same audio should be groupped into one AdaptationSet.
# However, most players don't support auto quality switching, so we have to trick them
# into providing a quality selector.
# See https://github.com/iv-org/invidious/issues/3074 for more details.
- xml.element("AdaptationSet", id: i, mimeType: mime_type, startWithSAP: 1, subsegmentAlignment: true, label: fmt["bitrate"].to_s + "k") do
- codecs = fmt["mimeType"].as_s.split("codecs=")[1].strip('"')
- bandwidth = fmt["bitrate"].as_i
- itag = fmt["itag"].as_i
- url = fmt["url"].as_s
-
+ xml.element("AdaptationSet", id: i, mimeType: mime_type, startWithSAP: 1, subsegmentAlignment: true, label: "#{(fmt.bitrate // 1000)} kbps") do
xml.element("Role", schemeIdUri: "urn:mpeg:dash:role:2011", value: i == 0 ? "main" : "alternate")
-
- xml.element("Representation", id: fmt["itag"], codecs: codecs, bandwidth: bandwidth) do
- xml.element("AudioChannelConfiguration", schemeIdUri: "urn:mpeg:dash:23003:3:audio_channel_configuration:2011",
- value: "2")
- xml.element("BaseURL") { xml.text url }
- xml.element("SegmentBase", indexRange: "#{fmt["indexRange"]["start"]}-#{fmt["indexRange"]["end"]}") do
- xml.element("Initialization", range: "#{fmt["initRange"]["start"]}-#{fmt["initRange"]["end"]}")
+ xml.element("Representation", id: fmt.itag, codecs: fmt.codecs, bandwidth: fmt.bitrate) do
+ xml.element("AudioChannelConfiguration", schemeIdUri: "urn:mpeg:dash:23003:3:audio_channel_configuration:2011", value: fmt.audio_channels)
+ xml.element("BaseURL") { xml.text fmt.url }
+ xml.element("SegmentBase", indexRange: fmt.index_range.to_s) do
+ xml.element("Initialization", range: fmt.init_range.to_s)
end
end
end
+
i += 1
end
end
@@ -98,33 +92,26 @@ module Invidious::Routes::API::Manifest
potential_heights = {4320, 2160, 1440, 1080, 720, 480, 360, 240, 144}
{"video/mp4"}.each do |mime_type|
- mime_streams = video_streams.select { |stream| stream["mimeType"].as_s.starts_with? mime_type }
+ mime_streams = video_streams.select(&.mime_type.== mime_type)
next if mime_streams.empty?
heights = [] of Int32
+
xml.element("AdaptationSet", id: i, mimeType: mime_type, startWithSAP: 1, subsegmentAlignment: true, scanType: "progressive") do
mime_streams.each do |fmt|
# OTF streams aren't supported yet (See https://github.com/TeamNewPipe/NewPipe/issues/2415)
- next if !(fmt.has_key?("indexRange") && fmt.has_key?("initRange"))
-
- codecs = fmt["mimeType"].as_s.split("codecs=")[1].strip('"')
- bandwidth = fmt["bitrate"].as_i
- itag = fmt["itag"].as_i
- url = fmt["url"].as_s
- width = fmt["width"].as_i
- height = fmt["height"].as_i
+ next if (fmt.index_range.nil? || fmt.init_range.nil?)
# Resolutions reported by YouTube player (may not accurately reflect source)
- height = potential_heights.min_by { |x| (height - x).abs }
+ height = potential_heights.min_by { |x| (fmt.video_height.to_i32 - x).abs }
next if unique_res && heights.includes? height
heights << height
- xml.element("Representation", id: itag, codecs: codecs, width: width, height: height,
- startWithSAP: "1", maxPlayoutRate: "1",
- bandwidth: bandwidth, frameRate: fmt["fps"]) do
- xml.element("BaseURL") { xml.text url }
- xml.element("SegmentBase", indexRange: "#{fmt["indexRange"]["start"]}-#{fmt["indexRange"]["end"]}") do
- xml.element("Initialization", range: "#{fmt["initRange"]["start"]}-#{fmt["initRange"]["end"]}")
+ xml.element("Representation", id: fmt.itag, codecs: fmt.codecs, width: fmt.video_width, height: height,
+ startWithSAP: "1", maxPlayoutRate: "1", bandwidth: fmt.bitrate, frameRate: fmt.video_fps) do
+ xml.element("BaseURL") { xml.text fmt.url }
+ xml.element("SegmentBase", indexRange: fmt.index_range.to_s) do
+ xml.element("Initialization", range: fmt.init_range.to_s)
end
end
end
@@ -135,8 +122,6 @@ module Invidious::Routes::API::Manifest
end
end
end
-
- return manifest
end
# /api/manifest/dash/id/videoplayback
diff --git a/src/invidious/routes/embed.cr b/src/invidious/routes/embed.cr
index 266f7ba4..f8617d7f 100644
--- a/src/invidious/routes/embed.cr
+++ b/src/invidious/routes/embed.cr
@@ -157,8 +157,8 @@ module Invidious::Routes::Embed
adaptive_fmts = video.adaptive_fmts
if params.local
- fmt_stream.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).request_target) }
- adaptive_fmts.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).request_target) }
+ fmt_stream.each { |fmt| fmt.url = HttpServer::Utils.proxy_video_url(fmt.url) }
+ adaptive_fmts.each { |fmt| fmt.url = HttpServer::Utils.proxy_video_url(fmt.url) }
end
video_streams = video.video_streams
@@ -192,10 +192,10 @@ module Invidious::Routes::Embed
thumbnail = "/vi/#{video.id}/maxres.jpg"
if params.raw
- url = fmt_stream[0]["url"].as_s
+ url = fmt_stream[0].url
fmt_stream.each do |fmt|
- url = fmt["url"].as_s if fmt["quality"].as_s == params.quality
+ url = fmt.url if fmt.label == params.quality
end
return env.redirect url
diff --git a/src/invidious/routes/video_playback.cr b/src/invidious/routes/video_playback.cr
index 26852d06..1aa688b2 100644
--- a/src/invidious/routes/video_playback.cr
+++ b/src/invidious/routes/video_playback.cr
@@ -285,14 +285,15 @@ module Invidious::Routes::VideoPlayback
if itag.nil?
fmt = video.fmt_stream[-1]?
else
- fmt = video.fmt_stream.find(nil) { |f| f["itag"].as_i == itag } || video.adaptive_fmts.find(nil) { |f| f["itag"].as_i == itag }
+ fmt = video.fmt_stream.find(nil, &.itag.== itag) || video.adaptive_fmts.find(nil, &.itag.== itag)
end
- url = fmt.try &.["url"]?.try &.as_s
- if !url
+ if !fmt
haltf env, status_code: 404
end
+ url = fmt.url
+
if local
url = URI.parse(url).request_target.not_nil!
url += "&title=#{URI.encode_www_form(title, space_to_plus: false)}" if title
diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr
index aabe8dfc..4a1982a9 100644
--- a/src/invidious/routes/watch.cr
+++ b/src/invidious/routes/watch.cr
@@ -121,8 +121,8 @@ module Invidious::Routes::Watch
adaptive_fmts = video.adaptive_fmts
if params.local
- fmt_stream.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).request_target) }
- adaptive_fmts.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).request_target) }
+ fmt_stream.each { |fmt| fmt.url = HttpServer::Utils.proxy_video_url(fmt.url) }
+ adaptive_fmts.each { |fmt| fmt.url = HttpServer::Utils.proxy_video_url(fmt.url) }
end
video_streams = video.video_streams
@@ -160,21 +160,21 @@ module Invidious::Routes::Watch
if params.raw
if params.listen
- url = audio_streams[0]["url"].as_s
+ url = audio_streams[0].url
if params.quality.ends_with? "k"
audio_streams.each do |fmt|
- if fmt["bitrate"].as_i == params.quality.rchop("k").to_i
- url = fmt["url"].as_s
+ if fmt.bitrate == params.quality.rchop("k").to_i
+ url = fmt.url
end
end
end
else
- url = fmt_stream[0]["url"].as_s
+ url = fmt_stream[0].url
fmt_stream.each do |fmt|
- if fmt["quality"].as_s == params.quality
- url = fmt["url"].as_s
+ if fmt.label == params.quality
+ url = fmt.url
end
end
end
diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr
index ae09e736..44312880 100644
--- a/src/invidious/videos.cr
+++ b/src/invidious/videos.cr
@@ -26,6 +26,12 @@ struct Video
@[DB::Field(ignore: true)]
@captions = [] of Invidious::Videos::Captions::Metadata
+ @[DB::Field(ignore: true)]
+ @adaptive_fmts = [] of IV::Videos::AdaptativeStream
+
+ @[DB::Field(ignore: true)]
+ @fmt_stream = [] of IV::Videos::ProgressiveHttpStream
+
@[DB::Field(ignore: true)]
property description : String?
@@ -92,32 +98,32 @@ struct Video
# Methods for parsing streaming data
- def fmt_stream : Array(Hash(String, JSON::Any))
- if formats = info.dig?("streamingData", "formats")
- return formats
- .as_a.map(&.as_h)
- .sort_by! { |f| f["width"]?.try &.as_i || 0 }
- else
- return [] of Hash(String, JSON::Any)
+ def fmt_stream : Array(IV::Videos::ProgressiveHttpStream)
+ if @fmt_stream.empty?
+ if formats = info.dig?("streamingData", "formats")
+ @fmt_stream = IV::Videos.parse_progressive_formats(formats)
+ end
end
+
+ return @fmt_stream
end
- def adaptive_fmts : Array(Hash(String, JSON::Any))
- if formats = info.dig?("streamingData", "adaptiveFormats")
- return formats
- .as_a.map(&.as_h)
- .sort_by! { |f| f["width"]?.try &.as_i || 0 }
- else
- return [] of Hash(String, JSON::Any)
+ def adaptive_fmts : Array(IV::Videos::AdaptativeStream)
+ if @adaptive_fmts.empty?
+ if formats = info.dig?("streamingData", "adaptiveFormats")
+ @adaptive_fmts = IV::Videos.parse_adaptative_formats(formats)
+ end
end
+
+ return @adaptive_fmts
end
- def video_streams
- adaptive_fmts.select &.["mimeType"]?.try &.as_s.starts_with?("video")
+ def video_streams : Array(IV::Videos::AdaptativeVideoStream)
+ self.adaptive_fmts.select(IV::Videos::AdaptativeVideoStream)
end
- def audio_streams
- adaptive_fmts.select &.["mimeType"]?.try &.as_s.starts_with?("audio")
+ def audio_streams : Array(IV::Videos::AdaptativeAudioStream)
+ self.adaptive_fmts.select(IV::Videos::AdaptativeAudioStream)
end
# Misc. methods
diff --git a/src/invidious/videos/formats.cr b/src/invidious/videos/formats.cr
index e98e7257..c49c7411 100644
--- a/src/invidious/videos/formats.cr
+++ b/src/invidious/videos/formats.cr
@@ -1,5 +1,5 @@
module Invidious::Videos::Formats
- def self.itag_to_metadata?(itag : JSON::Any)
+ def self.itag_to_metadata?(itag : Int)
return FORMATS[itag.to_s]?
end
diff --git a/src/invidious/views/components/player.ecr b/src/invidious/views/components/player.ecr
index 5c28358b..395ead68 100644
--- a/src/invidious/views/components/player.ecr
+++ b/src/invidious/views/components/player.ecr
@@ -12,19 +12,19 @@
best_m4a_stream_index = 0
best_m4a_stream_bitrate = 0
audio_streams.each_with_index do |fmt, i|
- bandwidth = fmt["bitrate"].as_i
- if (fmt["mimeType"].as_s.starts_with?("audio/mp4") && bandwidth > best_m4a_stream_bitrate)
+ bandwidth = fmt.bitrate
+ if (fmt.mime_type == "audio/mp4" && bandwidth > best_m4a_stream_bitrate)
best_m4a_stream_bitrate = bandwidth
best_m4a_stream_index = i
end
end
audio_streams.each_with_index do |fmt, i|
- src_url = "/latest_version?id=#{video.id}&itag=#{fmt["itag"]}"
+ src_url = "/latest_version?id=#{video.id}&itag=#{fmt.itag}"
src_url += "&local=true" if params.local
- bitrate = fmt["bitrate"]
- mimetype = HTML.escape(fmt["mimeType"].as_s)
+ bitrate = fmt.bitrate // 1000
+ mimetype = HTML.escape(fmt.raw_mime_type)
selected = (i == best_m4a_stream_index)
%>
@@ -39,14 +39,14 @@
<% end %>
<%
- fmt_stream.reject! { |f| f["itag"] == 17 }
- fmt_stream.sort_by! {|f| params.quality == f["quality"] ? 0 : 1 }
+ fmt_stream.reject!(&.itag.== 17)
+ fmt_stream.sort_by! { |f| params.quality == f.label ? 0 : 1 }
fmt_stream.each_with_index do |fmt, i|
- src_url = "/latest_version?id=#{video.id}&itag=#{fmt["itag"]}"
+ src_url = "/latest_version?id=#{video.id}&itag=#{fmt.itag}"
src_url += "&local=true" if params.local
- quality = fmt["quality"]
- mimetype = HTML.escape(fmt["mimeType"].as_s)
+ quality = fmt.label
+ mimetype = HTML.escape(fmt.raw_mime_type)
selected = params.quality ? (params.quality == quality) : (i == 0)
%>