kithe 2.16.0 → 2.17.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/README.md +2 -1
- data/app/derivative_transformers/kithe/ffmpeg_extract_jpg.rb +22 -6
- data/app/derivative_transformers/kithe/ffmpeg_transformer.rb +12 -2
- data/app/derivative_transformers/kithe/vips_cli_image_to_jpeg.rb +20 -8
- data/app/models/kithe/asset/derivative_definition.rb +21 -1
- data/lib/kithe/version.rb +1 -1
- data/lib/shrine/plugins/kithe_derivatives.rb +15 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3f74f2e5dc57d427f37635095e328d2dddd1498b86c85e153a126a8145308a5
|
4
|
+
data.tar.gz: 0ba6e1d1b075f3f3da6e9a6f697b354eb3b761dfb2c6e873e14e0e5e5a2782d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 25fcab14c568fee5937de11be81fb534bfcc6329dba65c8d2da64739828af036a7890a497feba71d22ee0ca1b02f8ac270b4c6703d7270bade63b2d7cfb509ac
|
7
|
+
data.tar.gz: 9484fb022d18b0ab20203f368de6b7d65ec4871c57571c1f0b8a34733431bc8414b250ecb5eba3730435d27cf50e248ea27e56252d3e16c010fd5f3f936eeb32
|
data/README.md
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# Kithe
|
2
2
|
An experiment in shareable tools/components for building a digital collections app in Rails.
|
3
3
|
|
4
|
-
[](https://github.com/sciencehistory/kithe/actions/workflows/ci.yml)
|
5
|
+
[](https://badge.fury.io/rb/kithe)
|
5
6
|
|
6
7
|
## What is kithe?
|
7
8
|
|
@@ -8,6 +8,10 @@ module Kithe
|
|
8
8
|
# @example tempfile = FfmpegExtractJpg.new.call(url)
|
9
9
|
# @example tempfile = FfmpegExtractJpg.new(start_seconds: 60).call(shrine_uploaded_file)
|
10
10
|
# @example tempfile = FfmpegExtractJpg.new(start_seconds: 10, width_pixels: 420).call(shrine_uploaded_file)
|
11
|
+
#
|
12
|
+
# @example you can also provide a Hash which will be mutated with metadata relevant to
|
13
|
+
# the derivative created, ffmpeg version and args:
|
14
|
+
# @example tempfile = FfmpegExtractJpg.new(start_seconds: 10, width_pixels: 420).call(shrine_uploaded_file, add_metadata: my_hash)
|
11
15
|
class FfmpegExtractJpg
|
12
16
|
class_attribute :ffmpeg_command, default: "ffmpeg"
|
13
17
|
attr_reader :start_seconds, :frame_sample_size, :width_pixels
|
@@ -43,19 +47,19 @@ module Kithe
|
|
43
47
|
# Most efficient is if we have a remote URL to give ffmpeg, one way or another!
|
44
48
|
#
|
45
49
|
# @returns [Tempfile] jpg extracted from movie
|
46
|
-
def call(input_arg)
|
50
|
+
def call(input_arg, add_metadata:nil)
|
47
51
|
if input_arg.kind_of?(Shrine::UploadedFile)
|
48
52
|
if input_arg.respond_to?(:url) && input_arg.url&.start_with?(/https?\:/)
|
49
|
-
_call(input_arg.url)
|
53
|
+
_call(input_arg.url, add_metadata: add_metadata)
|
50
54
|
else
|
51
55
|
Shrine.with_file(input_arg) do |local_file|
|
52
|
-
_call(local_file.path)
|
56
|
+
_call(local_file.path, add_metadata: add_metadata)
|
53
57
|
end
|
54
58
|
end
|
55
59
|
elsif input_arg.respond_to?(:path)
|
56
|
-
_call(input_arg.path)
|
60
|
+
_call(input_arg.path, add_metadata: add_metadata)
|
57
61
|
else
|
58
|
-
_call(input_arg.to_s)
|
62
|
+
_call(input_arg.to_s, add_metadata: add_metadata)
|
59
63
|
end
|
60
64
|
end
|
61
65
|
|
@@ -67,14 +71,26 @@ module Kithe
|
|
67
71
|
# @param ffmpeg_source_arg [String] filepath or URL. ffmpeg can take urls, which
|
68
72
|
# can be very efficient.
|
69
73
|
#
|
74
|
+
# @param add_metadata [Hash], optional, if provided will be filled out with metadata
|
75
|
+
# relevant to the derivative created -- ffmpeg version and args.
|
76
|
+
#
|
70
77
|
# @returns Tempfile pointing to a thumbnail
|
71
|
-
def _call(ffmpeg_source_arg)
|
78
|
+
def _call(ffmpeg_source_arg, add_metadata: nil)
|
72
79
|
tempfile = Tempfile.new(['temp_deriv', ".jpg"])
|
73
80
|
|
74
81
|
ffmpeg_args = produce_ffmpeg_args(input_arg: ffmpeg_source_arg, output_path: tempfile.path)
|
75
82
|
|
76
83
|
TTY::Command.new(printer: :null).run(*ffmpeg_args)
|
77
84
|
|
85
|
+
if add_metadata
|
86
|
+
add_metadata[:ffmpeg_command] = ffmpeg_args.join(" ")
|
87
|
+
|
88
|
+
`#{ffmpeg_command} -version` =~ /ffmpeg version (\d+\.\d+.*) Copyright/
|
89
|
+
if $1
|
90
|
+
add_metadata[:ffmpeg_version] = $1
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
78
94
|
return tempfile
|
79
95
|
rescue StandardError => e
|
80
96
|
tempfile.unlink if tempfile
|
@@ -39,13 +39,23 @@ module Kithe
|
|
39
39
|
end
|
40
40
|
|
41
41
|
# Will raise TTY::Command::ExitError if the ffmpeg returns non-null.
|
42
|
-
def call(original_file)
|
42
|
+
def call(original_file, add_metadata: nil)
|
43
43
|
tempfile = Tempfile.new(['temp_deriv', ".#{@output_suffix}"])
|
44
44
|
# -y tells ffmpeg to overwrite the abovementioned tempfile (still empty)
|
45
45
|
# with the output of ffmpeg.
|
46
46
|
ffmpeg_args = [ffmpeg_command, "-y", "-i", original_file.path]
|
47
47
|
ffmpeg_args += transform_arguments + [tempfile.path]
|
48
|
-
TTY::Command.new(printer: :null).run(*ffmpeg_args)
|
48
|
+
out, err = TTY::Command.new(printer: :null).run(*ffmpeg_args)
|
49
|
+
|
50
|
+
if add_metadata
|
51
|
+
add_metadata[:ffmpeg_command] = ffmpeg_args.join(" ")
|
52
|
+
|
53
|
+
`#{ffmpeg_command} -version` =~ /ffmpeg version (\d+\.\d+.*) Copyright/
|
54
|
+
if $1
|
55
|
+
add_metadata[:ffmpeg_version] = $1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
49
59
|
return tempfile
|
50
60
|
end
|
51
61
|
end
|
@@ -19,8 +19,8 @@ module Kithe
|
|
19
19
|
# built for use with kithe derivatives transformations, eg:
|
20
20
|
#
|
21
21
|
# class Asset < KitheAsset
|
22
|
-
# define_derivative(thumb) do |original_file
|
23
|
-
# Kithe::VipsCliImageToJpeg.new(max_width: 100, thumbnail_mode: true).call(original_file)
|
22
|
+
# Attacher.define_derivative(:thumb) do |original_file, add_metadata:|
|
23
|
+
# Kithe::VipsCliImageToJpeg.new(max_width: 100, thumbnail_mode: true).call(original_file, add_metadata: add_metadata)
|
24
24
|
# end
|
25
25
|
# end
|
26
26
|
#
|
@@ -28,8 +28,11 @@ module Kithe
|
|
28
28
|
# about ruby memory leaks or the GIL. An alternative that uses vips ruby bindings
|
29
29
|
# would also be possible, and might work well, but this is what for us is tried
|
30
30
|
# and true.
|
31
|
+
#
|
32
|
+
# Some usage suggestions at https://www.libvips.org/API/current/Using-vipsthumbnail.html
|
31
33
|
class VipsCliImageToJpeg
|
32
|
-
|
34
|
+
# vips has a built-in srgb profile, don't need our own anymore.
|
35
|
+
#class_attribute :srgb_profile_path, default: Kithe::Engine.root.join("lib", "vendor", "icc", "sRGB2014.icc").to_s
|
33
36
|
class_attribute :vips_thumbnail_command, default: "vipsthumbnail"
|
34
37
|
class_attribute :vips_command, default: "vips"
|
35
38
|
|
@@ -47,7 +50,7 @@ module Kithe
|
|
47
50
|
end
|
48
51
|
|
49
52
|
# Will raise TTY::Command::ExitError if the external Vips command returns non-null.
|
50
|
-
def call(original_file)
|
53
|
+
def call(original_file, add_metadata: nil)
|
51
54
|
tempfile = Tempfile.new(["kithe_vips_cli_image_to_jpeg", ".jpg"])
|
52
55
|
|
53
56
|
vips_args = []
|
@@ -59,7 +62,7 @@ module Kithe
|
|
59
62
|
# really huge one million pixels so it should not come into play, and
|
60
63
|
# we're constraining proportionally by width.
|
61
64
|
# https://github.com/jcupitt/libvips/issues/781
|
62
|
-
vips_args.concat [vips_thumbnail_command, original_file.path]
|
65
|
+
vips_args.concat [vips_thumbnail_command, "--version", original_file.path]
|
63
66
|
vips_args.concat maybe_profile_normalization_args
|
64
67
|
vips_args.concat ["--size", "#{max_width}x65500"]
|
65
68
|
vips_args.concat ["-o", "#{tempfile.path}#{vips_jpg_params}"]
|
@@ -72,7 +75,16 @@ module Kithe
|
|
72
75
|
vips_args.concat ["#{tempfile.path}#{vips_jpg_params}"]
|
73
76
|
end
|
74
77
|
|
75
|
-
TTY::Command.new(printer: :null).run(*vips_args)
|
78
|
+
out, err = TTY::Command.new(printer: :null).run(*vips_args)
|
79
|
+
|
80
|
+
if add_metadata
|
81
|
+
add_metadata[:vips_command] = vips_args.join(" ")
|
82
|
+
|
83
|
+
out =~ /vips[ \-](\d+\.\d+\.\d+.*$)/
|
84
|
+
if $1
|
85
|
+
add_metadata[:vips_version] = $1
|
86
|
+
end
|
87
|
+
end
|
76
88
|
|
77
89
|
return tempfile
|
78
90
|
end
|
@@ -88,7 +100,7 @@ module Kithe
|
|
88
100
|
def maybe_profile_normalization_args
|
89
101
|
return [] unless thumbnail_mode?
|
90
102
|
|
91
|
-
["--
|
103
|
+
["--export-profile", "srgb"]
|
92
104
|
end
|
93
105
|
|
94
106
|
# Params to add on to end of JPG output path, as in:
|
@@ -103,7 +115,7 @@ module Kithe
|
|
103
115
|
# @returns [String]
|
104
116
|
def vips_jpg_params
|
105
117
|
if thumbnail_mode?
|
106
|
-
"[Q=#{jpeg_q},interlace,optimize_coding,
|
118
|
+
"[Q=#{jpeg_q},interlace,optimize_coding,keep=none]"
|
107
119
|
else
|
108
120
|
# could be higher Q for downloads if we want, but we don't right now
|
109
121
|
# We do avoid striping metadata, no 'strip' directive.
|
@@ -9,12 +9,32 @@ class Kithe::Asset::DerivativeDefinition
|
|
9
9
|
@proc = proc
|
10
10
|
end
|
11
11
|
|
12
|
+
# @return [Hash] add_metadata hash of metadata to add to derivative on storage
|
12
13
|
def call(original_file:,attacher:)
|
14
|
+
add_metadata = {}
|
15
|
+
kwargs = {}
|
16
|
+
|
13
17
|
if proc_accepts_keyword?(:attacher)
|
14
|
-
|
18
|
+
kwargs[:attacher] = attacher
|
19
|
+
end
|
20
|
+
|
21
|
+
if proc_accepts_keyword?(:add_metadata)
|
22
|
+
kwargs[:add_metadata] = add_metadata
|
23
|
+
end
|
24
|
+
|
25
|
+
return_val = if kwargs.present?
|
26
|
+
proc.call(original_file, **kwargs)
|
15
27
|
else
|
16
28
|
proc.call(original_file)
|
17
29
|
end
|
30
|
+
|
31
|
+
# Save in context to later write to actual stored derivative metadata
|
32
|
+
if add_metadata.present?
|
33
|
+
attacher.context[:add_metadata] ||= {}
|
34
|
+
attacher.context[:add_metadata][key] = add_metadata
|
35
|
+
end
|
36
|
+
|
37
|
+
return_val
|
18
38
|
end
|
19
39
|
|
20
40
|
# Do content-type restrictions defined for this definition match a given asset?
|
data/lib/kithe/version.rb
CHANGED
@@ -32,9 +32,13 @@ class Shrine
|
|
32
32
|
|
33
33
|
module InstanceMethods
|
34
34
|
|
35
|
-
# Override to fix "filename" metadata to be something reasonable, regardless
|
35
|
+
# 1. Override to fix "filename" metadata to be something reasonable, regardless
|
36
36
|
# of what if anything was the filename of the IO being attached. shrine S3 will
|
37
|
-
# insist on setting a default content-disposition with this filename
|
37
|
+
# insist on setting a default content-disposition with this filename, so we
|
38
|
+
# can use that.
|
39
|
+
#
|
40
|
+
# 2. Set any specified derivative metadata on derivative. Specified add_metadata
|
41
|
+
# found in context.
|
38
42
|
def extract_metadata(io, derivative:nil, **context)
|
39
43
|
result = super
|
40
44
|
|
@@ -43,6 +47,15 @@ class Shrine
|
|
43
47
|
result["filename"] = "#{context[:record].friendlier_id}_#{derivative}.#{extension}"
|
44
48
|
end
|
45
49
|
|
50
|
+
# If derivative, add timestamp and any specified extra data
|
51
|
+
if derivative
|
52
|
+
result["created_at"] ||= Time.current.utc.iso8601.to_s
|
53
|
+
|
54
|
+
if (metadata = context.dig(:add_metadata, derivative)).present?
|
55
|
+
result.merge!(metadata.stringify_keys)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
46
59
|
result
|
47
60
|
end
|
48
61
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kithe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.17.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Rochkind
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-05-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|