kithe 2.4.0 → 2.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/characterization/kithe/ffprobe_characterization.rb +7 -0
- data/app/derivative_transformers/kithe/ffmpeg_extract_jpg.rb +106 -0
- data/app/indexing/kithe/indexable/record_index_updater.rb +3 -0
- data/app/models/kithe/asset.rb +15 -38
- data/app/models/kithe/model.rb +9 -3
- data/app/models/kithe/parameters.rb +17 -4
- data/lib/kithe/indexable_settings.rb +8 -9
- data/lib/kithe/version.rb +1 -1
- data/lib/shrine/plugins/kithe_derivative_definitions.rb +104 -7
- data/lib/shrine/plugins/kithe_persisted_derivatives.rb +4 -0
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4f768036d2b89fb4fedb4220b007e87f23967f9b81177cf4818fbd967f0b0d2
|
4
|
+
data.tar.gz: 358cf6e4531c022160b4877e8ea7931a10930e71e2714f095bc0e52499fc6eee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44139f3684a3609b16f972dffc58656bc2b110c6f6b5aefd635fc303089b30824a1351918ff704bcd48850bfb6cc95978bf2732ecda4166e8d9715ce9ab5ffee
|
7
|
+
data.tar.gz: 6be86d9e1b234832bced241f1b4bf7a9badcc446fd3d1c00b617395864e833ddc2894e702b6ce2b41789d87fc310e1725818bc8b44d786666a5f3fe549fea6f5
|
@@ -22,6 +22,13 @@ module Kithe
|
|
22
22
|
#
|
23
23
|
# ffprobe_results = FfprobeCharacterization.new(url).ffprobe_hash
|
24
24
|
#
|
25
|
+
# The class method .characterize_from_uploader can usefully extract a URL if possible
|
26
|
+
# or else execute with a file, such as from a shrine `add_metadata` block.
|
27
|
+
#
|
28
|
+
# add_metadata do |source_io, **context|
|
29
|
+
# Kithe::FfprobeCharacterization.characterize_from_uploader(source_io, context)
|
30
|
+
# end
|
31
|
+
#
|
25
32
|
class FfprobeCharacterization
|
26
33
|
class_attribute :ffprobe_command, default: "ffprobe"
|
27
34
|
class_attribute :ffprobe_timeout, default: 10
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'tty/command'
|
2
|
+
|
3
|
+
module Kithe
|
4
|
+
# Creates a JPG screen capture using ffmpeg, by default with the `thumbnail`
|
5
|
+
# filter to choose a representative frame from the first minute or so.
|
6
|
+
#
|
7
|
+
# @example tempfile = FfmpegExtractJpg.new.call(shrine_uploaded_file)
|
8
|
+
# @example tempfile = FfmpegExtractJpg.new.call(url)
|
9
|
+
# @example tempfile = FfmpegExtractJpg.new(start_seconds: 60).call(shrine_uploaded_file)
|
10
|
+
# @example tempfile = FfmpegExtractJpg.new(start_seconds: 10, width_pixels: 420).call(shrine_uploaded_file)
|
11
|
+
class FfmpegExtractJpg
|
12
|
+
class_attribute :ffmpeg_command, default: "ffmpeg"
|
13
|
+
attr_reader :start_seconds, :frame_sample_size, :width_pixels
|
14
|
+
|
15
|
+
# @param start_seconds [Integer] seek to this point to find thumbnail. If it's
|
16
|
+
# after the end of the video, you won't get a thumb back though! [Default 0]
|
17
|
+
#
|
18
|
+
# @param frame_sample_size [Integer,false,nil] argument passed to ffmpeg thumbnail filter,
|
19
|
+
# how many frames to sample, starting at start_seconds, to choose representative
|
20
|
+
# thumbnail. If set to false, thumbnail filter won't be used. If this one
|
21
|
+
# goes past the end of the video, ffmpeg is fine with it. Set to `false` to
|
22
|
+
# disable use of ffmpeg sample feature, and just use exact frame at start_seconds.
|
23
|
+
#
|
24
|
+
# NOTE: This can consume significant RAM depending on value and video resolution.
|
25
|
+
#
|
26
|
+
# [Default false, not operative]
|
27
|
+
#
|
28
|
+
# @width_pixels [Integer] output thumb at this width. aspect ratio will be
|
29
|
+
# maintained. Warning, if it's larger than video original, ffmpeg will
|
30
|
+
# upscale! If set to nil, thumb will be output at original video
|
31
|
+
# resolution. [Default nil]
|
32
|
+
def initialize(start_seconds: 0, frame_sample_size: false, width_pixels: nil)
|
33
|
+
@start_seconds = start_seconds
|
34
|
+
@frame_sample_size = frame_sample_size
|
35
|
+
@width_pixels = width_pixels
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
# @param input_arg [String,File,Shrine::UploadedFile] local File; String that
|
41
|
+
# can be URL or local file path; or Shrine::UploadedFile. If Shrine::UploadedFile,
|
42
|
+
# we'll try to get a URL from it if we can, otherwise use or make a local tempfile.
|
43
|
+
# Most efficient is if we have a remote URL to give ffmpeg, one way or another!
|
44
|
+
#
|
45
|
+
# @returns [Tempfile] jpg extracted from movie
|
46
|
+
def call(input_arg)
|
47
|
+
if input_arg.kind_of?(Shrine::UploadedFile)
|
48
|
+
if input_arg.respond_to?(:url) && input_arg.url&.start_with?(/https?\:/)
|
49
|
+
_call(input_arg.url)
|
50
|
+
else
|
51
|
+
Shrine.with_file(input_arg) do |local_file|
|
52
|
+
_call(local_file.path)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
elsif input_arg.respond_to?(:path)
|
56
|
+
_call(input_arg.path)
|
57
|
+
else
|
58
|
+
_call(input_arg.to_s)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# Internal implementation, after input has already been normalized to an
|
65
|
+
# string that can be an ffmpeg arg.
|
66
|
+
#
|
67
|
+
# @param ffmpeg_source_arg [String] filepath or URL. ffmpeg can take urls, which
|
68
|
+
# can be very efficient.
|
69
|
+
#
|
70
|
+
# @returns Tempfile pointing to a thumbnail
|
71
|
+
def _call(ffmpeg_source_arg)
|
72
|
+
tempfile = Tempfile.new(['temp_deriv', ".jpg"])
|
73
|
+
|
74
|
+
ffmpeg_args = produce_ffmpeg_args(input_arg: ffmpeg_source_arg, output_path: tempfile.path)
|
75
|
+
|
76
|
+
TTY::Command.new(printer: :null).run(*ffmpeg_args)
|
77
|
+
|
78
|
+
return tempfile
|
79
|
+
rescue StandardError => e
|
80
|
+
tempfile.unlink if tempfile
|
81
|
+
raise e
|
82
|
+
end
|
83
|
+
|
84
|
+
def produce_ffmpeg_args(input_arg:, output_path:)
|
85
|
+
ffmpeg_args = [ffmpeg_command, "-y"]
|
86
|
+
|
87
|
+
if start_seconds && start_seconds > 0
|
88
|
+
ffmpeg_args.concat ["-ss", start_seconds.to_i]
|
89
|
+
end
|
90
|
+
|
91
|
+
ffmpeg_args.concat ["-i", input_arg]
|
92
|
+
|
93
|
+
video_filter_parts = []
|
94
|
+
video_filter_parts << "thumbnail=#{frame_sample_size}" if (frame_sample_size || 0) > 1
|
95
|
+
video_filter_parts << "scale=#{width_pixels}:-1" if width_pixels
|
96
|
+
|
97
|
+
if video_filter_parts.present?
|
98
|
+
ffmpeg_args.concat ["-vf", video_filter_parts.join(',')]
|
99
|
+
end
|
100
|
+
|
101
|
+
ffmpeg_args.concat ["-frames:v", "1"]
|
102
|
+
|
103
|
+
ffmpeg_args << output_path
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -24,6 +24,9 @@ module Kithe
|
|
24
24
|
# it's nil, meaning we'll find the indexer to use from current thread settings,
|
25
25
|
# or global settings.
|
26
26
|
#
|
27
|
+
# (note: this design means we can't currently use traject processing_thread_pool for
|
28
|
+
# concurrency, sorry.)
|
29
|
+
#
|
27
30
|
# @param writer [Traject::Writer] Can pass i a custom Traject::Writer which the
|
28
31
|
# index representation will be sent to. By default it's nil, meaning we'll find
|
29
32
|
# the writer to use from current thread settings or global settings.
|
data/app/models/kithe/asset.rb
CHANGED
@@ -43,48 +43,24 @@ class Kithe::Asset < Kithe::Model
|
|
43
43
|
before_promotion :refresh_metadata_before_promotion
|
44
44
|
after_promotion :schedule_derivatives
|
45
45
|
|
46
|
-
#
|
47
|
-
# to create derivatives with conncurrent access safety, with the :kithe_derivatives
|
48
|
-
# processor argument, to create derivatives defined using kithe_derivative_definitions.
|
46
|
+
# Proxies to file_attacher.kithe_create_derivatives to create kithe managed derivatives.
|
49
47
|
#
|
50
|
-
# This
|
51
|
-
#
|
48
|
+
# This will include any derivatives you created with in the uploader with kithe
|
49
|
+
# Attacher.define_derivative, as well as any derivative processors you opted into
|
50
|
+
# kithe management with `kithe_include_derivatives_processors` in uploader.
|
52
51
|
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
# that has not been marked `default_create: false`.
|
52
|
+
# This is safe for concurrent updates to the underlying model, the derivatives will
|
53
|
+
# be consistent and not left orphaned.
|
56
54
|
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
# you can always just run it again.
|
62
|
-
#
|
63
|
-
# Will normally re-create derivatives (per existing definitions) even if they already exist,
|
64
|
-
# but pass `lazy: false` to skip creating if a derivative with a given key already exists.
|
65
|
-
# This will use the asset `derivatives` association, so if you are doing this in bulk for several
|
66
|
-
# assets, you should eager-load the derivatives association for efficiency.
|
67
|
-
#
|
68
|
-
# ## Avoiding eager-download
|
69
|
-
#
|
70
|
-
# Additionally, this has a feature to 'trick' shrine into not eager downloading
|
71
|
-
# the original before our kithe_derivatives processor has a chance to decide if it
|
72
|
-
# needs to create any derivatives (based on `lazy` arg), making no-op
|
73
|
-
# create_derivatives so much faster and more efficient, which matters when doing
|
74
|
-
# bulk operations say with our rake task.
|
75
|
-
#
|
76
|
-
# kithe_derivatives processor must then do a Shrine.with_file to make sure
|
77
|
-
# it's a local file, when needed.
|
78
|
-
#
|
79
|
-
# See https://github.com/shrinerb/shrine/issues/470
|
55
|
+
# By default it will create all derivatives configured for default generation,
|
56
|
+
# but you can customize by listing derivative keys with :only and :except options,
|
57
|
+
# and with :lazy option which, if true, only executes derivative creation if
|
58
|
+
# a given derivative doesn't already exist.
|
80
59
|
#
|
60
|
+
# See more in docs for kithe at
|
61
|
+
# Shrine::Plugins::KitheDerivativeDefinitions::AttacherMethods#kithe_create_derivatives
|
81
62
|
def create_derivatives(only: nil, except: nil, lazy: false)
|
82
|
-
|
83
|
-
return false unless source
|
84
|
-
|
85
|
-
local_files = file_attacher.process_derivatives(:kithe_derivatives, only: only, except: except, lazy: lazy)
|
86
|
-
|
87
|
-
file_attacher.add_persisted_derivatives(local_files)
|
63
|
+
file_attacher.kithe_create_derivatives(only: only, except: except, lazy: lazy)
|
88
64
|
end
|
89
65
|
|
90
66
|
|
@@ -186,7 +162,8 @@ class Kithe::Asset < Kithe::Model
|
|
186
162
|
|
187
163
|
# called by after_promotion hook
|
188
164
|
def schedule_derivatives
|
189
|
-
|
165
|
+
# no need to schedule if we don't have any
|
166
|
+
return unless self.file_attacher.kithe_derivative_definitions.present? || self.file_attacher.kithe_include_derivatives_processors.present?
|
190
167
|
|
191
168
|
Kithe::TimingPromotionDirective.new(key: :create_derivatives, directives: file_attacher.promotion_directives) do |directive|
|
192
169
|
if directive.inline?
|
data/app/models/kithe/model.rb
CHANGED
@@ -33,7 +33,9 @@ class Kithe::Model < ActiveRecord::Base
|
|
33
33
|
# when fetching all Kithe::Model. And it's to Kithe::Model so it can include
|
34
34
|
# both Works and Assets. We do some app-level validation to try and make it used
|
35
35
|
# as intended.
|
36
|
-
has_many :members, class_name: "Kithe::Model", foreign_key: :parent_id,
|
36
|
+
has_many :members, class_name: "Kithe::Model", foreign_key: :parent_id,
|
37
|
+
inverse_of: :parent, dependent: :destroy
|
38
|
+
|
37
39
|
belongs_to :parent, class_name: "Kithe::Model", inverse_of: :members, optional: true
|
38
40
|
|
39
41
|
# a self-referential many-to-many is a bit confusing, but our "contains" relation
|
@@ -130,11 +132,15 @@ class Kithe::Model < ActiveRecord::Base
|
|
130
132
|
LIMIT 1;
|
131
133
|
EOS
|
132
134
|
|
133
|
-
# trying to use a prepared statement, hoping it means performance advantage
|
135
|
+
# trying to use a prepared statement, hoping it means performance advantage,
|
136
|
+
# this is super undocumented
|
137
|
+
|
138
|
+
bind = ActiveRecord::Relation::QueryAttribute.new("m.id", self.representative_id, ActiveRecord::Type::Value.new)
|
139
|
+
|
134
140
|
result = self.class.connection.select_all(
|
135
141
|
recursive_cte,
|
136
142
|
"set_leaf_representative",
|
137
|
-
[
|
143
|
+
[bind],
|
138
144
|
preparable: true
|
139
145
|
).first.try(:dig, "id")
|
140
146
|
|
@@ -63,11 +63,24 @@
|
|
63
63
|
class Kithe::Parameters < ActionController::Parameters
|
64
64
|
attr_reader :auto_allowed_keys
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
|
67
|
+
# Rails 7 adds another initializer method, annoyingly
|
68
|
+
if Rails.version.split.first.to_i >= 7
|
69
|
+
def initialize(hash = {}, logging_context = {})
|
70
|
+
if hash.respond_to?(:to_unsafe_h)
|
71
|
+
hash = hash.to_unsafe_h
|
72
|
+
end
|
73
|
+
|
74
|
+
super(hash, logging_context)
|
75
|
+
end
|
76
|
+
else
|
77
|
+
def initialize(hash = {})
|
78
|
+
if hash.respond_to?(:to_unsafe_h)
|
79
|
+
hash = hash.to_unsafe_h
|
80
|
+
end
|
81
|
+
|
82
|
+
super(hash)
|
69
83
|
end
|
70
|
-
super(hash)
|
71
84
|
end
|
72
85
|
|
73
86
|
def permit_attr_json(klass, except:nil)
|
@@ -6,22 +6,21 @@ module Kithe
|
|
6
6
|
def initialize(solr_url:, writer_class_name:, writer_settings:,
|
7
7
|
model_name_solr_field:, solr_id_value_attribute:, disable_callbacks: false,
|
8
8
|
batching_mode_batch_size: 100)
|
9
|
-
@solr_url = solr_url
|
10
9
|
@writer_class_name = writer_class_name
|
11
10
|
@writer_settings = writer_settings
|
12
11
|
@model_name_solr_field = model_name_solr_field
|
13
12
|
@solr_id_value_attribute = solr_id_value_attribute || 'id'
|
14
13
|
@batching_mode_batch_size = batching_mode_batch_size
|
14
|
+
|
15
|
+
# use our local setter to set solr_url also in writer_settings
|
16
|
+
solr_url = solr_url
|
15
17
|
end
|
16
18
|
|
17
|
-
|
18
|
-
# writer_settings
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
else
|
23
|
-
@writer_settings
|
24
|
-
end
|
19
|
+
|
20
|
+
# set solr_url also in writer_settings, cause it's expected there.
|
21
|
+
def solr_url=(v)
|
22
|
+
@solr_url = v
|
23
|
+
writer_settings["solr.url"] = v if writer_settings
|
25
24
|
end
|
26
25
|
|
27
26
|
# Turn writer_class_name into an actual Class object.
|
data/lib/kithe/version.rb
CHANGED
@@ -5,9 +5,25 @@ class Shrine
|
|
5
5
|
# use Rails class_attribute to conveniently have a class-level place
|
6
6
|
# to store our derivative definitions that are inheritable and overrideable.
|
7
7
|
# We store it on the Attacher class, because that's where shrine
|
8
|
-
# puts derivative processor definitions, so seems appropriate.
|
8
|
+
# puts derivative processor definitions, so seems appropriate. Normally
|
9
|
+
# not touched directly by non-kithe code.
|
9
10
|
uploader::Attacher.class_attribute :kithe_derivative_definitions, instance_writer: false, default: []
|
10
11
|
|
12
|
+
# Kithe exersizes lifecycle control over derivatives, normally just the
|
13
|
+
# shrine processor labelled :kithe_derivatives. But you can opt additional shrine
|
14
|
+
# derivative processors into kithe control by listing their labels in this attribute.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
#
|
18
|
+
# class AssetUploader < Kithe::AssetUploader
|
19
|
+
# Attacher.kithe_include_derivatives_processors += [:my_processor]
|
20
|
+
# Attacher.derivatives(:my_processor) do |original|
|
21
|
+
# derivatives
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
uploader::Attacher.class_attribute :kithe_include_derivatives_processors, instance_writer: false, default: []
|
26
|
+
|
11
27
|
# Register our derivative processor, that will create our registered derivatives,
|
12
28
|
# with our custom options.
|
13
29
|
#
|
@@ -31,11 +47,12 @@ class Shrine
|
|
31
47
|
#
|
32
48
|
# The most basic definition consists of a derivative key, and a ruby block that
|
33
49
|
# takes the original file, transforms it, and returns a ruby File or other
|
34
|
-
# (shrine-compatible) IO-like object. It will usually be done inside
|
35
|
-
# class definition.
|
50
|
+
# (shrine-compatible) IO-like object. It will usually be done inside your custom
|
51
|
+
# AssetUploader class definition.
|
36
52
|
#
|
37
|
-
# class
|
38
|
-
# define_derivative :thumbnail do |original_file|
|
53
|
+
# class AssetUploader < Kithe::AssetUploader
|
54
|
+
# Attacher.define_derivative :thumbnail do |original_file|
|
55
|
+
# someTempFileOrOtherIo
|
39
56
|
# end
|
40
57
|
# end
|
41
58
|
#
|
@@ -52,7 +69,7 @@ class Shrine
|
|
52
69
|
# will be passed in. You can then get the model object from `attacher.record`, or the
|
53
70
|
# original file as a `Shrine::UploadedFile` object with `attacher.file`.
|
54
71
|
#
|
55
|
-
# define_derivative :thumbnail do |original_file, attacher:|
|
72
|
+
# Attacher.define_derivative :thumbnail do |original_file, attacher:|
|
56
73
|
# attacher.record.title, attacher.file.width, attacher.file.content_type # etc
|
57
74
|
# end
|
58
75
|
#
|
@@ -62,7 +79,7 @@ class Shrine
|
|
62
79
|
# remain, and be accessible, where they were created; there is no built-in solution at present
|
63
80
|
# for moving them).
|
64
81
|
#
|
65
|
-
# define_derivative :thumbnail, storage_key: :my_thumb_storage do |original| # ...
|
82
|
+
# Attacher.define_derivative :thumbnail, storage_key: :my_thumb_storage do |original| # ...
|
66
83
|
#
|
67
84
|
# You can also set `default_create: false` if you want a particular definition not to be
|
68
85
|
# included in a no-arg `asset.create_derivatives` that is normally triggered on asset creation.
|
@@ -101,6 +118,86 @@ class Shrine
|
|
101
118
|
end.freeze
|
102
119
|
end
|
103
120
|
end
|
121
|
+
|
122
|
+
module AttacherMethods
|
123
|
+
|
124
|
+
|
125
|
+
# Similar to shrine create_derivatives, but with kithe standards:
|
126
|
+
#
|
127
|
+
# * Will call the :kithe_derivatives processor (that handles any define_derivative definitions),
|
128
|
+
# plus any processors you've configured with kithe_include_derivatives_processors
|
129
|
+
#
|
130
|
+
# * Uses the methods added by :kithe_persisted_derivatives to add derivatives completely
|
131
|
+
# concurrency-safely, if the model had it's attachment changed concurrently, you
|
132
|
+
# won't get derivatives attached that belong to old version of original attachment,
|
133
|
+
# and won't get any leftover "orphaned" derivatives either.
|
134
|
+
#
|
135
|
+
# The :kithe_derivatives processor has additional logic and options for determining
|
136
|
+
# *which* derivative definitions -- created with `define_deriative` will be executed:
|
137
|
+
#
|
138
|
+
# * Ordinarily will create a definition for every definition that has not been marked
|
139
|
+
# `default_create: false`.
|
140
|
+
#
|
141
|
+
# * But you can also pass `only` and/or `except` to customize the list of definitions to be created,
|
142
|
+
# possibly including some that are `default_create: false`.
|
143
|
+
#
|
144
|
+
# * Will normally re-create derivatives (per existing definitions) even if they already exist,
|
145
|
+
# but pass `lazy: false` to skip creating if a derivative with a given key already exists.
|
146
|
+
# This will use the asset `derivatives` association, so if you are doing this in bulk for several
|
147
|
+
# assets, you should eager-load the derivatives association for efficiency.
|
148
|
+
#
|
149
|
+
# If you've added any custom processors with `kithe_include_derivatives_processors`, it's
|
150
|
+
# your responsibility to make them respect those options. See #process_kithe_derivative?
|
151
|
+
# helper method.
|
152
|
+
#
|
153
|
+
# create_derivatives should be idempotent. If it has failed having only created some derivatives,
|
154
|
+
# you can always just run it again.
|
155
|
+
#
|
156
|
+
def kithe_create_derivatives(only: nil, except: nil, lazy: false)
|
157
|
+
return false unless file
|
158
|
+
|
159
|
+
local_files = self.process_derivatives(:kithe_derivatives, only: only, except: except, lazy: lazy)
|
160
|
+
|
161
|
+
# include any other configured processors
|
162
|
+
self.kithe_include_derivatives_processors.each do |processor|
|
163
|
+
local_files.merge!(
|
164
|
+
self.process_derivatives(processor.to_sym, only: only, except: except, lazy: lazy)
|
165
|
+
)
|
166
|
+
end
|
167
|
+
|
168
|
+
self.add_persisted_derivatives(local_files)
|
169
|
+
end
|
170
|
+
|
171
|
+
# a helper method that you can use in your own shrine processors to
|
172
|
+
# handle only/except/lazy guarding logic.
|
173
|
+
#
|
174
|
+
# @return [Boolean] should the `key` be processed based on only/except/lazy conditions?
|
175
|
+
#
|
176
|
+
# @param key [Symbol] derivative key to check for guarded processing
|
177
|
+
# @param only [Array<Symbol>] If present, method will only return true if `key` is included in `only`
|
178
|
+
# @param except [Array<Symbol] If present, method will only return true if `key` is NOT included in `except`
|
179
|
+
# @param lazy [Boolean] If true, method will only return true if derivative key is not already present
|
180
|
+
# in attacher with a value.
|
181
|
+
#
|
182
|
+
def process_kithe_derivative?(key, **options)
|
183
|
+
key = key.to_sym
|
184
|
+
only = options[:only] && Array(options[:only]).map(&:to_sym)
|
185
|
+
except = options[:except] && Array(options[:except]).map(&:to_sym)
|
186
|
+
lazy = !! options[:lazy]
|
187
|
+
|
188
|
+
(only.nil? ? true : only.include?(key)) &&
|
189
|
+
(except.nil? || ! except.include?(key)) &&
|
190
|
+
(!lazy || !derivatives.keys.include?(key))
|
191
|
+
end
|
192
|
+
|
193
|
+
# Convenience to check #process_kithe_derivative? for multiple keys at once,
|
194
|
+
# @return true if any key returns true
|
195
|
+
#
|
196
|
+
# @example process_any_kithe_derivative?([:thumb_mini, :thumb_large], only: [:thumb_large, :thumb_mega], lazy: true)
|
197
|
+
def process_any_kithe_derivative?(keys, **options)
|
198
|
+
keys.any? { |k| process_kithe_derivative?(k, **options) }
|
199
|
+
end
|
200
|
+
end
|
104
201
|
end
|
105
202
|
register_plugin(:kithe_derivative_definitions, KitheDerivativeDefinitions)
|
106
203
|
end
|
@@ -134,6 +134,10 @@ class Shrine
|
|
134
134
|
def remove_persisted_derivatives(*paths, **options)
|
135
135
|
return if paths.empty?
|
136
136
|
|
137
|
+
# Shrine does weird things if we pass in Strings, let's save ourselves
|
138
|
+
# the terrible debugging on that mistake, and noramlize to symbols
|
139
|
+
paths = paths.collect(&:to_sym)
|
140
|
+
|
137
141
|
other_changes_allowed = !!options.delete(:allow_other_changes)
|
138
142
|
if record && !other_changes_allowed && record.changed?
|
139
143
|
raise TypeError.new("Can't safely add_persisted_derivatives on model with unsaved changes. Pass `allow_other_changes: true` to force.")
|
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.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Rochkind
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: 5.2.1
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
22
|
+
version: '7.1'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
version: 5.2.1
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
32
|
+
version: '7.1'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: attr_json
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -346,6 +346,7 @@ files:
|
|
346
346
|
- Rakefile
|
347
347
|
- app/assets/config/kithe_manifest.js
|
348
348
|
- app/characterization/kithe/ffprobe_characterization.rb
|
349
|
+
- app/derivative_transformers/kithe/ffmpeg_extract_jpg.rb
|
349
350
|
- app/derivative_transformers/kithe/ffmpeg_transformer.rb
|
350
351
|
- app/derivative_transformers/kithe/vips_cli_image_to_jpeg.rb
|
351
352
|
- app/helpers/kithe/form_helper.rb
|
@@ -425,7 +426,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
425
426
|
- !ruby/object:Gem::Version
|
426
427
|
version: '0'
|
427
428
|
requirements: []
|
428
|
-
rubygems_version: 3.
|
429
|
+
rubygems_version: 3.3.20
|
429
430
|
signing_key:
|
430
431
|
specification_version: 4
|
431
432
|
summary: Shareable tools/components for building a digital collections app in Rails.
|