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.
Files changed (33) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +33 -0
  5. data/.travis.yml +23 -0
  6. data/Gemfile +41 -0
  7. data/LICENSE +201 -0
  8. data/README.md +43 -0
  9. data/Rakefile +47 -0
  10. data/app/controllers/concerns/hyrax/iiif_av/controller_behavior.rb +63 -0
  11. data/app/helpers/hyrax/iiif_av/iiif_av_helper.rb +40 -0
  12. data/app/presenters/concerns/hyrax/iiif_av/displays_content.rb +123 -0
  13. data/app/presenters/concerns/hyrax/iiif_av/displays_iiif_av.rb +87 -0
  14. data/app/presenters/hyrax/iiif_av/iiif_file_set_presenter.rb +14 -0
  15. data/app/views/hyrax/base/_representative_media.html.erb +27 -0
  16. data/app/views/hyrax/base/iiif_viewers/_universal_viewer.html.erb +4 -0
  17. data/bin/rails +15 -0
  18. data/hyrax-iiif_av.gemspec +33 -0
  19. data/lib/generators/hyrax/iiif_av/add_to_work_type_generator.rb +40 -0
  20. data/lib/generators/hyrax/iiif_av/install_avalon_player_generator.rb +40 -0
  21. data/lib/generators/hyrax/iiif_av/install_generator.rb +12 -0
  22. data/lib/generators/hyrax/iiif_av/templates/AvalonIiifPlayer.js +28 -0
  23. data/lib/generators/hyrax/iiif_av/templates/_avalon.html.erb +23 -0
  24. data/lib/hyrax/iiif_av.rb +8 -0
  25. data/lib/hyrax/iiif_av/engine.rb +12 -0
  26. data/lib/hyrax/iiif_av/manifest_range.rb +13 -0
  27. data/lib/hyrax/iiif_av/spec/shared_specs.rb +4 -0
  28. data/lib/hyrax/iiif_av/spec/shared_specs/controller_behavior.rb +208 -0
  29. data/lib/hyrax/iiif_av/spec/shared_specs/displays_content.rb +166 -0
  30. data/lib/hyrax/iiif_av/spec/shared_specs/displays_iiif_av.rb +129 -0
  31. data/lib/hyrax/iiif_av/version.rb +6 -0
  32. data/lib/tasks/hyrax/iiif_av_tasks.rake +5 -0
  33. 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 %>
@@ -0,0 +1,4 @@
1
+ <%= PulUvRails::UniversalViewer.script_tag %>
2
+ <div class="viewer-wrapper">
3
+ <div class="uv viewer" data-uri="<%= main_app.polymorphic_path [main_app, :manifest, presenter], { locale: nil } %>"></div>
4
+ </div>
@@ -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
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ require 'rails/generators'
3
+
4
+ module Hyrax
5
+ module IiifAv
6
+ class InstallGenerator < Rails::Generators::Base
7
+ source_root File.expand_path('../templates', __FILE__)
8
+
9
+ # Do nothing for now
10
+ end
11
+ end
12
+ end