diff --git a/app/assets/javascripts/materials.js b/app/assets/javascripts/materials.js new file mode 100644 index 000000000..1ec5544cc --- /dev/null +++ b/app/assets/javascripts/materials.js @@ -0,0 +1,27 @@ +function make_zenodo_video(video_element, files_url, preferred_key) { + const videoExtensions = ['.mp4', '.webm', '.ogg', '.ogv', '.mov', '.m4v', '.mkv']; + const audioExtensions = ['.mp3', '.ogg', '.wav', '.aac', '.flac', '.opus']; + video_element.parentElement.style.display = 'none'; + + fetch(files_url) + .then(response => response.json()) + .then(data => { + let video_file = null; + if (preferred_key != null) { + video_file = data.entries.find(file => file.key === String(preferred_key)); + } + if (!video_file) { + video_file = data.entries.find(file => videoExtensions.some(ext => file.key.toLowerCase().endsWith(ext))); + } + if (!video_file) { // fallback to audio + video_file = data.entries.find(file => audioExtensions.some(ext => file.key.toLowerCase().endsWith(ext))); + } + if (video_file) { + const video_url = video_file.links.content; + video_element.src = video_url; + video_element.style.display = 'block'; + video_element.parentElement.style.display = 'block'; + } + }) + .catch(error => console.error('Error fetching Zenodo files:', error)); +} \ No newline at end of file diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 51dca1c07..af8996f3e 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -886,10 +886,11 @@ input[type=checkbox].field-lock + label:before, .embedded-content { margin: 2em auto; + display: flex; + justify-content: center; iframe { display: block; - margin: auto; } } diff --git a/app/helpers/materials_helper.rb b/app/helpers/materials_helper.rb index 0fc4d362e..04e8ffe38 100644 --- a/app/helpers/materials_helper.rb +++ b/app/helpers/materials_helper.rb @@ -124,7 +124,15 @@ def display_attribute_no_label(resource, attribute, markdown: false, &block) # r end def embed_youtube(material) - renderer = Renderers::Youtube.new(material) + embed_video(Renderers::Youtube, material) + end + + def embed_zenodo(material) + embed_video(Renderers::Zenodo, material) + end + + def embed_video(renderer_class, material) + renderer = renderer_class.new(material) return unless renderer.can_render? content_tag(:div, class: 'embedded-content') do diff --git a/app/views/materials/show.html.erb b/app/views/materials/show.html.erb index e180b97b6..81131bcc6 100644 --- a/app/views/materials/show.html.erb +++ b/app/views/materials/show.html.erb @@ -47,6 +47,7 @@ <%= embed_youtube(@material) %> + <%= embed_zenodo(@material) %>
diff --git a/lib/renderers/zenodo.rb b/lib/renderers/zenodo.rb new file mode 100644 index 000000000..bd51c2cdd --- /dev/null +++ b/lib/renderers/zenodo.rb @@ -0,0 +1,33 @@ +module Renderers + class Zenodo + VALID_SCHEMES = %w[http https].freeze + TEMPLATE = %() + + def initialize(resource) + @url = resource.url + @parsed_url = begin + Addressable::URI.parse(@url) + rescue StandardError + nil + end + end + + def can_render? + @url && @parsed_url && zenodo_id && VALID_SCHEMES.include?(@parsed_url.scheme) + end + + def render_content + files_url = "https://zenodo.org/api/records/#{zenodo_id}/files" + key = @parsed_url.query_values.to_h['preview_file'] + format(TEMPLATE, files_url:, key: key.to_json).html_safe + end + + private + + def zenodo_id + match = @parsed_url.host == 'zenodo.org' && @url.match(%r{records/(\d+)}) || + @parsed_url.host == 'doi.org' && @url.match(%r{10\.5281/zenodo\.(\d+)}) + match[1] if match + end + end +end diff --git a/test/controllers/materials_controller_test.rb b/test/controllers/materials_controller_test.rb index adf68ac00..e388d9b9d 100644 --- a/test/controllers/materials_controller_test.rb +++ b/test/controllers/materials_controller_test.rb @@ -1353,6 +1353,14 @@ class MaterialsControllerTest < ActionController::TestCase assert_select 'div.embedded-content iframe[src=?]', 'https://www.youtube.com/embed/1T_2xMTQCv4' end + test 'can render embedded zenodo video' do + sign_in users(:regular_user) + get :show, params: { id: materials(:zenodo_video_material) } + assert_response :success + + assert_select 'div.embedded-content video#zenodo-video' + end + test 'no embedded content section if not available' do sign_in users(:regular_user) get :show, params: { id: materials(:good_material) } diff --git a/test/fixtures/materials.yml b/test/fixtures/materials.yml index 10eaa65a5..34de6f04d 100644 --- a/test/fixtures/materials.yml +++ b/test/fixtures/materials.yml @@ -172,6 +172,20 @@ youtube_video_material: - Video learning_objectives: In this video, I will show you how to create and run data quality checks in REDCap. +zenodo_video_material: + user: regular_user + title: 'How to Soften Hard Water?' + url: https://zenodo.org/records/17402249 + description: In this video, I will show you how to soften hard water. + licence: CC-BY-NC-4.0 + contact: contact@elixir-uk.org + keywords: + - water + - "hard water" + resource_type: + - Video + learning_objectives: In this video, I will show you how to soften hard water. + plant_space_material: user: regular_user title: Plant material