#!/usr/bin/perl
#
# CD Ripper
#   usage: cdripper [-o num] [--no-cddb] [-T] [-a] [-y] [target_directory]
#
# Rips the contents of an audio CD into Ogg Vorbis files
# Puts the files in target_directory/artist/album_name/
# (default target_directory is ./)
#
# Requires cdparanoia, oggenc, vcfromfilename
#
# Changelog:
#   0.2.4: Fixed bug - files should get tagged again
#          Added support for -T option
#   0.2:   Aligned version with ds-audiotools
#          Implemented CDDB support (disabled with --no-cddb)
#          Ability to preview and edit all text before it's used
#          -y option to suppress all user input, taking defaults
#          -a option to be asked about CDDB options
#   0.1.2: Removed the erroneous fixname, updated fixname to do what I need
#          Now you can name things with natural characters, and it should be
#          automatically fixed
#          Added the -o option, functions as -o num, makes the first track
#          num + 1
#   0.1.1: Added version variable
#   0.1:   changed to perl (from bash)
#          improved file naming mechanism
#          added Vorbiscomment updating (using vcfromfilename script)
#          added program to ds-audio package
#   0.0.4: fixed track #s above 10 not happening :P
#   0.0.3: fixed the bug with track #s
#   0.0.2: changed entire code to bash script (from C++)
#   0.0.1: basic code in place

use CDDB_get qw( get_cddb );

$VERSION = "0.2.4";
$HELP_MSG = "# CD Ripper v$VERSION\n\tusage: cdripper [--no-cddb] [-a] " .
    "[-y] [-o num] [target_directory]\n\n" .
    "Options:\n-a:\t\tAsk users about multiple CDDB options\n" .
    "-o [num]:\tOffset track numbers by num.  The first track will be num+1\n" .
    "-y:\t\tDon't prompt for user confirmation of CDDB information\n\t\t(assume defaults are okay).\n" .
    "--no-cddb:\tDon't use CDDB.  Prompt the user for all information.\n" .
    "-T:\t\tWrite uppercase tag names.  Passes -T to tagfromfilename\n";

$CDPARANOIA_FORMAT = 'track*.cdda';
$TRACK_ZERO = 'track00';
chomp($orig_dir = `pwd`);
chomp($temp_dir = '/tmp/ds-cdripper-' . `whoami`);
$target_directory = $orig_dir;
$offset = 0;
$useCDDB = 1;
$noInput = 0;
$askCDDB = 0;

foreach (@ARGV)
{
    if ($offsetOnNext)
    {
	$offset = $_;
	$offsetOnNext = 0;
    }
    else
    {
	if (/^(--help)|(-h)$/) { print $HELP_MSG; exit; }
	elsif (/^-o$/) { $offsetOnNext = 1; }
	elsif (/^--no-cddb$/) { $useCDDB = 0; }
	elsif (/^-f$/) { $noInput = 1; }
	elsif (/^-a$/) { $askCDDB = 1; }
	elsif (/^-T$/) { $uppertags = '-T'; }
	else
	{
	    $target_directory = $_;
	}
    }
}

# Create temp location
system("rm -rf $temp_dir 2> /dev/null");
mkdir($temp_dir);
chdir($temp_dir);

# Get the filenames to use later
handle_names();

# Rip, convert
system('cdparanoia -B');
system("oggenc $CDPARANOIA_FORMAT.wav");
$sanityTest = `ls -1 | wc -l`;
chomp $sanityTest;
die "No files were created.  Aborting." unless ($sanityTest > 0);

# Fix filenames
init_old_tracks();
fix_files(@new_tracks);

# Move files to final location
$final_location = "$target_directory/$artist/$album";
mkdir($target_directory);
mkdir("$target_directory/$artist");
mkdir("$target_directory/$artist/$album");
system('mv', @new_tracks, $final_location);
chdir($final_location);
warn "Some files were not automatically named." if $unhandledFiles;

# Add vorbiscomment data
system('tagfromfilename', $uppertags, @new_tracks);

# Clean up
chdir($orig_dir);
system("rm -rf $temp_dir");

# Converts the filenames created by cdparanoia
# to my arbitrary file name standard, using CDDB or User Input
sub handle_names
{
    init_current_track();

    if ($useCDDB) { getinfo_cddb(); }
    else { getinfo_user(); }

    # final check for user
    confirm_filenames() unless $noInput;
}

# Gets user input to create the @new_tracks array
sub getinfo_user
{
    die "Trying to ask for user input with user input disabled.  THIS SHOULD NOT HAPPEN." if $noInput;

    print 'Artist: ';
    chomp($artist = <STDIN>);
    $artist = `fixname -o "$artist"`;
    print 'Album: ';
    chomp($album = <STDIN>);
    $album = `fixname -o "$album"`;

    my $numTracks = get_number_of_tracks();
    for (my $i = 1; $i <= $numTracks; $i++)
    {
	print "Track $current_track: " ;
	chomp (my $input = <STDIN>);
	my $input = `fixname -o "$input"`;
	
	my $track_name = $artist . '-' . $current_track . '-' . $input .
	    '.ogg';

	push @new_tracks, $track_name;
	$current_track++;
    }
}

# Uses CDDB to populate the new_tracks array
sub getinfo_cddb
{
    my %config;
    $config{input} = 1 if $askCDDB;

    my %cd=get_cddb(\%config);
    if (! defined $cd{title})
    {
	die "No CDDB entry and user input disabled.  Quitting." if $noInput;
	warn "Couldn't find CDDB entry for disc.  Switching to user input.\n";
	getinfo_user();
	return;
    }
    
    $artist = `fixname -o "$cd{artist}"`;
    $album  = `fixname -o "$cd{title}"`;

    foreach (@{$cd{track}})
    {
	my $track_name = $artist . '-' . $current_track . '-' .
	    `fixname -o "$_"` . '.ogg';

	push @new_tracks, $track_name;
	$current_track++;
    }
}

# Fixes the files listed in @old_tracks with the names given
# in @new_tracks
sub fix_files
{
    my @newTracks = @new_tracks;

    foreach (@old_tracks)
    {
	my $newName = shift @newTracks;
 	if ($newName) { system('mv', "$_", $newName); }
	else 
	{
	    push @new_tracks, $_;
	    $unhandledFiles = 1;
	}
    }
}

# Sets $current_track to the correct value
sub init_current_track
{
    $current_track='01';
    for ($i = 0; $i < $offset; $i++) { $current_track++; }
}

# Populates the @old_tracks array
sub init_old_tracks
{
    foreach (`ls $CDPARANOIA_FORMAT.ogg`)
    {
	chomp;
	next if /$TRACK_ZERO/;
	push @old_tracks, $_;
    }
}

# Create and open a file for final adjustments to filenames
sub confirm_filenames
{
    my $savedComma = $,;
    $, = "\n";

    # Dump the file
    open TMPFILE, "> $temp_dir/filenames";
    print TMPFILE $artist . "\n";
    print TMPFILE $album . "\n";
    print TMPFILE @new_tracks;
    print TMPFILE "\n";
    close TMPFILE;

    $, = $savedComma;

    # Allow editing
    my $editor = $ENV{'EDITOR'};
    if ($editor) { system($editor, "$temp_dir/filenames"); }
    elsif ( -x '/usr/bin/vi') { system('vi', "$temp_dir/filenames"); }
    else
    {
	warn "No \$EDITOR variable defined, and no default editor found.  Filename editing disabled.\n";
	return;
    }

    # Read the changes
    @new_tracks = ();
    open TMPFILE, "< $temp_dir/filenames";

    chomp ($artist = <TMPFILE>);
    chomp ($album = <TMPFILE>);

    while (chomp($_ = <TMPFILE>))
    {
	push @new_tracks, $_;
    }
    close TMPFILE;
}

sub get_number_of_tracks()
{
    my @tracks;

    # Get the track numbers
    foreach (`cdparanoia -Q 2>&1`)
    {
	next unless /^\s{1,2}\d{1,2}/;
	s/\..*$//; # Kill everything after the number
	s/^\s*//; # Kill the leading whitespace
	push @tracks, $_;
    }

    # Return the last track number, and we should be golden
    return pop @tracks;
}

# Copyright (c) 2004 - 2007 John Wiggins
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA