shrine-transloadit 0.5.1 → 1.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +469 -329
- data/lib/shrine/plugins/transloadit.rb +167 -326
- data/shrine-transloadit.gemspec +5 -7
- metadata +19 -43
- data/lib/shrine/plugins/transloadit2.rb +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 379b39a12a74f5b4e3e0c9336c1cc560eaa5ce78596fc55aa8990ea017d632bf
|
4
|
+
data.tar.gz: '04930268d5f2c682dac35cb635fd2e0be617fc6ce1c3bd55b0ee572f771b300f'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0bc371cbec27b5cf8a642eedea74c372e5b1bbef48b82956635a28dd76b02eb1436870a5ba3b18671f26bc897199c77c995df16070704688fecb3d42d11b8f74
|
7
|
+
data.tar.gz: 3da98b2895dd0af05e9f6aac2cc835105b754ef91e0ae0cd528b6cd7ace93a9ac82e8b7dc1ae5dc22b928d24caff89ebb3203b9a97735ac69349e97249ec89b4
|
data/README.md
CHANGED
@@ -1,474 +1,608 @@
|
|
1
1
|
# Shrine::Plugins::Transloadit
|
2
2
|
|
3
|
-
Provides [Transloadit] integration for [Shrine].
|
3
|
+
Provides [Transloadit] integration for [Shrine], using its [Ruby SDK].
|
4
4
|
|
5
|
-
Transloadit is a service that helps you
|
5
|
+
Transloadit is a service that helps you handle file uploads, resize, crop and
|
6
6
|
watermark your images, make GIFs, transcode your videos, extract thumbnails,
|
7
|
-
generate audio waveforms
|
8
|
-
|
7
|
+
generate audio waveforms and more.
|
8
|
+
|
9
|
+
## Contents
|
10
|
+
|
11
|
+
* [Installation](#installation)
|
12
|
+
* [Setup](#setup)
|
13
|
+
- [Credentials](#credentials)
|
14
|
+
* [Usage](#usge)
|
15
|
+
- [Backgrounding](#backgrounding)
|
16
|
+
* [Notifications](#notifications)
|
17
|
+
* [Direct uploads](#direct-uploads)
|
18
|
+
* [Promotion](#promotion)
|
19
|
+
* [Skipping exports](#skipping-exports)
|
20
|
+
* [API](#api)
|
21
|
+
- [Processing & Saving](#processing-saving)
|
22
|
+
- [Generating steps](#generating-steps)
|
23
|
+
- [Parsing files](#parsing-files)
|
24
|
+
- [Verifying signature](#verifying-signature)
|
25
|
+
- [Transloadit instance](#transloadit-instance)
|
26
|
+
|
27
|
+
## Installation
|
28
|
+
|
29
|
+
Put the gem in your Gemfile:
|
30
|
+
|
31
|
+
```rb
|
32
|
+
# Gemfile
|
33
|
+
gem "shrine-transloadit", "~> 1.0"
|
34
|
+
```
|
9
35
|
|
10
36
|
## Setup
|
11
37
|
|
12
|
-
|
13
|
-
this plugin currently supports only Amazon S3 (just because there are no Shrine
|
14
|
-
integrations written for other services on that list yet). You can just add
|
15
|
-
shrine-transloadit to your current setup:
|
38
|
+
Load the `transloadit` plugin and configure your Transloadit key and secret:
|
16
39
|
|
17
40
|
```rb
|
18
|
-
|
19
|
-
|
20
|
-
|
41
|
+
Shrine.plugin :transloadit, auth: {
|
42
|
+
key: "YOUR_TRANSLOADIT_KEY",
|
43
|
+
secret: "YOUR_TRANSLOADIT_SECRET",
|
44
|
+
}
|
21
45
|
```
|
22
46
|
|
23
|
-
|
24
|
-
require "shrine"
|
25
|
-
require "shrine/storage/s3"
|
47
|
+
### Credentials
|
26
48
|
|
27
|
-
|
28
|
-
|
29
|
-
region: "my-region",
|
30
|
-
access_key_id: "abc",
|
31
|
-
secret_access_key: "xyz",
|
32
|
-
}
|
49
|
+
You'll need to create [credentials] for the storage services you want to import
|
50
|
+
from and export to. Then you need to map these credentials to Shrine storages:
|
33
51
|
|
52
|
+
```rb
|
34
53
|
Shrine.storages = {
|
35
|
-
cache: Shrine::Storage::S3.new(prefix: "cache", **
|
36
|
-
store: Shrine::Storage::S3.new(
|
54
|
+
cache: Shrine::Storage::S3.new(prefix: "cache", **options),
|
55
|
+
store: Shrine::Storage::S3.new(**options),
|
37
56
|
}
|
38
57
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
58
|
+
Shrine.plugin :transloadit, auth: { ... },
|
59
|
+
credentials: {
|
60
|
+
cache: :s3_store, # use "s3_store" credentials for :cache storage
|
61
|
+
store: :s3_store, # use "s3_store" credentials for :store storage
|
62
|
+
}
|
44
63
|
```
|
45
64
|
|
46
|
-
|
47
|
-
uploads to Transloadit], or just use any other `:cache` storage which provides
|
48
|
-
URLs for uploaded files.
|
49
|
-
|
50
|
-
## How it works
|
51
|
-
|
52
|
-
Transloadit works in a way that you create an "assembly", which contains all
|
53
|
-
information about how the file(s) should be processed, from import to export.
|
54
|
-
Processing itself happens asynchronously, and you can give Transloadit a URL
|
55
|
-
which it will POST results to when processing finishes.
|
65
|
+
### Derivatives
|
56
66
|
|
57
|
-
|
58
|
-
|
59
|
-
a URL to the route in your app where you'd like Transloadit to POST the results
|
60
|
-
of processing. Then you can call the plugin again in the route to save the
|
61
|
-
results to your attachment column.
|
67
|
+
The examples will assume you have the [`derivatives`][derivatives] plugin
|
68
|
+
loaded:
|
62
69
|
|
63
|
-
|
64
|
-
|
70
|
+
```rb
|
71
|
+
Shrine.plugin :derivatives
|
72
|
+
```
|
65
73
|
|
66
74
|
## Usage
|
67
75
|
|
68
|
-
|
69
|
-
|
70
|
-
|
76
|
+
The `transloadit` plugin provides helper methods for creating [import][import
|
77
|
+
robots] and [export][export robots] steps, as well as for parsing out exported
|
78
|
+
files from results.
|
71
79
|
|
72
|
-
|
73
|
-
|
74
|
-
|
80
|
+
Here is a basic example where we kick off transcoding and thumbnail extraction
|
81
|
+
from an attached video, wait for assembly to complete, then save processed
|
82
|
+
files as derivatives:
|
75
83
|
|
76
84
|
```rb
|
77
|
-
class
|
78
|
-
|
79
|
-
|
80
|
-
|
85
|
+
class VideoUploader < Shrine
|
86
|
+
Attacher.transloadit_processor :video do
|
87
|
+
import = file.transloadit_import_step
|
88
|
+
encode = transloadit_step "encode", "/video/encode", use: import
|
89
|
+
thumbs = transloadit_step "thumbs", "/video/thumbs", use: import
|
90
|
+
export = store.transloadit_export_step use: [encode, thumbs]
|
91
|
+
|
92
|
+
assembly = transloadit.assembly(steps: [import, encode, thumbs, export])
|
93
|
+
assembly.create!
|
94
|
+
end
|
81
95
|
|
82
|
-
|
96
|
+
Attacher.transloadit_saver :video do |response|
|
97
|
+
transcoded = store.transloadit_file(response["results"]["encode"])
|
98
|
+
thumbnails = store.transloadit_files(response["results"]["thumbs"])
|
99
|
+
|
100
|
+
merge_derivatives(transcoded: transcoded, thumbnails: thumbnails)
|
83
101
|
end
|
84
102
|
end
|
85
103
|
```
|
104
|
+
```rb
|
105
|
+
response = attacher.transloadit_process(:video)
|
106
|
+
response.reload_until_finished!
|
86
107
|
|
87
|
-
|
88
|
-
|
89
|
-
|
108
|
+
if response.error?
|
109
|
+
# handle error
|
110
|
+
end
|
90
111
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
112
|
+
attacher.transloadit_save(:video, response)
|
113
|
+
attacher.derivatives #=>
|
114
|
+
# {
|
115
|
+
# transcoded: #<Shrine::UploadedFile storage_key=:store ...>,
|
116
|
+
# thumbnails: [
|
117
|
+
# #<Shrine::UploadedFile storage_key=:store ...>,
|
118
|
+
# #<Shrine::UploadedFile storage_key=:store ...>,
|
119
|
+
# ...
|
120
|
+
# ]
|
121
|
+
# }
|
122
|
+
```
|
96
123
|
|
97
|
-
###
|
124
|
+
### Backgrounding
|
98
125
|
|
99
|
-
|
100
|
-
|
126
|
+
When using [backgrounding], it's probably best to create the assembly after
|
127
|
+
promotion:
|
101
128
|
|
102
129
|
```rb
|
103
|
-
class
|
104
|
-
|
130
|
+
class PromoteJob
|
131
|
+
def perform(record, name, file_data)
|
132
|
+
attacher = Shrine::Attacher.retrieve(model: record, name: name, file: file_data)
|
133
|
+
attacher.atomic_promote
|
134
|
+
attacher.transloadit_process(:video)
|
135
|
+
# ...
|
136
|
+
rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
|
137
|
+
end
|
138
|
+
end
|
139
|
+
```
|
105
140
|
|
106
|
-
|
107
|
-
original = transloadit_file(io)
|
108
|
-
medium = original.add_step("resize_500", "/image/resize", width: 500)
|
109
|
-
small = original.add_step("resize_300", "/image/resize", width: 300)
|
141
|
+
## Notifications
|
110
142
|
|
111
|
-
|
143
|
+
When using [assembly notifications], the attacher data can be sent to the
|
144
|
+
webhook via `:fields`:
|
112
145
|
|
113
|
-
|
114
|
-
|
146
|
+
```rb
|
147
|
+
Attacher.transloadit_processor :video do
|
148
|
+
# ...
|
149
|
+
assembly = transloadit.assembly(
|
150
|
+
steps: [ ... ],
|
151
|
+
notify_url: "https://example.com/webhooks/transloadit",
|
152
|
+
fields: {
|
153
|
+
attacher: {
|
154
|
+
record_class: record.class,
|
155
|
+
record_id: record.id,
|
156
|
+
name: name,
|
157
|
+
data: file_data,
|
158
|
+
}
|
159
|
+
}
|
160
|
+
)
|
161
|
+
assembly.create!
|
115
162
|
end
|
116
163
|
```
|
117
164
|
|
118
|
-
|
165
|
+
Then in the webhook handler we can load the attacher and [atomically
|
166
|
+
persist][atomic_helpers] assembly results. If during processing the attachment
|
167
|
+
has changed or record was deleted, we make sure we delete processed files.
|
119
168
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
format in which shrine-transloadit should save the processed files.
|
169
|
+
```rb
|
170
|
+
post "/transloadit/video" do
|
171
|
+
Shrine.transloadit_verify!(params) # verify transloadit signature
|
124
172
|
|
125
|
-
|
173
|
+
response = JSON.parse(params["transloadit"])
|
126
174
|
|
127
|
-
|
175
|
+
record_class, record_id, name, file_data = response["fields"]["attacher"].values
|
176
|
+
record_class = Object.const_get(record_class)
|
128
177
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
thumbs = transloadit_file(io)
|
133
|
-
.add_step("thumbs", "/document/thumbs", ...)
|
134
|
-
.multiple(:list) # marks that the result of this pipeline should be saved as a list
|
178
|
+
begin
|
179
|
+
record = record_class.find(record_id)
|
180
|
+
attacher = Shrine::Attacher.retrieve(model: record, name: name, file: file_data)
|
135
181
|
|
136
|
-
|
182
|
+
attacher.transloadit_save(:video, response)
|
183
|
+
|
184
|
+
attacher.atomic_persist
|
185
|
+
rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
|
186
|
+
unless attacher
|
187
|
+
attacher = record_class.send(:"#{name}_attacher")
|
188
|
+
attacher.transloadit_save(:video, response)
|
189
|
+
end
|
190
|
+
|
191
|
+
attacher.destroy(background: true) # delete orphaned files
|
137
192
|
end
|
193
|
+
|
194
|
+
# return successful response for Transloadit
|
195
|
+
status 200
|
138
196
|
end
|
139
197
|
```
|
140
198
|
|
141
|
-
|
199
|
+
Note that if you have CSRF protection, make sure that you skip verifying the
|
200
|
+
CSRF token for this route.
|
201
|
+
|
202
|
+
## Direct uploads
|
142
203
|
|
143
|
-
|
144
|
-
|
145
|
-
# [
|
146
|
-
# #<Shrine::UploadedFile ...>
|
147
|
-
# #<Shrine::UploadedFile ...>
|
148
|
-
# ...
|
149
|
-
# ]
|
204
|
+
Transloadit supports client side uploads via [Robodog], an [Uppy]-based
|
205
|
+
JavaScript library.
|
150
206
|
|
151
|
-
|
207
|
+
If you have an HTML form, you can use Robodog's [Form API][Robodog Form] to add
|
208
|
+
Transloadit's encoding capabilities to it:
|
209
|
+
|
210
|
+
```js
|
211
|
+
window.Robodog.form('form#myform', {
|
212
|
+
params: {
|
213
|
+
auth: { key: 'YOUR_TRANSLOADIT_KEY' },
|
214
|
+
template_id: 'YOUR_TEMPLATE_ID',
|
215
|
+
},
|
216
|
+
waitForEncoding: true,
|
217
|
+
// ...
|
218
|
+
})
|
152
219
|
```
|
153
220
|
|
154
|
-
|
221
|
+
With the above setup, Robodog will send the assembly results to your controller
|
222
|
+
in the `transloadit` param, which we can parse out and save to our record. See
|
223
|
+
the [demo app] for an example of doing this.
|
224
|
+
|
225
|
+
## Promotion
|
155
226
|
|
156
|
-
Transloadit
|
157
|
-
|
227
|
+
If you want Transloadit to also upload your cached original file to permanent
|
228
|
+
storage, you can skip promotion on the Shrine side:
|
158
229
|
|
159
230
|
```rb
|
160
|
-
class
|
161
|
-
|
162
|
-
|
163
|
-
|
231
|
+
class VideoUploader < Shrine
|
232
|
+
Attacher.transloadit_processor :video do
|
233
|
+
import = file.transloadit_import_step
|
234
|
+
encode = transloadit_step "encode", "/video/encode", use: import
|
235
|
+
thumbs = transloadit_step "thumbs", "/video/thumbs", use: import
|
236
|
+
export = store.transloadit_export_step use: [import, encode, thumbs] # include original
|
237
|
+
|
238
|
+
assembly = transloadit.assembly(use: [import, encode, thumbs, export])
|
239
|
+
assembly.create!
|
240
|
+
end
|
241
|
+
|
242
|
+
Attacher.transloadit_saver :video do |response|
|
243
|
+
stored = store.transloadit_file(response["results"]["import"])
|
244
|
+
transcoded = store.transloadit_file(response["results"]["encode"])
|
245
|
+
thumbnails = store.transloadit_files(response["results"]["thumbs"])
|
246
|
+
|
247
|
+
set(stored) # set promoted file
|
248
|
+
merge_derivatives(transcoded: transcoded, thumbnails: thumbnails)
|
164
249
|
end
|
165
250
|
end
|
166
251
|
```
|
252
|
+
```rb
|
253
|
+
class PromoteJob
|
254
|
+
def perform(record, name, file_data)
|
255
|
+
attacher = Shrine::Attacher.retrieve(model: record, name: name, file: file_data)
|
167
256
|
|
168
|
-
|
169
|
-
|
257
|
+
response = attacher.transloadit_process(:video)
|
258
|
+
response.reload_until_finished!
|
170
259
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
260
|
+
if response.error?
|
261
|
+
# handle error
|
262
|
+
end
|
263
|
+
|
264
|
+
original_file = attacher.file
|
265
|
+
attacher.transloadit_save(:video, response)
|
266
|
+
|
267
|
+
attacher.atomic_persist(original_file)
|
268
|
+
rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
|
269
|
+
# delete orphaned processed files (backgrounding plugin is recommended)
|
270
|
+
attacher.destroy(background: true) if attacher
|
271
|
+
end
|
175
272
|
end
|
176
273
|
```
|
177
274
|
|
178
|
-
|
179
|
-
CSRF token for this route.
|
180
|
-
|
181
|
-
### Direct uploads
|
275
|
+
## Skipping exports
|
182
276
|
|
183
|
-
Transloadit
|
184
|
-
|
185
|
-
client side uploads, take a look its [Transloadit plugin][uppy transloadit] for
|
186
|
-
more details.
|
277
|
+
If you want to use Transloadit only for processing, and prefer to store results
|
278
|
+
to yourself, you can do so with help of the [shrine-url] gem.
|
187
279
|
|
188
|
-
```
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
.use(Uppy.Tus, {})
|
196
|
-
.use(Uppy.Transloadit, {
|
197
|
-
waitForEncoding: true,
|
198
|
-
params: {
|
199
|
-
auth: { key: 'YOUR_TRANSLOADIT_KEY' },
|
200
|
-
steps: {
|
201
|
-
// ...
|
202
|
-
}
|
203
|
-
}
|
204
|
-
})
|
280
|
+
```rb
|
281
|
+
# Gemfile
|
282
|
+
gem "shrine-url"
|
283
|
+
```
|
284
|
+
```rb
|
285
|
+
# ...
|
286
|
+
require "shrine/storage/url"
|
205
287
|
|
206
|
-
|
288
|
+
Shrine.storages = {
|
289
|
+
# ...
|
290
|
+
url: Shrine::Storage::Url.new,
|
291
|
+
}
|
207
292
|
```
|
208
293
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
which case Transloadit will return temporary URL to the processed files, which
|
213
|
-
we can use as the uploaded file identifier:
|
294
|
+
If you don't specify an export step, Transloadit will return processed files
|
295
|
+
uploaded to Transloadit's temporary storage. You can load these results using
|
296
|
+
the `:url` storage, and then upload them to your permanent storage:
|
214
297
|
|
215
|
-
```
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
transloadit: result['meta'],
|
227
|
-
}
|
228
|
-
})
|
298
|
+
```rb
|
299
|
+
class VideoUploader < Shrine
|
300
|
+
Attacher.transloadit_processor :video do
|
301
|
+
import = file.transloadit_import_step
|
302
|
+
encode = transloadit_step "encode", "/video/encode", use: import
|
303
|
+
thumbs = transloadit_step "thumbs", "/video/thumbs", use: import
|
304
|
+
# no export step
|
305
|
+
|
306
|
+
assembly = transloadit.assembly(steps: [import, encode, thumbs])
|
307
|
+
assembly.create!
|
308
|
+
end
|
229
309
|
|
230
|
-
|
231
|
-
|
232
|
-
|
310
|
+
Attacher.transloadit_saver :video do |response|
|
311
|
+
url = shrine_class.new(:url)
|
312
|
+
transcoded = url.transloadit_file(response["results"]["encode"])
|
313
|
+
thumbnails = url.transloadit_files(response["results"]["thumbs"])
|
233
314
|
|
234
|
-
|
235
|
-
|
315
|
+
# results are uploaded to Transloadit's temporary storage
|
316
|
+
transcoded #=> #<Shrine::UploadedFile @storage_key=:url @id="https://tmp.transloadit.com/..." ...>
|
317
|
+
thumbnails #=> [#<Shrine::UploadedFile @storage_key=:url @id="https://tmp.transloadit.com/..." ...>, ...]
|
236
318
|
|
319
|
+
# upload results to permanent storage
|
320
|
+
add_derivatives(transcoded: transcoded, thumbnails: thumbnails)
|
321
|
+
end
|
322
|
+
end
|
323
|
+
```
|
237
324
|
```rb
|
238
|
-
|
325
|
+
response = attacher.transloadit_process(:video)
|
326
|
+
response.reload_until_finished!
|
327
|
+
|
328
|
+
if response.error?
|
329
|
+
# handle error
|
330
|
+
end
|
331
|
+
|
332
|
+
attacher.transloadit_save(:video, response)
|
333
|
+
attacher.derivatives #=>
|
334
|
+
# {
|
335
|
+
# transcoded: #<Shrine::UploadedFile storage_key=:store ...>,
|
336
|
+
# thumbnails: [
|
337
|
+
# #<Shrine::UploadedFile storage_key=:store ...>,
|
338
|
+
# #<Shrine::UploadedFile storage_key=:store ...>,
|
339
|
+
# ...
|
340
|
+
# ]
|
341
|
+
# }
|
239
342
|
```
|
240
343
|
|
344
|
+
## API
|
345
|
+
|
346
|
+
### Processor
|
347
|
+
|
348
|
+
The processor is just a block registered under an identifier, which is expected
|
349
|
+
to create a Transloadit assembly:
|
350
|
+
|
241
351
|
```rb
|
242
|
-
|
243
|
-
|
352
|
+
class VideoUploader < Shrine
|
353
|
+
Attacher.transloadit_processor :video do
|
354
|
+
# ...
|
355
|
+
end
|
356
|
+
end
|
244
357
|
```
|
245
358
|
|
246
|
-
|
247
|
-
|
248
|
-
### Templates
|
359
|
+
It is executed when `Attacher#transloadit_process` is called:
|
249
360
|
|
250
|
-
|
251
|
-
|
361
|
+
```rb
|
362
|
+
attacher.transloadit_process(:video) # calls :video processor
|
363
|
+
```
|
252
364
|
|
253
|
-
|
254
|
-
and we just set the location of the imported file.
|
365
|
+
Any arguments passed to the processor will be given to the block:
|
255
366
|
|
256
367
|
```rb
|
257
|
-
|
258
|
-
{
|
259
|
-
steps: {
|
260
|
-
resize: {
|
261
|
-
robot: "/image/resize",
|
262
|
-
use: "import", # the "import" step will be passed in
|
263
|
-
width: 800
|
264
|
-
},
|
265
|
-
export: {
|
266
|
-
robot: "/s3/store",
|
267
|
-
use: "resize",
|
268
|
-
bucket: "YOUR_AWS_BUCKET",
|
269
|
-
key: "YOUR_AWS_KEY",
|
270
|
-
secret: "YOUR_AWS_SECRET",
|
271
|
-
bucket_region: "YOUR_AWS_REGION",
|
272
|
-
path: "videos/${unique_prefix}/${file.url_name}"
|
273
|
-
}
|
274
|
-
}
|
275
|
-
}
|
368
|
+
attacher.transloadit_process(:video, foo: "bar")
|
276
369
|
```
|
277
370
|
```rb
|
278
|
-
class
|
279
|
-
|
280
|
-
|
281
|
-
transloadit_assembly("my_template", steps: [import])
|
371
|
+
class VideoUploader < Shrine
|
372
|
+
Attacher.transloadit_processor :video do |options|
|
373
|
+
options #=> { :foo => "bar" }
|
282
374
|
end
|
283
375
|
end
|
284
376
|
```
|
285
377
|
|
286
|
-
|
287
|
-
|
288
|
-
Even though submitting a Transloadit assembly doesn't require any uploading, it
|
289
|
-
still does two HTTP requests, so you might want to put them into a background
|
290
|
-
job. You can configure that in the `TransloaditUploader` base uploader class:
|
378
|
+
The processor block is executed in context of a `Shrine::Attacher` instance:
|
291
379
|
|
292
380
|
```rb
|
293
|
-
class
|
294
|
-
|
295
|
-
|
296
|
-
auth_secret: "your transloadit secret"
|
381
|
+
class VideoUploader < Shrine
|
382
|
+
Attacher.transloadit_processor :video do
|
383
|
+
self #=> #<Shrine::Attacher>
|
297
384
|
|
298
|
-
|
385
|
+
record #=> #<Video>
|
386
|
+
name #=> :file
|
387
|
+
file #=> #<Shrine::UploadedFile>
|
388
|
+
end
|
299
389
|
end
|
300
390
|
```
|
301
|
-
```rb
|
302
|
-
class TransloaditJob
|
303
|
-
include Sidekiq::Worker
|
304
391
|
|
305
|
-
|
306
|
-
|
392
|
+
### Saver
|
393
|
+
|
394
|
+
The saver is just a block registered under an identifier, which is expected to
|
395
|
+
save given Transloadit results into the attacher:
|
396
|
+
|
397
|
+
```rb
|
398
|
+
class VideoUploader < Shrine
|
399
|
+
Attacher.transloadit_saver :video do |results|
|
400
|
+
# ...
|
307
401
|
end
|
308
402
|
end
|
309
403
|
```
|
310
404
|
|
311
|
-
|
405
|
+
It is executed when `Attacher#transloadit_save` is called:
|
406
|
+
|
407
|
+
```rb
|
408
|
+
attacher.transloadit_save(:video, results) # calls :video saver
|
409
|
+
```
|
312
410
|
|
313
|
-
|
314
|
-
about the status of that assembly, which the plugin saves to the cached
|
315
|
-
attachment's metadata.
|
411
|
+
Any arguments passed to the saver will be given to the block:
|
316
412
|
|
317
413
|
```rb
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
# "execution_duration" => 2.113,
|
327
|
-
# "params" => "{\"steps\":{...}}",
|
328
|
-
# ...
|
329
|
-
# }
|
414
|
+
attacher.transloadit_save(:video, results, foo: "bar")
|
415
|
+
```
|
416
|
+
```rb
|
417
|
+
class VideoUploader < Shrine
|
418
|
+
Attacher.transloadit_saver :video do |results, options|
|
419
|
+
options #=> { :foo => "bar" }
|
420
|
+
end
|
421
|
+
end
|
330
422
|
```
|
331
423
|
|
332
|
-
|
333
|
-
information:
|
424
|
+
The saver block is executed in context of a `Shrine::Attacher` instance:
|
334
425
|
|
335
426
|
```rb
|
336
|
-
|
337
|
-
|
338
|
-
|
427
|
+
class VideoUploader < Shrine
|
428
|
+
Attacher.transloadit_saver :video do |results|
|
429
|
+
self #=> #<Shrine::Attacher>
|
430
|
+
|
431
|
+
record #=> #<Video>
|
432
|
+
name #=> :file
|
433
|
+
file #=> #<Shrine::UploadedFile>
|
434
|
+
end
|
435
|
+
end
|
339
436
|
```
|
340
437
|
|
341
|
-
###
|
438
|
+
### Step
|
342
439
|
|
343
|
-
|
344
|
-
metadata. When the Transloadit processing is finished and the results are saved
|
345
|
-
as a Shrine attachment, this metadata will be automatically used to populate
|
346
|
-
the attachment's metadata.
|
440
|
+
You can generate `Transloadit::Step` objects with `Shrine.transloadit_step`:
|
347
441
|
|
348
|
-
|
349
|
-
|
442
|
+
```rb
|
443
|
+
Shrine.transloadit_step "my_name", "/my/robot", **options
|
444
|
+
#=> #<Transloadit::Step name="my_name", robot="/my/robot", options={...}>
|
445
|
+
```
|
446
|
+
|
447
|
+
This method adds the ability to pass another `Transloadit::Step` object as the
|
448
|
+
`:use` parameter:
|
350
449
|
|
351
450
|
```rb
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
# "date_recorded" => "2013/09/04 08:03:39",
|
356
|
-
# "date_file_created" => "2013/09/04 12:03:39 GMT",
|
357
|
-
# "date_file_modified" => "2016/07/11 02:27:11 GMT",
|
358
|
-
# "aspect_ratio" => "1.504",
|
359
|
-
# "city" => "Decatur",
|
360
|
-
# "state" => "Georgia",
|
361
|
-
# "country" => "United States",
|
362
|
-
# "latitude" => 33.77519301,
|
363
|
-
# "longitude" => -84.295608,
|
364
|
-
# "orientation" => "Horizontal (normal)",
|
365
|
-
# "colorspace" => "RGB",
|
366
|
-
# "average_color" => "#8b8688",
|
367
|
-
# ...
|
368
|
-
# }
|
451
|
+
step_one = Shrine.transloadit_step "one", "/robot/one"
|
452
|
+
step_two = Shrine.transloadit_step "two", "/robot/two", use: step_one
|
453
|
+
step_two.options[:use] #=> ["one"]
|
369
454
|
```
|
370
455
|
|
371
|
-
### Import
|
456
|
+
### Import step
|
372
457
|
|
373
|
-
|
374
|
-
|
458
|
+
The `Shrine::UploadedFile#transloadit_import_step` method generates an import
|
459
|
+
step for the uploaded file:
|
375
460
|
|
376
461
|
```rb
|
377
|
-
|
462
|
+
file = Shrine.upload(io, :store)
|
463
|
+
file.storage #=> #<Shrine::Storage::S3>
|
464
|
+
file.id #=> "foo"
|
378
465
|
|
379
|
-
|
466
|
+
step = file.transloadit_import_step
|
380
467
|
|
381
|
-
|
382
|
-
|
468
|
+
step #=> #<Transloadit::Step ...>
|
469
|
+
step.name #=> "import"
|
470
|
+
step.robot #=> "/s3/import"
|
471
|
+
|
472
|
+
step.options[:path] #=> "foo"
|
473
|
+
step.options[:credentials] #=> :s3_store (inferred from the plugin setting)
|
383
474
|
```
|
384
475
|
|
476
|
+
You can change the default step name:
|
477
|
+
|
385
478
|
```rb
|
386
|
-
|
479
|
+
step = file.transloadit_import_step("my_import")
|
480
|
+
step.name #=> "my_import"
|
481
|
+
```
|
387
482
|
|
388
|
-
|
483
|
+
You can also pass step options:
|
389
484
|
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
})
|
485
|
+
```rb
|
486
|
+
step = file.transloadit_import_step(ignore_errors: ["meta"])
|
487
|
+
step.options[:ignore_errors] #=> ["meta"]
|
394
488
|
```
|
395
489
|
|
396
|
-
|
397
|
-
expanded forms.
|
490
|
+
The following import robots are currently supported:
|
398
491
|
|
399
|
-
|
492
|
+
| Robot | Description |
|
493
|
+
| :----------- | :---------- |
|
494
|
+
| `/s3/import` | activated for `Shrine::Storage::S3` |
|
495
|
+
| `/http/import` | activated for any other storage which returns HTTP(S) URLs |
|
496
|
+
| `/ftp/import` | activated for any other storage which returns FTP URLs |
|
400
497
|
|
401
|
-
|
402
|
-
|
403
|
-
|
498
|
+
### Export step
|
499
|
+
|
500
|
+
The `Shrine#transloadit_export_step` method generates an export step for the underlying
|
501
|
+
storage:
|
404
502
|
|
405
503
|
```rb
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
504
|
+
uploader = Shrine.new(:store)
|
505
|
+
uploader.storage #=> #<Shrine::Storage::S3>
|
506
|
+
|
507
|
+
step = uploader.transloadit_export_step
|
508
|
+
|
509
|
+
step #=> #<Transloadit::Step ...>
|
510
|
+
step.name #=> "export"
|
511
|
+
step.robot #=> "/s3/store"
|
512
|
+
|
513
|
+
step.options[:credentials] #=> :s3_store (inferred from the plugin setting)
|
414
514
|
```
|
415
515
|
|
416
|
-
|
516
|
+
You can change the default step name:
|
417
517
|
|
418
|
-
|
419
|
-
|
420
|
-
|
518
|
+
```rb
|
519
|
+
step = uploader.transloadit_export_step("my_export")
|
520
|
+
step.name #=> "my_export"
|
521
|
+
```
|
522
|
+
|
523
|
+
You can also pass step options:
|
421
524
|
|
422
525
|
```rb
|
423
|
-
|
424
|
-
|
425
|
-
|
526
|
+
step = file.transloadit_export_step(acl: "public-read")
|
527
|
+
step.options[:acl] #=> "public-read"
|
528
|
+
```
|
426
529
|
|
427
|
-
|
428
|
-
notify_url = "https://myapp.com/webhooks/transloadit"
|
429
|
-
else
|
430
|
-
# In development we cannot receive webhooks, because Transloadit as an
|
431
|
-
# external service cannot reach our localhost.
|
432
|
-
end
|
530
|
+
The following export robots are currently supported:
|
433
531
|
|
434
|
-
|
435
|
-
|
436
|
-
|
532
|
+
| Robot | Description |
|
533
|
+
| :---- | :---------- |
|
534
|
+
| `/s3/store` | activated for `Shrine::Storage::S3` |
|
535
|
+
| `/google/store` | activated for [`Shrine::Storage::GoogleCloudStorage`][shrine-gcs] |
|
536
|
+
| `/youtube/store` | activated for [`Shrine::Storage::YouTube`][shrine-youtube] |
|
537
|
+
|
538
|
+
### File
|
539
|
+
|
540
|
+
The `Shrine#transloadit_file` method will convert a Transloadit result hash
|
541
|
+
into a `Shrine::UploadedFile` object:
|
542
|
+
|
543
|
+
```rb
|
544
|
+
uploader = Shrine.new(:store)
|
545
|
+
uploader.storage #=> #<Shrine::Storage::S3>
|
546
|
+
|
547
|
+
file = uploader.transloadit_file(
|
548
|
+
"url" => "https://my-bucket.s3.amazonaws.com/foo",
|
549
|
+
# ...
|
550
|
+
)
|
551
|
+
|
552
|
+
file.storage #=> #<Shrine::Storage::S3>
|
553
|
+
file.id #=> "foo"
|
437
554
|
```
|
438
555
|
|
556
|
+
It will include basic metadata:
|
557
|
+
|
439
558
|
```rb
|
440
|
-
|
441
|
-
|
559
|
+
file = uploader.transloadit_file(
|
560
|
+
# ...
|
561
|
+
"name" => "matrix.mp4",
|
562
|
+
"size" => 44198,
|
563
|
+
"mime" => "video/mp4",
|
564
|
+
)
|
565
|
+
|
566
|
+
file.original_filename #=> "matrix.mp4"
|
567
|
+
file.size #=> 44198
|
568
|
+
file.mime_type #=> "video/mp4"
|
569
|
+
```
|
442
570
|
|
443
|
-
|
444
|
-
attacher = TransloaditUploader::Attacher.transloadit_process(data)
|
571
|
+
It will also merge any custom metadata:
|
445
572
|
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
end
|
573
|
+
```rb
|
574
|
+
file = uploader.transloadit_file(
|
575
|
+
# ...
|
576
|
+
"meta" => { "duration" => 9000, ... },
|
577
|
+
)
|
578
|
+
|
579
|
+
file["duration"] #=> 9000
|
454
580
|
```
|
455
581
|
|
456
|
-
|
582
|
+
Currently only `Shrine::Stroage::S3` is supported. However, you can still
|
583
|
+
handle other remote files using [`Shrine::Storage::Url`][shrine-url]:
|
457
584
|
|
458
|
-
|
459
|
-
|
585
|
+
```rb
|
586
|
+
Shrine.storages => {
|
587
|
+
# ...
|
588
|
+
url: Shrine::Storage::Url.new,
|
589
|
+
}
|
590
|
+
```
|
591
|
+
```rb
|
592
|
+
uploader = Shrine.new(:url)
|
593
|
+
uploader #=> #<Shrine::Storage::Url>
|
460
594
|
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
S3_ACCESS_KEY_ID="..."
|
468
|
-
S3_SECRET_ACCESS_KEY="..."
|
595
|
+
file = uploader.transloadit_file(
|
596
|
+
"url" => "https://example.com/foo",
|
597
|
+
# ...
|
598
|
+
)
|
599
|
+
|
600
|
+
file.id #=> "https://example.com/foo"
|
469
601
|
```
|
470
602
|
|
471
|
-
|
603
|
+
## Contributing
|
604
|
+
|
605
|
+
Tests are run with:
|
472
606
|
|
473
607
|
```sh
|
474
608
|
$ bundle exec rake test
|
@@ -480,12 +614,18 @@ $ bundle exec rake test
|
|
480
614
|
|
481
615
|
[Shrine]: https://github.com/shrinerb/shrine
|
482
616
|
[Transloadit]: https://transloadit.com/
|
483
|
-
[
|
484
|
-
[
|
485
|
-
[
|
486
|
-
[
|
487
|
-
[
|
488
|
-
[
|
489
|
-
[
|
490
|
-
[
|
617
|
+
[Ruby SDK]: https://github.com/transloadit/ruby-sdk
|
618
|
+
[credentials]: https://transloadit.com/docs/#16-template-credentials
|
619
|
+
[import robots]: https://transloadit.com/docs/transcoding/#overview-service-file-importing
|
620
|
+
[export robots]: https://transloadit.com/docs/transcoding/#overview-service-file-exporting
|
621
|
+
[derivatives]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/derivatives.md#readme
|
622
|
+
[assembly notifications]: https://transloadit.com/docs/#24-assembly-notifications
|
623
|
+
[backgrounding]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/backgrounding.md#readme
|
624
|
+
[shrine-url]: https://github.com/shrinerb/shrine-url
|
625
|
+
[Robodog]: https://uppy.io/docs/robodog/
|
626
|
+
[Robodog Form]: https://uppy.io/docs/robodog/form/
|
627
|
+
[Uppy]: https://uppy.io/
|
628
|
+
[atomic_helpers]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/atomic_helpers.md#readme
|
629
|
+
[shrine-gcs]: https://github.com/renchap/shrine-google_cloud_storage
|
630
|
+
[shrine-youtube]: https://github.com/thedyrt/shrine-storage-you_tube
|
491
631
|
[shrine-url]: https://github.com/shrinerb/shrine-url
|