#!/bin/bash
#
# Copyright (C) 2023-2024 Eugene 'Vindex' Stulin
# Distributed under the Boost Software License 1.0.

set -eu -o pipefail

ENCLIB=libx265  # or hevc_nvenc
readonly DEFAULT_CRF=18  # constant rate factor


# The function prints help information.
Print_Help() {
cat <<EndOfHelp
This script re-encodes the specified video file into
a new file using the HEVC (H.265) codec.

Usage:
    $0 [-N] <input/video/path> [<CRF>]

Flag '-N' enables hevc_nvenc instead of libx265.
CRF (constant rate factor) by default is equal to 18.

Flags (now only -N) must precede the file path.

Example:
    $0 video.mp4 20
Result will be saved to "video.x265.mp4".

Help and version:
    $0 --help|-h
    $0 --version|-v
EndOfHelp
}


# The function prints the script version.
Print_Version() {
    local version_file="$(dirname -- "${BASH_SOURCE[0]}")/bbsi_version"
    local vers
    vers="$(cat "$version_file" 2>/dev/null)" || vers="is unknown"
    echo "Bash-based set of instruments (bbsi), version $vers."
}


# The function finds and prints the index of stream containing video.
# Parameters:
#     $1 - path to videofile.
Get_Video_Stream_Index() {
    declare -a temparr
    local tmp
    if ! tmp="$(ffprobe -hide_banner "$1" 2>&1)"; then
        echo "$tmp" >&2
        exit 1
    fi
    if ! tmp="$(echo "$tmp" | grep Stream | grep Video | grep -v mjpeg)"; then
        echo "Videostream not found." >&2
        exit 1
    fi
    IFS=: read -ra temparr <<< "$tmp"
    egrep -o '^[0-9]+' <<< "${temparr[1]}"
}


# parse command line arguments
while getopts ':-:hvN' VAL; do
    case $VAL in
        h) Print_Help ; exit 0 ;;
        v) Print_Version ; exit 0 ;;
        N) ENCLIB=hevc_nvenc ;;
        -)  # long arguments (with --)
            case $OPTARG in
                help) Print_Help ; exit 0 ;;
                version) Print_Version ; exit 0 ;;
                *) echo "Unknown argument: --$OPTARG" ; exit 1
            esac
            ;;
        *) echo "Unknown argument: $OPTARG" ; exit 1 ;;
    esac
done
shift $((OPTIND-1))
if [[ $# -eq 0 || $# -gt 2 ]]; then
    Print_Help
    exit 1
fi
readonly MEDIAFILE="$1"
readonly CRF="${2:-$DEFAULT_CRF}"
if [[ ! "$CRF" =~ ^[0-9]+$ ]]; then
    echo "CRF must be equal to numeric value." >&2
    exit 1
fi


# prepare information for re-encoding
PATH_WITHOUT_EXT="${MEDIAFILE%.*}"
EXT="${MEDIAFILE##*.}"
EXT="${EXT,,}"  # lower case
if [[ "$EXT" == mp4 || "$EXT" == m4v ]]; then
    FINAL_EXT=mp4
elif [[ "$EXT" == mov ]]; then
    FINAL_EXT=mov
else
    FINAL_EXT=mkv
fi
[[ "$ENCLIB" == libx265 ]] && ENC_INDICATOR=x265 || ENC_INDICATOR=$ENCLIB
[[ $CRF -ne $DEFAULT_CRF ]] && CRF_SUFF=crf${CRF}. || CRF_SUFF=""
ENCODED_FILE="${PATH_WITHOUT_EXT}.${ENC_INDICATOR}.${CRF_SUFF}${FINAL_EXT}"
NO=$(Get_Video_Stream_Index "$MEDIAFILE")
OPTIONS="-map 0 -c copy -c:$NO $ENCLIB -crf $CRF"


Interrupt_Execution() {
    set +x
    echo "The script has been interrupted." 2>&1
    rm -f "$ENCODED_FILE"
    exit 1
}
trap Interrupt_Execution ABRT INT QUIT TERM


# re-encode
set -x
ffmpeg -hide_banner -i "$MEDIAFILE" $OPTIONS "$ENCODED_FILE" -y
set +x

echo "Saved to $ENCODED_FILE."
