#!/usr/bin/perl -w use strict; $| = 1; # jukebox - http://raf.org/jukebox/ # # Copyright (C) 2002 raf # # 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 # 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 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 =~ /s/i; system("cdr --speed $spd /Catalogue.toc=$toc " . join ' ', @args); print 'Did it work? ([y]/n): '; last if !~ /n/i; print 'Halve the speed? ([y]/n): ' if $spd > 1; $spd /= 2 if $spd > 1 && !~ /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 () { $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 () { 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