uencode 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|