#!/usr/bin/perl -w
# mythexport v1.0
# By: John Baab
# Email: john.baab@gmail.com
# Purpose: Script for exporting mythtv recordings into formats used by portable devices.
# Requirements: ffmpeg (with aac,xvid,h264 support), perl and the DBI & DBD::mysql modules, 
#					MythTV perl bindings, AtomicParsley
#
# Modified from ipodexport.pl By Justin Hornsby 27 July 2007
#
#
# License:
#
# This Package 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 package 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 package; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#
# On Debian & Ubuntu systems, a complete copy of the GPL can be found under
# /usr/share/common-licenses/GPL-2, or (at your option) any later version

use DBI;
use DBD::mysql;
use MythTV;
use strict;

# Set default values
my $exportdir = '/home/mythtv/';
my $audio_bitrate = '96kb';
my $video_bitrate = '300kb';
my $aspect = '4:3';
my $size = "320x240";

my $connect = undef;
my $debug = 0;

my ($starttime, $chanid, $title, $subtitle, $description, $syndicatedepisodenumber, $showtype, $programid, $basename, $exportcodec, $exportdevice) = "";

##################################
#                                #
#    Main code starts here !!    #
#                                #
##################################

my $usage = "\nHow to use mythexport : \n"
        ."\nchanid = Channel ID associated with the recording to export.\n"
        ."starttime = Recording start time in either 'yyyy-mm-dd hh:mm:ss' or 'yyyymmddhhmmss' format.\n"
        ."exportdir = Directory to export completed MP4 files to (note the user the script runs as must have write permission on that directory).\n"
        ."size = Frame size of output file.  320x240 is the default value.\n"
        ."aspect = Aspect ratio of output file.  Valid values are 4:3 (default) and 16:9.\n"
        ."audio_bitrate = Audio bitrate in output file in kbps.  Default value is 96kb.\n"
	."video_bitrate = Video bitrate in output file in kbps.  Default value is 300kb.\n"
	."export_codec = Acceptable export codecs: mpeg4, xvid, h264.\n"
	."export_device = Acceptable export devices: ipod, psp.\n"
        ."debug = Enable debugging information - outputs which commands would be run.\n"
        ."\nExample: mythexport exportdir=/mythtv/ipod starttime=20060803205900 chanid=1006 size=320x240 aspect=4:3 audio_bitrate=192kb video_bitrate=300kb export_device=ipod export_codec=mpeg4 debug\n";

# get this script's ARGS
#

my $num = $#ARGV + 1;

# if user hasn't passed enough arguments, die and print the usage info
if ($num <= 2) {
    die "$usage";
}

#
# Get all the arguments
#

foreach (@ARGV){

    if ($_ =~ m/debug/) {
        $debug = 1;
    }
    elsif ($_ =~ m/size/) {
        $size = (split(/\=/,$_))[1];
    }
    elsif ($_ =~ m/aspect/) {
        $aspect = (split(/\=/,$_))[1];
    }
    elsif ($_ =~ m/audio_bitrate/) {
        $audio_bitrate = (split(/\=/,$_))[1];
    }
	elsif ($_ =~ m/video_bitrate/) {
        $video_bitrate = (split(/\=/,$_))[1];
    }
    elsif ($_ =~ m/starttime/) {
        $starttime = (split(/\=/,$_))[1];
    }
    elsif ($_ =~ m/chanid/) {
        $chanid = (split(/\=/,$_))[1];
    }
    elsif ($_ =~ m/exportdir/) {
        $exportdir = (split(/\=/,$_))[1];
    }
	elsif ($_ =~ m/export_codec/) {
        $exportcodec = (split(/\=/,$_))[1];
    }
	elsif ($_ =~ m/export_device/){
		$exportdevice = (split(/\=/,$_))[1];
	}
}

#
#
my $myth = new MythTV();
# connect to database
$connect = $myth->{'dbh'};

# PREPARE THE QUERY
my $query = "SELECT rec.title, rec.subtitle, rec.description, pg.syndicatedepisodenumber, pg.showtype, rec.programid 
FROM recorded rec left join program pg on pg.programid=rec.programid
WHERE rec.chanid=$chanid AND rec.starttime='$starttime'";
#print $query;
my $query_handle = $connect->prepare($query);


# EXECUTE THE QUERY
$query_handle->execute() || die "Cannot connect to database \n";

# BIND TABLE COLUMNS TO VARIABLES
$query_handle->bind_columns(undef, \$title, \$subtitle, \$description, \$syndicatedepisodenumber, \$showtype, \$programid);

# LOOP THROUGH RESULTS
$query_handle->fetch();

my $schemaVer = $myth->backend_setting('DBSchemaVer');
# Storage Groups were added in DBSchemaVer 1171
# FIND WHERE THE RECORDINGS LIVE
my $dir = 'UNKNOWN';
if ($schemaVer < 1171)
{
    if ($debug) {
        print ("Using compatibility mode\n");
    }
    $dir = $myth->backend_setting('RecordFilePrefix');
}
else
{
    if ($debug) {
        print ("Going into new mode\n");
    }
    my $storagegroup = new MythTV::StorageGroup();
    $dir = $storagegroup->FindRecordingDir($basename);
}

# FIND OUT THE CHANNEL NAME
$query = "SELECT name FROM channel WHERE chanid=?";
$query_handle = $connect->prepare($query);
$query_handle->execute($chanid)  || die "Unable to query settings table";

my $channame = $query_handle->fetchrow_array;

# replace whitespace in channame with dashes
$channame =~ s/\s+/-/g;

# replace non-word characters in title with underscores
my $title_old = $title;
$title =~ s/\W+/_/g;
# replace non-word characters in subtitle with underscores
my $subtitle_old = $subtitle;
$subtitle =~ s/\W+/_/g;

# Remove non alphanumeric chars from $starttime & $endtime
my $newstarttime = $starttime;
$newstarttime =~ s/[|^\W|\s|-|]//g;
my $filename = $dir."/".$chanid."_".$newstarttime.".mpg";
my $newfilename = $exportdir."/".$channame."_".$title."_".$subtitle."_".$newstarttime;

$syndicatedepisodenumber =~ m/^.*?(\d*)(\d{2})$/;
my $seasonnumber = $1;
my $episodenumber = $2;

# Trim any characters over 63 (59+4 for the extentsion), 
# it seems iTunes does not like files with lenghts this long.
$newfilename =~ s/^(.*\/(.{1,59})).*$/$1.mp4/g;

if ($debug) {
    print "\n\n Source filename:$filename \nDestination filename:$newfilename\n \n";
}

# move to the export directory incase any logs get written
chdir $exportdir;

# Now run ffmpeg to get iPod compatible video with a simple ffmpeg line
my $command = "";
my $command2 = "";

if ($exportdevice eq "ipod"){
	if ($exportcodec eq "mpeg4" or $exportcodec eq "xvid"){
		# This VBR line works well, but only in xvid.  Causes buffere underflows in Gutsy.	
		#$command = "nice -n19 ffmpeg -i $filename -acodec aac -ab $audio_bitrate -qmin 3 -qmax 5 -g 300 -bufsize 4096 -vcodec $exportcodec -b $video_bitrate -mbd 2 -flags +4mv+trell -aic 2 -cmp 2 -subcmp 2 -s $size -aspect $aspect '$newfilename' 2>&1";
		# This VBR line works well, but only in xvid.  Causes buffere underflows in Gutsy.
		#$command = "nice -n19 ffmpeg -i $filename -f mp4 -vcodec $exportcodec -maxrate 1000 -b $video_bitrate -qmin 3 -qmax 5 -bufsize 4096 -g 300 -acodec aac -ab $audio_bitrate -s $size -aspect $aspect '$newfilename' 2>&1"
	
		# Works cleanly with both vcodecs, but produces larger files.
		$command = "nice -n19 ffmpeg -i $filename -acodec aac -ab $audio_bitrate -vcodec $exportcodec -b $video_bitrate -mbd 2 -flags +4mv+trell -aic 2 -cmp 2 -subcmp 2 -s $size '$newfilename' 2>&1";
	}
	elsif ($exportcodec eq "h264"){
		# First pass
		$command = "nice -n19 ffmpeg -y -i $filename -an -v 1 -threads auto -vcodec h264 -b $video_bitrate -bt 175k -refs 1 -loop 1 -deblockalpha 0 -deblockbeta 0 -parti4x4 1 -partp8x8 1 -me full -subq 1 -me_range 21 -chroma 1 -slice 2 -bf 0 -level 30 -g 300 -keyint_min 30 -sc_threshold 40 -rc_eq 'blurCplx^(1-qComp)' -qcomp 0.7 -qmax 51 -qdiff 4 -i_qfactor 0.71428572 -maxrate 768k -bufsize 2M -cmp 1 -s $size -f mp4 -pass 1 /dev/null";
		# Second pass
		$command2 = "nice -n19 ffmpeg -y -i $filename -v 1 -threads auto -vcodec h264 -b $video_bitrate -bt 175k -refs 1 -loop 1 -deblockalpha 0 -deblockbeta 0 -parti4x4 1 -partp8x8 1 -me full -subq 6 -me_range 21 -chroma 1 -slice 2 -bf 0 -level 30 -g 300 -keyint_min 30 -sc_threshold 40 -rc_eq 'blurCplx^(1-qComp)' -qcomp 0.7 -qmax 51 -qdiff 4 -i_qfactor 0.71428572 -maxrate 768k -bufsize 2M -cmp 1 -s $size -acodec aac -ab $audio_bitrate -ar 48000 -ac 2 -f mp4 -pass 2 '$newfilename' 2>&1";
	}
	else{
		print "\n\nERROR: Unexpected Export Codec.";
		exit;
	}
}
elsif ($exportdevice eq "psp"){
	if ($exportcodec eq "mpeg4" or $exportcodec eq "xvid"){
		$command = "nice -n19 ffmpeg -i $filename -acodec aac -ab $audio_bitrate -vcodec $exportcodec -b $video_bitrate -ar 24000 -mbd 2 -flags +4mv+trell -aic 2 -cmp 2 -subcmp 2 -s $size -aspect $aspect -r 30000/1001 -f psp '$newfilename' 2>&1";
	}
	elsif ($exportcodec eq "h264"){
		# PSP h.254 encoding doesn't seem to be working.
		print "\n\nError: PSP h.264 encoding is not currently supported.  Use xvid or mpeg4 instead.";
		exit;		
		# According to the ffmpeg website, this should have worked.
		#$command = "nice -n19 ffmpeg -i $filename -acodec aac -ab $audio_bitrate -vcodec h264 -b $video_bitrate -ar 48000 -mbd 2 -coder 1 -cmp 2 -subcmp 2 -s $size -aspect $aspect -r 30000/1001 -title X -f psp -flags loop -trellis 2 -partitions parti4x4+parti8x8+partp4x4+partp8x8+partb8x8 '$newfilename' 2>&1";
	}
	else{
		print "\n\nERROR: Unexpected Export Codec.";
		exit;
	}
}
else{
	print "\n\nERROR: Unexpected Export Device.";
	exit;
}

# Update mp4 info using AtomicParsley
# need to fix this so movies actually show up as movies.
my $command3 = "AtomicParsley '$newfilename' --genre \"TV Shows\" --stik \"TV Show\" --TVNetwork $channame --TVShowName \"$title_old\" --TVEpisode \"$programid\" --TVEpisodeNum $episodenumber --TVSeason $seasonnumber --description \"$description\" --title \"$subtitle_old\" 2>&1";

# Print the commands instead of running them if in debug mode
if ($debug) {
    print "\n\nUSING $command \n\n";
	if ($command2){
		print "\n\nUSING $command2 \n\n";
	}
	print "\n\nUSING $command3 \n\n";
}

# Run the commands
if (!$debug) {
    system "$command";
	if ($command2){
		system "$command2";
	}
	system "$command3";
	system "rm $newfilename";
	system "mv $exportdir/*temp*.mp4 $newfilename";
}
