484 changes: 242 additions & 242 deletions trunk/nuv_utils.pm
Original file line number Diff line number Diff line change
@@ -1,271 +1,271 @@
package nuv_utils;

use Exporter;
our @ISA = qw/ Exporter /;
our @EXPORT = qw/ generate_showtime find_program nuv_info num_cpus fork_command shell_escape mysql_escape Quit system fifos_wait /;
use Exporter;
our @ISA = qw/ Exporter /;
our @EXPORT = qw/ generate_showtime find_program nuv_info num_cpus fork_command shell_escape mysql_escape Quit system fifos_wait /;

*DEBUG = *main::DEBUG;
*DEBUG = *main::DEBUG;

# Returns a nicely-formatted timestamp from a specified time
sub generate_showtime {
$showtime = '';
# Get the
my ($year, $month, $day, $hour, $minute, $second) = @_;
$month = int($month);
$day = int($day);
# Get the current time, so we know whether or not to display certain fields (eg. year)
my ($this_second, $this_minute, $this_hour, $ignore, $this_month, $this_year) = localtime;
$this_year += 1900;
$this_month++;
# Default the meridian to AM
my $meridian = 'AM';
# Generate the showtime string
$showtime .= "$month/$day";
$showtime .= "/$year" unless ($year == $this_year);
if ($hour == 0) {
$hour = 12;
}
elsif ($hour > 12) {
$hour -= 12;
$meridian = 'PM';
}
$showtime .= ", $hour:$minute $meridian";
# Return
return $showtime;
}
sub generate_showtime {
$showtime = '';
# Get the
my ($year, $month, $day, $hour, $minute, $second) = @_;
$month = int($month);
$day = int($day);
# Get the current time, so we know whether or not to display certain fields (eg. year)
my ($this_second, $this_minute, $this_hour, $ignore, $this_month, $this_year) = localtime;
$this_year += 1900;
$this_month++;
# Default the meridian to AM
my $meridian = 'AM';
# Generate the showtime string
$showtime .= "$month/$day";
$showtime .= "/$year" unless ($year == $this_year);
if ($hour == 0) {
$hour = 12;
}
elsif ($hour > 12) {
$hour -= 12;
$meridian = 'PM';
}
$showtime .= ", $hour:$minute $meridian";
# Return
return $showtime;
}

# This searches the path for the specified programs, and returns the lowest-index-value program found
sub find_program {
# Load the programs, and get a count of the priorities
my(%programs, $num_programs);
foreach my $program (@_) {
$programs{$program} = ++$num_programs;
}
# No programs requested?
return undef unless ($num_programs > 0);
# Search for the program(s)
my %found;
foreach my $path (split(/:/, $ENV{PATH}), '.') {
foreach my $program (keys %programs) {
if (-e "$path/$program" && (!$found{name} || $programs{$program} < $programs{$found{name}})) {
$found{name} = $program;
$found{path} = $path;
}
# Leave early if we found the highest priority program
last if ($found{name} && $programs{$found{name}} == 1);
}
}
# Return
return undef unless ($found{path} && $found{name});
return $found{path}.'/'.$found{name};
}
sub find_program {
# Load the programs, and get a count of the priorities
my(%programs, $num_programs);
foreach my $program (@_) {
$programs{$program} = ++$num_programs;
}
# No programs requested?
return undef unless ($num_programs > 0);
# Search for the program(s)
my %found;
foreach my $path (split(/:/, $ENV{PATH}), '.') {
foreach my $program (keys %programs) {
if (-e "$path/$program" && (!$found{name} || $programs{$program} < $programs{$found{name}})) {
$found{name} = $program;
$found{path} = $path;
}
# Leave early if we found the highest priority program
last if ($found{name} && $programs{$found{name}} == 1);
}
}
# Return
return undef unless ($found{path} && $found{name});
return $found{path}.'/'.$found{name};
}

# Opens a .nuv file and returns information about it
sub nuv_info {
my $file = shift;
my(%info, $buffer);
# open the file
sub nuv_info {
my $file = shift;
my(%info, $buffer);
# open the file
if ($main::video_dir and -e $main::video_dir and -e "$main::video_dir/$file") {
open(DATA, "$main::video_dir/$file") or die "Can't open $file: $!\n\n";
}
else {
open(DATA, $file) or die "Can't open $file: $!\n\n";
}
# Read the file info header
read(DATA, $buffer, 72);
# Unpack the data structure
($info{finfo}, # "NuppelVideo" + \0
$info{version}, # "0.05" + \0
$info{width},
$info{height},
$info{desiredheight}, # 0 .. as it is
$info{desiredwidth}, # 0 .. as it is
$info{pimode}, # P .. progressive, I .. interlaced (2 half pics) [NI]
$info{aspect}, # 1.0 .. square pixel (1.5 .. e.g. width=480: width*1.5=720 for capturing for svcd material
$info{fps},
$info{videoblocks}, # count of video-blocks -1 .. unknown 0 .. no video
$info{audioblocks}, # count of audio-blocks -1 .. unknown 0 .. no audio
$info{textsblocks}, # count of text-blocks -1 .. unknown 0 .. no text
$info{keyframedist}
) = unpack('Z12 Z5 xxx i i i i a xxx d d i i i i', $buffer);
# Is this even a NUV file?
return mpeg_info($file) unless ($info{finfo} =~ /\w/);
# Perl occasionally over-reads on the previous read()
seek(DATA, 72, 0);
# Read and parse the first frame header
read(DATA, $buffer, 12);
my ($frametype,
$comptype,
$keyframe,
$filters,
$timecode,
$packetlength) = unpack('a a a a i i', $buffer);
# Parse the frame
die "Illegal nuv file format: $file\n\n" unless ($frametype eq 'D');
# Read some more stuff if we have to
read(DATA, $buffer, $packetlength) if ($packetlength);
# Read the remaining frame headers
while (12 == read(DATA, $buffer, 12)) {
# Parse the frame header
($frametype,
$comptype,
$keyframe,
$filters,
$timecode,
$packetlength) = unpack('a a a a i i', $buffer);
# Read some more stuff if we have to
read(DATA, $buffer, $packetlength) if ($packetlength);
# Look for the audio frame
if ($frametype eq 'X') {
my $frame_version;
($frame_version,
$info{video_fourcc},
$info{audio_fourcc},
$info{audio_sample_rate},
$info{audio_bits_per_sample},
$info{audio_channels},
$info{audio_compression_ratio},
$info{audio_quality},
$info{rtjpeg_quality},
$info{rtjpeg_luma_filter},
$info{rtjpeg_chroma_filter},
$info{lavc_bitrate},
$info{lavc_qmin},
$info{lavc_qmax},
$info{lavc_maxqdiff},
$info{seektable_offset},
$info{keyframeadjust_offset}
) = unpack('iiiiiiiiiiiiiiill', $buffer);
# Found the audio data we want - time to leave
last;
}
# Done reading frames - let's leave
else {
last;
}
}
# Close the file
close DATA;
# Make sure some things are actually numbers
$info{width} += 0;
$info{height} += 0;
# Return
return %info;
}
# Read the file info header
read(DATA, $buffer, 72);
# Unpack the data structure
($info{finfo}, # "NuppelVideo" + \0
$info{version}, # "0.05" + \0
$info{width},
$info{height},
$info{desiredheight}, # 0 .. as it is
$info{desiredwidth}, # 0 .. as it is
$info{pimode}, # P .. progressive, I .. interlaced (2 half pics) [NI]
$info{aspect}, # 1.0 .. square pixel (1.5 .. e.g. width=480: width*1.5=720 for capturing for svcd material
$info{fps},
$info{videoblocks}, # count of video-blocks -1 .. unknown 0 .. no video
$info{audioblocks}, # count of audio-blocks -1 .. unknown 0 .. no audio
$info{textsblocks}, # count of text-blocks -1 .. unknown 0 .. no text
$info{keyframedist}
) = unpack('Z12 Z5 xxx i i i i a xxx d d i i i i', $buffer);
# Is this even a NUV file?
return mpeg_info($file) unless ($info{finfo} =~ /\w/);
# Perl occasionally over-reads on the previous read()
seek(DATA, 72, 0);
# Read and parse the first frame header
read(DATA, $buffer, 12);
my ($frametype,
$comptype,
$keyframe,
$filters,
$timecode,
$packetlength) = unpack('a a a a i i', $buffer);
# Parse the frame
die "Illegal nuv file format: $file\n\n" unless ($frametype eq 'D');
# Read some more stuff if we have to
read(DATA, $buffer, $packetlength) if ($packetlength);
# Read the remaining frame headers
while (12 == read(DATA, $buffer, 12)) {
# Parse the frame header
($frametype,
$comptype,
$keyframe,
$filters,
$timecode,
$packetlength) = unpack('a a a a i i', $buffer);
# Read some more stuff if we have to
read(DATA, $buffer, $packetlength) if ($packetlength);
# Look for the audio frame
if ($frametype eq 'X') {
my $frame_version;
($frame_version,
$info{video_fourcc},
$info{audio_fourcc},
$info{audio_sample_rate},
$info{audio_bits_per_sample},
$info{audio_channels},
$info{audio_compression_ratio},
$info{audio_quality},
$info{rtjpeg_quality},
$info{rtjpeg_luma_filter},
$info{rtjpeg_chroma_filter},
$info{lavc_bitrate},
$info{lavc_qmin},
$info{lavc_qmax},
$info{lavc_maxqdiff},
$info{seektable_offset},
$info{keyframeadjust_offset}
) = unpack('iiiiiiiiiiiiiiill', $buffer);
# Found the audio data we want - time to leave
last;
}
# Done reading frames - let's leave
else {
last;
}
}
# Close the file
close DATA;
# Make sure some things are actually numbers
$info{width} += 0;
$info{height} += 0;
# Return
return %info;
}

# Uses one of two mpeg info programs to load data about mpeg-based nuv files
sub mpeg_info {
my $file = "$main::video_dir/".shift;
$file =~ s/'/\\'/sg;
my %info;
# First, we check for the existence of an mpeg info program
my $program = find_program('tcprobe', 'mpgtx');
# Nothing found? Die
die "You need tcprobe (transcode) or mpgtx to use this script on mpeg-based nuv files.\n\n" unless ($program);
# Set the is_mpeg flag
$info{is_mpeg} = 1;
# Grab tcprobe info
if ($program =~ /tcprobe$/) {
my $data = `$program -i '$file'`;
($info{width}, $info{height}) = $data =~ /frame\s+size:\s+-g\s+(\d+)x(\d+)\b/m;
($info{fps}) = $data =~ /frame\s+rate:\s+-f\s+(\d+(?:\.\d+)?)\b/m;
($info{audio_sample_rate}) = $data =~ /audio\s+track:.+?-e\s+(\d+)\b/m;
}
# Grab tcmplex info
elsif ($program =~ /mpgtx$/) {
my $data = `$program -i '$file'`;
($info{width}, $info{height}, $info{fps}) = $data =~ /\bSize\s+\[(\d+)\s*x\s*(\d+)\]\s+(\d+(?:\.\d+)?)\s*fps/m;
($info{audio_sample_rate}) = $data =~ /\b(\d+)\s*Hz/m;
}
# Return
return %info;
}
sub mpeg_info {
my $file = "$main::video_dir/".shift;
$file =~ s/'/\\'/sg;
my %info;
# First, we check for the existence of an mpeg info program
my $program = find_program('tcprobe', 'mpgtx');
# Nothing found? Die
die "You need tcprobe (transcode) or mpgtx to use this script on mpeg-based nuv files.\n\n" unless ($program);
# Set the is_mpeg flag
$info{is_mpeg} = 1;
# Grab tcprobe info
if ($program =~ /tcprobe$/) {
my $data = `$program -i '$file'`;
($info{width}, $info{height}) = $data =~ /frame\s+size:\s+-g\s+(\d+)x(\d+)\b/m;
($info{fps}) = $data =~ /frame\s+rate:\s+-f\s+(\d+(?:\.\d+)?)\b/m;
($info{audio_sample_rate}) = $data =~ /audio\s+track:.+?-e\s+(\d+)\b/m;
}
# Grab tcmplex info
elsif ($program =~ /mpgtx$/) {
my $data = `$program -i '$file'`;
($info{width}, $info{height}, $info{fps}) = $data =~ /\bSize\s+\[(\d+)\s*x\s*(\d+)\]\s+(\d+(?:\.\d+)?)\s*fps/m;
($info{audio_sample_rate}) = $data =~ /\b(\d+)\s*Hz/m;
}
# Return
return %info;
}

# Queries /proc/cpuinfo to find out how many cpu's are available on this machine
sub num_cpus {
my $cpuinfo = `cat /proc/cpuinfo`;
$num = 0;
while ($cpuinfo =~ /^processor\s*:\s*\d+/mg) {
$num++;
}
return $num;
}
sub num_cpus {
my $cpuinfo = `cat /proc/cpuinfo`;
$num = 0;
while ($cpuinfo =~ /^processor\s*:\s*\d+/mg) {
$num++;
}
return $num;
}

# This subroutine forks and executes one system command - nothing fancy
sub fork_command {
my $command = shift;
if ($DEBUG) {
print "\nforking:\n$command\n";
return undef;
}
sub fork_command {
my $command = shift;
if ($DEBUG) {
print "\nforking:\n$command\n";
return undef;
}

# Fork and return the child's pid
my $pid = undef;
if ($pid = fork) {
return $pid
}
# $pid defined means that this is now the forked child
elsif (defined $pid) {
system($command);
# Exit using something that won't set off the END block
use POSIX;
POSIX::_exit(0);
}
# Couldn't fork, guess we have to quit
die "Couldn't fork: $!\n\n$command\n\n";
}
# Fork and return the child's pid
my $pid = undef;
if ($pid = fork) {
return $pid
}
# $pid defined means that this is now the forked child
elsif (defined $pid) {
system($command);
# Exit using something that won't set off the END block
use POSIX;
POSIX::_exit(0);
}
# Couldn't fork, guess we have to quit
die "Couldn't fork: $!\n\n$command\n\n";
}

sub shell_escape {
$file = shift;
$file =~ s/(["\$])/\\$1/sg;
return "\"$file\"";
}
sub shell_escape {
$file = shift;
$file =~ s/(["\$])/\\$1/sg;
return "\"$file\"";
}

sub mysql_escape {
$string = shift;
return 'NULL' unless (defined $string);
$string =~ s/'/\\'/sg;
return "'$string'";
}
sub mysql_escape {
$string = shift;
return 'NULL' unless (defined $string);
$string =~ s/'/\\'/sg;
return "'$string'";
}

sub Quit {
# If this is the main script, print a nice goodbye message
print "\nThanks for using nuvexport!\n\n" unless ($is_child);
# Time to leave
exit;
}
sub Quit {
# If this is the main script, print a nice goodbye message
print "\nThanks for using nuvexport!\n\n" unless ($is_child);
# Time to leave
exit;
}

# Allow the functions to clean up after themselves - and make sure that they can, but not if they are marked as child processes
END {
if (@main::Functions) {
foreach $function (@main::Functions) {
$function->cleanup;
}
}
}
# Allow the functions to clean up after themselves - and make sure that they can, but not if they are marked as child processes
END {
if (@main::Functions) {
foreach $function (@main::Functions) {
$function->cleanup;
}
}
}

sub system {
my $command = shift;
if ($DEBUG) {
print "\nsystem call:\n$command\n";
} else {
system($command);
}
}
sub system {
my $command = shift;
if ($DEBUG) {
print "\nsystem call:\n$command\n";
} else {
system($command);
}
}

sub fifos_wait {
# Sleep a bit to let mythtranscode start up
my $fifodir = shift;
my $overload = 0;
if (!$DEBUG) {
while (++$overload < 30 && !(-e "$fifodir/audout" && -e "$fifodir/vidout" )) {
sleep 1;
print "Waiting for mythtranscode to set up the fifos.\n";
}
unless (-e "$fifodir/audout" && -e "$fifodir/vidout") {
die "Waited too long for mythtranscode to create its fifos. Please try again.\n\n";
}
}
}
sub fifos_wait {
# Sleep a bit to let mythtranscode start up
my $fifodir = shift;
my $overload = 0;
if (!$DEBUG) {
while (++$overload < 30 && !(-e "$fifodir/audout" && -e "$fifodir/vidout" )) {
sleep 1;
print "Waiting for mythtranscode to set up the fifos.\n";
}
unless (-e "$fifodir/audout" && -e "$fifodir/vidout") {
die "Waited too long for mythtranscode to create its fifos. Please try again.\n\n";
}
}
}

1; #return true
1; #return true
394 changes: 197 additions & 197 deletions trunk/nuvexport
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ directory, and extracts all related database info into a matching .sql file.
To import this into another myth setup, just copy the nuv to your video directory
and run:
mysql mythconverg < sql_file_name.sql
mysql mythconverg < sql_file_name.sql
=head2 SVCD
Expand Down Expand Up @@ -83,257 +83,257 @@ format and use Microsoft's Windows Media Encoder to encode a WMV file.
=cut

# Load some modules that we'll use
use DBI;
use Getopt::Long;
use File::Basename;
use DBI;
use Getopt::Long;
use File::Basename;

# Add a couple of include paths so we can load the various export and gui modules
use lib dirname($ENV{'_'}), '/usr/share/nuvexport', '/usr/local/share/nuvexport';
use lib dirname($ENV{'_'}), '/usr/share/nuvexport', '/usr/local/share/nuvexport';

# A global list of the various programs (and full paths) we'll be needing/using
our %Prog;
our %Shows;
our @Functions;
our %Args; # Edit this to store command line arguments in individual variables
our @Arg_str; # Edit this to add more command line parse strings
our $DEBUG;
our $gui;
our $video_dir;
our $num_shows;
our $dbh;
our $hostname;
our %Prog;
our %Shows;
our @Functions;
our %Args; # Edit this to store command line arguments in individual variables
our @Arg_str; # Edit this to add more command line parse strings
our $DEBUG;
our $gui;
our $video_dir;
our $num_shows;
our $dbh;
our $hostname;

# Load the nuv utilities
use nuv_utils;
use nuv_utils;

# Load the gui modules
use gui_text;
use gui_cli;
use gui_text;
use gui_cli;

# Load the export modules
use export_DivX;
use export_NUV_SQL;
use export_SVCD;
use export_VCD;
use export_DVD;
use export_OGM;
use export_WMV;
use export_MP3;
use export_Trans_XviD;
use export_Trans_VCD;
use export_Trans_SVCD;
use export_DivX;
use export_NUV_SQL;
use export_SVCD;
use export_VCD;
use export_DVD;
use export_OGM;
use export_WMV;
use export_MP3;
use export_Trans_XviD;
use export_Trans_VCD;
use export_Trans_SVCD;

# Make sure that we have mythtranscode installed
$Prog{mythtranscode} = find_program('mythtranscode');
die "You need mythtranscode to use this program.\n\n" unless ($Prog{mythtranscode});
$Prog{mythtranscode} = find_program('mythtranscode');
die "You need mythtranscode to use this program.\n\n" unless ($Prog{mythtranscode});

# Make sure that we have ffmpeg installed
$Prog{ffmpeg} = find_program('ffmpeg');
die "You need ffmpeg to use this program.\n\n" unless ($Prog{ffmpeg});
$Prog{ffmpeg} = find_program('ffmpeg');
die "You need ffmpeg to use this program.\n\n" unless ($Prog{ffmpeg});

# Make sure that we have nice installed
$Prog{nice} = find_program('nice');
die "You need nice to use this program.\n\n" unless ($Prog{nice});
$Prog{nice} = find_program('nice');
die "You need nice to use this program.\n\n" unless ($Prog{nice});

# Find out which encoders are available to use, and load any extra command line argument variables
push @Functions, export_SVCD->new,
export_NUV_SQL->new,
export_DivX->new,
export_WMV->new,
export_VCD->new,
export_DVD->new,
export_OGM->new,
export_MP3->new,
export_Trans_XviD->new,
export_Trans_VCD->new,
export_Trans_SVCD->new;
push @Functions, export_SVCD->new,
export_NUV_SQL->new,
export_DivX->new,
export_WMV->new,
export_VCD->new,
export_DVD->new,
export_OGM->new,
export_MP3->new,
export_Trans_XviD->new,
export_Trans_VCD->new,
export_Trans_SVCD->new;

# Set up the signal handlers
$SIG{INT} = \&Quit;
$SIG{QUIT} = \&Quit;
$SIG{INT} = \&Quit;
$SIG{QUIT} = \&Quit;

# Load the commandline options
%Args = ('debug' => \$DEBUG);
push @Arg_str,
'help',
'debug',
# GUI override - not really needed at this point
'gui|ui=s',
# Used for searching
'title=s',
'subtitle|episode=s',
'description=s',
# CLI for which export mode to use
'mode|function|export=s',
# Used to specify a program
'chanid|channel=i',
'starttime|start_time=i',
# Save path - used by most exporters, so it's included here
'outfile|out=s';
GetOptions(\%Args, @Arg_str);
%Args = ('debug' => \$DEBUG);
push @Arg_str,
'help',
'debug',
# GUI override - not really needed at this point
'gui|ui=s',
# Used for searching
'title=s',
'subtitle|episode=s',
'description=s',
# CLI for which export mode to use
'mode|function|export=s',
# Used to specify a program
'chanid|channel=i',
'starttime|start_time=i',
# Save path - used by most exporters, so it's included here
'outfile|out=s';
GetOptions(\%Args, @Arg_str);

# Print the help - for now, this is just perldoc
if ($Args{help}) {
exec("perldoc $0");
}
if ($Args{help}) {
exec("perldoc $0");
}

if ($Args{function}) {
print "function: $Args{function}\n\n";
exit;
}
if ($Args{function}) {
print "function: $Args{function}\n\n";
exit;
}

if ($Args{ui}) {
print "ui: $Args{ui}\n\n";
exit;
}
if ($Args{ui}) {
print "ui: $Args{ui}\n\n";
exit;
}

# Get the hostname of this machine
$hostname = `hostname`;
chomp($hostname);
$hostname = `hostname`;
chomp($hostname);

# Read the mysql.txt file in use by MythTV.
# could be in a couple places, so try the usual suspects
open(CONF, "$ENV{HOME}/.mythtv/mysql.txt")
or open(CONF, "/usr/share/mythtv/mysql.txt")
or open(CONF, "/usr/local/share/mythtv/mysql.txt")
or die ("Unable to open /usr/share/mythtv/mysql.txt: $!\n\n");
while (my $line = <CONF>) {
chomp($line);
$line =~ s/^str //;
my ($var, $val) = split(/\=/, $line, 2);
next unless ($var && $var =~ /\w/);
if ($var eq 'DBHostName') {
$db_host = $val;
}
elsif ($var eq 'DBUserName') {
$db_user = $val;
}
elsif ($var eq 'DBName') {
$db_name = $val;
}
elsif ($var eq 'DBPassword') {
$db_pass = $val;
}
elsif ($var eq 'LocalHostName') {
$hostname = $val;
}
}
close CONF;
open(CONF, "$ENV{HOME}/.mythtv/mysql.txt")
or open(CONF, "/usr/share/mythtv/mysql.txt")
or open(CONF, "/usr/local/share/mythtv/mysql.txt")
or die ("Unable to open /usr/share/mythtv/mysql.txt: $!\n\n");
while (my $line = <CONF>) {
chomp($line);
$line =~ s/^str //;
my ($var, $val) = split(/\=/, $line, 2);
next unless ($var && $var =~ /\w/);
if ($var eq 'DBHostName') {
$db_host = $val;
}
elsif ($var eq 'DBUserName') {
$db_user = $val;
}
elsif ($var eq 'DBName') {
$db_name = $val;
}
elsif ($var eq 'DBPassword') {
$db_pass = $val;
}
elsif ($var eq 'LocalHostName') {
$hostname = $val;
}
}
close CONF;

# Connect to the database
$dbh = DBI->connect("dbi:mysql:database=$db_name:host=$db_host", $db_user, $db_pass)
or die "Cannot connect to database: $!\n\n";
$dbh = DBI->connect("dbi:mysql:database=$db_name:host=$db_host", $db_user, $db_pass)
or die "Cannot connect to database: $!\n\n";


# Find the directory where the recordings are located, and grab all of the filenames
my $q = "SELECT data FROM settings WHERE value='RecordFilePrefix' AND hostname=?";
my $sh = $dbh->prepare($q);
$sh->execute($hostname) or die "Could not execute ($q): $!\n\n";
($video_dir) = $sh->fetchrow_array;
die "This host not configured for myth.\n\n" unless ($video_dir);
die "Recordings directory $video_dir doesn't exist!\n\n" unless (-d $video_dir);
opendir(DIR, $video_dir) or die "Can't open $video_dir: $!\n\n";
my @Files = grep /\.nuv$/, readdir(DIR);
closedir DIR;
die "No recordings found!\n\n" unless (@Files);
my $q = "SELECT data FROM settings WHERE value='RecordFilePrefix' AND hostname=?";
my $sh = $dbh->prepare($q);
$sh->execute($hostname) or die "Could not execute ($q): $!\n\n";
($video_dir) = $sh->fetchrow_array;
die "This host not configured for myth.\n\n" unless ($video_dir);
die "Recordings directory $video_dir doesn't exist!\n\n" unless (-d $video_dir);
opendir(DIR, $video_dir) or die "Can't open $video_dir: $!\n\n";
my @Files = grep /\.nuv$/, readdir(DIR);
closedir DIR;
die "No recordings found!\n\n" unless (@Files);

# Parse out the record data for each file
$q = "SELECT title, subtitle, description, hostname, cutlist FROM recorded WHERE chanid=? AND starttime=? AND endtime=?";
$sh = $dbh->prepare($q);
foreach $file (@Files) {
next unless ($file =~ /\.nuv$/);
# Pull out the various parts that make up the filename
($channel,
$syear, $smonth, $sday, $shour, $sminute, $ssecond,
$eyear, $emonth, $eday, $ehour, $eminute, $esecond) = $file =~/^([a-z0-9]+)_(....)(..)(..)(..)(..)(..)_(....)(..)(..)(..)(..)(..)\.nuv$/i;
# Found a bad filename?
unless ($channel) {
print "Unknown filename format: $file\n";
next;
}
# Execute the query
$sh->execute($channel, "$syear$smonth$sday$shour$sminute$ssecond", "$eyear$emonth$eday$ehour$eminute$esecond")
or die "Could not execute ($q): $!\n\n";
my ($show, $episode, $description, $show_hostname, $cutlist) = $sh->fetchrow_array;
# Unknown file - someday we should report this
next unless ($show);
#$description =~ s/(?:''|``)/"/sg;
push @{$Shows{$show}}, {'filename' => $file,
'channel' => $channel,
'start_time' => "$syear$smonth$sday$shour$sminute$ssecond",
'end_time' => "$eyear$emonth$eday$ehour$eminute$esecond",
'start_time_sep' => "$syear-$smonth-$sday-$shour-$sminute-$ssecond",
'show_name' => $show,
'title' => ($episode or 'Untitled'),
'description' => ($description or 'No Description'),
'hostname' => $show_hostname,
'cutlist' => $cutlist,
'showtime' => generate_showtime($syear, $smonth, $sday, $shour, $sminute, $ssecond)};
}
$sh->finish();
$q = "SELECT title, subtitle, description, hostname, cutlist FROM recorded WHERE chanid=? AND starttime=? AND endtime=?";
$sh = $dbh->prepare($q);
foreach $file (@Files) {
next unless ($file =~ /\.nuv$/);
# Pull out the various parts that make up the filename
($channel,
$syear, $smonth, $sday, $shour, $sminute, $ssecond,
$eyear, $emonth, $eday, $ehour, $eminute, $esecond) = $file =~/^([a-z0-9]+)_(....)(..)(..)(..)(..)(..)_(....)(..)(..)(..)(..)(..)\.nuv$/i;
# Found a bad filename?
unless ($channel) {
print "Unknown filename format: $file\n";
next;
}
# Execute the query
$sh->execute($channel, "$syear$smonth$sday$shour$sminute$ssecond", "$eyear$emonth$eday$ehour$eminute$esecond")
or die "Could not execute ($q): $!\n\n";
my ($show, $episode, $description, $show_hostname, $cutlist) = $sh->fetchrow_array;
# Unknown file - someday we should report this
next unless ($show);
#$description =~ s/(?:''|``)/"/sg;
push @{$Shows{$show}}, {'filename' => $file,
'channel' => $channel,
'start_time' => "$syear$smonth$sday$shour$sminute$ssecond",
'end_time' => "$eyear$emonth$eday$ehour$eminute$esecond",
'start_time_sep' => "$syear-$smonth-$sday-$shour-$sminute-$ssecond",
'show_name' => $show,
'title' => ($episode or 'Untitled'),
'description' => ($description or 'No Description'),
'hostname' => $show_hostname,
'cutlist' => $cutlist,
'showtime' => generate_showtime($syear, $smonth, $sday, $shour, $sminute, $ssecond)};
}
$sh->finish();

# We now have a hash of show names, containing an array of episodes
# We should probably do some sorting by timestamp (and also count how many shows there are)
$num_shows = 0;
foreach my $show (sort keys %Shows) {
@{$Shows{$show}} = sort {$a->{start_time} <=> $b->{start_time} || $a->{channel} <=> $b->{channel}} @{$Shows{$show}};
$num_shows++;
}
$num_shows = 0;
foreach my $show (sort keys %Shows) {
@{$Shows{$show}} = sort {$a->{start_time} <=> $b->{start_time} || $a->{channel} <=> $b->{channel}} @{$Shows{$show}};
$num_shows++;
}

# No shows found?
die 'Found '.@Files." files, but no matching database entries.\n\n" unless ($num_shows);
die 'Found '.@Files." files, but no matching database entries.\n\n" unless ($num_shows);

# Command line search?
if ($Args{title} || $Args{subtitle} || $Args{description}) {
my @matches;
foreach my $show (sort keys %Shows) {
# Title search?
next unless (!$Args{title} || $show =~ /$Args{title}/si);
# Search episodes
foreach my $episode (@{$Shows{$show}}) {
next unless (!$Args{subtitle} || $episode->{title} =~ /$Args{subtitle}/si);
next unless (!$Args{description} || $episode->{description} =~ /$Args{description}/si);
push @matches, $episode;
}
}
# Display matching shows
if (@matches) {
print "\nMatching Shows:\n\n";
foreach my $episode (@matches) {
print " title: $episode->{show_name}\n",
" subtitle: $episode->{title}\n",
" chanid: $episode->{channel}\n",
" starts: $episode->{start_time}\n",
" ends: $episode->{end_time}\n",
" filename: $video_dir/$episode->{filename}\n\n";
}
}
# No matches?
else {
print "\nNo matching shows were found.\n\n";
}
# Exit gracefully
Quit();
}
if ($Args{title} || $Args{subtitle} || $Args{description}) {
my @matches;
foreach my $show (sort keys %Shows) {
# Title search?
next unless (!$Args{title} || $show =~ /$Args{title}/si);
# Search episodes
foreach my $episode (@{$Shows{$show}}) {
next unless (!$Args{subtitle} || $episode->{title} =~ /$Args{subtitle}/si);
next unless (!$Args{description} || $episode->{description} =~ /$Args{description}/si);
push @matches, $episode;
}
}
# Display matching shows
if (@matches) {
print "\nMatching Shows:\n\n";
foreach my $episode (@matches) {
print " title: $episode->{show_name}\n",
" subtitle: $episode->{title}\n",
" chanid: $episode->{channel}\n",
" starts: $episode->{start_time}\n",
" ends: $episode->{end_time}\n",
" filename: $video_dir/$episode->{filename}\n\n";
}
}
# No matches?
else {
print "\nNo matching shows were found.\n\n";
}
# Exit gracefully
Quit();
}

# Command line export request?
if ($Args{starttime} || $Args{chanid} || $Args{mode}) {
$gui = gui_cli->new;
}
if ($Args{starttime} || $Args{chanid} || $Args{mode}) {
$gui = gui_cli->new;
}

# Load another gui here?
# Nope, we don't have one
# Nope, we don't have one

# Load the text-based gui by default
else {
$gui = gui_text->new;
}
else {
$gui = gui_text->new;
}

# Run the main GUI loop
$gui->main_loop;
$gui->main_loop;

# Exit gracefully, in case we might accidentally execute some code below
Quit();
Quit();



6 changes: 3 additions & 3 deletions trunk/nuvinfo
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
#nuvinfo.pl

# Add a couple of include paths so we can load the various export and gui modules
use File::Basename;
use lib dirname($ENV{'_'}), '/usr/share/nuvexport', '/usr/local/share/nuvexport';
use File::Basename;
use lib dirname($ENV{'_'}), '/usr/share/nuvexport', '/usr/local/share/nuvexport';

# Load the nuv utilities
use nuv_utils;
use nuv_utils;

# No file specified?
die "usage:\n\n nuvinfo /path/to/file.nuv\n\n" unless ($ARGV[0]);
Expand Down