vzaar_api 2.0.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 +7 -0
- data/.gitignore +13 -0
- data/.rspec +4 -0
- data/.tool-versions +1 -0
- data/.travis.yml +3 -0
- data/Changelog +50 -0
- data/Gemfile +3 -0
- data/Guardfile +25 -0
- data/README.md +55 -0
- data/Rakefile +26 -0
- data/examples/README.md +33 -0
- data/examples/api_envs.yml.example +31 -0
- data/examples/category/create_update_delete_spec.rb +100 -0
- data/examples/category/list_spec.rb +38 -0
- data/examples/category/list_subtree_spec.rb +40 -0
- data/examples/category/lookup_spec.rb +35 -0
- data/examples/encoding_preset/list_spec.rb +38 -0
- data/examples/encoding_preset/lookup_spec.rb +35 -0
- data/examples/ingest_recipe/create_update_delete_spec.rb +70 -0
- data/examples/ingest_recipe/list_spec.rb +38 -0
- data/examples/ingest_recipe/lookup_spec.rb +35 -0
- data/examples/playlist/create_update_delete_spec.rb +97 -0
- data/examples/playlist/list_spec.rb +37 -0
- data/examples/playlist/lookup_spec.rb +34 -0
- data/examples/rate_limit_spec.rb +18 -0
- data/examples/spec_helper.rb +17 -0
- data/examples/support/helpers.rb +16 -0
- data/examples/support/videos/medium.mp4 +0 -0
- data/examples/support/videos/small.mp4 +0 -0
- data/examples/video/create_update_delete_spec.rb +73 -0
- data/lib/vzaar_api/abstract.rb +9 -0
- data/lib/vzaar_api/category.rb +39 -0
- data/lib/vzaar_api/encoding_preset.rb +19 -0
- data/lib/vzaar_api/ingest_recipe.rb +35 -0
- data/lib/vzaar_api/legacy_rendition.rb +11 -0
- data/lib/vzaar_api/lib/active_object.rb +92 -0
- data/lib/vzaar_api/lib/api.rb +54 -0
- data/lib/vzaar_api/lib/api_response.rb +61 -0
- data/lib/vzaar_api/lib/has_attributes.rb +49 -0
- data/lib/vzaar_api/lib/has_collection_builder.rb +17 -0
- data/lib/vzaar_api/lib/has_resource_url.rb +24 -0
- data/lib/vzaar_api/lib/paged_resource.rb +80 -0
- data/lib/vzaar_api/lib/will_paginate.rb +22 -0
- data/lib/vzaar_api/link_upload.rb +14 -0
- data/lib/vzaar_api/playlist.rb +29 -0
- data/lib/vzaar_api/rendition.rb +16 -0
- data/lib/vzaar_api/signature/abstract.rb +40 -0
- data/lib/vzaar_api/signature/factory.rb +39 -0
- data/lib/vzaar_api/signature/multipart.rb +23 -0
- data/lib/vzaar_api/signature/single.rb +17 -0
- data/lib/vzaar_api/strategy/video/create.rb +46 -0
- data/lib/vzaar_api/upload/s3.rb +90 -0
- data/lib/vzaar_api/upload/virtual_file.rb +14 -0
- data/lib/vzaar_api/version.rb +4 -0
- data/lib/vzaar_api/video.rb +38 -0
- data/lib/vzaar_api.rb +60 -0
- data/spec/fixtures/vcr_cassettes/categories/each_item.yml +363 -0
- data/spec/fixtures/vcr_cassettes/categories/find.yml +61 -0
- data/spec/fixtures/vcr_cassettes/categories/find_404.yml +49 -0
- data/spec/fixtures/vcr_cassettes/categories/paginate_first.yml +61 -0
- data/spec/fixtures/vcr_cassettes/categories/paginate_last.yml +119 -0
- data/spec/fixtures/vcr_cassettes/categories/paginate_next.yml +120 -0
- data/spec/fixtures/vcr_cassettes/categories/paginate_previous.yml +120 -0
- data/spec/fixtures/vcr_cassettes/categories/subtree.yml +127 -0
- data/spec/fixtures/vcr_cassettes/categories/subtree_paginate_first.yml +123 -0
- data/spec/fixtures/vcr_cassettes/categories/subtree_paginate_last.yml +185 -0
- data/spec/fixtures/vcr_cassettes/categories/subtree_paginate_next.yml +184 -0
- data/spec/fixtures/vcr_cassettes/categories/subtree_paginate_previous.yml +184 -0
- data/spec/fixtures/vcr_cassettes/encoding_presets/each_item.yml +299 -0
- data/spec/fixtures/vcr_cassettes/encoding_presets/find.yml +62 -0
- data/spec/fixtures/vcr_cassettes/encoding_presets/find_404.yml +51 -0
- data/spec/fixtures/vcr_cassettes/encoding_presets/paginate_first.yml +62 -0
- data/spec/fixtures/vcr_cassettes/encoding_presets/paginate_last.yml +121 -0
- data/spec/fixtures/vcr_cassettes/encoding_presets/paginate_next.yml +121 -0
- data/spec/fixtures/vcr_cassettes/encoding_presets/paginate_previous.yml +121 -0
- data/spec/fixtures/vcr_cassettes/ingest_recipes/create_200.yml +63 -0
- data/spec/fixtures/vcr_cassettes/ingest_recipes/create_422.yml +52 -0
- data/spec/fixtures/vcr_cassettes/ingest_recipes/delete_204.yml +166 -0
- data/spec/fixtures/vcr_cassettes/ingest_recipes/delete_422.yml +112 -0
- data/spec/fixtures/vcr_cassettes/ingest_recipes/each_item.yml +182 -0
- data/spec/fixtures/vcr_cassettes/ingest_recipes/find.yml +62 -0
- data/spec/fixtures/vcr_cassettes/ingest_recipes/find_404.yml +51 -0
- data/spec/fixtures/vcr_cassettes/ingest_recipes/paginate_first.yml +62 -0
- data/spec/fixtures/vcr_cassettes/ingest_recipes/paginate_last.yml +122 -0
- data/spec/fixtures/vcr_cassettes/ingest_recipes/paginate_next.yml +121 -0
- data/spec/fixtures/vcr_cassettes/ingest_recipes/paginate_previous.yml +122 -0
- data/spec/fixtures/vcr_cassettes/ingest_recipes/update_200.yml +242 -0
- data/spec/fixtures/vcr_cassettes/ingest_recipes/update_422.yml +113 -0
- data/spec/fixtures/vcr_cassettes/playlists/each_item.yml +607 -0
- data/spec/fixtures/vcr_cassettes/playlists/find.yml +66 -0
- data/spec/fixtures/vcr_cassettes/playlists/find_404.yml +51 -0
- data/spec/fixtures/vcr_cassettes/playlists/paginate_first.yml +74 -0
- data/spec/fixtures/vcr_cassettes/playlists/paginate_last.yml +146 -0
- data/spec/fixtures/vcr_cassettes/playlists/paginate_next.yml +145 -0
- data/spec/fixtures/vcr_cassettes/playlists/paginate_previous.yml +145 -0
- data/spec/fixtures/vcr_cassettes/signature/multipart_201.yml +62 -0
- data/spec/fixtures/vcr_cassettes/signature/multipart_422.yml +52 -0
- data/spec/fixtures/vcr_cassettes/signature/single_201.yml +62 -0
- data/spec/fixtures/vcr_cassettes/signature/single_422.yml +51 -0
- data/spec/fixtures/vcr_cassettes/upload/multipart_201.yml +279868 -0
- data/spec/fixtures/vcr_cassettes/upload/multipart_403.yml +116578 -0
- data/spec/fixtures/vcr_cassettes/upload/single_201.yml +23388 -0
- data/spec/fixtures/vcr_cassettes/upload/single_403.yml +23374 -0
- data/spec/fixtures/vcr_cassettes/videos/create/error.yml +51 -0
- data/spec/fixtures/vcr_cassettes/videos/create/guid_201.yml +65 -0
- data/spec/fixtures/vcr_cassettes/videos/create/guid_error.yml +52 -0
- data/spec/fixtures/vcr_cassettes/videos/create/link_201.yml +65 -0
- data/spec/fixtures/vcr_cassettes/videos/create/link_error.yml +51 -0
- data/spec/fixtures/vcr_cassettes/videos/create/path_201.yml +23509 -0
- data/spec/fixtures/vcr_cassettes/videos/delete_204.yml +168 -0
- data/spec/fixtures/vcr_cassettes/videos/find.yml +66 -0
- data/spec/fixtures/vcr_cassettes/videos/find_404.yml +51 -0
- data/spec/fixtures/vcr_cassettes/videos/paginate_first.yml +71 -0
- data/spec/fixtures/vcr_cassettes/videos/paginate_last.yml +137 -0
- data/spec/fixtures/vcr_cassettes/videos/paginate_next.yml +139 -0
- data/spec/fixtures/vcr_cassettes/videos/paginate_previous.yml +139 -0
- data/spec/spec_helper.rb +103 -0
- data/spec/support/files/video-1.0MB.mp4 +0 -0
- data/spec/support/files/video-12.0MB.mp4 +0 -0
- data/spec/support/files/video-4.9MB.mp4 +0 -0
- data/spec/support/files/video-5.0MB.mp4 +0 -0
- data/spec/support/helpers.rb +16 -0
- data/spec/vzaar_api/category_spec.rb +141 -0
- data/spec/vzaar_api/encoding_preset_spec.rb +92 -0
- data/spec/vzaar_api/ingest_recipe_spec.rb +197 -0
- data/spec/vzaar_api/lib/api_spec.rb +28 -0
- data/spec/vzaar_api/playlist_spec.rb +97 -0
- data/spec/vzaar_api/rendition_spec.rb +55 -0
- data/spec/vzaar_api/signature/factory_spec.rb +68 -0
- data/spec/vzaar_api/signature/multipart_spec.rb +81 -0
- data/spec/vzaar_api/signature/single_spec.rb +72 -0
- data/spec/vzaar_api/upload/s3_spec.rb +112 -0
- data/spec/vzaar_api/video_spec.rb +248 -0
- data/spec/vzaar_api/vzaar_api_spec.rb +18 -0
- data/spec/vzaar_api_helper.rb +19 -0
- data/vzaar.png +0 -0
- data/vzaar_api.gemspec +35 -0
- metadata +413 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require_relative './../spec_helper'
|
|
2
|
+
|
|
3
|
+
module VzaarApi
|
|
4
|
+
describe 'Ingest recipe: Lookup' do
|
|
5
|
+
|
|
6
|
+
let(:described_class) { IngestRecipe }
|
|
7
|
+
let(:id) { api_envs['ingest_recipe']['default'] }
|
|
8
|
+
|
|
9
|
+
context 'when user is authenticated' do
|
|
10
|
+
before { setup_for :account_owner }
|
|
11
|
+
|
|
12
|
+
context 'and resource can be found' do
|
|
13
|
+
subject { described_class.find(id) }
|
|
14
|
+
specify { expect(subject.id).to eq id }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
context 'and resource cannot be found' do
|
|
18
|
+
it 'raises an error' do
|
|
19
|
+
expect{ described_class.find(-1) }.to raise_error(
|
|
20
|
+
Error, 'Not found: Resource cannot be found')
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context 'when user is not authenticated' do
|
|
26
|
+
before { setup_for :intruder }
|
|
27
|
+
|
|
28
|
+
it 'raises an error' do
|
|
29
|
+
expect{ described_class.find(id) }.to raise_error(
|
|
30
|
+
Error, 'Authentication failed: Invalid credentials')
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
require_relative './../spec_helper'
|
|
2
|
+
|
|
3
|
+
module VzaarApi
|
|
4
|
+
describe 'Playlist: Create / Update / Delete' do
|
|
5
|
+
|
|
6
|
+
let(:described_class) { Playlist }
|
|
7
|
+
|
|
8
|
+
context 'when user is authenticated' do
|
|
9
|
+
before { setup_for :account_owner }
|
|
10
|
+
|
|
11
|
+
let(:attrs) { { title: 'new SDK playlist', category_id: api_envs['category_id'] } }
|
|
12
|
+
|
|
13
|
+
context "missing required parameters" do
|
|
14
|
+
it "errors out" do
|
|
15
|
+
expect{described_class.create}.to raise_error(
|
|
16
|
+
Error, "Invalid parameters: title is missing, category_id is missing"
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'creates, updates and deletes a playlist' do
|
|
22
|
+
# create new playlist
|
|
23
|
+
playlist = described_class.create attrs
|
|
24
|
+
expect(playlist.title).to eq attrs[:title]
|
|
25
|
+
expect(playlist.category_id).to eq attrs[:category_id]
|
|
26
|
+
expect(playlist.max_vids).to eq 10
|
|
27
|
+
expect(playlist.sort_by).to eq 'created_at'
|
|
28
|
+
expect(playlist.sort_order).to eq 'desc'
|
|
29
|
+
expect(playlist.private).to be_truthy
|
|
30
|
+
expect(playlist.dimensions).to eq 'auto'
|
|
31
|
+
expect(playlist.position).to eq 'left'
|
|
32
|
+
expect(playlist.autoplay).to be_falsey
|
|
33
|
+
expect(playlist.continuous_play).to be_falsey
|
|
34
|
+
expect(playlist.embed_code).to match(
|
|
35
|
+
"<iframe id=\"vzpl-#{playlist.id}\" name=\"vzpl-#{playlist.id}\" " \
|
|
36
|
+
"title=\"vzaar video player\" class=\"vzaar video player\" " \
|
|
37
|
+
"type=\"text/html\" width=\"927\" height=\"432\" frameborder=\"0\" " \
|
|
38
|
+
"allowFullScreen allowTransparency=\"true\" mozallowfullscreen " \
|
|
39
|
+
"webkitAllowFullScreen src=\"//#{api_envs["vd_hostname"]}/playlists/#{playlist.id}\">" \
|
|
40
|
+
"</iframe>"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# reload the playlist
|
|
44
|
+
playlist = described_class.find(playlist.id)
|
|
45
|
+
|
|
46
|
+
# update the playlist
|
|
47
|
+
expect(playlist).not_to be_changed
|
|
48
|
+
new_title = playlist.title = "(updated): #{Time.now.utc}"
|
|
49
|
+
playlist.max_vids = 11
|
|
50
|
+
playlist.sort_by = 'title'
|
|
51
|
+
playlist.sort_order = 'asc'
|
|
52
|
+
playlist.private = false
|
|
53
|
+
playlist.dimensions = '400x200'
|
|
54
|
+
playlist.position = 'top'
|
|
55
|
+
playlist.autoplay = true
|
|
56
|
+
playlist.continuous_play = true
|
|
57
|
+
|
|
58
|
+
expect(playlist).to be_changed
|
|
59
|
+
playlist.save
|
|
60
|
+
expect(playlist).not_to be_changed
|
|
61
|
+
|
|
62
|
+
expect(playlist.title).to eq new_title
|
|
63
|
+
expect(playlist.max_vids).to eq 11
|
|
64
|
+
expect(playlist.sort_by).to eq 'title'
|
|
65
|
+
expect(playlist.sort_order).to eq 'asc'
|
|
66
|
+
expect(playlist.private).to be_falsey
|
|
67
|
+
expect(playlist.dimensions).to eq '400x200'
|
|
68
|
+
expect(playlist.position).to eq 'top'
|
|
69
|
+
expect(playlist.autoplay).to be_truthy
|
|
70
|
+
expect(playlist.continuous_play).to be_truthy
|
|
71
|
+
expect(playlist.embed_code).to match(
|
|
72
|
+
"<iframe id=\"vzpl-#{playlist.id}\" name=\"vzpl-#{playlist.id}\" " \
|
|
73
|
+
"title=\"vzaar video player\" class=\"vzaar video player\" " \
|
|
74
|
+
"type=\"text/html\" width=\"400\" height=\"330\" frameborder=\"0\" " \
|
|
75
|
+
"allowFullScreen allowTransparency=\"true\" mozallowfullscreen " \
|
|
76
|
+
"webkitAllowFullScreen src=\"//#{api_envs["vd_hostname"]}/playlists/#{playlist.id}\">" \
|
|
77
|
+
"</iframe>"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# delete the playlist
|
|
81
|
+
playlist.delete
|
|
82
|
+
expect{ described_class.find(playlist.id) }.to raise_error(
|
|
83
|
+
Error, 'Not found: Resource cannot be found')
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
context 'when user is not authenticated' do
|
|
88
|
+
before { setup_for :intruder }
|
|
89
|
+
let(:attrs) { { title: 'no', category_id: 2253 } }
|
|
90
|
+
|
|
91
|
+
it 'raises an error' do
|
|
92
|
+
expect{ described_class.create(attrs) }.to raise_error(
|
|
93
|
+
Error, 'Authentication failed: Invalid credentials')
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require_relative './../spec_helper'
|
|
2
|
+
|
|
3
|
+
module VzaarApi
|
|
4
|
+
describe 'Playlist: List' do
|
|
5
|
+
|
|
6
|
+
let(:described_class) { Playlist }
|
|
7
|
+
|
|
8
|
+
context 'when user is authenticated' do
|
|
9
|
+
before { setup_for :account_owner }
|
|
10
|
+
|
|
11
|
+
describe '#each_item' do
|
|
12
|
+
it 'retrieves the resource list' do
|
|
13
|
+
ids = described_class.each_item.map(&:id)
|
|
14
|
+
expect(ids).not_to be_empty
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe '#paginate' do
|
|
19
|
+
let(:pager) { described_class.paginate(page: 2, per_page: 1) }
|
|
20
|
+
specify { expect(pager.first.count).to eq 1 }
|
|
21
|
+
specify { expect(pager.next.count).to eq 1 }
|
|
22
|
+
specify { expect(pager.previous.count).to eq 1 }
|
|
23
|
+
specify { expect(pager.last.count).to eq 1 }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context 'when user is not authenticated' do
|
|
28
|
+
before { setup_for :intruder }
|
|
29
|
+
|
|
30
|
+
it 'raises an error' do
|
|
31
|
+
pager = described_class.paginate
|
|
32
|
+
expect{ pager.first }.to raise_error(
|
|
33
|
+
Error, 'Authentication failed: Invalid credentials')
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require_relative './../spec_helper'
|
|
2
|
+
|
|
3
|
+
module VzaarApi
|
|
4
|
+
describe 'Playlist: Lookup' do
|
|
5
|
+
|
|
6
|
+
let(:described_class) { Playlist }
|
|
7
|
+
let(:id) { api_envs['playlist_id'] }
|
|
8
|
+
|
|
9
|
+
context 'when user is authenticated' do
|
|
10
|
+
before { setup_for :account_owner }
|
|
11
|
+
|
|
12
|
+
context 'and resource can be found' do
|
|
13
|
+
subject { described_class.find(id) }
|
|
14
|
+
specify { expect(subject.id).to eq id }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
context 'and resource cannot be found' do
|
|
18
|
+
it 'raises an error' do
|
|
19
|
+
expect{ described_class.find(-1) }.to raise_error(
|
|
20
|
+
Error, 'Not found: Resource cannot be found')
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context 'when user is not authenticated' do
|
|
26
|
+
before { setup_for :intruder }
|
|
27
|
+
|
|
28
|
+
it 'raises an error' do
|
|
29
|
+
expect{ described_class.find(id) }.to raise_error(
|
|
30
|
+
Error, 'Authentication failed: Invalid credentials')
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require_relative './spec_helper'
|
|
2
|
+
|
|
3
|
+
module VzaarApi
|
|
4
|
+
describe 'Rate limit' do
|
|
5
|
+
|
|
6
|
+
let(:described_class) { EncodingPreset }
|
|
7
|
+
let(:id) { api_envs['encoding_preset_id'] }
|
|
8
|
+
|
|
9
|
+
before { setup_for :account_owner }
|
|
10
|
+
|
|
11
|
+
it 'is available after each request' do
|
|
12
|
+
EncodingPreset.find(id)
|
|
13
|
+
expect(VzaarApi.rate_limit).to eq 200
|
|
14
|
+
expect(VzaarApi.rate_limit_remaining).to be < 200
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
3
|
+
|
|
4
|
+
require 'vzaar_api'
|
|
5
|
+
|
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
|
7
|
+
# in ./support/ and its subdirectories.
|
|
8
|
+
Dir["./examples/support/**/*.rb"].each {|f| require f}
|
|
9
|
+
|
|
10
|
+
RSpec.configure do |c|
|
|
11
|
+
c.include Helpers
|
|
12
|
+
c.order = 'defined'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
VCR.configure do |c|
|
|
16
|
+
c.allow_http_connections_when_no_cassette = true
|
|
17
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Helpers
|
|
2
|
+
|
|
3
|
+
def api_envs
|
|
4
|
+
@api_envs = begin
|
|
5
|
+
env = ENV["API_ENV"] || "development"
|
|
6
|
+
YAML.load_file("api_envs.yml")[env]
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def setup_for(user)
|
|
11
|
+
VzaarApi.hostname = api_envs['hostname'] if api_envs['hostname']
|
|
12
|
+
VzaarApi.auth_token = api_envs[user.to_s]['auth_token']
|
|
13
|
+
VzaarApi.client_id = api_envs[user.to_s]['client_id']
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require_relative './../spec_helper'
|
|
2
|
+
|
|
3
|
+
module VzaarApi
|
|
4
|
+
describe 'Video: Create' do
|
|
5
|
+
|
|
6
|
+
let(:described_class) { Video }
|
|
7
|
+
|
|
8
|
+
context 'when user is authenticated' do
|
|
9
|
+
before { setup_for :account_owner }
|
|
10
|
+
|
|
11
|
+
context 'when doing a single-part upload' do
|
|
12
|
+
it 'creates, updates and deletes the video' do
|
|
13
|
+
attrs = { title: "single: #{Time.now.utc}", path: 'examples/support/videos/small.mp4' }
|
|
14
|
+
video = described_class.create(attrs)
|
|
15
|
+
expect(video.title).to eq attrs[:title]
|
|
16
|
+
|
|
17
|
+
# reload the video
|
|
18
|
+
video = described_class.find(video.id)
|
|
19
|
+
|
|
20
|
+
# update the video
|
|
21
|
+
expect(video).not_to be_changed
|
|
22
|
+
video.title = "single (updated): #{Time.now.utc}"
|
|
23
|
+
video.description = 'this is the new description'
|
|
24
|
+
expect(video).to be_changed
|
|
25
|
+
video.save
|
|
26
|
+
expect(video).not_to be_changed
|
|
27
|
+
|
|
28
|
+
# delete the video
|
|
29
|
+
video.delete
|
|
30
|
+
expect{ described_class.find(video.id) }.to raise_error(
|
|
31
|
+
Error, 'Not found: Resource cannot be found')
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context 'when doing a multi-part upload' do
|
|
36
|
+
it 'creates the video' do
|
|
37
|
+
attrs = { title: "multi-part: #{Time.now.utc}", path: 'examples/support/videos/medium.mp4' }
|
|
38
|
+
video = described_class.create(attrs)
|
|
39
|
+
expect(video.title).to eq attrs[:title]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context 'when doing a multi-part upload with a non-default ingest recipe' do
|
|
44
|
+
it 'creates the video' do
|
|
45
|
+
attrs = { title: "custom-recipe: #{Time.now.utc}",
|
|
46
|
+
ingest_recipe_id: api_envs['ingest_recipe']['other'],
|
|
47
|
+
path: 'examples/support/videos/medium.mp4' }
|
|
48
|
+
video = described_class.create(attrs)
|
|
49
|
+
expect(video.title).to eq attrs[:title]
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
context 'when doing a link upload' do
|
|
54
|
+
it 'creates the video' do
|
|
55
|
+
attrs = { title: "link: #{Time.now.utc}", url: 'https://www.dropbox.com/s/zu1n51dm9sabogq/dropbox-video.mp4?dl=0' }
|
|
56
|
+
video = described_class.create(attrs)
|
|
57
|
+
expect(video.title).to eq attrs[:title]
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context 'when user is not authenticated' do
|
|
63
|
+
before { setup_for :intruder }
|
|
64
|
+
|
|
65
|
+
it 'raises an error' do
|
|
66
|
+
attrs = { path: 'examples/support/videos/small.mp4' }
|
|
67
|
+
expect{ described_class.create(attrs) }.to raise_error(
|
|
68
|
+
Error, 'Authentication failed: Invalid credentials')
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
class Category < Abstract
|
|
3
|
+
|
|
4
|
+
ENDPOINT = 'categories'
|
|
5
|
+
|
|
6
|
+
ATTR_READERS = [:id, :account_id, :user_id, :name,
|
|
7
|
+
:description, :parent_id, :depth,
|
|
8
|
+
:node_children_count, :tree_children_count,
|
|
9
|
+
:node_video_count, :tree_video_count,
|
|
10
|
+
:created_at, :updated_at].freeze
|
|
11
|
+
|
|
12
|
+
ATTR_ACCESSORS = [:name, :parent_id, :move_to_root].freeze
|
|
13
|
+
|
|
14
|
+
prepend Lib::HasAttributes
|
|
15
|
+
include Lib::HasCollectionBuilder
|
|
16
|
+
include Lib::HasResourceUrl
|
|
17
|
+
include Lib::ActiveObject::Find
|
|
18
|
+
include Lib::ActiveObject::Save
|
|
19
|
+
include Lib::ActiveObject::Delete
|
|
20
|
+
include Lib::WillPaginate
|
|
21
|
+
|
|
22
|
+
def initialize(attrs = {})
|
|
23
|
+
update_from_attributes attrs
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.create(attrs = {})
|
|
27
|
+
url = Lib::Api.resource_url(ENDPOINT)
|
|
28
|
+
new Lib::Api.new.post(url, attrs).data
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def subtree(query = {})
|
|
32
|
+
args = query.merge(
|
|
33
|
+
resource_url: resource_url("#{id}/subtree"),
|
|
34
|
+
resource_class: self.class
|
|
35
|
+
)
|
|
36
|
+
Lib::PagedResource.new(args)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
class EncodingPreset < Abstract
|
|
3
|
+
|
|
4
|
+
ENDPOINT = 'encoding_presets'
|
|
5
|
+
|
|
6
|
+
ATTR_READERS = [:id, :name, :description, :output_format,
|
|
7
|
+
:bitrate_kbps, :long_dimension, :video_codec,
|
|
8
|
+
:profile, :frame_rate_upper_threshold, :keyframe_upper_threshold,
|
|
9
|
+
:audio_bitrate_kbps, :audio_channels, :audio_sample_rate,
|
|
10
|
+
:max_bitrate_kbps, :created_at, :updated_at].freeze
|
|
11
|
+
|
|
12
|
+
prepend Lib::HasAttributes
|
|
13
|
+
include Lib::HasCollectionBuilder
|
|
14
|
+
include Lib::HasResourceUrl
|
|
15
|
+
include Lib::ActiveObject::Find
|
|
16
|
+
include Lib::WillPaginate
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
class IngestRecipe < Abstract
|
|
3
|
+
|
|
4
|
+
ENDPOINT = 'ingest_recipes'
|
|
5
|
+
|
|
6
|
+
ATTR_READERS = [:id, :recipe_type, :account_id, :user_id,
|
|
7
|
+
:created_at, :updated_at].freeze
|
|
8
|
+
|
|
9
|
+
ATTR_ACCESSORS = [:name, :description, :default, :multipass,
|
|
10
|
+
:frame_grab_time, :encoding_preset_ids,
|
|
11
|
+
:generate_animated_thumb, :generate_sprite,
|
|
12
|
+
:use_watermark, :send_to_youtube,
|
|
13
|
+
:encoding_presets].freeze
|
|
14
|
+
|
|
15
|
+
prepend Lib::HasAttributes
|
|
16
|
+
include Lib::HasResourceUrl
|
|
17
|
+
include Lib::ActiveObject::Find
|
|
18
|
+
include Lib::ActiveObject::Create
|
|
19
|
+
include Lib::ActiveObject::Save
|
|
20
|
+
include Lib::ActiveObject::Delete
|
|
21
|
+
include Lib::WillPaginate
|
|
22
|
+
|
|
23
|
+
def initialize(attrs = {})
|
|
24
|
+
update_from_attributes(attrs)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def update_from_attributes(attrs = {})
|
|
30
|
+
@encoding_presets = EncodingPreset.build(attrs[:encoding_presets])
|
|
31
|
+
@encoding_preset_ids = @encoding_presets.map(&:id)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
module Lib
|
|
3
|
+
module ActiveObject
|
|
4
|
+
|
|
5
|
+
module Find
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.extend(ClassMethods)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module ClassMethods
|
|
11
|
+
def find(id)
|
|
12
|
+
response = Lib::Api.new.get(resource_url(id))
|
|
13
|
+
new response.data
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module Create
|
|
19
|
+
def self.included(base)
|
|
20
|
+
base.extend(ClassMethods)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module ClassMethods
|
|
24
|
+
def create(attrs)
|
|
25
|
+
response = Lib::Api.new.post(resource_url, attrs)
|
|
26
|
+
new response.data
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
module Save
|
|
32
|
+
def self.included(base)
|
|
33
|
+
base.include(InstanceMethods)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
module InstanceMethods
|
|
37
|
+
def save
|
|
38
|
+
if changed?
|
|
39
|
+
response = Lib::Api.new.patch(resource_url(id), changed_attributes)
|
|
40
|
+
update_from_attributes response.data
|
|
41
|
+
saved!
|
|
42
|
+
end
|
|
43
|
+
true
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def changed?
|
|
47
|
+
!changes.empty?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def changed
|
|
51
|
+
changes.keys
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def changed_attributes
|
|
55
|
+
{}.tap do |result|
|
|
56
|
+
changes.each do |attr, vals|
|
|
57
|
+
result[attr] = vals[1]
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def changes
|
|
63
|
+
@changes ||= {}
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def has_changed?(attr)
|
|
67
|
+
changed.include? attr.to_sym
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def saved!
|
|
71
|
+
@changes = nil
|
|
72
|
+
end
|
|
73
|
+
private :saved!
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
module Delete
|
|
78
|
+
def self.included(base)
|
|
79
|
+
base.include(InstanceMethods)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
module InstanceMethods
|
|
83
|
+
def delete
|
|
84
|
+
Lib::Api.new.delete(resource_url(id))
|
|
85
|
+
true
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
module Lib
|
|
3
|
+
class Api
|
|
4
|
+
|
|
5
|
+
def self.api_root_url
|
|
6
|
+
"#{VzaarApi.protocol}://#{VzaarApi.hostname}/api/v2"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.resource_url(resource, path = nil)
|
|
10
|
+
[api_root_url, resource, path].compact.join('/')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def delete(url)
|
|
14
|
+
handle_response http_client.delete(url, {}, headers)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def get(url, query = {})
|
|
18
|
+
handle_response http_client.get(url, query, headers)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def patch(url, body = {})
|
|
22
|
+
handle_response http_client.patch(url, body.to_json, headers)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def post(url, body = {})
|
|
26
|
+
handle_response http_client.post(url, body.to_json, headers)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def handle_response(response)
|
|
30
|
+
api_response = ApiResponse.new(response)
|
|
31
|
+
VzaarApi.rate_limit = api_response.rate_limit
|
|
32
|
+
VzaarApi.rate_limit_remaining = api_response.rate_limit_remaining
|
|
33
|
+
VzaarApi.rate_limit_reset = api_response.rate_limit_reset
|
|
34
|
+
return api_response if api_response.ok?
|
|
35
|
+
raise Error.new(api_response.error)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def http_client
|
|
39
|
+
HTTPClient.new.tap do |c|
|
|
40
|
+
c.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def headers
|
|
45
|
+
{
|
|
46
|
+
'X-Auth-Token' => VzaarApi.auth_token,
|
|
47
|
+
'X-Client-Id' => VzaarApi.client_id,
|
|
48
|
+
'Content-Type' => 'application/json'
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
module Lib
|
|
3
|
+
class ApiResponse
|
|
4
|
+
|
|
5
|
+
attr_reader :response
|
|
6
|
+
|
|
7
|
+
def initialize(response)
|
|
8
|
+
@response = response
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def data
|
|
12
|
+
json[:data]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def meta
|
|
16
|
+
json[:meta]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def error
|
|
20
|
+
simple_errors.join('; ')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def ok?
|
|
24
|
+
response.ok?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def rate_limit
|
|
28
|
+
rate_limit_value 'X-RateLimit-Limit'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def rate_limit_remaining
|
|
32
|
+
rate_limit_value 'X-RateLimit-Remaining'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def rate_limit_reset
|
|
36
|
+
rate_limit_value 'X-RateLimit-Reset'
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def rate_limit_value(header)
|
|
42
|
+
if limit = response.headers[header]
|
|
43
|
+
limit.to_i
|
|
44
|
+
else
|
|
45
|
+
nil
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def simple_errors
|
|
50
|
+
json[:errors].map { |e| [e[:message], e[:detail]].join(': ') }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def json
|
|
54
|
+
@json ||= JSON.parse(response.body, symbolize_names: true)
|
|
55
|
+
rescue JSON::ParserError
|
|
56
|
+
raise Error.new('Invalid JSON response from API')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|