package ripenc;

# Necessary to be able to use Makefile.pl
require 5.002;
$VERSION = "0.96";

###############################################################################
#
# ripenc
# Version 0.01
# Date: 06/29/2000
# Copyright (c) 1999, 2000 Devon Jones (soulcatcher@evilsoft.org).
# All rights reserved. This program is free software;
# you can redistribute it and/or modify it under the same terms as Perl itself. 
#
###############################################################################

use ObjCDDB;
use MP3::Tag;
use IO::File;
  
###############################################################################
# Core Functions
###############################################################################

sub new {
###############################################################################
#          Name: ripenc->new (Public)
#    Parameters: none
#       Returns: a ripenc object
#   Description: creates a new ripenc object
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my ($this) = shift;
  my $class = $this;
  my $self = {};
  bless $self, $class;
  $self->init();
  return $self;
}


sub init {
###############################################################################
#          Name: ripenc->init (Private)
#    Parameters: None
#       Returns: Nothing
#   Description: initializes the ripenc object
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  
  $self->Config_Get;
  $self->Config_TestExternal;

  # CDDB Categories
  @{$self{'CDDBCATEGORIES'}} = qw( blues
                                   classical
                                   country
                                   data
                                   folk
                                   jazz
                                   misc
                                   newage
                                   reggae
                                   rock
                                   soundtrack );
  # Mapping of CDDB Categories to id3 categories
  @{$self{'ID3CDDBCATEGORIES'}} = (0,32,2,12,80,8,12,10,16,17,24);
  
  # Id3 categories
  @{$self{'ID3CATEGORIES'}} = ("Blues",
                 "Classic Rock",
                 "Country",
                 "Dance",
                 "Disco",
                 "Funk",
                 "Grunge",
                 "Hip-Hop",
                 "Jazz",
                 "Metal",
                 "New Age",
                 "Oldies",
                 "Other",
                 "Pop",
                 "R&B",
                 "Rap",
                 "Reggae",
                 "Rock",
                 "Techno",
                 "Industrial",
                 "Alternative",
                 "Ska",
                 "Death Metal",
                 "Pranks",
                 "Soundtrack",
                 "Euro-Techno",
                 "Ambient",
                 "Trip-Hop",
                 "Vocal",
                 "Jazz+Funk",
                 "Fusion",
                 "Trance",
                 "Classical",
                 "Instrumental",
                 "Acid",
                 "House",
                 "Game",
                 "Sound Clip",
                 "Gospel",
                 "Noise",
                 "Alternative Rock",
                 "Bass",
                 "Soul",
                 "Punk",
                 "Space",
                 "Meditative",
                 "Instrumental Pop",
                 "Instrumental Rock",
                 "Ethnic",
                 "Gothic",
                 "Darkwave",
                 "Techno-Industrial",
                 "Electronic",
                 "Pop-Folk",
                 "Eurodance",
                 "Dream",
                 "Southern Rock",
                 "Comedy",
                 "Cult",
                 "Gangsta",
                 "Top 40",
                 "Christian Rap",
                 "Pop/Funk",
                 "Jungle",
                 "Native US",
                 "Cabaret",
                 "New Wave",
                 "Psychadelic",
                 "Rave",
                 "Showtunes",
                 "Trailer",
                 "Lo-Fi",
                 "Tribal",
                 "Acid Punk",
                 "Acid Jazz",
                 "Polka",
                 "Retro",
                 "Musical",
                 "Rock & Roll",
                 "Hard Rock",
                 "Folk",
                 "Folk-Rock",
                 "National Folk",
                 "Swing",
                 "Fast Fusion",
                 "Bebob",
                 "Latin",
                 "Revival",
                 "Celtic",
                 "Bluegrass",
                 "Avantgarde",
                 "Gothic Rock",
                 "Progressive Rock",
                 "Psychedelic Rock",
                 "Symphonic Rock",
                 "Slow Rock",
                 "Big Band",
                 "Chorus",
                 "Easy Listening",
                 "Acoustic",
                 "Humour",
                 "Speech",
                 "Chanson",
                 "Opera",
                 "Chamber Music",
                 "Sonata",
                 "Symphony",
                 "Booty Bass",
                 "Primus",
                 "Porn Groove",
                 "Satire",
                 "Slow Jam",
                 "Club",
                 "Tango",
                 "Samba",
                 "Folklore",
                 "Ballad",
                 "Power Ballad",
                 "Rhytmic Soul",
                 "Freestyle",
                 "Duet",
                 "Punk Rock",
                 "Drum Solo",
                 "Acapella",
                 "Euro-House",
                 "Dance Hall",
                 "Goa",
                 "Drum & Bass",
                 "Club-House",
                 "Hardcore",
                 "Terror",
                 "Indie",
                 "BritPop",
                 "Negerpunk",
                 "Polsk Punk",
                 "Beat",
                 "Christian Gangsta Rap",
                 "Heavy Metal",
                 "Black Metal",
                 "Crossover",
                 "Contemporary Christian",
                 "Christian Rock",
                 "Merengue",
                 "Salsa",
                 "Trash Metal",
                 "Anime",
                 "Jpop",
                 "Synthpop");
  chdir;
  chdir ".oneripper";
  unless (-e "encoder.log") {
    system("touch encoder.log");
  }
  unless (-e "ripper.log") {
    system("touch ripper.log");
  }
}

sub ResetCD() {
###############################################################################
#          Name: ripenc->Cache_Read (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: Returns a valid queue line.
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 03/16/2001
###############################################################################
  my($self) = shift;

  $self->SetArtist("");
  $self->SetTitle("");
  $self->SetCDDBCategory("");
  $self->SetCDDBExtd("");
  for($i = 1; $i <= $self->ReturnNumTracks(); $i++) {
    $self->SetArtist("", $i);
    $self->SetTrack("", $i);
    $self->SetCDDBTrackExt("", $i);
    $self->SetID3Category(0, $i);
  }
  
}

sub CDDB_GetCD {
###############################################################################
#          Name: ripenc->CDDB_GetCD (Public)
#    Parameters: None
#       Returns: Array of cddb records
#   Description: This will reset the values of the current ripenc object,
#                and then it will check cddb to see if the current cd exists
#                it will then take all records that match, and return them in
#                an array
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($cd, $i) = "";

  $self->ResetState();
  $cd = new ObjCDDB($self->ReturnConfigValue('CDDB_HOST'),
  $self->ReturnConfigValue('CDDB_PORT'),
  $self->ReturnConfigValue('CD_DEVICE'), "oneripper", undef, $self->ReturnConfigValue('CDDB_SMTP'), $self->ReturnConfigValue('CDDB_SUBMIT'));
#  $self{'num'} = $cd->ReturnNumTracks;
  @cds = $cd->GetCDDBId();
  $self->SetNumTracks($cd->ReturnNumTracks());
  
  return @cds;
}

sub CDDB_GetCDData {
###############################################################################
#          Name: ripenc->CDDB_GetCDData (Public)
#    Parameters: Takes in a valid cddb response line.
#                (Ex: "200 rock c009560d The Beatles / Sgt. Pepper's Lonely Hearts Club Band")
#       Returns: Nothing
#   Description: This takes a cddb line, ans gets the full cddb record for that
#                line.  It will then set all the internal variables to what
#                is appropriate from the cddb record.
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($cdid) = shift; 
  my($cd, $i) = "";

  $cd = new ObjCDDB($self->ReturnConfigValue('CDDB_HOST'), $self->ReturnConfigValue('CDDB_PORT'), $self->ReturnConfigValue('CD_DEVICE'), undef, undef, $self->ReturnConfigValue('CDDB_SMTP'), $self->ReturnConfigValue('CDDB_SUBMIT'));
  $cd->GetCDInfo($cdid);
  
  $self->SetArtist($cd->ReturnArtist());
  $self->SetTitle($cd->ReturnTitle());
  $self->SetCDDBCategory($cd->ReturnCategory());
  $self->SetCDDBExtd($cd->ReturnExtd());
  $self->SetCDDBid($cd->ReturnCDDBid());
  $self->SetNumTracks($cd->ReturnNumTracks());
  $framestart = $cd->ReturnTrackFrames(0);
  for($i = 1; $i <= $self->ReturnNumTracks(); $i++) {
    $self->SetTrack($cd->ReturnTrack($i), $i);
    $frameend = $cd->ReturnTrackFrames($i);
    $frames = $frameend - $framestart;
    $self->SetTrackFrames($frames, $i);
    $framestart = $frameend;
    $self->SetCDDBTrackExt($cd->ReturnTrackExt($i), $i);
  }
}

sub Cache_Create {
###############################################################################
#          Name: ripenc->Cache_Create (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 03/16/2001
###############################################################################
  my($self) = shift;

  chdir;
  chdir ".oneripper";
  if(not -e "names.cache") {
    mkdir('names.cache',0700) || die "cannot mkdir .oneripper: $!";
  }
  chdir "names.cache";

  my($filename) = $self->ReturnCDDBid();
  if(not -e "$filename") {
    system("touch $filename");
  }

  open(CACHEWRITE, "> $filename") or die "Couldn't open $filename for writing: $!\n";

  my($tracks) = $self->ReturnNumTracks();
  for($i = 1; $i <= $tracks; $i++) {
    my($line) = $self->CreateQueueLine($i);
    print CACHEWRITE $line;
  }

  close(CACHEWRITE);

}

sub Cache_Read {
###############################################################################
#          Name: ripenc->Cache_Read (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: Returns a valid queue line.
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 03/16/2001
###############################################################################
  my($self) = shift;

  chdir;
  chdir ".oneripper";
  if(not -e "names.cache") {
    mkdir('names.cache',0700) || die "cannot mkdir .oneripper: $!";
  }
  chdir "names.cache";
  
  my($firsttime) = 1;
  my($filename) = $self->ReturnCDDBid();
  if(-e "$filename") {
    open(CACHEREAD, "< $filename") or die "Couldn't open $filename for readin: $!\n";
    while(<CACHEREAD>) {
      my($line) = $_;
      # Parse the file
      my($filename, $CDArtist, $CDTitle, $CDid3, $CDCDDBCat, $CDCDDBExt, $CDCDDBId, $CDTrackNo, $TrackArtist, $TrackName, $Trackid3, $TrackCDDBCat, $TrackCDDBExt, $CDRemixer, $CDType, $TrackRemixer, $TrackType, $Year) = $self->ParseQueueLine($line);

      if($firsttime) {
        $self->SetArtist($CDArtist);
        $self->SetTitle($CDTitle);
        $self->SetCDDBCategory($CDCDDBCat);
        $self->SetCDDBExtd($CDCDDBExt);
        $self->SetCDDBid($CDCDDBId);
        $firsttime = 0;
      }

      $self->SetArtist($TrackArtist, $CDTrackNo);
      $self->SetTrack($TrackName, $CDTrackNo);
      $self->SetCDDBTrackExt($TrackCDDBExt, $CDTrackNo);
      $self->SetID3Category($Trackid3, $CDTrackNo);
      $self->SetRemixer($CDRemixer);
      $self->SetType($CDType);
      $self->SetRemixer($TrackRemixer, $CDTrackNo);
      $self->SetType($TrackType, $CDTrackNo);
      $self->SetYear($Year);
    }
    close(CACHEWRITE);
  }
}

sub Cache_Check {
###############################################################################
#          Name: ripenc->Cache_Check (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: Returns a valid queue line.
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 03/16/2001
###############################################################################
  my($self) = shift;

  chdir;
  chdir ".oneripper";
  if(not -e "names.cache") {
    mkdir('names.cache',0700) || die "cannot mkdir .oneripper: $!";
  }
  chdir "names.cache";
  
  my($filename) = $self->ReturnCDDBid();
  if(-e "$filename") {
    return 1;
  }
  else {
    return 0;
  }
}

sub Ripper_Start {
###############################################################################
#          Name: ripenc->Ripper_Start (Public)
#    Parameters: nothing
#       Returns: nothing
#   Description: starts an ripping session to get all
#                songs that have been marked for retrieval
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/1999
###############################################################################
  my($self) = shift;
  my($i) = "";
  
  $self->Ripper_FileNames();
  
  for($i = 1; $i <= $self->ReturnNumTracks(); $i++) {
    if($self->ReturnTracksToRip($i)) {
      $self->Ripper_GetSong($i);
      $self->SetTracksNotToRip($i);
    }
  }
}

sub Ripper_DoNext {
###############################################################################
#          Name: ripenc->Ripper_DoNext (Public)
#    Parameters: none
#       Returns: 1 (Success) / undef (failure/no songs to rip)
#   Description: rips the next song (in numerical track order) that has been
#                marked to encode.
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/1999
###############################################################################
  my($self) = shift;
  my($i) = "";
  
  $self->Ripper_FileNames();
  
  for($i = 1; $i <= $self->ReturnNumTracks(); $i++) {
    if($self->ReturnTracksToRip($i)) {
      $success = $self->Ripper_GetSong($i);
      $self->SetTracksNotToRip($i);
      if($success)
      {
        return 1;
      }
      else
      {
        return undef;
      }
    }
  }
  return undef;
}

sub Ripper_GetSong {
###############################################################################
#          Name: ripenc->ripper_GetSong (Public)
#    Parameters: num - the track number of the song to rip
#       Returns: nothing
#   Description: Rips a song with the appropriate ripper, then creates a queue
#                file so that the encoder will know to encode the song
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/1999
###############################################################################
  my($self) = shift;
  my($num) = shift;
 
  my($line);

  chdir;
  chdir ".oneripper";
  my($files) = 0;
  for(my($i) = 1; $i <= $self->ReturnNumTracks(); $i++) {
    if($self->ReturnTracksToRip($i)) {
      $files++;
    }
  }
  open(RLOG, "> ripper.log");
  print RLOG "$files left to rip\n";
  close(RLOG);

  # Pick which ripper to use
  SWITCH: {
    # fork a cdparanoia session
    if ($self->ReturnConfigValue('RIPPER') =~ /cdparanoia/) {
      $failure = system("cdparanoia -d " . $self->ReturnConfigValue('CD_DEVICE') . " -w $num " . $self->ReturnConfigValue('SAVETO') . "/" . $self->ReturnFilename($num) . ".wav -e 2>> ~/.oneripper/ripper.log");
      last SWITCH;
    }
    # fork a cdda2wav session
    if ($self->ReturnConfigValue('RIPPER') =~ /cdda2wav/) {
      $failure = system("cdda2wav -D " . $self->ReturnConfigValue('CD_DEVICE') . " -t $num " . $self->ReturnConfigValue('SAVETO') . "/" . $self->ReturnFilename($num) . ".wav 2>> ~/.oneripper/ripper.log");
      system("rm " . $self->ReturnConfigValue('SAVETO') . "/*.cddb");
      system("rm " . $self->ReturnConfigValue('SAVETO') . "/*.inf");
      last SWITCH;
    }
    # fork a tosha session
    if ($self->ReturnConfigValue('RIPPER') =~ /tosha/) {
      $failure = system("tosha -q -f wav -d " . $self->ReturnConfigValue('CD_DEVICE') . " -t $num -o " . $self->ReturnConfigValue('SAVETO') . "/" . $self->ReturnFilename($num) . ".wav 2>> ~/.oneripper/ripper.log");
      last SWITCH;
    }
    # fork a tosha session
    if ($self->ReturnConfigValue('RIPPER') =~ /dagrab/) {
      $failure = system("dagrab -v -d " . $self->ReturnConfigValue('CD_DEVICE') . " -f " . $self->ReturnConfigValue('SAVETO') . "/" . $self->ReturnFilename($num) . ".wav $num 1>> ~/.oneripper/ripper.log 2>> ~/.oneripper/ripper.log");
      last SWITCH;
    }
  }
  
  unless($failure)
  {
    # enter ripper.queue directory, if it does not exist create it.
    chdir;
    chdir ".oneripper";
    if(not -e "ripper.queue") {
      mkdir('ripper.queue',0700) || die "cannot mkdir .oneripper: $!";
    }
    chdir "ripper.queue";
  
    # Make sure that all track numbers contain 2 digits.
    $trackno = $num;
    if($trackno < 10) {
      $trackno = "0$trackno";
    }
  
    # Open queue file for writing.
    $file = time() . " - " . $self->ReturnFilename($num);
    $file =~ s/\\//g;
    open(QUEUEWRITE, ">> $file.queue") or die "Couldn't open $path for reading: $!\n";
  
    $line = $self->CreateQueueLine($num);
    # Format of Queue file is: "filename || CD Artist || CD Title || CD id3 Category || CD CDDB Category || CD CDDB Extended Info || CD CDDB id  || CD Track Number || Track Artist || Track Name || Track id3 category || Track CDDB Category || Track CDDB Extended Info
    print QUEUEWRITE $line;
  
    close(QUEUEWRITE);
    return 1;
  }
  else
  {
    unlink($self->ReturnConfigValue('SAVETO') . "/" . $self->ReturnFilename($num) . ".wav");
    return undef;
  }
}

sub Ripper_FileNames {
###############################################################################
#          Name: ripenc->Ripper_FileNames (Private)
#    Parameters: none
#       Returns: nothing
#   Description: Sets filenames for all the songs (for Wav & queue)
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/1999
###############################################################################
  my($self) = shift;
  my($filename);

  for($i = 1; $i <= $self->ReturnNumTracks(); $i++) {
    # Create base filename
    $filename = $self->ReturnArtist($i) . ' - ' . $self->ReturnTitle() . ' - ' . $i . ' - ' .$self->ReturnTrack($i);
    $filename = $self->EscapeFileName($filename);

    # Set file name
    $self->SetFilename($filename, $i)
  }
}

sub Encoder_DoNext {
###############################################################################
#          Name: ripenc->Encoder_DoNext (Public)
#    Parameters: none
#       Returns: 1/undef
#   Description: looks for a file in the user's .oneripper/ripper.queue directory.
#                it takes the information in that file, and uses it to encode
#                the next wave file.
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/1999
###############################################################################
  my($self) = shift;

  my(@queueline, $line, $file, $nofiles, @files, $fileout, $delfile);

  # Read the files in the .oneripper/ripper.queue directory
  chdir;
  chdir ".oneripper";
  opendir(QUEUE, "ripper.queue");
  $nofiles = 1;
  undef(@files);
  while( defined ($file = readdir QUEUE) ) {
    next if $file =~ /^\.\.?$/;
    next if $file =~ /^E/;
    $nofiles = 0;
    push(@files, $file);
  }
  
  # If there are no files left, return.
  if($nofiles) {
    return undef;
  }
  
  # Sort the files, and take the next one.
  @files = sort(@files);
  $file = shift(@files);

  # Read the file
  chdir "ripper.queue";
  rename("$file", "0$file");
  $file = "0$file";
  open QUEUEREAD, "< $file" or die "Encode: No songs to rip: $!\n";
  while(<QUEUEREAD>) {
    push(@queueline, $_);
  }
  close(QUEUEREAD);
  $line = shift(@queueline);
  chdir;

  # Parse the file
  # Format of Queue file is: "filename || CD Artist || CD Title || CD id3 Category || CD CDDB Category || CD CDDB Extended Info || CD CDDB id  || CD Track Number || Track Artist || Track Name || Track id3 category || Track CDDB Category || Track CDDB Extended Info || CD Remixer || CD Type || Track Remixer || Track Type
  my($filename, $CDArtist, $CDTitle, $CDid3, $CDCDDBCat, $CDCDDBExt, $CDCDDBId, $CDTrackNo, $TrackArtist, $TrackName, $Trackid3, $TrackCDDBCat, $TrackCDDBExt, $CDRemixer, $CDType, $TrackRemixer, $TrackType, $Year) = $self->ParseQueueLine($line);

  # Pass the contents of the file to the proper encoder
  SWITCH:  {
    # Encode in Lame
    my($ogg) = 0;
    if ($self->ReturnConfigValue('ENCODER') =~ /lame/) {
      my($lame);
      if($self->ReturnConfigtestValue('lame')) {
        $lame = "lame --nohist";
      }
      elsif($self->ReturnConfigtestValue('notlame')) {
        $lame = "notlame --nohist";
      }
      my($ext) = "mp3";
      if ($self->ReturnConfigValue('ENCODER') =~ /lameogg/) {
        $ogg = 1;
        $lame .= " --ogg";
        $ext = "ogg";
      }
      # Use Lame's VBR
      if($self->ReturnConfigValue('VBR') eq "YES") {
        $lame .= " -V $self{'CONFIG'}{'VBR_BITRATE'}";
      } else { # Don't Use Lame's VBR
        $lame .= " -b $self{'CONFIG'}{'CBR_BITRATE'}";
      }
      
      $lame .= " $self{'CONFIG'}{'ENCFLAGS'}";

      # Create a proper file name (Replace with a function that can create a user defined
      # file name with)
      $fileout = $self->CreateFileName($TrackArtist, $CDTitle, $CDTrackNo, $TrackName, $TrackRemixer, $TrackType, $ext);

      # Run the encoder
      $failure = system("$lame $filename " . $self->ReturnConfigValue('SAVETO') . "/$fileout 2>> ~/.oneripper/encoder.log");
      
      # Tagging
      if(!$ogg) {
        $self->AddId3($line, $fileout);
      }

      last SWITCH;
    }
    # Use Bladeenc
    if ($self->ReturnConfigValue('ENCODER') =~ /bladeenc/) {
      my($bladeenc) = "bladeenc";
      $bladeenc .= " -br $self{'CONFIG'}{'CBR_BITRATE'}";
      $bladeenc .= " $self{'CONFIG'}{'ENCFLAGS'}";

      # Create a proper file name (Replace with a function that can create a user defined
      # file name with)
      $fileout = $self->CreateFileName($TrackArtist, $CDTitle, $CDTrackNo, $TrackName, $TrackRemixer, $TrackType, "mp3");

      $failure = system("$bladeenc $filename " . $self->ReturnConfigValue('SAVETO') . "/$fileout >> ~/.oneripper/encoder.log");

      # Tagging
      $self->AddId3($line, $fileout);

      last SWITCH;
    }
    # Use Oggenc
    if ($self->ReturnConfigValue('ENCODER') =~ /oggenc/)
    {
      my($oggenc) = "oggenc ";
      $oggenc .= " -b $self{'CONFIG'}{'CBR_BITRATE'}";
      $oggenc .= " -q $self{'CONFIG'}{'VBR_BITRATE'}";
      $oggenc .= " $self{'CONFIG'}{'ENCFLAGS'}";

      if($self->ReturnConfigValue('USE_TAGGING')) {
        $oggenc .= ' --title "' . $TrackName . '" --artist "' . $TrackArtist . '" --album "' . $CDTitle . '" --tracknum=' . $CDTrackNo;
      }
      # Create a proper file name (Replace with a function that can create a user defined
      # file name with)
      $fileout = $self->CreateFileName($TrackArtist, $CDTitle, $CDTrackNo, $TrackName, $TrackRemixer, $TrackType, "ogg");

      chdir;
      chdir ".oneripper";
      open ENCODELOG, ">> encoder.log" or die;
      $escfilename = $filename;
      $escfilename =~ s/\\//g;
      print ENCODELOG "OGGENC - $escfilename\n\n";
      close(ENCODELOG);
      $failure = system("$oggenc -o " . $self->ReturnConfigValue('SAVETO') . "/$fileout $filename 2>> ~/.oneripper/encoder.log");

      last SWITCH;
    }
    # Use Gogo
    if ($self->ReturnConfigValue('ENCODER') =~ /gogo/) {
      my($gogo);
      $gogo = "gogo ";
      my($ext) = "mp3";
      # Use gogo's VBR
      if($self->ReturnConfigValue('VBR') eq "YES") {
        $gogo .= " -v $self{'CONFIG'}{'VBR_BITRATE'}";
      } else { # Don't Use Gogo's VBR
        $gogo .= " -b $self{'CONFIG'}{'CBR_BITRATE'}";
      }
      
      $gogo .= " $self{'CONFIG'}{'ENCFLAGS'}";

      # Create a proper file name (Replace with a function that can create a user defined
      # file name with)
      $fileout = $self->CreateFileName($TrackArtist, $CDTitle, $CDTrackNo, $TrackName, $TrackRemixer, $TrackType, $ext);

      # Run the encoder
      $failure = system("$gogo $filename " . $self->ReturnConfigValue('SAVETO') . "/$fileout 2>> ~/.oneripper/encoder.log 1>> ~/.oneripper/encoder.log");
      
      $self->AddId3($line, $fileout);

      last SWITCH;
    }
  }
  # Delete the wav file
  unless($failure) {
    if ($self->ReturnConfigValue('DELWAV') =~ /YES/) {
      $delfile = $filename;
      $delfile =~ s/\\//g;
      $delfile =~ s/.*\///g;
      chdir($self->ReturnConfigValue('SAVETO'));
      unlink("$delfile");
    }
    # Delete the queue file
    chdir;
    unlink(".oneripper/ripper.queue/$file");
    return 1;
  } else {
    chdir;
    rename(".oneripper/ripper.queue/$file", ".oneripper/ripper.queue/E$file");
    return 2;
  }
  
  return undef;
}

sub AddId3 {
###############################################################################
#          Name: ripenc->AddId3 (Private)
#    Parameters: $line
#       Returns: 1
#   Description: Adds id3v1 & id3v2 tags to a file as appropriate.
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($line) = shift;
  my($encfile) = shift;
  my($filename, $CDArtist, $CDTitle, $CDid3, $CDCDDBCat, $CDCDDBExt, $CDCDDBId, $CDTrackNo, $TrackArtist, $TrackName, $Trackid3, $TrackCDDBCat, $TrackCDDBExt, $CDRemixer, $CDType, $TrackRemixer, $TrackType, $Year) = $self->ParseQueueLine($line);
  # Use id3 tags
  if($self->ReturnConfigValue('USE_TAGGING')) {
    $encfile =~ s/\\//g;
    my($mp3) = MP3::Tag->new($self->ReturnConfigValue('SAVETO') . "/$encfile");
    # Use id3v1 tags
    if($self->ReturnConfigValue('USE_TAGGING_ONE') eq 'YES') {
      $mp3->newTag("ID3v1");
#      $id3v1 = MP3::Tag::ID3v1->new($mp3, "true");
      #Track Title
      $mp3->{ID3v1}->song($TrackName);
      #Artist
      $mp3->{ID3v1}->artist($TrackArtist);
      #Album Name
      $mp3->{ID3v1}->album($CDTitle);
      #Track Number
      $mp3->{ID3v1}->track($CDTrackNo);
      #Genre
      $mp3->{ID3v1}->genre($Trackid3);
      #Year
      $mp3->{ID3v1}->year($Year);
      #Comments
      $mp3->{ID3v1}->comment('CDDB: ' . $CDCDDBId);
      $mp3->{ID3v1}->writeTag;
    }
    
    # Use id3v2 tags
    if($self->ReturnConfigValue('USE_TAGGING_TWO') eq "YES") {
#      $id3v2 = MP3::Tag::ID3v2->new($mp3, "true");
      $mp3->newTag("ID3v2");
      #TIT2 - Track Title
      $mp3->{ID3v2}->add_frame("TIT2", $TrackName);
      #TPE1 - Artist
      $mp3->{ID3v2}->add_frame("TPE1", $TrackArtist);
      #TALB - Album Name
      $mp3->{ID3v2}->add_frame("TALB", $CDTitle);
      #TRCK - Track Number
      $mp3->{ID3v2}->add_frame("TRCK", $CDTrackNo);
      #TCON - Genre
      $mp3->{ID3v2}->add_frame("TCON", $self{'ID3CATEGORIES'}[$CDid3]);
      #TYER - Year
      #COMM - Comments
      $mp3->{ID3v2}->add_frame("COMM", 'CDDB:' . $CDCDDBId);
      #TENC - Encoded by
      $mp3->{ID3v2}->add_frame("TENC", "The One Ripper $VERSION");
      #WXXX - User defined URL
      $mp3->{ID3v2}->add_frame("WXXX", "The One Ripper Website", "http://oneripper.sourceforge.net");
      #TCOM - Composer
      #TPE2 - Accompanied by
      #TPE3 - Conductor
      #TPE4 - Remixer
      $mp3->{ID3v2}->add_frame("TPE4", $TrackRemixer);
      #TYER - Year
      $mp3->{ID3v2}->add_frame("TYER", $Year);
      #TOPE - Original Artist(s)/Performer(s)
      #TXXX - Using it for song type (Remix, Live, Soundtrack)
      $mp3->{ID3v2}->add_frame("TXXX", "Type", $TrackType);
      $mp3->{ID3v2}->write_tag();
    }
#    $mp3->close;
  }
  return 1;
}      

sub ParseQueueLine {
###############################################################################
#          Name: ripenc->ParseQueueLine (Private)
#    Parameters: $line (A queue line)
#       Returns: $filename
#                $CDArtist
#                $CDTitle
#                $CDid3
#                $CDCDDBCat
#                $CDCDDBExt
#                $CDCDDBId
#                $CDTrackNo
#                $TrackArtist
#                $TrackName
#                $Trackid3
#                $TrackCDDBCat$TrackCDDBExt
#   Description: takes in a queue line, parses it, and returns all the values
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($line) = shift;

  # Format of Queue file is: "filename || CD Artist || CD Title || CD id3 Category || CD CDDB Category || CD CDDB Extended Info || CD CDDB id  || CD Track Number || Track Artist || Track Name || Track id3 category || Track CDDB Category || Track CDDB Extended Info || CD Remixer || CD Type || Track Remixer || Track Type
  $line =~ m/(.*?)\s*\|\|\s*(.*?)\s*\|\|\s*(.*?)\s*\|\|\s*(.*?)\s*\|\|\s*(.*?)\s*\|\|\s*(.*?)\s*\|\|\s*(.*?)\s*\|\|\s*(.*?)\s*\|\|\s*(.*?)\s*\|\|\s*(.*?)\s*\|\|\s*(.*?)\s*\|\|\s*(.*?)\s*\|\|(.*)/;
  my($filename) = $1;
  my($CDArtist) = $2;
  my($CDTitle) = $3;
  my($CDid3) = $4;
  my($CDCDDBCat) = $5;
  my($CDCDDBExt) = $6;
  my($CDCDDBId) = $7;
  my($CDTrackNo) = $8;
  my($TrackArtist) = $9;
  my($TrackName) = $10;
  my($Trackid3) = $11;
  my($TrackCDDBCat) = $12;
  my($TrackCDDBExt) = $13;
  my($TrackRemixer) = "";
  my($TrackType) = "";
  my($Year) = "";

  #Added 4 new fields  
  if($TrackCDDBExt =~ m/\|\|.*\|\|/) {
    $TrackCDDBExt =~ m/(.*?)\s*\|\|\s*(.*?)\s*\|\|s*(.*?)\s*\|\|s*(.*?)\s*\|\|\s*(.*?)\s*\|\|\s*(.*)/;
    $CDRemixer = $2;
    $CDType = $3;
    $TrackRemixer = $4;
    $TrackType = $5;
    $TrackCDDBExt = $1;
    $Year = $6;
  }
  return($filename, $CDArtist, $CDTitle, $CDid3, $CDCDDBCat, $CDCDDBExt, $CDCDDBId, $CDTrackNo, $TrackArtist, $TrackName, $Trackid3, $TrackCDDBCat, $TrackCDDBExt, $CDRemixer, $CDType, $TrackRemixer, $TrackType, $Year);
}

sub CreateQueueLine {
###############################################################################
#          Name: ripenc->CreateQueueLine (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: Returns a valid queue line.
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($num) = shift; 

  $trackno = $num;
  if($trackno < 10) {
    $trackno = "0$trackno";
  }

  # Format of Queue file is: "filename || CD Artist || CD Title || CD id3 Category || CD CDDB Category || CD CDDB Extended Info || CD CDDB id  || CD Track Number || Track Artist || Track Name || Track id3 category || Track CDDB Category || Track CDDB Extended Info
  my($line) = $self->ReturnConfigValue('SAVETO') . "/" .
    $self->ReturnFilename($num) . ".wav || " .
    $self->ReturnArtist() . " || " .
    $self->ReturnTitle() . " || " .
    $self->ReturnID3Category() . " || " .
    $self->ReturnCDDBCategory() . " || " .
    $self->ReturnCDDBExtd() . " || " .
    $self->ReturnCDDBid() . " || " .
    $trackno . " || " .
    $self->ReturnArtist($num) . " || " .
    $self->ReturnTrack($num) . " || " .
    $self->ReturnID3Category($num) . " || " .
    $self->ReturnCDDBExtd($num) . " || " .
    $self->ReturnCDDBTrackExt($num) . " || " .
    $self->ReturnRemixer() . " || " .
    $self->ReturnType() . " || " .
    $self->ReturnRemixer($num) . " || " .
    $self->ReturnType($num) . " || " .
    $self->ReturnYear() . "\n";
  
  return $line;
}

sub CreateFileName {
###############################################################################
#          Name: ripenc->CreateFileName (Private)
#    Parameters: $filename
#       Returns: $filename
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($TrackArtist) = shift;
  my($CDTitle) = shift;
  my($CDTrackNo) = shift;
  my($TrackName) = shift;
  my($TrackRemixer) = shift;
  my($TrackType) = shift;
  my($ext) = shift;
  
  my($ArtistDelim, $ArtistBegin, $ArtistEnd) = "";
  my($CDDelim, $CDBegin, $CDEnd) = "";
  my($NumDelim, $NumBegin, $NumEnd) = "";
  my($TrackDelim, $TrackBegin, $TrackEnd) = "";
  my($RemixerDelim, $RemixerBegin, $RemixerEnd) = "";

  $mask = $self->ReturnConfigValue('FILEMASK'); 

  # These masks represent a rule that if the delimiter exists in the string, then surround it with begin and end
  if($mask =~ /&A(.)(.)(.)/) {
    $ArtistDelim = $1;
    $ArtistBegin = $2;
    $ArtistEnd = $3;
    $mask =~ s/&A.../%A/g;
  }
  if($mask =~ /&C(.)(.)(.)/) {
    $CDDelim = $1;
    $CDBegin = $2;
    $CDEnd = $3;
    $mask =~ s/&C.../%C/g;
  }
  if($mask =~ /&R(.)(.)(.)/) {
    $RemixerDelim = $1;
    $RemixerBegin = $2;
    $RemixerEnd = $3;
    $mask =~ s/&R.../%R/g;
  } 
  if($mask =~ /&T(.)(.)(.)/) {
    $TrackDelim = $1;
    $TrackBegin = $2;
    $TrackEnd = $3;
    $mask =~ s/&T.../%T/g;
  } 
  if($mask =~ /&Y(.)(.)(.)/) {
    $TypeDelim = $1;
    $TypeBegin = $2;
    $TypeEnd = $3;
    $mask =~ s/&Y.../%Y/g;
  } 

  if($TrackArtist =~ /$ArtistDelim/) {
    $TrackArtist = $ArtistBegin . $TrackArtist . $ArtistEnd;
  }
  if($CDTitle =~ /$CDDelim/) {
    $CDTitle = $CDBegin . $CDTitle . $CDEnd;
  }
  if($TrackRemixer =~ /$RemixerDelim/) {
    $TrackRemixerName = $RemixerBegin . $TrackRemixer . $RemixerEnd;
  }
  if($TrackName =~ /$TrackDelim/) {
    $TrackName = $TrackBegin . $TrackName . $TrackEnd;
  }
  if($TrackType =~ /$TrackDelim/) {
    $TrackType = $TrackBegin . $TrackType . $TrackEnd;
  }
  
  # These masks represent a rule that if the string exists, then surround it with begin and end
  if($mask =~ /\@A(.)(.)/) {
    $ArtistBegin = $1;
    $ArtistEnd = $2;
    $ArtistMustExist = 1;
    $mask =~ s/\@A../%A/g;
  }
  if($mask =~ /\@C(.)(.)/) {
    $CDBegin = $1;
    $CDEnd = $2;
    $CDMustExist = 1;
    $mask =~ s/\@C../%C/g;
  }
  if($mask =~ /\@R(.)(.)/) {
    $RemixerBegin = $1;
    $RemixerEnd = $2;
    $RemixerMustExist = 1;
    $mask =~ s/\@R../%R/g;
  }
  if($mask =~ /\@T(.)(.)/) {
    $TrackBegin = $1;
    $TrackEnd = $2;
    $TrackMustExist = 1;
    $mask =~ s/\@T../%T/g;
  }
  if($mask =~ /\@Y(.)(.)/) {
    $TypeBegin = $1;
    $TypeEnd = $2;
    $TypeMustExist = 1;
    $mask =~ s/\@Y../%Y/g;
  }

  if($ArtistMustExist) {
    $TrackArtist =~ s/^\s+//g;
    $TrackArtist =~ s/\s+$//g;
    if($TrackArtist) {
      $TrackArtist = $ArtistBegin . $TrackArtist . $ArtistEnd;
    }
  }
  if($CDMustExist) {
    $CDTitle =~ s/^\s+//g;
    $CDTitle =~ s/\s+$//g;
    if($CDTitle) {
      $CDTitle = $CDBegin . $CDTitle . $CDEnd;
    }
  }
  if($RemixerMustExist) {
    $TrackRemixer =~ s/^\s+//g;
    $TrackRemixer =~ s/\s+$//g;
    if($TrackRemixer) {
      $TrackRemixer = $RemixerBegin . $TrackRemixer . $RemixerEnd;
    }
  }
  if($TrackMustExist) {
    $TrackName =~ s/^\s+//g;
    $TrackName =~ s/\s+$//g;
    if($TrackName) {
      $TrackName = $TrackBegin . $TrackName . $TrackEnd;
    }
  }
  if($TypeMustExist) {
    $TrackType =~ s/^\s+//g;
    $TrackType =~ s/\s+$//g;
    if($TrackType) {
      $TrackType = $TypeBegin . $TrackType . $TypeEnd;
    }
  }

  $mask =~ s/%A/$TrackArtist/g;
  $mask =~ s/%C/$CDTitle/g;
  $mask =~ s/%N/$CDTrackNo/g;
  $mask =~ s/%R/$TrackRemixer/g;
  $mask =~ s/%T/$TrackName/g;
  $mask =~ s/%Y/$TrackType/g;
  $mask .= ".$ext";

  $fileout = $self->EscapeFileName($mask);
  
  if($self->ReturnConfigValue('UNDERSCORE') eq 'YES') {
    $fileout =~ s/ /_/g;
  }

  return($fileout);
}

sub EscapeFileName {
###############################################################################
#          Name: ripenc->EscapeFileName (Private)
#    Parameters: $filename
#       Returns: $filename
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($filename) = shift;
  
  # Remove
  $filename =~ s/\*//g;
  $filename =~ s/\://g;
  $filename =~ s/\?//g;

  # Replace
  $filename =~ s/\\/-/g;
  $filename =~ s/\//-/g;
  $filename =~ s/\`/'/g;
  $filename =~ s/\´/'/g;
  $filename =~ s/\"/'/g;
  #"
  $filename =~ s/\</\[/g;
  $filename =~ s/\>/\]/g;

  # Escape
  $filename =~ s/\&/\\\&/g;
  $filename =~ s/\)/\\\)/g;
  $filename =~ s/\(/\\\(/g;
  $filename =~ s/ /\\ /g;
  $filename =~ s/'/\\'/g;
  $filename =~ s/`/\\`/g;
  $filename =~ s/;/\\;/g;

  return($filename);
}

sub InitCD {
###############################################################################
#          Name: ripenc->InitCD (Public)
#    Parameters: None
#       Returns: Nothing
#   Description: initializes the CDROM, and sets the number of tracks
#        Throws: "cd: cannot open cdrom"
#                "cd: cannot read toc"
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  
  my($cd) = new ObjCDDB($self->ReturnConfigValue('CDDB_HOST'),$self->ReturnConfigValue('CDDB_PORT'), $self->ReturnConfigValue('CD_DEVICE'), "oneripper", undef, $self->ReturnConfigValue('CDDB_SMTP'), $self->ReturnConfigValue('CDDB_SUBMIT'));
  $cd->ReadTOC();
  $cd->GenerateDiscId();
  $self->SetNumTracks($cd->ReturnNumTracks);
  my($id2) = sprintf "%08x", $cd->ReturnCDDBid();

  $self->SetCDDBid($id2);
  
  my($framestart) = $cd->ReturnTrackFrames(0);
  for($i = 1; $i <= $self->ReturnNumTracks(); $i++) {
    my($frameend) = $cd->ReturnTrackFrames($i);
    my($frames) = $frameend - $framestart;
    $self->SetTrackFrames($frames, $i);
    $framestart = $frameend;
  }

  return 1;
}

  

###############################################################################
# State Functions                                                             #
###############################################################################

sub ResetState {
###############################################################################
#          Name: ripenc->ResetState (Public)
#    Parameters: None
#       Returns: Nothing
#   Description: Resets the state of ripenc
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;

  undef($self{'cdartist'});
  undef($self{'title'});
  undef($self{'id3cat'});
  undef($self{'cddbid'});
  undef($self{'cddbcat'});
  undef($self{'cddbextd'});

  if(defined($self{'num'})) {
    for($i = 1; $i <= $self->ReturnNumTracks(); $i++) {
      undef($self{'artist'}[$i]);
      undef($self{'track'}[$i]{'name'});
      undef($self{'track'}[$i]{'rip'});
      undef($self{'trackid3cat'}[$i]);
      undef($self{'cddbext'}[$i]);
    }
    undef($self{'num'});
  }
}


###############################################################################
# Return Value Functions                                                      #
###############################################################################

sub ReturnArtist {
###############################################################################
#          Name: ripenc->ReturnArtist (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($num) = shift;
  
  if(defined($num)) {
    if(defined($self{'artist'}[$num])) {
      return $self{'artist'}[$num];
    } else {
      return "";
    }
  } else {
    if(defined($self{'cdartist'})) {
      return $self{'cdartist'};
    } else {
      return "";
    }
  }
}

sub ReturnTitle {
###############################################################################
#          Name: ripenc->ReturnTitle (Public)
#    Parameters: None
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  
  if(defined($self{'title'})) {
    return $self{'title'};
  } else {
    return "";
  }
}

sub ReturnNumTracks {
###############################################################################
#          Name: ripenc->ReturnNumTracks (Public)
#    Parameters: None
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  
  if(defined($self{'num'})) {
    return $self{'num'};
  } else {
    return 0;
  }
}

sub ReturnTrack {
###############################################################################
#          Name: ripenc->ReturnTrack (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($num) = shift;
  if($num <= $self->ReturnNumTracks() && $num > 0) {
    if(defined($self{'track'}[$num]{'name'})) {
      return $self{'track'}[$num]{'name'};
    } else {
      return "";
    }
  } else {
    return undef;
  }
}

sub ReturnRemixer {
###############################################################################
#          Name: ripenc->ReturnRemixer (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($num) = shift;

  if(defined($num)) {
    if(defined($self{'remixer'}[$num])) {
      return $self{'remixer'}[$num];
    } else {
      return "";
    }
  } else {
    if(defined($self{'cdremixer'})) {
      return $self{'cdremixer'};
    } else {
      return "";
    }
  }
}

sub ReturnYear {
###############################################################################
#          Name: ripenc->ReturnRemixer (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($num) = shift;

  if(defined($self{'year'})) {
    return $self{'year'};
  } else {
    return "";
  }
}

sub ReturnType {
###############################################################################
#          Name: ripenc->ReturnType (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;

  if(defined($num)) {
    if(defined($self{'type'}[$num])) {
      return $self{'type'}[$num];
    } else {
      return "";
    }
  } else {
    if(defined($self{'cdtype'})) {
      return $self{'cdtype'};
    } else {
      return "";
    }
  }
}

sub ReturnTrackFrames {
###############################################################################
#          Name: ripenc->ReturnTrackFrames (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($num) = shift;
  if($num <= $self->ReturnNumTracks() && $num > 0) {
    if(defined($self{'track'}[$num]{'frames'})) {
      return $self{'track'}[$num]{'frames'};
    } else {
      return "0";
    }
  } else {
    return undef;
  }
}

sub ReturnFilename {
###############################################################################
#          Name: ripenc->ReturnFilename (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($num) = shift;
  
  my($j) = $self->ReturnNumTracks();
  if($num <= $j && $num > 0) {
    if(defined($self{'filename'}[$num])) {
      return $self{'filename'}[$num];
    } else {
      return "";
    }
  } else {
    return undef;
  }
}

sub ReturnTracksToRip {
###############################################################################
#          Name: ripenc->ReturnTracksToRip (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($num) = shift;

  if($num <= $self->ReturnNumTracks() && $num > 0) {
    return $self{'track'}[$num]{'rip'};
  } else {
    return undef;
  }
}

sub ReturnID3Category {
###############################################################################
#          Name: ripenc->ReturnID3Category (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($num) = shift;
  
  if(defined($num)) {
    if(defined($self{'trackid3cat'}[$num])) {
      return $self{'trackid3cat'}[$num];
    } else {
      return "";
    }
  } else {
    if(defined($self{'id3cat'})) {
      return $self{'id3cat'};
    } else {
      return "";
    }
  }
}

sub ReturnID3Categories {
###############################################################################
#          Name: ripenc->ReturnID3Categorys (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  
  return @{$self{'ID3CATEGORIES'}};
}

sub ReturnID3CategoryName {
###############################################################################
#          Name: ripenc->ReturnID3Category (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($num) = shift;
  
  return $self{'ID3CATEGORIES'}[$num];
}

sub ReturnID3CategoryNum {
###############################################################################
#          Name: ripenc->ReturnID3Category (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($name) = shift;
  my($num) = 0;
  
  @cat = $self->ReturnID3Categories;
  foreach $genre (@cat) {
    if($name eq $genre) {
      return $num;
    }
    $num++;
  }
  
  return undef;
}

sub ReturnCDDBid {
###############################################################################
#          Name: ripenc->ReturnCDDBid (Public)
#    Parameters: None
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  
  if(defined($self{'cddbid'})) {
    return $self{'cddbid'};
  } else {
    return "";
  }
}

sub ReturnCDDBCategory {
###############################################################################
#          Name: ripenc->ReturnCDDBCategory (Public)
#    Parameters: None
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  
  if(defined($self{'cddbcat'})) {
    return $self{'cddbcat'};
  } else {
    return "";
  }
}

sub ReturnCDDBExtd {
###############################################################################
#          Name: ripenc->ReturnCDDBExtd (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  
  if(defined($self{'cddbextd'})) {
    return $self{'cddbextd'};
  } else {
    return "";
  }
}

sub ReturnCDDBTrackExt {
###############################################################################
#          Name: ripenc->ReturnCDDBTrackExt (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($num) = shift;
  if($num <= $self->ReturnNumTracks() && $num > 0) {
    if(defined($self{'cddbext'}[$num])) {
      return $self{'cddbext'}[$num];
    } else {
      return "";
    }
  } else {
    return undef;
  }
}

sub ReturnConfigValue {
###############################################################################
#          Name: ripenc->ReturnConfigValue (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($parameter) = shift;
  
  return $self{'CONFIG'}{uc($parameter)};
}

sub ReturnConfigtestValue {
###############################################################################
#          Name: ripenc->ReturnConfigtestValue (Public)
#    Parameters: 
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($parameter) = shift;
  
  return $self{'configtest'}{lc($parameter)};
}

###############################################################################
# Set Value Functions                                                         #
###############################################################################

sub SetArtist {
###############################################################################
#          Name: ripenc->SetArtist (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($artist) = shift;
  my($num) = shift;

  if(defined($num)) {
    $self{'artist'}[$num] = $artist;
    unless(defined($self{'cdartist'})) {
      $self{'cdartist'} = $artist;
    }
  } else {
    $self{'cdartist'} = $artist;
    for($i = 1; $i <= $self->ReturnNumTracks(); $i++) {
      $self{'artist'}[$i] = $artist;
    }
  }
  return 1;
}

sub SetTitle {
###############################################################################
#          Name: ripenc->SetTitle (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($title) = shift;
  $self{'title'} = $title;
  return 1;
}

sub SetTrack {
###############################################################################
#          Name: ripenc->SetTrack (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($track) = shift;
  my($num) = shift;
  
  if($num <= $self->ReturnNumTracks() && $num > 0) {
    $self{'track'}[$num]{'name'} = $track;
    return 1;
  }

  return undef;
}

sub SetRemixer
###############################################################################
#          Name: ripenc->SetRemixer (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
{
  my($self) = shift;
  my($artist) = shift;
  my($num) = shift;

  if(defined($num)) {
    $self{'remixer'}[$num] = $artist;
    unless(defined($self{'cdremixer'})) {
      $self{'cdremixer'} = $artist;
    }
  } else {
    $self{'cdremixer'} = $artist;
    for($i = 1; $i <= $self->ReturnNumTracks(); $i++) {
      $self{'remixer'}[$i] = $artist;
    }
  }
  return 1;
}

sub SetYear {
###############################################################################
#          Name: ripenc->SetYear (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($title) = shift;
  $self{'year'} = $title;
  return 1;
}

sub SetType
###############################################################################
#          Name: ripenc->SetCDDBTrackExt (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
{
  my($self) = shift;
  my($type) = shift;
  my($num) = shift;

  if(defined($num)) {
    $self{'type'}[$num] = $type;
    unless(defined($self{'cdtype'})) {
      $self{'cdtype'} = $type;
    }
  } else {
    $self{'cdtype'} = $type;
    for($i = 1; $i <= $self->ReturnNumTracks(); $i++) {
      $self{'type'}[$i] = $type;
    }
  }
  return 1;
}


sub SetTrackFrames {
###############################################################################
#          Name: ripenc->SetTrackFrames (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($frames) = shift;
  my($num) = shift;
  
  if($num <= $self->ReturnNumTracks() && $num > 0) {
    $self{'track'}[$num]{'frames'} = $frames;
    return 1;
  }

  return undef;
}

sub SetNumTracks {
###############################################################################
#          Name: ripenc->SetNumTracks (Public)
#    Parameters: None
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($num) = shift;
  $self{'num'} = $num;
  return 1;
}

sub SetFilename {
###############################################################################
#          Name: ripenc->SetFilename (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($file) = shift;
  my($num) = shift;
  
  if($num <= $self->ReturnNumTracks() && $num > 0) {
    $self{'filename'}[$num] = $file;
    return 1;
  }

  return undef;
}

sub SetTracksToRip {
###############################################################################
#          Name: ripenc->SetTracksToRip (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my(@num) = @_;
  my($i, $set) = "";
  
  if($num[0] eq 'ALL') {
    for($i = 1; $i <= $self->ReturnNumTracks(); $i++) {
      $self{'track'}[$i]{'rip'} = 1;
    }
    return 1;
  } else {
    foreach $number (@num) {
      my($j) = $self->ReturnNumTracks();
      if($number <= $j && $number > 0) {
        $self{'track'}[$number]{'rip'} = 1;
        $set = 1;
      }
    }
    if($set) {
      return 1;
    }
  }
  
  return undef;
}

sub SetTracksNotToRip {
###############################################################################
#          Name: ripenc->SetTracksNotToRip (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my(@num) = @_;
  my($i, $set) = "";
  
  if($num[0] eq 'ALL') {
    for($i = 1; $i <= $self->ReturnNumTracks(); $i++) {
      $self{'track'}[$i]{'rip'} = undef;
    }
    return 1;
  } else {
    foreach $number (@num) {
      if($number <= $self->ReturnNumTracks() && $number > 0) {
        $self{'track'}[$number]{'rip'} = undef;
        $set = 1;
      }
    }
    if($set) {
      return 1;
    }
  }
  
  return undef;
}

sub SetID3Category {
###############################################################################
#          Name: ripenc->SetID3Category (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($cat) = shift;
  my($num) = shift;

  if($cat >= 0 && $cat < 150) {
    if(defined($num)) {
      $self{'trackid3cat'}[$num] = $cat;
      unless(defined($self{'id3cat'})) {
        $self{'id3cat'} = $cat;
      }
    } else {
      $self{'id3cat'} = $cat;
      for($i = 1; $i <= $self->ReturnNumTracks(); $i++) {
        $self{'trackid3cat'}[$i] = $cat;
      }
    }
    return 1;
  }
  return undef;
}

sub SetCDDBid {
###############################################################################
#          Name: ripenc->SetCDDBid (Public)
#    Parameters: None
#       Returns: 
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($cddbid) = shift;
  $self{'cddbid'} = $cddbid;
  return 1;
}

sub SetCDDBCategory {
###############################################################################
#          Name: ripenc->SetCDDBCategory (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($cat) = shift;
  my($num) = shift;
  my($i) = 0;
  
  foreach $CATEGORY (@{$self{"CDDBCATEGORIES"}}) {
    if($CATEGORY eq $cat) {
      if(defined($num)) {
        $self{'trackcddbcat'}[$num] = $cat;
        unless(defined($self{'cddbcat'})) {
          $self{'cddbcat'} = $cat;
        }
      } else {
        $self{'cddbcat'} = $cat;
        for($j = 1; $j <= $self->ReturnNumTracks(); $j++) {
          $self{'trackcddbcat'}[$i] = $cat;
        }
        unless(defined($self{'id3cat'})) {
          $self->SetID3Category(@{$self{'ID3CDDBCATEGORIES'}}[$i]);
        }
      }
      return 1;
    }
    $i++;
  }
  
  return undef;
}

sub SetCDDBExtd
###############################################################################
#          Name: ripenc->SetCDDBExtd (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
{
  my($self) = shift;
  my($extd) = shift;
  
  $self{'extd'} = $extd;
  
  return 1;
}

sub SetCDDBTrackExt
###############################################################################
#          Name: ripenc->SetCDDBTrackExt (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
{
  my($self) = shift;
  my($ext) = shift;
  my($num) = shift;
  
  if($num <= $self->ReturnNumTracks() && $num > 0) {
    $self{'cddbext'}[$num] = $ext;
  }

  return undef;
}

sub SetConfigValue {
###############################################################################
#          Name: ripenc->SetConfigValue (Public)
#    Parameters: 
#       Returns: Nothing
#   Description: 
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/2000
###############################################################################
  my($self) = shift;
  my($parameter) = shift;
  my($value) = shift;
  
  $self{'CONFIG'}{uc($parameter)} = $value;
  
  return 1;
}

###############################################################################
# Config Functions                                                            #
###############################################################################

sub Config_TestExternal {
###############################################################################
#          Name: ripenc->Config_TestExternal (Private)
#    Parameters: none
#       Returns: nothing
#   Description: checks to see what encoders and what rippers are installed.
#                then sets them as either 1 or 0 in $self{'configtest'}{'prog'}
#                where prog is the name of the program's binary.
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/1999
###############################################################################
  my($self) = shift;
  my($test) = "";

  #Assume all possible binarieas are installed (and in your path)  
  $self{'configtest'}{'cdparanoia'} = 1;
  $self{'configtest'}{'tosha'} = 1;
  $self{'configtest'}{'dagrab'} = 1;
  $self{'configtest'}{'cdda2wav'} = 1;
  $self{'configtest'}{'bladeenc'} = 1;
  $self{'configtest'}{'lame'} = 1;
  $self{'configtest'}{'notlame'} = 1;
  $self{'configtest'}{'lameogg'} = 1;
  $self{'configtest'}{'notlameogg'} = 1;
  $self{'configtest'}{'oggenc'} = 1;
  $self{'configtest'}{'gogo'} = 1;
  $self{'configtest'}{'l3enc'} = 1;
  $self{'configtest'}{'8hz-mp3'} = 1;

  #Check to see if cdparanoia is not installed
  $test = `cdparanoia 1>&1 2>&1`;
  if($test =~ m/command not found/) {
    $self{'configtest'}{'cdparanoia'} = 0;
  }

  #Check to see if tosha is not installed
  $test = `tosha 1>&1 2>&1`;
  if($test =~ m/command not found/) {
    $self{'configtest'}{'tosha'} = 0;
  }

  #Check to see if dagrab is not installed
  $test = `dagrab 1>&1 2>&1`;
  if($test =~ m/command not found/) {
    $self{'configtest'}{'dagrab'} = 0;
  }

  #Check to see if cdda2wav is not installed
  $test = `cdda2wav 1>&1 2>&1`;
  if($test =~ m/command not found/) {
    $self{'configtest'}{'cdda2wav'} = 0;
  }

  #Check to see if bladeenc is not installed
  $test = `bladeenc 1>&1 2>&1`;
  if($test =~ m/command not found/) {
    $self{'configtest'}{'bladeenc'} = 0;
  }

  #Check to see if lame is not installed
  $test = `lame 1>&1 2>&1`;
  if($test =~ m/command not found/) {
    $self{'configtest'}{'lame'} = 0;
    $self{'configtest'}{'lameogg'} = 0;
    #Check to see if lame is compiled with ogg support
  } else {
    $test = `lame --ogg 1>&1 2>&1`;
    if($test =~ /Error: LAME not compiled with Vorbis support/i) {
      $self{'configtest'}{'lameogg'} = 0;
    }
  }
  
  #Check to see if notlame is not installed
  $test = `notlame 1>&1 2>&1`;
  if($test =~ m/command not found/) {
    $self{'configtest'}{'notlame'} = 0;
    $self{'configtest'}{'notlameogg'} = 0;
    #Check to see if notlame is compiled with ogg support
  } else {
    $test = `notlame --ogg 1>&1 2>&1`;
    if($test =~ /Error: LAME not compiled with Vorbis support/i) {
      $self{'configtest'}{'notlameogg'} = 0;
    }
  }

  #Check to see if oggenc is not installed
  $test = `oggenc 1>&1 2>&1`;
  if($test =~ m/command not found/) {
    $self{'configtest'}{'oggenc'} = 0;
  }
  
  #Check to see if gogo is not installed
  $test = `gogo 1>&1 2>&1`;
  if($test =~ m/command not found/) {
    $self{'configtest'}{'gogo'} = 0;
  }

  #Check to see if l3enc is not installed
  $test = `l3enc 1>&1 2>&1`;
  if($test =~ m/command not found/) {
    $self{'configtest'}{'l3enc'} = 0;
  }

  #Check to see if 8hz-mp3 is not installed
  $test = `8hz-mp3 1>&1 2>&1`;
  if($test =~ m/command not found/) {
    $self{'configtest'}{'8hz-mp3'} = 0;
  }
}


sub Config_Get {
###############################################################################
#          Name: ripenc->Config_Get (Private)
#    Parameters: none
#       Returns: nothing
#   Description: Sets config values to their defaults, then reads their current
#                values to that of the conf file.
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/1999
###############################################################################
  my($self) = shift;

  $self->Config_Defaults();

  chdir;
  if(not -e ".oneripper") {
    mkdir('.oneripper',0700) || die "cannot mkdir .oneripper: $!";
  }

  chdir ".oneripper";
  if(not -e "ripper.conf") {
    $self->Config_Save();
  }
  open(CONFIG, "< ripper.conf") or die "Couldn't open ripper.conf for reading: $!\n";

  while (<CONFIG>) {
    chomp;                  # no newline
    s/#.*//g;                # no comments
    s/^\s+//g;               # no leading white
    s/\s+$//g;               # no trailing white
    next unless length;     # anything left?
    my ($var, $value) = split(/\s*=\s*/, $_, 2);
    $self->SetConfigValue($var, $value);
  }
  close(CONFIG);
}

sub Config_Save {
###############################################################################
#          Name: ripenc->Config_Save (Public)
#    Parameters: none
#       Returns: nothing
#   Description: Writes the contents of the config hash to the file
#                ~/.oneripper/ripper.conf
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/1999
###############################################################################
  my($self) = shift;
  
  chdir;
  chdir ".oneripper";
  
  open(CONFIG, "> ripper.conf") or die "Couldn't open $path for reading: $!\n";
  
  while(($key, $value) = each(%{$self{'CONFIG'}})) {
    print CONFIG "$key = $value\n";
  }
  
  close(CONFIG);
}

sub Config_Defaults {
###############################################################################
#          Name: ripenc->Config_Defaults (Private)
#    Parameters: none
#       Returns: nothing
#   Description: sets all default values to the hash $self{'CONFIG'}{'?'}
#        Author: Devon Jones (soulcatcher@evilsoft.org)
#          Date: 06/29/1999
###############################################################################
  my($self) = shift;
#  $self->SetConfigValue('', '');

  #CD information
  $self->SetConfigValue('CD_DEVICE', '/dev/cdrom');

  #CDDB information
  $self->SetConfigValue('USE_CDDB', 'YES');
#  $self->SetConfigValue('CDDB_HOST', 'cddb.cddb.com');
  $self->SetConfigValue('CDDB_HOST', 'freedb.freedb.org');
#  $self->SetConfigValue('CDDB_HOST', 'freedb.instinct.org');
  $self->SetConfigValue('CDDB_PORT', '888');
  $self->SetConfigValue('CDDB_ALLOW_WRITE', 'NO');
#  $self->SetConfigValue('CDDB_SMTP', 'mail');
#  $self->SetConfigValue('CDDB_SMTP', 'shadow.evilsoft.org');
#  $self->SetConfigValue('CDDB_SUBMIT', 'freedb-submit@freedb.org');
#  $self->SetConfigValue('CDDB_SUBMIT', 'devon@integware.com');
  
  #Ripper Information
  $self->SetConfigValue('USE_RIPPER', 'YES');
  $self->SetConfigValue('RIPPER', 'cdparanoia');
  $self->SetConfigValue('SAVETO', '/tmp');
  $self->SetConfigValue('WHOLECD', 'YES');
  $self->SetConfigValue('DELWAV', 'YES');
  
  #Encoder Information
  $self->SetConfigValue('USE_ENCODER', 'YES');
  $self->SetConfigValue('ENCODER', 'lame');
  $self->SetConfigValue('VBR', 'YES');
  $self->SetConfigValue('CBR_BITRATE', '160');
  $self->SetConfigValue('VBR_BITRATE', '4');
  $self->SetConfigValue('FILEMASK', '%A-[@Y()@R{}%C]-%N-%T');
  $self->SetConfigValue('ENCFLAGS', '');
  $self->SetConfigValue('UNDERSCORE', 'NO');

  #Id3 Information
  $self->SetConfigValue('USE_TAGGING', 'YES');
  $self->SetConfigValue('USE_TAGGING_ONE', 'YES');
  $self->SetConfigValue('USE_TAGGING_TWO', 'YES');
}


1;
__END__

# Below is the stub of documentation for your module. You better edit it!

=head1 NAME

ripenc - library for ripping tracks from CDs to mp3 or ogg files.

=head1 SYNOPSIS

 #This will rip song 1, and encode it - naming it via CDDB.
 use ripenc;
 
 $ripper = new ripenc();
 $ripper->CDDB_GetCD();
 $ripper->CDDB_GetCDData();
 $ripper->Ripper_GetSong(1);
 $ripper->Encoder_DoNext();

 # The following are all of the public methods that can be used.

 CDDB_GetCD
 CDDB_GetCDData
 Ripper_Start
 Ripper_DoNext
 Ripper_GetSong
 Ripper_FileNames
 Encoder_DoNext
 InitCD
 ResetState
 ReturnArtist
 ReturnTitle
 ReturnNumTracks
 ReturnTrack
 ReturnTrackFrames
 ReturnFilename
 ReturnTracksToRip
 ReturnID3Category
 ReturnCDDBid
 ReturnCDDBCategory
 ReturnCDDBExtd
 ReturnCDDBTrackExt
 ReturnConfigValue
 ReturnConfigtestValue
 SetArtist
 SetTitle
 SetTrack
 SetTrackFrames
 SetNumTracks
 SetFilename
 SetTracksToRip
 SetTracksNotToRip
 SetID3Category
 SetCDDBid
 SetCDDBCategory
 SetCDDBExtd
 SetCDDBTrackExt
 SetConfigValue
 Config_Save

#  (c) Devon Jones <soulcatcher@evilsoft.org
#  Derived from code (c) 2000 Armin Obersteiner <armin@xos.net>
#
#  LICENSE
#
#  This library is released under the same conditions as Perl, that
#  is, either of the following:
#
#  a) the GNU General Public License as published by the Free
#  Software Foundation; either version 1, or (at your option) any
#  later version.
#
#  b) the Artistic License.
#
