animoto 0.0.0.alpha0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +39 -0
- data/lib/animoto/asset.rb +25 -0
- data/lib/animoto/client.rb +226 -0
- data/lib/animoto/content_type.rb +47 -0
- data/lib/animoto/directing_and_rendering_job.rb +19 -0
- data/lib/animoto/directing_and_rendering_manifest.rb +25 -0
- data/lib/animoto/directing_job.rb +18 -0
- data/lib/animoto/directing_manifest.rb +115 -0
- data/lib/animoto/errors.rb +3 -0
- data/lib/animoto/footage.rb +15 -0
- data/lib/animoto/image.rb +14 -0
- data/lib/animoto/job.rb +37 -0
- data/lib/animoto/manifest.rb +21 -0
- data/lib/animoto/rendering_job.rb +24 -0
- data/lib/animoto/rendering_manifest.rb +37 -0
- data/lib/animoto/resource.rb +153 -0
- data/lib/animoto/song.rb +16 -0
- data/lib/animoto/standard_envelope.rb +27 -0
- data/lib/animoto/storyboard.rb +22 -0
- data/lib/animoto/title_card.rb +26 -0
- data/lib/animoto/video.rb +29 -0
- data/lib/animoto/visual.rb +30 -0
- data/lib/animoto.rb +5 -0
- data/spec/animoto/asset_spec.rb +1 -0
- data/spec/animoto/client_spec.rb +119 -0
- data/spec/animoto/directing_and_rendering_job_spec.rb +45 -0
- data/spec/animoto/directing_and_rendering_manifest_spec.rb +143 -0
- data/spec/animoto/directing_job_spec.rb +48 -0
- data/spec/animoto/directing_manifest_spec.rb +186 -0
- data/spec/animoto/footage_spec.rb +56 -0
- data/spec/animoto/image_spec.rb +41 -0
- data/spec/animoto/job_spec.rb +128 -0
- data/spec/animoto/rendering_job_spec.rb +57 -0
- data/spec/animoto/rendering_manifest_spec.rb +115 -0
- data/spec/animoto/resource_spec.rb +55 -0
- data/spec/animoto/song_spec.rb +54 -0
- data/spec/animoto/standard_envelope_spec.rb +0 -0
- data/spec/animoto/storyboard_spec.rb +8 -0
- data/spec/animoto/title_card_spec.rb +42 -0
- data/spec/animoto/video_spec.rb +1 -0
- data/spec/animoto/visual_spec.rb +0 -0
- data/spec/animoto_spec.rb +5 -0
- data/spec/spec_helper.rb +10 -0
- metadata +127 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
module Animoto
|
2
|
+
class Resource
|
3
|
+
include ContentType
|
4
|
+
include StandardEnvelope
|
5
|
+
|
6
|
+
# @overload endpoint(path)
|
7
|
+
# Sets the endpoint for this class. This is the URL where all requests related
|
8
|
+
# to this service will go.
|
9
|
+
#
|
10
|
+
# @param [String] path the path to set
|
11
|
+
# @return [String] the endpoint
|
12
|
+
#
|
13
|
+
# @overload endpoint()
|
14
|
+
# Returns the endpoint for this class.
|
15
|
+
#
|
16
|
+
# @return [String] the endpoint
|
17
|
+
def self.endpoint path = nil
|
18
|
+
@endpoint = path if path
|
19
|
+
@endpoint
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the endpoint for this class.
|
23
|
+
#
|
24
|
+
# @return [String] the endpoint
|
25
|
+
def endpoint
|
26
|
+
self.class.endpoint
|
27
|
+
end
|
28
|
+
|
29
|
+
# @overload payload_key(key)
|
30
|
+
# Sets the payload key for this class. When building an instance of this class from
|
31
|
+
# a response body, the payload key determines which object in the response payload
|
32
|
+
# holds the attributes for the instance.
|
33
|
+
#
|
34
|
+
# @param [String] key the key to set
|
35
|
+
# @return [String] the key
|
36
|
+
#
|
37
|
+
# @overload payload_key()
|
38
|
+
# Returns the payload key for this class.
|
39
|
+
#
|
40
|
+
# @return [String] the key
|
41
|
+
def self.payload_key key = nil
|
42
|
+
@payload_key = key if key
|
43
|
+
@payload_key || infer_content_type
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns the payload key for this class.
|
47
|
+
#
|
48
|
+
# @return [String] the key
|
49
|
+
def payload_key
|
50
|
+
self.class.payload_key
|
51
|
+
end
|
52
|
+
|
53
|
+
# @private
|
54
|
+
#
|
55
|
+
# Makes a new instance of this class from a deserialized JSON response body. Note that
|
56
|
+
# it assumes the hash you're passing is structured correctly and does no format checking
|
57
|
+
# at all, so if the hash is not in the "standard envelope", this method will most likely
|
58
|
+
# raise an error.
|
59
|
+
#
|
60
|
+
# @param [Hash] body the deserialized JSON response body
|
61
|
+
# @return [Resource] an instance of this class
|
62
|
+
def self.load body
|
63
|
+
new unpack_standard_envelope(body)
|
64
|
+
end
|
65
|
+
|
66
|
+
class << self
|
67
|
+
|
68
|
+
# If an instance is instantiated with the same unique identifier (i.e. URL) as another,
|
69
|
+
# instead of creating a brand new object, will instead update and return the existing
|
70
|
+
# object. This way there should only be one object representing any one resource.
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
# client = Animoto::Client.new
|
74
|
+
# storyboard1 = Animoto::Storyboard.new :url => "https://api.animoto.com/storyboards/1"
|
75
|
+
# storyboard2 = client.find! Animoto::Storyboard, "https://api.animoto.com/storyboards/1"
|
76
|
+
# storyboard1.equal?(storyboard2) # => true
|
77
|
+
#
|
78
|
+
# @param [Hash] attributes a hash of attributes for this resource
|
79
|
+
# @return [Resource] either a new Resource instance, or an existing one with updated
|
80
|
+
# attributes
|
81
|
+
alias_method :original_new, :new
|
82
|
+
def new attributes = {}
|
83
|
+
if attributes[:url] && instances[attributes[:url]]
|
84
|
+
instances[attributes[:url]].instantiate attributes
|
85
|
+
else
|
86
|
+
original_new attributes
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# @private
|
91
|
+
#
|
92
|
+
# Registers an instance in the identity map so that subsequent finds or instantiations
|
93
|
+
# of this resource with the same URL will return the same object.
|
94
|
+
#
|
95
|
+
# @param [Resource] instance the instance to register
|
96
|
+
# @raise [ArgumentError] if the instance isn't of this class
|
97
|
+
def register instance
|
98
|
+
raise ArgumentError unless instance.is_a?(self)
|
99
|
+
instances[instance.url] = instance
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
# Returns (or vivifies) the identity map for this class.
|
105
|
+
#
|
106
|
+
# @return [Hash<String,Resource>] the identity map
|
107
|
+
def instances
|
108
|
+
@instances ||= {}
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
attr_reader :url, :errors
|
113
|
+
|
114
|
+
def initialize attributes = {}
|
115
|
+
instantiate attributes
|
116
|
+
end
|
117
|
+
|
118
|
+
# @private
|
119
|
+
#
|
120
|
+
# Update this instance with new attributes from the response body.
|
121
|
+
#
|
122
|
+
# @param [Hash] body deserialized JSON from a response body
|
123
|
+
# @return [self] this instance, updated
|
124
|
+
def load body = {}
|
125
|
+
instantiate unpack_standard_envelope(body)
|
126
|
+
end
|
127
|
+
|
128
|
+
# @private
|
129
|
+
#
|
130
|
+
# Since Resources can be created a number of different ways, this method does
|
131
|
+
# the actual attribute setting for a Resource, acting much like a public version
|
132
|
+
# of #initialize.
|
133
|
+
#
|
134
|
+
# @param [Hash] attributes hash of attributes for this resource
|
135
|
+
# @return [self] this instance
|
136
|
+
def instantiate attributes = {}
|
137
|
+
@errors = (attributes[:errors] || []).collect { |e| wrap_error e }
|
138
|
+
@url = attributes[:url]
|
139
|
+
self.class.register(self) if @url
|
140
|
+
self
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
# Turns an error from a response body into a Ruby object.
|
146
|
+
#
|
147
|
+
# @param [Hash] error the error "object" from a response body
|
148
|
+
# @return [Error] a Ruby error object
|
149
|
+
def wrap_error error
|
150
|
+
Animoto::Error.new error['message']
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
data/lib/animoto/song.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Animoto
|
2
|
+
class Song < Animoto::Asset
|
3
|
+
|
4
|
+
attr_accessor :start_time, :duration, :title, :artist
|
5
|
+
|
6
|
+
def to_hash
|
7
|
+
hash = super
|
8
|
+
hash['start_time'] = start_time if start_time
|
9
|
+
hash['duration'] = duration if duration
|
10
|
+
hash['title'] = title if title
|
11
|
+
hash['artist'] = artist if artist
|
12
|
+
hash
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Animoto
|
2
|
+
module StandardEnvelope
|
3
|
+
|
4
|
+
def self.included base
|
5
|
+
base.class_eval {
|
6
|
+
include Animoto::StandardEnvelope::InstanceMethods
|
7
|
+
extend Animoto::StandardEnvelope::ClassMethods
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
module InstanceMethods
|
12
|
+
def unpack_standard_envelope body = {}
|
13
|
+
self.class.unpack_standard_envelope body
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
protected
|
19
|
+
def unpack_standard_envelope body = {}
|
20
|
+
{
|
21
|
+
:url => body['response']['payload'][payload_key]['links']['self'],
|
22
|
+
:errors => body['response']['status']['errors'] || []
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Animoto
|
2
|
+
class Storyboard < Animoto::Resource
|
3
|
+
|
4
|
+
def self.unpack_standard_envelope body = {}
|
5
|
+
super.merge({
|
6
|
+
:duration => body['response']['payload'][payload_key]['metadata']['duration'],
|
7
|
+
:visuals_count => body['response']['payload'][payload_key]['metadata']['visuals_count'],
|
8
|
+
:preview_url => body['response']['payload'][payload_key]['links']['preview']
|
9
|
+
})
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :duration, :visuals_count, :preview_url
|
13
|
+
|
14
|
+
def instantiate attributes = {}
|
15
|
+
@duration = attributes[:duration]
|
16
|
+
@visuals_count = attributes[:visuals_count]
|
17
|
+
@preview_url = attributes[:preview_url]
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Animoto
|
2
|
+
class TitleCard
|
3
|
+
include Animoto::Visual
|
4
|
+
|
5
|
+
attr_accessor :title, :subtitle
|
6
|
+
|
7
|
+
# Creates a new TitleCard.
|
8
|
+
#
|
9
|
+
# @param [String] title the main text
|
10
|
+
# @param [String] subtitle the secondary text
|
11
|
+
def initialize title, subtitle = nil
|
12
|
+
@title, @subtitle = title, subtitle
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns a representation of this TitleCard as a Hash.
|
16
|
+
#
|
17
|
+
# @return [Hash] this TitleCard as a Hash
|
18
|
+
def to_hash
|
19
|
+
hash = super
|
20
|
+
hash['h1'] = title
|
21
|
+
hash['h2'] = subtitle if subtitle
|
22
|
+
hash['spotlit'] = spotlit? unless @spotlit.nil?
|
23
|
+
hash
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Animoto
|
2
|
+
class Video < Animoto::Resource
|
3
|
+
|
4
|
+
def self.unpack_standard_envelope body
|
5
|
+
super.merge({
|
6
|
+
:download_url => body['response']['payload'][payload_key]['links']['download'],
|
7
|
+
:storyboard_url => body['response']['payload'][payload_key]['links']['storyboard'],
|
8
|
+
:duration => body['response']['payload'][payload_key]['metadata']['duration'],
|
9
|
+
:format => body['response']['payload'][payload_key]['metadata']['format'],
|
10
|
+
:framerate => body['response']['payload'][payload_key]['metadata']['framerate'],
|
11
|
+
:resolution => body['response']['payload'][payload_key]['metadata']['vertical_resolution']
|
12
|
+
})
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :download_url, :storyboard_url, :storyboard, :duration, :format, :framerate, :resolution
|
16
|
+
|
17
|
+
def instantiate attributes = {}
|
18
|
+
@download_url = attributes[:download_url]
|
19
|
+
@storyboard_url = attributes[:storyboard_url]
|
20
|
+
@storyboard = Animoto::Storyboard.new(:url => @storyboard_url) if @storyboard_url
|
21
|
+
@duration = attributes[:duration]
|
22
|
+
@format = attributes[:format]
|
23
|
+
@framerate = attributes[:framerate]
|
24
|
+
@resolution = attributes[:resolution]
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Animoto
|
2
|
+
module Visual
|
3
|
+
|
4
|
+
# Setter for spotlighting, which instructs the director to give special attention
|
5
|
+
# to this visual when directing.
|
6
|
+
#
|
7
|
+
# @param [Boolean] bool true if this visual should receive special attention
|
8
|
+
def spotlit= bool
|
9
|
+
@spotlit = bool
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns true if this visual is spotlit.
|
13
|
+
#
|
14
|
+
# @return [Boolean] whether or not this visual is spotlit
|
15
|
+
def spotlit?
|
16
|
+
@spotlit
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a representation of this Visual as a Hash
|
20
|
+
#
|
21
|
+
# @return [Hash] this Visual as a Hash
|
22
|
+
def to_hash
|
23
|
+
hash = super rescue {}
|
24
|
+
hash['spotlit'] = spotlit? unless @spotlit.nil?
|
25
|
+
hash['type'] = self.class.name.split('::').last.gsub(/(^)?([A-Z])/) { "#{'_' unless $1}#{$2.downcase}" }
|
26
|
+
hash
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/lib/animoto.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
2
|
+
|
3
|
+
describe Animoto::Client do
|
4
|
+
def client options = {}
|
5
|
+
@client ||= Animoto::Client.new "joe", "secret", options
|
6
|
+
end
|
7
|
+
|
8
|
+
def object
|
9
|
+
@object ||= Object.new
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "supplying credentials" do
|
13
|
+
describe "manually" do
|
14
|
+
it "should accept the key and secret as the first two parameters on initialization" do
|
15
|
+
c = Animoto::Client.new "key", "secret"
|
16
|
+
c.key.should == "key"
|
17
|
+
c.secret.should == "secret"
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "when the secret isn't specified (i.e. only 1 parameter was passed)" do
|
21
|
+
before do
|
22
|
+
File.stubs(:exist?).returns(false) # <= to keep it from finding our .animotorc files
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should raise an error" do
|
26
|
+
lambda { Animoto::Client.new "key" }.should raise_error
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "automatically" do
|
32
|
+
before do
|
33
|
+
@home_path = File.expand_path("~/.animotorc")
|
34
|
+
@etc_path = "/etc/.animotorc"
|
35
|
+
@config = "key: joe\nsecret: secret"
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "when ~/.animotorc exists" do
|
39
|
+
before do
|
40
|
+
File.stubs(:exist?).with(@home_path).returns(true)
|
41
|
+
File.stubs(:read).with(@home_path).returns(@config)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should configure itself based on the options in ~/.animotorc" do
|
45
|
+
c = Animoto::Client.new
|
46
|
+
c.key.should == "joe"
|
47
|
+
c.secret.should == "secret"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "when ~/.animotorc doesn't exist" do
|
52
|
+
before do
|
53
|
+
File.stubs(:exist?).with(@home_path).returns(false)
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "when /etc/.animotorc exists" do
|
57
|
+
before do
|
58
|
+
File.stubs(:exist?).with(@etc_path).returns(true)
|
59
|
+
File.stubs(:read).with(@etc_path).returns(@config)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should configure itself based on the options in /etc/.animotorc" do
|
63
|
+
c = Animoto::Client.new
|
64
|
+
c.key.should == "joe"
|
65
|
+
c.secret.should == "secret"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "when /etc/.animotorc doesn't exist" do
|
70
|
+
it "should raise an error" do
|
71
|
+
lambda { Animoto::Client.new }.should raise_error
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "finding an instance by identifier" do
|
79
|
+
before do
|
80
|
+
@url = "https://api.animoto.com/storyboards/1"
|
81
|
+
@body = {'response'=>{'status'=>{'code'=>200}},'payload'=>{'storyboard'=>{'links'=>{'self'=>@url}}}}
|
82
|
+
stub_request(:get, @url).to_return(:body => @body.to_json, :status => [200,"OK"])
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should make a GET request to the given url" do
|
86
|
+
client.find(Animoto::Storyboard, @url)
|
87
|
+
WebMock.should have_requested(:get, @url)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should ask for a response in the proper format" do
|
91
|
+
client.find(Animoto::Storyboard, @url)
|
92
|
+
WebMock.should have_requested(:get, @url).with(:headers => { 'Accept' => "application/vnd.animoto.storyboard-v1+json"})
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should not sent a request body" do
|
96
|
+
client.find(Animoto::Storyboard, @url)
|
97
|
+
WebMock.should have_requested(:get, @url).with(:body => "")
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should return an instance of the correct resource type" do
|
101
|
+
client.find(Animoto::Storyboard, @url).should be_an_instance_of(Animoto::Storyboard)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "reloading an instance" do
|
106
|
+
before do
|
107
|
+
@url = 'https://api.animoto.com/jobs/directing/1'
|
108
|
+
@job = Animoto::DirectingJob.new :state => 'initial', :url => @url
|
109
|
+
@body = {'response'=>{'status'=>{'code'=>200}},'payload'=>{'directing_job'=>{'state'=>'retrieving_assets','links'=>{'self'=>@url}}}}
|
110
|
+
stub_request(:get, @url).to_return(:body => @body.to_json, :status => [200,"OK"])
|
111
|
+
@job.state.should == 'initial' # sanity check
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should update the resource's attributes" do
|
115
|
+
client.reload!(@job)
|
116
|
+
@job.state.should == 'retrieving_assets'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
2
|
+
|
3
|
+
describe Animoto::DirectingAndRenderingJob do
|
4
|
+
|
5
|
+
it "should have endpoint '/jobs/directing_and_rendering'" do
|
6
|
+
Animoto::DirectingAndRenderingJob.endpoint.should == '/jobs/directing_and_rendering'
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should have content_type 'application/vnd.animoto.directing_and_rendering_job'" do
|
10
|
+
Animoto::DirectingAndRenderingJob.content_type.should == 'directing_and_rendering_job'
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have payload key 'directing_and_rendering_job'" do
|
14
|
+
Animoto::DirectingAndRenderingJob.payload_key.should == 'directing_and_rendering_job'
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "loading from a response body" do
|
18
|
+
before do
|
19
|
+
@body = {
|
20
|
+
'response' => {
|
21
|
+
'status' => { 'code' => 200 },
|
22
|
+
'payload' => {
|
23
|
+
'directing_and_rendering_job' => {
|
24
|
+
'state' => 'completed',
|
25
|
+
'links' => {
|
26
|
+
'self' => 'http://animoto.com/jobs/directing_and_rendering/1',
|
27
|
+
'video' => 'http://animoto.com/videos/1'
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
@job = Animoto::DirectingAndRenderingJob.load @body
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should set the video url from the body" do
|
37
|
+
@job.video_url.should == 'http://animoto.com/videos/1'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should create a video from the video url" do
|
41
|
+
@job.video.should be_an_instance_of(Animoto::Video)
|
42
|
+
@job.video.url.should == @job.video_url
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Animoto::DirectingAndRenderingManifest do
|
4
|
+
|
5
|
+
def manifest options = {}
|
6
|
+
@manifest ||= Animoto::DirectingAndRenderingManifest.new options
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "generating a hash" do
|
10
|
+
before do
|
11
|
+
manifest(:title => 'Funderful Wonderment', :producer => 'Senor Spielbergo', :pacing => 'double',
|
12
|
+
:resolution => "720p", :framerate => 24, :format => 'flv')
|
13
|
+
@image = manifest.add_image 'http://website.com/image.png'
|
14
|
+
@title_card = manifest.add_title_card 'woohoo', 'this is awesome'
|
15
|
+
@footage = manifest.add_footage 'http://website.com/movie.mp4'
|
16
|
+
@song_obj = manifest.add_song 'http://website.com/song.mp3'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should have top-level 'directing_and_rendering_job' object" do
|
20
|
+
manifest.to_hash.should have_key('directing_and_rendering_job')
|
21
|
+
manifest.to_hash['directing_and_rendering_job'].should be_a(Hash)
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "when the callback url is set" do
|
25
|
+
before do
|
26
|
+
manifest.http_callback_url = 'http://website.com/callback'
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "but the callback format isn't" do
|
30
|
+
it "should raise an error" do
|
31
|
+
lambda { manifest.to_hash }.should raise_error(ArgumentError)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "as well as the format" do
|
36
|
+
before do
|
37
|
+
manifest.http_callback_format = 'xml'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should have the HTTP callback URL in the job" do
|
41
|
+
manifest.to_hash['directing_and_rendering_job'].should have_key('http_callback')
|
42
|
+
manifest.to_hash['directing_and_rendering_job']['http_callback'].should == manifest.http_callback_url
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should have the HTTP callback format in the job" do
|
46
|
+
manifest.to_hash['directing_and_rendering_job'].should have_key('http_callback_format')
|
47
|
+
manifest.to_hash['directing_and_rendering_job']['http_callback_format'].should == manifest.http_callback_format
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should have a 'directing_manifest' object within the job" do
|
53
|
+
manifest.to_hash['directing_and_rendering_job'].should have_key('directing_manifest')
|
54
|
+
manifest.to_hash['directing_and_rendering_job']['directing_manifest'].should be_a(Hash)
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "directing_manifest" do
|
58
|
+
before do
|
59
|
+
@hash = manifest.to_hash['directing_and_rendering_job']['directing_manifest']
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should have a 'style' key in the manifest" do
|
63
|
+
@hash.should have_key('style')
|
64
|
+
@hash['style'].should == manifest.style
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should have a 'pacing' key in the manifest" do
|
68
|
+
@hash.should have_key('pacing')
|
69
|
+
@hash['pacing'].should == manifest.pacing
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should have a 'producer_name' key in the manifest" do
|
73
|
+
@hash.should have_key('producer_name')
|
74
|
+
@hash['producer_name'].should == manifest.producer
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should have a 'visuals' key in the manifest" do
|
78
|
+
@hash.should have_key('visuals')
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should have a 'song' object in the manifest" do
|
82
|
+
@hash.should have_key('song')
|
83
|
+
@hash['song'].should be_a(Hash)
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "visuals array" do
|
87
|
+
before do
|
88
|
+
@visuals = @hash['visuals']
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should have the visuals in the order they were added" do
|
92
|
+
@visuals[0].should == @image.to_hash
|
93
|
+
@visuals[1].should == @title_card.to_hash
|
94
|
+
@visuals[2].should == @footage.to_hash
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "song" do
|
99
|
+
before do
|
100
|
+
@song = @hash['song']
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should have info about the song" do
|
104
|
+
@song.should == @song_obj.to_hash
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should have a 'rendering_manifest' object within the job" do
|
110
|
+
manifest.to_hash['directing_and_rendering_job'].should have_key('rendering_manifest')
|
111
|
+
manifest.to_hash['directing_and_rendering_job']['rendering_manifest'].should be_a(Hash)
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "rendering_manifest" do
|
115
|
+
before do
|
116
|
+
@hash = manifest.to_hash['directing_and_rendering_job']['rendering_manifest']
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should have a 'rendering_profile' object in the manifest" do
|
120
|
+
@hash.should have_key('rendering_profile')
|
121
|
+
@hash['rendering_profile'].should be_a(Hash)
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "rendering_profile" do
|
125
|
+
before do
|
126
|
+
@profile = @hash['rendering_profile']
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should have a 'vertical_resolution' key" do
|
130
|
+
@profile['vertical_resolution'].should == manifest.resolution
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should have a 'framerate' key" do
|
134
|
+
@profile['framerate'].should == manifest.framerate
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should have a 'format' key" do
|
138
|
+
@profile['format'].should == manifest.format
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
2
|
+
|
3
|
+
describe Animoto::DirectingJob do
|
4
|
+
|
5
|
+
it "should have endpoint '/jobs/directing'" do
|
6
|
+
Animoto::DirectingJob.endpoint.should == '/jobs/directing'
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should have content type 'application/vnd.animoto.directing_job'" do
|
10
|
+
Animoto::DirectingJob.content_type.should == 'directing_job'
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have payload key 'directing_job'" do
|
14
|
+
Animoto::DirectingJob.payload_key.should == 'directing_job'
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "loading from a response body" do
|
18
|
+
before do
|
19
|
+
@body = {
|
20
|
+
'response' => {
|
21
|
+
'status' => {
|
22
|
+
'code' => 200
|
23
|
+
},
|
24
|
+
'payload' => {
|
25
|
+
'directing_job' => {
|
26
|
+
'state' => 'completed',
|
27
|
+
'links' => {
|
28
|
+
'self' => 'http://animoto.com/jobs/directing/1',
|
29
|
+
'storyboard' => 'http://animoto.com/storyboards/1'
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
35
|
+
@job = Animoto::DirectingJob.load @body
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should set the storyboard url from the body" do
|
39
|
+
@job.storyboard_url.should == 'http://animoto.com/storyboards/1'
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should create a storyboard from the storyboard url" do
|
43
|
+
@job.storyboard.should be_an_instance_of(Animoto::Storyboard)
|
44
|
+
@job.storyboard.url.should == @job.storyboard_url
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|