Thursday, March 29, 2012

Move recordings from one MythTV folder to another - update the database

This script is built up from several transcode scripts and database scripts I have found elsewhere. 

It will take a recording from MythTV, give it a human readable filename, and then shift the recording to a new folder that you can specify. Finally, it will update the database to point to the new location.



#!/usr/bin/perl -w
# ============================================================================
# = NAME 
# move_myth_recordings.pl
#
# = PURPOSE
# Move recording from MythTV to a different folder, updating the database
# Hs the ability to change the filename to human readable
#
# = USAGE
my $usage = 'Usage:
move_myth_recordings.pl -j %JOBID%
move_myth_recordings.pl -f %FILE% 
';
# ============================================================================
use strict;
use MythTV;
use XML::Simple;
use File::Copy;


# What file are we copying/transcoding?
my $file  = '';
my $jobid = -1;


# do nothing?
my $noexec = 0;


# extra console output?
my $DEBUG = 1;


# some globals
my ($chanid, $command, $query, $ref, $starttime, $showtitle, $episodetitle);
my ($seasonnumber, $episodenumber, $episodedetails);
my ($newfilename, $newstarttime);
my $xmlparser = new XML::Simple;
my $xmlstring;


my $mt = '';
my $db = '';


# Set your desired output directory
# Make sure this folder is writable by your myth user
my $outputdir = "/home/david/Recordings/Sturt"; # Don't use a trailing slash


# ============================================================================
sub Reconnect()
{
    $mt = new MythTV();
    $db = $mt->{'dbh'};
}


# ============================================================================
sub Die($)
{
    print STDERR "@_\n";
    exit -1;
}


# ============================================================================
# Parse command-line arguments, check there is something to do:
#
if ( ! @ARGV )
{   Die "$usage"  }
Reconnect;


while ( @ARGV && $ARGV[0] =~ m/^-/ )
{
    my $arg = shift @ARGV;


    if ( $arg eq '-d' || $arg eq '--debug' )
    {   $DEBUG = 1  }
    elsif ( $arg eq '-n' || $arg eq '--noaction' )
    {   $noexec = 1  }
    elsif ( $arg eq '-j' || $arg eq '--jobid' )
    {   $jobid = shift @ARGV  }
    elsif ( $arg eq '-f' || $arg eq '--file' )
    {   $file = shift @ARGV  }
    else
    {
        unshift @ARGV, $arg;
        last;
    }
}


if ( ! $file && $jobid == -1 )
{
    Die "No file or job specified. $usage";
}


# ============================================================================
# If we were supplied a jobid, lookup chanid
# and starttime so that we can find the filename
#
if ( $jobid != -1 )
{
    $query = $db->prepare("SELECT chanid, starttime " .
                          "FROM jobqueue WHERE id=$jobid;");
    $query->execute || Die "Unable to query jobqueue table";
    $ref       = $query->fetchrow_hashref;
    $chanid    = $ref->{'chanid'};
    $starttime = $ref->{'starttime'};
    $query->finish;


    if ( ! $chanid || ! $starttime )
    {   Die "Cannot find details for job $jobid"  }


    $query = $db->prepare("SELECT basename FROM recorded " .
                          "WHERE chanid=$chanid AND starttime='$starttime';");
    $query->execute || Die "Unable to query recorded table";
    ($file) = $query->fetchrow_array;
    $query->finish;


    if ( ! $file )
    {   Die "Cannot find recording for chan $chanid, starttime $starttime"  }


    if ( $DEBUG )
    {
        print "Job $jobid refers to recording chanid=$chanid,",
              " starttime=$starttime\n"
    }
}
else
{
    if ( $file =~ m/(\d+)_(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/ )
    {   $chanid = $1, $starttime = "$2-$3-$4 $5:$6:$7"  }
    else
    {
        print "File $file has a strange name. Searching in recorded table\n";
        $query = $db->prepare("SELECT chanid, starttime " .
                              "FROM recorded WHERE basename='$file';");
        $query->execute || Die "Unable to query recorded table";
        ($chanid,$starttime) = $query->fetchrow_array;
        $query->finish;


        if ( ! $chanid || ! $starttime )
        {   Die "Cannot find details for filename $file"  }
    }
}


# ============================================================================
# A commonly used SQL row selector:
my $whereChanAndStarttime = "WHERE chanid=$chanid AND starttime='$starttime'";


# ============================================================================
# Find the directory that contains the recordings, check the file exists
#
my $dir  = undef;
my $dirs = $mt->{'video_dirs'};


foreach my $d ( @$dirs )
{
 if ( ! -e $d )
 {   Die "Cannot find directory $dir that contains recordings"  }


 if ( -e "$d/$file" )
 {
  $dir = $d;
  last
 }
 else
 {   print "$d/$file does not exist\n"   }
}


if ( ! $dir )
{   Die "Cannot find recording"  }


# ============================================================================
# First, generate a new filename,
#


$query = $db->prepare("SELECT title FROM recorded $whereChanAndStarttime;");
$query->execute || Die "Unable to query recorded table";
$showtitle = $query->fetchrow_array;
$query->finish;


$query = $db->prepare("SELECT subtitle FROM recorded $whereChanAndStarttime;");
$query->execute || Die "Unable to query recorded table";
$episodetitle = $query->fetchrow_array;
$query->finish;


if ( $episodetitle ne "" ) 
{
  $seasonnumber = "";
  $episodenumber = "";
  $xmlstring = `/usr/share/mythtv/metadata/Television/ttvdb.py -N "$showtitle" "$episodetitle"`;
  if ( $xmlstring ne "" ) {
    $episodedetails =$xmlparser->XMLin($xmlstring);
    $seasonnumber = $episodedetails->{item}->{season};
    $episodenumber = $episodedetails->{item}->{episode};
  }
}
my ($year,$month,$day,$hour,$mins,$secs) = split m/[- :]/, $starttime;
my $oldShortTime = sprintf "%04d%02d%02d",
                   $year, $month, $day;
my $iter = 0;


do {
  if ( $episodetitle eq "" || $seasonnumber eq "" || $episodenumber eq "" )
  {
    $newfilename = sprintf "%s_%s.%s.%s", $showtitle, $month, $day, $year;
  } else {
    $newfilename = sprintf "%s_S%0sE%0s_%s", $showtitle, $seasonnumber, $episodenumber, $episodetitle;
  }
  $newfilename =~ s/\;/   AND   /g;
  $newfilename =~ s/\&/   AND   /g;
  $newfilename =~ s/\s+/ /g;
  $newfilename =~ s/\s/_/g;
  $newfilename =~ s/:/_/g;
  $newfilename =~ s/__/_/g;
  $newfilename =~ s/\(//g;
  $newfilename =~ s/\)//g;
  $newfilename =~ s/'//g;
  $newfilename =~ s/\!//g;
  $newfilename =~ s/\///g;
  if ( $iter != "0" ) 
  {  $newfilename = sprintf "%s_%d%s", $newfilename, $iter, ".mkv"  } else { $newfilename = sprintf "%s%s", $newfilename, ".mkv" }
  $iter ++;
  $secs = $secs + $iter;
  $newstarttime = sprintf "%04d-%02d-%02d %02d:%02d:%02d",
                    $year, $month, $day, $hour, $mins, $secs;
} while  ( -e "$outputdir/$newfilename" );


$DEBUG && print "$outputdir/$newfilename seems unique\n";




# ============================================================================
# Next, move the file.
#
chdir $dir;
copy($file, "$outputdir/$newfilename") or die "File cannot be copied.";
#move($file, "$outputdir/$newfilename") or die "File cannot be moved.";




# ============================================================================
# Last, copy the existing recorded details with the new file name.
#
Reconnect;
$query = $db->prepare("SELECT * FROM recorded $whereChanAndStarttime;");
$query->execute ||  Die "Unable to query recorded table";
$ref = $query->fetchrow_hashref;
$query->finish;


$ref->{'starttime'} = $newstarttime;
$ref->{'basename'}  = $newfilename;
if ( $DEBUG && ! $noexec )
{
    print 'Old file size = ' . (-s "$dir/$file")        . "\n";
    print 'New file size = ' . (-s "$outputdir/$newfilename") . "\n";
}
$ref->{'filesize'}  = -s "$outputdir/$newfilename";


my $extra = 'Copy';




#
# The new recording file has no cutlist, so we don't insert that field
#
my @recKeys = grep(!/^cutlist$/, keys %$ref);


#
# Build up the SQL insert command:
#
$command = 'INSERT INTO recorded (' . join(',', @recKeys) . ') VALUES ("';
foreach my $key ( @recKeys )
{
    if (defined $ref->{$key})
    {   $command .= quotemeta($ref->{$key}) . '","'   }
    else
    {   chop $command; $command .= 'NULL,"'   }
}


chop $command; chop $command;  # remove trailing comma quote


$command .= ');';


if ( $DEBUG || $noexec )
{   print "# $command\n"  }


if ( ! $noexec )
{   $db->do($command)  || Die "Couldn't create new recording's record, but transcoded file exists $newfilename\n"   }


# ============================================================================
# Now, delete the old recording and png files, keeping the new transcoded recording
if ( -e "$outputdir/$newfilename" )
{
   $command = 'DELETE from recorded ' . join(',', $whereChanAndStarttime) . '; '; # Build up the SQL delete command:
    $db->do($command); # remove the mysql entry for the recording
    my $filepng = $file . join(',','.png'); # Create the file png filename
    my $filepng2 = $file . join(',','.-1.100x75.png'); # Create the file png filename
    unlink($file); # remove the original file
    unlink($filepng); # remove the file's png
    unlink($filepng2); # remove the file's png
}


# ============================================================================


$db->disconnect;
1;


# ============================================================================

No comments:

Post a Comment