convertr 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/convertr.gemspec +2 -2
- data/lib/convertr/convertor.rb +64 -44
- data/lib/convertr/migration.rb +4 -4
- data/lib/convertr/scheduler.rb +1 -1
- data/lib/convertr/scheduler/all_bt_first.rb +2 -2
- data/lib/convertr/task.rb +1 -0
- data/test/fixtures/files.yml +1 -1
- data/test/settings.yml +1 -0
- data/test/test_convertor.rb +172 -12
- data/test/test_file.rb +0 -2
- data/test/test_scheduler.rb +18 -0
- data/test/test_scheduler_allbtfirst.rb +1 -1
- data/test/test_task.rb +3 -0
- metadata +3 -3
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/convertr.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{convertr}
|
8
|
-
s.version = "0.0
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Ilya Lityuga", "Alexander Svetkin"]
|
12
|
-
s.date = %q{2010-10-
|
12
|
+
s.date = %q{2010-10-14}
|
13
13
|
s.default_executable = %q{convertr}
|
14
14
|
s.description = %q{Convertr works with database and handles converting tasks. It fetches files from remote sources and converts them to appropriate formats with ffmpeg}
|
15
15
|
s.email = %q{ilya.lityuga@gmail.com}
|
data/lib/convertr/convertor.rb
CHANGED
@@ -21,7 +21,7 @@ module Convertr
|
|
21
21
|
CONVERTOR_PAUSE_DELAY = 120
|
22
22
|
CONVERTOR_MAX_FETCH_TIME = 600
|
23
23
|
|
24
|
-
attr_accessor :scheduler, :max_tasks, :hostname, :initial_dir, :file, :task, :
|
24
|
+
attr_accessor :scheduler, :max_tasks, :hostname, :initial_dir, :file, :task, :tasks, :logger
|
25
25
|
|
26
26
|
def initialize(max_tasks = 0, scheduler = nil) # инициализация конертера {{{
|
27
27
|
@max_tasks = max_tasks
|
@@ -37,11 +37,11 @@ module Convertr
|
|
37
37
|
loop do
|
38
38
|
break if File.exists? CONVERTOR_STOPFILE
|
39
39
|
if !File.exists?(CONVERTOR_PAUSEFILE) and @task = @scheduler.schedule_next_task(@hostname)
|
40
|
-
task.update_attributes(
|
40
|
+
@task.update_attributes(
|
41
41
|
:convert_status => process_task,
|
42
42
|
:convert_stopped_at => Time.now
|
43
43
|
)
|
44
|
-
break if @max_tasks > 0 && (@tasks += 1)
|
44
|
+
break if @max_tasks > 0 && (@tasks += 1) >= @max_tasks
|
45
45
|
else
|
46
46
|
sleep(CONVERTOR_PAUSE_DELAY) && next
|
47
47
|
end
|
@@ -52,19 +52,17 @@ module Convertr
|
|
52
52
|
|
53
53
|
def process_task # выполнение конкретной задачи на конвертацию {{{
|
54
54
|
@file = @task.file
|
55
|
-
@
|
56
|
-
@working_dir = File.join( File.dirname(@file_path), File.filename(@filepath) )
|
57
|
-
@logger.info("Started #@filepath")
|
55
|
+
@logger.info("Started #{original_file}")
|
58
56
|
begin
|
59
|
-
fetch_file(@file.
|
60
|
-
FileUtils.cd
|
57
|
+
fetch_file(@file.location, @file.filename)
|
58
|
+
FileUtils.cd indir
|
61
59
|
process_profile(profile_by_bitrate(@task.bitrate))
|
62
60
|
if @task.bitrate == 600
|
63
61
|
count = calc_thumbnails_count(@file.duration)
|
64
62
|
interval = (@file.duration / count).to_i
|
65
|
-
system(make_thumbnails_cmd(count, interval, 150,
|
63
|
+
system(make_thumbnails_cmd(count, interval, 150, nil, 2)) or raise "thumbnails generation failed #{$?}"
|
66
64
|
end
|
67
|
-
@logger.info("Done
|
65
|
+
@logger.info("Done #{original_file}")
|
68
66
|
rescue StandardError => e
|
69
67
|
@logger.error e.message
|
70
68
|
return 'FAILURE'
|
@@ -75,13 +73,12 @@ module Convertr
|
|
75
73
|
end # }}}
|
76
74
|
|
77
75
|
def fetch_file(source_url, filename) # скачивание файла по FTP {{{
|
78
|
-
FileUtils.mkpath(
|
79
|
-
|
80
|
-
tmp_file = dst_file + ".part"
|
76
|
+
FileUtils.mkpath(indir)
|
77
|
+
tmp_file = work_name + ".part"
|
81
78
|
started_at = Time.now
|
82
79
|
loop do
|
83
|
-
return if File.exists?
|
84
|
-
if File.exists? tmp_file
|
80
|
+
return if ::File.exists? original_file
|
81
|
+
if ::File.exists? tmp_file
|
85
82
|
sleep(CONVERTOR_PAUSE_DELAY)
|
86
83
|
if Time.now > started_at + CONVERTOR_MAX_FETCH_TIME
|
87
84
|
FileUtils.rm_f tmp_file
|
@@ -94,18 +91,17 @@ module Convertr
|
|
94
91
|
end
|
95
92
|
|
96
93
|
url = URI.parse(source_url)
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
94
|
+
Net::FTP.open(url.host) do |ftp|
|
95
|
+
begin
|
96
|
+
ftp.login(@conf.ftp_user, @conf.ftp_pass)
|
97
|
+
ftp.getbinaryfile(url.path, tmp_file, 1024)
|
98
|
+
rescue StandardError => e
|
99
|
+
FileUtils.rm_f tmp_file
|
100
|
+
raise e
|
101
|
+
end
|
105
102
|
end
|
106
|
-
ftp.close
|
107
103
|
|
108
|
-
FileUtils.
|
104
|
+
FileUtils.move tmp_file, original_file
|
109
105
|
end # }}}
|
110
106
|
|
111
107
|
def profile_by_bitrate(bitrate) # bitrate -> profile {{{
|
@@ -120,37 +116,35 @@ module Convertr
|
|
120
116
|
|
121
117
|
def process_profile(pname) # конвертация, согласно профилю # {{{
|
122
118
|
profile = @conf.enc_profiles[pname]
|
123
|
-
outfile =
|
124
|
-
|
125
|
-
output_dir = File.join(@conf.output_dir, @working_dir)
|
126
|
-
FileUtils.mkpath output_dir unless File.exists? output_dir
|
127
|
-
FileUtils.chdir output_dir
|
128
|
-
FileUtils.mkdir pname unless File.exists? pname
|
129
|
-
FileUtils.chdir pname
|
119
|
+
outfile = filename_with_suffix("-#{pname}-0.mp4") # => z-sd-0.mp4
|
120
|
+
FileUtils.mkdir(pname) && FileUtils.chdir(pname)
|
130
121
|
|
131
122
|
@conf.enc_pass.each_with_index do |enc_pass_params, i|
|
132
|
-
cmd = mkcmd(enc_pass_params, pname,
|
123
|
+
cmd = mkcmd(enc_pass_params, pname, original_file, i == 0 ? '/dev/null' : outfile, @file.aspect)
|
133
124
|
@logger.info(cmd)
|
134
125
|
system(cmd) or raise "system #{cmd} failed: #{$?}"
|
135
126
|
end
|
136
127
|
|
137
|
-
outfile2 =
|
138
|
-
cmd = "#{@
|
128
|
+
outfile2 = filename_with_suffix("-#{pname}.mp4") # => z-sd.mp4
|
129
|
+
cmd = "#{@conf.qtfaststart} #{outfile} #{outfile2}"
|
139
130
|
system(cmd) or FileUtils.rm_f(outfile) && raise("system #{cmd} failed: #{$?}")
|
131
|
+
FileUtils.rm_f(outfile)
|
132
|
+
FileUtils.mkpath outdir # => /var/x/y
|
133
|
+
FileUtils.move outfile2, outdir
|
140
134
|
FileUtils.cd '..'
|
141
135
|
FileUtils.rm_rf pname
|
142
136
|
end # }}}
|
143
137
|
|
144
138
|
def make_thumbnails_cmd(count, interval, w, h, postfix) # генерация тумбнейлов {{{
|
145
|
-
|
146
|
-
|
139
|
+
file = task.file
|
140
|
+
w = (h * file.float_aspect).to_i if h && w.nil?
|
141
|
+
h = (w / file.float_aspect).to_i if file.aspect && w && h.nil?
|
147
142
|
tstamps = (1..count).collect {|i| i * interval}
|
148
143
|
params = ''
|
149
|
-
params += ' -c 20 ' if
|
150
|
-
params += ' -d ' if
|
151
|
-
|
152
|
-
pattern
|
153
|
-
"#{@conf.tmaker} -i #{infile} #{params} -w #{w} -h #{h} -o #{output_dir} #{tstamps.join(' ')}"
|
144
|
+
params += ' -c 20 ' if task.crop?
|
145
|
+
params += ' -d ' if task.deinterlace?
|
146
|
+
pattern = filename_with_suffix("-%d-#{postfix}.jpg")
|
147
|
+
"#{@conf.tmaker} -i #{original_file} #{params} -w #{w} -h #{h} -o \"#{outdir}/#{pattern}\" #{tstamps.join(' ')}"
|
154
148
|
end # }}}
|
155
149
|
|
156
150
|
def mkcmd(enc_pass, pname, infile, outfile, aspect) # подготовка команды на конвертацию {{{
|
@@ -173,10 +167,10 @@ module Convertr
|
|
173
167
|
(params['croptop'], params['cropbottom'], params['cropleft'], params['cropright']) =
|
174
168
|
case aspect
|
175
169
|
when '16:9'
|
176
|
-
w += 32
|
170
|
+
w += 32 ; h += 18
|
177
171
|
[10, 8, 16, 16]
|
178
172
|
else # '4:3', '5:3' etc
|
179
|
-
w += 32
|
173
|
+
w += 32 ; h += 24
|
180
174
|
[20, 4, 16, 16]
|
181
175
|
end
|
182
176
|
end
|
@@ -195,5 +189,31 @@ module Convertr
|
|
195
189
|
else 24
|
196
190
|
end
|
197
191
|
end # }}}
|
192
|
+
|
193
|
+
# тут чёрт ногу сломит с этими картами директорий
|
194
|
+
# /tmp/test.avi
|
195
|
+
def original_file
|
196
|
+
::File.join(@conf.tmp_dir, ::File.basename(@file.filename))
|
197
|
+
end
|
198
|
+
|
199
|
+
# /tmp/test
|
200
|
+
def indir
|
201
|
+
::File.join(@conf.tmp_dir, ::File.filename(@file.filename))
|
202
|
+
end
|
203
|
+
|
204
|
+
# /tmp/test/test
|
205
|
+
def work_name
|
206
|
+
::File.join(@conf.tmp_dir, ::File.filename(@file.filename), ::File.filename(@file.filename))
|
207
|
+
end
|
208
|
+
|
209
|
+
# test + suffix
|
210
|
+
def filename_with_suffix(suffix)
|
211
|
+
::File.filename(@file.filename) + suffix
|
212
|
+
end
|
213
|
+
|
214
|
+
# /var/x/y
|
215
|
+
def outdir
|
216
|
+
::File.join(@conf.output_dir, ::File.dirname(@file.filename))
|
217
|
+
end
|
198
218
|
end
|
199
219
|
end
|
data/lib/convertr/migration.rb
CHANGED
@@ -20,11 +20,11 @@ module Convertr
|
|
20
20
|
t.integer :file_id
|
21
21
|
t.integer :bitrate
|
22
22
|
t.string :convert_status, :limit => 20
|
23
|
-
t.
|
24
|
-
t.
|
23
|
+
t.datetime :convert_started_at
|
24
|
+
t.datetime :convert_stopped_at
|
25
25
|
t.string :copy_status, :limit => 20
|
26
|
-
t.
|
27
|
-
t.
|
26
|
+
t.datetime :copy_started_at
|
27
|
+
t.datetime :copy_stopped_at
|
28
28
|
t.boolean :crop
|
29
29
|
t.boolean :deinterlace
|
30
30
|
end
|
data/lib/convertr/scheduler.rb
CHANGED
@@ -21,7 +21,7 @@ module Convertr
|
|
21
21
|
def schedule(task, convertor)
|
22
22
|
Convertr::Task.transaction do
|
23
23
|
task.update_attributes(:convert_status => 'PROGRESS', :convert_started_at => Time.now)
|
24
|
-
task.file.update_attribute(:convertor
|
24
|
+
task.file.update_attribute(:convertor, convertor)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -2,8 +2,8 @@ module Convertr
|
|
2
2
|
module Scheduler
|
3
3
|
class AllBtFirst < Base
|
4
4
|
def get_task_for_schedule(convertor)
|
5
|
-
Convertr::Task.for_convertor(convertor).first
|
6
|
-
|
5
|
+
Convertr::Task.for_convertor(convertor).first ||
|
6
|
+
Convertr::Task.without_convertor.first
|
7
7
|
end
|
8
8
|
end
|
9
9
|
end
|
data/lib/convertr/task.rb
CHANGED
@@ -6,5 +6,6 @@ module Convertr
|
|
6
6
|
scope :for_convertor, lambda { |convertor|
|
7
7
|
not_completed.includes(:file).where('files.convertor' => convertor).order('files.broadcast_at asc')
|
8
8
|
}
|
9
|
+
scope :without_convertor, not_completed.includes(:file).where('files.convertor is null').order('files.broadcast_at asc')
|
9
10
|
end
|
10
11
|
end
|
data/test/fixtures/files.yml
CHANGED
data/test/settings.yml
CHANGED
data/test/test_convertor.rb
CHANGED
@@ -6,13 +6,18 @@ class TestConvertor < Test::Unit::TestCase
|
|
6
6
|
@convertor = Convertr::Convertor.new
|
7
7
|
end
|
8
8
|
|
9
|
-
should "be able to calculate thumbnails count" do
|
10
|
-
assert_equal 3, @convertor.instance_eval
|
11
|
-
assert_equal 6, @convertor.instance_eval
|
12
|
-
assert_equal 9, @convertor.instance_eval
|
9
|
+
should "be able to calculate thumbnails count" do # {{{
|
10
|
+
assert_equal 3, @convertor.instance_eval { calc_thumbnails_count(600) }
|
11
|
+
assert_equal 6, @convertor.instance_eval { calc_thumbnails_count(1200) }
|
12
|
+
assert_equal 9, @convertor.instance_eval { calc_thumbnails_count(1800) }
|
13
|
+
assert_equal 12, @convertor.instance_eval { calc_thumbnails_count(2400) }
|
14
|
+
assert_equal 15, @convertor.instance_eval { calc_thumbnails_count(3000) }
|
15
|
+
assert_equal 18, @convertor.instance_eval { calc_thumbnails_count(3600) }
|
16
|
+
assert_equal 21, @convertor.instance_eval { calc_thumbnails_count(3700) }
|
17
|
+
assert_equal 24, @convertor.instance_eval { calc_thumbnails_count(4260) }
|
13
18
|
end
|
14
|
-
|
15
|
-
should "find the right profile by bitrate" do
|
19
|
+
# }}}
|
20
|
+
should "find the right profile by bitrate" do # {{{
|
16
21
|
assert_equal 'sd', @convertor.instance_eval("profile_by_bitrate(300)")
|
17
22
|
assert_equal 'hd', @convertor.instance_eval("profile_by_bitrate(600)")
|
18
23
|
assert_equal 'hdp', @convertor.instance_eval("profile_by_bitrate(1000)")
|
@@ -20,14 +25,14 @@ class TestConvertor < Test::Unit::TestCase
|
|
20
25
|
@convertor.instance_eval("profile_by_bitrate(1234)")
|
21
26
|
end
|
22
27
|
end
|
23
|
-
|
24
|
-
context "for some task with crop and deinterlace" do
|
28
|
+
# }}}
|
29
|
+
context "for some task with crop and deinterlace" do # should prepare valid shell command for ffmpeg {{{
|
25
30
|
setup do
|
26
31
|
task = Factory.create(:task, :bitrate => 600, :crop => true, :deinterlace => true)
|
27
32
|
@convertor.stubs(:task).returns(task)
|
28
33
|
end
|
29
34
|
should "prepare valid command for ffmpeg" do
|
30
|
-
assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s
|
35
|
+
assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s 736x414 -ab 64k -ac 1 -acodec libfaac -ar 44100 -b 236k -bt 236k -cropbottom 8 -cropleft 16 -cropright 16 -croptop 10 -deinterlace -pass 2 -threads 3 -vcodec libx264 -vpre hq-flash outfile.mpg',
|
31
36
|
@convertor.instance_eval { mkcmd({'vpre' => 'hq-flash', 'pass' => 2}, 'sd', 'infile.avi', 'outfile.mpg', '16:9') }
|
32
37
|
end
|
33
38
|
end
|
@@ -38,7 +43,7 @@ class TestConvertor < Test::Unit::TestCase
|
|
38
43
|
@convertor.stubs(:task).returns(task)
|
39
44
|
end
|
40
45
|
should "prepare valid command for ffmpeg" do
|
41
|
-
assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s
|
46
|
+
assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s 736x414 -ab 64k -ac 1 -acodec libfaac -ar 44100 -b 236k -bt 236k -cropbottom 8 -cropleft 16 -cropright 16 -croptop 10 -pass 2 -threads 3 -vcodec libx264 -vpre hq-flash outfile.mpg',
|
42
47
|
@convertor.instance_eval { mkcmd({'vpre' => 'hq-flash', 'pass' => 2}, 'sd', 'infile.avi', 'outfile.mpg', '16:9') }
|
43
48
|
end
|
44
49
|
end
|
@@ -49,9 +54,164 @@ class TestConvertor < Test::Unit::TestCase
|
|
49
54
|
@convertor.stubs(:task).returns(task)
|
50
55
|
end
|
51
56
|
should "prepare valid command for ffmpeg" do
|
52
|
-
assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s
|
53
|
-
@convertor.instance_eval { mkcmd({'vpre' => 'hq-flash', 'pass' => 2}, 'sd', 'infile.avi', 'outfile.mpg', '
|
57
|
+
assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s 640x480 -ab 64k -ac 1 -acodec libfaac -ar 44100 -b 236k -bt 236k -pass 2 -threads 3 -vcodec libx264 -vpre hq-flash outfile.mpg',
|
58
|
+
@convertor.instance_eval { mkcmd({'vpre' => 'hq-flash', 'pass' => 2}, 'sd', 'infile.avi', 'outfile.mpg', '4:3') }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "for some task with unusual aspect (15:9) with crop" do
|
63
|
+
setup do
|
64
|
+
task = Factory.create(:task, :bitrate => 600, :crop => true, :deinterlace => false)
|
65
|
+
@convertor.stubs(:task).returns(task)
|
66
|
+
end
|
67
|
+
should "prepare valid command for ffmpeg" do
|
68
|
+
assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s 672x408 -ab 64k -ac 1 -acodec libfaac -ar 44100 -b 236k -bt 236k -cropbottom 4 -cropleft 16 -cropright 16 -croptop 20 -pass 2 -threads 3 -vcodec libx264 -vpre hq-flash outfile.mpg',
|
69
|
+
@convertor.instance_eval { mkcmd({'vpre' => 'hq-flash', 'pass' => 2}, 'sd', 'infile.avi', 'outfile.mpg', '15:9') }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "for some task with very unusual aspect (3:3)" do
|
74
|
+
setup do
|
75
|
+
task = Factory.create(:task, :bitrate => 600, :crop => false, :deinterlace => false)
|
76
|
+
@convertor.stubs(:task).returns(task)
|
77
|
+
end
|
78
|
+
should "prepare valid command for ffmpeg" do
|
79
|
+
assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s 640x480 -ab 64k -ac 1 -acodec libfaac -ar 44100 -aspect 1.33333333 -b 236k -bt 236k -pass 2 -threads 3 -vcodec libx264 -vpre hq-flash outfile.mpg',
|
80
|
+
@convertor.instance_eval { mkcmd({'vpre' => 'hq-flash', 'pass' => 2}, 'sd', 'infile.avi', 'outfile.mpg', '3:3') }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
#}}}
|
84
|
+
context "for task with crop and deinterlace and file with aspect 4:3" do # {{{
|
85
|
+
setup do
|
86
|
+
@convertor.file = Factory(:file, :aspect => '4:3', :filename => 'x/y/test.avi')
|
87
|
+
@convertor.task = Factory(:task, :file => @convertor.file, :crop => true, :deinterlace => true)
|
54
88
|
end
|
89
|
+
should "prepare valid shell command for thumbnail generation" do # {{{
|
90
|
+
assert_equal "/usr/local/bin/tmaker -i /tmp/test.avi -c 20 -d -w 150 -h 112 -o \"/tmp/output/x/y/test-%d-2.jpg\" 200 400 600",
|
91
|
+
@convertor.instance_eval { make_thumbnails_cmd(3, 200, 150, nil, 2) }
|
92
|
+
end # }}}
|
55
93
|
end
|
94
|
+
#}}}
|
95
|
+
context "when source file is available locally" do # {{{
|
96
|
+
setup do
|
97
|
+
@convertor.file = Factory(:file, :filename => 'test.avi', :location => 'ftp://example.com/test.avi')
|
98
|
+
FileUtils.touch '/tmp/test.avi'
|
99
|
+
Net::FTP.expects(:open).never
|
100
|
+
end
|
101
|
+
should "return immediately on attempt to fetch file" do
|
102
|
+
assert_nil @convertor.instance_eval { fetch_file('ftp://example.com/test.avi', 'test.avi') }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
# }}}
|
106
|
+
context "when source file is not available locally" do # {{{
|
107
|
+
setup do
|
108
|
+
@convertor.file = Factory(:file, :filename => 'test.avi', :location => 'ftp://example.com/test.avi')
|
109
|
+
FileUtils.rm_rf '/tmp/test.avi'
|
110
|
+
end
|
111
|
+
|
112
|
+
context "and ftp server works fine" do
|
113
|
+
setup do
|
114
|
+
ftp = mock()
|
115
|
+
ftp.expects(:login).with('test','test')
|
116
|
+
ftp.expects(:getbinaryfile).with('test.avi', '/tmp/test/test.part', 1024)
|
117
|
+
ftp.expects(:close)
|
118
|
+
Net::FTP.expects(:new).with('example.com', nil, nil, nil).returns(ftp)
|
119
|
+
end
|
120
|
+
should "download file by FTP" do
|
121
|
+
assert_equal 0, @convertor.instance_eval { fetch_file('ftp://example.com/test.avi', 'test.avi') }
|
122
|
+
assert !File.exists?('/tmp/test/test.avi.part')
|
123
|
+
assert File.exists?('/tmp/test.avi')
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context "and ftp server doesn't work" do
|
128
|
+
setup do
|
129
|
+
ftp = mock()
|
130
|
+
ftp.expects(:login).with('test','test')
|
131
|
+
ftp.expects(:getbinaryfile).raises(Net::FTPError)
|
132
|
+
ftp.expects(:close)
|
133
|
+
Net::FTP.expects(:new).with('example.com', nil, nil, nil).returns(ftp)
|
134
|
+
end
|
135
|
+
should "remove tmp file and raise error" do
|
136
|
+
assert_raise Net::FTPError do
|
137
|
+
@convertor.instance_eval { fetch_file('ftp://example.com/test.avi', 'test.avi') }
|
138
|
+
end
|
139
|
+
assert !File.exists?('/tmp/test/test.avi.part')
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
# }}}
|
144
|
+
context "processing file with some profile" do # {{{
|
145
|
+
setup do
|
146
|
+
@convertor.file = Factory(:file, :filename => 'x/y/test.avi')
|
147
|
+
@convertor.logger = Logger.new('/dev/null')
|
148
|
+
@convertor.expects(:mkcmd).twice.returns("echo OK > /dev/null").then.returns("echo OK > test-sd-0.mp4")
|
149
|
+
Convertr::Config.any_instance.stubs(:qtfaststart => 'mv')
|
150
|
+
@convertor.instance_eval { process_profile('sd') }
|
151
|
+
end
|
152
|
+
should "create converted file" do
|
153
|
+
assert File.exists?('/tmp/output/x/y/test-sd.mp4')
|
154
|
+
end
|
155
|
+
should "remove temporary dir" do
|
156
|
+
assert !File.exists?('sd')
|
157
|
+
end
|
158
|
+
end
|
159
|
+
# }}}
|
160
|
+
context "successfuly processing some task" do
|
161
|
+
setup do
|
162
|
+
file = Factory(:file, :filename => 'test.avi', :location => 'ftp://example.com/test.avi', :duration => 600)
|
163
|
+
@convertor.task = Factory(:task, :file => file, :bitrate => 600)
|
164
|
+
@convertor.logger = Logger.new('/dev/null')
|
165
|
+
FileUtils.mkpath('/tmp/test')
|
166
|
+
processing = sequence('processing')
|
167
|
+
@convertor.expects(:fetch_file).with('ftp://example.com/test.avi', 'test.avi').in_sequence(processing).returns(true)
|
168
|
+
@convertor.expects(:process_profile).with('hd').in_sequence(processing).returns(true)
|
169
|
+
@convertor.expects(:make_thumbnails_cmd).with(3, 200, 150, nil, 2).in_sequence(processing).returns('echo OK>/dev/null')
|
170
|
+
end
|
171
|
+
should "return SUCCESS" do
|
172
|
+
assert_equal 'SUCCESS', @convertor.instance_eval { process_task }
|
173
|
+
end
|
174
|
+
end
|
175
|
+
context "getting ftp error on processing some task" do
|
176
|
+
setup do
|
177
|
+
file = Factory(:file, :filename => 'test.avi', :location => 'ftp://example.com/test.avi', :duration => 600)
|
178
|
+
@convertor.task = Factory(:task, :file => file, :bitrate => 600)
|
179
|
+
@convertor.logger = Logger.new('/dev/null')
|
180
|
+
FileUtils.mkpath('/tmp/test')
|
181
|
+
@convertor.expects(:fetch_file).with('ftp://example.com/test.avi', 'test.avi').raises(Net::FTPError)
|
182
|
+
@convertor.expects(:process_profile).never
|
183
|
+
@convertor.expects(:make_thumbnails_cmd).never
|
184
|
+
end
|
185
|
+
should "return FAILURE" do
|
186
|
+
assert_equal 'FAILURE', @convertor.instance_eval { process_task }
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context "Convertor ran with max_tasks=2" do
|
192
|
+
setup do
|
193
|
+
@convertor = Convertr::Convertor.new(2)
|
194
|
+
end
|
195
|
+
|
196
|
+
context "after successful processing first and failure on second task" do # {{{
|
197
|
+
setup do
|
198
|
+
@task_success = Factory(:task)
|
199
|
+
@task_failure = Factory(:task)
|
200
|
+
@convertor.scheduler.stubs(:schedule_next_task).returns(@task_success).then.returns(@task_failure)
|
201
|
+
@convertor.stubs(:process_task).returns('SUCCESS').then.returns('FAILURE')
|
202
|
+
@convertor.run
|
203
|
+
end
|
204
|
+
should "exit" do
|
205
|
+
assert_equal 2, @convertor.tasks
|
206
|
+
end
|
207
|
+
should "update first task with success" do
|
208
|
+
assert_equal 'SUCCESS', @task_success.convert_status
|
209
|
+
assert_in_delta Time.now.to_i, @task_success.convert_stopped_at.to_i, 1
|
210
|
+
end
|
211
|
+
should "update second task with failure" do
|
212
|
+
assert_equal 'FAILURE', @task_failure.convert_status
|
213
|
+
assert_in_delta Time.now.to_i, @task_failure.convert_stopped_at.to_i, 1
|
214
|
+
end
|
215
|
+
end # }}}
|
56
216
|
end
|
57
217
|
end
|
data/test/test_file.rb
CHANGED
@@ -4,13 +4,11 @@ class TestFile < Test::Unit::TestCase
|
|
4
4
|
context "File class" do
|
5
5
|
should "have without_convertor scope" do
|
6
6
|
files = Convertr::File.without_convertor
|
7
|
-
assert_equal 2, files.size
|
8
7
|
assert_equal 3, files.first.id
|
9
8
|
end
|
10
9
|
|
11
10
|
should "have with_convertor scope" do
|
12
11
|
files = Convertr::File.with_convertor('convertor1')
|
13
|
-
assert_equal 2, files.size
|
14
12
|
assert_equal 1, files.first.id
|
15
13
|
end
|
16
14
|
end
|
data/test/test_scheduler.rb
CHANGED
@@ -5,10 +5,28 @@ class TestScheduler < Test::Unit::TestCase
|
|
5
5
|
setup do
|
6
6
|
@scheduler = Convertr::Scheduler::Base.new
|
7
7
|
end
|
8
|
+
|
8
9
|
should "raise exception on calling abstract methods" do
|
9
10
|
assert_raise RuntimeError do
|
10
11
|
@scheduler.instance_eval { get_task_for_schedule('convertor1') }
|
11
12
|
end
|
12
13
|
end
|
14
|
+
|
15
|
+
context "after scheduling next task" do
|
16
|
+
setup do
|
17
|
+
@task = Factory.build :task
|
18
|
+
@scheduler.expects(:get_task_for_schedule).with('convertor1').returns(@task)
|
19
|
+
@scheduler.schedule_next_task('convertor1')
|
20
|
+
end
|
21
|
+
|
22
|
+
should "update task accordingly" do
|
23
|
+
assert_equal 'PROGRESS', @task.convert_status
|
24
|
+
assert_in_delta Time.now.to_i, @task.convert_started_at.to_i, 1
|
25
|
+
end
|
26
|
+
|
27
|
+
should "update file accordingly" do
|
28
|
+
assert_equal "convertor1", @task.file.convertor
|
29
|
+
end
|
30
|
+
end
|
13
31
|
end
|
14
32
|
end
|
@@ -6,7 +6,7 @@ class TestSchedulerAllbtfirst < Test::Unit::TestCase
|
|
6
6
|
@scheduler = Convertr::SchedulerFactory.create('AllBtFirst')
|
7
7
|
end
|
8
8
|
should "find first task assigned for convertor" do
|
9
|
-
assert_equal
|
9
|
+
assert_equal 3, @scheduler.get_task_for_schedule('convertor1').id
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
data/test/test_task.rb
CHANGED
@@ -8,6 +8,9 @@ class TestTask < Test::Unit::TestCase
|
|
8
8
|
should "have not_completed scope" do
|
9
9
|
assert_equal 3, Convertr::Task.not_completed.size
|
10
10
|
end
|
11
|
+
should "have without_convertor scope" do
|
12
|
+
assert_equal 1, Convertr::Task.without_convertor.first.id
|
13
|
+
end
|
11
14
|
end
|
12
15
|
|
13
16
|
context "Task" do
|
metadata
CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 0.0.2
|
10
|
+
version: 0.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ilya Lityuga
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-10-
|
19
|
+
date: 2010-10-14 00:00:00 +04:00
|
20
20
|
default_executable: convertr
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|