#! /usr/bin/env perl # $Id$ =head1 NAME B - transcode FLAC file to MP3 files =head1 SYNOPSIS B I =head1 DESCRIPTION B transcodes the FLAC file I to MP3 files. I is the kind of FLAC file B generates. That is, it contains a cue sheet, one TITLE tag per track listed therein, and ARTIST, ALBUM, and DATE tags. =cut use strict; use warnings; use POSIX ':sys_wait_h'; use Pod::Usage; sub run_or_die { my $command = shift; my $status; $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 { return sprintf('%02d:%02d.%02d', @_); } sub get_decode_args { my $fn = shift; my @l; open(F, '-|', 'metaflac', '--export-cuesheet-to=-', $fn); while () { /INDEX 01 (\d\d):(\d\d):(\d\d)$/ or next; push(@l, [$1, $2, $3]); } my @args; for my $i (0..$#l) { my $arg = ["--skip=" . tformat(@{$l[$i]})]; my $next = $l[$i+1]; if (defined($next)) { if ($next->[2] == 0) { if ($next->[1] == 0) { push(@$arg, '--until=' . tformat($next->[0] - 1, 59, 74)); } else { push(@$arg, '--until=' . tformat($next->[0], $next->[1] - 1, 74)); } } else { push(@$arg, '--until=' . tformat($next->[0], $next->[1], $next->[2] - 1)); } } push(@args, $arg); } return @args; } # Return the ARTIST, ALBUM, and DATE tags followed by the TITLE tags # in the file FN. sub get_tags { my $fn = shift; my $tag; my $value; my $artist; my $album; my $date; my @titles; open(TAGS, '-|', 'metaflac', '--export-vc-to=-', $fn) or die("open(metaflac --export-vc-to=- $fn): $!"); while () { chomp; ($tag, $value) = split(/=/, $_, 2); if (/^ARTIST=/) { $artist = $value; } elsif (/^ALBUM=/) { $album = $value; } elsif (/^DATE=/) { $date = $value; } elsif (/TITLE/) { push(@titles, $value); } } close(TAGS) or die("close(metaflac --export-vc-to=- $fn): $?"); return ($artist, $album, $date, @titles); } sub flac2mp3 { my $fn = shift; my $title = shift; my $artist = shift; my $album = shift; my $date = shift; my $track = shift; my $skip_arg = shift; my $until_arg = shift; my $outfile; # 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; $until_arg ||= ''; run_or_die(join(' ', "flac -cd $skip_arg $until_arg '$fn'", " | lame --preset standard --tt '$title' --ta '$artist'", " --tl '$album' --ty '$date' --tn $track - '$outfile'")); } MAIN: { my $fn = shift or pod2usage(); my @args = get_decode_args($fn); my ($artist, $album, $date, @titles) = get_tags($fn); for my $i (0..$#titles) { flac2mp3($fn, $titles[$i], $artist, $album, $date, $i + 1, @{$args[$i]}); } } __END__ =head1 AUTHORS Written by Eric Gillespie . =cut # Local variables: # cperl-indent-level: 4 # perl-indent-level: 4 # indent-tabs-mode: nil # End: # vi: set tabstop=4 expandtab: