]> diplodocus.org Git - flac-archive/blobdiff - fa-rip
Fix a job in Jobs::run (@jobs < $maxjobs, not <=) and icky icky
[flac-archive] / fa-rip
diff --git a/fa-rip b/fa-rip
index e9ad756855d22c46764af369d2162285164ac00f..22140a54a4991601bddcc2be661d242e3d429e32 100755 (executable)
--- a/fa-rip
+++ b/fa-rip
@@ -23,53 +23,59 @@ use Env qw(
 use Fcntl qw(O_CREAT O_WRONLY);
 use File::Temp;
 use Getopt::Long qw(:config gnu_getopt no_ignore_case);
+use List::Util qw(min);
 use POSIX ':sys_wait_h';
 use Pod::Usage;
 
+use MusicBrainz::Client;
+use MusicBrainz::Queries qw(
+                            MBQ_GetCDTOC
+                            MBE_TOCGetFirstTrack
+                            MBE_TOCGetLastTrack
+                            MBE_TOCGetTrackSectorOffset
+);
 use MusicBrainz::Client::Simple;
 
-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 mkcue {
     my $device = shift;
     my $trackcount = shift;
-    my @command;
 
-    push(@command, 'mkcue');
-
-    if (defined($trackcount)) {
-        push(@command, "-t $trackcount");
-    }
+    my $mb = MusicBrainz::Client->new;
+    defined($device) and $mb->set_device($device);
+
+    $mb->query(MBQ_GetCDTOC) or die($mb->get_query_error);
+
+    open(my $fh, '>cue') or die("open('>cue'): $!");
+    print($fh "FILE \"dummy.wav\" WAVE\n");
+    print($fh "  TRACK 01 AUDIO\n");
+    print($fh "    INDEX 01 00:00:00\n");
+
+    my $first = $mb->get_result_data(MBE_TOCGetFirstTrack) + 1;
+    $trackcount = min($trackcount, $mb->get_result_data(MBE_TOCGetLastTrack));
+    # There is frequently (always?) an offset of 150 sectors, so
+    # we'll subtract this offset from each track offset.
+    my $something = $mb->get_result_data1(MBE_TOCGetTrackSectorOffset, 2);
+
+    for my $track ($first .. $trackcount) {
+        my $off = $mb->get_result_data1(MBE_TOCGetTrackSectorOffset, $track+1);
+        $off -= $something;
+
+        my ($minutes,$seconds)=(0,0);
+        my $sectors = $off % 75;
+        if ($off >= 75) {
+            $seconds = $off / 75;
+            if ($seconds >= 60) {
+                $minutes = $seconds / 60;
+                $seconds = $seconds % 60;
+            }
+        }
 
-    if (defined($device)) {
-        push(@command, $device);
+        printf($fh "  TRACK %02d AUDIO\n", $track);
+        printf($fh "    INDEX 01 %02d:%02d:%02d\n",
+               $minutes, $seconds, $sectors);
     }
 
-    push(@command, '> cue');
-    run_or_die(join(' ', @command));
-
-    if (not defined($trackcount)) {
-        open(F, 'cue') or die("open(cue): $!");
-        $trackcount = grep(/TRACK.*AUDIO/, <F>);
-        close(F);
-    }
+    close($fh) or die("close(>cue): $!");
 
     return $trackcount;
 }
@@ -80,6 +86,7 @@ sub tags_file {
     my $various = shift;
     my $artist = shift;
     my $album = shift;
+    my $release_dates = shift;
     my $fh;
     my $i;
     my $track;
@@ -88,8 +95,14 @@ sub tags_file {
     open($fh, '>', $fn) or die("open('>$fn'): $!");
     print($fh 'ARTIST=', (defined($artist) and $artist or ''), "\n");
     print($fh 'ALBUM=', (defined($album) and $album or ''), "\n");
-    # MusicBrainz doesn't have dates yet; these are usually wrong anyway.
-    print($fh "DATE=\n");
+
+    if (defined($release_dates) and %$release_dates) {
+        while (my ($country, $date) = each(%$release_dates)) {
+            print($fh "DATE[$country]=$date\n");
+        }
+    } else {
+        print($fh "DATE=\n");
+    }
 
     for $i (1 .. $trackcount) {
         $various and print($fh "ARTIST[$i]=\n");
@@ -107,6 +120,7 @@ sub tags_file {
 sub tags {
     my $device = shift;
     my $trackcount = shift;
+    my $no_mb = shift;
     my $mb;
     my @results;
     my $album;
@@ -114,6 +128,10 @@ sub tags {
     my $various;
     my $seen_various;
 
+    tags_file('candidate-tags-0', $trackcount, 0);
+
+    defined($no_mb) and $no_mb and return;
+
     if (defined($device)) {
         $mb = new MusicBrainz::Client::Simple (device=>$device);
     } else {
@@ -125,8 +143,6 @@ sub tags {
         die($mb->get_error);
     }
 
-    tags_file('candidate-tags-0', $trackcount, 0);
-
     for $album (@results) {
         $i++;
 
@@ -137,20 +153,27 @@ sub tags {
             }
         }
 
+        my %dates = $album->get_release_dates;
         tags_file("candidate-tags-$i", $trackcount, $various,
                   $album->get_artist->get_name, $album->get_name,
-                  $album->get_tracks);
+                  \%dates, $album->get_tracks);
     }
 }
 
 sub rip {
     my $device = shift;
     my $trackcount = shift;
+    my $single_file = shift;
+    my @output;
 
     $device ||= '/dev/cdrom';
+    if ($single_file) {
+        @output = ("1-$trackcount", 'wav');
+    } else {
+        @output = ('-B');
+    }
 
-    exec('cdparanoia', '-d', $device, "1-$trackcount", 'wav');
-    # exec prints its own error message so just
+    exec('cdparanoia', '-d', $device, @output);
     die;
 }
 
@@ -166,14 +189,18 @@ sub make_post_processor {
 }
 
 MAIN: {
+    my $no_mb;
     my $post_processor;
-    my $trackcount;
+    my $single_file;
+    my $trackcount = 99;
     my $help;
     my $tempdir;
 
     GetOptions(
                'device|d=s' => \$CDDEV,
+               'no-musicbrainz|m' => \$no_mb,
                'post-processor|p=s', \$post_processor,
+               'single-file|s' => \$single_file,
                'tracks|t=i' => \$trackcount,
                'help|h|?' => \$help,
               ) or pod2usage();
@@ -185,8 +212,8 @@ MAIN: {
 
     make_post_processor($post_processor);
     $trackcount = mkcue($CDDEV, $trackcount);
-    tags($CDDEV, $trackcount);
-    rip($CDDEV, $trackcount);
+    tags($CDDEV, $trackcount, $no_mb);
+    rip($CDDEV, $trackcount, $single_file);
 }
 
 \f
@@ -195,9 +222,9 @@ __END__
 =head1 DESCRIPTION
 
 B<fa-rip> creates a temporary directory for storage of its
-intermediate files, runs C<mkcue(1)> to create the "cue" file, uses
-MusicBrainz to generate candidate tags files, and runs
-C<cdparanoia(1)> to rip the CD to the "wav" file.
+intermediate files, uses MusicBrainz to create the "cue" file and
+candidate tags files, and runs C<cdparanoia(1)> to rip the CD to the
+"wav" file.
 
 In order for this CD to be processed by B<fa-flacd>, you must create a
 "tags" file.  This is usually done by renaming one of the
@@ -234,9 +261,8 @@ ignoring data tracks.
 
 =item CDDEV
 
-B<fa-rip> uses this to rip audio and save the cuesheet for a CD.  It
-makes some effort to check some common device names for FreeBSD,
-Linux, and NetBSD by default.
+B<fa-rip> uses this to rip audio and save the cuesheet for a CD.
+MusicBrainz::Client can usually figure this out automatically.
 
 =back