Skip to content

Instantly share code, notes, and snippets.

@produnis
Created August 2, 2012 11:30
Show Gist options
  • Save produnis/3236414 to your computer and use it in GitHub Desktop.
Save produnis/3236414 to your computer and use it in GitHub Desktop.
MythTV
#!/usr/bin/perl -w
### User-Job-Command:
### /path/to/copy_and_transcode.pl -f %FILE% -p autodetect
# ============================================================================
# = NAME
# copy_and_transcode.pl
#
# = PURPOSE
# Copy a recording before transcoding, so the user can re-cut the original
#
# = USAGE
my $usage = 'Usage:
copy_and_transcode.pl -f %FILE% -p autodetect
copy_and_transcode.pl -j %JOBID% -p autodetect
copy_and_transcode.pl --file file [--debug] [--noaction] [transcode-arguments]
';
# The first two forms would invoke this as a MythTV User Job
#
# = DESCRIPTION
# The exsisting mythtranscode system is designed for replacing a recording
# with a transcoded copy. There is a setting which causes the backend to
# keep the original file, but both the seektable and the cutlist are deleted.
# If you are using transcode to extract multiple clips from a recording,
# this is very inconvenient.
#
# This script transcodes a recording into a new recording,
# with a trivially different starttime.
# If the original recording had a cutlist, that should be honoured in the copy.
#
# = INSTALLATION
# Copy this script to a known location, and then add the command
# in mythtv-setup as a User Job (pg. 7 & 9 of General button) e.g.
#
# cp copy_and_transcode.pl /usr/local/bin
# UserJob1 /usr/local/bin/copy_and_transcode.pl -f %FILE% -p autodetect
# UserJobDesc1 Copy and Transcode
#
# = KNOWN BUGS
#
# = REVISION
# $Id: copy_and_transcode.pl 20349 2009-04-11 00:04:30Z xris $
#
# = AUTHORS
# Nigel Pearson
# ============================================================================
use strict;
use MythTV;
# 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);
my ($newfilename, $newstarttime);
my $mt = new MythTV();
my $db = $mt->{'dbh'};
# ============================================================================
sub Die($)
{
print STDERR "@_\n";
exit -1;
}
# ============================================================================
# Parse command-line arguments, check there is something to do:
#
if ( ! @ARGV )
{ Die "$usage" }
while ( @ARGV && $ARGV[0] =~ m/^-/ )
{
my $arg = shift;
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 }
elsif ( $arg eq '-f' || $arg eq '--file' )
{ $file = shift }
else
{
unshift @ARGV, $arg;
last;
}
}
if ( ! $file && $jobid == -1 )
{
print "No file or job specified. $usage";
exit;
}
if ( $noexec )
{ print "NoExecute mode. No transcoding or SQL database changes.\n" }
# ============================================================================
# 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;
#print "$d/$file exists\n";
last
}
else
{ print "$d/$file does not exist\n" }
}
if ( ! $dir )
{ Die "Cannot find recording" }
# ============================================================================
# First, generate a new filename,
# by adding one second to the starttime until we get a unique one
#
my ($year,$month,$day,$hour,$mins,$secs) = split m/[- :]/, $starttime;
my $oldShortTime = sprintf "%04d%02d%02d%02d%02d%02d",
$year, $month, $day, $hour, $mins, $secs;
do
{
$secs ++;
if ( $secs > 59 )
{ $secs -= 60, $mins ++ }
if ( $mins > 59 )
{ $mins -= 60, $hour ++ }
if ( $hour > 23 )
{ Die "Cannot generate a new file" }
$newstarttime = sprintf "%04d-%02d-%02d %02d:%02d:%02d",
$year, $month, $day, $hour, $mins, $secs;
my $newShrtTm = sprintf "%04d%02d%02d%02d%02d%02d",
$year, $month, $day, $hour, $mins, $secs;
$newfilename = $file;
$newfilename =~ s/_$oldShortTime/_$newShrtTm/;
} while ( -e "$dir/$newfilename" );
$DEBUG && print "$dir/$newfilename seems unique\n";
# ============================================================================
# Second, do the transcode, obeying the cutlist if there is one
#
$query = $db->prepare("SELECT cutlist FROM recorded $whereChanAndStarttime;");
$query->execute || Die "Unable to query recorded table";
my ($cutlist) = $query->fetchrow_array;
$ref = $query->fetchrow_hashref;
$query->finish;
$command = "mythtranscode -c $chanid -s '$starttime' -m --outfile $newfilename";
if ($cutlist)
{ $command .= ' --honorcutlist' }
if ( @ARGV )
{ $command .= ' ' . join(' ', @ARGV) }
if ( $DEBUG || $noexec )
{ print "# $command\n" }
if ( ! $noexec )
{
chdir $dir;
system $command;
if ( ! -e "$dir/$newfilename" )
{ Die "Transcode failed\n" }
# Insert the generated position map into the recorded markup table.
# File has a structure like this:
#
#Type: 9
#0 14
#12 380942
#
open(MAP, "$newfilename.map") || Die "Cannot find position map file";
my $type;
if ( <MAP> =~ m/^Type: (\d+)$/ )
{ $type = $1 }
else
{ Die "Position map file is incomplete" }
while ( <MAP> )
{
if ( m/^(\d+) (\d+)$/ )
{
$command = "INSERT INTO recordedseek" .
" (chanid,starttime,mark,offset,type)" .
" VALUES ($chanid,'$newstarttime',$1,$2,$type);";
# This outputs too many lines for normal debugging
#if ( $DEBUG || $noexec )
#{ print "# $command\n" }
if ( ! $noexec )
{
$db->do($command) ||
Die "Couldn't insert data into recordedmarkup"
}
}
else
{ Die "Position map file has bad data line" }
}
close MAP;
unlink "$newfilename.map" || Die "Cannot delete position map file";
}
# ============================================================================
# Last, copy the existing recorded details with the new file name.
#
$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 "$dir/$newfilename") . "\n";
}
$ref->{'filesize'} = -s "$dir/$newfilename";
my $extra = 'Copy';
if ( $cutlist )
{ $extra = 'Cut' }
if ( $ref->{'subtitle'} !~ m/$extra$/ )
{
if ( $ref->{'subtitle'} )
{ $ref->{'subtitle'} .= " - $extra" }
else
{ $ref->{'subtitle'} = $extra }
}
#
# 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" }
# ============================================================================
$db->disconnect;
1;
#!/usr/bin/env python
#
### User-Job-Command:
### /path/to/mythscp.py %CHANID% %STARTTIME%
import os, sys
import re
import dbus
import logging
import time
import pexpect
#------------------------------------------
#
#
log_path = "/var/log/mythtv/mythscp.log"
chanid = sys.argv[1]
starttime = sys.argv[2]
#
############### FUNKTIONEN ------------------------------
#----------- Zeitstempel erzeugen ---------------------------
def TimeStamp():
stamp = time.strftime("%Y%m%d", time.localtime())
return(stamp)
#-----------------------------------------------------------
#------- Log-File vorbereiten ---------------------------
# mehr Infos unter http://docs.python.org/library/logging.html
logging.basicConfig(filename=log_path,
level=logging.INFO,
format="%(asctime)s - %(levelname)s: %(message)s")
logger =logging.getLogger("")
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s - %(levelname)s: %(message)s")
ch.setFormatter(formatter)
logger.addHandler(ch)
#---------------------------------------------------------
#
#
######### HIER GEHTZ LOS ---------------------------------
logger.info("[%s]: Skript gestartet" % (TimeStamp()))
#logger.debug("Debugmeldung")
#logger.warning("Warnmeldung")
#os.system('enter your bash command here')
befehl = "/usr/share/doc/mythtv-backend/contrib/user_jobs/mythlink.pl --link /media/MYTH/tmp --chanid %s --starttime %s --format '%%Y%%m%%d%%H%%i%%s-%%c-%%T-%%S'" % (chanid,starttime)
os.system(befehl)
#--- Hole Datum, da die Videodatei so anfaengt
stamp = TimeStamp();
myvideo = "%s-%s" % (starttime,chanid)
befehl = "/bin/bash -c 'scp /media/MYTH/tmp/%s* [email protected]:Downloads/'" % (myvideo)
#befehl = "scp [email protected]:/hdd/movie/%s* /home/produnis/Downloads/" % ("10-12-19")
logger.info("Dateien starten mit %s" % (stamp))
logger.info("Verwende Befehl %s" % (befehl))
#
#
child = pexpect.spawn (befehl)
#child.expect ('.*yes*')
#child.sendline ('yes')
child.expect ('.*password:*')
child.sendline ('hansch')
child.expect(pexpect.EOF, timeout=7200)
#print str(child) # Debugging
#print "Ende"
#!/bin/sh
##### Commercial Remover Script for MythTV, updated 5/14/12
###
## Version Changes to mythutil and mythcommflag tools under MythTV 0.25
## necessitate different commands within the script. (Under MythTV < 0.25 you could
## just point mythcommflag at the recordings in the file system and get the job done, now
## under MythTV 0.25 you have to use mythutil to generate the cutlist and mythcommflag to
## flag commercials, AND point both at recordings based on %CHANID% and %STARTTIME%. Under
## MythTV 0.25 mythtranscode can also be pointed at %CHANID% and %STARTTIME% but since it
## currently supports the older infile /outfile method as well (and I prefer how this
## script creates old/new files, it is the method used.
##
## Since this script requires the User Job to pass additional arguments under MythTV 0.25,
## use following User Job syntax for userjobs under all versions:
##
## 'commercialremover.sh %DIR% %FILE% %CHANID% %STARTTIME%'
##
## Credits: Zwhite, Ricks03, Waxrat @ www.mythtv.org/wiki
###
#####
VIDEODIR=$1 #MythTV-024 %DIR%
FILENAME=$2 #MythTV-024 %FILE%
CHAN=$3 #REQUIRED FOR MythTV-025 %CHANID%
START=$4 #REQUIRED FOR MythTV-025 %STARTTIME%
# Sanity checking, to make sure everything is in order. Modified to check $CHAN and $START for MythTV 0.25 Support
if [ -z "$VIDEODIR" -o -z "$FILENAME" -o -z "$CHAN" -o -z "$START"]; then
echo "Usage: $0 <VideoDirectory> <FileName>"
exit 5
fi
if [ ! -f "$VIDEODIR/$FILENAME" ]; then
echo "File does not exist: $VIDEODIR/$FILENAME"
exit 6
fi
# The meat of the script. Flag commercials, copy the flagged commercials to
# the cutlist, and transcode the video to remove the commercials from the
# file.
echo "Flagging Commercials..."
##### - UNCOMMENT FOLLOWING LINE IF RUNNING MythTV Version <= 0.24
#mythcommflag -f $VIDEODIR/$FILENAME
##### - UNCOMMENT FOLLOWING LINE IF RUNNING MythTV Version >= 0.25
mythcommflag --chanid $CHAN --starttime $START
ERROR=$?
if [ $ERROR -gt 126 ]; then
echo "Commercial flagging failed for ${FILENAME} with error $ERROR"
exit $ERROR
fi
echo "Generating cutlist..."
##### - UNCOMMENT FOLLOWING LINE IF RUNNING MythTV Version <= 0.24
#mythcommflag --gencutlist -f $VIDEODIR/$FILENAME
##### - UNCOMMENT FOLLOWING LINE IF RUNNING MythTV Version >= 0.25
mythutil --gencutlist --chanid $CHAN --starttime $START
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "Copying cutlist failed for ${FILENAME} with error $ERROR"
exit $ERROR
fi
echo "Transcoding..."
mythtranscode --honorcutlist --showprogress -i $VIDEODIR/$FILENAME -o $VIDEODIR/$FILENAME.tmp
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "Transcoding failed for ${FILENAME} with error $ERROR"
exit $ERROR
fi
mv $VIDEODIR/$FILENAME $VIDEODIR/$FILENAME.old
mv $VIDEODIR/$FILENAME.tmp $VIDEODIR/$FILENAME
echo "Rebuilding..."
##### - UNCOMMENT FOLLOWING LINE IF RUNNING MythTV Version <= 0.24
#mythcommflag -f $VIDEODIR/${FILENAME} --rebuild
##### - UNCOMMENT FOLLOWING LINE IF RUNNING MythTV Version >= 0.25
mythcommflag --chanid $CHAN --starttime $START --rebuild
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "Rebuilding seek list failed for ${FILENAME} with error $ERROR"
exit $ERROR
fi
echo "Clearing cutlist..."
##### - UNCOMMENT FOLLOWING LINE IF RUNNING MythTV Version <= 0.24
#mythcommflag --clearcutlist -f $VIDEODIR/$FILENAME
##### - UNCOMMENT FOLLOWING LINE IF RUNNING MythTV Version >= 0.25
mythutil --clearcutlist --chanid $CHAN --starttime $START
ERROR=$?
if [ $ERROR -eq 0 ]; then
# Fix the database entry for the file
##### - Note: MAY need to add mysql mythconverg DB credentials '--user=<blah> --password=<blah>'
## to the 'mysql mythconverg' command below.)
# Fix the database entry for the file
cat << EOF | mysql mythconverg
UPDATE
recorded
SET
cutlist = 0,
filesize = $(ls -l $VIDEODIR/$FILENAME | awk '{print $5}')
WHERE
basename = '$FILENAME';
DELETE FROM
`recordedmarkup`
WHERE
CONCAT( chanid, starttime ) IN (
SELECT
CONCAT( chanid, starttime )
FROM
recorded
WHERE
basename = '$FILENAME'
);
EOF
exit 0
else
echo "Clearing cutlist failed for ${FILENAME} with error $ERROR"
rm -f $VIDEODIR/$FILENAME.tmp
exit $ERROR
fi
(END)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment