Skip to content

Instantly share code, notes, and snippets.

@SludgeVohaul
Created July 11, 2017 22:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SludgeVohaul/654ad130ab730c85e90122368f992aa7 to your computer and use it in GitHub Desktop.
Save SludgeVohaul/654ad130ab730c85e90122368f992aa7 to your computer and use it in GitHub Desktop.
Find all MKV files below a source directory and create a 2s long snippet of each found file below a target directory while preserving the directory structure.
#!/bin/bash
set -e
set -u
# Cannot use /bin/sh due to process substitution in run().
VERSION="20170711"
FIND=/usr/bin/find
MKDIR=/bin/mkdir
SORT=/usr/bin/sort
PWD=/bin/pwd
FILE=/usr/bin/file
# Install through homebrew with
# brew install ffmpeg --HEAD --without-libvo-aacenc --without-qtkit
FFMPEG=/usr/local/bin/ffmpeg
FFMPEG_LOGGING_ARGS=( "-loglevel" "warning" )
#FFMPEG_LOGGING_ARGS=( "-loglevel" "info" )
FFMPEG_BASE_ARGS=( "-hide_banner" )
# ######### TODO these values are not really user configurable right now #####
ABS_CURRENT_DIR=$("${PWD}")
# ############################################################################
# No user configurable options below this line.
# --------------------------------------------------------------------------------
function usage()
{
printf %s '
Version:
'"${VERSION}"'
Usage:
'"${PROGRAM}"' [-v] [-j] [-x] srcdir targetdir
-v increases the verbosity level. A higher level means more output to stdout.
Level 0: Warnings and errors only.
Level 1: Processed files.
Level 2: Executed commands.
-j writes a job summary to stdout and exits.
srcdir is the directory with the MKV files.
targetdir is the directory where the shortened MKV files are created.
Always use double quotes around names with spaces, or things won'"'"'t work.
'
}
# ----------------------------------------------------------------------------
function log()
{
local message="$1"
local verbosityLevel=$2
if (( VERBOSITY >= verbosityLevel )); then
echo "${message}"
fi
}
# --------------------------------------------------------------------------------
function logRun()
{
local commands=("$@")
# Read the last element (i.e. the verbosity level)
local verbosityLevel="${commands[$(( ${#commands[@]} - 1 ))]}"
# Remove last element (the verbosity level) from the commands array.
unset commands[$(( ${#commands[@]} - 1 ))]
if (( VERBOSITY >= verbosityLevel )); then
(set -x; "${commands[@]}")
else
"${commands[@]}"
fi
}
# --------------------------------------------------------------------------------
function shortenMkv()
{
local absSrcFile="$1"
local absTargetFile="$2"
local ffmpegInputArgs=( "-i" "${absSrcFile}" )
# Encode 2s only.
local ffmpegTestArgs=( "-ss" "00:00:00" "-t" "2" )
local ffmpegAudioArgs=( "-flags" "+global_header" "-map" "0:a" "-map" "-0:s" "-map" "0:v" "-map_metadata" "0" "-c:a" "copy" "-c:v" "copy")
local ffmpegAllArgs=(
"${FFMPEG_LOGGING_ARGS[@]}"
"${FFMPEG_BASE_ARGS[@]}"
"${ffmpegTestArgs[@]}")
ffmpegAllArgs+=(
"${ffmpegInputArgs[@]}"
"${ffmpegAudioArgs[@]}"
"${absTargetFile}")
log "-----------------------------------------------------------------------" 2
log "Shortening '${absSrcFile}'..." 1
logRun "${FFMPEG}" "${ffmpegAllArgs[@]}" 3
log "Done." 3
}
# ----------------------------------------------------------------------------
function showJobSummary()
{
local absSrcRootDir="$1"
local absTargetRootDir="$2"
local params=(
"${absSrcRootDir}"
"${absTargetRootDir}")
printf "
-----------------------------------------------------------------------
I would shorten all *.mkv files in source directory to target directory.
Source directory : '%s'
Target directory : '%s'
-----------------------------------------------------------------------
" "${params[@]}"
}
# --------------------------------------------------------------------------------
function run()
{
local absSrcRootDir="$1"
local absTargetRootDir="$2"
if (( JOB_SUMMARY )); then
showJobSummary "${absSrcRootDir}" "${absTargetRootDir}"
exit
fi
while read -d '' -r -u3 absSrcFile; do
local absTargetFile="${absSrcFile/${absSrcRootDir}/${absTargetRootDir}}"
if [ ! -d "${absTargetFile%/*}" ]; then
log "-----------------------------------------------------------------------" 2
log "Creating directory..." 2
logRun "${MKDIR}" -p "${absTargetFile%/*}" 3
log "Done." 3
fi
shortenMkv "${absSrcFile}" "${absTargetFile}"
done 3< <("${FIND}" "${absSrcRootDir}" -type f -name \*.mkv -print0 | "${SORT}" -z)
}
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
PROGRAM="${0##*/}"
VERBOSITY=0
JOB_SUMMARY=0
while getopts ":vj" optname; do
case "$optname" in
"v")
(( VERBOSITY++ ))
;;
"j")
JOB_SUMMARY=1
;;
"?")
log "Invalid option: -$OPTARG" 0 >&2
exit 1
;;
":")
log "Option -$OPTARG requires an argument." 0 >&2
exit 1
;;
esac
done
shift $(( OPTIND - 1 ))
if [ $# -ne 2 ]; then
usage
exit 1
fi
# http://www.network-theory.co.uk/docs/bashref/ShellParameterExpansion.html
if [ -d "${ABS_CURRENT_DIR}/${1}" ]; then
absSrcRootDir="${ABS_CURRENT_DIR}/${1%/}"
elif [ -d "${1}" ]; then
absSrcRootDir="${1%/}"
else
log "Invalid srcdir: '${1}'" 0 >&2
exit 1
fi
if [ -d "${ABS_CURRENT_DIR}/${2}" ]; then
absTargetRootDir="${ABS_CURRENT_DIR}/${2%/}"
elif [ -d "${2}" ]; then
absTargetRootDir="${2%/}"
else
log "Invalid targetdir: '${2}'" 0 >&2
exit 1
fi
run "${absSrcRootDir}" "${absTargetRootDir}"
log "-----------------------------------------------------------------------" 2
log "All done." 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment