#!/bin/bash
#
# /usr/local/bin/channel
#
# Script to record analog television programs to .avi files, using mencoder, and
# the associated closed captioning in a separate identically named .txt file
#
# You need to include /usr/local/bin in cron's PATH (see kcron's Variables)
# Use the bash interpreter -- /bin/bash, not /bin/sh
#
# Usage: channel <channel number> <duration> <title> <capture card number>
#
# For instance,
#
#       channel 28, 30min, "BBC World News", 1
#
# Input parameter rules:
#    * commas are optional
#    * give duration (recording time) in minutes 
#    * the word "min" (for minutes) is optional
#    * a space signals a new parameter
#    * enclose multi-word titles in quotes
#    * don't use apostrophes in titles -- messes up searching of captured text
#    * the default card number is 1
#
# Changelog
#    2005-01-12: added $! to terminate ntsc-cc and channel-timestamp
#    2005-04-15: added $DEV input parameter to handle multiple tv cards
#    2005-04-23: added aumix -d /dev/mixer1 -1 R for sound off the saa
#    2005-05-13: added mixer device number 
#    2005-05-16: new directories are created with 775
#    2005-05-22: added busy test
#    2005-10-07: use zvbi-ntsc-cc, soon in libzvbi 0.2.17
#    2006-02-15: removed colon from filename (FIL=)
#    2006-08-18: added drive assignment routine (checks for space)
#    2006-09-04: switched from oss to alsa (2.6.17 kernel)
#    2006-09-14: check /dev/vbi$DEV instead of /dev/dsp$DEV in busy loop
#                (you could use /dev/video$DEV)
#    2006-09-20: added some messages at the end, using 24-hour time
#    2006-09-24: added XDS information to closed captioning
#
# ***************************************************************************

# First some checks triggered by manual mode

if [ "$1" = "" ] ; then
 echo "Use news <channel number> <recording time in minutes>";
 echo "Please give a channel! Valid channels are 2, 4, 5, 7, 9, 11, 13, and 28.";
 exit
fi

if [ "$2" = "" ] ; then
 echo "Use news <channel number> <recording time in minutes>";
 echo "Please give a recording length in minutes!";
 exit
fi

if [ "$3" = "" ] ; then
 echo "Use news <number> <duration> <title>";
 echo "Please give a title to the recording!";
 exit
fi

# Define the video and VBI (vertical blanking interval) device to use
# Default is /dev/video1 and /dev/vbi1
if [ "$4" = "" ] ;
 then DEV=1
 else DEV=$4
fi

# Define variable DRV to contain the first tv drive with more than 1% free
for i in $(df | cut -d'/' -f4 | grep tv | sort); do
  if [ "$(df /$i | grep $i | cut -b 52-54)" -lt 99 ]
      then DRV=$i
      echo "Using drive" $DRV "with" "$(df -h /$i | grep $i | cut -b 35-37)GB free"
      break
  fi
done

# Define variable DIR to contain nested directories for
#  yyyy, yyyy-mm, and yyyy-mm-dd (today's date)
DIR=/$DRV/$(date +%Y)/$(date +%Y-%m)/$(date +%F)

# Create the directory (and any missing parents) if needed
if test ! -d $DIR
  then mkdir -p -m 775 $DIR
fi

# Strip the comma, if any, from the channel name
CH=${1%,*}

# Set the channel (current user needs X11 access)
# You can also set this in mencoder with tv://$CH or channel=$CH
v4lctl -c /dev/video$DEV setchannel $CH

# Convert channel number to name for the base file name
case $CH in
  2) CH=KCBS;;
  4) CH=KNBC;;
  5) CH=KTLA-WB;;
  7) CH=KABC;;
  9) CH=KCAL;;
 11) CH=KTTV-FOX;;
 13) CH=KCOP-UPN;;
 28) CH=KCET;;
esac

# Strip the {min,|min|,} if it's there, from the duration
TIM=${2%m*}; TIM=${TIM%,*}

# Strip the comma, if any, from the title, and convert spaces to underscores
TIT=_`echo ${3%,*} | sed -e "s/ /_/g"`

# Define the file name (escape underscore before $) and print it to screen
FIL=$(date +%F_%H%M)\_$CH$TIT; echo Preparing to record $FIL

# Check if the capture device is busy
BUSY="Capture card $DEV is busy -- will try for another five minutes \n"
START=$(date +%s); TARGET=$[$START + $[5*60]]

while [ "$(sudo lsof /dev/vbi$DEV)" != "" ]; do
  if [ $TARGET -gt $(date +%s) ]
    then echo -ne $BUSY
      sleep 5; BUSY=""
    else echo "Recording of $FIL aborted -- capture card $DEV is not available"
      exit
  fi
done

# Convert minutes to seconds and adjust down five seconds for the hardware to reset
TIM=$[$[TIM*60]-5]

# Adjust the duration down by the delay added by the busy check, exit if no time left
TIM=$[TIM-$[$(date +%s) -$START]]; if [ $TIM -lt 1 ]; then exit; fi

# Start the timestamp script and background
channel-timestamp $CH $TIT $DIR $FIL &

# Get the PID for the timestamper
TMSP=$!

# Start cc capture and background the process
zvbi-ntsc-cc -d /dev/vbi$DEV -cpx >> $DIR/$FIL.txt &

# Get the PID for the closed captioning
NTSC=$!

# Restore default sound sttings and open up the sound channel on the capture card 
/usr/sbin/alsactl restore $DEV

# Set any additional values (none currently needed)
#v4lctl -c /dev/video0 color "50%"

# Record the footage (note this assumes direct audio)

# Use this to control the bitrate -- default is 800
#lavc -lavcopts vbitrate=1800 -oac mp3lame -lameopts cbr:br=128 -endpos $TIM -o \

echo "Initiating recording of $FIL from channel $1"
echo "on capture card $DEV, at $(date +%T), duration $TIM seconds"

mencoder -tv driver=v4l2:device=/dev/video$DEV:fps=30000/1001:chanlist=us-bcast:\
audiorate=32000:adevice=hw.$DEV:alsa:input=0:amode=1:normid=4 -ffourcc DIVX -ovc \
lavc -oac mp3lame -lameopts cbr:br=128 -endpos $TIM -o $DIR/$FIL.avi tv:// > /dev/null

# Stamp the file with receipts to verify capture success
echo -e "\n"
ls -l $DIR/$FIL.*
echo -e "\nCompleted capture on $(date +%A\ %d\ %B\ %Y) at $(date +%T)"
echo -e "Video and audio   file size" $(ls -sh $DIR/$FIL.avi | cut -d' ' -f1)
echo -e "Closed captioning file size" $(ls -sh $DIR/$FIL.txt | cut -d' ' -f1) "\n"

# Terminate the closed captioning and the timestamper
kill $NTSC $TMSP

# EOF
