#!/usr/bin/perl -w
use DateTime;
use DateTime::Format::ISO8601;
use Getopt::Long;
#use Data::Dumper;

# install required libs
# apt-get install libgetopt-long-descriptive-perl
# apt-get install libdatetime-perl
# apt-get install libdatetime-format-iso8601-perl

#init command line parameters
my $file		='';
my $start		='';
my $end			='';
my $time_zone   	='';
my $startup_duration	=0;
my $help		='';
my $debug		=0;
my $output_directory    ='';

GetOptions (
	"i|file=s"  	=> \$file,
	"s|start=s" 	=> \$start,
	"e|end=s"   	=> \$end,
	"t|timezone=s" 	=> \$time_zone,
	"u|startup=i"	=> \$startup_duration,
	"O|output_dir=s"=> \$output_directory,
	"h|help"  	=> \$help,
	"v|verbose"	=> \$debug,
);
$time_zone='Europe/Berlin'	if ($time_zone eq '');

debug(qq{
Parameters:
file	   $file
start	   $start
end	   $end
timezone   $time_zone
startup    $startup_duration
output dir $output_directory
help	   $help
});

print_usage()	if ($help ne'');
print_usage()	if (($file eq '') || ($start eq '') || ($end eq ''));

if ($output_directory ne ''){
	unless (-e $output_directory){
		print STDERR "output directory '$output_directory' does not exist\n";
		print $file;
		exit 1;
	}
	unless (-w $output_directory){
		print STDERR "cant write into directory '$output_directory'\n";
		print $file;
		exit 1;
	}
}

#get utc datetime
my $now		=get_utc_datetime();
my $start_time	=get_utc_datetime($start);
my $end_time	=get_utc_datetime($end);

debug(qq{
Time:
UTC now 	$now
UTC start	$start_time
UTC end		$end_time
});

#get durations
my $duration	= $end_time->subtract_datetime($start_time);
my $duration_sec= duration_to_seconds($duration);
my $length	= get_file_length($file);
debug(qq{
audio length	}.($length/60).qq{ m
duration 	}.($duration_sec/60).qq{ m
});

#exit on invalid time range
if ($duration_sec<=0){
	print STDERR "WARNING: invalid time range\n";
	print "$file\n";
	exit 1;
}

#init cut points
$start_cut=0;
$end_cut=$length;

#cut end if show is longer than assumed
if ($length>$duration_sec){
	$end_cut=$duration_sec;
}else{
	#exit with original file if nothing to do
	if ($now.'' lt $start_time.''){
		print STDERR "WARNING: show has not started yet\n";
		print "$file\n";
		exit 0;
	}
	if ($now.'' ge $end_time.''){
		print STDERR "WARNING: show is already over\n";
		print "$file\n";
		exit 0;
	}
}

#cut start only, if currently running
if ( ($now.'' ge $start_time.'') && ($now.'' lt $end_time.'') ){
	#cut start if show is already running
	my $running_time=$now->subtract_datetime($start_time);
	$running_time->add(DateTime::Duration->new(seconds => $startup_duration)) if ($startup_duration>0);
	$start_cut=duration_to_seconds($running_time);
}

debug(qq{
start_cut	$start_cut s
end_cut		$end_cut s
});

#split mp3
mp3split($file,$start_cut,$end_cut);

#split mp3/ogg file from start to end using mp3splt
#see http://mp3splt.sourceforge.net/mp3splt_page/home.php
sub mp3split{
	my $file	=shift;
	my $start_cut	=shift;
	my $end_cut	=shift;

	$start_cut	=seconds_to_mp3splt($start_cut);
	$end_cut	=seconds_to_mp3splt($end_cut);

	debug(qq{
start:	$start_cut
end:	$end_cut
});

	if ($start_cut>0 || $end_cut>0){

		#calc new filename
		my $out_file=$file;
		my $file_ext='';
		my $dir='';
		my $dir_parameter='';

		#remove directory from filename
		if ($out_file=~/\/([^\/]+)$/){
			$out_file=$1;
		}

		if ($output_directory ne ''){
			#remove mulitple trailing slashes from output directory
			$output_directory=~s/\/+$//g;
			$output_directory.='/';

			$dir=$output_directory;
			$dir_parameter="-d $output_directory";
		}

		#remove file extension
		if ($out_file=~/\.([^\.]+)$/){
			$out_file=~s/\.([^\.]+)$//g;	
			$file_ext=$1;
		};
		$out_file.='_cut';

		#call mp3splt
		my $cmd=qq{mp3splt "$file" "$start_cut" "$end_cut" -o "$out_file" $dir_parameter -Q};
		debug($cmd);
		my $result=`$cmd`;
		print "$dir$out_file.$file_ext\n";
		return;
	}
	print "$file\n";
};

#get audio file length using mp3info
#see http://ibiblio.org/mp3info/
sub get_file_length{
	my $filename=shift;
	my $cmd=qq{mp3info -p "%S" $filename};
	debug($cmd);
	my $result=`$cmd`;
	$result=~s/\s+//g;
	return -1 unless ($result=~/^\d+$/);
	return $result;
}

#get datetime in UTC from given datetime string
#returns current time if no parameter is passed
#UTC is used for date/time calculations, 
#see http://search.cpan.org/dist/DateTime/lib/DateTime.pm#How_Datetime_Math_Works
sub get_utc_datetime{
	my $datetime=shift;

	unless (defined $datetime){
		my $dt = DateTime->now(time_zone=>$time_zone);
		$dt->set_time_zone('UTC');
		return $dt;
	}

	my $dt = DateTime::Format::ISO8601->parse_datetime( $datetime );
	$dt->set_time_zone($time_zone);
	$dt->set_time_zone('UTC');

	return $dt;
}

#convert seconds to mp3splt parameter time format "min.sec"
sub seconds_to_mp3splt{
	my $time=	shift;
	my $min=	int($time/60);
	$time-=		$min*60;
	my $sec=	$time;
	return 		"$min.$sec";
}

#get duration betweens two datetimes in seconds
sub duration_to_seconds{
	my $duration=shift;
	my %values= 	$duration->deltas();
	my $value= 	$values{seconds};
	$value+=	$values{minutes}*60;
	$value+=	$values{days}*24*60*60;
	return $value;
}

sub print_usage{
	my $usage=qq{
Prepare a audio file in case of scheduled playout should have been already started or file exceeds given time range.

$0 -f audio_file -s start -e end (-t timezone)
Parameters:
  -f, --file      path to source ogg/mp3 file
  -s,--start      scheduled start datetime, e.g. "2010-10-23T21:00"
  -e,--end        scheduled stop datetime, e.g. "2010-10-23T22:00"
  -t,--timezone   optional, default is "Europe/Berlin"
  -u,--startup    optional, estimated time in seconds to prepare the audio file and start playout process
  -O,--output_dir optional, temporary output directory for created files.
  -h,--help       this help
  -v,--verbose    debug information

Description:
In case of cutting the new file name will be returned otherwise the original filename will be returned.
Time calculation uses timezone to handle leap seconds and daylight saving time.
Startup time will be removed from audio start to get the prepared file playing in-time.
All datetime parameters should follow ISO8601. 

Example:
get file which is scheduled to be played from  2010-10-24T15:00 till  2010-10-24T16:00 
# perl prepare_audio.pl --file test.mp3 --start 2010-10-24T15:00 --end 2010-10-24T16:00 | tail -1 | xargs cvlc \$1

};

	print $usage;
	print "$file\n";
	exit 1;
}

sub debug{
	if($debug){
		$_[0]=~s/\s+$//g;
		print STDERR $_[0]."\n" ;
	}
}

