#!/usr/bin/perl

#
# Simple script that joins on or more recordings to another
#
# by Merten Falk <neves-enin (at) gmx (dot) net>
#
# some parts of this script are from convert.pl
#
# by Thomas Koch <tom (at) linvdr (dot) org>
#

use Getopt::Std;
use strict;

my $TODO_LIST       = "/var/log/joinrec/joinrec.txt";
my $LOCK_FILE       = "/var/log/joinrec/joinrec_lock";
my $VDRCONFDIR      = "/vdr/etc";
my $VIDEODIR        = "/media/video0";

my $SVDRPSEND       = "/usr/bin/svdrpsend.pl MESG %s 2>/dev/null 1>/dev/null";
my $GENINDEX        = "/usr/local/bin/genindex";

my $version         = "0.3";

my @rec;
my $newrec;
my $lifetime;
my $priority;
my $maxfilesize;

my %args;

$SIG{INT} = \&RemoveLock;

#################################################

getopts("dhln:qr:", \%args);



if($args{l} and (keys(%args) == 1)) {
  if (Lock()){
    print("Auftrag aktiv!\n\n");
  }
  List();
  exit 0;
}

if($args{d} and (keys(%args) == 1)) {
  if (Lock()) {
    print("Der Auftrag ist bereits aktiv.\nListe kann nicht mehr gelöscht werden.");
    exit 1;
  }
  else {
    RemoveList();
    print("Liste wurde gelöscht.");
    exit 0;
  }
}

if($args{q} and (keys(%args) == 1)) {
  if(!Lock()) {
    ReadList();
    $rec[0] =~ /(.*\/.*)(\/\d\d\d\d-\d\d-\d\d\.\d\d[\:\.]\d\d.\d\d\.\d\d.rec)/;
    $newrec = $1 . "_new" . $2;
    if (Check(1)) {
      CreateLock();
      ReadSetup();
      JoinRec();
      RemoveList();
      RemoveLock();
      system(sprintf($SVDRPSEND, "Aufnahmen zusammenfügen beendet."));
    }
    else {
      exit 1;
    }
  }
  else {
    system(sprintf($SVDRPSEND, "Der Auftrag wird bereits bearbeitet."));
    exit 1;
  }
  exit 0;
}

if($args{r} and (keys(%args) == 1) and (split(/,/,$args{r}) == 1)) {
  if (!Lock()){
    open(FILE, ">>$TODO_LIST") || die "cant write $TODO_LIST ($!)";
    print FILE $args{r} . "\n";
    close FILE;
    print("Zur Liste hinzugefügt.");
    exit 0;
  }
  else {
    print("Es ist gerade ein Auftrag aktiv.\nBitte warten Sie, bis der Auftrag beendet ist.");
    exit 1;
  }
}

if($args{n} and (split(/,/,$args{r}) > 1)) {
  ReadSetup();
  my $cmd = "date +%Y-%m-%d.%H.%M";
  my $date = qx($cmd);
  chomp($date);
  $newrec = $VIDEODIR . "/" . $args{n} . "/" . $date . "." . $priority . "." . $lifetime . ".rec";
  @rec = split(/,/,$args{r});
  if (Check()) {
    JoinRec();
  }
  else {
    exit 1;
  }
  exit 0;
}

if(1){
  PrintUsage();
}

#################################################

sub ReadSetup{
open(FILE, $VDRCONFDIR . "/setup.conf");
while(<FILE>) {
  if (/^DefaultLifetime = (\d\d)/){
    $lifetime = $1;
  }
  elsif (/^DefaultPriority = (\d\d)/){
    $priority = $1;
  }
  elsif (/^MaxVideoFileSize = (\d+)/){
    $maxfilesize = $1 * 1024 * 1024;
  }
}
close(FILE);
}

sub PrintUsage {
  printf("joinrec Version %s 2006 Merten Falk.\n", $version);
  print("Simple script that joins on or more recordings to another\n\n");
  print("Usage: joinrec -[dhlq]\n");
  print("Usage: joinrec -r <Recording>\n");
  print("Usage: joinrec -n <name> -r <recording>,<recording>...\n");
  print("  -d  delete queue\n");
  print("  -l  list queue\n");
  print("  -q  run queue\n");
  print("  -n  name of new recording\n");
  print("  -r  add recording to queue\n");
  print("  -h  you are reading this\n\n");
  print("Report bugs to <neves-enin\@gmx.net>\n");
}

sub JoinRec {
  
  system('mkdir -p "'.$newrec.'"');
  
  for(my $i = 0; $i <= $#rec; $i++){
    if($i == 0) {
      system('cp -a "'.$rec[$i].'"/summary.vdr "'.$newrec.'"/') if (-e "$rec[$i]/summary.vdr");
      system('cp -a "'.$rec[$i].'"/info.vdr "'.$newrec.'"/') if (-e "$rec[$i]/info.vdr");
    }
    CopyVideoFiles("$rec[$i]", $newrec);
  }
#   system("cd $newrec && $GENINDEX");
  system("touch $VIDEODIR/.update");
}

sub Check {
  my $message = @_ ? shift : 0;
  my $total_size = 0;
  my $disk_space = 0;
  my $cmd;
  my $ret = 1;
  if (@rec == 0 ) {
    system(sprintf($SVDRPSEND, "Auftragsliste leer.")) if ($message);
    $ret = 0;
  }
  elsif (@rec == 1) {
    system(sprintf($SVDRPSEND, "Nur eine Aufnahme ausgewählt.")) if ($message);
    $ret = 0;
  }
  else {
    foreach (@rec) {
      if (!-d "$_") {
        /.*\/(.*)\/(\d\d\d\d)-(\d\d)-(\d\d)\.(\d\d)[\:\.](\d\d).\d\d\.\d\d.rec/;
        if ($message) {
          system(sprintf($SVDRPSEND, "$1 existiert nicht."));
        }
        else {
          print "$_ existiert nicht.\n";
        }
        $ret = 0;
        last;
      }
      $cmd = 'du "' . $_ . '" | awk {\'print $1\'}';
      $total_size += qx($cmd);
    }
    if($ret) {
      if(-d $newrec) {
        if ($message) {
          $newrec =~ /.*\/(.*)\/(\d\d\d\d)-(\d\d)-(\d\d)\.(\d\d)[\:\.](\d\d).\d\d\.\d\d.rec/;
          system(sprintf($SVDRPSEND, "$1 existiert bereits!"));
        }
        else {
          print "Aufnahme $newrec existiert bereits!\n";
        }
        $ret = 0;
      }
    }
    if($ret){
      my @testdir = split(/\//, $newrec);
      my $testdir = join("/", @testdir);
      while(!-d "/" . $testdir){
        pop(@testdir);
        $testdir = join("/", @testdir);
      }
      $cmd = 'df "' . $testdir . '" | grep -v Dateisystem | awk {\'print $4\'}';
      $disk_space = qx($cmd);
      if ($disk_space <= $total_size) {
        if ($message) {
          system(sprintf($SVDRPSEND, "Nicht genug Platz auf der Festplatte."));
        }
        else {
          print "Nicht genug Platz auf der Festplatte.\n";
        }
        $ret = 0;
      }
    }
  }
  return $ret;
}

sub ReadList {
  if(-s $TODO_LIST) {
    open(FILE, $TODO_LIST) || die "cant read $TODO_LIST ($!)";
    while(<FILE>) {
      chomp $_;
      push(@rec, $_);
    }
    close(FILE);
  }
}

sub RemoveList {
  unlink($TODO_LIST);
}

sub List {
  if(-s $TODO_LIST) {
    open(FILE, $TODO_LIST) || die "cant read $TODO_LIST ($!)";
    while(<FILE>) {
      $_ =~ /.*\/(.*)\/(\d\d\d\d)-(\d\d)-(\d\d)\.(\d\d)[\:\.](\d\d).\d\d\.\d\d.rec/;
      print sprintf("%s.%s.%s\n%s\n\n",
       $4,
       $3,
       $2,
       ListTranslate($1),
     );
    }
    close(FILE);
  }
  else {
    print "leer";
  }
}

sub ListTranslate {
  $_ = shift;
  s/_/ /g;
  return($_);
}

sub Lock {
  if(-e $LOCK_FILE) {
    return(1);
  } else {
    return(0);
  }
}

sub CreateLock {
  open(FILE, ">$LOCK_FILE") || die "can't write $LOCK_FILE ($!)\n";
  print FILE $$;
  close(FILE);
}

sub RemoveLock {
  unlink($LOCK_FILE);
}

sub CopyVideoFiles {
  my ($fromdir, $todir) = @_;
  my $offset;
  my $nextoffset;
  my $filetowrite = GetVideoFileToWrite($todir);
  my $filetoread;
  my @char;
  my $eof = 0;
  my $bytesread = 0;
  my $addsize;
  my $frame;
  my @marks;
  
  if (not -e "$fromdir/index.vdr") {
    system("cd $fromdir && $GENINDEX");
  }
  
  if (-e "$todir/$filetowrite") {
    $addsize = $maxfilesize - (-s "$todir/$filetowrite");
  }
  else {
    $addsize = $maxfilesize;
  }
  
  if (-e "$fromdir/marks.vdr") {
    open (MARKS, "$fromdir/marks.vdr");
    while(<MARKS>) {
      if ($_ =~ /^(\d:\d\d:\d\d\.\d\d)/) {
        push(@marks, HMSFtoFrames($1));
      }
    }
    close(MARKS);
  }
  
  open(INDEX, "$fromdir/index.vdr");
  for (my $i = 0; $i < 8; $i++) {
    $char[$i] = getc(INDEX);
  }
  $offset = hex(sprintf("%02X%02X%02X%02X", ord($char[3]), ord($char[2]), ord($char[1]), ord($char[0])));
  $filetoread = sprintf("%03d.vdr", hex(sprintf("%02X", ord($char[5]))));
  
  seek(INDEX, 0, 0);
  open(OUT, "$fromdir/$filetoread");
  open(IN, ">>$todir/$filetowrite");
  open(NEWINDEX, ">>$todir/index.vdr");
  
  while (!eof(INDEX)) {
    for(my $i = 0; $i < 16; $i++){
      if (eof(INDEX)) {
        $eof = 1;
        last;
      }
      $char[$i] = getc(INDEX);
    }
    
    foreach(@marks) {
      if($_ == tell(INDEX) / 8 - 2) {
        open(NEWMARKS, ">>$todir/marks.vdr");
        printf(NEWMARKS "%s\n", FramestoHMSF(tell(NEWINDEX) / 8));
        close(NEWMARKS);
      }
    }
    
    my $pos = tell(IN);
    (my $fileno) = $filetowrite =~ /(\d\d\d)\.vdr/;
    my $indexframe = chr(hex(substr(sprintf("%08X", $pos),6,2))) . chr(hex(substr(sprintf("%08X", $pos),4,2))) . chr(hex(substr(sprintf("%08X", $pos),2,2))) . chr(hex(substr(sprintf("%08X", $pos),0,2))) . $char[4] . chr($fileno) . $char[6] . $char[7];
    print NEWINDEX $indexframe;
    if ($eof) {
      seek(OUT, $offset, 0);
      read(OUT, $frame , (-s "$fromdir/$filetoread") - $offset);
      print IN $frame;
    }
    else {
      seek(INDEX, -8 , 1);
      $nextoffset = hex(sprintf("%02X%02X%02X%02X", ord($char[11]), ord($char[10]), ord($char[9]), ord($char[8])));
      if ($nextoffset < $offset) {
        seek(OUT, $offset, 0);
        $bytesread += read(OUT, $frame , (-s "$fromdir/$filetoread") - $offset);
        print IN $frame;
        close(OUT);
        $filetoread = sprintf("%03d.vdr", hex(sprintf("%02X", ord($char[13]))));
        open(OUT, "$fromdir/$filetoread");
      }
      else {
        seek(OUT, $offset, 0);
        $bytesread += read(OUT, $frame , $nextoffset - $offset);
        print IN $frame;
      }
      $offset = $nextoffset;
      
      if(($bytesread >= $addsize) and
      (((hex(sprintf("%02X", ord($char[12]))) == 1) and (hex(sprintf("%02X", ord($char[5]))) == hex(sprintf("%02X", ord($char[13]))))) or
      (hex(sprintf("%02X", ord($char[5]))) < hex(sprintf("%02X", ord($char[13])))))) {
        close(IN);
        $filetowrite = GetVideoFileToWrite($todir);
        open(IN, ">>$todir/$filetowrite");
        $addsize = $maxfilesize;
        $bytesread = 0;
      }
    }
  }
  close(IN);
  close(OUT);
  close(INDEX);
  close(NEWINDEX);
}

sub GetVideoFileToWrite {
  my $dir = shift;
  my @todirfiles;
  my $filetowrite;
  
  opendir(DIR, $dir);
  foreach (sort(readdir(DIR))) {
    push(@todirfiles, $_) if ($_ =~ /\d\d\d\.vdr/);
  }
  closedir(DIR);
  if($#todirfiles >= 0) {
    if ((-s "$dir/$todirfiles[-1]") >= $maxfilesize) {
      (my $oldno) = $todirfiles[-1] =~ /(\d\d\d)\.vdr/;
      $filetowrite = sprintf("%03d.vdr", $oldno + 1);
    }
    else {
      $filetowrite = $todirfiles[-1];
    }
  }
  else {
    $filetowrite = "001.vdr";
  }
  
  return $filetowrite;
}

####
#### HMSFtoFrames and FramestoHMSF adapted from vdr/recording.c
####

sub HMSFtoFrames {
  my $HMSF = shift;
  $HMSF =~ /^(\d):(\d\d):(\d\d)\.(\d\d)/;
  return ($1 * 3600 + $2 * 60 + $3) * 25 + $4 - 1;
}

sub FramestoHMSF {
  my $frames = shift;
  my ($H, $M, $S, $F);
  $F = ($frames % 25) + 1;
  $S = ($frames / 25);
  $M = $S / 60 % 60;
  $H = $S / 3600;
  $S %= 60;
  return sprintf("%d:%02d:%02d.%02d", $H, $M, $S, $F);
}

