-#! /usr/bin/env zsh
+#! /usr/bin/env perl
# $Id$
+# $URL$
-set -e
-setopt NULL_GLOB
+=head1 NAME
-get_cddev () {
- local raw
- raw=$(sysctl -n kern.rawpartition > /dev/null | awk '{printf "%c",97+$0}')
+B<fa-rip> - rip a CD for B<fa-flacd>
- for CDDEV in /dev/{cdroms/cdrom*,cdrom*,rcd*${raw},{a,}cd*c}; do
- [[ -e ${CDDEV} ]] && return 0
- done
+=head1 SYNOPSIS
- return 1
+B<fa-rip> [B<-d> I<device>] [B<-t> I<track-count>]
+
+=cut
+
+use strict;
+use warnings;
+
+use Env qw(
+ CDDEV
+);
+
+use File::Temp;
+use Getopt::Long;
+use POSIX ':sys_wait_h';
+use Pod::Usage;
+
+use MusicBrainz::Client::Simple;
+
+sub run_or_die {
+ my $command = shift;
+ my $status;
+
+ system($command);
+
+ if (WIFEXITED($?)) {
+ $status = WEXITSTATUS($?);
+ if ($status != 0) {
+ die("$command exited $status");
+ }
+
+ } elsif (WIFSIGNALED($?)) {
+ $status = WTERMSIG($?);
+ die("$command signalled $status");
+
+ } elsif (WIFSTOPPED($?)) {
+ $status = WSTOPSIG($?);
+ die("$command stopped $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;
+}
+
+sub tags {
+ my $device = shift;
+ my $trackcount = shift;
+ my $mb;
+ my @results;
+ my $album;
+ my $i;
+ my @tracks;
+ my $name;
+ my $track;
+ my $j;
+
+ 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);
+ }
+
+ open(F, '>candidate-tags-0') or die("open('>candidate-tags-0'): $!");
+ print(F "$_=\n") for ('ARTIST', 'ALBUM', 'DATE');
+ print(F "TITLE=\n") for 1 .. $trackcount;
+ close(F) or die("close('>candidate-tags-0'): $!");
+
+ for $album (@results) {
+ $i++;
+ open(F, ">candidate-tags-$i") or die("open(>candidate-tags-$i): $!");
+
+ print(F 'ARTIST=', $album->get_artist->get_name, "\n");
+ print(F 'ALBUM=', $album->get_name, "\n");
+
+ # MusicBrainz doesn't have dates yet; these are usually wrong anyway.
+ print(F "DATE=\n");
+
+ @tracks = $album->get_tracks;
+ for $j (1 .. $trackcount) {
+ if ($track = shift(@tracks)) {
+ $name = $track->get_name;
+ } else {
+ $name = '';
+ }
+ print(F "TITLE=$name\n");
+ }
+
+ close(F) or die("close(>candidate-tags-$i): $!");
+ }
+}
+
+sub rip {
+ my $device = shift;
+ my $trackcount = shift;
+
+ $device ||= '/dev/cdrom';
+
+ print"$_\n" for ('cdparanoia', '-d', $device, "1-$trackcount", 'wav');
+ exec('cdparanoia', '-d', $device, "1-$trackcount", 'wav');
+ # exec prints its own error message so just
+ die;
+}
+
+MAIN: {
+ my $trackcount;
+ my $help;
+ my $tempdir;
+
+ GetOptions(
+ 'device|d=s' => \$CDDEV,
+ '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): $!");
+
+ $trackcount = mkcue($CDDEV, $trackcount);
+ tags($CDDEV, $trackcount);
+ rip($CDDEV, $trackcount);
}
-if [[ -z ${CDDEV} ]]; then
- if ! get_cddev; then
- echo 'CDDEV environment variable not set, defaults did not work'
- exit 2
- fi
-fi
+\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<-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>.
-cdrdao read-toc --device ${CDDEV} --driver generic-mmc toc
-toc2cue toc 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: