#!/bin/bash
#set -n		# read but do not execute commands (check on syntax errors)
#
# File: /usr/local/bin/mediatxt2video
#
# create a text-overlayed video.
#
#    Copyright (C) 2019  Juergen Kaesmann (JK)
#
##############################################################################
# GPL NOTICE
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
##############################################################################
# FIND SAMPLES
#
##############################################################################
# FILTER SAMPLES
#
##############################################################################
# AWK SAMPLES
#
##############################################################################
# SED SAMPLES
#
##############################################################################
# RSYNC OPTIONS
#
##############################################################################
# DIALOG SAMPLES
#
##############################################################################
# REPLACE STRINGS
#
##############################################################################
# EXIT CODES

##############################################################################
# SOURCE FILES
#
. /usr/local/etc/main.conf				# config main
#. $LLIBDIR/libfuncerr-sh				# functions error
. $LLIBDIR/libfuncstd-sh				# functions standard
#. $LLIBDIR/libfuncmath-sh				# functions math
#. $LLIBDIR/libfuncip-sh				# functions IP
#. /usr/local/etc/sample.conf				# config sample

#if [ ! -e ~/.samplerc ]; then				# install config user
#	cp /usr/local/share/ksm-sample/samplerc ~/.samplerc
#	echo "Please configure your ~/.samplerc"
#	exit 1
#fi
#. ~/.samplerc						# config user

##############################################################################
# DECLARATION OF STANDARD CONSTANTS AND VARIABLES
#
readonly package=Multimedia				# package name
readonly package_file=ksm-multimedia			# package file name
readonly vinfopath="/usr/local/share/$package_file"	# path to package dir
readonly version=$(/bin/cat $vinfopath/VERSION)		# package version
readonly release=$(/bin/cat $vinfopath/RELEASE)		# package release
readonly scriptname=$(basename $0)			# name of script
readonly tempfile=$TEMPDIR/$scriptname.$UID.tmp		# temporary file name
#tempfile=$(mktemp $TEMPDIR/$scriptname.$UID.XXXXXX)	# temporary file name
#readonly lockfile=$TEMPDIR/lock/$scriptname.$UID.lock	# lock file name
readonly debuglog="/usr/bin/logger -p user.debug -t $scriptname -- DEBUG:"	# log dbg msg
readonly errlog="/usr/bin/logger -p user.err -t $scriptname -- ERROR:"		# log err msg
readonly infolog="/usr/bin/logger -p user.info -t $scriptname -- INFO:"		# log inf msg
cmd=''							# sub command
debug=no						# debug=yes/no
verbose=''						# verbose=yes/''/no
err=${_ERR_OK_}						# error code

##############################################################################
# USER FILL IN AT FIRST RUN

##############################################################################
# SYSTEM

##############################################################################
# USER-CONSTANTS

##############################################################################
# USER-VARIABLES
#
# STRINGS
prefix="$TEMPDIR/$scriptname.${UID}.nr." # prefix for splitted text file parts
definf="/usr/local/share/ksm-multimedia/white.mp4"

#args=''				# all args from cmdline
arg1=''					# 1. arg from cmdline
arg2=''					# 2. arg from cmdline
#opt_o=''				# option -o (yes)
					# option --output (yes)
#opt_i=''				# option -i (arg)
					# option --infile (arg)
#opt_o=''				# option -o (arg)
					# option --outfile (arg)
#opt_p=''				# option -p (arg)
					# option --pages (arg)
opt_t=''				# option -t (arg)
infile=''
outfile=''
txtfile=''
s=''

# NUMBERS
#p_first=0				# first page
#p_last=0				# last page

# ARRAYS
# Indexed arrays are always zero based string arrays.
# If index starts with 1 and all members are assigned then
# count of members of array = last index of array
#declare -a arr
#maxarr="${#arr[@]}"			# get number of elements in arr
#unset arr[@]				# remove the entire array

##############################################################################
# SIGNAL HANDLING

##############################################################################
# FUNCTIONS
##############################################################################
#
##############################################################################
# HELP
#
#=============================================================================
function helptext ()
{
# Output helptext
# Uses cat, echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG helptext: $# $@" >&2
	$debuglog helptext: $# $@
fi

cat <<EOT
NAME
$scriptname - Create a text-overlayed video.

SYNOPSIS
$scriptname [options] [txtfile video]

DESCRIPTION
Create a text-overlayed video. The video should have a duration of some
secs, f.i. 10 secs. A default video is supplied with the package. If
the resolution of the video is (720 x 576) then the text should have a
max. of 40 lines and 80 columns to fit on one video page. Longer
textfiles are splitted into parts of 40 lines. They all go into the
video.

A text with 120 lines in the text file will produce a video with a
duration of 30 secs (3 parts with 10 secs. each part).

Defaults:  Split longer text to chuncs of 40 lines.

OPTIONS
Gnu style options:

  -h|--help    = Output help, then exit.
  -V|--version = Output version info, then exit.
  -d|--debug   = Turn on DEBUG mode.
  -q|--quiet   = Be quiet.
  -v|--verbose = Be verbose.
  -t templ     = The video template for creation. This video should
                 have a solid coloured white background. The time
                 should be 10 secs. (def. TEMPLATE).
  --           = End of options.

ARGUMENTS
Give if needed:

  txtfile = The file containing the text.
  video   = The video with the text.

EXIT STATUS
On program exit:

  Code 0 = OK

  See output of 'showerrmsg'.

FILES
Used directories and files:

  Config Global = /usr/local/etc/multimedia.conf
  Config User   = ~/.multimediarc
  TEMPLATE      = $definf

SEE ALSO
Related manpages:

  showerrmsg(1), ffmpeg(1), mediaconcat(1).

AUTHORS
Juergen Kaesmann <juergen@kaesmann-online.de>
EOT
#  -o|--output  = Output to STDOUT.
#  -i f         = Input from file <f>.
#  --infile=f   = Input from file <f>.
#  -o f         = Output to file <f>.
#  --outfile=f  = Output to file <f>.
#  -p s,e       = Pages s=START e=END.
#  --pages=s,e  = Pages s=START e=END.

#EXAMPLES
#For instance:
#
#  Do it:
#  $scriptname

return
}

#=============================================================================
function tab2spaces_textfile ()
{
# Split the textfile into parts.
# par1 = 

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG tab2spaces_textfile: $# $@" >&2
	$debuglog tab2spaces_textfile: $# $@
fi

local ret=0

# split textfile to {prefix}00 - {prefix}nn
if [ "$debug" == "yes" ]; then				# DEBUG
	$debuglog "tab2spaces_textfile: cat $txtfile | pr -t -e \> $tempfile"
fi
case "$verbose" in
    yes)
	echo "Make Tabs to Spaces $txtfile"
	;;
    '')
	echo "Make Tabs to Spaces"
	;;
    no)
	#echo "Make Tabs to Spaces $txtfile"
	;;
esac
if [ -e "$txtfile" ]; then
	cat $txtfile | pr -t -e > $tempfile
	ret=$?
	if [ "$ret" -ne 0 ]; then
		if [ "$verbose" != no ]; then
			echo "${ErrMsg[1]} in tab2spaces_textfile!" >&2
		else
			$errlog ${ErrMsg[1]} in tab2spaces_textfile!
		fi
	fi
else
	if [ "$verbose" != no ]; then
		echo "${ErrMsg[5]} - $txtfile" >&2
	else
		$errlog ${ErrMsg[5]} - $txtfile
	fi
	ret=5
fi

return $ret
}

#=============================================================================
function split_textfile ()
{
# Split the textfile into parts.
# par1 = 

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG split_textfile: $# $@" >&2
	$debuglog split_textfile: $# $@
fi

local ret=0

# split textfile to {prefix}00 - {prefix}nn
if [ "$debug" == "yes" ]; then				# DEBUG
	$debuglog split_textfile: split -d -l 40 $tempfile ${prefix}
fi
case "$verbose" in
    yes)
	echo "Split Textfile $txtfile"
	;;
    '')
	echo "Split Textfile"
	;;
    no)
	#echo "Split Textfile $txtfile"
	;;
esac

split -d -l 40 $tempfile ${prefix}
ret=$?
if [ "$ret" -ne 0 ]; then
	if [ "$verbose" != no ]; then
		echo "${ErrMsg[1]} from split!" >&2
	else
		$errlog ${ErrMsg[1]} from split!
	fi
fi

return $ret
}

#=============================================================================
function create_text_videos ()
{
# Create a video from each text part.
# par1 = 

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG create_text_videos: $# $@" >&2
	$debuglog create_text_videos: $# $@
fi

local i=0 nn=0 ret=0

# for each splitter create text video
# get maxn
bakoutf=$outfile
maxn=$(ls ${prefix}* | grep -c ^${prefix})		# range maxn= 1 - maxn
if [ "$debug" == "yes" ]; then				# DEBUG
	$debuglog create_text_videos: max. text splitter=$maxn
fi
i=0
while [ "$ret" -eq 0 ] && [ $i -lt $maxn ]; do		# i= 0 - maxn-1
	nn=$i
	if [ "$i" -lt 10 ]; then			# make nn 2 digits
		nn="0$i"
	fi
	txtfile="${prefix}${nn}"
	outfile="${prefix}${nn}.mp4"
	if [ "$debug" == "yes" ]; then			# DEBUG
		$debuglog create_text_videos: outfile=$outfile
	fi
	mainproc					# create {prefix}nn.mp4
	ret=$?
	let ++i
done
outfile=$bakoutf

return $ret
}

#=============================================================================
function concat_text_videos ()
{
# Concatenate the video parts.
# par1 = 

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG concat_text_videos: $# $@" >&2
	$debuglog concat_text_videos: $# $@
fi

local s=''
local i=0 nn=0 ret=0

# build list of all splitter.mp4
i=0
while [ $i -lt $maxn ]; do				# i= 0 - maxn-1
	if [ "$i" -ge 0 ]; then
		nn=$i
		if [ "$i" -lt 10 ]; then		# make nn 2 digits
			nn="0$i"
		fi
		s="$s ${prefix}${nn}.mp4"		# build list
	fi
	let ++i
done

# concat all splitter.mp4 from list to outfile
if [ $i -gt 1 ]; then					# min 2 splitter found
	if [ "$debug" == "yes" ]; then		# DEBUG
		$debuglog concat_text_videos: mediaconcat -o $outfile $s
	fi
	case "$verbose" in
	    yes)
		echo "Concat Textvideo splitter to $outfile"
		mediaconcat -v -o $outfile $s
		ret=$?
		;;
	    '')
		echo "Concat Textvideo splitter"
		mediaconcat -o $outfile $s
		ret=$?
		;;
	    no)
		#echo "Concat Textvideo splitter to $outfile"
		mediaconcat -q -o $outfile $s
		ret=$?
		;;
	esac
	if [ "$ret" -ne 0 ]; then
		if [ "$verbose" != no ]; then
			echo "${ErrMsg[$ret]} from mediaconcat!" >&2
		else
			$errlog ${ErrMsg[$ret]} from mediaconcat!
		fi
	fi
else							# only 1 splitter found
	cp $s $outfile
	ret=$?
fi

return $ret
}

#=============================================================================
function clean_up ()
{
# Rm temporary files.
# par1 = 

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG clean_up: $# $@" >&2
	$debuglog clean_up: $# $@
fi

local ret=0

rm -f $tempfile
rm -f ${prefix}*
ret=$?

return $ret
}

#=============================================================================
function mainproc ()
{
# Create text-overlayed video.
# par1 = 
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG mainproc: $# $@" >&2
	$debuglog mainproc: $# $@
fi

local ret=0
#local -a arr
#maxarr="${#arr[@]}"			# get number of elements in arr
#unset arr[@]				# remove the entire array

# use a box
# insert text from textfile, boxcolor 0.5 controls the opacity
#ffmpeg -hide_banner -i $infile -vf drawtext="fontfile=/usr/share/fonts/truetype/DejaVuSansMono.ttf: textfile=$txtfile: fontsize=13: fontcolor=black: box=1: boxcolor=white@0.5: boxborderw=5: x=(w-text_w)/2: y=(h-text_h)/2" -acodec aac $outfile

# insert text from textfile without box, direct to the screen
case "$verbose" in
    yes)					# allow STDOUT and STDERR
	echo "Run $scriptname"
	ffmpeg -i $infile -vf drawtext="fontfile=/usr/share/fonts/truetype/DejaVuSansMono.ttf: fontsize=13: fontcolor=black: textfile=$txtfile:" -acodec aac $outfile
	ret=$?
	;;
    '')						# suppress STDOUT or STDERR
	#echo "Run $scriptname"
	ffmpeg -hide_banner -i $infile -vf drawtext="fontfile=/usr/share/fonts/truetype/DejaVuSansMono.ttf: fontsize=13: fontcolor=black: textfile=$txtfile:" -acodec aac $outfile 2>/dev/null
	#1>/dev/null
	ret=$?
	;;
    no)						# suppress STDOUT and STDERR
	ffmpeg -hide_banner -y -i $infile -vf drawtext="fontfile=/usr/share/fonts/truetype/DejaVuSansMono.ttf: fontsize=13: fontcolor=black: textfile=$txtfile:" -acodec aac $outfile &>/dev/null
	ret=$?
	;;
esac

if [ "$ret" -ne 0 ]; then
	if [ "$verbose" != no ]; then
		echo "${ErrMsg[1]} $ret from ffmpeg!" >&2
	else
		$errlog ${ErrMsg[1]} $ret from ffmpeg!
	fi
fi

# create h264 video 1 color
#ffmpeg -hide_banner -f lavfi -i color=white:720x576:d=10 -vcodec h264 outfile.mp4
#ret=$?

return $ret
}

##############################################################################
# GET OPTIONS
##############################################################################
# Give 2 strings and all cmdline_args to function GetOpt
# (POSIX_options Gnu_long_options cmdline_args):
# GetOpt 'hVdqvi:m:' 'help version debug quiet verbose infile= myval=' $@
#
# A ':' after a POSIX option means this option needs an arg.
# A '=' after a Gnu long option means this option needs an arg.
#
# All cmd/options have to be initialised to ''!
#
# POSIX options are classified in 2 categories:
#   a) cmds (mutually exclusive). All cmds are given to var 'cmd'.
#   b) options (as many as you like). Each option is given to it's own var.
# As a general rule: If cmds/options are given multiple then last given wins.
#
# Options can take 1 argument (no whitespace in arg). If you want to give more
# than 1 arg or want to use multiple strings as 1 arg then concatenate them
# together with ',' as delimiter:
# sampleprog -m val1,val2
# sampleprog --myval=val1,val2
# It's at the programmers responsibility to do meaningfull things with the
# content of the options.
#
# If err != 0 then all args are processed, else continue to look for options.
# When GetOpt finishes then all options are removed from cmdline.
#
if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG Parse Commandline and check version: $# $@" >&2
	$debuglog Parse Commandline and check version: $# $@
fi
#
err=0
while [ "$err" -eq 0 ]; do
	GetOpt 'hVdqvt:' 'help version debug quiet verbose' $@
	err=$?
	#echo "DEBUG GET OPTIONS: err=${err}  _OPTNAME_=${_OPTNAME_}  _OPTVAL_=${_OPTVAL_}  _OPTPOS_=${_OPTPOS_}  _OPTIDX_=${_OPTIDX_}" >&2
	if [ $err -eq 0 ]; then
		case "$_OPTNAME_" in
		    h|help)	cmd="-h";;
		    V|version)	cmd="-V";;
#		    a)		cmd="-${_OPTNAME_}";;
		    d|debug)	debug=yes;;
		    q|quiet)	verbose=no;;
		    v|verbose)	verbose=yes;;
#		    o|output)	opt_o=yes;;
#		    i|infile)	opt_i="${_OPTVAL_}";;
#		    o|outfile)	opt_o="${_OPTVAL_}";;
#		    p|pages)	opt_p="${_OPTVAL_}";;
		    t)		opt_t="${_OPTVAL_}";;
		    --)		break;;
		    :)	if [ "$verbose" != no ]; then
				echo "${ErrMsg[8]} -${_OPTVAL_}" >&2
			else
				$errlog ${ErrMsg[8]} -${_OPTVAL_}
			fi; exit 8;;
		    ?)	if [ "$verbose" != no ]; then
				echo "${ErrMsg[4]} -${_OPTVAL_}" >&2
			else
				$errlog ${ErrMsg[4]} -${_OPTVAL_}
			fi; exit 4;;
		    *)	if [ "$verbose" != no ]; then
				echo "${ErrMsg[99]} _OPTNAME_=${_OPTNAME_} _OPTVAL_=${_OPTVAL_}" >&2
			else
				$errlog ${ErrMsg[99]} _OPTNAME_=${_OPTNAME_} _OPTVAL_=${_OPTVAL_}
			fi; exit 99;;
		esac
	fi
done
err=0
shift ${_OPTIDX_}				# rm all opts from cmdline
# Uncomment if giving a cmd is mandatory
#if [ -z "$cmd" ]; then					# error no cmd given
#	if [ "$verbose" != no ]; then
#		echo "${ErrMsg[7]}" >&2
#	else
#		$errlog ${ErrMsg[7]}
#	fi
#	exit 7
#fi

##############################################################################
# CHECK LINK NAMES

##############################################################################
# CHECK OPTIONS

##############################################################################
# CHECK VERSION

##############################################################################
# CHECK ARGUMENTS
#
case "$cmd" in
    '')
	if [ "$#" -eq 2 ]; then				# parameter count ok
		arg1="$1"
		arg2="$2"
		shift 3
		txtfile=$arg1
		outfile=$arg2
		#args="$@"
		#shift $#
	else						# error in param count
		if [ "$verbose" != no ]; then
			echo "${ErrMsg[2]}" >&2
		else
			$errlog ${ErrMsg[2]}
		fi
		exit 2
	fi
	;;
    *)
	if [ "$#" -ne 0 ]; then				# error in param count
		if [ "$verbose" != no ]; then
			echo "${ErrMsg[2]}" >&2
		else
			$errlog ${ErrMsg[2]}
		fi
		exit 2
	fi
	;;
esac

##############################################################################
# LOCK

##############################################################################
# MAINPROGRAM
##############################################################################
#
if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG Main: $# $@" >&2
	$debuglog Main: $# $@
fi

# Check what to do (sub commands, options and args are removed from cmdline)
case "$cmd" in
    '')
	if [ -n "$opt_t" ]; then
		if [ -e "$opt_t" ]; then
			infile="$opt_t"
		else
			Show_Err ${5} "$opt_t !"
			exit 5
		fi
	else
		infile="$definf"
	fi

	s=y
	if [ -e "$arg2" ]; then
		echo -n "Overwrite file (y/N)? "
		read s
	fi
	if [ "$s" == y ] || [ "$s" == Y ]; then
		#mainproc
		clean_up
		tab2spaces_textfile; err=$?
		if [ "$err" -eq 0 ]; then split_textfile; err=$?; fi
		if [ "$err" -eq 0 ]; then create_text_videos; err=$?; fi
		if [ "$err" -eq 0 ]; then concat_text_videos; err=$?; fi
		clean_up
		err=$?
	fi
	;;
    -h)
	helptext
	exit 0
	;;
    -V)
	echo "${scriptname}: (${package}) $package_file ${version}-${release}"
	exit 0
	;;
    *)							# error
	Show_Err ${_ERR_SUB_CMD_NOT_FOUND_} ""
	err=${_ERR_SUB_CMD_NOT_FOUND_}
	;;
esac

#rm -f $lockfile

exit $err
