#!/bin/bash

alerter=YOURHOSTNAMEHERE

### This is a handler called by notice-new-files-dispatcher.

### This is what actually ties everything together---it runs $1
### through the EAS detector, and sends a notification if it finds one.
### A later version might attempt to automatically reschedule as well.

### If the optional $2 is supplied, we'll use that instead of eas-notify if we find an alert.
### This allows running this over an entire preexisting corpus to accumulate results, without
### being intrusive.  "cat" would be a good choice here.  Note also that a custom alerter
### means we -don't- log to PERMLOG!  If that's what you want, your custom alerter should
### take care to do so.  Since the general idea for custom alerters is for debugging or
### doing mass runs over large corpuses to enable same, polluting the actual log that gets
### written into by the production system seems like a bad idea.

### If the optional $3 is supplied, we'll use that, and not pcm-tail-follow, to actually do
### the work of scanning the input.  This allows, for example, using something that expects
### precomputed raw PCM files directly (without running mplayer over them) and that calls
### eas-detect (possibly with extra args) directly on them---this allows rapidly debugging
### tweaks to eas-detect over a large corpus without all the overhead of repeatedly rerunning
### mplayer to regenerate the PCM input that eas-detect expects.  Like $2, this is expected
### to be mainly useful for debugging.

### Any extra args after $3 will be passed to $3 as args, -after- its inputfile and log args.
### The idea is to use these as args to eas-detect, which is what pcm-eas-raw does.

## We roll our own version of descriptive-name.pl with one that pulls from program, and not
## oldrecorded, precisely because we expect it will often be run to report on an -in-progress-
## recording, which oldrecorded can't know about yet.  Unfortunately, at least in mythtv 0.18,
## recorded doesn't have the pre/postroll offsets in its keys (and hence the insertion almost
## always just fails), and we can't look for the showing in program in a straightforward manner,
## because program (of course) won't have the pre/postrolls, either.  So instead, we do something
## truly pukeworthy (really, don't read farther if you don't want to barf on your shoes!), which
## is to keep asking with ever increasing fuzziness around the starttime until we either get a
## response, or we exceed even -our- boundless patience with kluges.  This will work so long as
## the amount of preroll isn't too horribly large; if it fails, then we don't get a descriptive
## name, but at least the rest of the alert is logged.  (If we're trying to do real rescheduling,
## this will probably have to be made better, but by then, maybe we'll be using a more-recent myth,
## and maybe that more-recent myth will handle the damned record table better in the presence
## of padding!)  Note carefully that we both add -and- subtract possible preroll amounts, since
## it's possible that a showing will have a negative preroll---this is quite rare, but -does-
## happen if I'm short on tuners and know that some particular channel always starts late (or
## really don't care about the first minute of something).  This will definitely fail if there
## are back-to-back recordings with the same chanid whose actual lengths are shorter than the
## preroll applied, but hopefully that's really rare, if not unheard-of, right?

## (Note that we don't actually call out to any version of descriptive-name.pl, even one with
## a different table in it, since it does lots of work [such as making all shellmetas safe)
## that we don't need here.)

## Definitions.  We won't need these unless we do an alert, which should be rare, but it takes
## virtually no runtime to define them, so we'll put 'em here where they're easy to find.

# +++ Public:  stolen from .aliases 'cause that file won't be on the backend.
dbhost=mb
dbuser=mythtv
dbpass=mythtv
dbargs="-h $dbhost -u${dbuser} -p${dbpass} mythconverg"

inmysql() { mysql -s -B $dbargs "$@" ; }
domysql() { inmysql --exec "$@" ; }
# ---

# +++ Private to this file.
PERMLOG=/myth/DEBUG/EAS

fuzziness=10			# Minutes.

filename-to-fuzzy-db-key() { echo "$1" | sed -r -e "s#.*/##g" -e "s/([0-9]+)_([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2}).*/chanid = '\1' AND starttime <= ('\2-\3-\4 \5:\6:\7' + interval $2 minute) AND starttime >= ('\2-\3-\4 \5:\6:\7' - interval $2 minute) /g" -; }

showpretty--table()       { domysql "SELECT title, subtitle FROM $1 WHERE `filename-to-fuzzy-db-key $2 $3`" 2>&1 | grep -iv "no result" | sed -e "s/\t/::/g"; }
showpretty--program()     { showpretty--table program     $1 $2; }
showpretty--oldrecorded() { showpretty--table oldrecorded $1 $2; }

# ---

## Now actually do some work.

input=$1;    shift
alerter=$1;  shift
detector=$1; shift

tmp=/dev/shm
log=$tmp/`basename $input`.$$.log		# Theoretically unnecessary, but if we happen to someone be running two copies over the same inputs...
out=$tmp/`basename $input`.$$.out		# Ditto.

if [ "$detector" == "" ]; then
  pcm-tail-follow $input $log			# Use the normal mplayer->eas-detect pipeline.
  eas_status=$?					# Resist the temptation to put this line after the endif!  Then it'll always reflect the IF's status!
else
  $detector $input $log $@			# Use some custom detector pipeline.
  eas_status=$?					# Ditto.
fi

## If status is zero, we're done---no alert.  It's conceivable that eas-detect
## may have written some logging information, yet failed to declare an alert;
## this happens when we see a runt, for example.  So make sure to delete it again.
if [ "$eas_status" == 0 ]; then
  rm -f $log
  exit 0
fi

## Okay, we need to alert.  First, see if we can figure out the prettyname.  Gaak.

result=""
for i in `seq 0 $fuzziness`; do
  result="`showpretty--program $input $i`"
  if [ "$result" != "" ]; then
    ## Apparently, its starttime is not too fuzzy and we ran while it was still
    ## in the program table (e.g., within a week).  Fine.
    break
  fi
done

if [ "$result" == "" ]; then
  ## Apparently, it wasn't in the program table.  Maybe we're running on really old data somehow?
  ## Go look in oldrecorded, since it's gotta be done by now.
  result="`showpretty--oldrecorded $input 0`"
fi

if [ "$result" == "" ]; then
  ## -Still- nothing?  Punt.  We have -no- idea where this data came from,
  ## but don't let that inhibit us from issuing the alert!
  result="[Can't find program info]"
fi

## Yay!  We're ready to issue an alert!  Christ almighty.
      
infile=`basename $input`
echo -e "`date`\n" > $out
cat $log >> $out		# Done in this roundabout way to preserve newlines in $log.
echo -e "\n$infile\n\n$result" >> $out

## Note:  unfortunately, it's the -client's- job to loop on connection-refused,
## for whatever port it's using, if there's a significant chance that multiple
## alerts will arrive simultaneously.  For us, it's a virtual certainty if we're
## recording on multiple streams when the alert happens, since it happens
## simultaneously across many/all feeds and the detectors are all running
## in parallel at virtually the same wallclock position in that feed.

if [ "$alerter" == "" ]; then
  ## Use the standard alerter, which means we also make a permanent log entry,
  ## so we can try to deduce the most likely times/channels for alerts.  We do
  ## this first, since we might hang for an indeterminate time trying to issue
  ##  the popup alert,  especially if the receiving host is down!  (Hasn't
  ## happened yet, but there's always a first time...)
  echo -e "$infile\t\t`date`"  >> $PERMLOG
  echo -e "$infile\t\t$result" >> $PERMLOG
  sed -e '/^$/d' -e "s/.*/$infile\t\t&/" $log >> $PERMLOG
  echo "" >> $PERMLOG
  ## We must check & loop to avoid raciness talking to the popup.
  ## We redirect its output because nc will otherwise blat to
  ## stderr about connection-refused errors on each failing iteration.
  while [ 1 ]; do
    cat $out | nc -w 1 $alerter 56789 >> /dev/null 2>&1
    if [ $? == 0 ]; then
      break
    else
      sleep 1
    fi
  done
else
  ## Use a custom alerter, such as cat.  We don't check success or loop if
  ## we don't get it, and we -don't- redirect any output from the command,
  ## since such output is probably the point.  We also don't pollute the
  ## permanent log.
  $alerter < $out
fi

## Get rid of our temporary stuff.
rm -f $log $out

# End of file.
