#!/usr/bin/perl

use strict;

$0 =~ s/.*\///;
$| = 1;

use Getopt::Mixed;

my $INTERRUPTED = 0;
my $OUTPUT = "";
my $ASPECT = "auto";
my $TITLE = 'auto';
my $FILE = 'dvd://';
my $VBITRATE = 1600;
my $ABITRATE = 192;
my $VOLUME = 20;
my $WIDTH = 800;
my $TWOPASS = 'no';
my $DEBUG = 'no';
my $LANG = 'en';
my $SLANG = 'none';
my $SID = -1;
my $FRAMESCAN = 500;
my $VERBOSE = 0;
my @CLIP = ('auto');
my $OVC = 'divx';
my $OAC = 'copy';
my $DEINT = 'no';
my $TV = 'no';

undef($ENV{DISPLAY});

$SIG{INT} = sub { $INTERRUPTED = 1; };
$SIG{QUIT} = sub { $INTERRUPTED = 1; };

sub error($) {
	print(STDERR "\e[1m\e[31m$0: $_[0]\n");
	print(STDERR "Try `rip --help' for more information.\e[0m\n");
	exit 1;
}

sub info {
	print("\e[1m\e[32m" . $_[0] . "\e[0m");
}

sub usage() {
	print(
"usage: $0 [<options>] <filename>

This is a wrapper for the DVD ripper `mencoder'.

  --help                This help
  -t|--title <n>        Rip title <n>                                ($TITLE)
  -f|--file <file>      Rip from file <file>                         ($FILE)
  -a|--aspect <n:m>     Use aspect ratio <n:m>                       ($ASPECT)
  -w|--width <n>        Specify output width                         ($WIDTH)
  -v|--volume <n>       Volume adjustment, in decibles (-200 to +40) ($VOLUME)
  --vrate <n>           Video recoding bitrate                       ($VBITRATE)
  --arate <n>           Audio recoding bitrate                       ($ABITRATE)
  --prescan <n>         Number of frames to pre-scan for clipping
                        region size and aspect ratio.                ($FRAMESCAN)
  -2|--twopass          Use higher quality two-pass mode. This is
                        useful for action movies with high change
                        deltas.                                      ($TWOPASS)
  --lang <n>            Select audio language                        ($LANG)
  --slang <n>           Select subtitle language                     ($SLANG)
  --debug               Debug mode                                   ($DEBUG)
  --clip <w:h:x:y>      Specify clipping region                      (" . join(":", @CLIP) . ")
  --codec <codec>       Specify video CODEC to use                   ($OVC)
  --acodec <codec>      Specify audio CODEC to use                   ($OAC)
  --deinterlace         Deinterlace                                  ($DEINT)
  --tv <channel>        Record from TV                               ($TV)

eg.
Rip the longest title on a DVD to foobar.avi:
  rip foobar.avi

Rip title 10 to foobar.avi:
  rip --title 10 foobar.avi
");
	exit 1;
}

Getopt::Mixed::init(
"t=i title>t
f=s file>f
a=s aspect>a
w=i width>w
v=i volume>v
debug
prescan=i
vrate=i
arate=i
clip=s
lang=s
slang=s
2 twopass>2
codec=s
acodec=s
deinterlace=s
help");

while (my ($option, $value, $extra) = Getopt::Mixed::nextOption()) {
	if ($option eq "t") {
		$TITLE = $value;
	} elsif ($option eq "f") {
		$FILE = $value;
	} elsif ($option eq 'deinterlace') {
		$DEINT = 'no';
	} elsif ($option eq "a") {
		$ASPECT = $value;
		error("invalid aspect ratio, should be in the form n:m") unless $ASPECT =~ /^[0-9]+:[0-9]+/;
	} elsif ($option eq "w") {
		$WIDTH = $value;
	} elsif ($option eq "v") {
		$VOLUME = $value;
	} elsif ($option eq "vrate") {
		$VBITRATE = $value;
	} elsif ($option eq "arate") {
		$ABITRATE = $value;
	} elsif ($option eq "2") {
		$TWOPASS = 'yes';
	} elsif ($option eq 'prescan') {
		$FRAMESCAN = $value;
	} elsif ($option eq 'debug') {
		$DEBUG = 'yes';
	} elsif ($option eq 'clip') {
		@CLIP = split(/:/, $value);
	} elsif ($option eq 'lang') {
		$LANG = $value;
	} elsif ($option eq 'slang') {
		$SLANG = $value;
	} elsif ($option eq 'codec') {
		$OVC = $value;
	} elsif ($option eq 'acodec') {
		$OAC = $value;
	} elsif ($option eq "help") {
		usage;
	} else {
		error("unhandled option '$option'");
	}
}
undef $TITLE unless ($FILE eq 'dvd://');

Getopt::Mixed::cleanup();

$OUTPUT = $ARGV[0] if @ARGV;
error("file name not specified") if $OUTPUT eq "";

#print(
#"
#Rip parameters:
#  Filename:      $OUTPUT
#  Title:         $TITLE
#  Two-pass:      $TWOPASS
#  Aspect:        $ASPECT
#  Width:         $WIDTH
#  Volume:        $VOLUME
#  Video bitrate: $VBITRATE
#  Audio bitrate: $ABITRATE
#
#");

# Find correct title to rip (longest)...
if ($TITLE eq 'auto') {
my $TITLES = 999;
my %TITLETIMES = ();
my ($LTITLE, $LTIME) = (-1, -1);

	info("Finding longest title\n");
	for ($TITLE = 1; $TITLE <= $TITLES; ++$TITLE) {
		open(P, "mplayer dvd://$TITLE -frames 0 -identify 2>&1 |") || error("couldn't do -identify via mplayer");
		while (<P>) {
			if (/There are (\d+) titles/) {
				$TITLES = $1;
			} elsif (/ID_LENGTH=(\d+)/) {
				$TITLETIMES{$TITLE} = $1;
				info("  Title $TITLE/$TITLES is $1 seconds long");
				if ($1 > 3600) { info(" (looks good)"); }
				info("\n");
				if ($1 > $LTIME) {
					$LTITLE = $TITLE;
					$LTIME = $1;
				}
			}
		}
		close(P);
	}

	$TITLE = $LTITLE;
	info("Chose title $TITLE (" . sprintf("%i", $LTIME / 60 / 60) . ":" . sprintf("%02i", ($LTIME / 60) % 60) . ")\n");
}

# Find available subtitle languages
if ($LANG ne 'none') {
	info("Finding available languages\n");
	my $CMD = "mencoder '$FILE$TITLE' -v";
	info("$CMD\n") if $DEBUG eq 'yes';
	open(P, "$CMD 2>&1 |") || error("couldn't find subtitles via mencoder?");
	my @AVAILSL;
	my @AVAILL;
	my $ALANG = 'none';
	LOOP: while (<P>) {
		if (/^\[open\] subtitle \( sid \): (\d+) language: (..)$/) {
			push(@AVAILSL, $2);
			$SID = $1 if $2 eq $SLANG or $1 eq $SLANG;
		} elsif (/^\[open\] audio stream.*language: (..)/) {
			push(@AVAILL, $1);
			$ALANG = $1 if $1 eq $LANG;
		}
	}
	error("Couldn't find sub-titles in language '$SLANG'.\n  Available sub-title languages are:\n    @AVAILSL") if $SLANG ne 'none' and $SID == -1;
	error("Couldn't find audio language '$LANG'.\n  Available audio languages are:\n    @AVAILL") if $ALANG eq 'none';
	close(P);
}

info("  Chose $LANG for audio, $SLANG for sub-titles\n");

# Find clipping region and/or aspect ratio
if ($CLIP[0] eq 'auto' || $ASPECT eq 'auto') {
my $CLIPFIND = 0;
my $FOUND = 0;

	$CLIPFIND = 1 if ($CLIP[0] eq 'auto');
	@CLIP = (0, 0, 999, 999) if ($CLIP[0] eq 'auto');
	info("Finding clipping region and aspect ratio\n");
	# Find aspect ratio
my $CMD = "mencoder '$FILE$TITLE' -ovc raw -vop cropdetect,scale -zoom -xy $WIDTH -oac copy -frames $FRAMESCAN -o /dev/null";
	$CMD .= " -alang $LANG" if $LANG ne 'none';
	info("$CMD\n") if $DEBUG eq 'yes';
	open(P, "$CMD 2>&1 |") || error("couldn't find clipping region via mencoder");
	LOOP: while (<P>) {
		print($_) if ($DEBUG eq 'yes');
		if (/^VIDEO:\s+(\w+)\s+(\d+)x(\d+)/) {
			info("  Video format is $1 with dimensions $2 x $3\n");
		} elsif (/^Movie-Aspect is ([\d.]+):([\d.]+)/) {
			info("  Aspect ratio is $1:$2\n");
			if ($ASPECT eq "auto") {
				info("    Auto-adjusting aspect ratio\n");
				$ASPECT = "$1:$2"
			} else {
			my @AS = split(/:/, $ASPECT);
			my $AR = sprintf("%0.2f", $AS[0] / $AS[1]);

				if ($AR != $1 / $2) {
					info("    WARNING: Movie aspect ratio (" . ($1 / $2) . ") does not agree with user aspect ratio (" . ($AR) . ")\n");
				} else {
					info("    User supplied aspect ratio agrees with DVD\n");
				}
			}
			$FOUND |= 1;
		} elsif (/-(?:vop|vf) crop=(\d+):(\d+):(\d+):(\d+)/) {
			$FOUND |= 2;
			if ($CLIPFIND) {
				if ($1 > $CLIP[0] || $2 > $CLIP[1] || $3 < $CLIP[2] || $4 < $CLIP[3]) {
					info("\r\e[2K  Adjusting cropping region to $3+$1 hor, $4+$2 vert...");
					@CLIP = ($1, $2, $3, $4);
				}
			} else {
				last LOOP;
			}
		}
	}

	error("Couldn't find clipping region or aspect. Possible reasons for this are:\n  - No DVD in the drive\n  - Your mencoder is broken\n") if $FOUND != 3;
	print("ok\n");
	close(P);
}


unlink("frameno.avi") if -e 'frameno.avi';

# Rip movie
my $ARGS = "-af volume=$VOLUME:sc -aspect $ASPECT '$FILE$TITLE' -vop crop=" . join(":", @CLIP) . ",scale -zoom -xy $WIDTH -o \"$OUTPUT\"";

$ARGS .= " -alang $LANG"
	if $LANG ne 'none';

if ($OAC eq 'mp3') {
	$ARGS .= " -oac mp3lame -lameopts cbr:preset=$ABITRATE";
} elsif ($OAC eq 'copy') {
	$ARGS .= " -oac copy";
} else {
	error("supported codecs are mp3 and copy");
}

if ($OVC eq 'divx') {
	$ARGS .= " -ovc lavc -lavcopts vcodec=mpeg4:vhq:vbitrate=$VBITRATE";
	$ARGS =~ s/-vop /-vop lavcdeint,/ if $DEINT eq 'yes';
} elsif ($OVC eq 'xvid') {
	$ARGS = "$ARGS -ovc xvid -xvidencopts me_quality=6:4mv:bitrate=$VBITRATE";
	# Multi-pass?
	$ARGS =~ s/(:4mv:)/\1pass=2:/ if $TWOPASS eq 'yes';
} else {
	error("supported video codecs are xvid and divx");
}

# Subtitles?
$ARGS = "$ARGS -sid $SID -subfont-blur 6 -subfont-outline 1 -subfont-text-scale 3"
	if $SLANG ne 'none';

if ($OVC eq 'divx' and $TWOPASS eq 'yes') {
	for (my $pass = 1; $pass < 3; ++$pass) {
		info("Encoder pass $pass\n");
		$ARGS =~ s/(vcodec=mpeg4:)/\1vpass=$pass:/;
	my $CMD = "mencoder $ARGS";
		info("$CMD\n") if $DEBUG eq 'yes';
		system($CMD);
	}
	unlink("divx2pass.log");
} else {
my $CMD = "mencoder $ARGS";

	info("$CMD\n") if $DEBUG eq 'yes';
	exit(1) if system($CMD) != 0;
}

system("eject&") unless $INTERRUPTED;
