X-Git-Url: https://diplodocus.org/git/flac-archive/blobdiff_plain/c96d51d20abdeefaf4e27377c6bfb69e20f5ea0e..fe8996f09b7acb90ff10342f05deeb6c038af045:/flac2mp3 diff --git a/flac2mp3 b/flac2mp3 index ab83c9f..842f0cd 100755 --- a/flac2mp3 +++ b/flac2mp3 @@ -8,7 +8,7 @@ B - transcode FLAC file to MP3 files =head1 SYNOPSIS -B [B<--lame-options> I] [B<-q>] [B<-v>] I [...] +B [B<--lame-options> I] [B<-j> I] [B<-q>] [B<-v>] I [...] =head1 DESCRIPTION @@ -19,6 +19,107 @@ ARTIST, ALBUM, and DATE tags. =cut +package Jobs; + +use strict; +use warnings; + +use Errno; +use POSIX ':sys_wait_h'; + +sub newjob { + my $f = shift; + my $jobs = shift; + my $debug = shift; + my $pid; + + if (not $debug) { + $pid = fork(); + if (not defined($pid)) { + die("fork: $!"); + } + } + + if ($debug or $pid == 0) { + exit($f->()); + } + + if ($pid == 0) { + exit($f->()); + } + + push(@$jobs, $pid); + + return $pid; +} + +sub deljob { + my $pid = shift; + my $status = shift; + my $jobs = shift; + + for (my $i = 0; $i <= $#$jobs; $i++) { + if ($pid == $jobs->[$i]) { + splice(@$jobs, $i, 1); + last; + } + } + + return ($pid, $status); +} + +sub run { + my %o = @_; + my $maxjobs = $o{'max-jobs'}; + my $get_job = $o{'get-job'}; + my $notify_start = $o{'notify-start'}; + my $notify_finish = $o{'notify-finish'}; + my @jobs; + my $pid; + + # Call notifier function if given. + sub call { + my $f = shift or return; + ref($f) eq 'CODE' or return; + $f->(@_); + } + + while (1) { + if (@jobs < $maxjobs) { + my $job; + while (defined($job = $get_job->())) { + $pid = newjob($job, \@jobs, $o{'debug'}); + call($notify_start, $pid, @jobs); + @jobs < $maxjobs or last; + } + + # No jobs running and get-job returned undef; we're finished. + if (@jobs == 0 and not defined($job)) { + return; + } + } + + # Now running as many jobs as we can, block waiting for one to die. + do { + $pid = waitpid(-1, 0); + } while ($pid == 0 + or ($pid == -1 and ($!{ECHILD} or $!{EINTR}))); + $pid == -1 and die("waitpid(-1): $!"); + + # Before starting more, see if any others have finished. + do { + call($notify_finish, deljob($pid, $?, \@jobs), @jobs); + } while (($pid = waitpid(-1, WNOHANG)) > 0); + if ($pid == -1) { + $!{ECHILD} or $!{EINTR} or die("waitpid(-1): $!"); + } + } +} + + +################################################################################ +package main; + use strict; use warnings; @@ -135,6 +236,11 @@ sub get_tags { } close(TAGS) or die("close(metaflac --export-vc-to=- $fn): $?"); + # If no TITLEs, stick a dummy in here. + if (@$titles == 0) { + push(@$titles, undef); + } + return ($artist, $album, $date, $discnum, $track); } @@ -151,10 +257,10 @@ sub arg { sub flac2mp3 { my $fn = shift; - my $title = shift; - my $artist = shift; - my $album = shift; - my $date = shift; + my $title = (shift or 'unknown'); + my $artist = (shift or 'unknown'); + my $album = (shift or 'unknown'); + my $date = (shift or 'unknown'); my $track = int(shift); my $skip_arg = shift; my $until_arg = shift; @@ -201,7 +307,11 @@ sub flac2mp3 { MAIN: { my $help; + my $debug; + my $maxjobs = 1; GetOptions( + 'debug|X' => \$debug, + 'jobs|j=i' => \$maxjobs, 'lame-options=s', \$lame_options, 'quiet|q' => \$quiet, 'verbose|v' => \$verbose, @@ -209,7 +319,9 @@ MAIN: { ) or pod2usage(); $help and pod2usage(-exitstatus=>0, -verbose=>1); - @ARGV or pod2usage(); + @ARGV > 0 or pod2usage(); + + my @jobs; for my $fn (@ARGV) { my @args = get_decode_args($fn); my (@artists, @titles); @@ -226,11 +338,18 @@ MAIN: { $track ||= 1; for my $i (0..$#titles) { - flac2mp3($fn, $titles[$i], ($artists[$i] or $artist), $album, $date, - $track, @{$args[$i]}); + push(@jobs, [$fn, $titles[$i], ($artists[$i] or $artist), $album, + $date, $track, @{$args[$i]}]); $track = $i + 2; } } + + Jobs::run('max-jobs'=>$maxjobs, + 'debug'=>$debug, + 'get-job'=>sub { + my $job = shift(@jobs) or return; + return sub { flac2mp3(@$job) } + }); } @@ -246,6 +365,10 @@ Pass I to B. This ends up being passed to the shell, so feel free to take advantage of that. You'll almost certainly have to put I in single quotes. +=item B<-j> [B<--jobs>] I + +Run up to I jobs instead of the default 1. + =item B<-q> [B<--quiet>] Suppress status information. This option is passed along to B