uencode 0.0.1
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/.autotest +0 -0
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/Guardfile +8 -0
- data/README.md +60 -0
- data/Rakefile +4 -0
- data/lib/uencode.rb +35 -0
- data/lib/uencode/elements.rb +233 -0
- data/lib/uencode/request.rb +33 -0
- data/lib/uencode/response.rb +30 -0
- data/lib/uencode/version.rb +3 -0
- data/spec/elements_spec.rb +478 -0
- data/spec/fixtures/job_with_one_video_and_no_capture.yml +87 -0
- data/spec/request_spec.rb +53 -0
- data/spec/response_spec.rb +48 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/uencode_spec.rb +14 -0
- data/uencode.gemspec +32 -0
- metadata +177 -0
data/.autotest
ADDED
File without changes
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# UEncode
|
2
|
+
|
3
|
+
A simple Ruby gem to consume the [uEncode](http://www.uencode.com) API.
|
4
|
+
|
5
|
+
## Synopsis
|
6
|
+
|
7
|
+
``` ruby
|
8
|
+
require 'uencode'
|
9
|
+
|
10
|
+
# In Rails you can put this inside an initializer
|
11
|
+
UEncode.configure do |c|
|
12
|
+
c.customer_key = "your_uencode_api_key"
|
13
|
+
end
|
14
|
+
|
15
|
+
job = UEncode::Job.new :source => "http://your_source_video_url/foo.avi", :userdata => "This is a simple test"
|
16
|
+
|
17
|
+
job.configure_video_output { |c| c.destination = "http://your_destination_url/transcoded.mp4"; c.container = "mpeg4" }
|
18
|
+
|
19
|
+
video = UEncode::Medium.new
|
20
|
+
|
21
|
+
video.configure_video { |c| c.bitrate = 300000; c.codec = "h264"}
|
22
|
+
|
23
|
+
video.configure_audio do |c|
|
24
|
+
c.bitrate = 64000
|
25
|
+
c.codec = "aac"
|
26
|
+
c.samplerate = 44100
|
27
|
+
c.channels = 1
|
28
|
+
end
|
29
|
+
|
30
|
+
job << video
|
31
|
+
|
32
|
+
capture = UEncode::CaptureOutput.new :destination => "http://whatever.com/foo.zip", :rate => "every 30s"
|
33
|
+
job.add_capture capture
|
34
|
+
|
35
|
+
request = UEncode::Request.new job
|
36
|
+
puts job.to_xml
|
37
|
+
response = request.send
|
38
|
+
|
39
|
+
puts response.code # => 'Ok'
|
40
|
+
puts response.message # => 'Your job was created successfully'
|
41
|
+
puts response.jobid # => 1234567
|
42
|
+
puts response.userdata # => 'This is a simple test'
|
43
|
+
```
|
44
|
+
|
45
|
+
## Accepted parameters
|
46
|
+
|
47
|
+
Currently all the uEncode API parameters are supported (or so I think :)
|
48
|
+
|
49
|
+
Currently the gem does not validate parameters' values, so pay attention at the API docs.
|
50
|
+
|
51
|
+
You can see the whole list of accepted parameters in the [uEncode API documentation](http://www.uencode.com/api/300#response_codes).
|
52
|
+
|
53
|
+
For the UEncode classes that map to each complex API parameters (like Crop, Size, FrameRate, etc) take a look at the spec file at /spec/elements_spec.rb or read the docs.
|
54
|
+
|
55
|
+
## Running the specs
|
56
|
+
|
57
|
+
* bundle install
|
58
|
+
* rspec spec
|
59
|
+
|
60
|
+
|
data/Rakefile
ADDED
data/lib/uencode.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
|
4
|
+
require 'singleton'
|
5
|
+
require 'nokogiri'
|
6
|
+
require 'httparty'
|
7
|
+
|
8
|
+
module UEncode
|
9
|
+
class << self
|
10
|
+
attr_accessor :customer_key
|
11
|
+
|
12
|
+
def configure
|
13
|
+
yield self
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module AttrSetting
|
18
|
+
def set_attributes(options)
|
19
|
+
self.class.const_get("ATTRIBUTES").each { |attr| instance_variable_set(:"@#{attr}", options[attr]) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(options)
|
23
|
+
set_attributes options
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.included(klass)
|
27
|
+
attr = klass.const_get "ATTRIBUTES"
|
28
|
+
klass.send(:attr_reader, *attr)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
require "uencode/elements"
|
34
|
+
require "uencode/request"
|
35
|
+
require "uencode/response"
|
@@ -0,0 +1,233 @@
|
|
1
|
+
module UEncode
|
2
|
+
class Crop
|
3
|
+
ATTRIBUTES = [:width, :height, :x, :y]
|
4
|
+
|
5
|
+
def to_xml
|
6
|
+
%Q{
|
7
|
+
<crop>
|
8
|
+
<width>#{width}</width>
|
9
|
+
<height>#{height}</height>
|
10
|
+
<x>#{x}</x>
|
11
|
+
<y>#{y}</y>
|
12
|
+
</crop>
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Size
|
18
|
+
ATTRIBUTES = [:width, :height]
|
19
|
+
|
20
|
+
def to_xml
|
21
|
+
%Q{
|
22
|
+
<size>
|
23
|
+
<width>#{width}</width>
|
24
|
+
<height>#{height}</heignt>
|
25
|
+
</size>
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module RateElement
|
31
|
+
def to_xml
|
32
|
+
%Q{
|
33
|
+
<#{root_name}>
|
34
|
+
<numerator>#{numerator}</numerator>
|
35
|
+
<denominator>#{denominator}</denominator>
|
36
|
+
</#{root_name}>
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class FrameRate
|
42
|
+
include RateElement
|
43
|
+
ATTRIBUTES = [:numerator, :denominator]
|
44
|
+
|
45
|
+
private
|
46
|
+
def root_name; "framerate"; end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Par < FrameRate
|
50
|
+
include RateElement
|
51
|
+
ATTRIBUTES = [:numerator, :denominator]
|
52
|
+
|
53
|
+
private
|
54
|
+
def root_name; "par"; end
|
55
|
+
end
|
56
|
+
|
57
|
+
class CaptureOutput
|
58
|
+
ATTRIBUTES = [:destination, :rate, :stretch, :crop, :size]
|
59
|
+
|
60
|
+
def initialize(options)
|
61
|
+
super
|
62
|
+
@stretch = false if @stretch.nil?
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_xml
|
66
|
+
%Q{
|
67
|
+
<output>
|
68
|
+
<capture>
|
69
|
+
<rate>#{rate}</rate>
|
70
|
+
<destination>#{destination}</destination>
|
71
|
+
#{@crop ? @crop.to_xml : ""}
|
72
|
+
#{@size ? @size.to_xml : ""}
|
73
|
+
</capture>
|
74
|
+
<//output>
|
75
|
+
}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class VideoOutput
|
80
|
+
ATTRIBUTES = [:destination, :container]
|
81
|
+
|
82
|
+
include Enumerable
|
83
|
+
|
84
|
+
# a list of Medium
|
85
|
+
attr_reader :items
|
86
|
+
attr_writer :destination, :container
|
87
|
+
|
88
|
+
def initialize(options)
|
89
|
+
@items = []
|
90
|
+
super
|
91
|
+
end
|
92
|
+
|
93
|
+
def each
|
94
|
+
@items.each { |item| yield item }
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_xml
|
98
|
+
%Q{
|
99
|
+
<output>
|
100
|
+
<video>
|
101
|
+
<destination>#{destination}</destination>
|
102
|
+
<container>#{container}</container>
|
103
|
+
<media>
|
104
|
+
#{@items.inject("") { |s, item| s << item.to_xml }}
|
105
|
+
</media>
|
106
|
+
</video>
|
107
|
+
</output>
|
108
|
+
}
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Medium is a single video to transcode
|
113
|
+
class Medium
|
114
|
+
def initialize
|
115
|
+
@video_config = VideoConfig.new
|
116
|
+
@audio_config = AudioConfig.new
|
117
|
+
end
|
118
|
+
|
119
|
+
def configure_video
|
120
|
+
yield @video_config
|
121
|
+
end
|
122
|
+
|
123
|
+
def configure_audio
|
124
|
+
yield @audio_config
|
125
|
+
end
|
126
|
+
|
127
|
+
def video
|
128
|
+
@video_config
|
129
|
+
end
|
130
|
+
|
131
|
+
def audio
|
132
|
+
@audio_config
|
133
|
+
end
|
134
|
+
|
135
|
+
def to_xml
|
136
|
+
%Q{
|
137
|
+
<medium>
|
138
|
+
<video>
|
139
|
+
<bitrate>#{video.bitrate}</birate>
|
140
|
+
<codec>#{video.codec}</birate>
|
141
|
+
#{!video.cbr.nil? ? '<cbr>' + video.cbr.to_s + '</cbr>' : ""}
|
142
|
+
#{video.crop ? video.crop.to_xml : ""}
|
143
|
+
#{video.deinterlace.nil? ? "" : '<deinterlace>' + video.deinterlace.to_s + '</deinterlace>'}
|
144
|
+
#{video.framerate ? video.framerate.to_xml : ""}
|
145
|
+
#{video.height.nil? ? "" : '<height>' + video.height.to_s + '</height>'}
|
146
|
+
#{video.keyframe_interval.nil? ? "" : '<keyframe_interval>' + video.keyframe_interval.to_s + '</keyframe_interval>'}
|
147
|
+
#{video.maxbitrate.nil? ? "" : '<maxbitrate>' + video.maxbitrate.to_s + '</maxbitrate>'}
|
148
|
+
#{video.par ? video.par.to_xml : ""}
|
149
|
+
#{video.profile.nil? ? "" : '<profile>' + video.profile + '</profile>'}
|
150
|
+
#{video.passes.nil? ? "" : '<passes>' + video.passes.to_s + '</passes>'}
|
151
|
+
#{[nil, false].include?(video.stretch) ? "" : '<stretch>' + video.stretch.to_s + '</stretch>'}
|
152
|
+
#{video.width.nil? ? "" : '<width>' + video.width.to_s + '</width>'}
|
153
|
+
</video>
|
154
|
+
<audio>
|
155
|
+
#{audio.codec.nil? ? "" : '<codec>' + audio.codec + '</codec>'}
|
156
|
+
#{audio.bitrate.nil? ? "" : '<bitrate>' + audio.bitrate.to_s + '</bitrate>'}
|
157
|
+
#{audio.channels.nil? ? "" : '<channels>' + audio.channels.to_s + '</channels>'}
|
158
|
+
#{audio.samplerate.nil? ? "" : '<samplerate>' + audio.samplerate.to_s + '</samplerate>'}
|
159
|
+
</audio>
|
160
|
+
</medium>
|
161
|
+
}
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# The video configs for each Medium
|
166
|
+
class VideoConfig
|
167
|
+
attr_accessor :bitrate, :codec, :cbr, :crop, :deinterlace, :framerate, :height, :keyframe_interval,
|
168
|
+
:maxbitrate, :par, :profile, :passes, :stretch, :width
|
169
|
+
|
170
|
+
def initialize
|
171
|
+
@cbr = false
|
172
|
+
@deinterlace = false
|
173
|
+
@profile = "main"
|
174
|
+
@passes = 1
|
175
|
+
@stretch = false
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# The audio configs for each Medium
|
180
|
+
class AudioConfig
|
181
|
+
attr_accessor :codec, :bitrate, :channels, :samplerate
|
182
|
+
end
|
183
|
+
|
184
|
+
class Job
|
185
|
+
ATTRIBUTES = [:source, :userdata, :notify]
|
186
|
+
|
187
|
+
include Enumerable
|
188
|
+
|
189
|
+
def initialize(options)
|
190
|
+
@video_output = VideoOutput.new options[:video_output] || {}
|
191
|
+
@captures = []
|
192
|
+
super
|
193
|
+
end
|
194
|
+
|
195
|
+
def configure_video_output
|
196
|
+
yield @video_output
|
197
|
+
end
|
198
|
+
|
199
|
+
def items
|
200
|
+
@video_output.items
|
201
|
+
end
|
202
|
+
|
203
|
+
def <<(item)
|
204
|
+
@video_output.items << item
|
205
|
+
end
|
206
|
+
|
207
|
+
def add_capture(capture)
|
208
|
+
@captures << capture
|
209
|
+
end
|
210
|
+
|
211
|
+
def each(&block)
|
212
|
+
@video_output.each &block
|
213
|
+
end
|
214
|
+
|
215
|
+
def to_xml
|
216
|
+
xml = %Q{
|
217
|
+
<job>
|
218
|
+
<customerkey>#{UEncode.customer_key}</customerkey>
|
219
|
+
<source>#{source}</source>
|
220
|
+
#{userdata.nil? ? "" : '<userdata>' + userdata + '</userdata>'}
|
221
|
+
#{notify.nil? ? "" : '<notify>' + notify + '</notify>'}
|
222
|
+
<outputs>
|
223
|
+
#{@video_output.to_xml}
|
224
|
+
#{@captures.inject("") { |s, cap| s << cap.to_xml }}
|
225
|
+
</outputs>
|
226
|
+
</job>
|
227
|
+
}
|
228
|
+
Nokogiri::XML(xml).to_xml
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
[Size, FrameRate, Crop, VideoOutput, CaptureOutput, Job].each { |klass| klass.send :include, AttrSetting }
|
233
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module UEncode
|
2
|
+
class Request
|
3
|
+
include HTTParty
|
4
|
+
|
5
|
+
base_uri "https://www.uencode.com"
|
6
|
+
format :xml
|
7
|
+
|
8
|
+
def initialize(job)
|
9
|
+
@job = job
|
10
|
+
end
|
11
|
+
|
12
|
+
def send
|
13
|
+
response = self.class.put "/jobs?version=300", :body => @job.to_xml
|
14
|
+
parse_response response
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def parse_response(response_xml)
|
19
|
+
doc = Nokogiri::XML response_xml.body
|
20
|
+
code = doc.xpath("//code").text
|
21
|
+
message = doc.xpath("//message").text
|
22
|
+
jobid = doc.xpath("//jobid").text
|
23
|
+
userdata = doc.xpath("//userdata").text
|
24
|
+
|
25
|
+
Response.new(
|
26
|
+
:code => code,
|
27
|
+
:message => message,
|
28
|
+
:jobid => jobid,
|
29
|
+
:userdata => userdata
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module UEncode
|
2
|
+
class Response
|
3
|
+
class BadRequestError < StandardError; end
|
4
|
+
class InvalidKeyError < StandardError; end
|
5
|
+
class NotActiveError < StandardError; end
|
6
|
+
class ServerError < StandardError; end
|
7
|
+
class UnknownError < StandardError; end
|
8
|
+
|
9
|
+
ATTRIBUTES = [:code, :message, :jobid, :userdata]
|
10
|
+
|
11
|
+
include AttrSetting
|
12
|
+
|
13
|
+
def initialize(options)
|
14
|
+
check_response_code options[:code], options[:message]
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def check_response_code(code, message)
|
20
|
+
return if code == 'Ok'
|
21
|
+
case code
|
22
|
+
when 'BadRequest'; raise BadRequestError, message
|
23
|
+
when 'InvalidKey'; raise InvalidKeyError, message
|
24
|
+
when 'NotActive'; raise NotActiveError, message
|
25
|
+
when 'ServerError'; raise ServerError, message
|
26
|
+
else raise UnknownError, "#{code}: #{message}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,478 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe UEncode::Medium do
|
4
|
+
let(:medium) { UEncode::Medium.new }
|
5
|
+
|
6
|
+
before :each do
|
7
|
+
medium.configure_video do |c|
|
8
|
+
c.bitrate = 10000
|
9
|
+
c.codec = "mp4"
|
10
|
+
c.cbr = false
|
11
|
+
c.crop = nil
|
12
|
+
c.deinterlace = true
|
13
|
+
c.framerate = UEncode::FrameRate.new :numerator => 1000, :denominator => 1001
|
14
|
+
c.height = 500
|
15
|
+
c.keyframe_interval = 0
|
16
|
+
c.maxbitrate = 10000
|
17
|
+
c.par = nil
|
18
|
+
c.profile = "baseline"
|
19
|
+
c.passes = 1
|
20
|
+
c.stretch = false
|
21
|
+
c.width = 400
|
22
|
+
end
|
23
|
+
|
24
|
+
medium.configure_audio do |c|
|
25
|
+
c.codec = "aac"
|
26
|
+
c.bitrate = 15000
|
27
|
+
c.channels = 2
|
28
|
+
c.samplerate = 10000
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#configure_video" do
|
33
|
+
let(:medium) { UEncode::Medium.new }
|
34
|
+
|
35
|
+
it { medium.video.bitrate.should == 10000 }
|
36
|
+
it { medium.video.codec.should == "mp4" }
|
37
|
+
it { medium.video.cbr.should == false }
|
38
|
+
it { medium.video.crop.should be_nil }
|
39
|
+
it { medium.video.deinterlace.should == true }
|
40
|
+
it { medium.video.framerate.numerator.should == 1000 }
|
41
|
+
it { medium.video.height.should == 500 }
|
42
|
+
it { medium.video.keyframe_interval.should == 0 }
|
43
|
+
it { medium.video.maxbitrate.should == 10000 }
|
44
|
+
it { medium.video.par.should be_nil }
|
45
|
+
it { medium.video.profile.should == "baseline" }
|
46
|
+
it { medium.video.passes.should == 1 }
|
47
|
+
it { medium.video.stretch.should == false }
|
48
|
+
it { medium.video.width.should == 400 }
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#configure_audio" do
|
52
|
+
let(:medium) { UEncode::Medium.new }
|
53
|
+
|
54
|
+
it { medium.audio.codec.should == "aac" }
|
55
|
+
it { medium.audio.bitrate.should == 15000 }
|
56
|
+
it { medium.audio.channels.should == 2 }
|
57
|
+
it { medium.audio.samplerate.should == 10000 }
|
58
|
+
end
|
59
|
+
|
60
|
+
context "video config default values" do
|
61
|
+
let(:medium_without_configuration) { described_class.new }
|
62
|
+
|
63
|
+
it { medium_without_configuration.video.cbr.should == false }
|
64
|
+
it { medium_without_configuration.video.deinterlace.should == false }
|
65
|
+
it { medium_without_configuration.video.profile.should == "main" }
|
66
|
+
it { medium_without_configuration.video.passes.should == 1 }
|
67
|
+
it { medium_without_configuration.video.stretch.should == false }
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#to_xml" do
|
71
|
+
let(:xml) { Nokogiri::XML medium.to_xml }
|
72
|
+
|
73
|
+
before :each do
|
74
|
+
medium.configure_video do |c|
|
75
|
+
c.crop = UEncode::Crop.new :width => 125, :height => 150, :x => 100, :y => 200
|
76
|
+
c.par = UEncode::Par.new :numerator => 10, :denominator => 11
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it "has a root element named 'media'" do
|
81
|
+
xml.root.name.should == 'medium'
|
82
|
+
end
|
83
|
+
|
84
|
+
it "has the correct video configs" do
|
85
|
+
config = xml.xpath("//video")
|
86
|
+
config.xpath("//video/bitrate").text.should == "10000"
|
87
|
+
config.xpath("//video/codec").text.should == "mp4"
|
88
|
+
config.xpath("//cbr").text.should == "false"
|
89
|
+
config.xpath("//crop/width").text.should == "125"
|
90
|
+
config.xpath("//crop/height").text.should == "150"
|
91
|
+
config.xpath("//crop/x").text.should == "100"
|
92
|
+
config.xpath("//crop/y").text.should == "200"
|
93
|
+
config.xpath("//deinterlace").text.should == "true"
|
94
|
+
config.xpath("//framerate/numerator").text.should == "1000"
|
95
|
+
config.xpath("//framerate/denominator").text.should == "1001"
|
96
|
+
config.xpath("//video/height").text.should == "500"
|
97
|
+
config.xpath("//keyframe_interval").text.should == "0"
|
98
|
+
config.xpath("//maxbitrate").text.should == "10000"
|
99
|
+
config.xpath("//par/numerator").text.should == "10"
|
100
|
+
config.xpath("//par/denominator").text.should == "11"
|
101
|
+
config.xpath("//profile").text.should == "baseline"
|
102
|
+
config.xpath("//passes").text.should == "1"
|
103
|
+
config.xpath("//video/width").text.should == "400"
|
104
|
+
end
|
105
|
+
|
106
|
+
it "does not include the cbr video config when it's null" do
|
107
|
+
medium.configure_video { |c| c.cbr = nil }
|
108
|
+
Nokogiri::XML(medium.to_xml).xpath("//video/cbr").should be_empty
|
109
|
+
end
|
110
|
+
|
111
|
+
it "does not include the crop video config when it's null" do
|
112
|
+
medium.configure_video { |c| c.crop = nil }
|
113
|
+
Nokogiri::XML(medium.to_xml).xpath("//video/crop").should be_empty
|
114
|
+
end
|
115
|
+
|
116
|
+
it "does not include the deinterlace video config when it's null" do
|
117
|
+
medium.configure_video { |c| c.deinterlace = nil }
|
118
|
+
Nokogiri::XML(medium.to_xml).xpath("//video/deinterlace").should be_empty
|
119
|
+
end
|
120
|
+
|
121
|
+
it "does not include the framerate video config when it's null" do
|
122
|
+
medium.configure_video { |c| c.framerate = nil }
|
123
|
+
Nokogiri::XML(medium.to_xml).xpath("//video/framerate").should be_empty
|
124
|
+
end
|
125
|
+
|
126
|
+
it "does not include the height video config when it's null" do
|
127
|
+
medium.configure_video { |c| c.height = nil }
|
128
|
+
Nokogiri::XML(medium.to_xml).xpath("//video/height").should be_empty
|
129
|
+
end
|
130
|
+
|
131
|
+
it "does not include the keyframe_interval video config when it's null" do
|
132
|
+
medium.configure_video { |c| c.keyframe_interval = nil }
|
133
|
+
Nokogiri::XML(medium.to_xml).xpath("//video/keyframe_interval").should be_empty
|
134
|
+
end
|
135
|
+
|
136
|
+
it "does not include the maxbitrate video config when it's null" do
|
137
|
+
medium.configure_video { |c| c.maxbitrate = nil }
|
138
|
+
Nokogiri::XML(medium.to_xml).xpath("//video/maxbitrate").should be_empty
|
139
|
+
end
|
140
|
+
|
141
|
+
it "does not include the par video config when it's null" do
|
142
|
+
medium.configure_video { |c| c.par = nil }
|
143
|
+
Nokogiri::XML(medium.to_xml).xpath("//video/par").should be_empty
|
144
|
+
end
|
145
|
+
|
146
|
+
it "does not include the profile video config when it's null" do
|
147
|
+
medium.configure_video { |c| c.profile = nil }
|
148
|
+
Nokogiri::XML(medium.to_xml).xpath("//video/profile").should be_empty
|
149
|
+
end
|
150
|
+
|
151
|
+
it "does not include the passes video config when it's null" do
|
152
|
+
medium.configure_video { |c| c.passes = nil }
|
153
|
+
Nokogiri::XML(medium.to_xml).xpath("//video/passes").should be_empty
|
154
|
+
end
|
155
|
+
|
156
|
+
it "does not include the stretch video config when it's null" do
|
157
|
+
medium.configure_video { |c| c.stretch = nil }
|
158
|
+
Nokogiri::XML(medium.to_xml).xpath("//video/stretch").should be_empty
|
159
|
+
end
|
160
|
+
|
161
|
+
it "does not include the width video config when it's null" do
|
162
|
+
medium.configure_video { |c| c.width = nil }
|
163
|
+
Nokogiri::XML(medium.to_xml).xpath("//video/width").should be_empty
|
164
|
+
end
|
165
|
+
|
166
|
+
it "does not include the stretch video config when it's false" do
|
167
|
+
medium.configure_video { |c| c.stretch = false }
|
168
|
+
Nokogiri::XML(medium.to_xml) .xpath("//video/stretch").should be_empty
|
169
|
+
end
|
170
|
+
|
171
|
+
it "has the correct audio configs" do
|
172
|
+
xml.xpath("//audio/codec").text.should == "aac"
|
173
|
+
xml.xpath("//audio/bitrate").text.should == "15000"
|
174
|
+
xml.xpath("//audio/channels").text.should == "2"
|
175
|
+
xml.xpath("//audio/samplerate").text.should == "10000"
|
176
|
+
end
|
177
|
+
|
178
|
+
it "does not include the bitrate audio config when it's null" do
|
179
|
+
medium.configure_audio { |c| c.bitrate = nil }
|
180
|
+
Nokogiri::XML(medium.to_xml).xpath("//audio/bitrate").should be_empty
|
181
|
+
end
|
182
|
+
|
183
|
+
it "does not include the channels audio config when it's null" do
|
184
|
+
medium.configure_audio { |c| c.channels = nil }
|
185
|
+
Nokogiri::XML(medium.to_xml).xpath("//audio/channels").should be_empty
|
186
|
+
end
|
187
|
+
|
188
|
+
it "does not include the samplerate audio config when it's null" do
|
189
|
+
medium.configure_audio { |c| c.samplerate = nil }
|
190
|
+
Nokogiri::XML(medium.to_xml).xpath("//audio/samplerate").should be_empty
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
describe UEncode::VideoOutput do
|
196
|
+
subject { described_class.new :destination => "http://foobar.com/bla.avi", :container => "mpeg4" }
|
197
|
+
|
198
|
+
its(:destination) { should == "http://foobar.com/bla.avi" }
|
199
|
+
its(:container) { should == "mpeg4" }
|
200
|
+
|
201
|
+
|
202
|
+
describe "#to_xml" do
|
203
|
+
let(:video_output) { described_class.new :destination => "http://foo.com/bar.mp4", :container => "mpeg4" }
|
204
|
+
let(:xml) { Nokogiri::XML video_output.to_xml }
|
205
|
+
|
206
|
+
|
207
|
+
it "has a root element named 'output'" do
|
208
|
+
xml.root.name.should == 'output'
|
209
|
+
end
|
210
|
+
|
211
|
+
it "has the correct destination value" do
|
212
|
+
xml.xpath("//output/video/destination").text.should == "http://foo.com/bar.mp4"
|
213
|
+
end
|
214
|
+
|
215
|
+
it "has the correct container value" do
|
216
|
+
xml.xpath("//output/video/container").text.should == "mpeg4"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe UEncode::CaptureOutput do
|
222
|
+
subject { described_class.new({
|
223
|
+
:destination => "http://whatever.com/foo.jpg",
|
224
|
+
:rate => "at 20s",
|
225
|
+
:stretch => false
|
226
|
+
}) }
|
227
|
+
|
228
|
+
its(:destination) { should == "http://whatever.com/foo.jpg" }
|
229
|
+
its(:rate) { should == "at 20s" }
|
230
|
+
its(:stretch) { should == false }
|
231
|
+
|
232
|
+
context "default values" do
|
233
|
+
let(:capture) { described_class.new :rate => "every 10s" }
|
234
|
+
|
235
|
+
it { capture.stretch.should == false }
|
236
|
+
end
|
237
|
+
|
238
|
+
describe "#to_xml" do
|
239
|
+
let(:crop) { UEncode::Crop.new :width => 125, :height => 140, :x => 100, :y => 200 }
|
240
|
+
let(:size) { UEncode::Size.new :width => 400, :height => 500 }
|
241
|
+
let(:xml) {
|
242
|
+
Nokogiri::XML described_class.new(
|
243
|
+
:destination => "http://foo.com/bla.mp4",
|
244
|
+
:stretch => false,
|
245
|
+
:rate => 'every 10s',
|
246
|
+
:crop => crop,
|
247
|
+
:size => size
|
248
|
+
).to_xml
|
249
|
+
}
|
250
|
+
|
251
|
+
it "has a root element named capture" do
|
252
|
+
xml.root.name.should == 'output'
|
253
|
+
end
|
254
|
+
|
255
|
+
it "has the correct value for the rate attribute" do
|
256
|
+
xml.xpath("//output/capture/rate").text.should == "every 10s"
|
257
|
+
end
|
258
|
+
|
259
|
+
it "has the correct value for the destination attribute" do
|
260
|
+
xml.xpath("//output/capture/destination").text.should == "http://foo.com/bla.mp4"
|
261
|
+
end
|
262
|
+
|
263
|
+
it "has the correct value for the crop attribute" do
|
264
|
+
xml.xpath("//output/capture/crop/width").text.should == "125"
|
265
|
+
xml.xpath("//output/capture/crop/height").text.should == "140"
|
266
|
+
end
|
267
|
+
|
268
|
+
it "has the correct value for the size attribute" do
|
269
|
+
xml.xpath("//output/capture/size/width").text.should == "400"
|
270
|
+
xml.xpath("//output/capture/size/height").text.should == "500"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
describe UEncode::Crop do
|
276
|
+
subject { described_class.new :width => 100, :height => 200, :x => 100, :y => 150 }
|
277
|
+
|
278
|
+
its(:width) { should == 100 }
|
279
|
+
its(:height) { should == 200 }
|
280
|
+
its(:x) { should == 100 }
|
281
|
+
its(:y) { should = 150 }
|
282
|
+
|
283
|
+
describe "#to_xml" do
|
284
|
+
let(:xml) { Nokogiri::XML described_class.new(:width => 100, :height => 200, :x => 100, :y => 150).to_xml }
|
285
|
+
|
286
|
+
it "has a root element named 'crop'" do
|
287
|
+
xml.root.name.should == 'crop'
|
288
|
+
end
|
289
|
+
|
290
|
+
it "has the correct value for the width attribute" do
|
291
|
+
xml.xpath("//width").text.should == "100"
|
292
|
+
end
|
293
|
+
|
294
|
+
it "has the correct value for the height attribute" do
|
295
|
+
xml.xpath("//height").text.should == "200"
|
296
|
+
end
|
297
|
+
|
298
|
+
it "has the correct value for the x attribute" do
|
299
|
+
xml.xpath("//x").text.should == "100"
|
300
|
+
end
|
301
|
+
|
302
|
+
it "has the correct value for the y attribute" do
|
303
|
+
xml.xpath("//y").text.should == "150"
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
shared_examples_for "an element that represents a rate number" do
|
309
|
+
subject { described_class.new :numerator => numerator, :denominator => denominator }
|
310
|
+
|
311
|
+
its(:numerator) { should == numerator }
|
312
|
+
its(:denominator) { should == denominator }
|
313
|
+
|
314
|
+
describe "#to_xml" do
|
315
|
+
let(:xml) { Nokogiri::XML described_class.new(:numerator => numerator, :denominator => denominator).to_xml }
|
316
|
+
|
317
|
+
it "has a root element named '#{name}'" do
|
318
|
+
xml.root.name.should == name
|
319
|
+
end
|
320
|
+
|
321
|
+
it "has the correct value for the numerator attribute" do
|
322
|
+
xml.xpath("//numerator").text.should == numerator.to_s
|
323
|
+
end
|
324
|
+
|
325
|
+
it "has the correct value for the denominator attribute" do
|
326
|
+
xml.xpath("//denominator").text.should == denominator.to_s
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
describe UEncode::FrameRate do
|
332
|
+
let(:name) { "framerate" }
|
333
|
+
let(:numerator) { 1000 }
|
334
|
+
let(:denominator) { 1001 }
|
335
|
+
|
336
|
+
it_should_behave_like "an element that represents a rate number"
|
337
|
+
end
|
338
|
+
|
339
|
+
describe UEncode::Par do
|
340
|
+
let(:name) { "par" }
|
341
|
+
let(:numerator) { 10 }
|
342
|
+
let(:denominator) { 11 }
|
343
|
+
|
344
|
+
it_should_behave_like "an element that represents a rate number"
|
345
|
+
end
|
346
|
+
|
347
|
+
describe UEncode::Size do
|
348
|
+
subject { described_class.new :width => 100, :height => 200 }
|
349
|
+
|
350
|
+
its(:height) { should == 200 }
|
351
|
+
its(:width) { should == 100 }
|
352
|
+
|
353
|
+
describe "#to_xml" do
|
354
|
+
let(:xml) { Nokogiri::XML described_class.new(:width => 200, :height => 250).to_xml }
|
355
|
+
|
356
|
+
it "has a root element named 'size'" do
|
357
|
+
xml.root.name.should == 'size'
|
358
|
+
end
|
359
|
+
|
360
|
+
it "has the correct value for the width attribute" do
|
361
|
+
xml.xpath("//width").text.should == "200"
|
362
|
+
end
|
363
|
+
|
364
|
+
it "has the correct value for the height attribute" do
|
365
|
+
xml.xpath("//height").text.should == "250"
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
describe UEncode::Job do
|
371
|
+
subject { described_class.new :source => "http://foo.com/bar.avi", :userdata => "some text", :notify => "http://my_url.com" }
|
372
|
+
|
373
|
+
its(:source) { should == "http://foo.com/bar.avi" }
|
374
|
+
its(:userdata) { should == "some text" }
|
375
|
+
its(:notify) { should == "http://my_url.com" }
|
376
|
+
its(:items) { should == [] }
|
377
|
+
|
378
|
+
describe "#<<" do
|
379
|
+
it "adds new elements to items" do
|
380
|
+
subject << "foo"
|
381
|
+
subject.items.should == ["foo"]
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
it "is enumerable" do
|
386
|
+
subject << "foo"
|
387
|
+
subject << "bar"
|
388
|
+
subject.map { |item| item }.should == ["foo", "bar"]
|
389
|
+
end
|
390
|
+
|
391
|
+
describe "#to_xml" do
|
392
|
+
let(:job) { UEncode::Job.new({
|
393
|
+
:customerkey => "0123456789",
|
394
|
+
:source => "http://whatever.com/foo.avi",
|
395
|
+
:userdata => "some text",
|
396
|
+
:notify => "http://notify.me/meh"
|
397
|
+
})}
|
398
|
+
|
399
|
+
let(:xml) { Nokogiri::XML job.to_xml }
|
400
|
+
|
401
|
+
before :each do
|
402
|
+
video1 = UEncode::Medium.new
|
403
|
+
video1.configure_video do |c|
|
404
|
+
c.bitrate = 1000
|
405
|
+
c.codec = 'mp4'
|
406
|
+
end
|
407
|
+
video1.configure_audio do |c|
|
408
|
+
c.codec = 'aac'
|
409
|
+
end
|
410
|
+
video2 = UEncode::Medium.new
|
411
|
+
video2.configure_video do |c|
|
412
|
+
c.bitrate = 1500
|
413
|
+
c.codec = 'mpeg2'
|
414
|
+
end
|
415
|
+
video2.configure_audio do |c|
|
416
|
+
c.codec = 'passthru'
|
417
|
+
end
|
418
|
+
job << video1
|
419
|
+
job << video2
|
420
|
+
|
421
|
+
job.configure_video_output do |c|
|
422
|
+
c.destination = "http://whatever.com/foo1.mp4"
|
423
|
+
c.container = "mpeg4"
|
424
|
+
end
|
425
|
+
|
426
|
+
capture1 = UEncode::CaptureOutput.new :destination => "http://whatever.com/foo.zip", :rate => "every 30s"
|
427
|
+
job.add_capture capture1
|
428
|
+
capture2 = UEncode::CaptureOutput.new :destination => "http://whatever.com/bar.zip", :rate => "every 10s"
|
429
|
+
job.add_capture capture2
|
430
|
+
end
|
431
|
+
|
432
|
+
it "has a root element named 'job'" do
|
433
|
+
xml.root.name.should == 'job'
|
434
|
+
end
|
435
|
+
|
436
|
+
it "has the correct customer key value" do
|
437
|
+
xml.xpath("//job/customerkey").text.should == "1q2w3e4r5t"
|
438
|
+
end
|
439
|
+
|
440
|
+
it "has the correct source attribute" do
|
441
|
+
xml.xpath("//job/source").text.should == "http://whatever.com/foo.avi"
|
442
|
+
end
|
443
|
+
|
444
|
+
it "has the correct user data value" do
|
445
|
+
xml.xpath("//job/userdata").text.should == 'some text'
|
446
|
+
end
|
447
|
+
|
448
|
+
it "has the correct notify value" do
|
449
|
+
xml.xpath("//job/notify").text.should == "http://notify.me/meh"
|
450
|
+
end
|
451
|
+
|
452
|
+
it "does not include the userdata attribute when it's null" do
|
453
|
+
job.instance_variable_set :@userdata, nil
|
454
|
+
xml.xpath("//job/userdata").should be_empty
|
455
|
+
end
|
456
|
+
|
457
|
+
it "does not include the notify attribute when it's null" do
|
458
|
+
job.instance_variable_set :@notify, nil
|
459
|
+
xml.xpath("//job/notify").should be_empty
|
460
|
+
end
|
461
|
+
|
462
|
+
it "contains the correct content to represent each video output item" do
|
463
|
+
xml.xpath("//job/outputs/output/video/media/medium").length.should == 2
|
464
|
+
end
|
465
|
+
|
466
|
+
it "has the correct video output destination" do
|
467
|
+
xml.xpath("//job/outputs/output/video/destination").text.should == "http://whatever.com/foo1.mp4"
|
468
|
+
end
|
469
|
+
|
470
|
+
it "has the correct video output container" do
|
471
|
+
xml.xpath("//job/outputs/output/video/container").text.should == "mpeg4"
|
472
|
+
end
|
473
|
+
|
474
|
+
it "contains the correct content to represent the video captures" do
|
475
|
+
xml.xpath("//job/outputs/output/capture").length.should == 2
|
476
|
+
end
|
477
|
+
end
|
478
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
---
|
2
|
+
- !ruby/struct:VCR::HTTPInteraction
|
3
|
+
request: !ruby/struct:VCR::Request
|
4
|
+
method: :put
|
5
|
+
uri: https://www.uencode.com:443/jobs?version=300
|
6
|
+
body: |
|
7
|
+
<?xml version="1.0"?>
|
8
|
+
<job>
|
9
|
+
<customerkey>1q2w3e4r5t</customerkey>
|
10
|
+
<source>http://dailydigital-files.s3.amazonaws.com/staging/3/iphone.mp4</source>
|
11
|
+
<userdata>This is a simple test</userdata>
|
12
|
+
|
13
|
+
<outputs>
|
14
|
+
|
15
|
+
<output>
|
16
|
+
<video>
|
17
|
+
<destination>http://dailydigital-files.s3.amazonaws.com/staging/3/iphone_transcoded.mp4</destination>
|
18
|
+
<container>mpeg4</container>
|
19
|
+
<media>
|
20
|
+
|
21
|
+
<medium>
|
22
|
+
<video>
|
23
|
+
<bitrate>300000</bitrate>
|
24
|
+
<codec>h264</codec>
|
25
|
+
<cbr>false</cbr>
|
26
|
+
|
27
|
+
<deinterlace>false</deinterlace>
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
<profile>main</profile>
|
34
|
+
<passes>1</passes>
|
35
|
+
|
36
|
+
|
37
|
+
</video>
|
38
|
+
<audio>
|
39
|
+
<codec>aac</codec>
|
40
|
+
<bitrate>64000</bitrate>
|
41
|
+
<channels>1</channels>
|
42
|
+
<samplerate>44100</samplerate>
|
43
|
+
</audio>
|
44
|
+
</medium>
|
45
|
+
|
46
|
+
</media>
|
47
|
+
</video>
|
48
|
+
</output>
|
49
|
+
|
50
|
+
|
51
|
+
</outputs>
|
52
|
+
</job>
|
53
|
+
|
54
|
+
headers:
|
55
|
+
response: !ruby/struct:VCR::Response
|
56
|
+
status: !ruby/struct:VCR::ResponseStatus
|
57
|
+
code: 200
|
58
|
+
message: OK
|
59
|
+
headers:
|
60
|
+
date:
|
61
|
+
- Wed, 18 May 2011 21:25:41 GMT
|
62
|
+
server:
|
63
|
+
- Apache/2.2.16 (Ubuntu)
|
64
|
+
etag:
|
65
|
+
- "\"1c1e90e26e3f60eeb74014a6aeb5ac22\""
|
66
|
+
cache-control:
|
67
|
+
- max-age=0, private, must-revalidate
|
68
|
+
x-ua-compatible:
|
69
|
+
- IE=Edge,chrome=1
|
70
|
+
set-cookie:
|
71
|
+
- _uencode_api_session=BAh7BiIPc2Vzc2lvbl9pZCIlOWM4ZWM4ZGUxMzNiNTNiNWZiOWMwMDA4ODkzMmY3ZWI%3D--697ce08be3ca2a9f6347474fe7fe5476333e9408; path=/; HttpOnly
|
72
|
+
x-runtime:
|
73
|
+
- "1.007000"
|
74
|
+
content-length:
|
75
|
+
- "202"
|
76
|
+
content-type:
|
77
|
+
- application/xml;charset=utf-8
|
78
|
+
body: |
|
79
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
80
|
+
<response>
|
81
|
+
<code>Ok</code>
|
82
|
+
<jobid>6068</jobid>
|
83
|
+
<message>You job was created successfully.</message>
|
84
|
+
<userdata>This is a simple test</userdata>
|
85
|
+
</response>
|
86
|
+
|
87
|
+
http_version: "1.1"
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe UEncode::Request do
|
4
|
+
context "being created" do
|
5
|
+
let(:job) { UEncode::Job.new :source => "http://whatever.com/foo/avi" }
|
6
|
+
let(:request) { UEncode::Request.new job }
|
7
|
+
|
8
|
+
it "initializes the job attribute" do
|
9
|
+
request.instance_variable_get(:@job).should == job
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#send" do
|
14
|
+
let(:job) { UEncode::Job.new :source => "http://dailydigital-files.s3.amazonaws.com/staging/3/iphone.mp4", :userdata => "This is a simple test" }
|
15
|
+
let(:request) { UEncode::Request.new job }
|
16
|
+
|
17
|
+
before :each do
|
18
|
+
job.configure_video_output do |c|
|
19
|
+
c.destination = "http://dailydigital-files.s3.amazonaws.com/staging/3/iphone_transcoded.mp4"
|
20
|
+
c.container = "mpeg4"
|
21
|
+
end
|
22
|
+
video1 = UEncode::Medium.new
|
23
|
+
video1.configure_video { |c| c.bitrate = 300000; c.codec = "h264"}
|
24
|
+
video1.configure_audio do |c|
|
25
|
+
c.bitrate = 64000
|
26
|
+
c.codec = "aac"
|
27
|
+
c.samplerate = 44100
|
28
|
+
c.channels = 1
|
29
|
+
end
|
30
|
+
job << video1
|
31
|
+
end
|
32
|
+
|
33
|
+
around :each do |example|
|
34
|
+
VCR.use_cassette "job_with_one_video_and_no_capture", &example
|
35
|
+
end
|
36
|
+
|
37
|
+
it "returns a response containing the jobid" do
|
38
|
+
request.send.jobid.should =~ /\A\d+\z/
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns a response containing a code" do
|
42
|
+
request.send.code.should == 'Ok'
|
43
|
+
end
|
44
|
+
|
45
|
+
it "returns a response containing the previously sent user data" do
|
46
|
+
request.send.userdata.should == "This is a simple test"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "returns a response containing a message" do
|
50
|
+
request.send.message.should == "You job was created successfully."
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe UEncode::Response do
|
4
|
+
context "errors" do
|
5
|
+
let(:response) { UEncode::Response.new :code => code, :message => "whatever" }
|
6
|
+
|
7
|
+
context "when initialized with a 'BadRequest' code" do
|
8
|
+
let(:code) { 'BadRequest' }
|
9
|
+
|
10
|
+
it "raises a UEncode::Response::BadRequestError error containing the error message" do
|
11
|
+
expect { response }.to raise_error(UEncode::Response::BadRequestError, "whatever")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when initialized with a 'InvalidKey' code" do
|
16
|
+
let(:code) { 'InvalidKey' }
|
17
|
+
|
18
|
+
it "raises a UEncode::Response::InvalidKeyError containing the error message" do
|
19
|
+
expect { response }.to raise_error(UEncode::Response::InvalidKeyError, "whatever")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when initialized with a 'NotActive' code" do
|
24
|
+
let(:code) { 'NotActive' }
|
25
|
+
|
26
|
+
it "raises a UEncode::Response::NotActiveError containing the error message" do
|
27
|
+
expect { response }.to raise_error(UEncode::Response::NotActiveError, "whatever")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when initialized with a 'ServerError' code" do
|
32
|
+
let(:code) { 'ServerError' }
|
33
|
+
|
34
|
+
it "raises a UEncode::Response::ServerError containing the error message" do
|
35
|
+
expect { response }.to raise_error(UEncode::Response::ServerError, "whatever")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "when initialized with an unknown code" do
|
40
|
+
let(:code) { 'Ffffuuuuu' }
|
41
|
+
|
42
|
+
it "raises a UEncode::Response::UnknownError containing the error code and the error message" do
|
43
|
+
expect { response }.to raise_error(UEncode::Response::UnknownError, "Ffffuuuuu: whatever")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'uencode'
|
2
|
+
require 'rspec'
|
3
|
+
require 'rspec/autorun'
|
4
|
+
require "vcr"
|
5
|
+
|
6
|
+
|
7
|
+
VCR.config do |c|
|
8
|
+
library_dir = File.join(File.dirname(__FILE__), 'fixtures/')
|
9
|
+
c.cassette_library_dir = library_dir
|
10
|
+
c.stub_with :webmock
|
11
|
+
c.allow_http_connections_when_no_cassette = false
|
12
|
+
c.ignore_localhost = true
|
13
|
+
end
|
14
|
+
|
15
|
+
UEncode.configure do |c|
|
16
|
+
c.customer_key = "1q2w3e4r5t"
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
|
6
|
+
describe UEncode do
|
7
|
+
it "has a customer_key configuration parameter" do
|
8
|
+
UEncode.configure do |c|
|
9
|
+
c.customer_key = "1234567890"
|
10
|
+
end
|
11
|
+
UEncode.customer_key.should == "1234567890"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
data/uencode.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "uencode/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "uencode"
|
7
|
+
s.version = UEncode::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Cássio Marques"]
|
10
|
+
s.email = ["cassiommc@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/cassiomarques/uencode"
|
12
|
+
s.summary = %q{Simple UEncode API client written in Ruby}
|
13
|
+
s.description = %q{UEncode API client}
|
14
|
+
|
15
|
+
s.rubyforge_project = "uencode"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_development_dependency "rspec", "2.6.0"
|
23
|
+
s.add_development_dependency "vcr", "1.9.0"
|
24
|
+
s.add_development_dependency "guard"
|
25
|
+
s.add_development_dependency "guard-rspec"
|
26
|
+
s.add_development_dependency "growl"
|
27
|
+
s.add_development_dependency "rb-fsevent"
|
28
|
+
s.add_development_dependency "webmock"
|
29
|
+
|
30
|
+
s.add_dependency "nokogiri", "1.4.4"
|
31
|
+
s.add_dependency "httparty"
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: uencode
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- "C\xC3\xA1ssio Marques"
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-05-18 00:00:00 -03:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rspec
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - "="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 2.6.0
|
25
|
+
type: :development
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: vcr
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - "="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 1.9.0
|
36
|
+
type: :development
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: guard
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: guard-rspec
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: growl
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
type: :development
|
70
|
+
version_requirements: *id005
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: rb-fsevent
|
73
|
+
prerelease: false
|
74
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0"
|
80
|
+
type: :development
|
81
|
+
version_requirements: *id006
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: webmock
|
84
|
+
prerelease: false
|
85
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: "0"
|
91
|
+
type: :development
|
92
|
+
version_requirements: *id007
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: nokogiri
|
95
|
+
prerelease: false
|
96
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - "="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.4.4
|
102
|
+
type: :runtime
|
103
|
+
version_requirements: *id008
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: httparty
|
106
|
+
prerelease: false
|
107
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: "0"
|
113
|
+
type: :runtime
|
114
|
+
version_requirements: *id009
|
115
|
+
description: UEncode API client
|
116
|
+
email:
|
117
|
+
- cassiommc@gmail.com
|
118
|
+
executables: []
|
119
|
+
|
120
|
+
extensions: []
|
121
|
+
|
122
|
+
extra_rdoc_files: []
|
123
|
+
|
124
|
+
files:
|
125
|
+
- .autotest
|
126
|
+
- .gitignore
|
127
|
+
- Gemfile
|
128
|
+
- Guardfile
|
129
|
+
- README.md
|
130
|
+
- Rakefile
|
131
|
+
- lib/uencode.rb
|
132
|
+
- lib/uencode/elements.rb
|
133
|
+
- lib/uencode/request.rb
|
134
|
+
- lib/uencode/response.rb
|
135
|
+
- lib/uencode/version.rb
|
136
|
+
- spec/elements_spec.rb
|
137
|
+
- spec/fixtures/job_with_one_video_and_no_capture.yml
|
138
|
+
- spec/request_spec.rb
|
139
|
+
- spec/response_spec.rb
|
140
|
+
- spec/spec_helper.rb
|
141
|
+
- spec/uencode_spec.rb
|
142
|
+
- uencode.gemspec
|
143
|
+
has_rdoc: true
|
144
|
+
homepage: http://github.com/cassiomarques/uencode
|
145
|
+
licenses: []
|
146
|
+
|
147
|
+
post_install_message:
|
148
|
+
rdoc_options: []
|
149
|
+
|
150
|
+
require_paths:
|
151
|
+
- lib
|
152
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: "0"
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
|
+
none: false
|
160
|
+
requirements:
|
161
|
+
- - ">="
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: "0"
|
164
|
+
requirements: []
|
165
|
+
|
166
|
+
rubyforge_project: uencode
|
167
|
+
rubygems_version: 1.6.2
|
168
|
+
signing_key:
|
169
|
+
specification_version: 3
|
170
|
+
summary: Simple UEncode API client written in Ruby
|
171
|
+
test_files:
|
172
|
+
- spec/elements_spec.rb
|
173
|
+
- spec/fixtures/job_with_one_video_and_no_capture.yml
|
174
|
+
- spec/request_spec.rb
|
175
|
+
- spec/response_spec.rb
|
176
|
+
- spec/spec_helper.rb
|
177
|
+
- spec/uencode_spec.rb
|