convertr 0.0.2 → 0.1.0
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/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
|