animoto 0.0.0.alpha9 → 0.1.0.beta0
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.
- data/README.md +26 -13
- data/integration/test.rb +2 -3
- data/lib/animoto/assets/base.rb +29 -0
- data/lib/animoto/assets/footage.rb +34 -0
- data/lib/animoto/assets/image.rb +25 -0
- data/lib/animoto/assets/song.rb +27 -0
- data/lib/animoto/assets/title_card.rb +35 -0
- data/lib/animoto/callbacks/base.rb +45 -0
- data/lib/animoto/callbacks/directing.rb +7 -0
- data/lib/animoto/callbacks/directing_and_rendering.rb +7 -0
- data/lib/animoto/callbacks/rendering.rb +7 -0
- data/lib/animoto/client.rb +133 -80
- data/lib/animoto/http_engines/base.rb +40 -0
- data/lib/animoto/http_engines/curl_adapter.rb +17 -5
- data/lib/animoto/http_engines/net_http_adapter.rb +6 -4
- data/lib/animoto/http_engines/patron_adapter.rb +7 -2
- data/lib/animoto/http_engines/rest_client_adapter.rb +3 -3
- data/lib/animoto/http_engines/typhoeus_adapter.rb +4 -4
- data/lib/animoto/manifests/base.rb +18 -0
- data/lib/animoto/manifests/directing.rb +146 -0
- data/lib/animoto/manifests/directing_and_rendering.rb +51 -0
- data/lib/animoto/manifests/rendering.rb +71 -0
- data/lib/animoto/resources/base.rb +133 -0
- data/lib/animoto/resources/jobs/base.rb +61 -0
- data/lib/animoto/resources/jobs/directing.rb +27 -0
- data/lib/animoto/resources/jobs/directing_and_rendering.rb +28 -0
- data/lib/animoto/resources/jobs/rendering.rb +35 -0
- data/lib/animoto/resources/storyboard.rb +36 -0
- data/lib/animoto/resources/video.rb +50 -0
- data/lib/animoto/response_parsers/base.rb +44 -0
- data/lib/animoto/response_parsers/json_adapter.rb +8 -7
- data/lib/animoto/response_parsers/yajl_adapter.rb +9 -8
- data/lib/animoto/support/content_type.rb +49 -0
- data/lib/animoto/support/coverable.rb +31 -0
- data/lib/animoto/support/dynamic_class_loader.rb +166 -0
- data/lib/animoto/support/errors.rb +5 -0
- data/lib/animoto/support/standard_envelope.rb +66 -0
- data/lib/animoto/support/visual.rb +32 -0
- data/lib/animoto.rb +7 -1
- data/spec/animoto/assets/base_spec.rb +5 -0
- data/spec/animoto/{footage_spec.rb → assets/footage_spec.rb} +4 -4
- data/spec/animoto/{image_spec.rb → assets/image_spec.rb} +4 -4
- data/spec/animoto/{song_spec.rb → assets/song_spec.rb} +3 -3
- data/spec/animoto/{title_card_spec.rb → assets/title_card_spec.rb} +4 -4
- data/spec/animoto/callbacks/base_spec.rb +76 -0
- data/spec/animoto/callbacks/directing_and_rendering_spec.rb +5 -0
- data/spec/animoto/callbacks/directing_spec.rb +5 -0
- data/spec/animoto/callbacks/rendering_spec.rb +5 -0
- data/spec/animoto/client_spec.rb +29 -5
- data/spec/animoto/{http_engine_spec.rb → http_engines/base_spec.rb} +5 -5
- data/spec/animoto/{directing_and_rendering_manifest_spec.rb → manifests/directing_and_rendering_spec.rb} +3 -3
- data/spec/animoto/{directing_manifest_spec.rb → manifests/directing_spec.rb} +8 -8
- data/spec/animoto/{rendering_manifest_spec.rb → manifests/rendering_spec.rb} +7 -7
- data/spec/animoto/{resource_spec.rb → resources/base_spec.rb} +7 -7
- data/spec/animoto/{job_spec.rb → resources/jobs/base_spec.rb} +9 -5
- data/spec/animoto/{directing_and_rendering_job_spec.rb → resources/jobs/directing_and_rendering_spec.rb} +7 -7
- data/spec/animoto/{directing_job_spec.rb → resources/jobs/directing_spec.rb} +7 -7
- data/spec/animoto/{rendering_job_spec.rb → resources/jobs/rendering_spec.rb} +8 -8
- data/spec/animoto/resources/storyboard_spec.rb +8 -0
- data/spec/animoto/resources/video_spec.rb +5 -0
- data/spec/animoto/response_parsers/json_adapter_spec.rb +2 -2
- data/spec/animoto/response_parsers/yajl_adapter_spec.rb +2 -2
- data/spec/animoto/support/coverable_spec.rb +5 -0
- data/spec/animoto/support/standard_envelope_spec.rb +5 -0
- data/spec/animoto/support/visual_spec.rb +5 -0
- metadata +56 -48
- data/lib/animoto/asset.rb +0 -19
- data/lib/animoto/content_type.rb +0 -47
- data/lib/animoto/coverable.rb +0 -29
- data/lib/animoto/directing_and_rendering_job.rb +0 -19
- data/lib/animoto/directing_and_rendering_manifest.rb +0 -25
- data/lib/animoto/directing_job.rb +0 -18
- data/lib/animoto/directing_manifest.rb +0 -112
- data/lib/animoto/dynamic_class_loader.rb +0 -64
- data/lib/animoto/errors.rb +0 -3
- data/lib/animoto/footage.rb +0 -16
- data/lib/animoto/http_engine.rb +0 -34
- data/lib/animoto/image.rb +0 -16
- data/lib/animoto/job.rb +0 -37
- data/lib/animoto/manifest.rb +0 -14
- data/lib/animoto/rendering_job.rb +0 -24
- data/lib/animoto/rendering_manifest.rb +0 -37
- data/lib/animoto/resource.rb +0 -149
- data/lib/animoto/response_parser.rb +0 -38
- data/lib/animoto/song.rb +0 -14
- data/lib/animoto/standard_envelope.rb +0 -27
- data/lib/animoto/storyboard.rb +0 -22
- data/lib/animoto/title_card.rb +0 -26
- data/lib/animoto/video.rb +0 -29
- data/lib/animoto/visual.rb +0 -30
- data/spec/animoto/asset_spec.rb +0 -5
- data/spec/animoto/coverable_spec.rb +0 -5
- data/spec/animoto/standard_envelope_spec.rb +0 -5
- data/spec/animoto/storyboard_spec.rb +0 -8
- data/spec/animoto/video_spec.rb +0 -5
- data/spec/animoto/visual_spec.rb +0 -5
data/README.md
CHANGED
|
@@ -31,6 +31,19 @@ This document does not cover the details of the Animoto API itself. For such inf
|
|
|
31
31
|
<a name="getting_started_using_the_ruby_client"></a>
|
|
32
32
|
## Getting Started using the Ruby Client
|
|
33
33
|
|
|
34
|
+
### Installation
|
|
35
|
+
|
|
36
|
+
You can install the Animoto API Ruby Client either through [RubyGems](http://rubygems.org):
|
|
37
|
+
|
|
38
|
+
gem install animoto -v 0.1.0.alpha0 --pre
|
|
39
|
+
|
|
40
|
+
Or by cloning [the repository](http://github.com/animoto/animoto_api_client_ruby) on [GitHub](http://github.com/) and building it from source:
|
|
41
|
+
|
|
42
|
+
git clone git://github.com/animoto/animoto_api_client_ruby.git
|
|
43
|
+
cd animoto_api_client_ruby
|
|
44
|
+
gem build animoto.gemspec
|
|
45
|
+
gem install animoto-0.1.0.alpha0.gem
|
|
46
|
+
|
|
34
47
|
### Prerequisites
|
|
35
48
|
|
|
36
49
|
#### Readers of this document should be familiar with...
|
|
@@ -87,7 +100,7 @@ client and using HTTP callbacks for status updates.
|
|
|
87
100
|
# create a directing and rendering manifest with the video title and
|
|
88
101
|
# producer. Also include rendering parameters like resolution, framerate,
|
|
89
102
|
# and format.
|
|
90
|
-
manifest =
|
|
103
|
+
manifest = Manifests::DirectingAndRendering.new(
|
|
91
104
|
:title => "Amazing Title!",
|
|
92
105
|
:producer => "Fishy Joe",
|
|
93
106
|
:resolution => "720p",
|
|
@@ -96,13 +109,13 @@ client and using HTTP callbacks for status updates.
|
|
|
96
109
|
)
|
|
97
110
|
|
|
98
111
|
# Add some images, text, and footage to our manifest.
|
|
99
|
-
manifest << Image.new("http://website.com/picture.png")
|
|
100
|
-
manifest << Image.new("http://website.com/hooray.png", :spotlit => true)
|
|
101
|
-
manifest << TitleCard.new("Woohoo!", "Hooray for everything!")
|
|
102
|
-
manifest << Footage.new("http://website.com/movie.mp4", :duration => 3.5)
|
|
112
|
+
manifest << Assets::Image.new("http://website.com/picture.png")
|
|
113
|
+
manifest << Assets::Image.new("http://website.com/hooray.png", :spotlit => true)
|
|
114
|
+
manifest << Assets::TitleCard.new("Woohoo!", "Hooray for everything!")
|
|
115
|
+
manifest << Assets::Footage.new("http://website.com/movie.mp4", :duration => 3.5)
|
|
103
116
|
|
|
104
117
|
# Setup the soundtrack.
|
|
105
|
-
manifest << Song.new("http://website.com/song.mp3", :artist => "Fishy Joe")
|
|
118
|
+
manifest << Assets::Song.new("http://website.com/song.mp3", :artist => "Fishy Joe")
|
|
106
119
|
|
|
107
120
|
# Setup to get http callbacks for status notification (see below for
|
|
108
121
|
# polling example).
|
|
@@ -128,16 +141,16 @@ status.
|
|
|
128
141
|
|
|
129
142
|
# Create a directing manifest. The directing manifest controls the images
|
|
130
143
|
# and other visual elements that will be in our final video.
|
|
131
|
-
manifest =
|
|
144
|
+
manifest = Manifests::Directing.new(:title => "Amazing Title!")
|
|
132
145
|
|
|
133
146
|
# Add some images, text, and footage to our manifest.
|
|
134
|
-
manifest << Image.new("http://website.com/picture.png")
|
|
135
|
-
manifest << Image.new("http://website.com/hooray.png", :spotlit => true)
|
|
136
|
-
manifest << TitleCard.new("Woohoo!", "Hooray for everything!")
|
|
137
|
-
manifest << Footage.new("http://website.com/movie.mp4", :duration => 3.5)
|
|
147
|
+
manifest << Assets::Image.new("http://website.com/picture.png")
|
|
148
|
+
manifest << Assets::Image.new("http://website.com/hooray.png", :spotlit => true)
|
|
149
|
+
manifest << Assets::TitleCard.new("Woohoo!", "Hooray for everything!")
|
|
150
|
+
manifest << Assets::Footage.new("http://website.com/movie.mp4", :duration => 3.5)
|
|
138
151
|
|
|
139
152
|
# Setup the soundtrack.
|
|
140
|
-
manifest << Song.new("http://website.com/song.mp3")
|
|
153
|
+
manifest << Assets::Song.new("http://website.com/song.mp3")
|
|
141
154
|
|
|
142
155
|
# Request a new directing job by sending the API our directing manifest.
|
|
143
156
|
directing_job = client.direct!(manifest)
|
|
@@ -154,7 +167,7 @@ status.
|
|
|
154
167
|
|
|
155
168
|
# Now it's time to render the storyboard into a video. First we create
|
|
156
169
|
# a rendering manifest.
|
|
157
|
-
manifest =
|
|
170
|
+
manifest = Manifests::Rendering.new(storyboard, :resolution => "720p", :framerate => 24, :format => 'h264')
|
|
158
171
|
|
|
159
172
|
# Send the manifest to the API.
|
|
160
173
|
rendering_job = client.render!(manifest)
|
data/integration/test.rb
CHANGED
|
@@ -33,7 +33,7 @@ raise "Example code not found in README (expected at xpath '#{example_code_path}
|
|
|
33
33
|
code = code_node.text
|
|
34
34
|
|
|
35
35
|
puts "Replacing example credentials with valid ones"
|
|
36
|
-
code.sub!(/Client\.new\(.+\)/, %Q{Client.new("#{credentials[:key]}","#{credentials[:secret]}")})
|
|
36
|
+
code.sub!(/Client\.new\(.+\)/, %Q{Client.new("#{credentials[:key]}","#{credentials[:secret]}",:endpoint => "#{credentials[:endpoint]}")})
|
|
37
37
|
|
|
38
38
|
puts "Replacing example assets with valid ones"
|
|
39
39
|
code.gsub!(/Image\.new\(.+\)/) { %Q{Image.new("#{assets[:images].shift}")} }
|
|
@@ -46,5 +46,4 @@ puts "Executing example"
|
|
|
46
46
|
eval code
|
|
47
47
|
|
|
48
48
|
puts
|
|
49
|
-
puts "If you're seeing this, things should have worked fine!"
|
|
50
|
-
puts "Enjoy your video at #{video.download_url}"
|
|
49
|
+
puts "If you're seeing this, things should have worked fine!"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Animoto
|
|
2
|
+
module Assets
|
|
3
|
+
|
|
4
|
+
# @abstract
|
|
5
|
+
class Base
|
|
6
|
+
|
|
7
|
+
# The URL of this asset.
|
|
8
|
+
# @return [String]
|
|
9
|
+
attr_accessor :source
|
|
10
|
+
|
|
11
|
+
# Creates a new asset.
|
|
12
|
+
#
|
|
13
|
+
# @param [String] source the URL of this asset
|
|
14
|
+
# @return [Assets::Base] the asset
|
|
15
|
+
def initialize source, options = {}
|
|
16
|
+
@source = source
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Returns a representation of this asset as a Hash. Used mainly for generating
|
|
20
|
+
# manifests.
|
|
21
|
+
#
|
|
22
|
+
# @return [Hash<String,Object>] this asset as a Hash
|
|
23
|
+
def to_hash
|
|
24
|
+
{ 'source_url' => @source }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Animoto
|
|
2
|
+
module Assets
|
|
3
|
+
class Footage < Animoto::Assets::Base
|
|
4
|
+
include Support::Visual
|
|
5
|
+
include Support::Coverable
|
|
6
|
+
|
|
7
|
+
# Whether or not to mix the audio of this footage with the video's soundtrack.
|
|
8
|
+
# @return [Boolean]
|
|
9
|
+
attr_accessor :audio_mix
|
|
10
|
+
|
|
11
|
+
# The time in seconds of where to start extracting a clip from this footage to
|
|
12
|
+
# add to the video.
|
|
13
|
+
# @return [Float]
|
|
14
|
+
attr_accessor :start_time
|
|
15
|
+
|
|
16
|
+
# The duration in seconds of how long this footage should run in the video.
|
|
17
|
+
# @return [Float]
|
|
18
|
+
attr_accessor :duration
|
|
19
|
+
|
|
20
|
+
# Returns a representation of this Footage as a Hash.
|
|
21
|
+
#
|
|
22
|
+
# @return [Hash<String,Object>] this asset as a Hash
|
|
23
|
+
# @see Animoto::Support::Visual#to_hash
|
|
24
|
+
# @see Animoto::Assets::Base#to_hash
|
|
25
|
+
def to_hash
|
|
26
|
+
hash = super
|
|
27
|
+
hash['audio_mix'] = 'MIX' if audio_mix
|
|
28
|
+
hash['start_time'] = start_time if start_time
|
|
29
|
+
hash['duration'] = duration if duration
|
|
30
|
+
hash
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Animoto
|
|
2
|
+
module Assets
|
|
3
|
+
class Image < Animoto::Assets::Base
|
|
4
|
+
include Support::Visual
|
|
5
|
+
include Support::Coverable
|
|
6
|
+
|
|
7
|
+
# The EXIF rotation value for how this image should be rotated in the video.
|
|
8
|
+
# @return [Integer]
|
|
9
|
+
attr_accessor :rotation
|
|
10
|
+
|
|
11
|
+
# Returns a representation of this Image as a Hash.
|
|
12
|
+
#
|
|
13
|
+
# @return [Hash<String,Object>] this asset as a Hash
|
|
14
|
+
# @see Animoto::Support::Visual#to_hash
|
|
15
|
+
# @see Animoto::Assets::Base#to_hash
|
|
16
|
+
def to_hash
|
|
17
|
+
hash = super
|
|
18
|
+
hash['rotation'] = rotation if rotation
|
|
19
|
+
hash['spotlit'] = spotlit? unless @spotlit.nil?
|
|
20
|
+
hash['cover'] = cover? unless @cover.nil?
|
|
21
|
+
hash
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Animoto
|
|
2
|
+
module Assets
|
|
3
|
+
class Song < Animoto::Assets::Base
|
|
4
|
+
|
|
5
|
+
# The offset in seconds from the beginning denoting where to start
|
|
6
|
+
# using this song in the video.
|
|
7
|
+
# @return [Float]
|
|
8
|
+
attr_accessor :start_time
|
|
9
|
+
|
|
10
|
+
# The duration in seconds of how long this song should play.
|
|
11
|
+
# @return [Float]
|
|
12
|
+
attr_accessor :duration
|
|
13
|
+
|
|
14
|
+
# Returns a representation of this Song as a Hash.
|
|
15
|
+
#
|
|
16
|
+
# @return [Hash<String,Object>] this asset as a Hash
|
|
17
|
+
# @see Animoto::Assets::Base#to_hash
|
|
18
|
+
def to_hash
|
|
19
|
+
hash = super
|
|
20
|
+
hash['start_time'] = start_time if start_time
|
|
21
|
+
hash['duration'] = duration if duration
|
|
22
|
+
hash
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Animoto
|
|
2
|
+
module Assets
|
|
3
|
+
class TitleCard
|
|
4
|
+
include Support::Visual
|
|
5
|
+
|
|
6
|
+
# The main text of this title card.
|
|
7
|
+
# @return [String]
|
|
8
|
+
attr_accessor :title
|
|
9
|
+
|
|
10
|
+
# The secondary text of this title card.
|
|
11
|
+
# @return [String]
|
|
12
|
+
attr_accessor :subtitle
|
|
13
|
+
|
|
14
|
+
# Creates a new TitleCard.
|
|
15
|
+
#
|
|
16
|
+
# @param [String] title the main text
|
|
17
|
+
# @param [String] subtitle the secondary text
|
|
18
|
+
def initialize title, subtitle = nil
|
|
19
|
+
@title, @subtitle = title, subtitle
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns a representation of this TitleCard as a Hash.
|
|
23
|
+
#
|
|
24
|
+
# @return [Hash<String,Object>] this TitleCard as a Hash
|
|
25
|
+
# @see Animoto::Support::Visual#to_hash
|
|
26
|
+
def to_hash
|
|
27
|
+
hash = super
|
|
28
|
+
hash['h1'] = title
|
|
29
|
+
hash['h2'] = subtitle if subtitle
|
|
30
|
+
hash['spotlit'] = spotlit? unless @spotlit.nil?
|
|
31
|
+
hash
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Animoto
|
|
2
|
+
module Callbacks
|
|
3
|
+
|
|
4
|
+
# @abstract
|
|
5
|
+
class Base
|
|
6
|
+
include Support::StandardEnvelope
|
|
7
|
+
|
|
8
|
+
# @return [String]
|
|
9
|
+
# @see Animoto::Support::StandardEnvelope::ClassMethods#payload_key
|
|
10
|
+
def self.payload_key
|
|
11
|
+
super + '_callback'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @return [Hash<Symbol,Object>]
|
|
15
|
+
# @see Animoto::Support::StandardEnvelope::ClassMethods#unpack_standard_envelope
|
|
16
|
+
def self.unpack_standard_envelope body = {}
|
|
17
|
+
super.merge({ :state => body['response']['payload'][payload_key]['state'] })
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# The state of the job when it completed.
|
|
21
|
+
# @return [String]
|
|
22
|
+
attr_reader :state
|
|
23
|
+
|
|
24
|
+
# Errors for the job.
|
|
25
|
+
# @return [Array<Animoto::Error>]
|
|
26
|
+
attr_reader :errors
|
|
27
|
+
|
|
28
|
+
# The url for this job.
|
|
29
|
+
# @return [String]
|
|
30
|
+
attr_reader :url
|
|
31
|
+
|
|
32
|
+
# Creates a new Callback.
|
|
33
|
+
#
|
|
34
|
+
# @param [String] body the request body of the HTTP callback
|
|
35
|
+
# @return [Callbacks::Base] the Callback
|
|
36
|
+
def initialize body
|
|
37
|
+
params = unpack_standard_envelope(body)
|
|
38
|
+
@state = params[:state]
|
|
39
|
+
@errors = params[:errors].collect { |e| Animoto::Error.new(e['message']) }
|
|
40
|
+
@url = params[:url]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/animoto/client.rb
CHANGED
|
@@ -2,30 +2,39 @@ require 'yaml'
|
|
|
2
2
|
require 'uri'
|
|
3
3
|
require 'logger'
|
|
4
4
|
|
|
5
|
-
require 'animoto/
|
|
6
|
-
require 'animoto/
|
|
7
|
-
require 'animoto/
|
|
8
|
-
require 'animoto/
|
|
9
|
-
require 'animoto/
|
|
10
|
-
require 'animoto/visual'
|
|
11
|
-
|
|
12
|
-
require 'animoto/
|
|
13
|
-
require 'animoto/
|
|
14
|
-
require 'animoto/
|
|
15
|
-
require 'animoto/
|
|
16
|
-
require 'animoto/
|
|
17
|
-
require 'animoto/
|
|
18
|
-
require 'animoto/
|
|
19
|
-
|
|
20
|
-
require 'animoto/
|
|
21
|
-
require 'animoto/
|
|
22
|
-
require 'animoto/
|
|
23
|
-
require 'animoto/
|
|
24
|
-
require 'animoto/
|
|
25
|
-
|
|
26
|
-
require 'animoto/
|
|
27
|
-
require 'animoto/
|
|
28
|
-
require 'animoto/
|
|
5
|
+
require 'animoto/support/content_type'
|
|
6
|
+
require 'animoto/support/coverable'
|
|
7
|
+
require 'animoto/support/dynamic_class_loader'
|
|
8
|
+
require 'animoto/support/errors'
|
|
9
|
+
require 'animoto/support/standard_envelope'
|
|
10
|
+
require 'animoto/support/visual'
|
|
11
|
+
|
|
12
|
+
require 'animoto/resources/base'
|
|
13
|
+
require 'animoto/resources/storyboard'
|
|
14
|
+
require 'animoto/resources/video'
|
|
15
|
+
require 'animoto/resources/jobs/base'
|
|
16
|
+
require 'animoto/resources/jobs/directing_and_rendering'
|
|
17
|
+
require 'animoto/resources/jobs/directing'
|
|
18
|
+
require 'animoto/resources/jobs/rendering'
|
|
19
|
+
|
|
20
|
+
require 'animoto/assets/base'
|
|
21
|
+
require 'animoto/assets/footage'
|
|
22
|
+
require 'animoto/assets/image'
|
|
23
|
+
require 'animoto/assets/song'
|
|
24
|
+
require 'animoto/assets/title_card'
|
|
25
|
+
|
|
26
|
+
require 'animoto/manifests/base'
|
|
27
|
+
require 'animoto/manifests/directing'
|
|
28
|
+
require 'animoto/manifests/directing_and_rendering'
|
|
29
|
+
require 'animoto/manifests/rendering'
|
|
30
|
+
|
|
31
|
+
require 'animoto/callbacks/base'
|
|
32
|
+
require 'animoto/callbacks/directing'
|
|
33
|
+
require 'animoto/callbacks/directing_and_rendering'
|
|
34
|
+
require 'animoto/callbacks/rendering'
|
|
35
|
+
|
|
36
|
+
require 'animoto/http_engines/base'
|
|
37
|
+
require 'animoto/response_parsers/base'
|
|
29
38
|
|
|
30
39
|
module Animoto
|
|
31
40
|
class Client
|
|
@@ -33,8 +42,54 @@ module Animoto
|
|
|
33
42
|
API_VERSION = 1
|
|
34
43
|
BASE_CONTENT_TYPE = "application/vnd.animoto"
|
|
35
44
|
|
|
36
|
-
|
|
37
|
-
|
|
45
|
+
# Your API key.
|
|
46
|
+
# @return [String]
|
|
47
|
+
attr_accessor :key
|
|
48
|
+
|
|
49
|
+
# Your API secret.
|
|
50
|
+
# @return [String]
|
|
51
|
+
attr_accessor :secret
|
|
52
|
+
|
|
53
|
+
# The base URL where all requests will be sent.
|
|
54
|
+
# @return [String]
|
|
55
|
+
attr_accessor :endpoint
|
|
56
|
+
|
|
57
|
+
# A logger.
|
|
58
|
+
# @return [Logger]
|
|
59
|
+
attr_accessor :logger
|
|
60
|
+
|
|
61
|
+
# The engine to handle HTTP requests.
|
|
62
|
+
# @return [HTTPEngines::Base]
|
|
63
|
+
# @overload http_engine
|
|
64
|
+
# Returns the HTTP engine.
|
|
65
|
+
# @return [HTTPEngines::Base]
|
|
66
|
+
# @overload http_engine=(engine)
|
|
67
|
+
# Sets the HTTP engine.
|
|
68
|
+
#
|
|
69
|
+
# @param [HTTPEngines::Base,Symbol,Class] engine you may pass a
|
|
70
|
+
# HTTPEngine instance to use, or the symbolic name of an adapter to use,
|
|
71
|
+
# or a Class whose instances respond to #request and return a String of
|
|
72
|
+
# the response body
|
|
73
|
+
# @see Animoto::HTTPEngines::Base
|
|
74
|
+
# @return [HTTPEngines::Base] the engine instance
|
|
75
|
+
# @raise [ArgumentError] if given a class without the correct interface
|
|
76
|
+
attr_reader :http_engine
|
|
77
|
+
|
|
78
|
+
# The engine to handle parsing XML or JSON responses.
|
|
79
|
+
# @return [ResponseParsers::Base]
|
|
80
|
+
# @overload response_parser
|
|
81
|
+
# Returns the parser.
|
|
82
|
+
# @return [ResponseParsers::Base]
|
|
83
|
+
# @overload response_parser=(parser)
|
|
84
|
+
# Sets the parser.
|
|
85
|
+
#
|
|
86
|
+
# @param [ResponseParsers::Base,Symbol,Class] parser you may pass a
|
|
87
|
+
# ResponseParser instance to use, or the symbolic name of an adapter to use,
|
|
88
|
+
# or a Class whose instances respond to #parse, #unparse, and #format.
|
|
89
|
+
# @see Animoto::ResponseParsers::Base
|
|
90
|
+
# @return [ResponseParsers::Base] the parser instance
|
|
91
|
+
# @raise [ArgumentError] if given a class without the correct interface
|
|
92
|
+
attr_reader :response_parser
|
|
38
93
|
|
|
39
94
|
# Creates a new Client object which handles credentials, versioning, making requests, and
|
|
40
95
|
# parsing responses.
|
|
@@ -60,18 +115,9 @@ module Animoto
|
|
|
60
115
|
__send__ :response_parser=, options[:response_parser] || :json
|
|
61
116
|
end
|
|
62
117
|
|
|
63
|
-
# Set the HTTP engine this client will use.
|
|
64
|
-
#
|
|
65
|
-
# @param [HTTPEngine, Symbol, Class] engine you may pass a
|
|
66
|
-
# HTTPEngine instance to use, or the symbolic name of a adapter to use,
|
|
67
|
-
# or a Class whose instances respond to #request and return a String of
|
|
68
|
-
# the response body
|
|
69
|
-
# @see Animoto::HTTPEngine
|
|
70
|
-
# @return [HTTPEngine] the engine instance
|
|
71
|
-
# @raise [ArgumentError] if given a class without the correct interface
|
|
72
118
|
def http_engine= engine
|
|
73
119
|
@http_engine = case engine
|
|
74
|
-
when Animoto::
|
|
120
|
+
when Animoto::HTTPEngines::Base
|
|
75
121
|
engine
|
|
76
122
|
when Class
|
|
77
123
|
if engine.instance_methods.include?('request')
|
|
@@ -80,21 +126,13 @@ module Animoto
|
|
|
80
126
|
raise ArgumentError
|
|
81
127
|
end
|
|
82
128
|
else
|
|
83
|
-
Animoto::
|
|
129
|
+
Animoto::HTTPEngines[engine].new
|
|
84
130
|
end
|
|
85
131
|
end
|
|
86
132
|
|
|
87
|
-
# Set the response parser this client will use.
|
|
88
|
-
#
|
|
89
|
-
# @param [ResponseParser, Symbol, Class] parser you may pass a
|
|
90
|
-
# ResponseParser instance to use, or the symbolic name of a adapter to use,
|
|
91
|
-
# or a Class whose instances respond to #parse, #unparse, and #format.
|
|
92
|
-
# @see Animoto::ResponseParser
|
|
93
|
-
# @return [ResponseParser] the parser instance
|
|
94
|
-
# @raise [ArgumentError] if given a class without the correct interface
|
|
95
133
|
def response_parser= parser
|
|
96
134
|
@response_parser = case parser
|
|
97
|
-
when Animoto::
|
|
135
|
+
when Animoto::ResponseParsers::Base
|
|
98
136
|
parser
|
|
99
137
|
when Class
|
|
100
138
|
if %{format parse unparse}.all? { |m| parser.instance_methods.include? m }
|
|
@@ -103,53 +141,62 @@ module Animoto
|
|
|
103
141
|
raise ArgumentError
|
|
104
142
|
end
|
|
105
143
|
else
|
|
106
|
-
Animoto::
|
|
144
|
+
Animoto::ResponseParsers[parser].new
|
|
107
145
|
end
|
|
108
146
|
end
|
|
109
147
|
|
|
110
148
|
# Finds a resource by its URL.
|
|
111
149
|
#
|
|
112
|
-
# @param [Class] klass the
|
|
150
|
+
# @param [Class] klass the resource class you're finding
|
|
113
151
|
# @param [String] url the URL of the resource you want
|
|
114
|
-
# @param [Hash] options
|
|
115
|
-
# @return [
|
|
152
|
+
# @param [Hash<Symbol,Object>] options
|
|
153
|
+
# @return [Resources::Base] the resource object found
|
|
116
154
|
def find klass, url, options = {}
|
|
117
155
|
klass.load(find_request(klass, url, options))
|
|
118
156
|
end
|
|
119
157
|
|
|
158
|
+
# Returns a callback object of the specified type given the callback body.
|
|
159
|
+
#
|
|
160
|
+
# @param [Class] klass the callback class
|
|
161
|
+
# @param [String] body the HTTP body of the callback
|
|
162
|
+
# @return [Callbacks::Base] the callback object
|
|
163
|
+
def process_callback klass, body
|
|
164
|
+
klass.new(response_parser.parse(body))
|
|
165
|
+
end
|
|
166
|
+
|
|
120
167
|
# Sends a request to start directing a storyboard.
|
|
121
168
|
#
|
|
122
|
-
# @param [
|
|
123
|
-
# @param [Hash] options
|
|
124
|
-
# @return [
|
|
169
|
+
# @param [Manifests::Directing] manifest the manifest to direct
|
|
170
|
+
# @param [Hash<Symbol,Object>] options
|
|
171
|
+
# @return [Jobs::Directing] a job to monitor the status of the directing
|
|
125
172
|
def direct! manifest, options = {}
|
|
126
|
-
|
|
173
|
+
Resources::Jobs::Directing.load(send_manifest(manifest, Resources::Jobs::Directing.endpoint, options))
|
|
127
174
|
end
|
|
128
175
|
|
|
129
176
|
# Sends a request to start rendering a video.
|
|
130
177
|
#
|
|
131
|
-
# @param [
|
|
132
|
-
# @param [Hash] options
|
|
133
|
-
# @return [
|
|
178
|
+
# @param [Manifests::Rendering] manifest the manifest to render
|
|
179
|
+
# @param [Hash<Symbol,Object>] options
|
|
180
|
+
# @return [Jobs::Rendering] a job to monitor the status of the rendering
|
|
134
181
|
def render! manifest, options = {}
|
|
135
|
-
|
|
182
|
+
Resources::Jobs::Rendering.load(send_manifest(manifest, Resources::Jobs::Rendering.endpoint, options))
|
|
136
183
|
end
|
|
137
184
|
|
|
138
185
|
# Sends a request to start directing and rendering a video.
|
|
139
186
|
#
|
|
140
|
-
# @param [
|
|
141
|
-
# @param [Hash] options
|
|
142
|
-
# @return [
|
|
187
|
+
# @param [Manifests::DirectingAndRendering] manifest the manifest to direct and render
|
|
188
|
+
# @param [Hash<Symbol,Object>] options
|
|
189
|
+
# @return [Jobs::DirectingAndRendering] a job to monitor the status of the directing and rendering
|
|
143
190
|
def direct_and_render! manifest, options = {}
|
|
144
|
-
|
|
191
|
+
Resources::Jobs::DirectingAndRendering.load(send_manifest(manifest, Resources::Jobs::DirectingAndRendering.endpoint, options))
|
|
145
192
|
end
|
|
146
193
|
|
|
147
194
|
# Update a resource with the latest attributes. Useful to update the state of a Job to
|
|
148
195
|
# see if it's ready if you are not using HTTP callbacks.
|
|
149
196
|
#
|
|
150
|
-
# @param [
|
|
151
|
-
# @param [Hash] options
|
|
152
|
-
# @return [
|
|
197
|
+
# @param [Resources::Base] resource the resource to update
|
|
198
|
+
# @param [Hash<Symbol,Object>] options
|
|
199
|
+
# @return [Resources::Base] the given resource with the latest attributes
|
|
153
200
|
def reload! resource, options = {}
|
|
154
201
|
resource.load(find_request(resource.class, resource.url, options))
|
|
155
202
|
end
|
|
@@ -159,6 +206,7 @@ module Animoto
|
|
|
159
206
|
# Sets the API credentials from an .animotorc file. First looks for one in the current
|
|
160
207
|
# directory, then checks ~/.animotorc, then finally /etc/.animotorc.
|
|
161
208
|
#
|
|
209
|
+
# @return [void]
|
|
162
210
|
# @raise [ArgumentError] if none of the files are found
|
|
163
211
|
def configure_from_rc_file
|
|
164
212
|
current_path = Dir.pwd + '/.animotorc'
|
|
@@ -183,18 +231,18 @@ module Animoto
|
|
|
183
231
|
#
|
|
184
232
|
# @param [Class] klass the Resource class you're looking for
|
|
185
233
|
# @param [String] url the URL of the resource
|
|
186
|
-
# @param [Hash] options
|
|
187
|
-
# @return [Hash] deserialized response body
|
|
234
|
+
# @param [Hash<Symbol,Object>] options
|
|
235
|
+
# @return [Hash<String,Object>] deserialized response body
|
|
188
236
|
def find_request klass, url, options = {}
|
|
189
237
|
request(:get, url, nil, { "Accept" => content_type_of(klass) }, options)
|
|
190
238
|
end
|
|
191
239
|
|
|
192
240
|
# Builds a request requiring a manifest.
|
|
193
241
|
#
|
|
194
|
-
# @param [
|
|
242
|
+
# @param [Manifests::Base] manifest the manifest being acted on
|
|
195
243
|
# @param [String] endpoint the endpoint to send the request to
|
|
196
|
-
# @param [Hash] options
|
|
197
|
-
# @return [Hash] deserialized response body
|
|
244
|
+
# @param [Hash<Symbol,Object>] options
|
|
245
|
+
# @return [Hash<String,Object>] deserialized response body
|
|
198
246
|
def send_manifest manifest, endpoint, options = {}
|
|
199
247
|
u = URI.parse(self.endpoint)
|
|
200
248
|
u.path = endpoint
|
|
@@ -211,25 +259,30 @@ module Animoto
|
|
|
211
259
|
#
|
|
212
260
|
# @param [Symbol] method which HTTP method to use (should be lowercase, i.e. :get instead of :GET)
|
|
213
261
|
# @param [String] url the URL of the request
|
|
214
|
-
# @param [String,
|
|
262
|
+
# @param [String,nil] body the request body
|
|
215
263
|
# @param [Hash<String,String>] headers the request headers (will be sent as-is, which means you should
|
|
216
264
|
# specify "Content-Type" => "..." instead of, say, :content_type => "...")
|
|
217
|
-
# @param [Hash] options
|
|
218
|
-
# @return [Hash] deserialized response body
|
|
265
|
+
# @param [Hash<Symbol,Object>] options
|
|
266
|
+
# @return [Hash<String,Object>] deserialized response body
|
|
219
267
|
# @raise [Error]
|
|
220
268
|
def request method, url, body, headers = {}, options = {}
|
|
221
|
-
|
|
269
|
+
code, body = catch(:fail) do
|
|
222
270
|
options = { :username => @key, :password => @secret }.merge(options)
|
|
223
271
|
@logger.info "Sending request to #{url.inspect} with body #{body}"
|
|
224
272
|
response = http_engine.request(method, url, body, headers, options)
|
|
225
273
|
@logger.info "Received response #{response}"
|
|
226
274
|
return response_parser.parse(response)
|
|
227
275
|
end
|
|
228
|
-
if
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
276
|
+
if code
|
|
277
|
+
if body.empty?
|
|
278
|
+
@logger.error "HTTP error (#{code})"
|
|
279
|
+
raise Animoto::Error.new("HTTP error (#{code})")
|
|
280
|
+
else
|
|
281
|
+
errors = response_parser.parse(body)['response']['status']['errors']
|
|
282
|
+
err_string = errors.collect { |e| e['message'] }.join(', ')
|
|
283
|
+
@logger.error "Error response from server: #{err_string}"
|
|
284
|
+
raise Animoto::Error.new(err_string)
|
|
285
|
+
end
|
|
233
286
|
else
|
|
234
287
|
@logger.error "Error sending request to #{url.inspect}"
|
|
235
288
|
raise Animoto::Error
|
|
@@ -240,7 +293,7 @@ module Animoto
|
|
|
240
293
|
end
|
|
241
294
|
|
|
242
295
|
# Creates the full content type string given a Resource class or instance
|
|
243
|
-
# @param [Class,ContentType] klass_or_instance the class or instance to build the
|
|
296
|
+
# @param [Class,Support::ContentType] klass_or_instance the class or instance to build the
|
|
244
297
|
# content type for
|
|
245
298
|
# @return [String] the full content type with the version and format included (i.e.
|
|
246
299
|
# "application/vnd.animoto.storyboard-v1+json")
|