#!/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

# toc2tags - add tags to 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';

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

sub help
{
	print << "ENDHELP";
NAME

$name - add tags to 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
    -v, --verbose         - Print messages while tagging
    -T, --verify          - Verify tags (read and print after writing)
    -t, --tocglob tocglob - Override default tocfile glob ($default_tocglob)

DESCRIPTION

$name reads a jukebox table of contents file and uses its contents
to add tags to the corresponding tracks' mp3/ogg/flac files.

The genre is taken to be the first word in the "Jukebox:" header
which should be the category returned by freedb.org (to improve
the chance of it being accepted). If MP3::Info wouldn't accept it,
it's not used. This isn't an issue if you have ogg or flac files.
Also note that mp3 tags are very short (28 characters) but ogg and
flac tags can be long.

The -v option causes the tag information to be printed to standard
output as each file is tagged so you can see what it's trying to do.
The -T option causes the tags to be read back from the track files
and printed to standard output after they've been written so you can
see what really happened. The -t option overrides the default glob
used to identify the tocfile.

BUGS

Requires the existence of the MP3::Info perl module even if you only have
ogg or flac files.

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 "toc2tags-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 v|verbose T|verify t|tobglob=s);
help() if exists $opt{h};
version() if exists $opt{V};
my $verbose = exists $opt{v};
my $verify = exists $opt{T};
my $tocglob = $opt{t} || $default_tocglob;
my $tocfile = glob($tocglob);

# Read tocfile, tag the tracks

my $artist;
my $album;
my $album_comment;
my $track_comment;
my $genre;
my @srcfile;
my $srcfile;
my $suffix;

die "No such toc file: '$tocglob'" unless defined $tocfile;
open(TOC, $tocfile) or die "failed to open $tocfile: $!\n";

while (<TOC>)
{
	$artist = $1, next if $_ =~ /^Artist: (.*)$/ && !defined $artist;
	$album = $1, next if $_ =~ /^Title: (.*)$/ && !defined $album;
	$album_comment = $1, next if $_ =~ /^Jukebox: (.*)/ && !defined $album_comment;
	my ($index, $title) = $_ =~ /^(\d{2}) (.*)$/;
	next unless defined $index && defined $title && $title ne '';
	($track_comment) = $title =~ /\[[jJ]ukebox: ([^\]]+)\]/;
	$title =~ s/\s*\[.*\]\s*//g;

	for my $fmt ('mp3', 'ogg', 'flac')
	{
		@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 track $index. Skipping...\n"), next unless @srcfile;

	($genre) = $album_comment =~ /^(\w+)/;
	my $comment = $album_comment;
	$comment .= ' ' . $track_comment if defined $track_comment;

	if ($suffix eq 'mp3')
	{
		use MP3::Info qw(:genres set_mp3tag get_mp3tag);
		$genre = undef if defined $genre && !exists $mp3_genres{$genre};
		$comment = substr($comment, 0, 28);
		$_ = substr($_, 0, 30) for ($title, $artist, $album);
		print "Tagging: $srcfile\nArtist: $artist\nAlbum: $album\nTitle: $title\nComment: $comment\n", (defined $genre ? "Genre: $genre\n" : ""), "TrackNumber: $index\n\n" if $verbose;
		set_mp3tag($srcfile, $title, $artist, $album, undef, $comment, $genre, $index);
		my $tags = get_mp3tag($srcfile) if $verify;
		print "Tagged: $srcfile\nArtist: $tags->{ARTIST}\nAlbum: $tags->{ALBUM}\nTitle: $tags->{TITLE}\nComment: $tags->{COMMENT}\n", (defined $tags->{GENRE} ? "Genre: $tags->{GENRE}\n" : ""), "TrackNumber: $tags->{TRACKNUM}\n\n" if $verify;
	}
	elsif ($suffix eq 'ogg')
	{
		$_ =~ s/"//g for ($title, $artist, $album, $comment,);
		print "Tagging: $srcfile\nArtist: $artist\nAlbum: $album\nTitle: $title\nComment: $comment\nGenre: $genre\nTrackNumber: $index\n\n" if $verbose;
		system("vorbiscomment -w -t \"artist=$artist\" -t \"album=$album\" -t \"title=$title\" -t \"comment=$comment\" -t \"genre=$genre\" -t \"tracknumber=$index\" $srcfile");
		system("vorbiscomment -l $srcfile"), print "\n" if $verify;
	}
	elsif ($suffix eq 'flac')
	{
		$_ =~ s/"//g for ($title, $artist, $album, $comment,);
		print "Tagging: $srcfile\nArtist: $artist\nAlbum: $album\nTitle: $title\nComment: $comment\nGenre: $genre\nTrackNumber: $index\n\n" if $verbose;
		system("metaflac --remove-vc-all --set-vc-field \"artist=$artist\" --set-vc-field \"album=$album\" --set-vc-field \"title=$title\" --set-vc-field \"comment=$comment\" --set-vc-field \"genre=$genre\" --set-vc-field \"tracknumber=$index\" $srcfile");
		system("metaflac --export-vc-to=- $srcfile"), print "\n" if $verify;
	}
	else
	{
		warn "Unable to tag $srcfile. Skipping...\n";
	}
}

close(TOC);
exit;

# Load the configuration fie

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=['"]?([^'"]+)['"]?$/;
	}

	close(CONFIG);
}

# vi:set ts=4 sw=4
