X-Git-Url: https://diplodocus.org/git/flac-archive/blobdiff_plain/6aa2468770481c0e17a41760600b8a4eaff7a846..88f71cc4fb6076781e9479cbdfb22993cc84af1f:/flac2mp3 diff --git a/flac2mp3 b/flac2mp3 index 2231b1f..8964522 100755 --- a/flac2mp3 +++ b/flac2mp3 @@ -8,7 +8,7 @@ B - transcode FLAC file to MP3 files =head1 SYNOPSIS -B I +B [B<--lame-options> I] [B<-q>] [B<-v>] I =head1 DESCRIPTION @@ -22,13 +22,37 @@ and DATE tags. use strict; use warnings; +use POSIX ':sys_wait_h'; use Pod::Usage; +use Getopt::Long qw(:config gnu_getopt no_ignore_case); + +my $flac_options; +my $lame_options; +my $quiet; +my $verbose; + +sub run_or_die { + my $command = shift; + my $status; + + $verbose and print(STDERR "$command\n"); + $status = system($command); + + if (WIFEXITED($status)) { + if (($status = WEXITSTATUS($status)) != 0) { + die("$command exited with status $status"); + } + } elsif (WIFSIGNALED($status)) { + die("$command killed with signal ", WTERMSIG($status)); + } elsif (WIFSTOPPED($status)) { + die("$command stopped with signal ", WSTOPSIG($status)); + } else { + die("Major horkage on system($command): \$? = $? \$! = $!"); + } +} sub tformat { - my $min = shift; - my $sec = shift; - my $hun = shift; - return "$min:$sec.$hun"; + return sprintf('%02d:%02d.%02d', @_); } sub get_decode_args { @@ -48,10 +72,10 @@ sub get_decode_args { if (defined($next)) { if ($next->[2] == 0) { if ($next->[1] == 0) { - push(@$arg, '--until=' . tformat($next->[0] - 1, 59, 99)); + push(@$arg, '--until=' . tformat($next->[0] - 1, 59, 74)); } else { push(@$arg, '--until=' . tformat($next->[0], $next->[1] - 1, - 99)); + 74)); } } else { push(@$arg, '--until=' . tformat($next->[0], $next->[1], @@ -75,7 +99,8 @@ sub get_tags { my $date; my @titles; - open(TAGS, '-|', 'metaflac', '--export-vc-to=-', $fn); + open(TAGS, '-|', 'metaflac', '--export-vc-to=-', $fn) + or die("open(metaflac --export-vc-to=- $fn): $!"); while () { chomp; @@ -87,11 +112,14 @@ sub get_tags { $album = $value; } elsif (/^DATE=/) { $date = $value; - } elsif (/TITLE=/) { + + # Intentionally don't match the = on this one, to support the + # TITLE[1] .. TITLE[n] tag style. + } elsif (/^TITLE/) { push(@titles, $value); } } - close(TAGS) or die("close($fn): $!"); + close(TAGS) or die("close(metaflac --export-vc-to=- $fn): $?"); return ($artist, $album, $date, @titles); } @@ -105,19 +133,50 @@ sub flac2mp3 { my $track = shift; my $skip_arg = shift; my $until_arg = shift; + my @tmp; + my $outfile; + + if ($quiet) { + $flac_options = '--silent'; + } else { + $flac_options = ''; + } - my $outfile = sprintf("$artist ($album) \%02s $title.mp3", $track); + if ($lame_options) { + push(@tmp, $lame_options); + } else { + push(@tmp, '--preset standard'); + } + $quiet and push(@tmp, '--quiet'); + $verbose and push(@tmp, '--verbose'); + $lame_options = join(' ', @tmp); + + # We'll be putting these in single quotes, so we need to escape + # any single quotes in the filename by closing the quote ('), + # putting an escaped quote (\'), and then reopening the quote ('). + for ($fn, $title, $artist, $album, $date) { + s/'/'\\''/g; + } + + $outfile = sprintf("$artist ($album) \%02s $title.mp3", $track); $outfile =~ s/\//_/g; - $outfile =~ s/:/_/g; - $outfile =~ s/'/_/g; - $outfile =~ s/"/_/g; - # XXX $until_arg ||= ''; - system("flac -cd $skip_arg $until_arg '$fn' | lame --preset standard --tt '$title' --ta '$artist' --tl '$album' --ty '$date' --tn $track - '$outfile'"); + run_or_die(join(' ', "flac $flac_options -cd $skip_arg $until_arg '$fn'", + " | lame $lame_options --tt '$title' --ta '$artist'", + " --tl '$album' --ty '$date' --tn $track - '$outfile'")); } MAIN: { + my $help; + GetOptions( + 'lame-options=s', \$lame_options, + 'quiet|q' => \$quiet, + 'verbose|v' => \$verbose, + 'help|h|?' => \$help, + ) or pod2usage(); + $help and pod2usage(-exitstatus=>0, -verbose=>1); + my $fn = shift or pod2usage(); my @args = get_decode_args($fn); my ($artist, $album, $date, @titles) = get_tags($fn); @@ -131,6 +190,28 @@ MAIN: { __END__ +=head1 OPTIONS + +=over 4 + +=item B<--lame-options> I + +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<-q> [B<--quiet>] + +Suppress status information. This option is passed along to B +and B. + +=item B<-v> [B<--verbose>] + +Print diagnostic information. This option is passed along to B +and B. + +=back + =head1 AUTHORS Written by Eric Gillespie .