#!/bin/bash
#
# This file is part of fadecut
# https://github.com/fadecut/fadecut
#
# fadecut 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 3 of the License, or
# (at your option) any later version.
#
# fadecut 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 fadecut.  If not, see <http://www.gnu.org/licenses/>.

# Script exit codes ------------------------------------------------------------
# Returnvalues  : 0 - successfully
#                 1 - partionally unsuccuessfully
#                 2 - function unexpected aborted
#                 3 - action aborted
#                 4 - syntax error
#                 5 - couldn't read, write or find file
#                 6 - invalid status
#                 99 - undefinded error code
#
# Constants --------------------------------------------------------------------
#
# you may overwrite all this constants in 
#   ~/.fadecut/fadecutrc 
# and/or
#   ~/.fadecut/profiles/<profile>
#

FILES=*.mp3					# which files to work on

ENCODING=ogg					# target format [opus/ogg/mp3]
TRIM_BEGIN=0					# trim n seconds at beginning
TRIM_END=0					# trim n seconds at end of song
FADE_IN=1					# seconds to fade in
FADE_OUT=4					# seconds to fade out

PWD=$(pwd)					# main directory of fadecut
LOGDIR=/tmp					# where to write logfiles
PROFILEDIR="$HOME/.fadecut" 			# profiledir
WORKDIR="$PWD"					# workdir
OUTPUTDIR="$PWD/new"				# where to put fadecut'ted files
ORIGDIR="$PWD/orig"				# where to put original files
DONEDIR="$PWD/done"				# here the user puts finished
						# files, which are tested and
						# listened
DONTLIKEDIR="$PWD/dontlike"			# here are songs we don't like
ERRORDIR="$PWD/error"				# files had an error
TMPDIR=/tmp					# here to put temporary files

ENQUEUE=0					# enqueue to rhythmbox or vlc
KEEPORIG=0					# don't keep original files
DEBUG=0						# debug level 0-3
VERBOSE=1					# verbosity level
LOOP_INTERVAL=10				# loop interval in seconds
RESTART_STREAMRIPPER_INTERVAL=900		# restart interval streamripper
STREAMRIPPER_START=0 				# start streamripper [0/1]
ADD_TIMESTAMP=0					# add Timestamp to the Filename
USER_AGENT="Streamripper/1.x"			# streamripper useragent
STREAMRIPPER_OPTS="-o always -T"		# streamripper options

E_NOARGS=65					# standard errorlevel definition
PID=$$						# fadecut's pid

# define all binaries
BIN_STREAMRIPPER=$(which streamripper)
BIN_SOX=$(which sox)
BIN_OPUSINFO=$(which opusinfo)
BIN_OPUSENC=$(which opusenc)
BIN_OGGINFO=$(which ogginfo)
BIN_OGGENC=$(which oggenc)
BIN_ID3V2=$(which id3v2)
BIN_LAME=$(which lame)
BIN_MEDIAINFO=$(which mediainfo)

# Variables --------------------------------------------------------------------
PidStreamripper="-1"
IdleCounter=-1
IdleSeconds=0
MissingVar=""
Fdst=""
PostExit=0					# Used for delayed shutdown's

Editor=vi
if [ -n "$EDITOR" ]; then
 Editor="$EDITOR"
fi

# Functions --------------------------------------------------------------------

usage()
#
# Description:  shows help text
# 
# Parameter  :  none
#
# Output     :  shows help text
#
{
cat << EOF

usage: $(basename $0) -p <profilename> [other options]

OPTIONS:
  -c    create profile <profilename>
  -d    Debug: -d 0|1|2|3 (level 0 is standard, -d without number is like 1)
  -e    edit profile <profilename>
  -h	Show this message
  -i    optional input directory
  -k    keep original file
  -l    list all existing profiles
  -o    optional output directory
  -p    Profile <profilename>
  -q	Quiet
  -r    Stream (and rip), start streamripper
  -t    add Timestamp to the Filename
  -v	Verbose

examples:

  if you want to rip audio from a radio station:
  $(basename $0) -p swisspop -r

  if you just want to process some files out of a directory:
  $(basename $0) -p swisspop -i <input-directory>

  (Warning: files will be deleted from <input-directory>!
            use option -k to keep them in ./orig)

EOF
return 0
}

logging()
#
# Description:  It writes messages to logfile or standard output.
#
# Parameter  :  $1 - the level of message
#               $2 - the message
#
# Std. Output:  Logging messages.
#
{
 if [ $DEBUG -ge 3 ]; then set -x
 fi

 logtime="$(date +%H):$(date +%M):$(date +%S)"
 prefix=""
 stderr=-1

 case $1 in
   -e)     prefix="Error:   " stderr=1 verbose=0;; #show always
   -s)     prefix="Success: " stderr=0 verbose=0;; #show always
   -r)     prefix="Stream:  " stderr=0 verbose=0;; #show always
   -i)     prefix="Info:    " stderr=0 verbose=1;; #show in VERBOSE>=1 mode
   -a)     prefix="         " stderr=0 verbose=1;; #show in VERBOSE>=1 mode
   -n)     prefix="Notice:  " stderr=0 verbose=2;; #show in VERBOSE>1 mode
   -w)     prefix="Warning: " stderr=1 verbose=2;; #show in VERBOSE>1 mode
   -d)     prefix="Debug:   " stderr=1 verbose=3;; #show only in DEBUG mode
 esac
 shift

# if VERBOSE mode is set, then show all messages, which we want to show in verbose mode
if [ $VERBOSE -ge 1 ] && [ $verbose -lt 2 ] ; then 
 if [ "$stderr" -eq 1 ]; then
   echo "$logtime $prefix" $1 >&2
 else
   echo "$logtime $prefix" $1
 fi
elif [ $VERBOSE -gt 1 ] && [ $verbose -lt 3 ] ; then 
 if [ "$stderr" -eq 1 ]; then
   echo "$logtime $prefix" $1 >&2
 else
   echo "$logtime $prefix" $1
 fi
# else show only messages which are defined to show in non-verbose mode
elif [ $verbose -eq 0 ] ; then
 if [ "$stderr" -eq 1 ]; then
   echo "$logtime $prefix" $1 >&2
 else
   echo "$logtime $prefix" $1
 fi
fi
# show debug messages
if [ $DEBUG -ge 1 ] && [ $verbose -eq 3 ] ; then
   echo "$logtime $prefix" $1 >&2
fi
}

createDirs()
#
# Description:  creates needed directories
# 
# Parameter  :  none
#
# Output     :  none
#
{
if [ $DEBUG -ge 3 ]; then set -x
fi

if [ ! -d "$PROFILEDIR/profiles" ]; then
  mkdir -p "$PROFILEDIR/profiles"
fi

return 0
}

startStream()
#
# Description:  forks the streamripper process
# 
# Parameter  :  none
#
# Output     :  none
#
{
if [ $DEBUG -ge 3 ]; then set -x
fi

cd "$WORKDIR"

if [ ! -x $BIN_STREAMRIPPER ]; then
  logging -e "Ooops! Streamripper not found"
  shutdown_fadecut 3
fi

if [ ! -d "/proc/$PidStreamripper" ] && [ "$STREAMRIPPER_START" == "1" ];
then
  $BIN_STREAMRIPPER $STREAM_URL -d . \
                      --codeset-filesys=utf8 \
                      --codeset-id3=ISO-8859-1 \
                      -u $USER_AGENT \
                      -s $STREAMRIPPER_OPTS \
                      > $LOGDIR/fadecutstream-$PID.log 2>&1 & 
  PidStreamripper=$!
  logging -s "$BIN_STREAMRIPPER started pid=$PidStreamripper"
else
  logging -n "$BIN_STREAMRIPPER running pid=$PidStreamripper"
fi

cd "$PWD"

return 0
}

shutdown_streamripper()
#
# Description:  shutting down streamripper
# 
# Parameter  :  none
#
# Output     :  logging
#
{
if [ $DEBUG -ge 3 ]; then set -x
fi

TmpPid=$(pidof streamripper)

if [ -z "$TmpPid" ]; then return 0
fi

if [[ " $TmpPid " == *" $PidStreamripper "* ]];
then
  logging -i "Shuting down streamripper" 
  kill $PidStreamripper 
  sleep 1
  if [[ " $(pidof streamripper) " == *" $PidStreamripper "* ]];
  then
    logging -w "Streamripper still here, killing it!"
    kill -9 $PidStreamripper
  fi
else
  logging -n "Another streamripper is still running"
fi

return 0
}

shutdown_fadecut()
#
# Description:  shutting down fadecut and cleaning up
# 
# Parameter  :  none
#
# Output     :  logging
#
{
if [ $DEBUG -ge 3 ]; then set -x
fi

logging -n "Shutting down fadecut..."
ExitCode=$1
shutdown_streamripper

if [ -f "$LOGDIR/fadecutstream-$PID.log" ] ; then
  rm $LOGDIR/fadecutstream-$PID.log
fi

case $ExitCode in
	0)
	  logging -s "Fadecut exiting..."
	;;
	1)
	  logging -w "Fadecut stopped partionally unsuccuessfull"
	;;
esac
logging -d "Returnvalue=$ExitCode"

exit $ExitCode
}

queueSong()
#
# Description:  queue song to music player
# 
# Parameter  :  none
#
# Output     :  logging
#
{
if [ $DEBUG -ge 2 ]; then set -x
fi

if [ $ENQUEUE -eq "1" ]; then
  if [ "$(pidof rhythmbox)" ];
  then
    logging -i "Rhythmbox is running, adding to playlist"
    rhythmbox-client --enqueue "$OUTPUTDIR"/"$Fdst"
  fi
  if [ "$(pidof vlc)" ];
  then
    # enqueue to vlc player if in one instance mode (default disabled)
    logging -i "vlc is running, adding to playlist"
    vlc --playlist-enqueue "$OUTPUTDIR"/"$Fdst" > /dev/null 2>&1
  fi
fi

return 0
}

control_c()
#
# Description:  run if user hits control-c
# 
# Parameter  :  none
#
# Output     :  logging
#
{
if [ $DEBUG -ge 3 ]; then set -x
fi

logging -n "CTRL-C catched"
shutdown_fadecut 0
}

loop_fadecut()
#
# Description:  main processing function of fadecut
# 
# Parameter  :  none
#
# Output     :  none
#
{
if [ $DEBUG -ge 3 ]; then set -x
fi

RetLoop=0

cd "$WORKDIR"
for F in $FILES
do
  # if there are no more files to process, go to idle state or clean up
  # and shutdown fadecut.
  if [ "$F" == "$FILES" ]; then
    let IdleCounter=$((IdleCounter+1))
    let IdleSeconds=$((IdleCounter*LOOP_INTERVAL))
    logging -n "no files to process, idle for $IdleSeconds seconds"
    if [ $STREAMRIPPER_START == "0" ];
    then 
      shutdown_fadecut $PostExit
    else
      if [ $IdleSeconds -ge $RESTART_STREAMRIPPER_INTERVAL ];
      then
        logging -w "Oops! Seems to hang, restarting it"
	shutdown_streamripper
	startStream
        IdleCounter=0
      fi
    fi
    break
  fi
  IdleCounter=0

  # Checking part of loop_fadecut()
  # check next file 
  logging -i "Processing: $F"

  # preserve timestamp
  TIMESTAMP=$(date -R -r "$F")  

  Fstatus="processing"
  Fnew=$(filerename "$F")
  # Converting id3v1->id3v2 tags, if necessary. Must be before `id3v2 -l`
  # command.
  $BIN_ID3V2 -C "$F" > /dev/null 2>&1

  # restore original timestamp
  touch -d "$TIMESTAMP" "$F"

  ARTIST=`$BIN_ID3V2 -l "$F" | sed -e '/TPE1/!d' -e 's/^.*: //g'`
  TITLE=`$BIN_ID3V2 -l "$F" | sed -e '/TIT2/!d' -e 's/^.*: //g'`

  if [ "$KEEPORIG" -eq "1" ]; then
    copy_file "$F" "$ORIGDIR"
  fi

  # do some checks, check if file already exists and set status
  # status will be written to statslog
  # depending on status the processing will continue or will skipped to next file
  if [[ -z $ARTIST ]] || [[ -z $TITLE ]] 
  then
    logging -e "could not get mp3 tags from source file."
    logging -e "ARTIST: $ARTIST / TITLE: $TITLE"
    move_file "$F" "$ERRORDIR"
    Fstatus="error-notags"
    PostExit=1
  elif [ -f "$DONEDIR"/"$F" ] || [ -f "$DONEDIR"/"$Fnew" ] ; then
    logging -i "File already exists in $DONEDIR ..."
    rm "$F"
    Fstatus="double-done"
  elif [ -f "$OUTPUTDIR"/"$F" ] || [ -f "$OUTPUTDIR"/"$Fnew" ] ; then
    logging -i "File already exists in $OUTPUTDIR ..."
    rm "$F"
    Fstatus="double-output"
  elif [ -f "$DONTLIKEDIR"/"$F" ] || [ -f "$DONTLIKEDIR"/"$Fnew" ] ; then
    logging -i "I don't like. File exists in $DONTLIKEDIR -> deleting ..."
    rm "$F"
    Fstatus="dontlike"
  fi
  
  # Processing part of loop_fadecut()
  writeStats "$ARTIST" "$TITLE" "$GENRE" "$PROFILE" "$Fstatus" "$Fnew"

  # skip processing of current file if it is "double" or "don't like"
  if [[ $Fstatus != "processing" ]] ; then
    continue
  fi

  splitting "$F" "$ARTIST" "$TITLE" "$GENRE" "$COMMENT"

  LENGTH=`$BIN_SOX "$TMPDIR"/"$F" -n stat 2>&1 | grep Length | sed -e 's/.* //' -e 's/\..*//'`
  let TRIMLENGTH=$((LENGTH-TRIM_BEGIN-TRIM_END))
  let FADE_OUT_START=$((TRIMLENGTH-FADE_OUT))

  if [ "$ENCODING" == "mp3" ]; then
    mp3Encoding "$F"
  fi
  if [ "$ENCODING" == "ogg" ]; then
    oggEncoding "$F"
  fi
  if [ "$ENCODING" == "opus" ]; then
    opusEncoding "$F"
  fi
  
  if [ "$RetLoop" -eq "0" ]; then
    logging -s "Ready for listening: $Fdst"
    rm "$TMPDIR"/"$F"
    rm "$F"
  else
    move_file "$F" "$ERRORDIR"
      # when sox or lame are receiving SIGINT they exit with return-code > 0
      # the ctrl_c function does not catch this case, so we have to break here
    logging -n "loop_fadecut(): Oops! Something was wrong."
    logging -e "loop_fadecut(): returnvalue=$RetLoop"
    shutdown_fadecut 3
  fi

  queueSong
  showStats
done
cd "$PWD"
}

list_profiles()
#
# Description:  list all existing profiles
# 
# Parameter  :  none
#
# Output     :  none
#
{

if ls -1 $PROFILEDIR/profiles/* >/dev/null 2>&1
then
  for F in $PROFILEDIR/profiles/*
  do
    echo "$(basename $F)	$(grep GENRE $F)	$(grep URL $F)"
  done
else
  logging -e "no profiles found in $PROFILEDIR"
  logging -e "create your first profile with 'fadecut -e first-profile'"
fi

return 0

}


load_profile()
#
# Description:  loading fadecutrc and profile file
# 
# Parameter  :  none
#
# Output     :  none
#
{
if [ $DEBUG -ge 3 ]; then set -x
fi

if [ ! -r "$PROFILEDIR/profiles/$PROFILE" ]; then
  logging -e "Can't not load profile $PROFILEDIR/profiles/$PROFILE"
  exit 1
else
  logging -i "Loading profile: $PROFILEDIR/profiles/$PROFILE"
  . "$PROFILEDIR/profiles/$PROFILE"
fi

check_profile
}

create_profile()
#
# Description:  creates a new profile
# 
# Parameter  :  none
#
# Output     :  none
#
{
if [ $DEBUG -ge 3 ]; then set -x
fi

NEW=$1

echo \
"STREAM_URL=\"http://radiostream\"
GENRE=\"YourGenre\"
COMMENT=\"Your Comment\"
# all values in seconds:
FADE_IN=1
FADE_OUT=4
# TRIM_BEGIN=0
# TRIM_END=0" > "$PROFILEDIR/profiles/$NEW"
logging -i "Starting $Editor editor"
$Editor "$PROFILEDIR/profiles/$NEW"
logging -i "Now start: fadecut -r -p $NEW [optional other options]"
}

edit_profile()
#
# Description:  edit an existing profile
# 
# Parameter  :  $1  profile name
#
# Output     :  none
#
{
$Editor "$PROFILEDIR/profiles/$1"
}

check_profile()
#
# Description:  check existing profile
#               we need all variables to work
# 
# Parameter  :  none
#
# Output     :  none
#
{
if [ $DEBUG -ge 3 ]; then set -x
fi

RetCheckProfile=0
MissingVar=""

if [ -z "$STREAM_URL" ]; then 
  RetCheckProfile=1
  MissingVar="STREAM_URL"
fi
if [ -z "$COMMENT" ]; then 
  RetCheckProfile=1
  MissingVar="COMMENT $MissingVar"
fi
if [ -z "$TRIM_BEGIN" ]; then 
  RetCheckProfile=1
  MissingVar="TRIM_BEGIN $MissingVar"
fi
if [ -z "$TRIM_END" ]; then 
  RetCheckProfile=1
  MissingVar="TRIM_END $MissingVar"
fi
if [ -z "$FADE_IN" ]; then 
  RetCheckProfile=1
  MissingVar="FADE_IN $MissingVar"
fi
if [ -z "$FADE_OUT" ]; then 
  RetCheckProfile=1
  MissingVar="FADE_OUT $MissingVar"
fi

if [ $RetCheckProfile -eq 1 ]; 
then 
  logging -e "$PROFILEDIR/profiles/$PROFILE:"
  logging -a "$MissingVar not defined"
  shutdown_fadecut 1
fi

return 0
}

showStats()
#
# Description:  shows file statistics
# 
# Parameter  :  none
#
# Output     :  none
#
{
if [ $DEBUG -ge 3 ]; then set -x
fi

# show statistics only, if all directories are existing
if [ -d "$OUTPUTDIR" ]; then
  StatsNewDir=`ls -1 "$OUTPUTDIR" | wc -l`
fi
if [ -d "$ORIGDIR" ]; then
  StatsOrigDir=`ls -1 "$ORIGDIR"  | wc -l`
fi
if [ -d "$DONEDIR" ]; then
  StatsDoneDir=`ls -1 "$DONEDIR"  | wc -l`
fi
if [ -d "$DONTLIKEDIR" ]; then
  StatsDontlikeDir=`ls -1 "$DONTLIKEDIR"  | wc -l`
fi
if [ -d "$ERRORDIR" ]; then
  StatsErrorDir=`ls -1 "$ERRORDIR"  | wc -l`
fi

if [ -f "$PROFILEDIR"/statslog.csv ]; then
  double=$(grep ";double-" "$PROFILEDIR"/statslog.csv | \
           grep ";$PROFILE;" | \
           cut -d \; -f 4 | \
           sort -u | \
           wc -l)
  processed=$(grep ";processing" "$PROFILEDIR"/statslog.csv | \
              grep ";$PROFILE;" | \
              cut -d \; -f 4 | \
              sort -u | \
              wc -l)
fi
  logging -a "Output:$StatsNewDir Orig:$StatsOrigDir Done:$StatsDoneDir Dontlike:$StatsDontlikeDir Error:$StatsErrorDir Double:$double Processed:$processed"
}

writeStats()
#
# Description:  writes statistics log
# 
# Parameter  :  $1  "artist"
#               $2  "title"
#               $3  "genre"
#               $4  "profile"
#               $5  "status"
#		$6  "filename"
#
# Usage      :  writeStats "artist" "title" "genre" "profile" "status" "filename"
#
# Output     :  none
#
{
if [ $DEBUG -ge 3 ]; then set -x
fi

date=`date +%d.%m.%Y`
time=`date +%H:%M:%S`
artist=`echo "$1" | iconv -f ISO-8859-1 -t UTF-8`
title=`echo "$2"  | iconv -f ISO-8859-1 -t UTF-8`
genre="$3"
profile="$4"
status="$5"
filename="$6"
echo "$date;$time;$artist;$title;$genre;$profile;$status;$filename" >> "$PROFILEDIR"/statslog.csv
}

oggEncoding()
#
# Description:  encoding to ogg
# 
# Parameter  :  $1  filename
#
# Output     :  none
#
{
if [ $DEBUG -ge 2 ]; then set -x
fi

Fsrc="$*"
Bitrate=$($BIN_MEDIAINFO "$Fsrc" | grep 'Bit rate   ' | awk '{ print $4 }')
if [ -z "$Bitrate" ] ; then
  Bitrate=128
fi
Fdst=$(filerename "$Fsrc")
if [ ! -d "$OUTPUTDIR" ]; then
  mkdir -p "$OUTPUTDIR"
fi
# The Bash ‘-o pipefail’ option to set will cause a pipeline to return a 
# failure status if any command fails. 
set -o pipefail
nice -15 $BIN_SOX -V1 "$TMPDIR"/"$F" -t wav - trim $TRIM_BEGIN $TRIMLENGTH \
  silence -l 1 0.5 0.1% -1 0.5 0.1% \
  fade t $FADE_IN $FADE_OUT_START $FADE_OUT | \
  oggenc - --quiet -b $Bitrate -t "$TITLE"  -a  "$ARTIST" -G "$GENRE" \
	-c "comment=$COMMENT" -o "$OUTPUTDIR"/"$Fdst" || RetLoop=3

# restore original download timestamp
touch -d "$TIMESTAMP" "$OUTPUTDIR/$Fdst"

# Disable pipefail (default)
set +o pipefail
if [ $VERBOSE -ge 2 ];
then
  ogginfo "$OUTPUTDIR"/"$Fdst" || RetLoop=3
fi
}

opusEncoding()
#
# Description:  encoding to opus
#
# Parameter  :  $1  filename
#
# Output     :  none
#
{
if [ $DEBUG -ge 2 ]; then set -x
fi

Fsrc="$*"
Fdst=$(filerename "$Fsrc")
if [ ! -d "$OUTPUTDIR" ]; then
  mkdir -p "$OUTPUTDIR"
fi
# The Bash ‘-o pipefail’ option to set will cause a pipeline to return a
# failure status if any command fails.
set -o pipefail
nice -15 $BIN_SOX -V1 "$TMPDIR"/"$F" -t wav - trim $TRIM_BEGIN $TRIMLENGTH \
  silence -l 1 0.5 0.1% -1 0.5 0.1% \
  fade t $FADE_IN $FADE_OUT_START $FADE_OUT | \
  opusenc - --quiet --title "$TITLE"  --artist "$ARTIST" --genre "$GENRE" \
	--comment "comment=$COMMENT" "$OUTPUTDIR"/"$Fdst" || RetLoop=3

# restore original download timestamp
touch -d "$TIMESTAMP" "$OUTPUTDIR/$Fdst"

# Disable pipefail (default)
set +o pipefail
if [ $VERBOSE -ge 2 ];
then
  opusinfo "$OUTPUTDIR"/"$Fdst" || RetLoop=3
fi
}

mp3Encoding()
#
# Description:  encoding to mp3
# 
# Parameter  :  $1  filename
#
# Output     :  none
#
{
if [ $DEBUG -ge 2 ]; then set -x
fi

Fsrc="$*"
Bitrate=$($BIN_MEDIAINFO "$Fsrc" | grep 'Bit rate   ' | awk '{ print $4 }')
if [ -z "$Bitrate" ] ; then
  Bitrate=128
fi
Fdst=$(filerename "$Fsrc")
if [ ! -d "$OUTPUTDIR" ]; then
  mkdir -p "$OUTPUTDIR"
fi
# The Bash ‘-o pipefail’ option to set will cause a pipeline to return a 
# failure status if any command fails. 
set -o pipefail
nice -15 $BIN_SOX -V1 "$TMPDIR"/"$Fsrc" -t wav - trim $TRIM_BEGIN $TRIMLENGTH \
  silence -l 1 0.5 0.1% -1 0.5 0.1% \
  fade t $FADE_IN $FADE_OUT_START $FADE_OUT | \
  lame --quiet -b $Bitrate --add-id3v2 --ta "$ARTIST" --tt "$TITLE" \
  --tg "$GENRE" --tc "$COMMENT" - "$OUTPUTDIR"/"$Fdst" || RetLoop=3

# restore original download timestamp
touch -d "$TIMESTAMP" "$OUTPUTDIR/$Fdst"

# Disable pipefail (default)
set +o pipefail
# delete tag written by lame (TLEN is always the same and always wrong)
# found with LAME 32bits version 3.98.4
# this patch was made after a feedback of Jonas Schmid
$BIN_ID3V2 --TLEN "" "$OUTPUTDIR"/"$Fdst"
}

splitting()
#
# Description:  split files using silence detection of sox
# 
# Parameter  :  $1  filename
#               $2  "artist"
#               $3  "title"
#               $4  "genre"
#               $5  "comment"
#
# Output     :  none
#
{
F="$1"
ARTIST="$2"
TITLE="$3"
GENRE="$4"
COMMENT="$5"

$BIN_SOX -V1 "$F" -t wav "$TMPDIR"/"$F".wav silence 1 0.50 0.1% 1 0.5 0.1% : newfile : restart
Fcount=`ls -1 "$TMPDIR"/"$F"* | wc -l`
#choose biggest file of sox output as we think this will be the wanted main part
Ftmp=`ls -1S "$TMPDIR"/"$F"* | sed -e 's/.*\///g' | head -1`
mv "$TMPDIR"/"$Ftmp" "$TMPDIR"/"$F"
if [ $Fcount -ge 2 ] ; then
  logging -i "sox found silence and splitted..."
  rm "$TMPDIR"/"$F"00*
  Fnew=$(filerename "$F")
  writeStats "$ARTIST" "$TITLE" "$GENRE" "$PROFILE" "soxsplit into $Fcount files" "$Fnew"
fi

return 0
}

filerename()
#
# Description:  rename filenames
# 
# Parameter  :  $1  old filename
#
# Output     :  new filename
#
{
if [ $DEBUG -ge 2 ]; then set -x
fi

Fnold="$*"
# Change destination filename according to selected $ENCODING
local tmp=$(echo "$Fnold" | sed -e "s/\.mp3/\.$ENCODING/g")
Fnnew=$(echo $tmp | sed -e 's/ /_/g' -e 's/\(.*\)/\L\1/')
if [ $ADD_TIMESTAMP -gt 0 ]; then
  Fnnew="$(date) $Fnnew"
fi
echo $Fnnew

return 0
}

checkRequirements()
#
# Description:  Check if all necessary tools and binaries are available
# 
# Parameter  :  none
#
# Output     :  logging
#               forces an error if a needed binary is not available
#
{
if [ $DEBUG -ge 3 ]; then set -x
fi

logging -d "Checking fadecut requirements"
if [ -z $BIN_STREAMRIPPER ]; then RequirementsMsg=streamripper
fi
if [ -z $BIN_SOX ]; then RequirementsMsg=sox
fi
if [ -z $BIN_ID3V2 ]; then RequirementsMsg=id3v2
fi
if [ -z $BIN_MEDIAINFO ]; then RequirementsMsg=mediainfo
fi

if [ "$ENCODING" == "ogg" ];
then
  if [ -z $BIN_OGGINFO ]; then RequirementsMsg=ogginfo
  fi
  if [ -z $BIN_OGGENC ]; then RequirementsMsg=oggenc
  fi
fi

if [ "$ENCODING" == "opus" ];
then
  if [ -z $BIN_OPUSINFO ]; then RequirementsMsg=opusinfo
  fi
  if [ -z $BIN_OPUSENC ]; then RequirementsMsg=opusenc
  fi
fi

if [ "$ENCODING" == "mp3" ];
then
  if [ -z $BIN_LAME ]; then RequirementsMsg=lame
  fi
fi

if [ ! -z $RequirementsMsg ];
then
  logging -e "Program $RequirementsMsg not installed or not in PATH"
  return 1
fi

if [ ! -w "$WORKDIR" ];
then
  logging -e "Cannot write into $WORKDIR directory"
  return 1
fi

return 0
}

copy_file()
#
# Description:  checks if directory exists, creates it if necessary and copy file to it
# 
# Parameter  :  $1  file
#               $2  destination directory
#
# Output     :  none
#
{
if [ $DEBUG -ge 2 ]; then set -x
fi

if [ ! -d "$2" ]; then
  mkdir -p "$2"
fi
cp -p "$1" "$2"

return 0
}

move_file()
#
# Description:  checks if directory exists, creates it if necessary and moves file to it
# 
# Parameter  :  $1  file
#               $2  destination directory
#
# Output     :  none
#
{
if [ $DEBUG -ge 2 ]; then set -x
fi

if [ ! -d "$2" ]; then
  mkdir -p "$2"
fi
mv "$1" "$2"

return 0
}

set_options()
#
# Description:  set variables according to commandline settings
# 
# Parameter  :  none
#
# Output     :  none
#
{
if [ ! -z "$GETOPT_DEBUG" ] ; then
  DEBUG=$GETOPT_DEBUG
fi
if [ ! -z "$GETOPT_VERBOSE" ] ; then
  VERBOSE=$GETOPT_VERBOSE
fi
if [ ! -z "$GETOPT_KEEPORIG" ] ; then
  KEEPORIG=$GETOPT_KEEPORIG
fi
if [ ! -z "$GETOPT_WORKDIR" ]; then
  WORKDIR=$GETOPT_WORKDIR
fi
if [ ! -z "$GETOPT_OUTPUTDIR" ]; then
  OUTPUTDIR=$GETOPT_OUTPUTDIR
fi
if [ ! -z "$GETOPT_STREAMRIPPER_START" ]; then
  STREAMRIPPER_START=$GETOPT_STREAMRIPPER_START
fi
if [ ! -z "$GETOPT_ADD_TIMESTAMP" ]; then
  ADD_TIMESTAMP=$GETOPT_ADD_TIMESTAMP
fi
}

# Main  ------------------------------------------------------------------------

# trap keyboard interrupt (control-c)
trap control_c SIGINT

# create profile directory if it does not already exist
createDirs

# When you need an argument that needs a value, you put the ":" right after 
# the argument in the optstring. If your var is just a flag, withou any 
# additional argument, just leave the var, without the ":" following it.
#
# please keep letters in alphabetic order
#
while getopts ":c:d:e:hi:klo:p:qrtv" OPTION
do
  case $OPTION in
    c)
      create_profile $OPTARG
      exit 0
      ;;
    d)
      GETOPT_DEBUG=$OPTARG
      ;;
    e)
      edit_profile $OPTARG
      exit 0
      ;;
    h)
      usage
      exit 1
      ;;
    i)
      GETOPT_WORKDIR=$(readlink -f $OPTARG)
      ;;
    k)
      GETOPT_KEEPORIG=1				# keep original files
      ;;
    l)
      list_profiles
      exit 0
      ;;
    o)
      GETOPT_OUTPUTDIR=$(readlink -f $OPTARG)
      ;;
    p)
      PROFILE=$OPTARG
      ;;
    q)
      GETOPT_VERBOSE=0
      # add LOGGING variable and change logging function to be able to turn 
      # all output off
      ;;
    r)
      GETOPT_STREAMRIPPER_START=1 
      ;;
    t)
      GETOPT_ADD_TIMESTAMP=1
      ;;
    v)
      GETOPT_VERBOSE=1
      ;;
    \?)
      logging -e "Invalid option: -$OPTARG" >&2
      usage
      shutdown_fadecut 1
      ;;
    :)
      logging -e "Option -$OPTARG requires an argument." >&2
      shutdown_fadecut 1
      ;;
  esac
done

# set_options first, to be quiet or verbose
set_options

# load master profile
if [ -r "$PROFILEDIR/fadecutrc" ]; then
  logging -i "Loading master profile: $PROFILEDIR/fadecutrc"
  . "$PROFILEDIR/fadecutrc"
fi

# set_options again, to override predefined settings from master profile with commandline settings
set_options

# load profile first, so we are able to define profile specific settings
if [ -z $PROFILE ] ; then
  usage
  exit 1
else
  load_profile
fi

# set_options again, to override predefined settings from profiles with commandline settings
set_options

# set working directory AFTER loading profile to be able to override settings with commandline parameters
if [ ! -d "$WORKDIR" ]; then
  logging -e "$WORKDIR: Input directory does not exist"
  shutdown_fadecut 3
else
  logging -n "Using for input: $WORKDIR"
fi

# check if directory settings are ok
if [ "$OUTPUTDIR" = "$WORKDIR" ]; then
  logging -e "Output and input directory can not be equal!"
  usage
  exit 1
fi

# CheckRequirements before starting the action
if ! checkRequirements; then shutdown_fadecut 1
fi

StreamInfo=""
StreamInfo2=""
while true
do
  startStream
  loop_fadecut
  logging -n "Main(): Loop until we're finished"
  sleep 2
  # if streamripper is working then show info about it
  if [ $STREAMRIPPER_START == "1" ] && [ -f $LOGDIR/fadecutstream-$PID.log ];
  then
    StreamStatus=$(tail $LOGDIR/fadecutstream-$PID.log | grep error)
    if [ -z "$StreamStatus" ] ; then
      StreamInfo=$(tail -1 $LOGDIR/fadecutstream-$PID.log | sed -e 's/ \[.*$//g')
      if [ "$StreamInfo" != "$StreamInfo2" ] ; then
        logging -r "$StreamInfo"
        StreamInfo2="$StreamInfo"
      fi
    else
      logging -e "Streamripper exited with $StreamStatus"
      rm $LOGDIR/fadecutstream-$PID.log
      exit 1
    fi
  sleep $LOOP_INTERVAL
  fi
done

