Files
handbrake-cluster/handbrake-cluster-worker.pl
Ben Roberts f71987cbb6 Massive update tidying codebase for release
Added POD to client and worker
Updated HTMl and Text email templates
2010-02-19 22:07:45 +00:00

227 lines
6.7 KiB
Perl
Executable File

#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
use Gearman::Worker;
use Getopt::Long;
use IPC::Open2;
use Log::Handler;
use Pod::Usage;
use String::Random qw/random_string/;
use Storable qw/freeze thaw/;
use Switch;
# Globals
our %options = (
verbose => 0,
quiet => 0,
log_file => '/tmp/handbrake-cluster-worker.log',
silent => 0,
help => 0,
pretend => 0,
job_servers => ['build0.sihnon.net', 'build1.sihnon.net', 'build2.sihnon.net'],
handbrake => '/usr/bin/HandBrakeCLI',
);
Getopt::Long::Configure( qw(bundling no_getopt_compat) );
GetOptions(
'help|h' => \$options{help},
'verbose|v' => \$options{verbose},
'debug|d' => \$options{debug},
'quiet|q' => \$options{quiet},
'silent|s' => \$options{silent},
'log|l=s' => \$options{log_file},
'pretend|n' => \$options{pretend},
'job-servers|j=s@' => \$options{job_servers},
'handbrake' => \$options{handbrake},
) or pod2usage(-verbose => 0);
pod2usage(-verbose => 1) if ($options{help});
# 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
my $maxFileLogLevel = ($options{debug} ? 'debug' : 'info');
if ( ! $options{silent}) {
$log->add(
screen => {
log_to => 'STDOUT',
minlevel => 'emergency',
maxlevel => $maxLogLevel,
},
);
}
if ( $options{log_file}) {
$log->add(
file => {
filename => $options{log_file},
minlevel => 'emergency',
maxlevel => $maxFileLogLevel,
},
);
}
# Setup the worker, and listen for jobs
my $worker = Gearman::Worker->new(job_servers => $options{job_servers});
$worker->register_function(handbrake_rip => \&handbrake_rip);
$worker->work while 1;
sub handbrake_rip {
my $job = shift;
my %rip_options = %{ thaw($job->arg) };
my %response;
$log->notice("Beginning new rip to $rip_options{output_filename}");
# Generate a unique filename based on the output filename to prevent clashes from previous runs
my $uuid = random_string('cccccc');
$rip_options{real_output_filename} = $rip_options{output_filename};
$rip_options{real_output_filename} =~ s/\.([^\.]+)$/\.$uuid\.$1/;
$response{real_output_filename} = $rip_options{real_output_filename};
# Generate the command line for handbrake
my @handbrake_cmd = (
# Reduce the priority of the ripping process, since it is very processor intensive
'nice', '-n', $rip_options{nice},
# Construct the handbrake command line
$options{handbrake},
get_options(\%rip_options, 'input_filename', '-i'),
get_options(\%rip_options, 'real_output_filename', '-o'),
get_options(\%rip_options, 'title'),
get_options(\%rip_options, 'format', '-f'),
get_options(\%rip_options, 'video_codec', '-e'),
get_options(\%rip_options, 'quantizer', '-q'),
get_options(\%rip_options, 'video_width', '-w'),
get_options(\%rip_options, 'video_height', '-l'),
get_options(\%rip_options, 'deinterlace'),
get_options(\%rip_options, 'audio_tracks', '-a'),
get_options(\%rip_options, 'audio_codec', '-E'),
get_options(\%rip_options, 'audio_names', '-A'),
get_options(\%rip_options, 'subtitle_tracks', '-s'),
);
# Return a copy of the command used to rip the title
$response{handbrake_cmd} = @handbrake_cmd;
# Execute the ripping process
$log->debug("Beginning ripping process with command:\n" . join(' ', @handbrake_cmd));
my ($child_in, $child_out);
my $child_pid = open2($child_out, $child_in, @handbrake_cmd);
# No need to write to the child process
close($child_in);
# Log the output from handbrake, and return it back to the client
$response{log} = ();
my $line;
while ($line = <$child_out>) {
push @{ $response{log} }, $line;
$log->debug($line);
}
close($child_out);
# If the rip process failed, report an error status here
waitpid($child_pid, 0);
$response{status} = $? >> 8;
$response{success} = $response{status} == 0;
if ($response{success}) {
$log->notice("Finished rip to $rip_options{real_output_filename}");
} else {
$log->warning("Ripping process returned error status: $response{status}");
}
return freeze(\%response);
}
sub get_options {
my $rip_options = shift or die;
my $option_name = shift or die;
my $option = shift;
switch ($option_name) {
case 'title' {
return ('-L') if ! defined($rip_options->{$option_name}) || $rip_options->{$option_name} < 0;
return ('-t', $rip_options->{$option_name});
}
case 'deinterlace' {
switch ($rip_options->{$option_name}) {
case 1 { return ('-d') }
case 2 { return ('-5') }
return ();
}
}
return (defined $rip_options->{$option_name} ? ($option, $rip_options->{$option_name}) : ());
}
}
__END__;
=head1 NAME
handbrake-cluster-worker - Processes DVD rips farmed out by gearman
=head1 SYNOPSIS
handbrake-cluster-worker.pl -h|--help
handbrake-cluster-worker.pl [[-v|--verbose] | [-d|--debug] |
[-q|--quiet] | [-s|--silent]]
[-l|--log <log file>]
[-n|--pretend]
[-j|--job-servers <server list>]
[--handbrake <handbrake executable>]
=head1 DESCRIPTION
Processes ripping tasks as requested by a gearman job server. Logging and the
job servers to use are configurable by command line arguments.
=head1 OPTIONS
=over 4
=item B<-h|--help>
Displays this help information and quits.
=item B<-v|--verbose>
Displays verbose logging information.
=item B<-d|--debug>
Displays full debugging information, including all output from HandBrake.
=item B<-q|--quiet>
Displays only errors.
=item B<-s|--silent>
Displays no output whatsoever, useful for scripting. Output will still be
logged to disk if a file is specified.
=item B<-l|--log E<lt>log fileE<gt>>
Specifies the name of a file to write logging information to.
=item B<-n|--pretend>
Only shows what action would be taken, no rips are actually performed.
=item B<-j|--job-servers E<lt>server listE<gt>>
Specifies a comma separated list of alternate servers to use for job
distribution.
=item B<--handbrake E<lt>handbrake executableE<gt>>
Specifies an alternate HandBrake executable to use. Default is
C</usr/bin/HandBrakeCLI>.
=cut