diff --git a/app/models/iiif_canvas_presenter.rb b/app/models/iiif_canvas_presenter.rb index 53688984bd..f2c481b1f1 100644 --- a/app/models/iiif_canvas_presenter.rb +++ b/app/models/iiif_canvas_presenter.rb @@ -98,21 +98,29 @@ def service def video_content # @see https://github.com/samvera-labs/iiif_manifest - stream_urls.collect { |quality, _url| video_display_content(quality) } + stream_urls.collect { |quality, url, mimetype| video_display_content(quality, url, mimetype) } end - def video_display_content(quality) - IIIFManifest::V3::DisplayContent.new(Rails.application.routes.url_helpers.hls_manifest_master_file_url(master_file.id, quality: quality), - **manifest_attributes(quality, 'Video')) + def video_display_content(quality, url, mimetype) + if mimetype.present? && mimetype != 'application/x-mpegURL' + IIIFManifest::V3::DisplayContent.new(url, **manifest_attributes(quality, 'Video', mimetype: mimetype)) + else + IIIFManifest::V3::DisplayContent.new(Rails.application.routes.url_helpers.hls_manifest_master_file_url(master_file.id, quality: quality), + **manifest_attributes(quality, 'Video')) + end end def audio_content - stream_urls.collect { |quality, _url| audio_display_content(quality) } + stream_urls.collect { |quality, url, mimetype| audio_display_content(quality, url, mimetype) } end - def audio_display_content(quality) - IIIFManifest::V3::DisplayContent.new(Rails.application.routes.url_helpers.hls_manifest_master_file_url(master_file.id, quality: quality), - **manifest_attributes(quality, 'Sound')) + def audio_display_content(quality, url, mimetype) + if mimetype.present? && mimetype != 'application/x-mpegURL' + IIIFManifest::V3::DisplayContent.new(url, **manifest_attributes(quality, 'Sound', mimetype: mimetype)) + else + IIIFManifest::V3::DisplayContent.new(Rails.application.routes.url_helpers.hls_manifest_master_file_url(master_file.id, quality: quality), + **manifest_attributes(quality, 'Sound')) + end end def supplementing_content_data(file) @@ -142,7 +150,7 @@ def supplementing_content_data(file) def stream_urls stream_info[:stream_hls].collect do |d| - [d[:quality], d[:url]] + [d[:quality], d[:url], d[:mimetype]] end end @@ -214,14 +222,14 @@ def parse_hour_min_sec(s) smh[0] + (60 * smh[1]) + (3600 * smh[2]) end - def manifest_attributes(quality, media_type) + def manifest_attributes(quality, media_type, mimetype: 'application/x-mpegURL') media_hash = { label: quality, width: (master_file.width || '1280').to_i, height: (master_file.height || MasterFile::AUDIO_HEIGHT).to_i, duration: stream_info[:duration], type: media_type, - format: 'application/x-mpegURL' + format: mimetype }.compact if master_file.media_object.visibility == 'public' diff --git a/app/models/iiif_playlist_canvas_presenter.rb b/app/models/iiif_playlist_canvas_presenter.rb index 887c0793fe..64b2038dad 100644 --- a/app/models/iiif_playlist_canvas_presenter.rb +++ b/app/models/iiif_playlist_canvas_presenter.rb @@ -115,21 +115,29 @@ def metadata_field(label, value, default = nil) def video_content # @see https://github.com/samvera-labs/iiif_manifest - stream_urls.collect { |quality, _url| video_display_content(quality) } + stream_urls.collect { |quality, url, mimetype| video_display_content(quality, url, mimetype) } end - def video_display_content(quality) - IIIFManifest::V3::DisplayContent.new(CGI.unescape(Rails.application.routes.url_helpers.hls_manifest_master_file_url(master_file.id, quality: quality, anchor: fragment_identifier)), - **manifest_attributes(quality, 'Video')) + def video_display_content(quality, url, mimetype) + if mimetype.present? && mimetype != 'application/x-mpegURL' + IIIFManifest::V3::DisplayContent.new(URI.join(url, "##{fragment_identifier}").to_s, **manifest_attributes(quality, 'Video', mimetype: mimetype)) + else + IIIFManifest::V3::DisplayContent.new(CGI.unescape(Rails.application.routes.url_helpers.hls_manifest_master_file_url(master_file.id, quality: quality, anchor: fragment_identifier)), + **manifest_attributes(quality, 'Video')) + end end def audio_content - stream_urls.collect { |quality, _url| audio_display_content(quality) } + stream_urls.collect { |quality, url, mimetype| audio_display_content(quality, url, mimetype) } end - def audio_display_content(quality) - IIIFManifest::V3::DisplayContent.new(CGI.unescape(Rails.application.routes.url_helpers.hls_manifest_master_file_url(master_file.id, quality: quality, anchor: fragment_identifier)), - **manifest_attributes(quality, 'Sound')) + def audio_display_content(quality, url, mimetype) + if mimetype.present? && mimetype != 'application/x-mpegURL' + IIIFManifest::V3::DisplayContent.new(URI.join(url, "##{fragment_identifier}").to_s, **manifest_attributes(quality, 'Sound', mimetype: mimetype)) + else + IIIFManifest::V3::DisplayContent.new(CGI.unescape(Rails.application.routes.url_helpers.hls_manifest_master_file_url(master_file.id, quality: quality, anchor: fragment_identifier)), + **manifest_attributes(quality, 'Sound')) + end end def marker_content(marker) @@ -174,7 +182,7 @@ def supplemental_attributes(file) def stream_urls stream_info[:stream_hls].collect do |d| - [d[:quality], d[:url]] + [d[:quality], d[:url], d[:mimetype]] end end @@ -192,14 +200,14 @@ def simple_iiif_range(label = stream_info[:embed_title]) ) end - def manifest_attributes(quality, media_type) + def manifest_attributes(quality, media_type, mimetype: 'application/x-mpegURL') media_hash = { label: quality, width: (master_file.width || '1280').to_i, height: (master_file.height || MasterFile::AUDIO_HEIGHT).to_i, duration: stream_info[:duration], type: media_type, - format: 'application/x-mpegURL' + format: mimetype }.compact if master_file.media_object.visibility == 'public' diff --git a/spec/factories/derivatives.rb b/spec/factories/derivatives.rb index 41fffdcbc9..c0877a8861 100644 --- a/spec/factories/derivatives.rb +++ b/spec/factories/derivatives.rb @@ -26,7 +26,8 @@ video_bitrate { '4000000.0' } audio_codec { 'AAC' } audio_bitrate { '163842.0' } - absolute_location { 'file:///srv/avalon/content/6f69c008-06a4-4bad-bb60-26297f0b4c06/35bddaa0-fbb4-404f-ab76-58f22921529c/warning.mp4' } + mime_type { nil } + derivativeFile { 'file:///srv/avalon/content/6f69c008-06a4-4bad-bb60-26297f0b4c06/35bddaa0-fbb4-404f-ab76-58f22921529c/warning.mp4' } trait :with_master_file do after(:create) do |d| diff --git a/spec/models/iiif_canvas_presenter_spec.rb b/spec/models/iiif_canvas_presenter_spec.rb index 7a3a58dce0..fb85b8c8dd 100644 --- a/spec/models/iiif_canvas_presenter_spec.rb +++ b/spec/models/iiif_canvas_presenter_spec.rb @@ -61,6 +61,19 @@ expect(subject.width).to eq 1280 expect(subject.height).to eq 40 end + + context 'with mp3 file' do + let(:mp3_url) { 'https://streaming.example.com/dir/file.mp3' } + let(:derivative) { FactoryBot.build(:derivative, hls_url: mp3_url, mime_type: 'audio/mpeg' ) } + + it 'has format' do + expect(subject.format).to eq 'audio/mpeg' + end + + it 'has progressive download url' do + expect(subject.url).to eq mp3_url + end + end end context 'when video file' do @@ -72,6 +85,19 @@ expect(subject.width).to eq 1024 expect(subject.height).to eq 768 end + + context 'with mp4 file' do + let(:mp4_url) { 'https://streaming.example.com/dir/file.mp4' } + let(:derivative) { FactoryBot.build(:derivative, hls_url: mp4_url, mime_type: 'video/mp4' ) } + + it 'has format' do + expect(subject.format).to eq 'video/mp4' + end + + it 'has progressive download url' do + expect(subject.url).to eq mp4_url + end + end end end diff --git a/spec/models/iiif_playlist_canvas_presenter_spec.rb b/spec/models/iiif_playlist_canvas_presenter_spec.rb index dffc4bd6a0..3baf193a28 100644 --- a/spec/models/iiif_playlist_canvas_presenter_spec.rb +++ b/spec/models/iiif_playlist_canvas_presenter_spec.rb @@ -90,6 +90,19 @@ expect(subject.width).to eq 1280 expect(subject.height).to eq 40 end + + context 'with mp3 file' do + let(:mp3_url) { 'https://streaming.example.com/dir/file.mp3' } + let(:derivative) { FactoryBot.build(:derivative, hls_url: mp3_url, mime_type: 'audio/mpeg' ) } + + it 'has format' do + expect(subject.format).to eq 'audio/mpeg' + end + + it 'has progressive download url with media fragment' do + expect(subject.url).to eq "#{mp3_url}#t=#{playlist_item.start_time / 1000},#{playlist_item.end_time / 1000}" + end + end end context 'when video file' do @@ -105,6 +118,19 @@ expect(subject.width).to eq 1024 expect(subject.height).to eq 768 end + + context 'with mp4 file' do + let(:mp4_url) { 'https://streaming.example.com/dir/file.mp4' } + let(:derivative) { FactoryBot.build(:derivative, hls_url: mp4_url, mime_type: 'video/mp4' ) } + + it 'has format' do + expect(subject.format).to eq 'video/mp4' + end + + it 'has progressive download url with media fragment' do + expect(subject.url).to eq "#{mp4_url}#t=#{playlist_item.start_time / 1000},#{playlist_item.end_time / 1000}" + end + end end context 'when a user does not have access to a restricted item' do