Added a function to construct commandline parameters from rip_options array to exclude any unspecified options, and simplify handling of special cases.
189 lines
5.5 KiB
Perl
Executable File
189 lines
5.5 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/thaw/;
|
|
use Switch;
|
|
|
|
# Handle interrupts, and term signals
|
|
$SIG{'INT'} = 'INT_handler';
|
|
$SIG{'TERM'} = 'TERM_handler';
|
|
|
|
# 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(
|
|
'verbose|v+' => \$options{verbose},
|
|
'debug|d' => \$options{debug},
|
|
'quiet|q' => \$options{quiet},
|
|
'silent|s' => \$options{silent},
|
|
'log|l=s' => \$options{log_file},
|
|
'help|h' => \$options{help},
|
|
'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(rip => \&do_rip);
|
|
$worker->work while 1;
|
|
|
|
sub do_rip {
|
|
my $job = shift;
|
|
my %rip_options = %{ thaw($job->arg) };
|
|
|
|
$log->notice("Beginning new rip to $rip_options{output_filename}");
|
|
|
|
my $uuid = random_string('cccccc');
|
|
$log->debug("Using $uuid as unique identifier for this job");
|
|
$rip_options{unique_output_filename} = $rip_options{output_filename};
|
|
$rip_options{unique_output_filename} =~ s/\.([^\.]+)$/\.$uuid\.$1/;
|
|
|
|
# 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, 'unique_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'),
|
|
);
|
|
|
|
$log->debug("Beginning ripping process with command:\n" . join(' ', @handbrake_cmd));
|
|
|
|
# Execute the ripping process
|
|
my ($child_in, $child_out);
|
|
my $child_pid = open2($child_out, $child_in, @handbrake_cmd);
|
|
# Don't need to write from the child
|
|
close($child_in);
|
|
|
|
my $line;
|
|
while ($line = <$child_out>) {
|
|
$log->debug($line);
|
|
}
|
|
close($child_out);
|
|
|
|
# If the rip process failed, report an error status here
|
|
waitpid($child_pid, 0);
|
|
my $child_exit_status = $? >> 8;
|
|
|
|
if ($child_exit_status) {
|
|
$log->warning("Ripping process returned error status: $child_exit_status");
|
|
return undef;
|
|
}
|
|
|
|
$log->notice("Finished rip to $rip_options{unique_output_filename}");
|
|
return $rip_options{unique_output_filename};
|
|
}
|
|
|
|
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}) : ());
|
|
}
|
|
}
|
|
|
|
sub INT_handler {
|
|
$log->error("Caught interrupt, exiting.");
|
|
exit 0;
|
|
}
|
|
|
|
sub TERM_handler {
|
|
$log->error("Caught SIGTERM, exiting.");
|
|
exit 0;
|
|
}
|
|
|
|
|
|
__END__;
|
|
=head1 NAME
|
|
|
|
handbrake-cluster-worker - Processes DVD rips farmed out by gearman
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
handbrake-cluster-worker.pl -h
|
|
handbrake-cluster-worker.pl [-v [-d]|-q|-s]
|
|
[-l logfile]
|
|
[-n]
|
|
|
|
=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
|
|
|
|
=cut
|