#!/usr/bin/perl -w

use ripenc;

$VERSION = "0.96";
$PROGVER = $VERSION;

$SIG{CHLD} = 'IGNORE';

$ripper=new ripenc();

$choice = 0;

while($choice != 8) {
  PrintMenu($ripper);
  $choice = <STDIN>;
  $choice =~ s/\n//;
  SWITCH: {
    if($choice == 1)   { OptPrefs($ripper); last SWITCH; }
    if($choice == 2)   { system("eject " . $ripper->ReturnConfigValue('CD_DEVICE')); last SWITCH; }
    if($choice == 3)   { OptEncode($ripper); last SWITCH; }
    if($choice == 4)   { EncoderSpawn($ripper); last SWITCH; }
    if($choice == 5)   { OptList($ripper); last SWITCH; }
    if($choice == 6)   { EncoderMeter($ripper); last SWITCH; }
    if($choice == 7)   { OptAbout(); last SWITCH; }
  }
}    


sub OptPrefs {
  $ripper = shift;
  my($choice) = 0;

  while($choice != 13) {
    PrintConfigMenu($ripper);
    $choice = <STDIN>;
    $choice =~ s/\n//;
    SWITCH: {
      if($choice eq '2a') { OptVBR($ripper); last SWITCH; }
      if($choice eq '5a') { OptCDDBServer($ripper); last SWITCH; }
      if($choice eq '5b') { OptCDDBPort($ripper); last SWITCH; }
      if($choice == 1)    { OptDirectory($ripper); last SWITCH; }
      if($choice == 2)    { OptEncoder($ripper); last SWITCH; }
      if($choice == 3)    { OptRipper($ripper); last SWITCH; }
      if($choice == 4)    { OptId3($ripper); last SWITCH; }
      if($choice == 5)    { OptCDDB($ripper); last SWITCH; }
      if($choice == 6)    { OptName($ripper); last SWITCH; }
      if($choice == 7)    { OptUnderscore($ripper); last SWITCH; }
      if($choice == 8)    { OptCD($ripper); last SWITCH; }
      if($choice == 9)    { OptCDDevice($ripper); last SWITCH; }
      if($choice == 10)   { OptEncValue($ripper); last SWITCH; }
      if($choice == 11)   { OptEncFlags($ripper); last SWITCH; }
      if($choice == 12)   { OptDelWav($ripper); last SWITCH; }
    }
  }    
}

sub OptEncode {
  $ripper = shift;

  my($i) = 1;
  system("clear");
 
  # If CDDB is off, or cannot find it, then init the CD to get hte number of tracks.
  eval {
    $ripper->ResetCD();
    $ripper->InitCD();
  };

  if($@) {
    print "Cannot Read from CDROM Device\n";
    $pick = <STDIN>;
    $pick = undef;
    return undef;
  }

  # Check CDDB for CD
  if(!GetCDDB($ripper)) {
    return undef;
  }

  # Determine if all tracks should be ripped or not
  if($ripper->ReturnConfigValue('WHOLECD') eq 'YES') {
    $ripper->SetTracksToRip('ALL');
  } else {
    $ripper->SetTracksNotToRip('ALL');
  }

  $change = 0;
  while($change ne '') {
    PrintEditMenu($ripper);
    $change = <STDIN>;
    $change =~ s/\n//;
    if($change eq '') {
      $change = '';
    }
    elsif($change =~ /a/i) {
      print "\n  Artist (Will change the artist for all songs)\n";
      print "\n  " . $ripper->ReturnArtist() . "\n";
      print "-> ";
      $artist = <STDIN>;
      $artist =~ s/\n//;
      if($artist =~ /^\s*$/) {
        $artist = $ripper->ReturnArtist();
      }
      $ripper->SetArtist($artist);
    }
    elsif($change =~ /b/i) {
      print "\n  CD Title\n";
      print "\n  " . $ripper->ReturnTitle() . "\n";
      print "-> ";
      $title = <STDIN>;
      $title =~ s/\n//;
      if($title =~ /^\s*$/) {
        $title = $ripper->ReturnTitle();
      }
      $ripper->SetTitle($title);
    }
    elsif($change =~ /c/i) {
      PrintId3Menu($ripper);
      $genre = <STDIN>;
      $genre =~ s/\n//;
      if($genre =~ /\d*/) {
        @categories = sort($ripper->ReturnID3Categories());
        $category = $categories[$genre-1];
        $catnum = $ripper->ReturnID3CategoryNum($category);
        $ripper->SetID3Category($catnum);
      }
    }
    elsif($change =~ /d/i) {
      print "\n  Remixer (Will change the remixer for all songs)\n";
      print "\n  " . $ripper->ReturnRemixer() . "\n";
      print "-> ";
      $remixer = <STDIN>;
      $remixer =~ s/\n//;
      if($remixer =~ /^\s*$/) {
        $remixer = $ripper->ReturnRemixer();
      }
      $ripper->SetRemixer($remixer);
    }
    elsif($change =~ /e/i) {
      print "\n  CD Year\n";
      print "\n  " . $ripper->ReturnYear() . "\n";
      print "-> ";
      $year = <STDIN>;
      $year =~ s/\n//;
      if($year =~ /^\s*$/ || $year =~ /\D/) {
        $year = $ripper->ReturnYear();
      }
      $ripper->SetYear($year);
    }
    elsif($change =~ /f/i) {
      my($tracks) = $ripper->ReturnNumTracks();
      for($i = 1; $i <= $tracks; $i++) {
        SplitTrack($ripper, $i)
      }
    }
    elsif($change =~ /g/i) {
      my($tracks) = $ripper->ReturnNumTracks();
      for($i = 1; $i <= $tracks; $i++) {
        SplitTrack($ripper, $i, 1)
      }
    }
    elsif($change =~ /h/i) {
      my($type) = $ripper->ReturnType();
      if($type =~ /remix/i) {
        $type =~ s/remix\s*//i;
      } else {
        $type = "Remix " . $type;
      }
      
      $ripper->SetType($type);
    }
    elsif($change =~ /i/i) {
      my($type) = $ripper->ReturnType();
      if($type =~ /soundtrack/i) {
        $type =~ s/soundtrack\s*//i;
      } else {
        $type = "Soundtrack " . $type;
      }
      
      $ripper->SetType($type);
    }
    elsif($change =~ /j/i) {
      my($type) = $ripper->ReturnType();
      if($type =~ /live/i) {
        $type =~ s/live\s*//i;
      } else {
        $type = "Live " . $type;
      }
      
      $ripper->SetType($type);
    }
    elsif($change =~ /n/i) {
      return undef;
    }
    elsif($change =~ /\d*/) {
      my($artist) = $ripper->ReturnArtist($change);
      my($remixer) = $ripper->ReturnRemixer($change);
      my($track) = $ripper->ReturnTrack($change);
      my($cat) = $ripper->ReturnID3CategoryName($ripper->ReturnID3Category($change));
      my($type) = $ripper->ReturnType($change);
      print "\n  a) Artist: $artist\n";
      print "  b) Track: $track\n";
      print "  c) Genre: $cat\n";
      print "  d) Guess: Track is - artist / track\n";
      print "  e) Guess: Track is - track / artist\n";
      print "     Type: $type\n";
      print "  f) Mark as Remix (Toggle)\n";
      print "  g) Mark as Live (Toggle)\n";
      if($type =~ /remix/i) {
        print "  h) Remixer: $remixer\n";
      }
      print "-> ";
      $trackch = <STDIN>;
      $trackch =~ s/\n//;
      if($trackch =~ /a/i) {
        print "\n  Artist:\n";
        print "\n  " . $ripper->ReturnArtist($change) . "\n";
        print "-> ";
        $art = <STDIN>;
        $art =~ s/\n//;
        if($art =~ /^\s*$/) {
          $art = $ripper->ReturnArtist($change);
        }
        $ripper->SetArtist($art, $change);
      }
      elsif($trackch =~ /b/i) {
        print "\n  Track:\n";
        print "\n  " . $ripper->ReturnTrack($change) . "\n";
        print "-> ";
        $tr = <STDIN>;
        $tr =~ s/\n//;
        if($tr =~ /^\s*$/) {
          $tr = $ripper->ReturnTrack($change);
        }
        $ripper->SetTrack($tr, $change);
      }
      elsif($trackch =~ /c/i) {
        PrintId3Menu($ripper);
        $genre = <STDIN>;
        $title =~ s/\n//;
        if($genre =~ /(\d*)/) {
          $ripper->SetID3Category($1, $change);
        }
      }
      elsif($trackch =~ /d/i) {
        SplitTrack($ripper, $change)
      }
      elsif($trackch =~ /e/i) {
        SplitTrack($ripper, $change, 1)
      }
      elsif($trackch =~ /f/i) {
        my($type) = $ripper->ReturnType($change);
        if($type =~ /remix/i) {
          $type =~ s/remix\s*//i;
        } else {
          $type = "Remix " . $type;
        }

        $ripper->SetType($type, $change);
      }
      elsif($trackch =~ /g/i) {
        my($type) = $ripper->ReturnType($change);
        if($type =~ /live/i) {
          $type =~ s/live\s*//i;
        } else {
          $type = "Live " . $type;
        }

        $ripper->SetType($type, $change);
      }
      elsif($trackch =~ /h/i) {
        print "\n  Remixer:\n";
        print "\n  " . $ripper->ReturnRemixer($change) . "\n";
        print "-> ";
        $art = <STDIN>;
        $art =~ s/\n//;
#        if($art =~ /^\s*$/) {
#          $art = $ripper->ReturnRemixer($change);
#        }
        $ripper->SetRemixer($art, $change);
      }
    }
  }

  $change = 0;
  while($change ne '') {
    PrintTracksMenu($ripper);
    $change = <STDIN>;
    $change =~ s/\n//;
    if($change =~ /a/i) {
      my($dir) = $ripper->ReturnTracksToRip(1);
      if($dir) {
        $ripper->SetTracksNotToRip('ALL');
      } else {
        $ripper->SetTracksToRip('ALL');
      }
    }
    elsif($change =~ /n/i) {
      return undef;
    }
    elsif($change =~ /\d/) {
      my($dir) = $ripper->ReturnTracksToRip($change);
      if($dir) {
        $ripper->SetTracksNotToRip($change);
      } else {
        $ripper->SetTracksToRip($change);
      }
    }
  }
  
  $frames = 0;
  for($i = 1; $i <= $ripper->ReturnNumTracks(); $i++) {
    if($ripper->ReturnTracksToRip($i)) {
      $frames = $frames + $ripper->ReturnTrackFrames($i);
    }
  }

  chdir;
  chdir($ripper->ReturnConfigValue('SAVETO'));
  @output = `df -k .`;
  if($output[1] =~ /\/.*?\/.*?\s\s*\d*\s*\d*\s*(\d*).*/ ) {
    $kleft = $1;
    $kleft += 3000;
    $kleft = $kleft * 1024;
    $kframes = int(($frames * 2352));
    if($kleft <= $kframes) {
      print(" Space needed ($kframes)\n is less then the amount left in working directory ($kleft)\n");
      $x = <STDIN>;
      undef($x);
      return undef;
    }
  }
  $ripper->Cache_Create();
  EncoderSpawn($ripper);
  RipperSpawn($ripper);
}

sub PrintMenu {
  $ripper = shift;
  system("clear");
  print "The One Ripper - version $PROGVER, Copyright (C) 2000 Devon Jones\n";
  print '<soulcatcher@evilsoft.org>, The One Ripper comes with ABSOLUTELY NO WARRANTY' . "\n\n";

  $saveto = $ripper->ReturnConfigValue('SAVETO');
  print " 1) Change Preferences\n";
  print " 2) Eject cd-rom\n";
  print " 3) Start Ripper\n";
  print " 4) Start Background Encoder\n";
  print " 5) View/Edit the background encoding queue\n";
  print " 6) View Status of Background Encoder\n";
  print " 7) About\n";
  print " 8) Exit\n";
  print "-> "; 
}

sub PrintConfigMenu {
  $ripper = shift;
  system("clear");
  print "The One Ripper - version $PROGVER, Copyright (C) 2000 Devon Jones\n";
  print '<soulcatcher@evilsoft.org>, The One Ripper comes with ABSOLUTELY NO WARRANTY' . "\n\n";

  $saveto = $ripper->ReturnConfigValue('SAVETO');
  print " 1) Change working directory....................[$saveto]\n";

  $encoder = $ripper->ReturnConfigValue('ENCODER');
  print " 2) Choose encoder..............................[$encoder]\n";
  $vbr = $ripper->ReturnConfigValue('VBR');
  if($encoder eq 'lame' || $encoder eq 'gogo') {
    print "    2a) Use Variable Bit Rate...................[$vbr]\n";
  }

  $rip = $ripper->ReturnConfigValue('RIPPER');
  print " 3) Choose ripper...............................[$rip]\n";

  if($ripper->ReturnConfigValue('USE_TAGGING') eq 'NO') {
    $id3 = 'NO'
  } else {
    $id3 = 'YES';
    if($ripper->ReturnConfigValue('USE_TAGGING_ONE') eq 'YES') {
      $id3 .= ' 1';
    }
    if($ripper->ReturnConfigValue('USE_TAGGING_TWO') eq 'YES') {
      $id3 .= ' 2';
    }
  }
  print " 4) Use id3.....................................[$id3]\n";

  $cddb = $ripper->ReturnConfigValue('USE_CDDB');
  if($cddb eq 'YES') { $cddb = 'cddb'; }
  else { $cddb = 'manual'; }
  print " 5) Toggle between Manual and CDDB naming.......[$cddb]\n";
  if($cddb eq 'cddb') {
    $cddbhost = $ripper->ReturnConfigValue('CDDB_HOST');
    print "    5a)Set CDDB Server..........................[$cddbhost]\n";
    $cddbport = $ripper->ReturnConfigValue('CDDB_PORT');
    print "    5b)Set CDDB Server Port.....................[$cddbport]\n";
  }

  $mask = $ripper->ReturnConfigValue('FILEMASK');
  $mask =~ s/%A/Artist/g;
  $mask =~ s/%T/Track/g;
  $mask =~ s/%C/Cd Title/g;
  $mask =~ s/%N/TrackNo/g;
  $mask =~ s/&A.../Artist/g;
  $mask =~ s/&T.../Track/g;
  $mask =~ s/&C.../Cd Title/g;
  print " 6) Set preferred naming convention.............[$mask]\n";

  if($ripper->ReturnConfigValue('UNDERSCORE') eq 'NO') {
    $underscore = 'NO'
  } else {
    $underscore = 'YES';
  }
  print " 7) Convert Spaces to Underscores in file name..[$underscore]\n";
  
  $wholecd = $ripper->ReturnConfigValue('WHOLECD');
  print " 8) Rip whole CD?...............................[$wholecd]\n";
  $cddevice = $ripper->ReturnConfigValue('CD_DEVICE');
  print " 9) Please select your Cd-Rom device............[$cddevice]\n";
  if($vbr eq 'YES' && ($encoder eq 'lame' || $encoder eq 'gogo')) {
    $vbrrate = $ripper->ReturnConfigValue('VBR_BITRATE');
    print "10) Set the VBR rate for the encoded MP3's......[$vbrrate]\n";
  } elsif($encoder eq 'oggenc') {
    $vbrrate = $ripper->ReturnConfigValue('VBR_BITRATE');
    print "10) Set the Quality for the encoded OGG's.......[$vbrrate]\n";
    $cbrrate = $ripper->ReturnConfigValue('CBR_BITRATE');
    print "    And Set the Bitrate for the encoded OGG's...[$cbrrate]\n";
  } else {
    $cbrrate = $ripper->ReturnConfigValue('CBR_BITRATE');
    print "10) Set the Bitrate for the encoded MP3's.......[$cbrrate]\n";
  }
  $encoderflags = $ripper->ReturnConfigValue('ENCFLAGS');
  print "11) Other Flags to pass to encoder..............[$encoderflags]\n";
  $delwav = $ripper->ReturnConfigValue('DELWAV');
  print "12) Delete wav files when finished?.............[$delwav]\n";
  print "13) Return to Main Menu\n";
  print "-> "; 
}

sub PrintTracksMenu {
  $ripper = shift;
  # Print out a listing of the CD where a person can determine what tracks to rip  
  system("clear");
  my($tracks) = $ripper->ReturnNumTracks();
  my($cdartist) = $ripper->ReturnArtist();
  my($cdtitle) = $ripper->ReturnTitle();
  my($cdremixer) = $ripper->ReturnRemixer();
  my($cdtype) = $ripper->ReturnType();
  my($frames) = 0;
  
  print "\n\nCD Contents (Encode)\n\n";
  print "   CD Artist:  $cdartist\n";
  print "   CD Title:   $cdtitle\n";
  if($cdtype =~ /remix/i) {
    print "   CD Remixer: $cdremixer\n";
  }
  print "               $cdtype\n";
  print "               $tracks tracks\n\n";
  
  for($i = 1; $i <= $tracks; $i++) {
    my($artist) = $ripper->ReturnArtist($i);
    my($track) = $ripper->ReturnTrack($i);
    my($rip) = $ripper->ReturnTracksToRip($i);
    my($type) = $ripper->ReturnType($i);
    my($remixer) = $ripper->ReturnRemixer($i);
    
    $type =~ s/^\s+//;
    $type =~ s/\s+$//;
    $type =~ s/Live/L/;
    $type =~ s/Remix/R/;
    $type =~ s/Soundtrack/S/;
    $remixer =~ s/^\s+//;
    $remixer =~ s/\s+$//;

    my($num) = $i;
    if($i <= 9) {
      $num = " $i";
    }

    my($todo) = "[N]";
    if($rip) {
      $todo = "[Y]";
      $frames = $frames + $ripper->ReturnTrackFrames($i);
    }

    print "  $num) $todo $track ($artist)";
    if($type) {
      print(" ($type)");
    }
    if($remixer) {
      print(" {$remixer}");
    }
    print("\n")
  }

  chdir;
  chdir($ripper->ReturnConfigValue('SAVETO'));
  @output = `df -k .`;
  if($output[1] =~ /\/.*?\/.*?\s\s*\d*\s*\d*\s*(\d*).*/ ) {
    $kleft = $1;
    $kleft += 3000;
    $kleft = $kleft * 1024;
    $kframes = int(($frames * 2352));
    #$kleft /= 1024;
    #$kframes /= 1024;
    $kleft /= 1048576;
    $kframes /= 1048576;
    print("\n  Space needed:    (" . int($kframes) . " M)");
    print("\n  Space avaliable: (" . int($kleft) . " M)\n");
  }

  print "\n  a) All\n";
  print "\n  n) Exit\n\n";
  print "\n  Enter) Done\n";
  print "->";
}

sub PrintEditMenu {
  $ripper = shift;
  # Print out a listing of the CD where a person can determine what tracks to rip  
  system("clear");
  my($tracks) = $ripper->ReturnNumTracks();
  my($cdartist) = $ripper->ReturnArtist();
  my($cdtitle) = $ripper->ReturnTitle();
  my($category) = $ripper->ReturnID3CategoryName($ripper->ReturnID3Category());
  my($cdremixer) = $ripper->ReturnRemixer();
  my($cdtype) = $ripper->ReturnType();
  my($cdyear) = $ripper->ReturnYear();
  
  print "\n\nCD Contents (Encode)\n\n";
  print "   a) CD Artist:  $cdartist\n";
  print "   b) CD Title:   $cdtitle\n";
  print "   c) CD Genre:   $category\n";
  if($cdtype =~ /remix/i) {
  print "   d) CD Remixer: $cdremixer\n";
  }
  print "   e) CD Year:    $cdyear\n";
  print "                  $cdtype\n";
  print "                  $tracks tracks\n\n";
  
  for($i = 1; $i <= $tracks; $i++) {
    my($artist) = $ripper->ReturnArtist($i);
    my($track) = $ripper->ReturnTrack($i);
    my($type) = $ripper->ReturnType($i);
    my($remixer) = $ripper->ReturnRemixer($i);

    $type =~ s/^\s+//;
    $type =~ s/\s+$//;
    $type =~ s/Live/L/;
    $type =~ s/Remix/R/;
    $type =~ s/Soundtrack/S/;
    $remixer =~ s/^\s+//;
    $remixer =~ s/\s+$//;

    my($num) = $i;
    if($i <= 9) {
      $num = " $i";
    }

    print "  $num) $track ($artist)";
    if($type) {
      print(" ($type)");
    }
    if($remixer) {
      print(" {$remixer}");
    }
    print("\n")
  }
  print "\n   f) Rename all songs Guess: Track is - artist / track\n";
  print "   g) Rename all songs Guess: Track is - track / artist\n";
  print "   h) Mark as Remix CD (Toggle)\n";
  print "   i) Mark as Soundtrack (Toggle)\n";
  print "   j) Mark as Live CD (Toggle)\n";
  print "   n) Exit\n\n";
  print "\n   Enter) Done\n";
  print "-> ";
}

sub PrintQueueMenu {
  $ripper = shift;

  my(@files, $file);
  
  # Read the files in the .oneripper/ripper.queue directory
  chdir;
  chdir ".oneripper";
  opendir(QUEUE, "ripper.queue");
  undef(@files);
  while( defined ($file = readdir QUEUE) ) {
    next if $file =~ /^\.\.?$/;
    push(@files, $file);
  }
  
  # Sort the files, and take the next one.
  @files = sort(@files);

  $num = 0;

  system("clear");
  print("\n\nCurrent encoding queue\n\n");
  foreach $file (@files) {
    $num++;

    chdir "ripper.queue";
    open QUEUEREAD, "< $file" or die "Encode: No songs to rip: $!\n";
    while(<QUEUEREAD>) {
      push(@queueline, $_);
    }
    close(QUEUEREAD);
    my($filename, $CDArtist, $CDTitle, $CDid3, $CDCDDBCat, $CDCDDBExt, $CDCDDBId, $CDTrackNo, $TrackArtist, $TrackName, $Trackid3, $TrackCDDBCat, $TrackCDDBExt, $CDRemixer, $CDType, $TrackRemixer, $TrackType) = $ripper->ParseQueueLine(shift(@queueline));
    
    if($file =~ /^E/) {
      $TrackArtist = "[Error] $TrackArtist";
    }
    elsif($file =~ /^0/) {
      $TrackArtist = "[Active] $TrackArtist";
    }
    $dir = $ripper->ReturnConfigValue('SAVETO'); 
    chdir($dir);
    $filename =~ s/.*\///;
    $filename =~ s/\\//g;
    unless(-e $filename) {
      $TrackName .= " {Warning, Wave file missing}";
    }
    chdir;
    chdir ".oneripper";
    chdir "ripper.queue";
    print "  $num) $TrackArtist - $TrackName\n";
  }
  print "   n) Exit\n\n";
  print "\n   Enter) Done\n";
  print "-> ";
  return @files;
}

sub PrintId3Menu {
  $ripper = shift;
  
  system("clear");
  print("\n\nSelect a genre.\n\n");
  my($category);
  my($num) = 1;
  @categories = sort($ripper->ReturnID3Categories());
  
  foreach $category (@categories) {
    if($category) {
      printf(" %3s) %-20.20s ", $num, $category);
      if($num % 3 == 0) {
        print "\n";
      }
    }
    $num++;
  }
  print("\n->");
}

sub OptAbout {
  system("clear");
  print "\n\nThe One Ripper:";
  print "\n\nThree Rippers for the Java-kings compiling on-the-fly,";
  print "\nSeven for the Mac-lords in their cases of gemstone,";
  print "\nNine for Mortal Windows doomed to die,";
  print "\nOne for the Dark Lord on his dark throne";
  print "\nIn the Land of POSIX where the Programmers lie.";
  print "\nOne Ripper to rule them all, One Ripper to cut them,";
  print "\nOne Ripper to encode them all and in the darkness tag them";
  print "\nIn the Land of POSIX where the Programmers lie.";
  print "\n\n  -- The Lord of the Rippers";
  print "\n    (With appologies to J.R.R. Tolkien)";
  print "\n\nVersion $PROGVER";
  print "\nCopyright (C) 2000, 2001  Devon Jones " . '<soulcatcher@evilsoft.org>';
  print "\nThe One Ripper comes with ABSOLUTELY NO WARRANTY";
  print "\n\nRequired:";
  print "\nPerl 5.006";
  print "\ntagged 0.25 or later";
  print "\n\nThe One Ripper can use the following Encoders";
  print "\nLAME/NotLame 3.86beta or later";
  print "\nBladeenc 0.82 or later";
  print "\nOggenc 0.7 or later";
  print "\ngogo 2.39 or later";
  print "\n\nThe One Ripper can use the following Rippers";
  print "\ncdparanoia 9.6 or later";
  print "\ndagrab 0.3.5 or later";
  print "\ncdda2wav 0.6 or later";
  print "\n\nPress [Enter] to return to main menu.\n";
  $x = <STDIN>;
  undef($x);
}

sub OptList {
  $ripper = shift;
  $choice = 'x'; 
  while($choice ne '') {
    @files = PrintQueueMenu($ripper);
    $choice = <STDIN>;
    $choice =~ s/\n//;
    if($choice eq '') {
      $choice = '';
    }
    elsif($choice =~ /n/i) {
      return undef;
    }
    elsif($choice =~ /\d*/) {
      chdir;
      chdir ".oneripper";
      chdir "ripper.queue";
      $file = $files[$choice - 1];
      open QUEUEREAD, "< " . $file or die "Encode: No songs to rip: $!\n";
      while(<QUEUEREAD>) {
        push(@queueline, $_);
      }
      close(QUEUEREAD);
      my($filename, $CDArtist, $CDTitle, $CDid3, $CDCDDBCat, $CDCDDBExt, $CDCDDBId, $CDTrackNo, $TrackArtist, $TrackName, $Trackid3, $TrackCDDBCat, $TrackCDDBExt, $CDRemixer, $CDType, $TrackRemixer, $TrackType) = $ripper->ParseQueueLine(shift(@queueline));

      if($files[$choice - 1] =~ /^E/)
      {
        print "\n  1) Unmark as error"
      }
      print "\n  a) Delete\n";
      print "  b) Move to top\n";
      print "  c) Move to bottom\n";
      print "  d) Artist: $TrackArtist\n";
      print "  e) Track: $TrackName\n";
      print "  f) CD Title: $CDTitle\n";
      print "  g) Track No: $CDTrackNo\n";
#      print "  h) Category: $Trackid3\n";
      print "  n) Exit\n\n";
      print "\n   Enter) Done\n";
      print "-> ";
      $trackch = <STDIN>;
      $trackch =~ s/\n//;
      if($trackch =~ /1/ && $file =~ /^E/)
      {
        $file =~ s/^E//;
        rename("E$file", "$file");
      }
      elsif($trackch =~ /a/i) {
        unlink($file);
        chdir($ripper->ReturnConfigValue('SAVETO'));
        $filename =~ s/.*\///;
        $filename =~ s/\\//g;
        unlink("$filename");
      }
      elsif($trackch =~ /b/i) {
        rename("$file", "1$file");
      }
      elsif($trackch =~ /c/i) {
        rename("$file", "9$file");
      }
      elsif($trackch =~ /d/i) {
        print "\n  Artist:\n";
        print "\n  " . $TrackArtist . "\n";
        print "-> ";
        $art = <STDIN>;
        $art =~ s/\n//;
        unless($art =~ /^\s*$/) {
          chdir;
          chdir ".oneripper";
          chdir "ripper.queue";
          open(QUEUEWRITE, "> $file") or die "Couldn't open $path for reading: $!\n";
          # 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 "$filename || $CDArtist || $CDTitle || $CDid3 || $CDCDDBCat || $CDCDDBExt || $CDCDDBId || $CDTrackNo || $art || $TrackName || $Trackid3 || $TrackCDDBCat || $TrackCDDBExt");
          close(QUEUEWRITE);
        }
      }
      elsif($trackch =~ /e/i) {
        print "\n  Track:\n";
        print "\n  " . $TrackName . "\n";
        print "-> ";
        $track = <STDIN>;
        $track =~ s/\n//;
        unless($track =~ /^\s*$/) {
          chdir;
          chdir ".oneripper";
          chdir "ripper.queue";
          open(QUEUEWRITE, "> $file") or die "Couldn't open $path for reading: $!\n";
          # 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 "$filename || $CDArtist || $CDTitle || $CDid3 || $CDCDDBCat || $CDCDDBExt || $CDCDDBId || $CDTrackNo || $TrackArtist || $track || $Trackid3 || $TrackCDDBCat || $TrackCDDBExt");
          close(QUEUEWRITE);
        }
      }
      elsif($trackch =~ /f/i) {
        print "\n  CD Title:\n";
        print "\n  " . $CDTitle . "\n";
        print "-> ";
        $title = <STDIN>;
        $title =~ s/\n//;
        unless($title =~ /^\s*$/) {
          chdir;
          chdir ".oneripper";
          chdir "ripper.queue";
          open(QUEUEWRITE, "> $file") or die "Couldn't open $path for reading: $!\n";
          # 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 "$filename || $CDArtist || $title || $CDid3 || $CDCDDBCat || $CDCDDBExt || $CDCDDBId || $CDTrackNo || $TrackArtist || $TrackName || $Trackid3 || $TrackCDDBCat || $TrackCDDBExt");
          close(QUEUEWRITE);
        }
      }
      elsif($trackch =~ /g/i) {
        print "\n  Track No:\n";
        print "\n  " . $CDTrackNo . "\n";
        print "-> ";
        $no = <STDIN>;
        $no =~ s/\n//;
        if($no =~ /\d*/) {
          $no = int($no);
          if($no < 10)
          {
            $no = "0$no";
          }
          chdir;
          chdir ".oneripper";
          chdir "ripper.queue";
          open(QUEUEWRITE, "> $file") or die "Couldn't open $path for reading: $!\n";
          # 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 "$filename || $CDArtist || $CDTitle || $CDid3 || $CDCDDBCat || $CDCDDBExt || $CDCDDBId || $no || $TrackArtist || $TrackName || $Trackid3 || $TrackCDDBCat || $TrackCDDBExt");
          close(QUEUEWRITE);
          $x = <STDIN>;
        }
      }
    }
  }
}

sub OptId3 {
  $ripper = shift;

  my($tag1) = $ripper->ReturnConfigValue('USE_TAGGING_ONE');
  my($tag2) = $ripper->ReturnConfigValue('USE_TAGGING_TWO');

  print "  a) Use all tag types (Id3 V1, V2)\n";
  print "  b) Use Id3V1 tags\n";
  print "  c) Use Id3V2 tags\n";
  print "  d) Use no tags\n";
  print "\nTags -> [a,b,c,d] ";
  $tag = <STDIN>;
  
  if($tag =~ /a/) {
    $ripper->SetConfigValue('USE_TAGGING', 'YES');
    $ripper->SetConfigValue('USE_TAGGING_ONE', 'YES');
    $ripper->SetConfigValue('USE_TAGGING_TWO', 'YES');
  }
  elsif($tag =~ /b/) {
    $ripper->SetConfigValue('USE_TAGGING', 'YES');
    if($tag1 eq 'YES') {
      $ripper->SetConfigValue('USE_TAGGING_ONE', 'NO');
    }
    else {
      $ripper->SetConfigValue('USE_TAGGING_ONE', 'YES');
    }
  }
  if($tag =~ /c/) {
    $ripper->SetConfigValue('USE_TAGGING', 'YES');
    if($tag2 eq 'YES') {
      $ripper->SetConfigValue('USE_TAGGING_TWO', 'NO');
    } else {
      $ripper->SetConfigValue('USE_TAGGING_TWO', 'YES');
    }
  }
  if($tag =~ /d/) {
    $ripper->SetConfigValue('USE_TAGGING', 'NO');
    $ripper->SetConfigValue('USE_TAGGING_ONE', 'NO');
    $ripper->SetConfigValue('USE_TAGGING_TWO', 'NO');
  }
  $ripper->Config_Save();
}

sub OptEncValue {
  $ripper = shift;
  my($vbr) = $ripper->ReturnConfigValue('VBR');
  my($encoder) = $ripper->ReturnConfigValue('ENCODER');
  if($vbr eq 'YES' && ($encoder eq 'lame' || $encoder eq 'gogo')) {
    print "\nVBR Rate -> [0-9] ";
    $rate = <STDIN>;
    $rate =~ s/\n//;
    if($rate eq '') {
      return;
    }
    $ripper->SetConfigValue('VBR_BITRATE', $rate);
  } elsif($encoder eq 'oggenc') {
    print "\nQuality Rate -> [0-9] ";
    $rate = <STDIN>;
    $rate =~ s/\n//;
    if($rate eq '') {
      return;
    }
    $ripper->SetConfigValue('VBR_BITRATE', $rate);
    print "\nBitate -> [32 40 48 56 64 80 96 112 128 160 192 224 256 320] ";
    $rate = <STDIN>;
    $rate =~ s/\n//;
    if($rate eq '') {
      return;
    }
    $ripper->SetConfigValue('CBR_BITRATE', $rate);
  } else {
    print "\nBitate -> [32 40 48 56 64 80 96 112 128 160 192 224 256 320] ";
    $rate = <STDIN>;
    $rate =~ s/\n//;
    if($rate eq '') {
      return;
    }
    $ripper->SetConfigValue('CBR_BITRATE', $rate);
  }
  $ripper->Config_Save();
}

sub OptEncFlags {
  $ripper = shift;
  print "\nEncoder Flags (will be passed to encoder at run time) -> ";
  $encflags = <STDIN>;
  $encflags =~ s/\n//;
  $ripper->SetConfigValue('ENCFLAGS', $encflags);
  $ripper->Config_Save();
}

sub OptCDDevice {
  $ripper = shift;
  print "\nCD Device -> ";
  $device = <STDIN>;
  $device =~ s/\n//;
  if($device eq '') {
    return;
  }
  $ripper->SetConfigValue('CD_DEVICE', $device);
  $ripper->Config_Save();
}

sub OptCD {
  $ripper = shift;
  my($cd) = $ripper->ReturnConfigValue('WHOLECD');
  if($cd eq 'YES') {
    $ripper->SetConfigValue('WHOLECD', 'NO');
  } else {
    $ripper->SetConfigValue('WHOLECD', 'YES');
  }
  $ripper->Config_Save();
}

sub OptDelWav {
  $ripper = shift;
  my($cd) = $ripper->ReturnConfigValue('DELWAV');
  if($cd eq 'YES') {
    $ripper->SetConfigValue('DELWAV', 'NO');
  } else {
    $ripper->SetConfigValue('DELWAV', 'YES');
  }
  $ripper->Config_Save();
}

sub OptCDDBServer {
  $ripper = shift;
  print "\nCDDB Server -> ";
  $server = <STDIN>;
  $server =~ s/\n//;
  if($server eq '') {
    return;
  }
  $ripper->SetConfigValue('CDDB_HOST', $server);
  $ripper->Config_Save();
}

sub OptCDDBPort {
  $ripper = shift;
  print "\nDirectory -> ";
  $port = <STDIN>;
  $port =~ s/\n//;
  if($port eq '') {
    return;
  }
  $ripper->SetConfigValue('CDDB_PORT', $port);
  $ripper->Config_Save();
}

sub OptCDDB {
  $ripper = shift;
  my($cddb) = $ripper->ReturnConfigValue('USE_CDDB');
  if($cddb eq 'YES') {
    $ripper->SetConfigValue('USE_CDDB', 'NO');
  } else {
    $ripper->SetConfigValue('USE_CDDB', 'YES');
  }
  $ripper->Config_Save();
}

sub OptName {
  $ripper = shift;
  print "\n a) Artist-CD Title-TrackNo-Title";
  print "\n b) (Artist) - Title";
  print "\n c) Create your own";
  print "\n ->";
  $selection = <STDIN>;
  if($selection =~ /a/) {
    $mask = "&A-[]-&C-[]-%N-&T-[]";
    $ripper->SetConfigValue('FILEMASK', $mask);
    $ripper->Config_Save();
  } elsif ($selection =~ /b/) {
    $mask = "(%A) - %T";
    $ripper->SetConfigValue('FILEMASK', $mask);
    $ripper->Config_Save();
  } elsif ($selection =~ /c/) {
    print "\nCreate a mask for file names:\n";
    print "%A - Artist\n";
    print "%C - CD Title\n";
    print "%N - Track Number\n";
    print "%T - Track Title\n";
    print "%R - Remixer\n";
    print "%T - Track Type\n";
    print "Example: %A-%C-%N-%T: Artist-CD-Num-Title\n";
    print "See README for advanced name creation\n\n";
    print "Mask -> ";
    $mask = <STDIN>;
    $mask =~ s/\n//;
    $ripper->SetConfigValue('FILEMASK', $mask);
    $ripper->Config_Save();
  }

}

sub OptVBR {
  $ripper = shift;
  my($VBR) = $ripper->ReturnConfigValue('VBR');
  if($VBR eq 'YES') {
    $ripper->SetConfigValue('VBR', 'NO');
  } else {
    $ripper->SetConfigValue('VBR', 'YES');
  }
  $ripper->Config_Save();
}

sub OptUnderscore {
  $ripper = shift;
  my($underscore) = $ripper->ReturnConfigValue('UNDERSCORE');
  if($underscore eq 'YES') {
    $ripper->SetConfigValue('UNDERSCORE', 'NO');
  } else {
    $ripper->SetConfigValue('UNDERSCORE', 'YES');
  }
  $ripper->Config_Save();
}

sub OptDirectory {
  $ripper = shift;
  print "\nDirectory -> ";
  $dir = <STDIN>;
  $dir =~ s/\n//;
  if($dir eq '') {
    return;
  }
  $dir =~ s/\~/$ENV{HOME}/;
  $ripper->SetConfigValue('SAVETO', $dir);
  $ripper->Config_Save();
}

sub OptEncoder {
  $ripper = shift;
  print "\n";
  my($lame) = $ripper->ReturnConfigtestValue('lame');
  if($lame) {
    print "  a) lame\n";
  } else {
    print "  a) lame (not installed)\n";
  }
#  my($lameogg) = $ripper->ReturnConfigtestValue('lameogg');
#  if($lameogg) {
#    print "  b) lame (ogg)\n";
#  } else {
#    print "  b) lame (ogg) (not installed)\n";
#  }
  my($bladeenc) = $ripper->ReturnConfigtestValue('bladeenc');
  if($bladeenc) {
    print "  c) bladeenc\n";
  } else {
    print "  c) bladeenc (not installed)\n";
  }
  my($oggenc) = $ripper->ReturnConfigtestValue('oggenc');
  if($oggenc) {
    print "  d) oggenc\n";
  }
  else {
    print "  d) oggenc (not installed)\n";
  }
  my($gogo) = $ripper->ReturnConfigtestValue('gogo');
  if($gogo) {
    print "  e) gogo\n";
  }
  else {
    print "  e) gogo (not installed)\n";
  }
  
#  my($l3enc) = $ripper->ReturnConfigtestValue('l3enc');
#  if($l3enc)
#  {
#    print "  e) l3enc\n";
#  }
#  else
#  {
#    print "  e) l3enc (not installed)\n";
#  }
#  my($hzmp3) = $ripper->ReturnConfigtestValue('8hz-mp3');
#  if($hzmp3)
#  {
#    print "  f) 8hz-mp3\n";
#  }
#  else
#  {
#    print "  f) 8hz-mp3 (not installed)\n";
#  }
  print "\n  ->";
  
  $encoder = <STDIN>;
  $encoder =~ s/\n//;
  if($encoder eq '') {
    return;
  }
  
  ENCODER: {
    if($encoder eq 'a'){ $encoder = 'lame'; last ENCODER; }
    if($encoder eq 'b'){ $encoder = 'lameogg'; last ENCODER; }
    if($encoder eq 'c'){ $encoder = 'bladeenc'; $ripper->SetConfigValue('VBR', 'NO'); last ENCODER; }
    if($encoder eq 'd'){ $encoder = 'oggenc'; $ripper->SetConfigValue('VBR', 'YES'); last ENCODER; }
    if($encoder eq 'e'){ $encoder = 'gogo'; last ENCODER; }
#    if($encoder eq 'e'){ $encoder = 'l3enc'; last ENCODER; }
#    if($encoder eq 'f'){ $encoder = '8hz-mp3'; last ENCODER; }
  }
  $ripper->SetConfigValue('ENCODER', $encoder);
  $ripper->Config_Save();
}

sub OptRipper {
  $ripper = shift;
  print "\n";

  my($cdparanoia) = $ripper->ReturnConfigtestValue('cdparanoia');
  if($cdparanoia) {
    print "  a) cdparanoia\n";
  } else {
    print "  a) cdparanoia (not installed)\n";
  }
  my($cdda2wav) = $ripper->ReturnConfigtestValue('cdda2wav');
  if($cdda2wav) {
    print "  b) cdda2wav\n";
  } else {
    print "  b) cdda2wav (not installed)\n";
  }
  my($dagrab) = $ripper->ReturnConfigtestValue('dagrab');
  if($dagrab) {
    print "  c) dagrab\n";
  } else {
    print "  c) dagrab (not installed)\n";
  }
#  my($tosha) = $ripper->ReturnConfigtestValue('tosha');
#  if($tosha)
#  {
#    print "  c) tosha\n";
#  }
#  else
#  {
#    print "  c) tosha (not installed)\n";
#  }
  print "\n  ->";
  
  $rip = <STDIN>;
  $rip =~ s/\n//;
  if($rip eq '') {
    return;
  }

  RIP: {
    if($rip eq 'a'){ $rip = 'cdparanoia'; last RIP; }
    if($rip eq 'b'){ $rip = 'cdda2wav'; last RIP; }
    if($rip eq 'c'){ $rip = 'dagrab'; last RIP; }
#    if($rip eq 'c'){ $rip = 'tosha'; last RIP; }
  }
  $ripper->SetConfigValue('RIPPER', $rip);
  $ripper->Config_Save();
}

sub SplitTrack {
  $ripper = shift;
  $trackno = shift;
  $reverse = shift;
  my($track) = $ripper->ReturnTrack($trackno);
  my($newtr) = $track;
  my($newart) = $ripper->ReturnArtist($trackno);
  
  if($track =~ /\s*\/\s*/) {
    $newart = $track;
    $newart =~ s/\s*\/.*//;
    $newtr = $track;
    $newtr =~ s/.*\/\s*//;
  }
  elsif($track =~ /\s*\\\s*/) {
    $newart = $track;
    $newart =~ s/\s*\\.*//;
    $newtr = $track;
    $newtr =~ s/.*\\\s*//;
  }
  elsif($track =~ /\s*-\s*/) {
    $newart = $track;
    $newart =~ s/\s*-.*//;
    $newtr = $track;
    $newtr =~ s/.*-\s*//;
  }

  if(defined($reverse)) {
    if($reverse == 1) {
      my($temp) = $newart;
      $newart = $newtr;
      $newtr = $temp;
    }
  }

  $ripper->SetArtist($newart, $trackno);
  $ripper->SetTrack($newtr, $trackno);
  return $ripper;
}

sub GetCDDB {
  $ripper = shift;
  my($pick, $cdtitle, $cd, @cds);
  my($i) = 1;
  my($x) = 0;  


  if($ripper->Cache_Check()) {
    print "\n\n    CD recognized\n\n";
    print "  a) Use Cache\n";
    print "  b) Manual\n";
    if($ripper->ReturnConfigValue('USE_CDDB') eq 'YES') {
      print "  c) Use CDDB\n";
    }
    print "  n) Exit\n";
    print "-> ";
    $pick = <STDIN>;
    $pick =~ s/\n//;
    
    if($pick =~ /a/) {
      $ripper->Cache_Read();
      return 1;
    } elsif($pick =~ /b/) {
      return 1;
    } elsif($pick =~ /c/ && $ripper->ReturnConfigValue('USE_CDDB') eq 'YES') {
      $x = 1;  
    } else {
      return undef;
    }
  }
  if($x == 1) { $x = 0; }

  # Connect to CDDB (or at least get a track listing)
  if($ripper->ReturnConfigValue('USE_CDDB') eq 'YES') {
    print "\n\nConnecting to CDDB\n";
    eval {
      @cds = $ripper->CDDB_GetCD();
    };

    if($@) {
      $@ =~ s/ at.*//;
      print "$@";
      $pick = <STDIN>;
      $ripper->InitCD();
      return 1;
    } else {
      foreach $cd (@cds) {
        $cdtitle = $cd;
        $cdtitle =~ s/\d\d\d\s\w*\s//;
        $cdtitle =~ s/\w*\s//;
        print "  $i) $cdtitle\n";
        $i++;
      }

      print "  n) None of the Above\n";
      print "-> ";
      $pick = <STDIN>;
    }
  } else {
    return 1;
  }

  $pick =~ s/\n//;

  if($pick =~ /\d*/ && $pick > 0  && $pick <= $i) {
    $pick--;
    $cd = $cds[$pick];
    $ripper->CDDB_GetCDData($cd);
    $ripper->Cache_Create();
    return 1;
  } else {
    return undef;
  }
}

sub RipAll {
  $ripper = shift;
  $doall = 1;
  while($doall) {
    $doall = $ripper->Ripper_DoNext();
    EncoderSpawn($ripper);
    if(getppid() == 1) {
      $doall = undef;
    }
  }
}

sub RipperSpawn {
  $ripper = shift;
  chdir;
  chdir ".oneripper";
  $pid = "";
  if(-e "ripper.pid") {
    open(PID, "< ripper.pid") or die "Couldn't open ripper.pid for reading: $!\n";
    while(<PID>) {
      push(@pid, $_);
    }
    $pid = shift(@pid);
    close(PID);
  } else {
    $pid = 0;
  }

  if($pid == 0 or $pid eq "") {
    $encode = 1;
  }
  elsif(getpriority(0, $pid)) {
    chdir;
    chdir ".oneripper";
    truncate "ripper.pid", 0;
    $encode = 1;
  } else {
    $encode = undef;
  }

  if($encode) {
    if (!defined($child_pid = fork())) {
      die "cannot fork: $!";
    }
    elsif ($child_pid) {
      chdir;
      chdir ".oneripper";
      truncate "ripper.log", 0;
      open(PID, "> ripper.pid") or die "Couldn't open ripper.pid for writing: $!\n";
      print PID "$child_pid";
      close PID;
      ProgressMeter($ripper);
    } else {
      eval {
        RipAll($ripper);
      };
      chdir;
      chdir ".oneripper";
      truncate "ripper.pid", 0;
      open RLOG, ">> ripper.log";
      print RLOG "\nFINIS";
      close RLOG;
      exit;
    }
  }
}

sub EncodeAll {
  $ripper = shift;
  $doall = 1;
  while($doall) {
    $doall = $ripper->Encoder_DoNext();
  }
}

sub EncoderSpawn {
  $ripper = shift;
  chdir;
  chdir ".oneripper";
  if(-e "encoder.pid")
  {
    open(PID, "< encoder.pid") or die "Couldn't open encoder.pid for reading: $!\n";
    while(<PID>) {
      push(@pid, $_);
    }
    $pid = shift(@pid);
    close(PID);
  }
  else
  {
    undef($pid);
  }

  
  if(!$pid) {
    $encode = 1;
  } else {
    $pid =~ s/\n//;
    $pid =~ s/\s*//;
    $working = system("ps -p " . $pid . " | grep oneripper");
    if($working == 256) {
      $encode = 1;
    } else {
      $encode = undef;
    }
  }

  if($encode) {
    if (!defined($child_pid = fork())) {
      die "cannot fork: $!";
    }
    elsif ($child_pid) {
      chdir;
      chdir ".oneripper";
      truncate "encoder.log", 0;
      open(PID, "> encoder.pid") or die "Couldn't open encoder.pid for writing: $!\n";
      print PID "$child_pid";
      close PID;
    } else {
      eval {
        EncodeAll($ripper);
      };
      chdir;
      chdir ".oneripper";
      truncate "encoder.pid", 0;
      open ELOG, ">> encoder.log";
      print ELOG "\nFINIS";
      close ELOG;
      exit;
    }
  }
}

sub ProgressMeter {
  $ripper = shift;
  
  my($percent) = .4;
  my($time) = "0:00:00";
  my($timetotal) = "0:00:00";

  my($rstart) = 1;
  my($rfinish) = 1;
  my($rpercent) = .4;
  my($rtime) = "0:00:00";
  my($rtimetotal) = "0:00:00";

  my($numstars) = 1;
  my($ripnumstars) = 1;


  my($artist) = "No Songs Encoding";
  my($rartist) = "No Songs Ripping";
  my($cdtitle) = "";
  my($rcdtitle) = "";
  my($trackno) = 0;
  my($rtrackno) = 0;
  my($track) = "";
  my($rtrack) = "";

  my($ENCODER) = "LAME";
  my($RIPPER) = "CDPARANOIA";

  my($eline, $rline, $size, @filestat, $currsize, $encfiles, $ripfiles, $startfiles, $tpercent, $trpercent);

  chdir;
  chdir ".oneripper";
  open (ELOGFILE, "encoder.log") or die "can't open encoder.log: $!";
  open (RLOGFILE, "ripper.log") or die "can't open ripper.log: $!";

  $startfiles = 0;
  for($i = 1; $i <= $ripper->ReturnNumTracks(); $i++) {
    if($ripper->ReturnTracksToRip($i)) {
      $startfiles++;
    }
  }
  $ripfiles = $startfiles;

  for (;;) {
    $size = tell(ELOGFILE);
    @filestat = stat(ELOGFILE);
    $currsize = $filestat[7];
    if($currsize < $size) {
      close(ELOGFILE);
      open (ELOGFILE, "encoder.log") or die "can't open encoder.log: $!";
    }

    $size = tell(RLOGFILE);
    @filestat = stat(RLOGFILE);
    $currsize = $filestat[7];
    if($currsize < $size) {
      close(RLOGFILE);
      open (RLOGFILE, "ripper.log") or die "can't open ripper.log: $!";
    }

    opendir(QUEUE, "ripper.queue");
    $encfiles = 0;
    while( defined ($file = readdir QUEUE) ) {
      next if $file =~ /^\.\.?$/;
      next if $file =~ /^E/;
      $encfiles++;
    }

    while (<ELOGFILE>) {
      $eline = $_;
      if($eline =~ /LAME/) {
        $ENCODER = "LAME";
      }
      elsif($eline =~ /OGGENC/) {
        $ENCODER = "OGGENC";
      }
      elsif($eline =~ /BladeEnc/) {
        $ENCODER = "BLADEENC";
      }
      elsif($eline =~ /GOGO-no-coda/) {
        $ENCODER = "GOGO";
      }
      
      if($eline =~ /FINIS/) {
        $time = "0:00:00";
        $timetotal = "0:00:00";
        $percent = .4;
        $artist = "No Songs Encoding";
        $cdtitle = "";
        $trackno = 0;
        $track = "";
      }
      
      if($ENCODER eq "LAME")
      {
        if($eline =~ /Encoding/) {
          $eline =~ s/to \/.*//;
          $eline =~ s/.*\///;
          if($eline =~ /\s*(.*?) - (.*?) - (.*?) - (.*?)\.wav/) {
            $artist = $1;
            $cdtitle = $2;
            $trackno = $3;
            $track = $4;
          }
          $percent = 0;
        }
        ($tpercent, $time, $timetotal) = EncoderLogLame($eline);
        if($tpercent > $percent) {
          $percent = $tpercent
        }
      }
      elsif($ENCODER eq "OGGENC") {
        if($eline =~ /OGGENC/) {
          if($eline =~ /.*\/(.*?) - (.*?) - (.*?) - (.*?)\.wav/) {
            $artist = $1;
            $cdtitle = $2;
            $trackno = $3;
            $track = $4;
          }
        }
        ($percent, $time, $timetotal) = EncoderLogOgg($eline);
      }
      elsif($ENCODER eq "BLADEENC") {
        if($eline =~ /Encoding/) {
          if($eline =~ /.*\/(.*?) - (.*?) - (.*?) - (.*?)\.wav/) {
            $artist = $1;
            $cdtitle = $2;
            $trackno = $3;
            $track = $4;
          }
        }
        if($eline =~ /Status/){
          ($percent, $time, $timetotal) = EncoderLogBladeEnc($eline);
        }
      }
      elsif($ENCODER eq "GOGO") {
        if($eline =~ /input/) {
          if($eline =~ /.*\/(.*?) - (.*?) - (.*?) - (.*?)\.wav/) {
            $artist = $1;
            $cdtitle = $2;
            $trackno = $3;
            $track = $4;
          }
        }
        ($percent, $time, $timetotal) = EncoderLogGogo($eline);
      }
    }

    while (<RLOGFILE>) {
      $x++;
      $rline = $_;
      
      if($rline =~ /cdparanoia/) {
        $RIPPER = "CDPARANOIA";
      }
      elsif($rline =~ /CDINDEX/) {
        $RIPPER = "CDDA2WAV";
      }
      elsif($rline =~ /dagrab/) {
        $RIPPER = "DAGRAB";
      }

      if($rline =~ m/(\d*) left to rip/i) {
        $ripfiles = $1;
      }
      
      if($rline =~ /FINIS/) {
        close(RLOGFILE);
        return;
      }
      
      if($RIPPER eq "CDPARANOIA")
      {
        if($rline =~ /outputting/) {
          $rline =~ s/.*\///;
          if($rline =~ m/(.*?) - (.*?) - (\d*?) - (.*?)\.wav/) {
            $rartist = $1;
            $rcdtitle = $2;
            $rtrackno = $3;
            $rtrack = $4;
          }
          $rpercent = 0;
        }

        if($rline =~ m/Ripping from sector\s*(\d*)/) {
          $rstart = $1;
        }
        elsif($rline =~ m/\s*to sector\s*(\d*)/) {
          $rfinish = $1;
        }
        else
        {
          ($trpercent, $rtime, $rtimetotal) = RipperLogCdparanoia($rline, $rstart, $rfinish);
          if($trpercent > $rpercent) {
            $rpercent = $trpercent
          }
        }
      }
      elsif($RIPPER eq "CDDA2WAV")
      {
        if($rline =~ /recording/) {
          $rline =~ s/.*\///;
          if($rline =~ m/(.*?) - (.*?) - (.*?) - (.*?)/) {
            $rartist = $1;
            $rcdtitle = $2;
            $rtrackno = $3;
            $rtrack = $4;
          }
        }

        if($rline =~ m/\%/) {
          ($rpercent, $rtime, $rtimetotal) = RipperLogCddawav($rline);
        }
      }
      elsif($RIPPER eq "DAGRAB")
      {
        if($rline =~ /Output/) {
          $rline =~ s/.*\///;
          if($rline =~ m/(.*?) - (.*?) - (.*?) - (.*?)/) {
            $rartist = $1;
            $rcdtitle = $2;
            $rtrackno = $3;
            $rtrack = $4;
          }
        }

        if($rline =~ m/lba\s*(\d*) to lba\s*(\d*)/) {
          $rstart = $1;
          $rfinish = $2;
        }
        elsif($rline =~ m/Reading block/) {
          ($rpercent, $rtime, $rtimetotal) = RipperLogDagrab($rline, $rstart, $rfinish);
        }
      }
    }

    $encnumstars = $percent / 3.3333;

    $ripnumstars = $rpercent / 3.33333;

    system("clear");
    print("\n");
    print(" ---------------------------------------------------------------\n");
    print(" | Encoder                      | Ripper                       |\n");
    print(" -------------------------------|-------------------------------\n");
    printf(" | %-28.28s | %-28.28s |\n", $artist, $rartist); 
    printf(" | %-28.28s | %-28.28s |\n", $cdtitle, $rcdtitle);
    printf(" | (%-2.2s) %-23.23s | (%-2.2s) %-23.23s |\n", $trackno, $track, $rtrackno, $rtrack);
    print(" -------------------------------|-------------------------------\n");

    print(" |");

    for($i = 1; $i < 31; $i++) {
      if($encnumstars >= $i) {
        print("*");
      } else {
        print(" ");
      }
    }
    print "|";
    for($i = 1; $i < 31; $i++) {
      if($ripnumstars >= $i) {
        print("*");
      } else {
        print(" ");
      }
    }
    print "|\n";

    if($timetotal ne "0:00:00") {
      print(" | $time / $timetotal       ");
    }
    else {
      print(" | $time left            ");
    }
    printf("%3s", int($percent));
    if($rtime ne "0:00:00") {
      print("\% | $rtime                 ");
    }
    else {
      print("\% |                         ");
    }
    printf("%3s", int($rpercent));
    print("\% |\n");
    print(" -------------------------------|-------------------------------\n");
    printf(" | %3s file(s) to encode        | %3s/%3s file(s) to rip       |\n", $encfiles, $ripfiles, $startfiles);
    print(" ---------------------------------------------------------------\n");

    sleep(2);
    seek(ELOGFILE, 0, 1);
    seek(RLOGFILE, 0, 1);
  }
}

sub EncoderMeter {
  $ripper = shift;
  
  my($percent) = 1;
  my($time) = "0:00:00";
  my($timetotal) = "0:00:00";

  my($numstars) = 1;


  my($artist) = "No Songs Encoding";
  my($cdtitle) = "";
  my($trackno) = 0;
  my($track) = "";

  my($ENCODER) = "LAME";

  my($eline, $size, @filestat, $currsize, $encfiles, $tpercent);

  chdir;
  chdir ".oneripper";
  open (ELOGFILE, "encoder.log") or die "can't open encoder.log: $!";

  if (!defined($child_pid = fork())) {
    die "cannot fork: $!";
  }
  elsif ($child_pid) {
    # Parent
    $x = <STDIN>;
    undef($x);
    kill(9, $child_pid);
  } else {
    # Child
    for (;;) {
      $size = tell(ELOGFILE);
      @filestat = stat(ELOGFILE);
      $currsize = $filestat[7];
      if($currsize < $size) {
        close(ELOGFILE);
        open (ELOGFILE, "encoder.log") or die "can't open encoder.log: $!";
      }

      opendir(QUEUE, "ripper.queue");
      $encfiles = 0;
      while( defined ($file = readdir QUEUE) ) {
        next if $file =~ /^\.\.?$/;
        next if $file =~ /^E/;
        $encfiles++;
      }

      while (<ELOGFILE>) {
        $eline = $_;
        if($eline =~ /LAME/) {
          $ENCODER = "LAME";
        }
        elsif($eline =~ /OGGENC/) {
          $ENCODER = "OGGENC";
        }
        elsif($eline =~ /BladeEnc/) {
          $ENCODER = "BLADEENC";
        }
        elsif($eline =~ /GOGO-no-coda/) {
          $ENCODER = "GOGO";
        }

        if($ENCODER eq "LAME")
        {
          if($eline =~ /Encoding/) {
            $eline =~ s/to \/.*//;
            $eline =~ s/.*\///;
            if($eline =~ /\s*(.*?) - (.*?) - (.*?) - (.*?)\.wav/) {
              $artist = $1;
              $cdtitle = $2;
              $trackno = $3;
              $track = $4;
            }
            $percent = 0;
          }
          ($tpercent, $time, $timetotal) = EncoderLogLame($eline);
          if($tpercent > $percent) {
            $percent = $tpercent
          }
        }
        elsif($ENCODER eq "OGGENC") {
          if($eline =~ /OGGENC/) {
            if($eline =~ /.*\/(.*?) - (.*?) - (.*?) - (.*?)\.wav/) {
              $artist = $1;
              $cdtitle = $2;
              $trackno = $3;
              $track = $4;
            }
          }
          ($percent, $time, $timetotal) = EncoderLogOgg($eline);
        }
        elsif($ENCODER eq "BLADEENC") {
          if($eline =~ /Encoding/) {
            if($eline =~ /.*\/(.*?) - (.*?) - (.*?) - (.*?)\.wav/) {
              $artist = $1;
              $cdtitle = $2;
              $trackno = $3;
              $track = $4;
            }
          }
          if($eline =~ /Status/){
            ($percent, $time, $timetotal) = EncoderLogBladeEnc($eline);
          }
        }
        elsif($ENCODER eq "GOGO") {
          if($eline =~ /input/) {
            if($eline =~ /.*\/(.*?) - (.*?) - (.*?) - (.*?)\.wav/) {
              $artist = $1;
              $cdtitle = $2;
              $trackno = $3;
              $track = $4;
            }
          }
          ($percent, $time, $timetotal) = EncoderLogGogo($eline);
        }
      }

      $encnumstars = $percent / 3.3333;

      system("clear");
      print("\n");
      print(" --------------------------------\n");
      print(" | Encoder                      |\n");
      print(" --------------------------------\n");
      printf(" | %-28.28s |\n", $artist); 
      printf(" | %-28.28s |\n", $cdtitle);
      printf(" | (%-2.2s) %-23.23s |\n", $trackno, $track);
      print(" --------------------------------\n");

      print(" |");

      for($i = 1; $i < 31; $i++) {
        if($encnumstars >= $i) {
          print("*");
        } else {
          print(" ");
        }
      }
      print "|\n";

      if($timetotal ne "0:00:00") {
        print(" | $time / $timetotal       ");
      }
      else {
        print(" | $time left            ");
      }
      printf("%3s", $percent);
      print("\% |\n");
      print(" --------------------------------\n");
      printf(" | %3s file(s) to encode        |\n", $encfiles);
      print(" --------------------------------\n");
      print("\n\nPress [Enter] to return to main menu.\n");
      sleep 2;
      seek(ELOGFILE, 0, 1);
    }
  }
}

sub EncoderLogLame {
  my($line) = shift;
  my($frame) = 0;
  my($frametotal) = 1;
  my($time) = "0:00:00";
  my($timetotal) = "0:00:00";

  if($line =~ m/\s*(\d*)\/\s*(\d*)\(\s*\d*\%\)\| \d*\:\d*\:\d*\/ \d*\:\d*\:\d*\| (\d*\:\d*\:\d*)\/ (\d*\:\d*\:\d*)/) {
    $frame = $1;
    $frametotal = $2;
    $time = $3;
    $timetotal = $4;
  }
  elsif($line =~ /\s*(\d*)\/(\d*)\s*\(\s?\d*\%\)\|\s*\d*\:\d*\/\s*\d*\:\d*\|\s*(\d*)\:(\d*)\/\s*(\d*)\:(\d*)\|\s*\d*\.\d*x\|\s*\d*\:\d*\s*$/) {
    $frame = $1;
    $frametotal = $2;
    if($3 < 10)
    {
      $time = "0:0" . $3 . ":" . $4;
    }
    else
    {
      $time = "0:" . $3 . ":" . $4;
    }
    if($5 < 10)
    {
      $timetotal = "0:0" . $5 . ":" . $6;
    }
    else
    {
      $timetotal = "0:" . $5 . ":" . $6;
    }
  }
  $percent = int($frame / $frametotal * 100);
  if($percent < 0)
  {
    $percent = 0;
  }
  return($percent, $time, $timetotal);
}

sub EncoderLogOgg {
  my($line) = shift;
  my($percent) = 0;
  my($time) = "0:00:00";
  my($timetotal) = "0:00:00";

  if($line =~ m/.*?\[\s?\s?(\d*).\d\%\] \[\s?(\d*)m(\d*)/) {
    $percent = $1;
    if($2 < 10)
    {
      $time = "0:0" . $2 . ":" . $3;
    }
    else
    {
      $time = "0:" . $2 . ":" . $3;
    }
  }
  return($percent, $time, $timetotal);
}

sub EncoderLogBladeEnc {
  my($line) = shift;
  my($percent) = 0;
  my($time) = "0:00:00";
  my($timetotal) = "0:00:00";

  if($line =~ m/.*\:\s*(\d?\d).\d\%/) {
    $percent = "$1";
  }

  if($line =~ m/.*ETA (\d*)\:(\d*)\:(\d*)/) {
    $time = int($1) . ":" . $2 . ":" . $3;
  }
  
  return($percent, $time, $timetotal);
}

sub EncoderLogGogo {
  my($line) = shift;
  my($percent) = 0;
  my($time) = "0:00:00";
  my($timetotal) = "0:00:00";

  if($line =~ m/(\d*)\.\d\%.*?re\:\[(\d\d)\:(\d\d)\:(\d\d)\.\d\d\] to\:\[(\d\d)\:(\d\d)\:(\d\d)\.\d\d\]/) {
    $percent = $1;
    $time = int($2) . ":" . $3 . ":" . $4;
    $timetotal = int($5) . ":" . $6 . ":" . $7;
  }
  
  return($percent, $time, $timetotal);
}

sub RipperLogCdparanoia {
  my($line) = shift;
  my($rstart) = shift;
  my($rfinish) = shift;
  my($rpercent) = 1;
  my($rread) = 1;
  my($writepercent) = 1;
  my($rwrite) = 1;
  my($readnumstars) = 1;
  my($writenumstars) = 1;
  my($finish) = 1;
  my($start) = 1;
  my($total) = 1;
  my($time) = "0:00:00";
  my($timetotal) = "0:00:00";

  if($line =~ m/.*\[read\] @ (\d*)/) {
    $rread = $1;
  }
  elsif($line =~ m/.*\[wrote\] @ (\d*)/) {
    $rwrite = $1;
  }
  
  $finish = $rfinish * 1176;
  $start = $rstart * 1176;
  $total = $finish - $start;
  if($total == 0) {
    $rpercent = 1;
  }
  else {
    if($rread == 1)
    {
      $rpercent = int(($rwrite - $start) / $total * 100);
    }
    else
    {
      $rpercent = int(($rread - $start) / $total * 100);
    }
  }
  if($rpercent < 0)
  {
    $rpercent = 0;
  }
  return($rpercent, $time, $timetotal);;
}

sub RipperLogCddawav {
  my($line) = shift;
  my($percent) = 9;
  my($time) = "0:00:00";
  my($timetotal) = "0:00:00";

  if($line =~ m/.*(\d\d)\%/) {
    $percent = $1;
  }
  elsif($line =~ m/.*(\d)\%/) {
    $percent = $1;
  }

  return($percent, $time, $timetotal);;
}

sub RipperLogDagrab {
  my($line) = shift;
  my($rstart) = shift;
  my($rfinish) = shift;
  my($rread) = 1;
  my($time) = "0:00:00";
  my($timetotal) = "0:00:00";
  my($rpercent) = 1;

  if($line =~ m/.*Reading block\s*(\d*) -.*- (\d\d)\:(\d\d)\:(\d\d)/) {
    $rread = $1;
    $time = int($2) . ":" . $3 . ":" . $4;
  }
  $rpercent = int((($rread - $rstart) / ($rfinish - $rstart)) * 100);
  
  return($rpercent, $time, $timetotal);;
}
