]> diplodocus.org Git - flac-archive/blobdiff - fa-rip
(flac2mp3): Force track number argument to int.
[flac-archive] / fa-rip
diff --git a/fa-rip b/fa-rip
index 627ac739ee3f9645680e52f3ed527de813fb24e7..e9ad756855d22c46764af369d2162285164ac00f 100755 (executable)
--- a/fa-rip
+++ b/fa-rip
-#! /usr/bin/env zsh
+#! /usr/bin/env perl
 
 # $Id$
+# $URL$
 
-set -e
+=head1 NAME
 
-function get_cddev {
-    typeset raw
-    raw=$(sysctl -n kern.rawpartition > /dev/null | awk '{printf "%c",97+$0}')
+B<fa-rip> - rip a CD for B<fa-flacd>
 
-    if [[ -n ${ZSH_VERSION} ]]; then
-        setopt NULL_GLOB
-    fi
+=head1 SYNOPSIS
 
-    for CDDEV in /dev/{cdroms/cdrom*,cdrom*,rcd*${raw},{a,}cd*c}; do
-        [[ -e ${CDDEV} ]] && return 0
-    done
+B<fa-rip> [B<-d> I<device>] [B<-p> I<post-processor> [B<-t> I<track-count>]
 
-    return 1
+=cut
+
+use strict;
+use warnings;
+
+use Env qw(
+           CDDEV
+);
+
+use Fcntl qw(O_CREAT O_WRONLY);
+use File::Temp;
+use Getopt::Long qw(:config gnu_getopt no_ignore_case);
+use POSIX ':sys_wait_h';
+use Pod::Usage;
+
+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");
+    }
+
+    if (defined($device)) {
+        push(@command, $device);
+    }
+
+    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);
+    }
+
+    return $trackcount;
 }
 
-if [[ -z ${CDDEV} ]]; then
-    if ! get_cddev; then
-        echo 'CDDEV environment variable not set, defaults did not work' >&2
-        exit 2
-    fi
-    export CDDEV
-fi
+sub tags_file {
+    my $fn = shift;
+    my $trackcount = shift;
+    my $various = shift;
+    my $artist = shift;
+    my $album = shift;
+    my $fh;
+    my $i;
+    my $track;
+    my $name;
+
+    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");
+
+    for $i (1 .. $trackcount) {
+        $various and print($fh "ARTIST[$i]=\n");
+        if ($track = shift(@_)) {
+            $name = $track->get_name;
+        } else {
+            $name = '';
+        }
+        print($fh "TITLE[$i]=$name\n");
+    }
+
+    close($fh) or die("close(>$fn): $!");
+}
+
+sub tags {
+    my $device = shift;
+    my $trackcount = shift;
+    my $mb;
+    my @results;
+    my $album;
+    my $i;
+    my $various;
+    my $seen_various;
+
+    if (defined($device)) {
+        $mb = new MusicBrainz::Client::Simple (device=>$device);
+    } else {
+        $mb = new MusicBrainz::Client::Simple;
+    }
+
+    @results = $mb->lookup_cd;
+    if (not $mb->success) {
+        die($mb->get_error);
+    }
+
+    tags_file('candidate-tags-0', $trackcount, 0);
+
+    for $album (@results) {
+        $i++;
+
+        if ($various = $album->has_various_artists) {
+            if (not $seen_various) {
+                $seen_various = 1;
+                tags_file('candidate-tags-0v', $trackcount, 1);
+            }
+        }
+
+        tags_file("candidate-tags-$i", $trackcount, $various,
+                  $album->get_artist->get_name, $album->get_name,
+                  $album->get_tracks);
+    }
+}
+
+sub rip {
+    my $device = shift;
+    my $trackcount = shift;
+
+    $device ||= '/dev/cdrom';
+
+    exec('cdparanoia', '-d', $device, "1-$trackcount", 'wav');
+    # exec prints its own error message so just
+    die;
+}
+
+sub make_post_processor {
+    my $command = shift;
+
+    defined($command) or return;
+
+    sysopen(F, 'post-processor', O_CREAT | O_WRONLY, 0555)
+      or die("sysopen(post-processor, O_CREAT | O_WRONLY, 0555): $!");
+    print(F $command, ' "$@"', "\n");
+    close(F) or die("close(post-processor, O_CREAT | O_WRONLY, 0555): $!");
+}
+
+MAIN: {
+    my $post_processor;
+    my $trackcount;
+    my $help;
+    my $tempdir;
+
+    GetOptions(
+               'device|d=s' => \$CDDEV,
+               'post-processor|p=s', \$post_processor,
+               'tracks|t=i' => \$trackcount,
+               'help|h|?' => \$help,
+              ) or pod2usage();
+    $help and pod2usage(-exitstatus=>0, -verbose=>1);
+
+    # File::Temp::tempdir calls die on error.
+    $tempdir = File::Temp::tempdir('flac-archive.XXXXXXXXXX');
+    chdir($tempdir) or die("chdir($tempdir): $!");
+
+    make_post_processor($post_processor);
+    $trackcount = mkcue($CDDEV, $trackcount);
+    tags($CDDEV, $trackcount);
+    rip($CDDEV, $trackcount);
+}
+
+\f
+__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.
+
+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
+candidate-tags files and deleting the others.  Don't forget to fill in
+the DATE tag in the selected candidate before renaming it.  If
+B<fa-rip> could not find any tag information from MusicBrainz, you'll
+have to fill out the candidate-tags-0 template.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-d> [B<--device>] I<device>
+
+Use I<device> as the CD-ROM device, instead of the default
+"/dev/cdrom" or the environment variable CDDEV.
+
+=item B<-p> [B<--post-processor>] I<post-processor>
+
+Create a "post-processor" file in the temporary directory containing
+the line 'I<post-processor> "$@"'.  See B<fa-flacd>'s man page for
+information about this hook.
+
+=item B<-t> [B<--tracks>] I<track-count>
+
+Archive only the first I<track-count> tracks.  This is handy for
+ignoring data tracks.
+
+=back
+
+=head1 ENVIRONMENT
+
+=over 4
+
+=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.
+
+=back
+
+=head1 AUTHORS
 
-dir=$(mktemp -d flac-archive.XXXXXXXXXX)
-cd ${dir}
+Written by Eric Gillespie <epg@pretzelnet.org>.
 
-mkcue ${CDDEV} > cue
+flac-archive is free software; you may redistribute it and/or modify
+it under the same terms as Perl itself.
 
-trackcount=$(grep -c 'TRACK.*AUDIO' cue)
+=cut
 
-fa-tags ${trackcount}
+# Local variables:
+# cperl-indent-level: 4
+# perl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
 
-exec cdparanoia -d ${CDDEV} 1-$(grep -c 'TRACK.*AUDIO' cue) wav
+# vi: set tabstop=4 expandtab: