hyrax-iiif_av 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.rspec +1 -0
- data/.rubocop.yml +33 -0
- data/.travis.yml +23 -0
- data/Gemfile +41 -0
- data/LICENSE +201 -0
- data/README.md +43 -0
- data/Rakefile +47 -0
- data/app/controllers/concerns/hyrax/iiif_av/controller_behavior.rb +63 -0
- data/app/helpers/hyrax/iiif_av/iiif_av_helper.rb +40 -0
- data/app/presenters/concerns/hyrax/iiif_av/displays_content.rb +123 -0
- data/app/presenters/concerns/hyrax/iiif_av/displays_iiif_av.rb +87 -0
- data/app/presenters/hyrax/iiif_av/iiif_file_set_presenter.rb +14 -0
- data/app/views/hyrax/base/_representative_media.html.erb +27 -0
- data/app/views/hyrax/base/iiif_viewers/_universal_viewer.html.erb +4 -0
- data/bin/rails +15 -0
- data/hyrax-iiif_av.gemspec +33 -0
- data/lib/generators/hyrax/iiif_av/add_to_work_type_generator.rb +40 -0
- data/lib/generators/hyrax/iiif_av/install_avalon_player_generator.rb +40 -0
- data/lib/generators/hyrax/iiif_av/install_generator.rb +12 -0
- data/lib/generators/hyrax/iiif_av/templates/AvalonIiifPlayer.js +28 -0
- data/lib/generators/hyrax/iiif_av/templates/_avalon.html.erb +23 -0
- data/lib/hyrax/iiif_av.rb +8 -0
- data/lib/hyrax/iiif_av/engine.rb +12 -0
- data/lib/hyrax/iiif_av/manifest_range.rb +13 -0
- data/lib/hyrax/iiif_av/spec/shared_specs.rb +4 -0
- data/lib/hyrax/iiif_av/spec/shared_specs/controller_behavior.rb +208 -0
- data/lib/hyrax/iiif_av/spec/shared_specs/displays_content.rb +166 -0
- data/lib/hyrax/iiif_av/spec/shared_specs/displays_iiif_av.rb +129 -0
- data/lib/hyrax/iiif_av/version.rb +6 -0
- data/lib/tasks/hyrax/iiif_av_tasks.rake +5 -0
- metadata +221 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2011-2018, The Trustees of Indiana University and Northwestern
|
3
|
+
# University. Additional copyright may be held by others, as reflected in
|
4
|
+
# the commit history.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
# --- END LICENSE_HEADER BLOCK ---
|
18
|
+
|
19
|
+
module Hyrax
|
20
|
+
module IiifAv
|
21
|
+
module IiifAvHelper
|
22
|
+
def iiif_viewer_display(presenter, locals = {})
|
23
|
+
render iiif_viewer_display_partial(presenter),
|
24
|
+
locals.merge(presenter: presenter)
|
25
|
+
end
|
26
|
+
|
27
|
+
def iiif_viewer_display_partial(work_presenter)
|
28
|
+
'hyrax/base/iiif_viewers/' + iiif_viewer_for_work(work_presenter).to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
def iiif_viewer_for_work(work_presenter)
|
32
|
+
if work_presenter.respond_to? :iiif_viewer
|
33
|
+
work_presenter.iiif_viewer
|
34
|
+
else
|
35
|
+
:universal_viewer
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2011-2018, The Trustees of Indiana University and Northwestern
|
3
|
+
# University. Additional copyright may be held by others, as reflected in
|
4
|
+
# the commit history.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
# --- END LICENSE_HEADER BLOCK ---
|
18
|
+
|
19
|
+
require 'iiif_manifest'
|
20
|
+
|
21
|
+
module Hyrax
|
22
|
+
module IiifAv
|
23
|
+
# This gets mixed into IiifFileSetPresenter in order to create
|
24
|
+
# a canvas on a IIIF manifest
|
25
|
+
module DisplaysContent
|
26
|
+
extend ActiveSupport::Concern
|
27
|
+
|
28
|
+
# Creates a display content only where FileSet is an image, audio, or video.
|
29
|
+
#
|
30
|
+
# @return [IIIFManifest::V3::DisplayContent] the display content required by the manifest builder.
|
31
|
+
def display_content
|
32
|
+
return nil unless display_content_allowed?
|
33
|
+
|
34
|
+
return image_content if solr_document.image?
|
35
|
+
return video_content if solr_document.video?
|
36
|
+
return audio_content if solr_document.audio?
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def display_content_allowed?
|
42
|
+
content_supported? && current_ability.can?(:read, id)
|
43
|
+
end
|
44
|
+
|
45
|
+
def content_supported?
|
46
|
+
solr_document.video? || solr_document.audio? || solr_document.image?
|
47
|
+
end
|
48
|
+
|
49
|
+
def image_content
|
50
|
+
url = Hyrax.config.iiif_image_url_builder.call(
|
51
|
+
solr_document.id,
|
52
|
+
request.base_url,
|
53
|
+
Hyrax.config.iiif_image_size_default
|
54
|
+
)
|
55
|
+
|
56
|
+
# Look at the request and target prezi 2 or 3 for images
|
57
|
+
parent.iiif_version == 3 ? image_content_v3(url) : image_content_v2(url)
|
58
|
+
end
|
59
|
+
|
60
|
+
def image_content_v3(url)
|
61
|
+
# @see https://github.com/samvera-labs/iiif_manifest
|
62
|
+
IIIFManifest::V3::DisplayContent.new(url,
|
63
|
+
width: 640,
|
64
|
+
height: 480,
|
65
|
+
type: 'Image',
|
66
|
+
iiif_endpoint: iiif_endpoint(solr_document.id))
|
67
|
+
end
|
68
|
+
|
69
|
+
def image_content_v2(url)
|
70
|
+
# @see https://github.com/samvera-labs/iiif_manifest
|
71
|
+
IIIFManifest::DisplayImage.new(url,
|
72
|
+
width: 640,
|
73
|
+
height: 480,
|
74
|
+
iiif_endpoint: iiif_endpoint(solr_document.id))
|
75
|
+
end
|
76
|
+
|
77
|
+
def video_content
|
78
|
+
# @see https://github.com/samvera-labs/iiif_manifest
|
79
|
+
if solr_document['derivatives_metadata_ssi'].present?
|
80
|
+
files_metadata = JSON.parse(solr_document['derivatives_metadata_ssi'])
|
81
|
+
external_files = files_metadata.select { |f| f['external_file_uri'].present? }
|
82
|
+
unless external_files.empty?
|
83
|
+
return external_files.map do |f|
|
84
|
+
uri = URI(f['external_file_uri'])
|
85
|
+
uri = URI.join(request.base_url, uri) if uri.relative?
|
86
|
+
video_display_content(uri, f['label'])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
[video_display_content(download_path('mp4'), 'mp4'), video_display_content(download_path('webm'), 'webm')]
|
91
|
+
end
|
92
|
+
|
93
|
+
def video_display_content(url, label = '')
|
94
|
+
IIIFManifest::V3::DisplayContent.new(url,
|
95
|
+
label: label,
|
96
|
+
width: Array(solr_document.width).first.try(:to_i),
|
97
|
+
height: Array(solr_document.height).first.try(:to_i),
|
98
|
+
duration: Array(solr_document.duration).first.try(:to_i) / 1000.0,
|
99
|
+
type: 'Video')
|
100
|
+
end
|
101
|
+
|
102
|
+
def audio_content
|
103
|
+
if solr_document['derivatives_metadata_ssi'].present?
|
104
|
+
files_metadata = JSON.parse(solr_document['derivatives_metadata_ssi'])
|
105
|
+
external_files = files_metadata.select { |f| f['external_file_uri'].present? }
|
106
|
+
return external_files.map { |f| audio_display_content(f['external_file_uri'], f['label']) } unless external_files.empty?
|
107
|
+
end
|
108
|
+
[audio_display_content(download_path('ogg'), 'ogg'), audio_display_content(download_path('mp3'), 'mp3')]
|
109
|
+
end
|
110
|
+
|
111
|
+
def audio_display_content(url, label = '')
|
112
|
+
IIIFManifest::V3::DisplayContent.new(url,
|
113
|
+
label: label,
|
114
|
+
duration: Array(solr_document.duration).first.try(:to_i) / 1000.0,
|
115
|
+
type: 'Sound')
|
116
|
+
end
|
117
|
+
|
118
|
+
def download_path(extension)
|
119
|
+
Hyrax::Engine.routes.url_helpers.download_url(solr_document, file: extension, host: request.base_url)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2011-2018, The Trustees of Indiana University and Northwestern
|
4
|
+
# University. Additional copyright may be held by others, as reflected in
|
5
|
+
# the commit history.
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
# --- END LICENSE_HEADER BLOCK ---
|
19
|
+
|
20
|
+
require 'hyrax/iiif_av/manifest_range'
|
21
|
+
|
22
|
+
module Hyrax
|
23
|
+
module IiifAv
|
24
|
+
module DisplaysIiifAv
|
25
|
+
extend ActiveSupport::Concern
|
26
|
+
|
27
|
+
IIIF_DEFAULT_VERSION = 2
|
28
|
+
IIIF_DEFAULT_MANIFEST_MIME = "application/json;profile=http://iiif.io/api/presentation/#{IIIF_DEFAULT_VERSION}/context.json"
|
29
|
+
|
30
|
+
# @return [Boolean] render a IIIF viewer
|
31
|
+
def iiif_viewer?
|
32
|
+
representative_id.present? &&
|
33
|
+
representative_presenter.present? &&
|
34
|
+
(representative_presenter.video? ||
|
35
|
+
representative_presenter.audio? ||
|
36
|
+
(representative_presenter.image? && Hyrax.config.iiif_image_server?))
|
37
|
+
end
|
38
|
+
|
39
|
+
alias universal_viewer? iiif_viewer?
|
40
|
+
# deprecation_deprecate universal_viewer?: "use iiif_viewer? instead"
|
41
|
+
|
42
|
+
def iiif_viewer
|
43
|
+
if representative_presenter.video? || representative_presenter.audio?
|
44
|
+
:avalon
|
45
|
+
elsif representative_presenter.image?
|
46
|
+
:universal_viewer
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return the highest IIIF version (as an integer) specified in the Accept request header, or the default version if none specified
|
51
|
+
def iiif_version
|
52
|
+
accept = parse_accept(request.headers['Accept'])
|
53
|
+
return accept if accept.present?
|
54
|
+
if representative_presenter.present? &&
|
55
|
+
(representative_presenter.video? ||
|
56
|
+
representative_presenter.audio?)
|
57
|
+
3
|
58
|
+
else
|
59
|
+
IIIF_DEFAULT_VERSION
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def ranges
|
64
|
+
[
|
65
|
+
Hyrax::IiifAv::ManifestRange.new(
|
66
|
+
label: { '@none'.to_sym => title.first },
|
67
|
+
items: file_set_presenters.collect(&:range)
|
68
|
+
)
|
69
|
+
]
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def parse_accept(accept)
|
75
|
+
return nil if accept.blank?
|
76
|
+
version = 0 # assume all valid versions will be at least greater than 0
|
77
|
+
# check for multiple profiles for highest IIIF version. Note: only digits are allowed in the version number
|
78
|
+
regexp = Regexp.new(Regexp.escape(IIIF_DEFAULT_MANIFEST_MIME[/profile.*$/]).gsub("/#{IIIF_DEFAULT_VERSION}/", "/(\\d+)/"))
|
79
|
+
accept.scan(regexp).each do |matched|
|
80
|
+
v = matched[0].to_i
|
81
|
+
version = v > version ? v : version
|
82
|
+
end
|
83
|
+
version.zero? ? nil : version
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hyrax
|
4
|
+
module IiifAv
|
5
|
+
class IiifFileSetPresenter < ::Hyrax::FileSetPresenter
|
6
|
+
include Hyrax::IiifAv::DisplaysContent
|
7
|
+
|
8
|
+
# Override this to include ranges in your manifest
|
9
|
+
def range
|
10
|
+
[]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<%#
|
2
|
+
Copyright 2011-2018, The Trustees of Indiana University and Northwestern
|
3
|
+
University. Additional copyright may be held by others, as reflected in
|
4
|
+
the commit history.
|
5
|
+
|
6
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
you may not use this file except in compliance with the License.
|
8
|
+
You may obtain a copy of the License at
|
9
|
+
|
10
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
|
12
|
+
Unless required by applicable law or agreed to in writing, software
|
13
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
See the License for the specific language governing permissions and
|
16
|
+
limitations under the License.
|
17
|
+
--- END LICENSE_HEADER BLOCK ---
|
18
|
+
%>
|
19
|
+
<% if presenter.representative_id.present? && presenter.representative_presenter.present? %>
|
20
|
+
<% if defined?(viewer) && viewer %>
|
21
|
+
<%= iiif_viewer_display presenter %>
|
22
|
+
<% else %>
|
23
|
+
<%= media_display presenter.representative_presenter %>
|
24
|
+
<% end %>
|
25
|
+
<% else %>
|
26
|
+
<%= image_tag 'default.png', class: "canonical-image" %>
|
27
|
+
<% end %>
|
data/bin/rails
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
# This command will automatically be run when you run "rails" with Rails gems
|
4
|
+
# installed from the root of your application.
|
5
|
+
|
6
|
+
ENGINE_ROOT = File.expand_path('..', __dir__)
|
7
|
+
ENGINE_PATH = File.expand_path('../lib/hyrax/iiif_av/engine', __dir__)
|
8
|
+
# APP_PATH = File.expand_path('../.internal_test_app/config/application', __dir__)
|
9
|
+
|
10
|
+
# Set up gems listed in the Gemfile.
|
11
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
12
|
+
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
13
|
+
|
14
|
+
require 'rails/all'
|
15
|
+
require 'rails/engine/commands'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.push File.expand_path("lib", __dir__)
|
4
|
+
|
5
|
+
# Maintain your gem's version:
|
6
|
+
require "hyrax/iiif_av/version"
|
7
|
+
|
8
|
+
# Describe your gem and declare its dependencies:
|
9
|
+
Gem::Specification.new do |s|
|
10
|
+
s.name = "hyrax-iiif_av"
|
11
|
+
s.version = Hyrax::IiifAv::VERSION
|
12
|
+
s.authors = ["Chris Colvard", "Brian Keese", "Ying Feng", "Phuong Dinh"]
|
13
|
+
s.email = ["cjcolvar@indiana.edu", "bkeese@indiana.edu", "yingfeng@iu.edu", "phuongdh@gmail.com"]
|
14
|
+
s.summary = "Hyrax plugin for IIIF Presentation 3.0 audiovisual support"
|
15
|
+
s.description = "Hyrax plugin for IIIF Presentation 3.0 audiovisual support"
|
16
|
+
s.license = 'Apache-2.0'
|
17
|
+
|
18
|
+
s.files = `git ls-files -z`.split("\x0").reject do |f|
|
19
|
+
f.match(%r{^(test|spec|features)/})
|
20
|
+
end
|
21
|
+
|
22
|
+
s.add_dependency "rails", "~>5.1"
|
23
|
+
s.add_dependency "blacklight"
|
24
|
+
s.add_dependency "hyrax", "~> 2.1"
|
25
|
+
s.add_dependency "iiif_manifest", "~> 0.5"
|
26
|
+
|
27
|
+
s.add_development_dependency 'bixby'
|
28
|
+
s.add_development_dependency 'coffee-rails'
|
29
|
+
s.add_development_dependency 'engine_cart', '~> 2.0'
|
30
|
+
s.add_development_dependency 'factory_bot_rails'
|
31
|
+
s.add_development_dependency 'rails-controller-testing'
|
32
|
+
s.add_development_dependency 'rspec-rails', '~> 3.8'
|
33
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'rails/generators'
|
3
|
+
require 'rails/generators/model_helpers'
|
4
|
+
|
5
|
+
module Hyrax
|
6
|
+
module IiifAv
|
7
|
+
class AddToWorkTypeGenerator < Rails::Generators::NamedBase
|
8
|
+
# ActiveSupport can interpret models as plural which causes
|
9
|
+
# counter-intuitive route paths. Pull in ModelHelpers from
|
10
|
+
# Rails which warns users about pluralization when generating
|
11
|
+
# new models or scaffolds.
|
12
|
+
include Rails::Generators::ModelHelpers
|
13
|
+
|
14
|
+
def inject_into_controller
|
15
|
+
controller_file = File.join('app/controllers/hyrax', class_path, "#{plural_file_name}_controller.rb")
|
16
|
+
insert_into_file controller_file, after: 'include Hyrax::BreadcrumbsForWorks' do
|
17
|
+
"\n" \
|
18
|
+
" # Adds behaviors for hyrax-iiif_av plugin.\n" \
|
19
|
+
" include Hyrax::IiifAv::ControllerBehavior"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def inject_into_presenter
|
24
|
+
presenter_file = File.join('app/presenters/hyrax', class_path, "#{file_name}_presenter.rb")
|
25
|
+
insert_into_file presenter_file, after: '< Hyrax::WorkShowPresenter' do
|
26
|
+
"\n" \
|
27
|
+
" # Adds behaviors for hyrax-iiif_av plugin.\n" \
|
28
|
+
" include Hyrax::IiifAv::DisplaysIiifAv\n" \
|
29
|
+
" Hyrax::MemberPresenterFactory.file_presenter_class = Hyrax::IiifAv::IiifFileSetPresenter\n" \
|
30
|
+
"\n" \
|
31
|
+
" # Optional override to select iiif viewer to render\n" \
|
32
|
+
" # default :avalon for audio and video, :universal_viewer for images\n" \
|
33
|
+
" # def iiif_viewer\n" \
|
34
|
+
" # :avalon\n" \
|
35
|
+
" # end"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'rails/generators'
|
3
|
+
|
4
|
+
module Hyrax
|
5
|
+
module IiifAv
|
6
|
+
class InstallAvalonPlayerGenerator < Rails::Generators::Base
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
def install_dependencies
|
10
|
+
gem 'webpacker'
|
11
|
+
gem 'react-rails'
|
12
|
+
|
13
|
+
Bundler.with_clean_env do
|
14
|
+
run "bundle install"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def webpacker_install
|
19
|
+
rake("webpacker:install")
|
20
|
+
end
|
21
|
+
|
22
|
+
def react_install
|
23
|
+
rake("webpacker:install:react")
|
24
|
+
generate "react:install"
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_avalon_yarn_dependency
|
28
|
+
`yarn add react-iiif-media-player`
|
29
|
+
end
|
30
|
+
|
31
|
+
def copy_avalon_player
|
32
|
+
copy_file '_avalon.html.erb', 'app/views/hyrax/base/iiif_viewers/_avalon.html.erb'
|
33
|
+
end
|
34
|
+
|
35
|
+
def copy_avalon_react_component
|
36
|
+
copy_file 'AvalonIiifPlayer.js', 'app/javascript/components/AvalonIiifPlayer.js'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|