transloadit 3.0.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b480b37a302c532534cdcc551cf6cd4dd587fa835525a5a62fca02eb26971fa
4
- data.tar.gz: f2a3aa8d77377d3c95b7e8ea93d47538474724c5964067c03db82ef569942b49
3
+ metadata.gz: 6d73cc9f7b8291b8c4d208ec3f4bdd624a115bc31de35803b7651f7f86d09dee
4
+ data.tar.gz: d5298dfe9ba4df6723e087267f6a1ee1c96ab890c4888d1116a3bfba53d9a2eb
5
5
  SHA512:
6
- metadata.gz: efa23c8fcf0bacbe2a37c38355f52377ca9bdec6d521994e1ed97d8e6959e47257daf2d47ecf0874ddc143185491ebefc03a9abef4c9b7e7942fef4bebaba01a
7
- data.tar.gz: 61e34802da9d7de2e1c9d1db604b863ff4f1078f95940224c74d610045923498fd0f5c2a462f1604697d1eace135e09b65743393bbde00215d9cab599b74111c
6
+ metadata.gz: c789384262485d41d6d4a6c188f2c860efc155721197f026980c80cfc6aa61cda8018ea9a346200885fdd2f663ad2a7cfdad8df89299ed5c07209e4e1b240023
7
+ data.tar.gz: e19fc6c2f00aebd20639fbacfc787da14999d4900b7b53cb0cf5f19776160fffbe385863636c88c3cb842d5d98622478f4b5808997aaad054105e5c42cef5925
@@ -1,5 +1,12 @@
1
1
  name: CI
2
- on: push
2
+ on:
3
+ push:
4
+ branches:
5
+ - main
6
+ pull_request:
7
+ types:
8
+ - opened
9
+ - synchronize
3
10
  jobs:
4
11
  ci:
5
12
  runs-on: ubuntu-latest
@@ -9,15 +16,19 @@ jobs:
9
16
  - 3.0
10
17
  - 3.1
11
18
  - 3.2
19
+ - 3.3
12
20
  - jruby
13
- # - jruby-head
14
21
  - truffleruby
15
- # - truffleruby-head
22
+ fail-fast: false
16
23
  steps:
17
- - uses: actions/checkout@v2
24
+ - uses: actions/checkout@v3
25
+ - uses: actions/setup-node@v4
26
+ with:
27
+ node-version: 20
28
+ - run: npm install -g tsx
18
29
  - uses: ruby/setup-ruby@v1
19
30
  with:
20
31
  ruby-version: ${{ matrix.ruby }}
21
32
  bundler-cache: true
22
33
  - run: bundle exec standardrb
23
- - run: COVERAGE=false bundle exec rake test
34
+ - run: COVERAGE=0 TEST_NODE_PARITY=1 bundle exec rake test
data/.gitignore CHANGED
@@ -12,3 +12,6 @@ pkg
12
12
  transloadit-*.gem
13
13
 
14
14
  .DS_Store
15
+ env.sh
16
+ .env
17
+ vendor/bundle/
@@ -0,0 +1,13 @@
1
+ {
2
+ "folders": [
3
+ {
4
+ "path": ".."
5
+ }
6
+ ],
7
+ "settings": {
8
+ "workbench.colorCustomizations": {
9
+ "titleBar.activeForeground": "#ffffff",
10
+ "titleBar.activeBackground": "#cc0000"
11
+ },
12
+ }
13
+ }
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ### 3.1.0 / 2024-11-24
2
+
3
+ - Add Smart CDN signature support via `signed_smart_cdn_url` method (kvz)
4
+
5
+ ### 3.0.2 / 2024-03-01
6
+
7
+ - Upgrade signature algorithm to more secure SHA-384 [#69](https://github.com/transloadit/ruby-sdk/pull/69) (@aduh95)
8
+
1
9
  ### 3.0.1 / 2024-01-10
2
10
 
3
11
  - Fix `undefined method` errors when handling network exceptions [#67](https://github.com/transloadit/ruby-sdk/pull/67) (@Acconut)
data/Makefile ADDED
@@ -0,0 +1,18 @@
1
+ .PHONY: all test fix
2
+
3
+ all: fix test
4
+
5
+ # Run tests
6
+ test:
7
+ bundle exec rake test
8
+
9
+ # Fix code formatting
10
+ fix:
11
+ bundle exec standardrb --fix
12
+
13
+ # Install dependencies
14
+ install:
15
+ bundle install
16
+
17
+ # Run both fix and test
18
+ check: fix test
data/README.md CHANGED
@@ -11,7 +11,7 @@ A **Ruby** Integration for [Transloadit](https://transloadit.com)'s file uploadi
11
11
 
12
12
  This is a **Ruby** SDK to make it easy to talk to the [Transloadit](https://transloadit.com) REST API.
13
13
 
14
- *If you run Ruby on Rails and are looking to integrate with the browser for file uploads, checkout the [rails-sdk](https://github.com/transloadit/rails-sdk).*
14
+ _If you run Ruby on Rails and are looking to integrate with the browser for file uploads, checkout the [rails-sdk](https://github.com/transloadit/rails-sdk)._
15
15
 
16
16
  ## Install
17
17
 
@@ -29,14 +29,14 @@ $ irb -rubygems
29
29
  => true
30
30
  ```
31
31
 
32
- Then create a Transloadit instance, which will maintain your
33
- [authentication credentials](https://transloadit.com/accounts/credentials)
32
+ Then create a Transloadit instance, which will maintain your
33
+ [authentication credentials](https://transloadit.com/accounts/credentials)
34
34
  and allow us to make requests to [the API](https://transloadit.com/docs/api/).
35
35
 
36
36
  ```ruby
37
37
  transloadit = Transloadit.new(
38
- :key => 'YOUR_TRANSLOADIT_KEY',
39
- :secret => 'YOUR_TRANSLOADIT_SECRET'
38
+ :key => 'MY_TRANSLOADIT_KEY',
39
+ :secret => 'MY_TRANSLOADIT_SECRET'
40
40
  )
41
41
  ```
42
42
 
@@ -49,8 +49,8 @@ and store the result on [Amazon S3](https://aws.amazon.com/s3/).
49
49
  require 'transloadit'
50
50
 
51
51
  transloadit = Transloadit.new(
52
- :key => 'YOUR_TRANSLOADIT_KEY',
53
- :secret => 'YOUR_TRANSLOADIT_SECRET'
52
+ :key => 'MY_TRANSLOADIT_KEY',
53
+ :secret => 'MY_TRANSLOADIT_SECRET'
54
54
  )
55
55
 
56
56
  # First, we create two steps: one to resize the image to 320x240, and another to
@@ -60,9 +60,9 @@ resize = transloadit.step 'resize', '/image/resize',
60
60
  :height => 240
61
61
 
62
62
  store = transloadit.step 'store', '/s3/store',
63
- :key => 'YOUR_AWS_KEY',
64
- :secret => 'YOUR_AWS_SECRET',
65
- :bucket => 'YOUR_S3_BUCKET'
63
+ :key => 'MY_AWS_KEY',
64
+ :secret => 'MY_AWS_SECRET',
65
+ :bucket => 'MY_S3_BUCKET'
66
66
 
67
67
  # Now that we have the steps, we create an assembly (which is just a request to
68
68
  # process a file or set of files) and let Transloadit do the rest.
@@ -125,7 +125,7 @@ API at the time the <dfn>Assembly</dfn> was created. You have to explicitly ask
125
125
  # reloads the response's contents from the REST API
126
126
  response.reload!
127
127
 
128
- # reloads once per second until all processing is finished, up to number of
128
+ # reloads once per second until all processing is finished, up to number of
129
129
  # times specified in :tries option, otherwise will raise ReloadLimitReached
130
130
  response.reload_until_finished! tries: 300 # default is 600
131
131
  ```
@@ -147,8 +147,8 @@ than one file in the same request. You can also pass a single <dfn>Step</dfn> fo
147
147
  require 'transloadit'
148
148
 
149
149
  transloadit = Transloadit.new(
150
- :key => 'YOUR_TRANSLOADIT_KEY',
151
- :secret => 'YOUR_TRANSLOADIT_SECRET'
150
+ :key => 'MY_TRANSLOADIT_KEY',
151
+ :secret => 'MY_TRANSLOADIT_SECRET'
152
152
  )
153
153
 
154
154
  assembly = transloadit.assembly(steps: store)
@@ -160,7 +160,7 @@ response = assembly.create!(
160
160
  )
161
161
  ```
162
162
 
163
- You can also pass an array of files to the `create!` method.
163
+ You can also pass an array of files to the `create!` method.
164
164
  Just unpack the array using the splat `*` operator.
165
165
 
166
166
  ```ruby
@@ -178,8 +178,8 @@ simply need to `use` other <dfn>Steps</dfn>. Following
178
178
  require 'transloadit'
179
179
 
180
180
  transloadit = Transloadit.new(
181
- :key => 'YOUR_TRANSLOADIT_KEY',
182
- :secret => 'YOUR_TRANSLOADIT_SECRET'
181
+ :key => 'MY_TRANSLOADIT_KEY',
182
+ :secret => 'MY_TRANSLOADIT_SECRET'
183
183
  )
184
184
 
185
185
  encode = transloadit.step 'encode', '/video/encode', { ... }
@@ -208,17 +208,17 @@ for recurring encoding tasks. In order to use these do the following:
208
208
  require 'transloadit'
209
209
 
210
210
  transloadit = Transloadit.new(
211
- :key => 'YOUR_TRANSLOADIT_KEY',
212
- :secret => 'YOUR_TRANSLOADIT_SECRET'
211
+ :key => 'MY_TRANSLOADIT_KEY',
212
+ :secret => 'MY_TRANSLOADIT_SECRET'
213
213
  )
214
214
 
215
215
  transloadit.assembly(
216
- :template_id => 'YOUR_TEMPLATE_ID'
216
+ :template_id => 'MY_TEMPLATE_ID'
217
217
  ).create! open('/PATH/TO/FILE.mpg')
218
218
  ```
219
219
 
220
220
  You can use your steps together with this template and even use variables.
221
- The [Transloadit documentation](https://transloadit.com/docs/#passing-variables-into-a-template)
221
+ The [Transloadit documentation](https://transloadit.com/docs/#passing-variables-into-a-template)
222
222
  has some nice examples for that.
223
223
 
224
224
  ### 5. Using fields
@@ -231,8 +231,8 @@ to the upload itself. You can use fields like the following:
231
231
  require 'transloadit'
232
232
 
233
233
  transloadit = Transloadit.new(
234
- :key => 'YOUR_TRANSLOADIT_KEY',
235
- :secret => 'YOUR_TRANSLOADIT_SECRET'
234
+ :key => 'MY_TRANSLOADIT_KEY',
235
+ :secret => 'MY_TRANSLOADIT_SECRET'
236
236
  )
237
237
 
238
238
  transloadit.assembly(
@@ -252,8 +252,8 @@ a Notify URL for the <dfn>Assembly</dfn>.
252
252
  require 'transloadit'
253
253
 
254
254
  transloadit = Transloadit.new(
255
- :key => 'YOUR_TRANSLOADIT_KEY',
256
- :secret => 'YOUR_TRANSLOADIT_SECRET'
255
+ :key => 'MY_TRANSLOADIT_KEY',
256
+ :secret => 'MY_TRANSLOADIT_SECRET'
257
257
  )
258
258
 
259
259
  transloadit.assembly(
@@ -271,8 +271,8 @@ Transloadit also provides methods to retrieve/replay <dfn>Assemblies</dfn> and t
271
271
  require 'transloadit'
272
272
 
273
273
  transloadit = Transloadit.new(
274
- :key => 'YOUR_TRANSLOADIT_KEY',
275
- :secret => 'YOUR_TRANSLOADIT_SECRET'
274
+ :key => 'MY_TRANSLOADIT_KEY',
275
+ :secret => 'MY_TRANSLOADIT_SECRET'
276
276
  )
277
277
 
278
278
  assembly = transloadit.assembly
@@ -281,10 +281,10 @@ assembly = transloadit.assembly
281
281
  assembly.list
282
282
 
283
283
  # returns a specific assembly
284
- assembly.get 'YOUR_ASSEMBLY_ID'
284
+ assembly.get 'MY_ASSEMBLY_ID'
285
285
 
286
286
  # replays a specific assembly
287
- response = assembly.replay 'YOUR_ASSEMBLY_ID'
287
+ response = assembly.replay 'MY_ASSEMBLY_ID'
288
288
  # should return true if assembly is replaying and false otherwise.
289
289
  response.replaying?
290
290
 
@@ -292,7 +292,7 @@ response.replaying?
292
292
  assembly.get_notifications
293
293
 
294
294
  # replays an assembly notification
295
- assembly.replay_notification 'YOUR_ASSEMBLY_ID'
295
+ assembly.replay_notification 'MY_ASSEMBLY_ID'
296
296
  ```
297
297
 
298
298
  ### 8. Templates
@@ -304,8 +304,8 @@ for recurring encoding tasks. Here's how you would create a <dfn>Template</dfn>:
304
304
  require 'transloadit'
305
305
 
306
306
  transloadit = Transloadit.new(
307
- :key => 'YOUR_TRANSLOADIT_KEY',
308
- :secret => 'YOUR_TRANSLOADIT_SECRET'
307
+ :key => 'MY_TRANSLOADIT_KEY',
308
+ :secret => 'MY_TRANSLOADIT_SECRET'
309
309
  )
310
310
 
311
311
  template = transloadit.template
@@ -331,8 +331,8 @@ There are also some other methods to retrieve, update and delete a <dfn>Template
331
331
  require 'transloadit'
332
332
 
333
333
  transloadit = Transloadit.new(
334
- :key => 'YOUR_TRANSLOADIT_KEY',
335
- :secret => 'YOUR_TRANSLOADIT_SECRET'
334
+ :key => 'MY_TRANSLOADIT_KEY',
335
+ :secret => 'MY_TRANSLOADIT_SECRET'
336
336
  )
337
337
 
338
338
  template = transloadit.template
@@ -341,11 +341,11 @@ template = transloadit.template
341
341
  template.list
342
342
 
343
343
  # returns a specific template.
344
- template.get 'YOUR_TEMPLATE_ID'
344
+ template.get 'MY_TEMPLATE_ID'
345
345
 
346
346
  # updates the template whose id is specified.
347
347
  template.update(
348
- 'YOUR_TEMPLATE_ID',
348
+ 'MY_TEMPLATE_ID',
349
349
  :name => 'CHANGED_TEMPLATE_NAME',
350
350
  :template => {
351
351
  :steps => {
@@ -358,7 +358,7 @@ template.update(
358
358
  )
359
359
 
360
360
  # deletes a specific template
361
- template.delete 'YOUR_TEMPLATE_ID'
361
+ template.delete 'MY_TEMPLATE_ID'
362
362
  ```
363
363
 
364
364
  ### 9. Getting Bill reports
@@ -370,8 +370,8 @@ you can use the `bill` method passing the required month and year like the follo
370
370
  require 'transloadit'
371
371
 
372
372
  transloadit = Transloadit.new(
373
- :key => 'YOUR_TRANSLOADIT_KEY',
374
- :secret => 'YOUR_TRANSLOADIT_SECRET'
373
+ :key => 'MY_TRANSLOADIT_KEY',
374
+ :secret => 'MY_TRANSLOADIT_SECRET'
375
375
  )
376
376
 
377
377
  # returns bill report for February, 2016.
@@ -380,7 +380,48 @@ transloadit.bill(2, 2016)
380
380
 
381
381
  Not specifying the `month` or `year` would default to the current month or year.
382
382
 
383
- ### 10. Rate limits
383
+ ### 10. Signing Smart CDN URLs
384
+
385
+ You can generate signed [Smart CDN](https://transloadit.com/services/content-delivery/) URLs using your Transloadit instance:
386
+
387
+ ```ruby
388
+ require 'transloadit'
389
+
390
+ transloadit = Transloadit.new(
391
+ :key => 'MY_TRANSLOADIT_KEY',
392
+ :secret => 'MY_TRANSLOADIT_SECRET'
393
+ )
394
+
395
+ # Generate a signed URL using instance credentials
396
+ url = transloadit.signed_smart_cdn_url(
397
+ workspace: "MY_WORKSPACE",
398
+ template: "MY_TEMPLATE",
399
+ input: "avatars/jane.jpg"
400
+ )
401
+
402
+ # Add URL parameters
403
+ url = transloadit.signed_smart_cdn_url(
404
+ workspace: "MY_WORKSPACE",
405
+ template: "MY_TEMPLATE",
406
+ input: "avatars/jane.jpg",
407
+ url_params: {
408
+ width: 100,
409
+ height: 200
410
+ }
411
+ )
412
+
413
+ # Set expiration time
414
+ url = transloadit.signed_smart_cdn_url(
415
+ workspace: "MY_WORKSPACE",
416
+ template: "MY_TEMPLATE",
417
+ input: "avatars/jane.jpg",
418
+ expire_at_ms: 1732550672867 # Specific timestamp
419
+ )
420
+ ```
421
+
422
+ The generated URL will be signed using your Transloadit credentials and can be used to access files through the Smart CDN in a secure manner.
423
+
424
+ ### 11. Rate limits
384
425
 
385
426
  Transloadit enforces rate limits to guarantee that no customers are adversely affected by the usage
386
427
  of any given customer. See [Rate Limiting](https://transloadit.com/docs/api/#rate-limiting).
@@ -393,8 +434,8 @@ To change the number of attempts that will be made when creating an <dfn>Assembl
393
434
  require 'transloadit'
394
435
 
395
436
  transloadit = Transloadit.new(
396
- :key => 'YOUR_TRANSLOADIT_KEY',
397
- :secret => 'YOUR_TRANSLOADIT_SECRET'
437
+ :key => 'MY_TRANSLOADIT_KEY',
438
+ :secret => 'MY_TRANSLOADIT_SECRET'
398
439
  )
399
440
 
400
441
  # would make one extra attempt after a failed attempt.
@@ -423,3 +464,24 @@ Please see [ci.yml](https://github.com/transloadit/ruby-sdk/tree/main/.github/wo
423
464
  ### Ruby 2.x
424
465
 
425
466
  If you still need support for Ruby 2.x, 2.0.1 is the last version that supports it.
467
+
468
+ ## Contributing
469
+
470
+ ### Running tests
471
+
472
+ ```bash
473
+ bundle install
474
+ bundle exec rake test
475
+ ```
476
+
477
+ To also test parity against the Node.js reference implementation, run:
478
+
479
+ ```bash
480
+ TEST_NODE_PARITY=1 bundle exec rake test
481
+ ```
482
+
483
+ To disable coverage reporting, run:
484
+
485
+ ```bash
486
+ COVERAGE=0 bundle exec rake test
487
+ ```
data/examples/README.md CHANGED
@@ -40,8 +40,8 @@ utilizing our credentials that we set in environment variables.
40
40
  ### First example
41
41
 
42
42
  In the [first example](https://github.com/transloadit/ruby-sdk/blob/main/examples/basic/image-transcoder.rb)
43
- that gets played, we fetch an image from the cat api, optimize it using the Transloadit `/image/optimize` robot, and then optionally
44
- stores it in s3 if the s3 credentials are set.
43
+ that gets played, we load an image, optimize it using the Transloadit `/image/optimize` robot, and then optionally
44
+ store it in s3 if the s3 credentials are set.
45
45
 
46
46
  There are only two steps:
47
47
 
@@ -65,7 +65,7 @@ begin
65
65
 
66
66
  steps.push(store)
67
67
  rescue KeyError => e
68
- p 's3 config not set. Skipping s3 storage...'
68
+ puts 's3 config not set. Skipping s3 storage...'
69
69
  end
70
70
 
71
71
  ```
@@ -119,7 +119,7 @@ begin
119
119
 
120
120
  steps.push(store)
121
121
  rescue KeyError => e
122
- p 's3 config not set. Skipping s3 storage...'
122
+ puts 's3 config not set. Skipping s3 storage...'
123
123
  end
124
124
  ```
125
125
 
@@ -175,10 +175,10 @@ concat = transloadit_client.step('concat', '/audio/concat', {
175
175
 
176
176
  Taking a look at the `concat` step, we see a different usage of the `use` parameter
177
177
  than we have seen in previous examples. We are effectively able to define the ordering of the
178
- concatenation by specifying the ```name```, `as` and `fields` parameters.
178
+ concatenation by specifying the ```name```, `as` and `fields` parameters.
179
179
 
180
180
  In this example, we have set the name for each to `:original`, specifying that the input
181
- at index `i` should be the input file defined at index `i`.
181
+ at index `i` should be the input file defined at index `i`.
182
182
 
183
183
  It is equally important to specify the `as` parameter. This simple parameter tells the assembly
184
184
  the ordering.
@@ -205,7 +205,7 @@ begin
205
205
 
206
206
  steps.push(store)
207
207
  rescue KeyError => e
208
- p 's3 config not set. Skipping s3 storage...'
208
+ puts 's3 config not set. Skipping s3 storage...'
209
209
  end
210
210
 
211
211
  assembly = transloadit_client.assembly(steps: steps)
Binary file
@@ -27,7 +27,7 @@ class AudioConcatTranscoder < MediaTranscoder
27
27
 
28
28
  steps.push(store)
29
29
  rescue KeyError
30
- p "s3 config not set. Skipping s3 storage..."
30
+ puts "s3 config not set. Skipping s3 storage..."
31
31
  end
32
32
 
33
33
  assembly = transloadit_client.assembly(steps: steps)
@@ -30,7 +30,7 @@ class AudioTranscoder < MediaTranscoder
30
30
 
31
31
  steps.push(store)
32
32
  rescue KeyError
33
- p "s3 config not set. Skipping s3 storage..."
33
+ puts "s3 config not set. Skipping s3 storage..."
34
34
  end
35
35
 
36
36
  assembly = transloadit_client.assembly(steps: steps)
@@ -23,7 +23,7 @@ class ImageTranscoder < MediaTranscoder
23
23
 
24
24
  steps.push(store)
25
25
  rescue KeyError
26
- p "s3 config not set. Skipping s3 storage..."
26
+ puts "s3 config not set. Skipping s3 storage..."
27
27
  end
28
28
 
29
29
  assembly = transloadit_client.assembly(steps: steps)
@@ -1,63 +1,56 @@
1
- require "open-uri"
2
1
  require_relative "media-transcoder"
3
2
  require_relative "image-transcoder"
4
3
  require_relative "audio-transcoder"
5
4
  require_relative "audio-concat-transcoder"
6
5
 
7
- p "starting image transcoding job..."
8
- p "fetching image from the cat api..."
6
+ puts "starting image transcoding job..."
9
7
 
10
- open("http://thecatapi.com/api/images/get") do |f|
11
- p "starting transcoding job..."
8
+ File.open("#{__dir__}/assets/cat.jpg") do |f|
12
9
  image_transcoder = ImageTranscoder.new
13
10
  response = image_transcoder.transcode!(f)
14
11
 
15
12
  # if you are using rails one thing you can do would be to start an ActiveJob process that recursively
16
13
  # checks on the status of the assembly until it is finished
17
- p "checking job status..."
14
+ puts "checking job status..."
18
15
  response.reload_until_finished!
19
16
 
20
- p response[:message]
21
- p response[:results]["image"][0]["url"]
17
+ puts response[:message]
18
+ puts response[:results]["image"][0]["ssl_url"]
19
+ puts "\n"
22
20
  end
23
21
 
24
- p "starting audio transcoding job..."
25
- p "fetching soundbite from nasa..."
26
- p "\n"
22
+ puts "starting audio transcoding job..."
27
23
 
28
- open("https://www.nasa.gov/640379main_Computers_are_in_Control.m4r") do |f|
29
- p "starting transcoding job..."
24
+ File.open("#{__dir__}/assets/Computers_are_in_Control.flac") do |f|
30
25
  audio_transcoder = AudioTranscoder.new
31
26
  response = audio_transcoder.transcode!(f)
32
27
 
33
28
  # if you are using rails one thing you can do would be to start an ActiveJob process that recursively
34
29
  # checks on the status of the assembly until it is finished
35
- p "checking job status..."
30
+ puts "checking job status..."
36
31
  response.reload_until_finished!
37
32
 
38
- p response[:message]
39
- p response[:results]["mp3"][0]["url"]
40
- p "\n"
33
+ puts response[:message]
34
+ puts response[:results]["mp3"][0]["ssl_url"]
35
+ puts "\n"
41
36
  end
42
37
 
43
- p "starting audio concat transcoding job..."
44
- p "fetching 3 soundbites from nasa..."
38
+ puts "starting audio concat transcoding job..."
45
39
 
46
40
  files = [
47
- "https://www.nasa.gov/mp3/640148main_APU%20Shutdown.mp3",
48
- "https://www.nasa.gov/mp3/640164main_Go%20for%20Deploy.mp3",
49
- "https://www.nasa.gov/mp3/640165main_Lookin%20At%20It.mp3"
41
+ "#{__dir__}/assets/APU_Shutdown.mp3",
42
+ "#{__dir__}/assets/Go_for_Deploy.mp3",
43
+ "#{__dir__}/assets/Lookin_At_It.mp3"
50
44
  ]
51
45
 
52
- p "starting transcoding job..."
53
46
  audio_concat_transcoder = AudioConcatTranscoder.new
54
47
  response = audio_concat_transcoder.transcode!(files)
55
48
 
56
49
  # if you are using rails one thing you can do would be to start an ActiveJob process that recursively
57
50
  # checks on the status of the assembly until it is finished
58
- p "checking job status..."
51
+ puts "checking job status..."
59
52
  response.reload_until_finished!
60
53
 
61
- p response[:message]
62
- p response[:results]["concat"][0]["url"]
63
- p "\n"
54
+ puts response[:message]
55
+ puts response[:results]["concat"][0]["ssl_url"]
56
+ puts "\n"
@@ -4,7 +4,7 @@ require "transloadit"
4
4
  # Represents an Assembly API ready to make calls to the REST API endpoints.
5
5
  #
6
6
  # See the Transloadit {documentation}[https://transloadit.com/docs/api-docs/#assembly-api]
7
- # for futher information on Assemblies and available endpoints.
7
+ # for further information on Assemblies and available endpoints.
8
8
  #
9
9
  class Transloadit::Assembly < Transloadit::ApiModel
10
10
  DEFAULT_TRIES = 3
@@ -23,7 +23,7 @@ class Transloadit::Assembly < Transloadit::ApiModel
23
23
  # at which point Transloadit will process and store the files according to the
24
24
  # rules in the Assembly.
25
25
  # See the Transloadit {documentation}[https://transloadit.com/docs/building-assembly-instructions]
26
- # for futher information on Assemblies and their parameters.
26
+ # for further information on Assemblies and their parameters.
27
27
  #
28
28
  # Accepts as many IO objects as you wish to process in the assembly.
29
29
  # The last argument is an optional Hash
@@ -16,7 +16,7 @@ class Transloadit::Request
16
16
  API_HEADERS = {"Transloadit-Client" => "ruby-sdk:#{Transloadit::VERSION}"}
17
17
 
18
18
  # The HMAC algorithm used for calculation request signatures.
19
- HMAC_ALGORITHM = OpenSSL::Digest.new("sha1")
19
+ HMAC_ALGORITHM = OpenSSL::Digest.new("sha384")
20
20
 
21
21
  # @return [String] the API endpoint for the request
22
22
  attr_reader :url
@@ -203,6 +203,6 @@ class Transloadit::Request
203
203
  # @return [String] the HMAC signature for the params
204
204
  #
205
205
  def signature(params)
206
- self.class._hmac(secret, params) if secret.to_s.length > 0
206
+ "sha384:" + self.class._hmac(secret, params) if secret.to_s.length > 0
207
207
  end
208
208
  end
@@ -6,7 +6,7 @@ require "transloadit"
6
6
  # +options+ specific to the chosen robot.
7
7
  #
8
8
  # See the Transloadit {documentation}[https://transloadit.com/docs/building-assembly-instructions]
9
- # for futher information on robot types and their parameters.
9
+ # for further information on robot types and their parameters.
10
10
  #
11
11
  class Transloadit::Step
12
12
  # @return [String] the name to give the step
@@ -4,7 +4,7 @@ require "transloadit"
4
4
  # Represents a Template API ready to interact with its corresponding REST API.
5
5
  #
6
6
  # See the Transloadit {documentation}[https://transloadit.com/docs/api-docs/#template-api]
7
- # for futher information on Templates and their parameters.
7
+ # for further information on Templates and their parameters.
8
8
  #
9
9
  class Transloadit::Template < Transloadit::ApiModel
10
10
  #
@@ -1,3 +1,3 @@
1
1
  class Transloadit
2
- VERSION = "3.0.1"
2
+ VERSION = "3.1.0"
3
3
  end
data/lib/transloadit.rb CHANGED
@@ -1,5 +1,9 @@
1
1
  require "multi_json"
2
2
  require "date"
3
+ require "json"
4
+ require "openssl"
5
+ require "uri"
6
+ require "cgi"
3
7
 
4
8
  #
5
9
  # Implements the Transloadit REST API in Ruby. Check the {file:README.md README}
@@ -11,6 +15,7 @@ class Transloadit
11
15
  autoload :Exception, "transloadit/exception"
12
16
  autoload :Request, "transloadit/request"
13
17
  autoload :Response, "transloadit/response"
18
+ autoload :SmartCDN, "transloadit/smart_cdn"
14
19
  autoload :Step, "transloadit/step"
15
20
  autoload :Template, "transloadit/template"
16
21
  autoload :VERSION, "transloadit/version"
@@ -83,7 +88,7 @@ class Transloadit
83
88
  # Creates a Transloadit::Template instance ready to interact with its corresponding REST API.
84
89
  #
85
90
  # See the Transloadit {documentation}[https://transloadit.com/docs/api-docs/#template-api]
86
- # for futher information on Templates and available endpoints.
91
+ # for further information on Templates and available endpoints.
87
92
  #
88
93
  def template(options = {})
89
94
  Transloadit::Template.new(self, options)
@@ -130,6 +135,54 @@ class Transloadit
130
135
  MultiJson.dump(to_hash)
131
136
  end
132
137
 
138
+ # @param workspace [String] Workspace slug
139
+ # @param template [String] Template slug or template ID
140
+ # @param input [String] Input value that is provided as `${fields.input}` in the template
141
+ # @param url_params [Hash] Additional parameters for the URL query string (optional)
142
+ # @param expire_at_ms [Integer] Expiration time as Unix timestamp in milliseconds (optional)
143
+ # @return [String] Signed Smart CDN URL
144
+ def signed_smart_cdn_url(
145
+ workspace:,
146
+ template:,
147
+ input:,
148
+ expire_at_ms: nil,
149
+ url_params: {}
150
+ )
151
+ raise ArgumentError, "workspace is required" if workspace.nil? || workspace.empty?
152
+ raise ArgumentError, "template is required" if template.nil? || template.empty?
153
+ raise ArgumentError, "input is required" if input.nil?
154
+
155
+ workspace_slug = CGI.escape(workspace)
156
+ template_slug = CGI.escape(template)
157
+ input_field = CGI.escape(input)
158
+
159
+ expire_at = expire_at_ms || (Time.now.to_i * 1000 + 60 * 60 * 1000) # 1 hour default
160
+
161
+ query_params = {}
162
+ url_params.each do |key, value|
163
+ next if value.nil?
164
+ Array(value).each do |val|
165
+ next if val.nil?
166
+ (query_params[key.to_s] ||= []) << val.to_s
167
+ end
168
+ end
169
+
170
+ query_params["auth_key"] = [key]
171
+ query_params["exp"] = [expire_at.to_s]
172
+
173
+ # Sort parameters to ensure consistent ordering
174
+ sorted_params = query_params.sort.flat_map do |key, values|
175
+ values.map { |v| "#{CGI.escape(key)}=#{CGI.escape(v)}" }
176
+ end.join("&")
177
+
178
+ string_to_sign = "#{workspace_slug}/#{template_slug}/#{input_field}?#{sorted_params}"
179
+
180
+ signature = OpenSSL::HMAC.hexdigest("sha256", secret, string_to_sign)
181
+
182
+ final_params = "#{sorted_params}&sig=#{CGI.escape("sha256:#{signature}")}"
183
+ "https://#{workspace_slug}.tlcdn.com/#{template_slug}/#{input_field}?#{final_params}"
184
+ end
185
+
133
186
  private
134
187
 
135
188
  #
@@ -72,7 +72,7 @@ http_interactions:
72
72
  recorded_at: Fri, 08 Mar 2013 15:13:10 GMT
73
73
  - request:
74
74
  method: get
75
- uri: https://api2.transloadit.com/?params=%7B%22params%22:%7B%22foo%22:%22bar%22%7D%7D&signature=78f291e3038e3eeb82d9f79e11a68fe7b858ee97
75
+ uri: https://api2.transloadit.com/?params=%7B%22params%22:%7B%22foo%22:%22bar%22%7D%7D&signature=sha384:edccc99aef8cb46e087e17093fbcd6a2316e2fbe31dc0842c4af87a52808d0736d94a3bd5774deca2c215b53804ca572
76
76
  body:
77
77
  encoding: US-ASCII
78
78
  string: ''
data/test/test_helper.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
2
  $:.unshift File.expand_path("../../lib", __FILE__)
3
3
 
4
- if ENV["COVERAGE"] != "false"
4
+ if ENV["COVERAGE"] != "0"
5
5
  require "simplecov"
6
6
  SimpleCov.start { add_filter "/test/" }
7
7
  end
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env tsx
2
+ // Reference Smart CDN (https://transloadit.com/services/content-delivery/) Signature implementation
3
+ // And CLI tester to see if our SDK's implementation
4
+ // matches Node's
5
+
6
+ /// <reference types="node" />
7
+
8
+ import { createHash, createHmac } from 'crypto'
9
+
10
+ interface SmartCDNParams {
11
+ workspace: string
12
+ template: string
13
+ input: string
14
+ expire_at_ms?: number
15
+ auth_key?: string
16
+ auth_secret?: string
17
+ url_params?: Record<string, any>
18
+ }
19
+
20
+ function signSmartCDNUrl(params: SmartCDNParams): string {
21
+ const {
22
+ workspace,
23
+ template,
24
+ input,
25
+ expire_at_ms,
26
+ auth_key = 'my-key',
27
+ auth_secret = 'my-secret',
28
+ url_params = {},
29
+ } = params
30
+
31
+ if (!workspace) throw new Error('workspace is required')
32
+ if (!template) throw new Error('template is required')
33
+ if (input === null || input === undefined)
34
+ throw new Error('input must be a string')
35
+
36
+ const workspaceSlug = encodeURIComponent(workspace)
37
+ const templateSlug = encodeURIComponent(template)
38
+ const inputField = encodeURIComponent(input)
39
+
40
+ const expireAt = expire_at_ms ?? Date.now() + 60 * 60 * 1000 // 1 hour default
41
+
42
+ const queryParams: Record<string, string[]> = {}
43
+
44
+ // Handle url_params
45
+ Object.entries(url_params).forEach(([key, value]) => {
46
+ if (value === null || value === undefined) return
47
+ if (Array.isArray(value)) {
48
+ value.forEach((val) => {
49
+ if (val === null || val === undefined) return
50
+ ;(queryParams[key] ||= []).push(String(val))
51
+ })
52
+ } else {
53
+ queryParams[key] = [String(value)]
54
+ }
55
+ })
56
+
57
+ queryParams.auth_key = [auth_key]
58
+ queryParams.exp = [String(expireAt)]
59
+
60
+ // Sort parameters to ensure consistent ordering
61
+ const sortedParams = Object.entries(queryParams)
62
+ .sort()
63
+ .map(([key, values]) =>
64
+ values.map((v) => `${encodeURIComponent(key)}=${encodeURIComponent(v)}`)
65
+ )
66
+ .flat()
67
+ .join('&')
68
+
69
+ const stringToSign = `${workspaceSlug}/${templateSlug}/${inputField}?${sortedParams}`
70
+ const signature = createHmac('sha256', auth_secret)
71
+ .update(stringToSign)
72
+ .digest('hex')
73
+
74
+ const finalParams = `${sortedParams}&sig=${encodeURIComponent(
75
+ `sha256:${signature}`
76
+ )}`
77
+ return `https://${workspaceSlug}.tlcdn.com/${templateSlug}/${inputField}?${finalParams}`
78
+ }
79
+
80
+ // Read JSON from stdin
81
+ let jsonInput = ''
82
+ process.stdin.on('data', (chunk) => {
83
+ jsonInput += chunk
84
+ })
85
+
86
+ process.stdin.on('end', () => {
87
+ const params = JSON.parse(jsonInput)
88
+ console.log(signSmartCDNUrl(params))
89
+ })
@@ -286,7 +286,7 @@ describe Transloadit::Assembly do
286
286
  end
287
287
 
288
288
  describe "when replaying assembly notification" do
289
- it "must replay notification of sepcified assembly" do
289
+ it "must replay notification of specified assembly" do
290
290
  VCR.use_cassette "replay_assembly_notification" do
291
291
  response = @assembly.replay_notification "2ea5d21063ad11e6bc93e53395ce4e7d"
292
292
 
@@ -0,0 +1,169 @@
1
+ require "test_helper"
2
+ require "json"
3
+ require "open3"
4
+
5
+ describe Transloadit do
6
+ before do
7
+ @auth_key = "my-key"
8
+ @auth_secret = "my-secret"
9
+ @transloadit = Transloadit.new(key: @auth_key, secret: @auth_secret)
10
+ @workspace = "my-app"
11
+ @template = "test-smart-cdn"
12
+ @input = "inputs/prinsengracht.jpg"
13
+ @expire_at = 1732550672867
14
+ end
15
+
16
+ def run_node_script(params)
17
+ return unless ENV["TEST_NODE_PARITY"] == "1"
18
+ script_path = File.expand_path("./node-smartcdn-sig", __dir__)
19
+ json_input = JSON.dump(params)
20
+ stdout, stderr, status = Open3.capture3("tsx #{script_path}", stdin_data: json_input)
21
+ raise "Node script failed: #{stderr}" unless status.success?
22
+ stdout.strip
23
+ end
24
+
25
+ describe "#signed_smart_cdn_url" do
26
+ it "requires workspace" do
27
+ assert_raises ArgumentError, "workspace is required" do
28
+ @transloadit.signed_smart_cdn_url(
29
+ workspace: nil,
30
+ template: @template,
31
+ input: @input
32
+ )
33
+ end
34
+
35
+ assert_raises ArgumentError, "workspace is required" do
36
+ @transloadit.signed_smart_cdn_url(
37
+ workspace: "",
38
+ template: @template,
39
+ input: @input
40
+ )
41
+ end
42
+ end
43
+
44
+ it "requires template" do
45
+ assert_raises ArgumentError, "template is required" do
46
+ @transloadit.signed_smart_cdn_url(
47
+ workspace: @workspace,
48
+ template: nil,
49
+ input: @input
50
+ )
51
+ end
52
+
53
+ assert_raises ArgumentError, "template is required" do
54
+ @transloadit.signed_smart_cdn_url(
55
+ workspace: @workspace,
56
+ template: "",
57
+ input: @input
58
+ )
59
+ end
60
+ end
61
+
62
+ it "requires input" do
63
+ assert_raises ArgumentError, "input is required" do
64
+ @transloadit.signed_smart_cdn_url(
65
+ workspace: @workspace,
66
+ template: @template,
67
+ input: nil
68
+ )
69
+ end
70
+ end
71
+
72
+ it "allows empty input string" do
73
+ params = {
74
+ workspace: @workspace,
75
+ template: @template,
76
+ input: "",
77
+ expire_at_ms: @expire_at
78
+ }
79
+ expected_url = "https://my-app.tlcdn.com/test-smart-cdn/?auth_key=my-key&exp=1732550672867&sig=sha256%3Ad5e13df4acde8d4aaa0f34534489e54098b5128c54392600ed96dd77669a533e"
80
+
81
+ url = @transloadit.signed_smart_cdn_url(**params)
82
+ assert_equal expected_url, url
83
+
84
+ if (node_url = run_node_script(params.merge(auth_key: "my-key", auth_secret: "my-secret")))
85
+ assert_equal expected_url, node_url
86
+ end
87
+ end
88
+
89
+ it "uses instance credentials" do
90
+ params = {
91
+ workspace: @workspace,
92
+ template: @template,
93
+ input: @input,
94
+ expire_at_ms: @expire_at
95
+ }
96
+ expected_url = "https://my-app.tlcdn.com/test-smart-cdn/inputs%2Fprinsengracht.jpg?auth_key=my-key&exp=1732550672867&sig=sha256%3A8620fc2a22aec6081cde730b7f3f29c0d8083f58a68f62739e642b3c03709139"
97
+
98
+ url = @transloadit.signed_smart_cdn_url(**params)
99
+ assert_equal expected_url, url
100
+
101
+ if (node_url = run_node_script(params.merge(auth_key: "my-key", auth_secret: "my-secret")))
102
+ assert_equal expected_url, node_url
103
+ end
104
+ end
105
+
106
+ it "includes empty width parameter" do
107
+ params = {
108
+ workspace: @workspace,
109
+ template: @template,
110
+ input: @input,
111
+ expire_at_ms: @expire_at,
112
+ url_params: {
113
+ width: "",
114
+ height: 200
115
+ }
116
+ }
117
+ expected_url = "https://my-app.tlcdn.com/test-smart-cdn/inputs%2Fprinsengracht.jpg?auth_key=my-key&exp=1732550672867&height=200&width=&sig=sha256%3Aebf562722c504839db97165e657583f74192ac4ab580f1a0dd67d3d868b4ced3"
118
+
119
+ url = @transloadit.signed_smart_cdn_url(**params)
120
+ assert_equal expected_url, url
121
+
122
+ if (node_url = run_node_script(params.merge(auth_key: "my-key", auth_secret: "my-secret")))
123
+ assert_equal expected_url, node_url
124
+ end
125
+ end
126
+
127
+ it "handles nil values in parameters" do
128
+ params = {
129
+ workspace: @workspace,
130
+ template: @template,
131
+ input: @input,
132
+ expire_at_ms: @expire_at,
133
+ url_params: {
134
+ width: nil,
135
+ height: 200
136
+ }
137
+ }
138
+ expected_url = "https://my-app.tlcdn.com/test-smart-cdn/inputs%2Fprinsengracht.jpg?auth_key=my-key&exp=1732550672867&height=200&sig=sha256%3Ad6897a0cb527a14eaab13c54b06f53527797c553d8b7e5d0b1a5df237212f083"
139
+
140
+ url = @transloadit.signed_smart_cdn_url(**params)
141
+ assert_equal expected_url, url
142
+
143
+ if (node_url = run_node_script(params.merge(auth_key: "my-key", auth_secret: "my-secret")))
144
+ assert_equal expected_url, node_url
145
+ end
146
+ end
147
+
148
+ it "handles array values in parameters" do
149
+ params = {
150
+ workspace: @workspace,
151
+ template: @template,
152
+ input: @input,
153
+ expire_at_ms: @expire_at,
154
+ url_params: {
155
+ tags: ["landscape", "amsterdam", nil, ""],
156
+ height: 200
157
+ }
158
+ }
159
+ expected_url = "https://my-app.tlcdn.com/test-smart-cdn/inputs%2Fprinsengracht.jpg?auth_key=my-key&exp=1732550672867&height=200&tags=landscape&tags=amsterdam&tags=&sig=sha256%3Aff46eb0083d64b250b2e4510380e333f67da855b2401493dee7a706a47957d3f"
160
+
161
+ url = @transloadit.signed_smart_cdn_url(**params)
162
+ assert_equal expected_url, url
163
+
164
+ if (node_url = run_node_script(params.merge(auth_key: "my-key", auth_secret: "my-secret")))
165
+ assert_equal expected_url, node_url
166
+ end
167
+ end
168
+ end
169
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: transloadit
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Touset
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-01-10 00:00:00.000000000 Z
12
+ date: 1980-01-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rest-client
@@ -177,12 +177,19 @@ files:
177
177
  - ".github/workflows/ci.yml"
178
178
  - ".gitignore"
179
179
  - ".standard.yml"
180
+ - ".vscode/ruby-sdk.code-workspace"
180
181
  - CHANGELOG.md
181
182
  - Gemfile
182
183
  - LICENSE
184
+ - Makefile
183
185
  - README.md
184
186
  - Rakefile
185
187
  - examples/README.md
188
+ - examples/basic/assets/APU_Shutdown.mp3
189
+ - examples/basic/assets/Computers_are_in_Control.flac
190
+ - examples/basic/assets/Go_for_Deploy.mp3
191
+ - examples/basic/assets/Lookin_At_It.mp3
192
+ - examples/basic/assets/cat.jpg
186
193
  - examples/basic/audio-concat-transcoder.rb
187
194
  - examples/basic/audio-transcoder.rb
188
195
  - examples/basic/image-transcoder.rb
@@ -221,10 +228,12 @@ files:
221
228
  - test/fixtures/cassettes/update_template.yml
222
229
  - test/test_helper.rb
223
230
  - test/unit/test_transloadit.rb
231
+ - test/unit/transloadit/node-smartcdn-sig.ts
224
232
  - test/unit/transloadit/test_api.rb
225
233
  - test/unit/transloadit/test_assembly.rb
226
234
  - test/unit/transloadit/test_request.rb
227
235
  - test/unit/transloadit/test_response.rb
236
+ - test/unit/transloadit/test_smart_cdn.rb
228
237
  - test/unit/transloadit/test_step.rb
229
238
  - test/unit/transloadit/test_template.rb
230
239
  - transloadit.gemspec
@@ -247,7 +256,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
247
256
  - !ruby/object:Gem::Version
248
257
  version: 2.2.0
249
258
  requirements: []
250
- rubygems_version: 3.5.3
259
+ rubygems_version: 3.5.22
251
260
  signing_key:
252
261
  specification_version: 4
253
262
  summary: Official Ruby gem for Transloadit