#!/usr/bin/perl
#
#    rip -- A command line based, audio Compact Disc (CD) track to
#    Motion Picture Experts Group Layer 3 (MP3) file, ripper.
#
#    Copyright (C) 2001 Gregory Smethells
#
#
#    License:
#    This program is free software; you can redistribute it and/or
#    modify it under the terms of the GNU General Public License
#    as published by the Free Software Foundation; either version 2
#    of the License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#    02111-1307, USA.
#
#
#    Author's Notes:
#    This script requires cdparanoia and bladeenc to be on your path,
#    since it is essentially only a wrapper. All major functionality is
#    found in those two programs. However, I believe that the abstract
#    functionality provided by this script is quite useful.
#
#
#    Disclaimer:
#    YOU SHOULD ONLY ENCODE MP3s FROM AUDIO CDs THAT YOU OWN LEGALLY.
#    ANY OTHER USE OF THIS SCRIPT IS NOT LEGAL, IS NOT CONDONED BY THIS
#    AUTHOR, NOR IS SUCH ACTION IN THE SPIRIT OF THIS SCRIPT. THE AUTHOR
#    TAKES NO RESPONSIBILITY FOR MIS-USE OF THIS SOFTWARE OR RELATED
#    SOFTWARE.
#



##########################################################################
#                                                                        #
# DECLARATIONS                                                           #
#                                                                        #
##########################################################################

use Cwd;
use Time::localtime;


$time            = localtime(time());
$now             = $time->mon . $time->mday . $time->hour . $time->min . $time->sec;

$date            = "2001-2-8";      # Date of last modification
$version         = "0.65";          # Version number for this script

$tempFile        = "/tmp/rip-$now"; # Default temp file
$DEFAULT_DIR     = getcwd;          # Default "default directory"
$cwd             = $DEFAULT_DIR;    # For convience
$outputDir       = $DEFAULT_DIR;    # Default directory where output is placed
$wavONLY         = "false";         # Default is to encode CD tracks to MP3

$cdparanoiaFlags = "-B";            # Default cdparanoia flags
$bladeencFlags   = "-del";          # Default bladeenc flags



##########################################################################
#                                                                        #
# MAIN SCRIPT                                                            #
#                                                                        #
##########################################################################

# Make sure we have our tools available on the $PATH first...

chop( $cdparanoiaPath = `which cdparanoia` );
chop( $bladeencPath   = `which bladeenc`   );

$cdparanoiaFOUND = ( $cdparanoiaPath =~ /cdparanoia/ );
$bladeencFOUND   = ( $bladeencPath   =~ /bladeenc/   );

if( !( $bladeencFOUND )  ) {
  chop( $bladeencPath = `which BladeEnc` );
  $bladeencFOUND = ( $bladeencPath =~ /BladeEnc/ );

  if( $bladeencFOUND ) {
    print( "rip: \"bladeenc\" found under alternate name: \"BladeEnc\"\n" );
    print( "rip: BladeEnc absolute path: $bladeencPath\n" );
    print( "rip: To not see these messages again have root run the\n" );
    print( "rip: command:  mv $bladeencPath /usr/local/bin/bladeenc\n" );
  }
}


# ...then proceed accordingly

if( !($cdparanoiaFOUND) || !($bladeencFOUND) ) {
  # Prints an error message and exits the script NOW
  &abort;
}
else {
  $case =   ( $ARGV[0] =~ /^-/  )  &&  "flag"     # Either there're flags
         || ( $ARGV[0] =~ /\d/	)  &&  "encode"   # or just digits
         ||                            "default"; # or no args at all

  # Prints a usage message and exits the script IFF there are NO args
  if( $case eq "default" ) {
    &usage;
  }

  # Parse any flags if they exist in the argument list (sets GLOBAL vars)
  if( $case eq "flag" ) {
    &parseFlags;
    &handleFlags;
  }

  # Encode the requested tracks accordingly
  &parseTracks;
  &setNames;
  &encode;
}

exit( 0 );



##########################################################################
#                                                                        #
# SUBROUTINES                                                            #
#                                                                        #
##########################################################################


##########################################################################
#                                                                        #
# SUB: parseFlags                                                        #
#                                                                        #
#   Parses arguments (flags) given to rip. Once it is determined what    #
#   flags have been given, either GLOBAL variables that sub encode       #
#   looks at are set or functions such as cdparanoia's query are run.    #
#                                                                        #
##########################################################################

sub parseFlags {
  while( $ARGV[0] =~ /^-/ ) {

    # Parse flags of the form:  --query

    $item =   ( $ARGV[0] =~ /^--help/     )  &&  "help"
           || ( $ARGV[0] =~ /^--query/    )  &&  "query"
           || ( $ARGV[0] =~ /^--version/  )  &&  "version"
           || ( $ARGV[0] =~ /^--verbose/  )  &&  "verbose"
           || ( $ARGV[0] =~ /^--paranoia/ )  &&  "paranoia"
           || ( $ARGV[0] =~ /^--quiet/    )  &&  "quiet"
           || ( $ARGV[0] =~ /^--rename/   )  &&  "rename"
           || ( $ARGV[0] =~ /^--bitrate=/ )  &&  "bitrate"
           || ( $ARGV[0] =~ /^-b=/        )  &&  "bitrate"
           || ( $ARGV[0] =~ /^--move=/    )  &&  "move"
           || ( $ARGV[0] =~ /^-m=/        )  &&  "move"
           || ( $ARGV[0] =~ /^--wav/      )  &&  "wav"
           || ( $ARGV[0] =~ /^-s=/        )  &&  "cdspeed"
           || ( $ARGV[0] =~ /^--speed=/   )  &&  "cdspeed"
           || ( $ARGV[0] =~ /^-d=/        )  &&  "device"
           || ( $ARGV[0] =~ /^--dev=/     )  &&  "device"
           || ( $ARGV[0] =~ /^--cddb/     )  &&  "cddb"
           || ( $ARGV[0] =~ /^--lazy/     )  &&  "lazy"
           ||                                    "unknown";


    # Parse out value given to bitrate=, move=, speed=,
    # or dev= when argument is in one of those formats.

    $revArg = reverse( $ARGV[0] );
    chop($revArg); chop($revArg); chop($revArg);

    if( $ARGV[0] =~ /^--bitrate=/ ) {
      chop($revArg); chop($revArg); chop($revArg); chop($revArg);
      chop($revArg); chop($revArg); chop($revArg);
      $kbps = reverse( $revArg );
    }
    elsif( $ARGV[0] =~ /^-b=/ ) {
      $kbps = reverse( $revArg );
    }
    elsif( $ARGV[0] =~ /^--move=/ ) {
      chop($revArg); chop($revArg); chop($revArg); chop($revArg);
      $outputDir = reverse( $revArg );
      $outputDir = $outputDir . "\/";
    }
    elsif( $ARGV[0] =~ /^-m=/ ) {
      $outputDir = reverse( $revArg );
      $outputDir = $outputDir . "\/";
    }
    elsif( $ARGV[0] =~ /^--speed=/ ) {
      chop($revArg); chop($revArg); chop($revArg); chop($revArg); chop($revArg);
      $speed = reverse( $revArg );
    }
    elsif( $ARGV[0] =~ /^-s=/ ) {
      $speed = reverse( $revArg );
    }
    elsif( $ARGV[0] =~ /^--dev=/ ) {
      chop($revArg); chop($revArg); chop($revArg);
      $dev = reverse( $revArg );
    }
    elsif( $ARGV[0] =~ /^-d=/ ) {
      $dev = reverse( $revArg );
    }


    if( $item ne "unknown" ) {
      # Accumulate the $item to be dealt with later or...

      @flagsToCheck = ( $item, @flagsToCheck );
    }
    else {
      # ...parse flags of the form:  -Qpr

      while( $ARGV[0] =~ /^-\w/ ) {
        $check = chop( $ARGV[0] );

        $item =   ( $check =~ /h/  )  &&  "help"
               || ( $check =~ /q/  )  &&  "query"
               || ( $check =~ /V/  )  &&  "version"
               || ( $check =~ /v/  )  &&  "verbose"
               || ( $check =~ /p/  )  &&  "paranoia"
               || ( $check =~ /Q/  )  &&  "quiet"
               || ( $check =~ /r/  )  &&  "rename"
               || ( $check =~ /w/  )  &&  "wav"
               || ( $check =~ /c/  )  &&  "cddb"
               || ( $check =~ /l/  )  &&  "lazy"
               ||                         "default";

        @flagsToCheck = ( $item, @flagsToCheck );
      }
    }

    shift( @ARGV );
  }
}



##########################################################################
#                                                                        #
# SUB: handleFlags                                                       #
#                                                                        #
#   Once parseFlags sets up the @flagsToCheck array, handleFlags may     #
#   run through the array, taking appropriate action. These actions can  #
#   include, and are not limited to: setting cdparaoniaFlags or setting  #
#   bladeencFlags, querying & exiting, calling usage & exiting, and      #
#   printing out version info. Many switches only set flags and do not   #
#   exit the script.                                                     #
#                                                                        #
##########################################################################

sub handleFlags {
  # Finished parsing the ARGV array. Now determine how to
  # flag cdparanoia and bladeenc; possibly reacting, calling
  # subroutines abort or usage, even exit.

  foreach $flag ( @flagsToCheck ) {
    if( $flag eq "query" ) {
      print( "\n***************************************\n"    );
      print( "The contents of the CD are as follows:\n"       );
      print( "***************************************\n\n"  );
      `cdparanoia -sQ`;
      print( "\n" );

      exit( 0 );
    }
    elsif( $flag eq "version" ) {
      print( "\n" );
      `cdparanoia --version`;
      print( "\n\n" );
      print( `bladeenc version` );
      print( "\n\n\n\n"                                                   );
      print( "########################################################\n" );
      print( "#     rip  --  Created by Greg Smethells (c) 2001      #\n" );
      print( "########################################################\n" );
      print( "# Current version: $version was last modified on $date #\n" );
      print( "# Please report bugs and/or email your suggestions to  #\n" );
      print( "#             gsmethells\@linuxfreak.com                #\n" );
      print( "#    http://www.linuxfreak.com/~gsmethells/rip.html    #\n" );
      print( "########################################################\n" );
      print( "\n\n"                                                       );

      exit( 0 );
    }
    elsif( $flag eq "paranoia" ) {
      $cdparanoiaFlags = $cdparanoiaFlags . " --never-skip ";
      $bladeencFlags   = $bladeencFlags   . " -br 160 ";
    }
    elsif( $flag eq "bitrate" ) {
      if( !($kbps =~ /\d{1,}/) ) {
        print( "Invalid bitrate ${kbps}. Aborting.\n" );
        exit( 2 );
      }

      $bladeencFlags = $bladeencFlags . " -br " . $kbps;
    }
    elsif( $flag eq "device" ) {
      if( $dev =~ /^\/dev\// ) {
        $cdparanoiaFlags = $cdparanoiaFlags . " --force-cdrom-device " . $dev;
      }
      else {
        print( "Invalid device: ${dev}. Aborting.\n" ) ;
        exit( 3 );
      }
    }
    elsif( $flag eq "cddb" ) {
      $checkDatabase = "true";
    }
    elsif( $flag eq "lazy" ) {
      @flagsToCheck = (@flagsToCheck, "paranoia" );
      @flagsToCheck = (@flagsToCheck, "cddb"     );
      @flagsToCheck = (@flagsToCheck, "quiet"    );

      $lazy = "true";
    }
    elsif( $flag eq "cdspeed" ) {
      if( $speed > 50 || $speed < 0 ) {
        print( "\nCD read speed should be ${speed}?\n" );
        print( "Are you sure (y/N)? " );
        chop( $answer = <STDIN> );

        if( $answer =~ /^[yY]/ ) {
          $cdparanoiaFlags = $cdparanoiaFlags . " --force-read-speed " . $speed;
        }
      }
      else {
        if(  !( $speed =~ /\d/ )  ) {
          print( "Invalid CD read speed: ${speed}. Aborting.\n" );
          exit( 4 );
        }
        else {
          $cdparanoiaFlags = $cdparanoiaFlags . " --force-read-speed " . $speed;
        }
      }
    }
    elsif( $flag eq "rename" ) {
      $renameTracks = "true";
    }
    elsif( $flag eq "move" ) {
      if(  !( -e $outputDir && -w $outputDir )  ) {
        `mkdir $outputDir`;

        if(  !( -e $outputDir && -w $outputDir )  ) {
          print( "Either the output directory $outputDir cannot be created\n" );
          $outputDir = $DEFAULT_DIR;
          print( "or it is not writable. Output will be to $outputDir instead.\n" );
        }
        else {
          $moveIt   = "true";
          $finalDir = $outputDir;
        }
      }
    }
    elsif( $flag eq "quiet"  ) {
      $cdparanoiaFlags = $cdparanoiaFlags . " --quiet ";
      $bladeencFlags   = $bladeencFlags   . " -quiet ";
    }
    elsif( $flag eq "wav" ) {
      $wavONLY = "true";
    }
    elsif( $flag eq "verbose" ) {
      $cdparanoiaFlags = $cdparanoiaFlags . " -v ";
    }
    elsif( $flag eq "help" || $flag eq "default" ) {
      &usage;
    }
    else {
      print( "rip:  Unknown flag \"${flag}\". It will be ignored.\n" );
    }
  }
}



##########################################################################
#                                                                        #
# SUB: parseTracks                                                       #
#                                                                        #
#   Parses the track list argument to rip. Then set @trackList to show   #
#   what tracks to handle.
#                                                                        #
##########################################################################

sub parseTracks {
  # Parse the tracks list given after the flags
  while( $ARGV[0] =~ /\d/ ) {
    # Determine if the user used a dash or spaced number format
    if( $ARGV[0] =~ /^\d{1,2}-\d{1,2}$/ ) {      # USED DASHED
      $char  = chop( $ARGV[0] );
      $start = "";
      $end   = "";

      while( $char ne '-' ) {
        $end  = $char . $end;
        $char = chop( $ARGV[0] );
      }

      $start = $ARGV[0];

      @trackList = ( @trackList, ${start}..${end} );
    }
    elsif( $ARGV[0] =~ /^\d{1,2}$/ ) {           # USED SPACED
      @trackList = ( @trackList, $ARGV[0] );
    }
    else {                                       # ELSE IGNORE
      print( "Sorry. Cannot rip \"$ARGV[0]\"\n" );
      $case = "default";
    }

    shift( @ARGV );
  }

  if( @trackList != 0 ) {
    print( "\n\nRipping the following track(s):  @trackList\n\n" );
  }
}



##########################################################################
#                                                                        #
# SUB: setNames                                                          #
#                                                                        #
#   If the track are to be renamed after encoding, then request or set   #
#   the names to be used for each track now.                             #
#                                                                        #
##########################################################################

sub setNames {
  if( $checkDatabase eq "true" && $renameTracks eq "true" ) {
    print( "\nOnly ONE of these flags can be used \n" );
    print( "at the same time: -c, --cddb, -r, --rename\n\n" );
    &abort;
  }

  if( $renameTracks eq "true" && $wavONLY eq "false" ) {
    &manualRename;
  }

  if( $checkDatabase eq "true" && !($renameTracks eq "true") ) {
    &cddbRename;
  }

  if( $lazy eq "true" ) {
    &beLazy;
  }
}



##########################################################################
#                                                                        #
# SUB: manualRename                                                      #
#                                                                        #
#   Prompt the user, manually, to give the name for each track which is  #
#   to be ripped to MP3.
#                                                                        #
##########################################################################

sub manualRename {
  # Get the names to rename MP3s to, if so requested (flagged)
  print( "\n****************************************************\n" );
  print( "We will now take the proper names for the mp3 files.\n" );
  print( "EXAMPLE:  Riders_On_The_Storm.mp3\n\n"                  );
  print( "You may remove the CD for a moment if you need it.\n\n" );

  $doItAgain = "true";

  while( $doItAgain eq "true" ) {
    @renameList = ();

    foreach $num (@trackList) {
      $newName = "";

      if( $num < 10 ) {
        print( "<Rename track $num >  " );
      }
      else {
        print( "<Rename track $num>  " );
      }

      chop( $newName = <STDIN> );
      @renameList = ( @renameList, $newName );
    }

    print( "\n\n\n" );

    $num = 1;
    foreach $item (@renameList) {
      if( $num < 10 ) {
        print( "track $num : $item\n" );
      }
      else {
        print( "track $num: $item\n" );
      }

      $num++;
    }

    print( "\nIs this right (Y/n)?  " );
    chop( $answer = <STDIN> );
    print( "\n" );

    if( $answer =~ /^[nN]/ ) {
      $doItAgain = "true";
    }
    else {
      $doItAgain = "false";
    }
  }

  print( "\nMake sure the CD is in the drive and hit <ENTER>." );
  <STDIN>;

  print( "****************************************************\n\n" );
}



##########################################################################
#                                                                        #
# SUB: cddbRename                                                        #
#                                                                        #
#   Setup the renameList variable by way of CDDB.                        #
#                                                                        #
##########################################################################

sub cddbRename {
  # Get the names to rename MP3s to, via CDDB, if so requested (flagged)
  chop( $cddbPath = `which cddb.pl` );
  $cddbFound = ( $cddbPath =~ /cddb.pl/ );

  if( !($cddbFound) ) {
    print( "The -c or --cddb flag you used requires CDDB/CDDB_get\n" );
    print( "You can find this on http://freshmeat.com by searching\n" );
    print( "on the keyword:  CDDB_get\n" );
  }
  else {
    if( @trackList == 0 ) {
      `$cddbPath > /dev/tty`;
    }
    else {
      `rm -f /tmp/rip-*`;
      `echo 1 | $cddbPath > $tempFile`;

      open( INFILE, "<$tempFile") || die( "rip: cannot open file: $!\n");

      if( eof INFILE ) {
        print( "rip: Cannot connect to CDDB when you are offline.\n" );
        print( "rip: CDDB lookup has been aborted.\n" );
      }
      else {
         $_ = <INFILE>;

         if( $_ =~ /^This CD could be/ ) {
           print( "Could be more than one CD from CDDB. Aborting.\n" );
           exit( 7 );
         }

         for( $i = 0 ; $i < 4 ; $i++ ) {
           <INFILE>;
         }

         while( <INFILE> ) {
           chop( $_ );
           s/ /_/g;
           s/[\(\)\[\]\{\}\'\"\`\.\?,]//g;
           @line = split( ":", $_);
           $newName = reverse( $line[1] );
           chop( $newName );
           $newName = reverse( $newName ) . ".mp3";
           @renameList = ( @renameList, $newName );
         }
      }
    }
  }

  close( INFILE );
}



##########################################################################
#                                                                        #
# SUB: beLazy                                                            #
#                                                                        #
#   Using cddb.pl, create a dir in the current working dir with the name #
#   given in the artist field, setup the trackList to rip the entire CD, #
#   and create a playlist that XMMS could use in the "artist's" dir.     #
#                                                                        #
##########################################################################

sub beLazy {
  # Do the entire CD (uses CDDB to lookup the number of tracks on the CD)
  `rm -f /tmp/rip-*`;
  `$cddbPath > $tempFile`;

  open( INFILE, "<$tempFile") || die( "rip: cannot open file: $!\n");

  # Read the artist name and create an output dir with that name
  $_ = <INFILE>;
  chop( $_ );
  s/ //g;
  @line = split( ":", $_ );
  $artistDir = $line[1];
  $outputDir = "$cwd/$artistDir/";
  print( "OUTPUT DIR: $outputDir\n" );

  if(  -e $outputDir && -w $outputDir  ) {
    print( "Output dir $outputDir already exists. Aborting.\n" );
    exit( 6 );
  }
  else {
    `mkdir $outputDir`;

    if(  !( -e $outputDir && -w $outputDir )  ) {
      print( "Either the output directory $outputDir cannot be created\n" );
      $outputDir = $DEFAULT_DIR;
      print( "or it is not writable. Output will be to $outputDir instead.\n" );
    }
  }

  # Read the album name and use it to make a XMMS play list
  $_ = <INFILE>;
  chop( $_ );
  s/ //g;
  s/[\(\)\[\]\{\}\'\"\`\.\?,]//g;
  @line = split( ":", $_ );
  $list = $line[1];

  # Ditch 2 lines
  <INFILE>;
  <INFILE>;

  # Read the num of tracks and setup the trackList var
  $_ = <INFILE>;
  chop( $_ );
  s/ //g;
  @line = split( ":", $_ );
  @trackList = (1..$line[1]);

  close( INFILE );

  # Create play list
  `touch $outputDir/$list`;
  open( OUTFILE, ">$outputDir/$list" ) || die( "rip: cannot open file: $!\n" );

  for( $i = 0 ; $i < $line[1] ; $i++ ) {
    $nextTrack = $renameList[$i];
    print OUTFILE ( "${outputDir}${nextTrack}\n" );
  }

  close( OUTFILE );
}



##########################################################################
#                                                                        #
# SUB: encode                                                            #
#                                                                        #
#   Based upon what GLOBAL variables have been set, encode the given     #
#   tracks to MP3 or to WAV one at a time. This saves hard drive space   #
#   compared to ripping all tracks to WAV first and then encoding.       #
#                                                                        #
##########################################################################

sub encode {
  # If in verbose mode, output flags in use by cdparanoia and bladeenc
  if( $cdparanoiaFlags =~ /-v/ ) {
    print( "\nUsing cdparanoia in: $cdparanoiaPath\n" );
    print( "Using bladeenc in: $bladeencPath\n" );
    print( "Using cdparanoia flags: $cdparanoiaFlags\n" );
    print( "Using bladeenc flags: $bladeencFlags\n" );
    print( "Output directory is: $outputDir\n" );
  }


  # Rip all the way to MP3 unless the WAV only flags is set
  foreach $track ( @trackList ) {
    if( $track =~ /^\d{1,2}$/ ) {
      print( "\nNow ripping CD track $track...\n" );

      `cdparanoia $cdparanoiaFlags $track`;

      if( $wavONLY eq "false" ) {
        print( "Now encoding track $track to MP3.\n" );
        print( "Please wait, this may take several minutes...\n" );

        `bladeenc $bladeencFlags *wav`;

        if( $renameTracks eq "true" ) {
          $properName = shift( @renameList );
        }
        elsif( $checkDatabase eq "true" ) {
          $properName = $renameList[ $track - 1 ];
        }
        else {
          $properName = "track" . $track . ".mp3";
        }

        if( $track < 10 ) {
          $currentTrack = "track0" . $track . ".cdda.mp3";
        }
        else {
          $currentTrack = "track"  . $track . ".cdda.mp3";
        }

        `mv $currentTrack ${outputDir}${properName}`;
      }

      if( $lazy eq "true" && $moveIt eq "true" ) {
        print( "Using -m/--move and -l/--lazy together: not yet implemented\n" );
      }
    }
    else {
      print( "The track to rip argument was syntactically incorrect: $track\n\n" );
      print( "An example of legal syntax is:   rip 2-5 7 8 10-13 15\n"           );

      &usage;
    }
  }
}



##########################################################################
#                                                                        #
# SUB: usage                                                             #
#                                                                        #
#   Prints a usage message for rip and exits.                            #
#                                                                        #
##########################################################################

sub usage {
  print( "\nUSAGE: rip [option(s)] <track(s)>\n\n"                                      );
  print( "OPTIONS:\n\n"                                                                 );
  print( "  -b=  --bitrate=NUM          set bitrate for encoding to NUM kbps\n"         );
  print( "  -c   --cddb                 use CDDB to rename MP3 files (must be online\n" );
  print( "  -d=  --dev=DEV              set input cdrom device to be DEV\n"             );
  print( "  -h   --help                 print this help to screen\n"                    );
  print( "  -l   --lazy                 rip entire CD, create playlist, move to artist dir\n" );
  print( "  -m=  --move=DIR             move MP3 files to DIR (absolute pathname)\n"    );
  print( "  -p   --paranoia             Use 160 kbps and don't accept skips on rip\n"   );
  print( "  -q   --query                print track info for the CD in the drive\n"     );
  print( "  -Q   --quiet                rip tracks quietly\n"                           );
  print( "  -r   --rename               prompt user for proper name of each track \n"   );
  print( "  -s=  --speed=NUM            set CD read speed to NUM during ripping \n"     );
  print( "  -v   --verbose              rip tracks in a verbose manner\n"               );
  print( "  -V   --version              print version information\n"                    );
  print( "  -w   --wav                  only rip tracks to *.wav files.\n\n"            );
  print( "EXAMPLES:\n\n"                                                                );
  print( "  rip 3-5                     rip tracks 3, 4, and 5 to MP3\n"                );
  print( "  rip 7 12 14                 rip tracks 7, 12, and 14 to MP3\n"              );
  print( "  rip 3-5 7 12 14             rip tracks 3, 4, 5, 7, 12, and 14 to MP3\n"     );
  print( "  rip 6                       rip track 6\n"                                  );
  print( "  rip -v 6                    rip track 6 in a verbose manner\n"              );
  print( "  rip -w 6                    rip track 6 to a *.wav file, only\n"            );
  print( "  rip -Q 6                    rip track 6 in a quiet manner\n"                );
  print( "  rip -c 6                    rip track 6 and rename MP3 file via CDDB\n"     );
  print( "  rip -r 6                    rip track 6 and ask for a name\n"               );
  print( "  rip -m=/home/mp3 6          rip track 6 and move MP3 file to /home/mp3\n"   );
  print( "  rip -s=32 6                 rip track 6 using a CD read speed of 32x\n"     );
  print( "  rip -b=160 6                rip track 6 using 160 kbps encoding\n"          );
  print( "  rip -d=/dev/cdrom 6         rip track 6 using /dev/cdrom as input device\n" );
  print( "  rip -p 6                    rip track 6 using 160 kbps & accept no skips\n" );
  print( "  rip -q                      print track info for CD in drive\n"             );
  print( "  rip --version               print version information\n"                    );
  print( "  rip --help                  print this help screen\n\n"                     );
  print( "NORMAL USAGE:\n\n"                                                            );
  print( "  rip -q                      figure out what tracks you want to rip\n"       );
  print( "  rip -Qpr 1-3 6 8-11         rip to MP3 with quiet paranoia and rename\n"    );
  print( "  rip -Qpc 1-3 6 8-11         similar: renames via CDDB (must be online)\n"   );
  print( "  rip -Qpc -m=/home/mp3 1-11  similar: also does a move (must be online)\n"   );
  print( "  rip -l                      laziness at its best IMHO (must be online)\n\n"      );

  exit( 0 );
}



##########################################################################
#                                                                        #
# SUB: abort                                                             #
#                                                                        #
#   Prints error messages if either cdparanoia or bladeenc is not        #
#   present on the $PATH, then exits.                                    #
#                                                                        #
##########################################################################

sub abort {
  if( !($cdparanoiaFOUND) ) {
    print( "\nrip:  WARNING: cdparanoia was *not* found on your \$PATH\n" );
    print ("rip: you can download it from http://www.xiph.org/paranoia/\n\n" );
  }

  if( !($bladeencFOUND) ) {
    print( "\nrip:  WARNING: bladeenc was *not* found on your \$PATH\n" );
    print ("rip: you can download it from http://bladeenc.mp3.no\n\n" );
  }

  exit( 1 );
}
