#!/usr/bin/perl
#
# Author: Espen Skoglund <espensk@stud.cs.uit.no>
# Date:   before 1999-02-08
#
# Rip music from CD and convert to MP3
#
# Hacked by Petter Reinholdtsen <pere@td.org.uit.no>, 1999-02-08

sub usage {
    print "USAGE: $0 [-h][-t] <topdir> [<start track> [<endtrack>]]\n";
}

use File::Path;

$rip_times_only = 0;
while ( $_ = shift ) {
  if ( /^-t$/ ) {
    $rip_times_only = 1;
  } elsif ( /^-?-h(elp)?$/ ) {
    $0 =~ s!.*/([^/]+)$!\1!;
    usage();
    exit;
  } else {
    push( @args, $_ );
  }
}
($topdir, $trbegin, $trend) = @args;

if ( ! $topdir ) {
  usage();
  exit;
}

$dagrab = find_prog_in_path("dagrab");
$cdparanoia = find_prog_in_path("cdparanoia");
$cdda2wav = find_prog_in_path("cdda2wav");
$gcdplay = find_prog_in_path("gcdplay");

$l3enc =  find_prog_in_path("l3enc");
$bladeenc =  find_prog_in_path("bladeenc");
$mp3_8hz =  find_prog_in_path("8hz-mp3");

# Choose encoder
if ( $l3enc ) {
  $mp3encoder = "$l3enc _infile_ _outfile_";
} elsif ( $bladeenc ) {
  $mp3encoder = "$bladeenc _infile_ _outfile_ -br 192000";
} elsif ( $mp3_8hz ) {
  $mp3encoder = "$mp3_8hz -b 128 _infile_ _outfile_";
}

$tmp = $ENV{TMPDIR} || '/tmp';

$[ = 1;

## Get artist and tracknages from CDDB
if ( $gcdplay ) {
  # extract online from CDDB
  open (GCDPLAY, "$gcdplay -q -i|") || die "open($gcdplay -q -i |): $!\n";
  while (<GCDPLAY>) {
    chomp;
    if (m/^CD TITLE:/) {
      ($artist) = m%^CD TITLE: (.+\S)\s*/[^/]+$%;
      ($title) = m%/\s*([^/]+)$%;
    }
    if (m/\d+: /) {
      my ($track, $name) = m/^(\d+): (.+)$/;
      $names[$track] = $name;
    }
  }
  close(GCDPLAY);
} else {
  print "Unable to find gcdplay.  It is required to fetch title and track\n";
  print "names from CDDB.  Fetch gcdplay from\n";
  print "<URL:http://www.korax.net/~mglisic/gcdplay/>.\n";
  exit;
}

if ($artist) {
  $artist =~ s%/%&%g;
  print "Artist: $artist\n";
  print "Title: $title\n";
  $destdir = "$topdir/$artist/$title";
  mkpath($destdir, 0, 0775);
} else {
  print "Error: CD is unknown to CDDB.  Unable to extract info, and\n";
  print "thereby unable to rip.  Add it to CDDB.\n";
  exit;
}
$numnames = scalar(@names);

## Get tracktimes
if ( $cdparanoia ) {
  open( TOC, "$cdparanoia -Q 2>&1|" ) || die "open(cdparanoia -Q |): $!\n";
  while( <TOC> ) {
    push( @times, $1 ) if /^\s*\d+\.\s*\d+\s*\[(\d+:\d*)/;
  }
  close TOC;
} elsif ( $dagrab ) {
  open( TOC, "$dagrab -i 2>&1|" ) || die "open(dagrab -i |): $!\n";
  while( <TOC> ) {
    push( @times, $1 ) if /\d\d:(\d\d:\d\d)/;
  }
  close TOC;
} elsif ( $gcdplay ) {
  open( TOC, "$gcdplay -di 2>&1|" ) || die "open(gcdplay -di |): $!\n";
  my (@starttimes, $endtime);
  while( <TOC> ) {
    chomp;
    $endtime = $1 * 60 + $2 if /^\d+ Tracks, (\d+) minutes and (\d+) seconds/;
    push(@starttimes, $1 * 60 + $2) if /minute: \[(\d+)\] second: \[(\d+)\]/;
  }
  close TOC;

  my $lasttime;
  for $time (@starttimes, $endtime) {
    if ($lasttime) {
      my $sec = $time - $lasttime;
      my $time = sprintf("%02d:%02d", int($sec / 60), ($sec%60));
      push(@times, $time);
    }
    $lasttime = $time;
  }
}
$numtracks = scalar(@times);

## Warn if the number of tracknames does not match number of tracks
if ( $numtracks && !$rip_times_only && $numnames != $numtracks ) {
  warn ("Warn: The number of names is not equal to the Number of ".
	"tracks on CD.\n      (Number of tracks = $numtracks, ".
	"number of names = $numnames)\n");
}
$trbegin = 1 unless $trbegin;
$trend = $numtracks if $numtracks && !$trend;

## Store tracktimes.
$timesfile = "$destdir/.times";
open( TIMES, ">$timesfile" ) || die "open(>$timesfile): $!\n";
foreach $time ( @times ) {
  print TIMES "$time\n";
}
close TIMES;

exit if $rip_times_only;

## Start processing the tracks
my $pid = 0;
foreach $track ( $trbegin .. $trend ) {

  # Get the track from the CD.
  if ( $cdda2wav ) {
    system "$cdda2wav -D /dev/cdrom -x -t $track+$track ".
      "$tmp/track-$track.wav 2>&-";
  } elsif ( $dagrab ) {
    system "$dagrab -f $tmp/track-$track.wav $track 2>/dev/null 1>/dev/null";
  } elsif ( $cdparanoia ) {
    system "$cdparanoia $track $tmp/track-$track.wav 2>&-";
  } else {
    die "I don't know of any cdrippers.\n";
  }

  # Wait for the previous encoding to get finished.
  waitpid( $pid, 0 ) if $pid != 0;

  # Fork off a new process that does the encoding.  We may then start
  # reading another track from the CD.
  unless ( $pid = fork ) {
    chdir($destdir);
    my $time = $times[$track];
    my $name = $names[$track] || "Track $track";
    my $mp3enc = $mp3encoder;
    my $destfile = sprintf( "%02d - %s.mp3", $track, $name );
    $destfile =~ s/\"/\\\"/g;
    $destfile =~ s/\\/\\\\/g;
    $mp3enc =~ s!_infile_!$tmp/track-$track.wav!;
    $mp3enc =~ s!_outfile_!\"$destfile\"!;

    print sprintf("Encoding: %02d - $name\n", $track);

    # MP3 encode the track
    system "$mp3enc >/dev/null 2>&1";

    # Remove temporary wav file.
    unlink "$tmp/track-$track.wav";
    exit;
  }

}

# Wait for last encoding to be finished
waitpid( $pid, 0 ) if $pid;

sub find_prog_in_path {
  my $prog = shift;
  for $dir (split(/:/, $ENV{PATH})) {
    my $fullpath = "$dir/$prog";
    return $fullpath if ( -x $fullpath );
  }
  return; # Not found
}

