#!/usr/bin/perl
#
# splitmp3album (c) 2002 Richard van den Berg <richard@vdberg.org>
#
# Distributed under the GPL: http://www.gnu.org/copyleft/gpl.html
#
# This tool splits mp3 albums into separate tracks.
# It is based on the assumption that when merging mp3 files together,
# the headers will introduce errors in the otherwise continuous stream of
# mp3 frames. A tool like mp3check can identify these errors.
# This script just takes the markers from mp3check and splits the album.
#
# Usage: mp3check -e album.mp3|splitmp3album [-d dest] [-i] [-m] [-h] album.mp3
#
# Joining tracks into an album is now as simple as:
#
# cat *.mp3 > album.mp3
#
# Get mp3check at http://packages.debian.org/mp3check
# MPEG::MP3Info is at http://sourceforge.net/projects/mp3-info/
#
# 04/07/2003 version 1.1: added hex() to push statement

use Getopt::Std;
use File::Basename;

$version="v1.1";
$dest=".";
$bsize=8*1024;
$id3=0;
$m3u=0;

getopts('himd:',\%opt) || exit;
&usage if($opt{'h'});
$id3=1 if($opt{'i'});
$m3u=1 if($opt{'m'});
$dest=$opt{'d'} if(defined($opt{'d'}));

if($id3) {
	use MPEG::MP3Info;
}

&usage if($#ARGV<0);
$file=$ARGV[0];

while(<STDIN>) {
	@line=split;
	push(@track,hex($line[5])) if($line[5]=~m/^0x/);
}
push(@track,2**32); # 4 Gb for last file marker..should be enough

&usage if($#track<3);

open(IN,"<$file") || die "Can't open file $file: $!\n";

$tnum=0;
$total=0;
$tname=sprintf("%s/%02i.mp3",$dest,$tnum+1);
die "Aborting: $tname exists\n" if(-e $tname);
open(OUT,">$tname") || die "Can't write to file $tname: $!\n";
while($read=read(IN,$buf,$bsize)){
	if($read+$total>=$track[$tnum]){
		syswrite(OUT,$buf,$track[$tnum]-$total) || die "Error writing: $!\n";
		close(OUT);
		$total=$track[$tnum++];
		print "Closed file $tname at $total\n";
		seek(IN,$total,0);
		$tname=sprintf("%s/%02i.mp3",$dest,$tnum+1);
		die "Aborting: $tname exists\n" if(-e $tname);
		open(OUT,">$tname") || die "Can't write to file $tname: $!\n";
	} else {
		syswrite(OUT,$buf) || die "Error writing: $!\n";
		$total+=$read;
	}
}
close(OUT);
print "Closed file $tname at $total\n";
close(IN);

if($id3){
	print "Renaming files...\n";
	if($m3u){
		$mfile=$dest."/".basename($file,".mp3").".m3u";
		print "Appending to $mfile\n" if(-e $mfile);
		open(M3U,">>$mfile") || die "Cannot write to $mfile: $!\n";
	}
	loop: for($tnum=1;$tnum-1<=$#track;$tnum++){
		$tname=sprintf("%s/%02i.mp3",$dest,$tnum);
		$info=get_mp3tag($tname);
		$artist=$info->{ARTIST};
		$title=$info->{TITLE};
		$artist=~tr/\"\'\?//d;
		$title=~tr/\"\'\?//d;
		if(!$artist || !$title){
			print "$tname does not have a usable ID3 tag: not renaming\n";
			print M3U basename($tname)."\n" if($m3u);
			next loop;
		}
		$newname="$dest/$artist - $title.mp3";
		if(-e $newname) {
			print "$newname exists: not renaming $tname\n";
			print M3U basename($tname)."\n" if($m3u);
			next loop;
		}
		print "Renaming $tname to $newname\n";
		rename $tname,$newname || print "Failed to rename $tname to $newname: $!\n";
		print M3U basename($newname)."\n" if($m3u);
	}
	close(M3U) if($m3u);
}

exit(0);

sub usage {
	$name=basename($0);
	print "splitmp3album($version): splits an mp3 album into separate tracks\n";
	print "(c) 2002 Richard van den Berg <richard\@vdberg.org>\n\n";
	print "Usage: mp3check -e album.mp3 | $name [-d dest] [-i] [-m] [-h] album.mp3\n";
	print "        -d  create files in this directory\n";
	print "        -i  use id3 tags to rename files after separation\n";
	print "        -m  write m3u file after renaming files\n";
	print "        -h  print this help page\n\n";
	print "Get mp3check at http://packages.debian.org/mp3check\n";
	exit(1);
}
