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,49 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
module Lib
|
|
3
|
+
module HasAttributes
|
|
4
|
+
|
|
5
|
+
def self.prepended(klass)
|
|
6
|
+
klass::ATTR_READERS.each do |attr|
|
|
7
|
+
klass.send :attr_reader, attr
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
unless defined? klass::ATTR_ACCESSORS
|
|
11
|
+
klass.const_set 'ATTR_ACCESSORS', [].freeze
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
klass::ATTR_ACCESSORS.each do |attr|
|
|
15
|
+
klass.send :attr_accessor, attr
|
|
16
|
+
|
|
17
|
+
klass.send(:define_method, "#{attr}=") do |val|
|
|
18
|
+
if self.changes[attr]
|
|
19
|
+
self.changes[attr][1] = val
|
|
20
|
+
else
|
|
21
|
+
self.changes[attr] = [self.send(attr), val]
|
|
22
|
+
end
|
|
23
|
+
val
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def initialize(attrs = {})
|
|
29
|
+
self.class::ATTR_READERS.each do |attr|
|
|
30
|
+
instance_variable_set("@#{attr}", attrs[attr])
|
|
31
|
+
end
|
|
32
|
+
self.class::ATTR_ACCESSORS.each do |attr|
|
|
33
|
+
instance_variable_set("@#{attr}", attrs[attr])
|
|
34
|
+
end
|
|
35
|
+
super
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def update_from_attributes(attrs = {})
|
|
41
|
+
attrs.each do |attr, val|
|
|
42
|
+
instance_variable_set("@#{attr}", attrs[attr])
|
|
43
|
+
end
|
|
44
|
+
super
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
module Lib
|
|
3
|
+
module HasCollectionBuilder
|
|
4
|
+
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.extend(ClassMethods)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module ClassMethods
|
|
10
|
+
def build(data = [])
|
|
11
|
+
Array(data).map { |attrs| new attrs }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
module Lib
|
|
3
|
+
module HasResourceUrl
|
|
4
|
+
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.include(InstanceMethods)
|
|
7
|
+
base.extend(ClassMethods)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module InstanceMethods
|
|
11
|
+
def resource_url(path = nil)
|
|
12
|
+
self.class.resource_url(path)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module ClassMethods
|
|
17
|
+
def resource_url(path = nil)
|
|
18
|
+
Api.resource_url self::ENDPOINT, path
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
module Lib
|
|
3
|
+
class PagedResource
|
|
4
|
+
|
|
5
|
+
attr_reader :query, :meta, :collection, :resource_class, :resource_url
|
|
6
|
+
|
|
7
|
+
def initialize(query = {})
|
|
8
|
+
@query = query.dup
|
|
9
|
+
@resource_class = @query.delete(:resource_class)
|
|
10
|
+
@resource_url = @query.delete(:resource_url)
|
|
11
|
+
@loaded = false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def loaded?
|
|
15
|
+
@loaded
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def each_item
|
|
19
|
+
return enum_for :each_item unless block_given?
|
|
20
|
+
begin
|
|
21
|
+
each { |record| yield record }
|
|
22
|
+
end while !self.next.empty?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def first
|
|
26
|
+
loaded? ? load_page_url(:first) : load!
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def next
|
|
30
|
+
load_page_url :next
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def previous
|
|
34
|
+
load_page_url :previous
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def last
|
|
38
|
+
load_page_url :last
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def load!
|
|
44
|
+
@loaded = true
|
|
45
|
+
load_from_url resource_url, query
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def load_page_url(page)
|
|
49
|
+
load! unless loaded?
|
|
50
|
+
if url = meta_link(page)
|
|
51
|
+
load_from_url meta[:links][page]
|
|
52
|
+
else
|
|
53
|
+
[]
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def meta_link(page)
|
|
58
|
+
return unless meta
|
|
59
|
+
meta[:links][page]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def each
|
|
63
|
+
return enum_for :each unless block_given?
|
|
64
|
+
load! unless collection
|
|
65
|
+
collection.each { |record| yield record }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def load_from_url(url, query = {})
|
|
69
|
+
response = Api.new.get(url, query)
|
|
70
|
+
@meta = response.meta
|
|
71
|
+
@collection = build_collection response.data
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def build_collection(items)
|
|
75
|
+
items.map { |attrs| resource_class.new attrs }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
module Lib
|
|
3
|
+
module WillPaginate
|
|
4
|
+
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.extend(ClassMethods)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module ClassMethods
|
|
10
|
+
def each_item(query = {}, &block)
|
|
11
|
+
paginate(query).each_item(&block)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def paginate(query = {})
|
|
15
|
+
args = query.merge({ resource_url: resource_url, resource_class: self })
|
|
16
|
+
Lib::PagedResource.new(args)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
class Playlist < Abstract
|
|
3
|
+
|
|
4
|
+
ENDPOINT = 'feeds/playlists'
|
|
5
|
+
|
|
6
|
+
ATTR_READERS = %i(
|
|
7
|
+
id title sort_order sort_by autoplay continuous_play category_id
|
|
8
|
+
embed_code created_at updated_at
|
|
9
|
+
).freeze
|
|
10
|
+
|
|
11
|
+
ATTR_ACCESSORS = %i(
|
|
12
|
+
category_id title sort_by sort_order private dimensions max_vids
|
|
13
|
+
position autoplay continuous_play max_vids
|
|
14
|
+
).freeze
|
|
15
|
+
|
|
16
|
+
prepend Lib::HasAttributes
|
|
17
|
+
include Lib::HasCollectionBuilder
|
|
18
|
+
include Lib::HasResourceUrl
|
|
19
|
+
include Lib::ActiveObject::Find
|
|
20
|
+
include Lib::ActiveObject::Save
|
|
21
|
+
include Lib::ActiveObject::Delete
|
|
22
|
+
include Lib::WillPaginate
|
|
23
|
+
|
|
24
|
+
def self.create(attrs = {})
|
|
25
|
+
url = Lib::Api.resource_url(ENDPOINT)
|
|
26
|
+
new Lib::Api.new.post(url, attrs).data
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
class Rendition < Abstract
|
|
3
|
+
|
|
4
|
+
ATTR_READERS = [:audio_bitrate_kbps, :audio_channels,
|
|
5
|
+
:audio_sample_rate, :bitrate_kbps,
|
|
6
|
+
:encoding_preset_id, :error_message,
|
|
7
|
+
:frame_rate, :height, :id, :keyframe,
|
|
8
|
+
:name, :output_format, :profile, :size_in_bytes,
|
|
9
|
+
:source_as_rendition, :state, :video_codec, :width,
|
|
10
|
+
:created_at, :updated_at].freeze
|
|
11
|
+
|
|
12
|
+
prepend Lib::HasAttributes
|
|
13
|
+
include Lib::HasCollectionBuilder
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
module Signature
|
|
3
|
+
class Abstract
|
|
4
|
+
|
|
5
|
+
include Lib::HasResourceUrl
|
|
6
|
+
|
|
7
|
+
attr_reader :access_key_id, :acl, :bucket, :content_type,
|
|
8
|
+
:guid, :key, :policy, :signature, :success_action_status,
|
|
9
|
+
:upload_hostname
|
|
10
|
+
|
|
11
|
+
def initialize(attrs = {})
|
|
12
|
+
@access_key_id = attrs[:access_key_id]
|
|
13
|
+
@acl = attrs[:acl]
|
|
14
|
+
@bucket = attrs[:bucket]
|
|
15
|
+
@content_type = attrs[:content_type]
|
|
16
|
+
@guid = attrs[:guid]
|
|
17
|
+
@key = attrs[:key]
|
|
18
|
+
@policy = attrs[:policy]
|
|
19
|
+
@signature = attrs[:signature]
|
|
20
|
+
@success_action_status = attrs[:success_action_status]
|
|
21
|
+
@upload_hostname = attrs[:upload_hostname]
|
|
22
|
+
after_initialize(attrs)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def after_initialize(attrs = {})
|
|
26
|
+
raise Error.new('Cannot call #after_initialize on Signature::Abstract')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def multipart?
|
|
30
|
+
raise Error.new('Cannot call #multipart? on Signature::Abstract')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.create(attrs = {})
|
|
34
|
+
attrs[:uploader] = UPLOADER
|
|
35
|
+
new Lib::Api.new.post(resource_url, attrs).data
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
module Signature
|
|
3
|
+
class Factory
|
|
4
|
+
|
|
5
|
+
# 5MB is min size required for multipart upload
|
|
6
|
+
MIN_S3_MULTIPART_FILE_SIZE = 5 * (1024 ** 2)
|
|
7
|
+
|
|
8
|
+
attr_reader :attrs, :path
|
|
9
|
+
|
|
10
|
+
def initialize(attrs)
|
|
11
|
+
@attrs = attrs
|
|
12
|
+
@path = attrs.fetch(:path)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.create(attrs)
|
|
16
|
+
new(attrs).create
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def create
|
|
20
|
+
klass = multipart? ? Multipart : Single
|
|
21
|
+
klass.create(multipart_attrs)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def multipart?
|
|
25
|
+
multipart_attrs[:filesize].to_i >= MIN_S3_MULTIPART_FILE_SIZE
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def multipart_attrs
|
|
29
|
+
{
|
|
30
|
+
filesize: File::Stat.new(path).size,
|
|
31
|
+
filename: File.basename(path)
|
|
32
|
+
}
|
|
33
|
+
rescue Errno::ENOENT
|
|
34
|
+
raise Error.new 'Invalid parameters: path is invalid'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
module Signature
|
|
3
|
+
class Multipart < Abstract
|
|
4
|
+
|
|
5
|
+
include Lib::HasResourceUrl
|
|
6
|
+
|
|
7
|
+
ENDPOINT = 'signature/multipart'
|
|
8
|
+
|
|
9
|
+
attr_reader :upload_hostname, :part_size, :part_size_in_bytes, :parts
|
|
10
|
+
|
|
11
|
+
def after_initialize(attrs = {})
|
|
12
|
+
@part_size = attrs[:part_size]
|
|
13
|
+
@part_size_in_bytes = attrs[:part_size_in_bytes]
|
|
14
|
+
@parts = attrs[:parts]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def multipart?
|
|
18
|
+
true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
module Strategy
|
|
3
|
+
module Video
|
|
4
|
+
class Create
|
|
5
|
+
|
|
6
|
+
attr_reader :attrs, :video_class
|
|
7
|
+
|
|
8
|
+
def initialize(attrs, video_class)
|
|
9
|
+
@attrs = attrs
|
|
10
|
+
@video_class = video_class
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def execute
|
|
14
|
+
case
|
|
15
|
+
when attrs.has_key?(:guid)
|
|
16
|
+
create_from_guid
|
|
17
|
+
when attrs.has_key?(:path)
|
|
18
|
+
create_from_path
|
|
19
|
+
when attrs.has_key?(:url)
|
|
20
|
+
create_from_url
|
|
21
|
+
else
|
|
22
|
+
raise Error.new('Invalid parameters: Expected one of :guid, :path, :url')
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def create_from_guid
|
|
29
|
+
url = Lib::Api.resource_url video_class::ENDPOINT
|
|
30
|
+
video_class.new Lib::Api.new.post(url, attrs).data
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def create_from_path
|
|
34
|
+
signature = Signature::Factory.create(attrs)
|
|
35
|
+
upload_attrs = Upload::S3.new(attrs, signature).execute
|
|
36
|
+
video_class.create upload_attrs
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def create_from_url
|
|
40
|
+
LinkUpload.create(attrs.merge({ uploader: UPLOADER }))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
module Upload
|
|
3
|
+
class S3
|
|
4
|
+
extend Forwardable
|
|
5
|
+
|
|
6
|
+
SEND_TIMEOUT = 1800
|
|
7
|
+
|
|
8
|
+
attr_reader :attrs, :path, :signature
|
|
9
|
+
|
|
10
|
+
def_delegators :@signature, :access_key_id, :acl, :bucket,
|
|
11
|
+
:guid, :key, :multipart?, :part_size_in_bytes, :policy,
|
|
12
|
+
:success_action_status, :upload_hostname
|
|
13
|
+
|
|
14
|
+
def initialize(attrs, signature)
|
|
15
|
+
@attrs = attrs.dup
|
|
16
|
+
@path = @attrs.delete(:path)
|
|
17
|
+
@signature = signature
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def execute
|
|
21
|
+
if multipart?
|
|
22
|
+
multipart_upload
|
|
23
|
+
else
|
|
24
|
+
single_part_upload
|
|
25
|
+
end
|
|
26
|
+
attrs.merge({ guid: guid })
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def multipart_upload
|
|
32
|
+
_headers = headers.dup
|
|
33
|
+
chunk = 0
|
|
34
|
+
File.open(path, "r") do |file|
|
|
35
|
+
until file.eof?
|
|
36
|
+
_headers['key'] = "#{key}.#{chunk}"
|
|
37
|
+
_headers['file'] = VirtualFile.new(file, part_size_in_bytes)
|
|
38
|
+
validate_response! upload_file(_headers)
|
|
39
|
+
chunk += 1
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
rescue => e
|
|
43
|
+
raise Error.new(e.message)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def single_part_upload
|
|
47
|
+
File.open(path, "r") do |file|
|
|
48
|
+
_headers = headers.dup
|
|
49
|
+
_headers['key'] = key
|
|
50
|
+
_headers['file'] = file
|
|
51
|
+
validate_response! upload_file(_headers)
|
|
52
|
+
end
|
|
53
|
+
rescue => e
|
|
54
|
+
raise Error.new(e.message)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def upload_file(headers)
|
|
58
|
+
http_client.post upload_hostname, headers
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def headers
|
|
62
|
+
@headers ||= {
|
|
63
|
+
'acl' => acl,
|
|
64
|
+
'bucket' => bucket,
|
|
65
|
+
'success_action_status' => success_action_status,
|
|
66
|
+
'policy' => policy,
|
|
67
|
+
'AWSAccessKeyId' => access_key_id,
|
|
68
|
+
'signature' => signature.signature,
|
|
69
|
+
'x-amz-meta-uploader' => UPLOADER
|
|
70
|
+
}
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def http_client
|
|
74
|
+
@http_client ||= begin
|
|
75
|
+
HTTPClient.new.tap { |c| c.send_timeout = SEND_TIMEOUT }
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def validate_response!(response)
|
|
80
|
+
return if response.ok?
|
|
81
|
+
raise error_message(response.body)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def error_message(body)
|
|
85
|
+
/Message\>(.+)\<\/Message/.match(body)[1]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module VzaarApi
|
|
2
|
+
class Video < Abstract
|
|
3
|
+
|
|
4
|
+
ENDPOINT = 'videos'
|
|
5
|
+
|
|
6
|
+
ATTR_READERS = [:id, :user_id, :account_id, :categories,
|
|
7
|
+
:renditions, :legacy_renditions, :url,
|
|
8
|
+
:thumbnail_url, :state,
|
|
9
|
+
:created_at, :updated_at].freeze
|
|
10
|
+
|
|
11
|
+
ATTR_ACCESSORS = [:category_ids, :description, :private, :seo_url, :title].freeze
|
|
12
|
+
|
|
13
|
+
prepend Lib::HasAttributes
|
|
14
|
+
include Lib::HasResourceUrl
|
|
15
|
+
include Lib::ActiveObject::Find
|
|
16
|
+
include Lib::ActiveObject::Save
|
|
17
|
+
include Lib::ActiveObject::Delete
|
|
18
|
+
include Lib::WillPaginate
|
|
19
|
+
|
|
20
|
+
def initialize(attrs = {})
|
|
21
|
+
update_from_attributes attrs
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.create(attrs = {})
|
|
25
|
+
Strategy::Video::Create.new(attrs, self).execute
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def update_from_attributes(attrs)
|
|
31
|
+
@categories = Category.build(attrs[:categories])
|
|
32
|
+
@category_ids = @categories.map(&:id)
|
|
33
|
+
@renditions = Rendition.build(attrs[:renditions])
|
|
34
|
+
@legacy_renditions = LegacyRendition.build(attrs[:renditions])
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/vzaar_api.rb
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
$: << File.dirname(__FILE__)
|
|
2
|
+
|
|
3
|
+
require 'forwardable'
|
|
4
|
+
require 'httpclient'
|
|
5
|
+
require 'json'
|
|
6
|
+
|
|
7
|
+
require 'vzaar_api/version'
|
|
8
|
+
|
|
9
|
+
require 'vzaar_api/lib/api'
|
|
10
|
+
require 'vzaar_api/lib/api_response'
|
|
11
|
+
require 'vzaar_api/lib/active_object'
|
|
12
|
+
require 'vzaar_api/lib/has_attributes'
|
|
13
|
+
require 'vzaar_api/lib/has_collection_builder'
|
|
14
|
+
require 'vzaar_api/lib/has_resource_url'
|
|
15
|
+
require 'vzaar_api/lib/paged_resource'
|
|
16
|
+
require 'vzaar_api/lib/will_paginate'
|
|
17
|
+
|
|
18
|
+
require 'vzaar_api/abstract'
|
|
19
|
+
require 'vzaar_api/category'
|
|
20
|
+
require 'vzaar_api/encoding_preset'
|
|
21
|
+
require 'vzaar_api/ingest_recipe'
|
|
22
|
+
require 'vzaar_api/legacy_rendition'
|
|
23
|
+
require 'vzaar_api/link_upload'
|
|
24
|
+
require 'vzaar_api/playlist'
|
|
25
|
+
require 'vzaar_api/rendition'
|
|
26
|
+
require 'vzaar_api/strategy/video/create'
|
|
27
|
+
require 'vzaar_api/video'
|
|
28
|
+
|
|
29
|
+
require 'vzaar_api/signature/abstract'
|
|
30
|
+
require 'vzaar_api/signature/factory'
|
|
31
|
+
require 'vzaar_api/signature/multipart'
|
|
32
|
+
require 'vzaar_api/signature/single'
|
|
33
|
+
|
|
34
|
+
require 'vzaar_api/upload/s3'
|
|
35
|
+
require 'vzaar_api/upload/virtual_file'
|
|
36
|
+
|
|
37
|
+
module VzaarApi
|
|
38
|
+
class Error < StandardError ; end
|
|
39
|
+
|
|
40
|
+
DEFAULT_HOSTNAME = 'api.vzaar.com'
|
|
41
|
+
DEFAULT_PROTOCOL = 'https'
|
|
42
|
+
|
|
43
|
+
class << self
|
|
44
|
+
attr_accessor :auth_token, :client_id, :hostname,
|
|
45
|
+
:rate_limit, :rate_limit_remaining, :rate_limit_reset
|
|
46
|
+
|
|
47
|
+
def hostname
|
|
48
|
+
@hostname || DEFAULT_HOSTNAME
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def protocol
|
|
52
|
+
@protocol || DEFAULT_PROTOCOL
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def protocol=(value)
|
|
56
|
+
@protocol = value.downcase == 'https' ? 'https' : 'http'
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|