Batch processing and config file support

Added a config file to describe multiple jobs to run, and to provide
values for options not specified on command line.
In the config file, presets can be used to save duplication of rip
options common to multiple jobs.
This commit is contained in:
Ben Roberts
2010-02-17 01:13:58 +00:00
parent 0e4f9324aa
commit 3ea5aa5706
6 changed files with 134 additions and 10 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.*.swp

40
config.yml Normal file
View File

@@ -0,0 +1,40 @@
---
options:
verbose: 1
log_file: /tmp/handbrake-cluster-client.log
job_servers:
- build0.example.com
- build1.example.com
report_email: me@example.com
presets:
tvseries:
nice: 15
format: mkv
video_codec: x264
video_width: 720
video_height: 480
quantizer: 0.61
deinterlace: 2
audio_tracks: 1
audio_codec: ac3
audio_names: English
subtitle_tracks: 1,5
disk1:
input_filename: /dev/sr1
disk2:
input_filename: /tmp/dvds/disk2/VIDEO_TS
jobs:
- presets:
- tvseries
- disk1
output_filename: /tmp/title1.mkv
title: 1
- presets:
- tvseries
- disk2
output_filename: /tmp/title2.mkv
title: -1

View File

@@ -7,28 +7,35 @@ use Data::Dumper;
use Gearman::Client;
use Getopt::Long;
use Log::Handler;
use MIME::Lite::TT::HTML;
use Pod::Usage;
use Storable qw/freeze thaw/;
use YAML::Any;
# Handle interrupts, and term signals
$SIG{'INT'} = 'INT_handler';
$SIG{'TERM'} = 'TERM_handler';
# Globals
our %options = (
our %default_options = (
verbose => 0,
debug => 0,
quiet => 0,
log_file => '/tmp/handbrake-cluster-client.log',
silent => 0,
help => 0,
pretend => 0,
job_servers => ['build0.sihnon.net', 'build1.sihnon.net', 'build2.sihnon.net'],
report_email => '',
config_file => '',
);
our %options = map { $_ => undef } keys %default_options;
our %rip_options = (
nice => 15,
input_filename => '/dev/sr0',
output_filename => 'rip-output.mkv',
title => -1,
title => 0,
format => 'mkv',
video_codec => 'x264',
video_width => 720, # DVD resolution
@@ -51,6 +58,8 @@ GetOptions(
'help|h' => \$options{help},
'pretend|n' => \$options{pretend},
'job-servers|j=s@' => \$options{job_servers},
'report|r=s' => \$options{report_email},
'config|c=s' => \$options{config_file},
'nice|N=i' => \$rip_options{nice},
'input|i=s' => \$rip_options{input_filename},
'output|o=s' => \$rip_options{output_filename},
@@ -68,6 +77,19 @@ GetOptions(
) or pod2usage(-verbose => 0);
pod2usage(-verbose => 1) if ($options{help});
my @jobs;
my $config;
# Read a configuration file, if provided
if ($options{config_file}) {
$config = parse_config($options{config_file});
push @jobs, @{ $config->{jobs} };
}
# A list of jobs to run, formed from command line options or config file
if ($rip_options{title}) {
push @jobs, \%rip_options;
}
# Setup logging
my $log = Log::Handler->new();
my $maxLogLevel = ($options{debug} ? 'debug' : ($options{quiet} ? 3 : $options{verbose} + 4)); # default to logging warning+, unless quiet in which case log error+, or debug in which case log everything
@@ -96,19 +118,39 @@ if ( $options{log_file}) {
my $client = Gearman::Client->new;
$client->job_servers($options{job_servers});
# Add new ripping task
# Add new ripping task for each job to run
my $taskset = $client->new_task_set;
$taskset->add_task("rip", freeze(\%rip_options),
foreach my $job (@jobs) {
$taskset->add_task("rip", freeze($job),
{
on_complete => \&on_complete_handler,
on_fail => \&on_fail_handler,
}
);
);
}
$taskset->wait;
sub on_complete_handler {
my $result_ref = shift or die;
if ($options{report_email}) {
my $email = MIME::Lite::TT::HTML->new(
From => $options{report_email},,
To => $options{report_email},
Subject => 'Rip completed',
TimeZone => 'Europe/London',
Encoding => 'quoted-printable',
Template => {
html => 'rip-completed.html',
text => 'rip-completed.txt',
},
Charset => 'utf8',
TmplOptions => {},
TmplParams => {},
);
$email->send;
}
$log->notice("Completed rip to $$result_ref");
}
@@ -116,6 +158,38 @@ sub on_fail_handler {
$log->error("Rip failed");
}
sub parse_config {
my $config_file = shift or die;
my $config = YAML::Any::LoadFile($options{config_file}) or die 'Unable to load configuration file: ' . $!;
# Update any unset options with values from config file
foreach my $option (keys %options) {
# Update the value of any option which has not been set by a command line argument
if (!$options{$option}) {
# Try the config file first, otherwise use the default value
if (defined $config->{options}->{$option}) {
$options{$option} = $config->{options}->{$option};
} else {
$options{$option} = $default_options{$option};
}
}
}
# Iterate through each job, and inject any preset variables that haven't been redefined by the job
foreach my $job (@{ $config->{jobs} }) {
if ($job->{presets}) {
foreach my $preset_name (@{ $job->{presets} }) {
print "Copying values for preset $preset_name into job\n";
foreach my $preset_key (keys %{$config->{presets}->{$preset_name}}) {
$job->{$preset_key} = $config->{presets}->{$preset_name}->{$preset_key} unless $job->{$preset_key};
}
}
}
}
return $config;
}
sub INT_handler {
$log->error("Caught interrupt, exiting.");

View File

@@ -87,13 +87,20 @@ sub do_rip {
push @deinterlace_options, '-d' if ($rip_options{deinterlace} == 1);
push @deinterlace_options, '-5' if ($rip_options{deinterlace} == 2);
my @title_options;
if ($rip_options{title} < 0) {
push @title_options, '-L';
} else {
push @title_options, '-t', $rip_options{title};
}
# Generate the command line for handbrake
my @handbrake_cmd = (
'nice', '-n', $rip_options{nice},
$options{handbrake},
'-i', $rip_options{input_filename},
'-o', $rip_filename,
'-t', $rip_options{title},
@title_options.
'-f', $rip_options{format},
'-e', $rip_options{video_codec},
'-q', $rip_options{quantizer},

1
rip-completed.html Normal file
View File

@@ -0,0 +1 @@
A rip has completed successfully

1
rip-completed.txt Normal file
View File

@@ -0,0 +1 @@
A rip has completed successfully