#!/usr/bin/perl -w
use strict;
$| = 1;

# 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

# mp3backup - backup an mp3/ogg collection onto multiple cdr/dvd discs
#
# 20021208 raf <raf@raf.org>

# Set defaults and load configuration

my ($name) = $0 =~ /([^\/]+)$/;
my $default_size = 700;
my $default_root = '/mnt/music';
my $default_tocglob = '00*.toc';
my $default_speed = '24';

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

sub help
{
	print << "ENDHELP";
NAME

$name - backup an mp3/ogg collection onto cdr/dvd discs

SYNOPSIS

  $name [options]
  option:
    -h, --help            - Show the help message then exit
    -V, --version         - Show the version message then exit
    -n, --nobackup        - Do not backup (just output the catalogue)
    -c, --catalogue file  - Write the catalogue to file
    -b, --brief           - Don't include track titles in the catalogue
    -s, --speed #         - Override default speed ($default_speed)
    -r, --root dir        - Override default music directory ($default_root)
    -t, --tocglob tocglob - Override default tocfile glob ($default_tocglob)
    -S, --size size       - Override default cdr/dvd size ($default_size)

DESCRIPTION

$name backs up an mp3/ogg collection onto a set of cdr/dvd discs fitting as
much as it can onto each cdr/dvd. The -c option causes it to also output a
catalogue to the file specified as its argument. The -n option prevents the
backup from occurring so the only action is to produce the catalogue (This
is used internally to place a copy of the catalogue on each cdr/dvd). If no
catalogue file is specified when the -n option is given, the catalogue is
printed to standard output. The -b option prevents track titles in the
catalogue. The -s option overrides the default speed. The -S option
overrides the default cdr/dvd size. The -r option overrides the default
music directory. The -t option overrides the default tocfile glob. All
parameters such as the cdr/dvd device, the speed and so on are specified in
the configuration file.

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 "mp3backup-0.1\n";
	exit;
}

# Check the arguments

use POSIX;
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|nobackup c|catalogue=s b|brief s|speed=i r|root=s t|tocglob=s S|size=i);
help() if exists $opt{h};
version() if exists $opt{V};
my $backup = !exists $opt{n};
my $catfile = $opt{c} if exists $opt{c};
my $brief = exists $opt{b};
my $speed = $opt{s} || $default_speed;
my $root = $opt{r} || $default_root;
my $tocglob = $opt{t} || $default_tocglob;
my $cdrsize = $opt{S} || $default_size;
my $limit = ($cdrsize - 1) * 1024;

# Prepare to start

my @items;
my @artists;
my @titles;
my @tracks;
my @args;
my $size = 0;
my $count = 0;
my $cat = '';

if (defined $catfile)
{
	open(CAT, "> $catfile") or die "Failed to open $catfile for writing: $!\n";
}

# Create a simple catalogue file in advance to place on each cdr.

my $toc = "/tmp/$name.$$";

if ($backup)
{
	system("'$0' -s '$cdrsize' -r '$root' -c '$toc' -n" . ($brief ? ' -b' : ''));
	unlink($toc), exit 1 unless -s $toc;
}

# Backup directories to multiple cdrs.

for my $rootdir (split /[,: ]+/, $root)
{
	die "Invalid jukebox root: $rootdir (Not a directory)\n" unless -d $rootdir;

	for my $entry (glob("$rootdir/*"))
	{
		next if $entry =~ /\/(\.\.?|lost\+found|tmp)$/;

		my (@album) = grep { -d } glob("$entry/*");
		@album = ($entry) unless @album;

		for my $album (@album)
		{
			my ($blocks, $name) = `du -s $album` =~ /^(\d+)\s+(.*)$/;
			my ($artist, $title, $tracks) = readtoc($album);
			my $dst = substr($name, length($rootdir) + 1);

			if ($size + $blocks < $limit)
			{
				push(@args, (-d $name) ? "$dst/=$name" : $name);
				push(@items, $name);
				push(@artists, $artist);
				push(@titles, $title);
				push(@tracks, $tracks) unless $brief;
				$size += $blocks;
			}
			else
			{
				backup();
				@args = ((-d $name) ? "$dst/=$name" : $name);
				@items = ($name);
				@artists = ($artist);
				@titles = ($title);
				@tracks = ($tracks) unless $brief;
				$size = $blocks;
			}
		}
	}
}

backup() if $size;
unlink($toc) if $backup;
print CAT $cat if defined $catfile;
close CAT if defined $catfile;
print $cat if !$backup && !defined $catfile;
exit;

# Write one cdr

sub backup
{
	++$count;
	die "Aborting: ", (defined $items[0] ? "$items[0] " : ""), "directory too large!\n" if !$size || $size > $limit;
	my $mb = POSIX::ceil($size / 1024);
	my $item = "Disc $count: $artists[0] to $artists[$#artists] (${mb}MB)\n";

	for (my $i = 0; $i <= $#artists; ++$i)
	{
		$item .= "\n  $artists[$i]\n" unless $i && $artists[$i] eq $artists[$i - 1];
		$item .= "    $titles[$i]\n";
		$item .= join("\n", @{$tracks[$i]}). "\n" unless $brief;
	}

	$item .= "\n";
	$cat .= $item;
	return unless $backup;
	my $spd = $speed;

	for (;;)
	{
		print $item;
		print "Insert a cdr then press return (or 's' to skip): ";
		last if <STDIN> =~ /s/i;
		system("cdr --speed $spd /Catalogue.toc=$toc " . join ' ', @args);
		print 'Did it work? ([y]/n): ';
		last if <STDIN> !~ /n/i;
		print 'Halve the speed? ([y]/n): ' if $spd > 1;
		$spd /= 2 if $spd > 1 && <STDIN> !~ /n/i;
	}
}

# Read tocfile and return artist and album title

sub readtoc
{
	my ($album) = @_;
	my ($artist, $title);
	my @toc = glob "$album/$tocglob";
	return (undef, undef, undef) unless @toc;

	open(TOCFILE, $toc[0]) or die "Failed to open $toc[0] for reading: $!\n";
	my $tracks = ($brief) ? undef : [];

	while (<TOCFILE>)
	{
		$artist = $1, next if /^Artist: (.*)$/;
		$title = $1, next if /^Title: (.*)$/;
		last if /^$/ && $brief;

		if (/^\d{2}\s+(.*)$/)
		{
			my $track = $1;
			$track =~ s/\s+\[[jJ]ukebox:\s*[^]]*\]//g;
			push(@{$tracks}, '      ' . $track);
			next;
		}
	}

	close(TOCFILE);
	return ($artist, $title, $tracks);
}

# 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_root = $1 if /^juke_root=['"]?([^'"]+)['"]?$/;
		$default_size = $1 if /^cdr_size=['"]?([^'"]+)['"]?$/;
		$default_tocglob = $1 if /^juke_toc=['"]?([^'"]+)['"]?$/;
		$default_speed = $1 if /^cdr_spd=['"]?([^'"]+)['"]?$/;
	}

	close(CONFIG);
}

# vi:set ts=4 sw=4
