handbrake 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +7 -0
- data/README.md +7 -0
- data/lib/handbrake.rb +6 -0
- data/lib/handbrake/cli.rb +83 -2
- data/lib/handbrake/version.rb +1 -1
- data/spec/handbrake/cli_spec.rb +156 -3
- data/spec/spec_helper.rb +17 -14
- metadata +49 -87
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -126,6 +126,13 @@ To put it more technically, the chain object returned from each
|
|
126
126
|
intermediate configuration step returns an independent copy of the
|
127
127
|
configuration chain.
|
128
128
|
|
129
|
+
### Output options
|
130
|
+
|
131
|
+
By default, the `output` execution method behaves just like invoking
|
132
|
+
HandBrakeCLI directly. `handbrake.rb` also supports a couple of
|
133
|
+
additional behaviors, including overwrite detection and atomic output
|
134
|
+
file creation. See {HandBrake::CLI#output} for more details.
|
135
|
+
|
129
136
|
Additional resources
|
130
137
|
--------------------
|
131
138
|
|
data/lib/handbrake.rb
CHANGED
@@ -8,4 +8,10 @@ module HandBrake
|
|
8
8
|
autoload :Titles, 'handbrake/titles'
|
9
9
|
autoload :Title, 'handbrake/titles'
|
10
10
|
autoload :Chapter, 'handbrake/titles'
|
11
|
+
|
12
|
+
##
|
13
|
+
# The exception thrown when a file exists that shouldn't.
|
14
|
+
#
|
15
|
+
# @see CLI#output
|
16
|
+
class FileExistsError < StandardError; end;
|
11
17
|
end
|
data/lib/handbrake/cli.rb
CHANGED
@@ -59,11 +59,88 @@ module HandBrake
|
|
59
59
|
# Performs a conversion. This method immediately begins the
|
60
60
|
# transcoding process; set all other options first.
|
61
61
|
#
|
62
|
+
# @param [String] filename the desired name for the final output
|
63
|
+
# file
|
64
|
+
# @param [Hash] options additional options to control the behavior
|
65
|
+
# of the output process
|
66
|
+
# @option options [Boolean,:ignore] :overwrite (true) determines
|
67
|
+
# the behavior if the desired output file already exists. If
|
68
|
+
# `true`, the file is replaced. If `false`, an exception is
|
69
|
+
# thrown. If `:ignore`, the file is skipped; i.e., HandBrakeCLI
|
70
|
+
# is not invoked.
|
71
|
+
# @option options [Boolean] :atomic (false) provides a
|
72
|
+
# pseudo-atomic mode for transcoded output. If true, the
|
73
|
+
# transcode will go into a temporary file and only be copied to
|
74
|
+
# the specified filename if it completes. The temporary filename
|
75
|
+
# is the target filename with `.handbraking` inserted before the
|
76
|
+
# extension. Any `:overwrite` checking will be applied to the
|
77
|
+
# target filename both before and after the transcode happens
|
78
|
+
# (the temporary file will always be overwritten). This option
|
79
|
+
# is intended to aid in writing automatically resumable batch
|
80
|
+
# scripts.
|
81
|
+
#
|
62
82
|
# @return [void]
|
63
|
-
def output(filename)
|
64
|
-
|
83
|
+
def output(filename, options={})
|
84
|
+
overwrite = options.delete :overwrite
|
85
|
+
case overwrite
|
86
|
+
when true, nil
|
87
|
+
# no special behavior
|
88
|
+
when false
|
89
|
+
raise FileExistsError, filename if File.exist?(filename)
|
90
|
+
when :ignore
|
91
|
+
if File.exist?(filename)
|
92
|
+
trace "Ignoring transcode to #{filename.inspect} because it already exists"
|
93
|
+
return
|
94
|
+
end
|
95
|
+
else
|
96
|
+
raise "Unsupported value for :overwrite: #{overwrite.inspect}"
|
97
|
+
end
|
98
|
+
|
99
|
+
atomic = options.delete :atomic
|
100
|
+
interim_filename =
|
101
|
+
if atomic
|
102
|
+
partial_filename(filename)
|
103
|
+
else
|
104
|
+
filename
|
105
|
+
end
|
106
|
+
|
107
|
+
unless options.empty?
|
108
|
+
raise "Unknown options for output: #{options.keys.inspect}"
|
109
|
+
end
|
110
|
+
|
111
|
+
run('--output', interim_filename)
|
112
|
+
|
113
|
+
if filename != interim_filename
|
114
|
+
replace =
|
115
|
+
if File.exist?(filename)
|
116
|
+
trace "#{filename.inspect} showed up during transcode"
|
117
|
+
case overwrite
|
118
|
+
when false
|
119
|
+
raise FileExistsError, filename
|
120
|
+
when :ignore
|
121
|
+
trace "- will leave #{filename.inspect} as is; copy #{interim_filename.inspect} manually if you want to replace it"
|
122
|
+
false
|
123
|
+
else
|
124
|
+
trace '- will replace with new transcode'
|
125
|
+
true
|
126
|
+
end
|
127
|
+
else
|
128
|
+
true
|
129
|
+
end
|
130
|
+
FileUtils.mv interim_filename, filename if replace
|
131
|
+
end
|
65
132
|
end
|
66
133
|
|
134
|
+
def partial_filename(name)
|
135
|
+
if File.basename(name).index '.'
|
136
|
+
dot_at = name.rindex '.'
|
137
|
+
name.dup.insert dot_at, '.handbraking'
|
138
|
+
else
|
139
|
+
name + '.handbraking'
|
140
|
+
end
|
141
|
+
end
|
142
|
+
private :partial_filename
|
143
|
+
|
67
144
|
##
|
68
145
|
# Performs a title scan. Unlike HandBrakeCLI, if you do not
|
69
146
|
# specify a title, this method will return information for all
|
@@ -136,6 +213,10 @@ module HandBrake
|
|
136
213
|
end
|
137
214
|
end
|
138
215
|
|
216
|
+
def trace(msg)
|
217
|
+
$stderr.puts msg if trace?
|
218
|
+
end
|
219
|
+
|
139
220
|
##
|
140
221
|
# Copies this CLI instance and appends another command line switch
|
141
222
|
# plus optional arguments.
|
data/lib/handbrake/version.rb
CHANGED
data/spec/handbrake/cli_spec.rb
CHANGED
@@ -71,14 +71,167 @@ module HandBrake
|
|
71
71
|
end
|
72
72
|
|
73
73
|
it 'works' do
|
74
|
-
lambda { cli.
|
74
|
+
lambda { cli.preset_list }.should_not raise_error
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
78
|
describe '#output' do
|
79
|
+
let(:filename) { File.join(tmpdir, 'foo.m4v') }
|
80
|
+
|
81
|
+
def it_should_have_run(expected_fn=filename)
|
82
|
+
runner.actual_arguments.should == ['--output', expected_fn]
|
83
|
+
end
|
84
|
+
|
85
|
+
def it_should_not_have_run
|
86
|
+
runner.actual_arguments.should be_nil
|
87
|
+
end
|
88
|
+
|
79
89
|
it 'uses the --output argument' do
|
80
|
-
cli.output(
|
81
|
-
runner.actual_arguments.should ==
|
90
|
+
cli.output(filename)
|
91
|
+
runner.actual_arguments.should == ['--output', filename]
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'fails for an unknown option' do
|
95
|
+
lambda { cli.output(filename, :quux => 'zap') }.
|
96
|
+
should raise_error('Unknown options for output: [:quux]')
|
97
|
+
end
|
98
|
+
|
99
|
+
describe ':overwrite' do
|
100
|
+
context 'true' do
|
101
|
+
it 'executes when the file does not exist' do
|
102
|
+
cli.output(filename, :overwrite => true)
|
103
|
+
it_should_have_run
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'executes when the file exists' do
|
107
|
+
FileUtils.touch filename
|
108
|
+
cli.output(filename, :overwrite => true)
|
109
|
+
it_should_have_run
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'is the default' do
|
113
|
+
FileUtils.touch filename
|
114
|
+
cli.output(filename)
|
115
|
+
it_should_have_run
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'false' do
|
120
|
+
it 'executes when the file does not exist' do
|
121
|
+
cli.output(filename, :overwrite => false)
|
122
|
+
it_should_have_run
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'throws an exception when the file does exist' do
|
126
|
+
FileUtils.touch filename
|
127
|
+
lambda { cli.output(filename, :overwrite => false) }.
|
128
|
+
should raise_error(HandBrake::FileExistsError)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context ':ignore' do
|
133
|
+
it 'executes when the file does not exist' do
|
134
|
+
cli.output(filename, :overwrite => :ignore)
|
135
|
+
it_should_have_run
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'does nothing when the file does exist' do
|
139
|
+
FileUtils.touch filename
|
140
|
+
cli.output(filename, :overwrite => :ignore)
|
141
|
+
it_should_not_have_run
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'other value' do
|
146
|
+
it 'throws an exception' do
|
147
|
+
lambda { cli.output(filename, :overwrite => 'flip') }.
|
148
|
+
should raise_error('Unsupported value for :overwrite: "flip"')
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe ':atomic' do
|
154
|
+
context 'false' do
|
155
|
+
it 'executes normally' do
|
156
|
+
cli.output(filename, :atomic => false)
|
157
|
+
it_should_have_run
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'is the default' do
|
161
|
+
cli.output(filename)
|
162
|
+
it_should_have_run
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context 'true' do
|
167
|
+
let(:expected_temporary_file) { File.join(tmpdir, "foo.handbraking.m4v") }
|
168
|
+
|
169
|
+
it 'outputs to the temporary file with ".handbraking" inserted before the extension' do
|
170
|
+
cli.output(filename, :atomic => true)
|
171
|
+
it_should_have_run(expected_temporary_file)
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'appends .handbraking if the output file does not have an extension' do
|
175
|
+
cli.output(File.join(tmpdir('a.b.c'), 'foo'), :atomic => true)
|
176
|
+
it_should_have_run(File.join(tmpdir('a.b.c'), 'foo.handbraking'))
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'copies the output to the desired filename' do
|
180
|
+
cli.output(filename, :atomic => true)
|
181
|
+
File.read(filename).should == 'This is the file created by --output'
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'removes the temporary file' do
|
185
|
+
cli.output(filename, :atomic => true)
|
186
|
+
File.exist?(expected_temporary_file).should be_false
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'overwrites the temporary file if it exists' do
|
190
|
+
FileUtils.touch expected_temporary_file
|
191
|
+
cli.output(filename, :atomic => true)
|
192
|
+
it_should_have_run(expected_temporary_file)
|
193
|
+
end
|
194
|
+
|
195
|
+
describe 'and :overwrite' do
|
196
|
+
describe 'false' do
|
197
|
+
it 'throws an exception if the target filename exists initially' do
|
198
|
+
FileUtils.touch filename
|
199
|
+
lambda { cli.output(filename, :atomic => true, :overwrite => false) }.
|
200
|
+
should raise_error(HandBrake::FileExistsError)
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'throws an exception if the target filename exists after output' do
|
204
|
+
runner.behavior = lambda { FileUtils.touch filename }
|
205
|
+
lambda { cli.output(filename, :atomic => true, :overwrite => false) }.
|
206
|
+
should raise_error(HandBrake::FileExistsError)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
describe ':ignore' do
|
211
|
+
it 'does nothing if the target filename exists initially' do
|
212
|
+
FileUtils.touch filename
|
213
|
+
cli.output(filename, :atomic => true, :overwrite => :ignore)
|
214
|
+
it_should_not_have_run
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'does not copy the output if the target filename exists after encoding' do
|
218
|
+
runner.behavior = lambda {
|
219
|
+
File.open(filename, 'w') { |f| f.write 'Other process result' }
|
220
|
+
}
|
221
|
+
cli.output(filename, :atomic => true, :overwrite => :ignore)
|
222
|
+
File.read(filename).should == 'Other process result'
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'does not remove the temporary output if the target filename exists after encoding' do
|
226
|
+
runner.behavior = lambda {
|
227
|
+
File.open(filename, 'w') { |f| f.write 'Other process result' }
|
228
|
+
}
|
229
|
+
cli.output(filename, :atomic => true, :overwrite => :ignore)
|
230
|
+
File.exist?(expected_temporary_file).should be_true
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
82
235
|
end
|
83
236
|
end
|
84
237
|
|
data/spec/spec_helper.rb
CHANGED
@@ -2,38 +2,29 @@ require 'bundler'
|
|
2
2
|
Bundler.setup
|
3
3
|
|
4
4
|
require 'rspec'
|
5
|
+
require 'fileutils'
|
5
6
|
|
6
7
|
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
7
8
|
|
8
9
|
require 'handbrake'
|
9
10
|
|
10
11
|
RSpec.configure do |config|
|
11
|
-
# Captures everything printed to stdout during the block
|
12
|
-
# and returns it as a string.
|
13
|
-
def capture_stdout
|
14
|
-
old_stdout, $stdout = $stdout, StringIO.new
|
15
|
-
begin
|
16
|
-
yield
|
17
|
-
$stdout.string
|
18
|
-
ensure
|
19
|
-
$stdout = old_stdout
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
12
|
def tmpdir(sub=nil)
|
24
13
|
@tmpdir ||= begin
|
25
14
|
dirname = File.expand_path("../tmp", __FILE__)
|
26
|
-
mkdir_p dirname
|
15
|
+
FileUtils.mkdir_p dirname
|
27
16
|
dirname
|
28
17
|
end
|
29
18
|
if sub
|
30
19
|
full = File.join(@tmpdir, sub)
|
31
|
-
mkdir_p full
|
20
|
+
FileUtils.mkdir_p full
|
32
21
|
full
|
33
22
|
else
|
34
23
|
@tmpdir
|
35
24
|
end
|
36
25
|
end
|
26
|
+
|
27
|
+
config.after { FileUtils.rm_rf @tmpdir if @tmpdir }
|
37
28
|
end
|
38
29
|
|
39
30
|
module HandBrake
|
@@ -42,10 +33,22 @@ module HandBrake
|
|
42
33
|
# A stub implementation of the runner for HandBrake::CLI.
|
43
34
|
class StaticRunner
|
44
35
|
attr_accessor :output, :status
|
36
|
+
##
|
37
|
+
# A lambda that specifies desired side effects of execution or
|
38
|
+
# simulates things happening outside the execution but
|
39
|
+
# simultaneous with it.
|
40
|
+
attr_accessor :behavior
|
45
41
|
attr_reader :actual_arguments
|
46
42
|
|
47
43
|
def run(args)
|
48
44
|
@actual_arguments = args
|
45
|
+
if i = args.index('--output')
|
46
|
+
fn = args[i + 1]
|
47
|
+
File.open(fn, 'w') { |f| f.write 'This is the file created by --output' }
|
48
|
+
end
|
49
|
+
if behavior
|
50
|
+
behavior.call
|
51
|
+
end
|
49
52
|
HandBrake::CLI::RunnerResult.new(output, status)
|
50
53
|
end
|
51
54
|
|
metadata
CHANGED
@@ -1,96 +1,68 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: handbrake
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
- 0
|
10
|
-
version: 0.1.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Rhett Sutphin
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
dependencies:
|
21
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2011-08-07 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
22
15
|
name: rubytree
|
23
|
-
|
24
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &2153799900 !ruby/object:Gem::Requirement
|
25
17
|
none: false
|
26
|
-
requirements:
|
18
|
+
requirements:
|
27
19
|
- - ~>
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
hash: 61
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
- 8
|
33
|
-
- 1
|
20
|
+
- !ruby/object:Gem::Version
|
34
21
|
version: 0.8.1
|
35
22
|
type: :runtime
|
36
|
-
version_requirements: *id001
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
|
-
name: rspec
|
39
23
|
prerelease: false
|
40
|
-
|
24
|
+
version_requirements: *2153799900
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
requirement: &2153799400 !ruby/object:Gem::Requirement
|
41
28
|
none: false
|
42
|
-
requirements:
|
29
|
+
requirements:
|
43
30
|
- - ~>
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
|
46
|
-
segments:
|
47
|
-
- 2
|
48
|
-
- 5
|
49
|
-
version: "2.5"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.5'
|
50
33
|
type: :development
|
51
|
-
version_requirements: *id002
|
52
|
-
- !ruby/object:Gem::Dependency
|
53
|
-
name: rake
|
54
34
|
prerelease: false
|
55
|
-
|
35
|
+
version_requirements: *2153799400
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rake
|
38
|
+
requirement: &2153798940 !ruby/object:Gem::Requirement
|
56
39
|
none: false
|
57
|
-
requirements:
|
40
|
+
requirements:
|
58
41
|
- - ~>
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
hash: 59
|
61
|
-
segments:
|
62
|
-
- 0
|
63
|
-
- 9
|
64
|
-
- 0
|
42
|
+
- !ruby/object:Gem::Version
|
65
43
|
version: 0.9.0
|
66
44
|
type: :development
|
67
|
-
version_requirements: *id003
|
68
|
-
- !ruby/object:Gem::Dependency
|
69
|
-
name: yard
|
70
45
|
prerelease: false
|
71
|
-
|
46
|
+
version_requirements: *2153798940
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: yard
|
49
|
+
requirement: &2153798480 !ruby/object:Gem::Requirement
|
72
50
|
none: false
|
73
|
-
requirements:
|
51
|
+
requirements:
|
74
52
|
- - ~>
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
hash: 3
|
77
|
-
segments:
|
78
|
-
- 0
|
79
|
-
- 7
|
80
|
-
- 0
|
53
|
+
- !ruby/object:Gem::Version
|
81
54
|
version: 0.7.0
|
82
55
|
type: :development
|
83
|
-
|
84
|
-
|
85
|
-
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2153798480
|
58
|
+
description: A lightweight literate ruby wrapper for HandBrakeCLI, the command-line
|
59
|
+
interface for the HandBrake video transcoder.
|
60
|
+
email:
|
86
61
|
- rhett@detailedbalance.net
|
87
62
|
executables: []
|
88
|
-
|
89
63
|
extensions: []
|
90
|
-
|
91
64
|
extra_rdoc_files: []
|
92
|
-
|
93
|
-
files:
|
65
|
+
files:
|
94
66
|
- .gitignore
|
95
67
|
- .rvmrc
|
96
68
|
- .travis.yml
|
@@ -112,41 +84,31 @@ files:
|
|
112
84
|
- spec/handbrake/titles_spec.rb
|
113
85
|
- spec/handbrake/version_spec.rb
|
114
86
|
- spec/spec_helper.rb
|
115
|
-
has_rdoc: true
|
116
87
|
homepage: https://github.com/rsutphin/handbrake.rb
|
117
88
|
licenses: []
|
118
|
-
|
119
89
|
post_install_message:
|
120
90
|
rdoc_options: []
|
121
|
-
|
122
|
-
require_paths:
|
91
|
+
require_paths:
|
123
92
|
- lib
|
124
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
125
94
|
none: false
|
126
|
-
requirements:
|
127
|
-
- -
|
128
|
-
- !ruby/object:Gem::Version
|
129
|
-
|
130
|
-
|
131
|
-
- 0
|
132
|
-
version: "0"
|
133
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
100
|
none: false
|
135
|
-
requirements:
|
136
|
-
- -
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
|
139
|
-
segments:
|
140
|
-
- 0
|
141
|
-
version: "0"
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
142
105
|
requirements: []
|
143
|
-
|
144
106
|
rubyforge_project:
|
145
|
-
rubygems_version: 1.
|
107
|
+
rubygems_version: 1.8.6
|
146
108
|
signing_key:
|
147
109
|
specification_version: 3
|
148
110
|
summary: A ruby wrapper for HandBrakeCLI
|
149
|
-
test_files:
|
111
|
+
test_files:
|
150
112
|
- spec/handbrake/cli_spec.rb
|
151
113
|
- spec/handbrake/sample-preset-list.out
|
152
114
|
- spec/handbrake/sample-titles-scan.err
|