animoto 0.0.0.alpha0
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 +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
|