#!/usr/bin/perl -w
use strict;

# jukebox - http://raf.org/jukebox/
#
# Copyright (C) 2002 raf <raf@raf.org>
#
# 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
# or visit http://www.gnu.org/copyleft/gpl.html

# toc2names - name wav/mp3/ogg/flac... files based on the contents of a tocfile
#
# 20021208 raf <raf@raf.org>

# Set defaults and load configuration

my ($name) = $0 =~ /([^\/]+)$/;
my $default_tocglob = '00*.toc';
my $default_formats = 'wav,mp3,ogg,flac';
my $default_names = 'simple';

load('/etc/jukebox.conf');
load("$ENV{HOME}/.jukeboxrc");

sub help
{
	print << "ENDHELP";
NAME

$name - name wav/mp3/ogg/flac... files based on the contents of a tocfile

SYNOPSIS

  $name [options]
  options:
    -h, --help            - Show the help message then exit
    -V, --version         - Show the version message then exit
    -n, --noname          - Do not name files (just print mv commands)
    -t, --tocglob tocglob - Override default tocfile glob ($default_tocglob)
    -f, --formats formats - Override default formats ($default_formats)
    -s, --style style     - Override default naming style ($default_names)

DESCRIPTION

$name reads a jukebox table of contents file and uses its contents to
construct descriptive names for the corresponding track files (i.e.
*<index>*.{$default_formats}). The -t option overrides the default glob used
to identify the tocfile. The -f option overrides the default list of
acceptable file format extensions. The -n option suppresses the naming of
the track files. The commands that would have executed are printed to
standard output.

There are two naming styles supported. The "simple" style has dashes instead
of spaces, no upper case characters, very little punctuation and no 8 bit
characters. The "complex" style preserves spaces, upper case and accented
characters. The default style is specified in the juke_names variable in
/etc/jukebox.conf. It can be overriden with the -s option.

For each track title in the tocfile, the following transformations are
performed to create a simple file name for the corresponding track file:

  - Remove accents from accented characters
  - Convert upper case to lower case
  - Remove anything in square brackets
  - Unabbreviate "in'" into "ing"
  - Unabbreviate "o'" into "of"
  - Unabbreviate "&" into " and "
  - Unabbreviate "+" into " plus "
  - Unabbreviate "#" into " number "
  - Unabbreviate "=" into " equal "
  - Replace spaces and slashes with dashes
  - Remove all unacceptable characters (i.e. [^!?a-z0-9-])
  - Strip leading and trailing dashes
  - Compress strings of dashes
  - And end up with <tracknum>[- ]<title>.<format>

The user must confirm or override all suggested names.

Simple names look like:

  01-track-title.mp3

Complex names look like:

  01 Track Titlé.mp3

FILES

  /etc/jukebox.conf - System wide configuration file
  ~/.jukeboxrc      - User specific configuration file

SEE ALSO

  rip(1), riptrack(1), mktoc(1), toc2names(1), toc2tags(1),
  cdr(1), cdrw(1), burn(1), burnw(1), cdbackup(1), mp3backup(1),
  jukebox(1), jukeboxc(1), jukeboxc.jar(1), jukeboxd(8),
  jukeboxd-init.d(8), jukebox.conf(5),
  http://raf.org/jukebox/Jukebox-HOWTO

AUTHOR

raf <raf\@raf.org>

ENDHELP

	exit;
}

sub version
{
	print "toc2names-0.1\n";
	exit;
}

# Check the arguments

use Getopt::Long; #qw(:config gnu_getopt);
Getopt::Long::Configure qw(no_getopt_compat permute bundling);
my %opt;
help() unless GetOptions \%opt, qw(h|help V|version n|noname t|tocglob=s f|formats=s s|style=s);
help() if exists $opt{h};
version() if exists $opt{V};
my $debug = exists $opt{n};
my $preserve = ($opt{s} || $default_names) eq 'complex';
my $sep = ($preserve) ? ' ' : '-';
my $tocglob = $opt{t} || $default_tocglob;
my $formats = $opt{f} || $default_formats;
my $tocfile = glob($tocglob);
my @formats = split /[, ]+/, $formats;

# Construct track file names from track titles

die "No such toc file: '$tocglob'" unless defined $tocfile;
open(TOC, $tocfile) or die "failed to open $tocfile: $!\n";
my $artist = <TOC>;
my $cdtitle = <TOC>;
my $blank = <TOC>;

while (<TOC>)
{
	my ($index, $title) = $_ =~ /^(\d{2}) (.*)$/;

	next unless defined $index && defined $title && $title ne '';

	$title =~ tr/¿ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåçèéêëìíîïðñòóôõöøùúûüýþÿ/?AAAAAACEEEEIIIIDNOOOOOxOUUUUYPBaaaaaaceeeeiiiidnoooooouuuuypy/ if !$preserve;
	$title =~ s/Æ/AE/g if !$preserve;
	$title =~ s/æ/ae/g if !$preserve;
	$title =~ tr/A-Z/a-z/ if !$preserve;
	$title =~ s/\[.*\]//g;
	$title =~ s/in' /ing /g if !$preserve;
	$title =~ s/in'$/ing/g if !$preserve;
	$title =~ s/([oO])' /$1f /g if !$preserve;
	$title =~ s/&/ and /g;
	$title =~ s/\+/ plus /g;
	$title =~ s/#/ number /g;
	$title =~ s/=/ equal /g;
	$title =~ s/[\s\/]+/-/g if !$preserve;
	$title =~ s/\/+/ /g if $preserve;
	$title =~ s/[^-!?a-z0-9]+//g if !$preserve;
	$title =~ s/[^-!?a-z0-9A-Z ¿ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåçèéêëìíîïðñòóôõöøùúûüýþÿ]+//g if $preserve;
	$title =~ s/^[-\s]+//;
	$title =~ s/[-\s]+$//;
	$title =~ s/[-\s]+/-/g if !$preserve;
	$title =~ s/\s+/ /g if $preserve;

	# User has to confirm/override constructed name

	my @srcfile;
	my $srcfile;
	my $suffix;

	for my $fmt (@formats)
	{
		@srcfile = glob("*$index*.$fmt");
		$srcfile = $srcfile[0], $suffix = $fmt, last if @srcfile;
	}

	if (@srcfile > 1)
	{
		@srcfile = glob("$index*.$suffix");
		$srcfile = $srcfile[0] if @srcfile;
	}

	if (@srcfile == 0)
	{
		@srcfile = glob("[a-z]*$index*.$suffix");
		$srcfile = $srcfile[0] if @srcfile;
	}

	warn("Too many matches: @srcfile. Skipping...\n"), next if @srcfile > 1;
	warn("Failed to find *$index*.{$formats} ($title). Skipping...\n"), next unless @srcfile;

	my $dstfile = "$index$sep$title.$suffix";
	warn("Source and destination are the same ($srcfile). Skipping...\n"), next if $srcfile eq $dstfile;
	warn("Destination already exists ($dstfile). Skipping...\n"), next if -f $dstfile;

	print "mv '$srcfile' '$dstfile' ([Y]/n): ";
	my $response = <STDIN>;

	if ($response =~ /^\s*[nN]/)
	{
		print "Enter track name: ";
		chop($dstfile = <STDIN>);
		$dstfile = "$index$sep$dstfile" unless $dstfile =~ /^$index$sep/;
		$dstfile .= ".$suffix" unless $dstfile =~ /\.$suffix$/;
		print "mv '$srcfile' '$dstfile'\n";
	}

	rename($srcfile, $dstfile) unless $debug;
}

close(TOC);
exit;

# Load the configuration file

sub load
{
	my ($config) = @_;
	return unless -r $config;
	return unless open(CONFIG, $config);

	while (<CONFIG>)
	{
		s/#.*$//;
		s/^\s+//;
		s/\s+$//;
		s/\s+/ /g;
		next if /^$/;
		$default_tocglob = $1 if /^juke_toc=['"]?([^'"]+)['"]?$/;
		$default_formats = $1 if /^juke_fmt=['"]?([^'"]+)['"]?$/;
		$default_names = $1 if /^juke_names=['"]?([^'"]+)['"]?$/;
	}

	close(CONFIG);
}

# vi:set ts=4 sw=4
