sufia-models 3.0.0 → 3.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 +4 -4
- data/app/models/datastreams/file_content_datastream.rb +1 -15
- data/app/models/geo_names_resource.rb +0 -2
- data/lib/sufia/models.rb +1 -1
- data/lib/sufia/models/engine.rb +12 -1
- data/lib/sufia/models/file_content.rb +0 -3
- data/lib/sufia/models/generic_file.rb +6 -10
- data/lib/sufia/models/generic_file/actions.rb +1 -1
- data/lib/sufia/models/generic_file/characterization.rb +1 -1
- data/lib/sufia/models/generic_file/derivatives.rb +31 -0
- data/lib/sufia/models/generic_file/mime_types.rb +27 -0
- data/lib/sufia/models/generic_file/thumbnail.rb +6 -60
- data/lib/sufia/models/jobs/active_fedora_pid_based_job.rb +19 -0
- data/lib/sufia/models/jobs/audit_job.rb +12 -8
- data/lib/sufia/models/jobs/characterize_job.rb +3 -10
- data/lib/sufia/models/jobs/import_url_job.rb +2 -9
- data/lib/sufia/models/jobs/resolrize_job.rb +8 -1
- data/lib/sufia/models/jobs/transcode_audio_job.rb +4 -28
- data/lib/sufia/models/jobs/transcode_video_job.rb +4 -28
- data/lib/sufia/models/jobs/unzip_job.rb +5 -19
- data/lib/sufia/models/model_methods.rb +2 -16
- data/lib/sufia/models/user_local_directory_behavior.rb +29 -0
- data/lib/sufia/models/version.rb +1 -1
- data/sufia-models.gemspec +1 -1
- metadata +21 -19
- data/lib/sufia/models/file_content/extract_metadata.rb +0 -60
- data/lib/sufia/models/jobs/ffmpeg_transcode_job.rb +0 -61
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9476084b14b4f2ae7d223df7c2fa01adfe908d2b
|
4
|
+
data.tar.gz: 13905aa01d70e375b30ab10ab9b1976b64370076
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12b4d9d871804e7627179916e96e9b811589db27bdfdec2b826800e5b0cacb736d13994081e31118f06c3d93a4a4a4a7a86fab4dc1c686c2e8ebb76ff9a8b0b8
|
7
|
+
data.tar.gz: e46ccc9c4efc212f32cefea6dad8bc97cb90bd7b057f6c335371042c76f46af36bcb9d27ca59bad3a3365c58b31e58c4c46b1f1fc3154a3dbc3516acae02af2d
|
@@ -1,18 +1,4 @@
|
|
1
|
-
# Copyright © 2012 The Pennsylvania State University
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
|
-
|
15
1
|
class FileContentDatastream < ActiveFedora::Datastream
|
16
|
-
include
|
2
|
+
include Hydra::Derivatives::ExtractMetadata
|
17
3
|
include Sufia::FileContent::Versions
|
18
4
|
end
|
data/lib/sufia/models.rb
CHANGED
@@ -5,7 +5,7 @@ require 'nest'
|
|
5
5
|
require 'mailboxer'
|
6
6
|
require 'acts_as_follower'
|
7
7
|
require 'paperclip'
|
8
|
-
require
|
8
|
+
require "active_resource" # used by GenericFile to catch errors & by GeoNamesResource
|
9
9
|
begin
|
10
10
|
# activerecord-import 0.3.1 does not support rails 4, so we don't require it.
|
11
11
|
require 'activerecord-import'
|
data/lib/sufia/models/engine.rb
CHANGED
@@ -22,6 +22,7 @@ module Sufia
|
|
22
22
|
config.fits_path = "fits.sh"
|
23
23
|
config.enable_contact_form_delivery = false
|
24
24
|
config.dropbox_api_key = nil
|
25
|
+
config.enable_local_ingest = nil
|
25
26
|
config.queue = Sufia::Resque::Queue
|
26
27
|
|
27
28
|
config.autoload_paths += %W(
|
@@ -40,22 +41,32 @@ module Sufia
|
|
40
41
|
end
|
41
42
|
|
42
43
|
initializer 'requires' do
|
44
|
+
require 'hydra/derivatives'
|
43
45
|
require 'sufia/models/model_methods'
|
44
46
|
require 'sufia/models/noid'
|
45
47
|
require 'sufia/models/file_content'
|
46
|
-
require 'sufia/models/file_content/extract_metadata'
|
47
48
|
require 'sufia/models/file_content/versions'
|
48
49
|
require 'sufia/models/generic_file/actions'
|
49
50
|
require 'sufia/models/generic_file/audit'
|
50
51
|
require 'sufia/models/generic_file/characterization'
|
52
|
+
require 'sufia/models/generic_file/derivatives'
|
51
53
|
require 'sufia/models/generic_file/export'
|
54
|
+
require 'sufia/models/generic_file/mime_types'
|
52
55
|
require 'sufia/models/generic_file/permissions'
|
53
56
|
require 'sufia/models/generic_file/thumbnail'
|
54
57
|
require 'sufia/models/generic_file'
|
55
58
|
require 'sufia/models/user'
|
59
|
+
require 'sufia/models/user_local_directory_behavior'
|
56
60
|
require 'sufia/models/id_service'
|
57
61
|
require 'sufia/models/solr_document_behavior'
|
58
62
|
end
|
63
|
+
|
64
|
+
initializer 'configure' do
|
65
|
+
Hydra::Derivatives.ffmpeg_path = Sufia.config.ffmpeg_path
|
66
|
+
Hydra::Derivatives.temp_file_base = Sufia.config.temp_file_base
|
67
|
+
Hydra::Derivatives.fits_path = Sufia.config.fits_path
|
68
|
+
Hydra::Derivatives.enable_ffmpeg = Sufia.config.enable_ffmpeg
|
69
|
+
end
|
59
70
|
end
|
60
71
|
end
|
61
72
|
end
|
@@ -2,22 +2,20 @@ module Sufia
|
|
2
2
|
module GenericFile
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
extend ActiveSupport::Autoload
|
5
|
-
autoload :Export
|
6
|
-
autoload :Thumbnail
|
7
|
-
autoload :Characterization
|
8
|
-
autoload :Audit
|
9
5
|
autoload :Actions
|
10
6
|
autoload :Permissions
|
11
7
|
autoload :WebForm, 'sufia/models/generic_file/web_form'
|
12
8
|
autoload :AccessibleAttributes, 'sufia/models/generic_file/accessible_attributes'
|
13
9
|
include Sufia::ModelMethods
|
14
10
|
include Sufia::Noid
|
11
|
+
include Sufia::GenericFile::MimeTypes
|
15
12
|
include Sufia::GenericFile::Thumbnail
|
16
13
|
include Sufia::GenericFile::Export
|
17
14
|
include Sufia::GenericFile::Characterization
|
18
15
|
include Sufia::GenericFile::Audit
|
19
16
|
include Sufia::GenericFile::Permissions
|
20
17
|
include Sufia::GenericFile::WebForm
|
18
|
+
include Sufia::GenericFile::Derivatives
|
21
19
|
|
22
20
|
included do
|
23
21
|
has_metadata :name => "descMetadata", :type => GenericFileRdfDatastream
|
@@ -52,21 +50,19 @@ module Sufia
|
|
52
50
|
end
|
53
51
|
|
54
52
|
def pdf?
|
55
|
-
|
53
|
+
self.class.pdf_mime_types.include? self.mime_type
|
56
54
|
end
|
57
55
|
|
58
56
|
def image?
|
59
|
-
|
57
|
+
self.class.image_mime_types.include? self.mime_type
|
60
58
|
end
|
61
59
|
|
62
60
|
def video?
|
63
|
-
|
61
|
+
self.class.video_mime_types.include? self.mime_type
|
64
62
|
end
|
65
63
|
|
66
64
|
def audio?
|
67
|
-
|
68
|
-
# audio/mpeg is the mime type that fits 0.6.0 returns for an mp3 file.
|
69
|
-
['audio/mp3', 'audio/mpeg', 'audio/x-wave', 'audio/x-wav', 'audio/ogg'].include? self.mime_type
|
65
|
+
self.class.audio_mime_types.include? self.mime_type
|
70
66
|
end
|
71
67
|
|
72
68
|
def persistent_url
|
@@ -3,7 +3,7 @@ module Sufia::GenericFile
|
|
3
3
|
module Actions
|
4
4
|
def self.create_metadata(generic_file, user, batch_id)
|
5
5
|
|
6
|
-
generic_file.apply_depositor_metadata(user
|
6
|
+
generic_file.apply_depositor_metadata(user)
|
7
7
|
generic_file.date_uploaded = Date.today
|
8
8
|
generic_file.date_modified = Date.today
|
9
9
|
generic_file.creator = user.name
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Sufia
|
2
|
+
module GenericFile
|
3
|
+
module Derivatives
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
include Hydra::Derivatives
|
8
|
+
|
9
|
+
makes_derivatives do |obj|
|
10
|
+
case obj.mime_type
|
11
|
+
when *pdf_mime_types
|
12
|
+
obj.transform_datastream :content,
|
13
|
+
{ :thumbnail => {size: "338x493", datastream: 'thumbnail'} }
|
14
|
+
when *audio_mime_types
|
15
|
+
obj.transform_datastream :content,
|
16
|
+
{ :mp3 => {format: 'mp3', datastream: 'mp3'},
|
17
|
+
:ogg => {format: 'ogg', datastream: 'ogg'} }, processor: :audio
|
18
|
+
when *video_mime_types
|
19
|
+
obj.transform_datastream :content,
|
20
|
+
{ :webm => {format: "webm", datastream: 'webm'},
|
21
|
+
:mp4 => {format: "mp4", datastream: 'mp4'} }, processor: :video
|
22
|
+
when *image_mime_types
|
23
|
+
obj.transform_datastream :content, { :thumbnail => {size: "200x150>", datastream: 'thumbnail'} }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Sufia
|
2
|
+
module GenericFile
|
3
|
+
module MimeTypes
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def image_mime_types
|
8
|
+
['image/png','image/jpeg', 'image/jpg', 'image/jp2', 'image/bmp', 'image/gif']
|
9
|
+
end
|
10
|
+
|
11
|
+
def pdf_mime_types
|
12
|
+
['application/pdf']
|
13
|
+
end
|
14
|
+
|
15
|
+
def video_mime_types
|
16
|
+
['video/mpeg', 'video/mp4', 'video/webm', 'video/x-msvideo', 'video/avi', 'video/quicktime', 'application/mxf']
|
17
|
+
end
|
18
|
+
|
19
|
+
def audio_mime_types
|
20
|
+
# audio/x-wave is the mime type that fits 0.6.0 returns for a wav file.
|
21
|
+
# audio/mpeg is the mime type that fits 0.6.0 returns for an mp3 file.
|
22
|
+
['audio/mp3', 'audio/mpeg', 'audio/wav', 'audio/x-wave', 'audio/x-wav', 'audio/ogg']
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,17 +1,18 @@
|
|
1
1
|
module Sufia
|
2
2
|
module GenericFile
|
3
3
|
module Thumbnail
|
4
|
+
extend ActiveSupport::Concern
|
4
5
|
# Create thumbnail requires that the characterization has already been run (so mime_type, width and height is available)
|
5
6
|
# and that the object is already has a pid set
|
6
7
|
def create_thumbnail
|
7
8
|
return unless self.content.has_content?
|
8
|
-
|
9
|
-
|
10
|
-
elsif image?
|
11
|
-
create_image_thumbnail
|
12
|
-
elsif video?
|
9
|
+
|
10
|
+
if video?
|
13
11
|
create_video_thumbnail
|
12
|
+
else
|
13
|
+
create_derivatives
|
14
14
|
end
|
15
|
+
self.save
|
15
16
|
end
|
16
17
|
|
17
18
|
protected
|
@@ -29,61 +30,6 @@ module Sufia
|
|
29
30
|
|
30
31
|
self.thumbnail.content = File.open(output_file, 'rb').read
|
31
32
|
self.thumbnail.mimeType = 'image/png'
|
32
|
-
self.save
|
33
|
-
end
|
34
|
-
|
35
|
-
def create_pdf_thumbnail
|
36
|
-
retryCnt = 0
|
37
|
-
stat = false;
|
38
|
-
for retryCnt in 1..3
|
39
|
-
begin
|
40
|
-
pdf = load_image_transformer
|
41
|
-
first = pdf.to_a[0]
|
42
|
-
first.format = "PNG"
|
43
|
-
thumb = first.scale(338, 493)
|
44
|
-
self.thumbnail.content = thumb.to_blob { self.format = "PNG" }
|
45
|
-
self.thumbnail.mimeType = 'image/png'
|
46
|
-
self.save
|
47
|
-
break
|
48
|
-
rescue => e
|
49
|
-
logger.warn "Rescued an error #{e.inspect} retry count = #{retryCnt}"
|
50
|
-
sleep 1
|
51
|
-
end
|
52
|
-
end
|
53
|
-
return stat
|
54
|
-
end
|
55
|
-
|
56
|
-
def create_image_thumbnail
|
57
|
-
self.thumbnail.content = scale_image.to_blob { self.format = "PNG" }
|
58
|
-
self.thumbnail.mimeType = 'image/png'
|
59
|
-
#logger.debug "Has the content before saving? #{self.content.changed?}"
|
60
|
-
self.save
|
61
|
-
end
|
62
|
-
|
63
|
-
def scale_image
|
64
|
-
img = load_image_transformer
|
65
|
-
height = Float(self.height.first.to_i)
|
66
|
-
width = Float(self.width.first.to_i)
|
67
|
-
if width > height && width > 150 && height > 105
|
68
|
-
# horizontal img
|
69
|
-
scale = 150 / width
|
70
|
-
img.scale(150, height * scale)
|
71
|
-
elsif height >= width && width > 150 && height > 200
|
72
|
-
# vertical or square
|
73
|
-
scale = 200 / height
|
74
|
-
img.scale(width*scale, 200)
|
75
|
-
else
|
76
|
-
# Too small to worry about resizing
|
77
|
-
img
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# Override this method if you want a different transformer, or need to load the
|
82
|
-
# raw image from a different source (e.g. external datastream)
|
83
|
-
def load_image_transformer
|
84
|
-
xformer = Magick::ImageList.new
|
85
|
-
xformer.from_blob(content.content)
|
86
|
-
xformer
|
87
33
|
end
|
88
34
|
|
89
35
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class ActiveFedoraPidBasedJob
|
2
|
+
def queue_name
|
3
|
+
:pid_based
|
4
|
+
end
|
5
|
+
|
6
|
+
attr_accessor :pid
|
7
|
+
def initialize(pid)
|
8
|
+
self.pid = pid
|
9
|
+
end
|
10
|
+
def object
|
11
|
+
@object ||= ActiveFedora::Base.find(pid, cast:true)
|
12
|
+
end
|
13
|
+
alias_method :generic_file, :object
|
14
|
+
alias_method :generic_file_id, :pid
|
15
|
+
|
16
|
+
def run
|
17
|
+
raise RuntimeError, "Define #run in a subclass"
|
18
|
+
end
|
19
|
+
end
|
@@ -12,7 +12,7 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
class AuditJob
|
15
|
+
class AuditJob < ActiveFedoraPidBasedJob
|
16
16
|
def queue_name
|
17
17
|
:audit
|
18
18
|
end
|
@@ -20,16 +20,15 @@ class AuditJob
|
|
20
20
|
PASS = 'Passing Audit Run'
|
21
21
|
FAIL = 'Failing Audit Run'
|
22
22
|
|
23
|
-
attr_accessor :
|
23
|
+
attr_accessor :pid, :datastream_id, :version_id
|
24
24
|
|
25
|
-
def initialize(
|
26
|
-
|
25
|
+
def initialize(pid, datastream_id, version_id)
|
26
|
+
super(pid)
|
27
27
|
self.datastream_id = datastream_id
|
28
28
|
self.version_id = version_id
|
29
29
|
end
|
30
30
|
|
31
31
|
def run
|
32
|
-
generic_file = GenericFile.find(generic_file_id)
|
33
32
|
#logger.info "GF is #{generic_file.pid}"
|
34
33
|
if generic_file
|
35
34
|
datastream = generic_file.datastreams[datastream_id]
|
@@ -37,7 +36,7 @@ class AuditJob
|
|
37
36
|
if datastream
|
38
37
|
#logger.info "Datastream for audit = #{datastream.inspect}"
|
39
38
|
version = datastream.versions.select { |v| v.versionID == version_id}.first
|
40
|
-
log =
|
39
|
+
log = run_audit(version)
|
41
40
|
|
42
41
|
# look up the user for sending the message to
|
43
42
|
login = generic_file.depositor
|
@@ -56,10 +55,15 @@ class AuditJob
|
|
56
55
|
end
|
57
56
|
end
|
58
57
|
else
|
59
|
-
logger.warn "No datastream for audit!!!!! pid: #{
|
58
|
+
logger.warn "No datastream for audit!!!!! pid: #{pid} dsid: #{datastream_id}"
|
60
59
|
end
|
61
60
|
else
|
62
|
-
logger.warn "No generic file for data stream audit!!!!! pid: #{
|
61
|
+
logger.warn "No generic file for data stream audit!!!!! pid: #{pid} dsid: #{datastream_id}"
|
63
62
|
end
|
64
63
|
end
|
64
|
+
|
65
|
+
private
|
66
|
+
def run_audit(version)
|
67
|
+
object.class.run_audit(version)
|
68
|
+
end
|
65
69
|
end
|
@@ -12,20 +12,13 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
class CharacterizeJob
|
15
|
+
class CharacterizeJob < ActiveFedoraPidBasedJob
|
16
16
|
|
17
17
|
def queue_name
|
18
18
|
:characterize
|
19
19
|
end
|
20
20
|
|
21
|
-
attr_accessor :generic_file_id, :generic_file
|
22
|
-
|
23
|
-
def initialize(generic_file_id)
|
24
|
-
self.generic_file_id = generic_file_id
|
25
|
-
end
|
26
|
-
|
27
21
|
def run
|
28
|
-
self.generic_file = GenericFile.find(generic_file_id)
|
29
22
|
generic_file.characterize
|
30
23
|
after_characterize
|
31
24
|
end
|
@@ -35,9 +28,9 @@ class CharacterizeJob
|
|
35
28
|
generic_file.create_thumbnail
|
36
29
|
end
|
37
30
|
if generic_file.video?
|
38
|
-
Sufia.queue.push(TranscodeVideoJob.new(generic_file_id
|
31
|
+
Sufia.queue.push(TranscodeVideoJob.new(generic_file_id))
|
39
32
|
elsif generic_file.audio?
|
40
|
-
Sufia.queue.push(TranscodeAudioJob.new(generic_file_id
|
33
|
+
Sufia.queue.push(TranscodeAudioJob.new(generic_file_id))
|
41
34
|
end
|
42
35
|
end
|
43
36
|
end
|
@@ -2,20 +2,13 @@ require 'net/https'
|
|
2
2
|
require 'uri'
|
3
3
|
require 'tempfile'
|
4
4
|
|
5
|
-
class ImportUrlJob
|
5
|
+
class ImportUrlJob < ActiveFedoraPidBasedJob
|
6
6
|
|
7
7
|
def queue_name
|
8
8
|
:import_url
|
9
9
|
end
|
10
10
|
|
11
|
-
attr_accessor :pid
|
12
|
-
|
13
|
-
def initialize(pid)
|
14
|
-
self.pid = pid
|
15
|
-
end
|
16
|
-
|
17
11
|
def run
|
18
|
-
generic_file = GenericFile.find(self.pid)
|
19
12
|
f = Tempfile.new(self.pid)
|
20
13
|
f.binmode
|
21
14
|
|
@@ -26,7 +19,7 @@ class ImportUrlJob
|
|
26
19
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
27
20
|
|
28
21
|
http.start do
|
29
|
-
http.request_get(uri) do |resp|
|
22
|
+
http.request_get(uri.request_uri) do |resp|
|
30
23
|
resp.read_body do |segment|
|
31
24
|
f.write(segment)
|
32
25
|
end
|
@@ -18,6 +18,13 @@ class ResolrizeJob
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def run
|
21
|
-
|
21
|
+
require 'active_fedora/version'
|
22
|
+
active_fedora_version = Gem::Version.new(ActiveFedora::VERSION)
|
23
|
+
minimum_feature_version = Gem::Version.new('6.4.4')
|
24
|
+
if active_fedora_version >= minimum_feature_version
|
25
|
+
ActiveFedora::Base.reindex_everything("pid~#{Sufia.config.id_namespace}:*")
|
26
|
+
else
|
27
|
+
ActiveFedora::Base.reindex_everything
|
28
|
+
end
|
22
29
|
end
|
23
30
|
end
|
@@ -2,38 +2,14 @@
|
|
2
2
|
# 7 Feb 2013
|
3
3
|
# An asyncronous job for transcoding audio files using FFMpeg
|
4
4
|
|
5
|
-
class TranscodeAudioJob <
|
5
|
+
class TranscodeAudioJob < ActiveFedoraPidBasedJob
|
6
6
|
def queue_name
|
7
7
|
:audio
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
10
|
+
def run
|
11
|
+
generic_file.create_derivatives
|
12
|
+
generic_file.save
|
13
13
|
end
|
14
14
|
|
15
|
-
private
|
16
|
-
def encode_ogg
|
17
|
-
opts = ""
|
18
|
-
if generic_file.mime_type == 'audio/ogg'
|
19
|
-
# Don't re-encode, just copy
|
20
|
-
generic_file.add_file_datastream(generic_file.content.read, :dsid=>'ogg', :mimeType=>'audio/ogg')
|
21
|
-
#generic_file.content.rewind
|
22
|
-
else
|
23
|
-
encode_datastream('ogg', 'audio/ogg', opts)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def encode_mp3
|
28
|
-
opts = ""
|
29
|
-
if generic_file.mime_type == 'audio/mpeg'
|
30
|
-
# Don't re-encode, just copy
|
31
|
-
generic_file.add_file_datastream(generic_file.content.read, :dsid=>'mp3', :mimeType=>'audio/mpeg')
|
32
|
-
else
|
33
|
-
encode_datastream('mp3', 'audio/mpeg', opts)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
15
|
end
|
39
|
-
|
@@ -2,38 +2,14 @@
|
|
2
2
|
# 13 Dec 2012
|
3
3
|
# An asyncronous job for transcoding video files using FFMpeg
|
4
4
|
|
5
|
-
class TranscodeVideoJob <
|
5
|
+
class TranscodeVideoJob < ActiveFedoraPidBasedJob
|
6
6
|
def queue_name
|
7
7
|
:video
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def encode_webm
|
18
|
-
# -g 30 enforces keyframe generation every second (30fps)
|
19
|
-
# -b:v is the video bitrate
|
20
|
-
# -acodec is the audio codec
|
21
|
-
opts = "#{size_attributes} -g 30 -b:v 345k -acodec libvorbis #{audio_attributes}"
|
22
|
-
encode_datastream('webm', 'video/webm', opts)
|
23
|
-
end
|
24
|
-
|
25
|
-
def encode_mp4
|
26
|
-
opts = "#{size_attributes} -b:v 345k -vcodec libx264 -acodec libfaac #{audio_attributes} "
|
27
|
-
encode_datastream('mp4', 'video/mp4', opts)
|
28
|
-
end
|
29
|
-
|
30
|
-
|
31
|
-
def size_attributes
|
32
|
-
"-s 320x240"
|
33
|
-
end
|
34
|
-
|
35
|
-
def audio_attributes
|
36
|
-
"-ac 2 -ab 96k -ar 44100"
|
10
|
+
def run
|
11
|
+
generic_file.create_derivatives
|
12
|
+
generic_file.save
|
37
13
|
end
|
38
14
|
end
|
39
15
|
|
@@ -12,19 +12,13 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
class UnzipJob
|
15
|
+
class UnzipJob < ActiveFedoraPidBasedJob
|
16
16
|
def queue_name
|
17
17
|
:unzip
|
18
18
|
end
|
19
19
|
|
20
|
-
attr_accessor :pid
|
21
|
-
|
22
|
-
def initialize(pid)
|
23
|
-
self.pid = pid
|
24
|
-
end
|
25
|
-
|
26
20
|
def run
|
27
|
-
Zip::Archive.open_buffer(
|
21
|
+
Zip::Archive.open_buffer(object.content.content) do |archive|
|
28
22
|
archive.each do |f|
|
29
23
|
if f.directory?
|
30
24
|
create_directory(f)
|
@@ -41,14 +35,9 @@ class UnzipJob
|
|
41
35
|
# @param file [Zip::File]
|
42
36
|
def create_file(file)
|
43
37
|
@generic_file = GenericFile.new
|
44
|
-
@generic_file.batch_id =
|
45
|
-
|
46
|
-
|
47
|
-
mime_type = mime_types.empty? ? "application/octet-stream" : mime_types.first.content_type
|
48
|
-
options = {:label=>file_name, :dsid=>'content', :mimeType=>mime_type}
|
49
|
-
@generic_file.add_file_datastream(file.read, options)
|
50
|
-
@generic_file.set_title_and_label( file_name, :only_if_blank=>true )
|
51
|
-
@generic_file.apply_depositor_metadata(zip_file.edit_users.first)
|
38
|
+
@generic_file.batch_id = object.batch.pid
|
39
|
+
@generic_file.add_file(file.read, 'content', file.name)
|
40
|
+
@generic_file.apply_depositor_metadata(object.edit_users.first)
|
52
41
|
@generic_file.date_uploaded = Time.now.ctime
|
53
42
|
@generic_file.date_modified = Time.now.ctime
|
54
43
|
@generic_file.save
|
@@ -60,7 +49,4 @@ class UnzipJob
|
|
60
49
|
def create_directory(file)
|
61
50
|
end
|
62
51
|
|
63
|
-
def zip_file
|
64
|
-
@zip_file ||= GenericFile.find(pid)
|
65
|
-
end
|
66
52
|
end
|
@@ -1,18 +1,3 @@
|
|
1
|
-
# Copyright © 2012 The Pennsylvania State University
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
|
-
|
15
|
-
require 'hydra/model_methods'
|
16
1
|
module Sufia
|
17
2
|
module ModelMethods
|
18
3
|
extend ActiveSupport::Concern
|
@@ -26,9 +11,10 @@ module Sufia
|
|
26
11
|
# Adds metadata about the depositor to the asset
|
27
12
|
# Most important behavior: if the asset has a rightsMetadata datastream, this method will add +depositor_id+ to its individual edit permissions.
|
28
13
|
|
29
|
-
def apply_depositor_metadata(
|
14
|
+
def apply_depositor_metadata(depositor)
|
30
15
|
rights_ds = self.datastreams["rightsMetadata"]
|
31
16
|
prop_ds = self.datastreams["properties"]
|
17
|
+
depositor_id = depositor.respond_to?(:user_key) ? depositor.user_key : depositor
|
32
18
|
|
33
19
|
rights_ds.update_indexed_attributes([:edit_access, :person]=>depositor_id) unless rights_ds.nil?
|
34
20
|
prop_ds.depositor = depositor_id unless prop_ds.nil?
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# To enable local file ingest,
|
2
|
+
# - Make User model define .directory method that returns a String corresponding to the User's personal import directory on the server. This can be a simple ActiveRecord attribute on the User model, or it can be something more elaborate.
|
3
|
+
# - Include this module in your User model, or define a .files() method that behaves the same
|
4
|
+
# - Set Sufia.config.enable_local_ingest to true
|
5
|
+
#
|
6
|
+
module Sufia::UserLocalDirectoryBehavior
|
7
|
+
|
8
|
+
# You can use this validator in your User model.
|
9
|
+
# Ensures that a string defining the path to the user's directory has been provided
|
10
|
+
# and corresponds to a real directory on the server.
|
11
|
+
# @example
|
12
|
+
# validate :directory_must_exist
|
13
|
+
def directory_must_exist
|
14
|
+
unless directory.blank? || File.directory?(directory)
|
15
|
+
errors.add(:directory, "must be an existing directory")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# List the contents of the user's directory on the server
|
20
|
+
# Indicates whether each item is a directory or not.
|
21
|
+
def files
|
22
|
+
return [] unless directory.present? && File.directory?(directory)
|
23
|
+
Dir[File.join(directory, '*')].inject([]) do |accum, val|
|
24
|
+
accum << { name: File.basename(val), directory: File.directory?(val)}
|
25
|
+
accum
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/lib/sufia/models/version.rb
CHANGED
data/sufia-models.gemspec
CHANGED
@@ -38,9 +38,9 @@ Gem::Specification.new do |spec|
|
|
38
38
|
spec.add_dependency 'noid', '~> 0.6.6'
|
39
39
|
spec.add_dependency 'curationexperts-mailboxer', '0.10.3'
|
40
40
|
spec.add_dependency 'acts_as_follower', '0.1.1'
|
41
|
-
spec.add_dependency 'rmagick'
|
42
41
|
spec.add_dependency 'paperclip', '~> 3.4.0'
|
43
42
|
spec.add_dependency 'zipruby', '0.3.6'
|
43
|
+
spec.add_dependency 'hydra-derivatives', '~> 0.0.5'
|
44
44
|
# https://github.com/zdennis/activerecord-import/pull/79
|
45
45
|
#spec.add_dependency 'activerecord-import', '0.3.0' # 0.3.1 caused a bug in testing: "SQLite3::SQLException: near ",": syntax error: INSERT INTO..."
|
46
46
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sufia-models
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Friesen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -184,20 +184,6 @@ dependencies:
|
|
184
184
|
- - '='
|
185
185
|
- !ruby/object:Gem::Version
|
186
186
|
version: 0.1.1
|
187
|
-
- !ruby/object:Gem::Dependency
|
188
|
-
name: rmagick
|
189
|
-
requirement: !ruby/object:Gem::Requirement
|
190
|
-
requirements:
|
191
|
-
- - '>='
|
192
|
-
- !ruby/object:Gem::Version
|
193
|
-
version: '0'
|
194
|
-
type: :runtime
|
195
|
-
prerelease: false
|
196
|
-
version_requirements: !ruby/object:Gem::Requirement
|
197
|
-
requirements:
|
198
|
-
- - '>='
|
199
|
-
- !ruby/object:Gem::Version
|
200
|
-
version: '0'
|
201
187
|
- !ruby/object:Gem::Dependency
|
202
188
|
name: paperclip
|
203
189
|
requirement: !ruby/object:Gem::Requirement
|
@@ -226,6 +212,20 @@ dependencies:
|
|
226
212
|
- - '='
|
227
213
|
- !ruby/object:Gem::Version
|
228
214
|
version: 0.3.6
|
215
|
+
- !ruby/object:Gem::Dependency
|
216
|
+
name: hydra-derivatives
|
217
|
+
requirement: !ruby/object:Gem::Requirement
|
218
|
+
requirements:
|
219
|
+
- - ~>
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
version: 0.0.5
|
222
|
+
type: :runtime
|
223
|
+
prerelease: false
|
224
|
+
version_requirements: !ruby/object:Gem::Requirement
|
225
|
+
requirements:
|
226
|
+
- - ~>
|
227
|
+
- !ruby/object:Gem::Version
|
228
|
+
version: 0.0.5
|
229
229
|
description: Models and services for sufia
|
230
230
|
email:
|
231
231
|
- jeremy.n.friesen@gmail.com
|
@@ -264,22 +264,23 @@ files:
|
|
264
264
|
- lib/sufia/models/active_support/core_ext/marshal.rb
|
265
265
|
- lib/sufia/models/engine.rb
|
266
266
|
- lib/sufia/models/file_content.rb
|
267
|
-
- lib/sufia/models/file_content/extract_metadata.rb
|
268
267
|
- lib/sufia/models/file_content/versions.rb
|
269
268
|
- lib/sufia/models/generic_file.rb
|
270
269
|
- lib/sufia/models/generic_file/accessible_attributes.rb
|
271
270
|
- lib/sufia/models/generic_file/actions.rb
|
272
271
|
- lib/sufia/models/generic_file/audit.rb
|
273
272
|
- lib/sufia/models/generic_file/characterization.rb
|
273
|
+
- lib/sufia/models/generic_file/derivatives.rb
|
274
274
|
- lib/sufia/models/generic_file/export.rb
|
275
|
+
- lib/sufia/models/generic_file/mime_types.rb
|
275
276
|
- lib/sufia/models/generic_file/permissions.rb
|
276
277
|
- lib/sufia/models/generic_file/thumbnail.rb
|
277
278
|
- lib/sufia/models/generic_file/web_form.rb
|
278
279
|
- lib/sufia/models/id_service.rb
|
280
|
+
- lib/sufia/models/jobs/active_fedora_pid_based_job.rb
|
279
281
|
- lib/sufia/models/jobs/audit_job.rb
|
280
282
|
- lib/sufia/models/jobs/batch_update_job.rb
|
281
283
|
- lib/sufia/models/jobs/characterize_job.rb
|
282
|
-
- lib/sufia/models/jobs/ffmpeg_transcode_job.rb
|
283
284
|
- lib/sufia/models/jobs/import_url_job.rb
|
284
285
|
- lib/sufia/models/jobs/resolrize_job.rb
|
285
286
|
- lib/sufia/models/jobs/transcode_audio_job.rb
|
@@ -290,6 +291,7 @@ files:
|
|
290
291
|
- lib/sufia/models/resque.rb
|
291
292
|
- lib/sufia/models/solr_document_behavior.rb
|
292
293
|
- lib/sufia/models/user.rb
|
294
|
+
- lib/sufia/models/user_local_directory_behavior.rb
|
293
295
|
- lib/sufia/models/utils.rb
|
294
296
|
- lib/sufia/models/version.rb
|
295
297
|
- lib/tasks/resque.rake
|
@@ -315,7 +317,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
315
317
|
version: '0'
|
316
318
|
requirements: []
|
317
319
|
rubyforge_project:
|
318
|
-
rubygems_version: 2.0.
|
320
|
+
rubygems_version: 2.0.5
|
319
321
|
signing_key:
|
320
322
|
specification_version: 4
|
321
323
|
summary: Models and services for sufia
|
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'open3'
|
2
|
-
module Sufia
|
3
|
-
module FileContent
|
4
|
-
module ExtractMetadata
|
5
|
-
include Open3
|
6
|
-
|
7
|
-
def extract_metadata
|
8
|
-
out = nil
|
9
|
-
to_tempfile do |f|
|
10
|
-
out = run_fits!(f.path)
|
11
|
-
end
|
12
|
-
out
|
13
|
-
end
|
14
|
-
|
15
|
-
def to_tempfile &block
|
16
|
-
return unless has_content?
|
17
|
-
tmp_base = Sufia.config.temp_file_base
|
18
|
-
f = Tempfile.new("#{pid}-#{dsVersionID}")
|
19
|
-
f.binmode
|
20
|
-
if content.respond_to? :read
|
21
|
-
f.write(content.read)
|
22
|
-
else
|
23
|
-
f.write(content)
|
24
|
-
end
|
25
|
-
f.close
|
26
|
-
content.rewind if content.respond_to? :rewind
|
27
|
-
yield(f)
|
28
|
-
f.unlink
|
29
|
-
end
|
30
|
-
|
31
|
-
# Return true if the content is present
|
32
|
-
# You can override this method if your content is an external datastream
|
33
|
-
def has_content?
|
34
|
-
!content.nil?
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
|
40
|
-
def run_fits!(file_path)
|
41
|
-
command = "#{fits_path} -i \"#{file_path}\""
|
42
|
-
stdin, stdout, stderr, wait_thr = popen3(command)
|
43
|
-
stdin.close
|
44
|
-
out = stdout.read
|
45
|
-
stdout.close
|
46
|
-
err = stderr.read
|
47
|
-
stderr.close
|
48
|
-
exit_status = wait_thr.value
|
49
|
-
raise "Unable to execute command \"#{command}\"\n#{err}" unless exit_status.success?
|
50
|
-
out
|
51
|
-
end
|
52
|
-
|
53
|
-
|
54
|
-
def fits_path
|
55
|
-
Sufia.config.fits_path
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
# Created by: Justin Coyne
|
2
|
-
# 7 Feb 2013
|
3
|
-
# An abstract class for asyncronous jobs that transcode files using FFMpeg
|
4
|
-
|
5
|
-
require 'tmpdir'
|
6
|
-
|
7
|
-
class FfmpegTranscodeJob
|
8
|
-
extend Open3
|
9
|
-
|
10
|
-
attr_accessor :generic_file_id, :datastream_in, :datastream, :generic_file
|
11
|
-
|
12
|
-
def initialize(generic_file_id, datastream_in)
|
13
|
-
self.generic_file_id = generic_file_id
|
14
|
-
self.datastream_in = datastream_in
|
15
|
-
end
|
16
|
-
|
17
|
-
def process
|
18
|
-
raise "You attempted to call process() on an abstract class. Implement process() on the concrete class"
|
19
|
-
end
|
20
|
-
|
21
|
-
def run
|
22
|
-
return unless Sufia.config.enable_ffmpeg
|
23
|
-
self.generic_file = GenericFile.find(generic_file_id)
|
24
|
-
self.datastream = generic_file.datastreams[datastream_in]
|
25
|
-
if datastream
|
26
|
-
process
|
27
|
-
generic_file.save!
|
28
|
-
else
|
29
|
-
logger.warn "No datastream for transcoding!!!!! pid: #{generic_file_id} dsid: #{datastream_in}"
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def encode_datastream(dest_dsid, mime_type, options)
|
34
|
-
file_suffix = dest_dsid
|
35
|
-
out_file = nil
|
36
|
-
output_file = Dir::Tmpname.create(['sufia', ".#{file_suffix}"], Sufia.config.temp_file_base){}
|
37
|
-
datastream.to_tempfile do |f|
|
38
|
-
self.class.encode(f.path, options, output_file)
|
39
|
-
end
|
40
|
-
out_file = File.open(output_file, "rb")
|
41
|
-
generic_file.add_file_datastream(out_file.read, :dsid=>dest_dsid, :mimeType=>mime_type)
|
42
|
-
File.unlink(output_file)
|
43
|
-
end
|
44
|
-
|
45
|
-
def self.encode(path, options, output_file)
|
46
|
-
command = "#{ffmpeg_path} -y -i \"#{path}\" #{options} #{output_file}"
|
47
|
-
stdin, stdout, stderr, wait_thr = popen3(command)
|
48
|
-
stdin.close
|
49
|
-
out = stdout.read
|
50
|
-
stdout.close
|
51
|
-
err = stderr.read
|
52
|
-
stderr.close
|
53
|
-
raise "Unable to execute command \"#{command}\"\n#{err}" unless wait_thr.value.success?
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.ffmpeg_path
|
57
|
-
Sufia.config.ffmpeg_path
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
|