major version bump to 2.0

This commit is contained in:
Nathaniel Landau
2016-01-06 17:01:51 -05:00
parent de20b3f319
commit 512729c6e9

View File

@@ -3,7 +3,7 @@
# ##################################################
# My Generic BASH script template
#
version="1.2.0" # Sets version variable for this script
version="2.0.0" # Sets version variable for this script
#
scriptTemplateVersion="1.5.0" # Version of scriptTemplate.sh that this script is based on
#
@@ -14,6 +14,13 @@ scriptTemplateVersion="1.5.0" # Version of scriptTemplate.sh that this script is
# * 2015-04-07 - v1.1.0 - Added support for music files
# * 2015-05-26 - v1.1.1 - Fixed log level on downsize720
# * 2015-08-30 - v1.2.0 - Support for recursive directory conversions
# * 2016-01-03 - v1.2.1 - Fixed XLD audio conversion which had been broken
# * 2016-01-15 - v2.0.0 - Major refactoring of code.
# - Better JSON parsing via JQ
# - MIME type discovery based on file metadata (rather than user input)
# - Better error handling
# - Better renaming of existing files
#
#
# ##################################################
@@ -43,6 +50,7 @@ fi
# -----------------------------------
function trapCleanup() {
echo ""
# Delete temp files, if any
if is_dir "${tmpDir}"; then
rm -r "${tmpDir}"
fi
@@ -64,6 +72,9 @@ debug=false
safeRun=0
downsize720=0
deleteOriginal=false
newFileFlag=false
videoFoundFlag=false
audioFoundFlag=false
XLD=0
args=()
@@ -72,7 +83,7 @@ args=()
# Create temp directory with three random numbers and the process ID
# in the name. This directory is removed automatically at exit.
# -----------------------------------
tmpDir="/tmp/${scriptName}.$RANDOM.$RANDOM.$RANDOM.$$"
tmpDir="/tmp/${scriptName}.${RANDOM}.${RANDOM}.${RANDOM}.${$}"
(umask 077 && mkdir "${tmpDir}") || {
die "Could not create temporary directory! Exiting."
}
@@ -85,7 +96,7 @@ tmpDir="/tmp/${scriptName}.$RANDOM.$RANDOM.$RANDOM.$$"
# Save to Desktop use: $HOME/Desktop/${scriptBasename}.log
# Save to standard user log location use: $HOME/Library/Logs/${scriptBasename}.log
# -----------------------------------
logFile="$HOME/Library/Logs/${scriptBasename}.log"
logFile="${HOME}/Library/Logs/${scriptBasename}.log"
# Check for Dependencies
# -----------------------------------
@@ -100,170 +111,212 @@ caskDependencies=()
gemDependencies=()
function mainScript() {
############## Begin Script Here ###################
####################################################
############## Begin Script Here ###################
####################################################
# file extension mappings - ie - are we working with a video or music file....
videoTypes=(mp4 mov avi mkv wmv flv ogg m4p m4v 3gp divx h264)
audioTypes=(mp3 m4a aiff aac m4p wav wma flac)
# File extension mappings - ie - are we working with a video or music file?
videoTypes=(mp4 mov avi mkv wmv flv ogg m4p m4v 3gp divx h264)
audioTypes=(mp3 m4a aiff aac m4p wav wma flac)
function breakLoop() {
# Break the for loop when a user specifies a file from the CLI.
# Basically, this ensures that we only run the loop once for a single file.
if [[ -n "${userFile}" ]]; then
break
function identifyFiles() {
local item
local maxSearchDepth
local fileType
local fileMatch
# Assign user specified files
if [ -n "${userFile}" ]; then
filesToConvert+=("${userFile}")
fi
}
function outputDir() {
if $verbose; then v="-v" ; fi
if [[ -n "${saveDir}" ]]; then
if [[ -e "${saveDir}" && ! -d "${saveDir}" ]]; then
die "${saveDir} exists but is not a directory"
if [ -n "${args}" ]; then
filesToConvert+=("${args[@]}")
fi
if [[ ! -d "${saveDir}" ]]; then
seek_confirmation "${saveDir} does not exist. Create?"
if is_confirmed; then
mkdir $v "${saveDir}"
# Respect recursive file searches when requested
if ${recursive}; then
maxSearchDepth=4
else
die "Can't run without a place to save the files."
maxSearchDepth=1
fi
fi
# remove trailing slash if included. Add back to ensure it's always there.
outputDir="${saveDir%/}/" && verbose "outputDir=${saveDir%/}/"
fi
}
function identifyUserFile() {
# If a user specifies a single file type extension, respect it.
# Assign files based on MEDIATYPE extension
if [ -n "${MEDIATYPE}" ]; then
if [[ "${videoTypes[*]}" =~ "${MEDIATYPE}" ]]; then
videoTypes=($MEDIATYPE) # Reset the video type array to user-input, if specified
fi
if [[ "${audioTypes[*]}" =~ "${MEDIATYPE}" ]]; then
audioTypes=($MEDIATYPE) # Reset the audio type array to user-input, if specified
fi
fi
if [[ -n "${args}" ]]; then
userFile="${args}"
fi
if [[ -n "${userFile}" ]]; then
#test -f "${f}" # Ensure that what we've found is a file
extension="${userFile##*.}" # Grab file extension of input file
if [[ "${videoTypes[*]}" =~ "${extension}" ]]; then
userVideoFile="${userFile}"
fi
if [[ "${audioTypes[*]}" =~ "${extension}" ]]; then
userAudioFile="${userFile}"
fi
fi
}
function recursiveSearch() {
# Add matching items to array
while read item; do
recursiveFiles+=("${item}")
done < <(find . -name "*.${MEDIATYPE}" -type f -maxdepth 4)
filesToConvert+=("${item}")
done < <(find . -name "*.${MEDIATYPE}" -type f -maxdepth ${maxSearchDepth})
fi
for i in "${recursiveFiles[@]}"; do
userFile="${i}"
verbose "found item: ${userFile}"
recursiveDirectory=$(dirname "${userFile}")
recursiveDirectory="${recursiveDirectory#*/}"
saveDir="${recursiveDirectory}/"
runScript
# Figure out what to do if a user doesn't specify any files or input types
if [ ${#filesToConvert[@]} -eq 0 ]; then
notice "We couldn't find any files to act on."
seek_confirmation "Do you want to convert all VIDEO files?"
if is_confirmed; then
for fileType in "${videoTypes[@]}"; do
while read fileMatch; do
filesToConvert+=("${fileMatch}")
done < <(find . -name "*.${fileType}" -type f -maxdepth ${maxSearchDepth})
done
}
function userFormat() {
# Reads user input for format (-o, --output)
# Override defaults with CLI
if [ -n "$userOutput" ]; then
outputFormat="${userOutput,,}" #&& verbose "outputFormat=${outputFormat}"
fi
}
convertVideo() {
for vt in "${videoTypes[@]}"; do
for f in *."${vt}"; do
if [[ -n "${userVideoFile}" ]]; then
# Override the file search if user specifies a specific file from CLI.
f="${userVideoFile}"
fi
test -f "${f}" || continue # Ensure that what we've found is a file
extension="${f##*.}" # Grab file extension of input file
informationFile="${tmpDir}/${f////.}.json"
# JSON METADATA FOR EACH ASSET
######################################################################
verbose "Reading JSON and writing to TMP"
# Output a JSON file for each video asset being parsed.
ffprobe -v quiet -print_format json -show_format -show_streams "${f}" >> "${informationFile}"
# uncomment the line below for debugging. It will write a json file for each file in the source directory
# ffprobe -v quiet -print_format json -show_format -show_streams "${f}" >> "${f}.json"
# Read the necessary information from the JSON
format="$(jq -r ".format.format_long_name" "${informationFile}")"
formatName="$(jq -r ".format.format_name" "${informationFile}")"
if [[ $(jq -r ".streams[0].codec_type" "${informationFile}") == "video" ]]; then
videoHeight="$(jq -r ".streams[0].height" "${informationFile}")"
videoWidth="$(jq -r ".streams[0].width" "${informationFile}")"
videoCodec="$(jq -r '.streams[0].codec_name' "${informationFile}")"
videoCodecLong="$(jq -r ".streams[0].codec_long_name" "${informationFile}")"
elif [[ $(jq -r ".streams[1].codec_type" "${informationFile}") == "video" ]]; then
videoHeight="$(jq -r ".streams[1].height" "${informationFile}")"
videoWidth="$(jq -r ".streams[1].width" "${informationFile}")"
videoCodec="$(jq -r '.streams[1].codec_name' "${informationFile}")"
videoCodecLong="$(jq -r ".streams[1].codec_long_name" "${informationFile}")"
elif [[ $(jq -r ".streams[2].codec_type" "${informationFile}") == "video" ]]; then
videoHeight="$(jq -r ".streams[2].height" "${informationFile}")"
videoWidth="$(jq -r ".streams[2].width" "${informationFile}")"
videoCodec="$(jq -r '.streams[2].codec_name' "${informationFile}")"
videoCodecLong="$(jq -r ".streams[2].codec_long_name" "${informationFile}")"
else
warning "Missing video information for '"$f"'. Inspecting with 'ffprobe'."
ffprobe -v quiet -print_format json -show_format -show_streams "${f}"
safeExit
seek_confirmation "Do you want to convert all AUDIO files?"
if is_confirmed; then
for fileType in "${audioTypes[@]}"; do
while read fileMatch; do
filesToConvert+=("${fileMatch}")
done < <(find . -name "*.${fileType}" -type f -maxdepth ${maxSearchDepth})
done
fi
if [ $(jq -r ".streams[0].codec_type" "${informationFile}") == "audio" ]; then
audioCodec="$(jq -r '.streams[0].codec_name' "${informationFile}")"
audioCodecLong="$(jq -r ".streams[0].codec_long_name" "${informationFile}")"
audioSampleRate="$(jq -r ".streams[0].sample_rate" "${informationFile}")"
audioBitRate="$(jq -r ".streams[0].bit_rate" "${informationFile}")"
elif [ $(jq -r ".streams[1].codec_type" "${informationFile}") == "audio" ]; then
audioCodec="$(jq -r '.streams[1].codec_name' "${informationFile}")"
audioCodecLong="$(jq -r ".streams[1].codec_long_name" "${informationFile}")"
audioSampleRate="$(jq -r ".streams[1].sample_rate" "${informationFile}")"
audioBitRate="$(jq -r ".streams[1].bit_rate" "${informationFile}")"
elif [ $(jq -r ".streams[2].codec_type" "${informationFile}") == "audio" ]; then
audioCodec="$(jq -r '.streams[2].codec_name' "${informationFile}")"
audioCodecLong="$(jq -r ".streams[2].codec_long_name" "${informationFile}")"
audioSampleRate="$(jq -r ".streams[2].sample_rate" "${informationFile}")"
audioBitRate="$(jq -r ".streams[2].bit_rate" "${informationFile}")"
else
warning "Missing audio information for '"$f"'. Inspecting with 'ffprobe'."
ffprobe -v quiet -print_format json -show_format -show_streams "${f}"
fi
fi
# Error handling: Ensure the count of elements in ${filesToConvert[@]} is not zero.
if [ ${#filesToConvert[@]} -eq 0 ]; then
error "We couldn't find any files to act on. Exiting."
safeExit
fi
# SET OUTPUT FORMAT
# Default to 'mp4' for everything.
# TODO - think through additional defaults
##########################################################
# debug
verbose "filesToConvert=${filesToConvert[@]}"
}
function testFiles() {
# This function ensures that the specified files exist and can be converted
local extension
# Ensure we have a valid file
if [ ! -f "${fileToTest}" ]; then die "We can't find '${fileToTest}' or it is not valid."; fi
# Ensure the extension is known to this script
extension="${fileToTest##*.}" # Grab file extension of input file
# See if the extension is in the specified extension mappings
if [[ ! "${videoTypes[*]}" =~ "${extension}" ]] && [[ ! "${audioTypes[*]}" =~ "${extension}" ]]; then
error "The extension of '${extension} ' was not recognized."
die "We don't know what to do with ${fileToTest}."
fi
}
function convertToFormat() {
# Do things on video files
if [[ "${videoTypes[*]}" =~ "${file##*.}" ]]; then
# if you wanted a default target format for a specific input format,
# you would put it here.
# Set the default video conversion format to mp4
case "${format}" in
'Matroska / WebM') outputFormat='mp4' ;;
*) outputFormat='mp4' ;;
esac
fi
# Do things on audio files
if [[ "${audioTypes[*]}" =~ "${file##*.}" ]]; then
# Ensure a user sets an output format since we don't have a default.
if [[ -z ${userOutput} ]]; then
warning "Please specify an output audio format using '-o, --output'. Exiting"
safeExit
fi
# Confirm if a user wants to convert audio to it's own format
if [[ "${file##*.}" == "${userOutput}" ]]; then
warning "You are attempting to convert a ${file##*.} file to ${userOutput}."
seek_confirmation "Do you want to proceed?"
if is_not_confirmed; then
continue
fi
fi
fi
# Reads user input for format (-o, --output)
if [ -n "${userOutput}" ]; then
outputFormat="${userOutput,,}" #&& verbose "outputFormat=${outputFormat}"
fi
}
function parseJSON() {
local ii
local videoFoundFlag
local audioFoundFlag
local informationFile
# Create the temporary JSON file
informationFile="${tmpDir}/${file////}.json"
verbose "Reading audio data and writing JSON to tmp"
verbose "-> ${informationFile}"
# Output a JSON file for each video asset being parsed.
ffprobe -v quiet -print_format json -show_format -show_streams "${file}" >> "${informationFile}"
# Debugging: Uncomment either (or both) of these lines
# ffprobe -v quiet -print_format json -show_format -show_streams "${file}" >> "${file}.json"
# cat "${informationFile}"
# Read the necessary information from the JSON
format="$(jq -r ".format.format_long_name" "${informationFile}")"
formatName="$(jq -r ".format.format_name" "${informationFile}")"
jsonFilename="$(jq -r ".format.filename" "${informationFile}")"
formatBit_Rate="$(jq -r ".format.bit_rate" "${informationFile}")"
numStreams="$(jq -r ".format.nb_streams" "${informationFile}")"
# Iterate over results
ii=0
while [ ${ii} -lt ${numStreams} ]; do
if [[ $(jq -r --arg ii ${ii} ".streams[$ii | tonumber].codec_type" "${informationFile}") == "video" ]]; then
videoHeight="$(jq -r --arg ii ${ii} ".streams[$ii | tonumber].height" "${informationFile}")"
videoWidth="$(jq -r --arg ii ${ii} ".streams[$ii | tonumber].width" "${informationFile}")"
videoCodec="$(jq -r --arg ii ${ii} ".streams[$ii | tonumber].codec_name" "${informationFile}")"
videoCodecLong="$(jq -r --arg ii ${ii} ".streams[$ii | tonumber].codec_long_name" "${informationFile}")"
videoFoundFlag=true # Used for error handling to confirm we found a video stream
fi
if [ $(jq -r --arg ii ${ii} ".streams[$ii | tonumber].codec_type" "${informationFile}") == "audio" ]; then
audioCodec="$(jq -r --arg ii ${ii} ".streams[$ii | tonumber].codec_name" "${informationFile}")"
audioCodecLong="$(jq -r --arg ii ${ii} ".streams[$ii | tonumber].codec_long_name" "${informationFile}")"
audioSampleRate="$(jq -r --arg ii ${ii} ".streams[$ii | tonumber].sample_rate" "${informationFile}")"
audioBitRate="$(jq -r --arg ii ${ii} ".streams[$ii | tonumber].bit_rate" "${informationFile}")"
audioFoundFlag=true # Used for error handling to confirm we found an audio stream
fi
# Increase loop count
ii=$[$ii+1]
done
# Error Handling for video files
if [[ "${videoTypes[*]}" =~ "${file##*.}" ]]; then
if [ "${videoFoundFlag}" = "false" ]; then
warning "Missing video stream for '${file}'."
seek_confirmation "Inspect the file with ffprobe?"
if is_confirmed; then
ffprobe -v quiet -print_format json -show_format -show_streams "${file}"
safeExit
else
notice "Exiting"
safeExit
fi
fi
fi
# Error Handling for audio files
if [[ "${audioTypes[*]}" =~ "${file##*.}" ]]; then
if [ "${audioFoundFlag}" = "false" ]; then
warning "Missing audio stream for '${file}'."
seek_confirmation "Inspect the file with ffprobe?"
if is_confirmed; then
ffprobe -v quiet -print_format json -show_format -show_streams "${file}"
safeExit
else
notice "Exiting"
safeExit
fi
fi
fi
}
function convertVideo() {
verbose "Running 'convertVideo' function"
# SET AUDIO INFORMATION
# Copy audio in compatible formats. Re-encode audio when needed
@@ -271,9 +324,9 @@ convertVideo() {
# Pick the best aac audio encoder
if $(ffmpeg -version | grep enable-libfdk-aac >/dev/null); then
aacEncoder="libfdk_aac" && verbose "aac encoder set to libfdk_aac"
aacEncoder="libfdk_aac"
else
aacencoder="libfaac" && verbose "aac encoder set to libfaac"
aacencoder="libfaac"
fi
supportedAudioCodecs=(aac ac3 eac3)
@@ -289,13 +342,13 @@ convertVideo() {
################################################################
# Is input video a known preset size?
if [[ "$videoWidth" == "1920" && "$videoHeight" == "1080" ]] || [[ "$videoWidth" == "1920" && "$videoHeight" == "816" ]]; then
if [[ "${videoWidth}" == "1920" && "${videoHeight}" == "1080" ]] || [[ "${videoWidth}" == "1920" && "${videoHeight}" == "816" ]]; then
videoPreset="1080p" && verbose "Input video has preset: 1080p"
fi
if [[ "$videoWidth" == "1280" && "$videoHeight" == "720" ]] || [[ "$videoWidth" == "1280" && "$videoHeight" == "544" ]]; then
videoPreset="720p" && verbose "Input video has preset: 720p"
if [[ "${videoWidth}" == "1280" && "${videoHeight}" == "720" ]] || [[ "${videoWidth}" == "1280" && "$videoHeight" == "544" ]]; then
{videoPreset}="720p" && verbose "Input video has preset: 720p"
fi
if [[ "$videoWidth" == "720" && "$videoHeight" == "576" ]]; then
if [[ "${videoWidth}" == "720" && "${videoHeight}" == "576" ]]; then
videoPreset="DVPAL" && verbose "Input video has preset: DVPAL"
fi
@@ -320,8 +373,7 @@ convertVideo() {
if [[ "${videoPreset}" == "1080p" ]]; then
videoSize="hd720" && verbose "videoSize=hd720"
else
notice "Skipping ${f}. It's not 1080p"
breakLoop
notice "Skipping ${file}. It's not 1080p"
continue
fi
fi
@@ -332,14 +384,12 @@ convertVideo() {
# Don't resize videos to their same size
if [[ "${videoSize}" == "hd720" ]] || [[ "${videoSize}" == "720" || "${videoSize}" == "1280x720" ]]; then
if [[ "$videoPreset" == "720p" ]]; then
notice ""${f}" is already 720p. Skipping...."
breakLoop
notice "${file} is already 720p. Skipping...."
continue
fi
elif [[ "${videoSize}" == "hd1080" || "${videoSize}" == "1080" || "${videoSize}" == "1920x1080" ]]; then
if [[ "$videoPreset" == "1080p" ]]; then
notice ""${f}" is already 1080p. Skipping...."
breakLoop
notice "${file} is already 1080p. Skipping...."
continue
fi
fi
@@ -356,9 +406,8 @@ convertVideo() {
userWidth=$(echo ${videoSize} | cut -f1 -dx)
userHeight=$(echo ${videoSize} | cut -f2 -dx)
if [ "${userWidth}" -gt "${videoWidth}" ] || [ "${userHeight}" -gt "${videoHeight}" ]; then
seek_confirmation "Upscale "${f}" to "${videoSize}"? It is already "${videoWidth}"x"${videoHeight}"."
seek_confirmation "Upscale "${file}" to "${videoSize}"? It is already "${videoWidth}"x"${videoHeight}"."
if is_not_confirmed; then
breakLoop
continue
fi
fi
@@ -370,21 +419,19 @@ convertVideo() {
# Scaling variables
# ####################################
if is_not_empty "$height"; then
if is_not_empty "${height}"; then
if [ "${height}" -gt "${videoHeight}" ]; then
seek_confirmation "Upscale "${f}" to height "${height}"? It is already "${videoWidth}"x"${videoHeight}"."
seek_confirmation "Upscale "${file}" to height "${height}"? It is already "${videoWidth}"x"${videoHeight}"."
if is_not_confirmed; then
breakLoop
continue
fi
fi
videoResize="-vf scale=-1:${height}" && verbose "videoResize='-vf scale=-1:${height}'"
fi
if is_not_empty "$width"; then
if is_not_empty "${width}"; then
if [ "${width}" -gt "${videoWidth}" ]; then
seek_confirmation "Upscale "${f}" to width "${width}"? It is already "${videoWidth}"x"${videoHeight}"."
seek_confirmation "Upscale "${file}" to width "${width}"? It is already "${videoWidth}"x"${videoHeight}"."
if is_not_confirmed; then
breakLoop
continue
fi
fi
@@ -400,88 +447,16 @@ convertVideo() {
videoCommand="-c:v libx264 -crf 18 -preset slow" && verbose "videoCommand'-c:v libx264 -crf 18 -preset slow'"
fi
# Do the conversion
# ##########################
# Don't convert to self if no other options set
if [[ -z $height && -z $width && -z $videoSize && $downsize720 == "0" && "$outputFormat" == "$extension" ]]; then
warning "Can't convert a '"${extension}"' to itself. Skipping all '"${extension}"' files."
break
fi
doConvert # Invoke FFMpeg
# Unset variables
unset videoCodec
unset videoCodecLong
unset format
unset formatName
unset videoHeight
unset videoWidth
unset videoPreset
unset audioCodec
unset audioCodecLong
unset audioSampleRate
unset audioBitRate
breakLoop
done
breakLoop
done
}
convertMusic() {
for mt in "${audioTypes[@]}"; do
for f in *."${mt}"; do
if [[ -n "${userAudioFile}" ]]; then # TODO: Rewrite user video files and write function to detect user video or music
# Override the file search if user specifies a specific file from CLI.
f="${userAudioFile}"
fi
test -f "${f}" || continue # Ensure that what we've found is a file
extension="${f##*.}" # Grab file extension of input file
informationFile="${tmpDir}/${f////.}.json"
# For audio files, ensure that the user specifies an output format
if [[ -z ${userOutput} ]]; then
die "Please specify an output audio format using '-o, --output'"
fi
# JSON METADATA FOR EACH ASSET
######################################################################
verbose "Reading audio data and writing JSON to tmp"
# Output a JSON file for each video asset being parsed.
ffprobe -v quiet -print_format json -show_format -show_streams "${f}" >> "${informationFile}"
# uncomment the line below for debugging. It will write a json file for each file in the source directory
# ffprobe -v quiet -print_format json -show_format -show_streams "${f}" >> "${f}.json"
# Read the necessary information from the JSON
format="$(jq -r ".format.format_long_name" "${informationFile}")"
formatName="$(jq -r ".format.format_name" "${informationFile}")"
formatBit_Rate="$(jq -r ".format.bit_rate" "${informationFile}")"
if [[ $(jq -r ".streams[0].codec_type" "${informationFile}") == "audio" ]]; then
audioCodec="$(jq -r '.streams[0].codec_name' "${informationFile}")"
audioCodecLong="$(jq -r ".streams[0].codec_long_name" "${informationFile}")"
audioSampleRate="$(jq -r ".streams[0].sample_rate" "${informationFile}")"
audioBitRate="$(jq -r ".streams[0].bit_rate" "${informationFile}")"
elif [[ $(jq -r ".streams[1].codec_type" "${informationFile}") == "audio" ]]; then
audioCodec="$(jq -r '.streams[1].codec_name' "${informationFile}")"
audioCodecLong="$(jq -r ".streams[1].codec_long_name" "${informationFile}")"
audioSampleRate="$(jq -r ".streams[1].sample_rate" "${informationFile}")"
audioBitRate="$(jq -r ".streams[1].bit_rate" "${informationFile}")"
elif [[ $(jq -r ".streams[2].codec_type" "${informationFile}") == "audio" ]]; then
audioCodec="$(jq -r '.streams[2].codec_name' "${informationFile}")"
audioCodecLong="$(jq -r ".streams[2].codec_long_name" "${informationFile}")"
audioSampleRate="$(jq -r ".streams[2].sample_rate" "${informationFile}")"
audioBitRate="$(jq -r ".streams[2].bit_rate" "${informationFile}")"
else
warning "Missing audio information for '"$f"'. Inspect with 'ffprobe'."
ffprobe -v quiet -print_format json -show_format -show_streams "${f}"
safeExit
if [[ -z ${height} && -z ${width} && -z ${videoSize} && ${downsize720} == "0" && "${outputFormat}" == "${file##*.}" ]]; then
error "Can't convert a '"${file##*.}"' file to itself. Skipping ${file}"
continue
fi
}
function convertAudio() {
verbose "Running 'convertAudio' function"
# note on XLD: If you have XLD installed and configured, lossless audio conversion
# will be run using built-in XLD profiles. You can disable this by
# changing ensuring that XLD=0 in sections below.
@@ -529,7 +504,6 @@ convertMusic() {
mp3Encoder='libmp3lame' && verbose "mp3Encoder = libmp3lame"
else
warning "No workable ffmpeg mp3 encoder. Skipping ${f}..."
breakLoop
continue
fi
# Take user specified bitrate
@@ -541,55 +515,68 @@ convertMusic() {
audioConvertCommand="-acodec ${mp3Encoder} -qscale:a 0" && verbose "audioConvertCommand = -acodec ${mp3Encoder} -qscale:a 0"
fi
else
die "Unknown audio conversion format: ${outputFormat}"
die "Unknown audio conversion format: '${outputFormat}'."
fi
}
function setOutputDirectory() {
if ${verbose}; then v="-v" ; fi
# Do the conversion
# ##########################
# Use the user's specified directory to save the new file in if specified.
# default to use the location of the original file.
if [[ -n "${saveDir}" ]]; then
if [[ -e "${saveDir}" && ! -d "${saveDir}" ]]; then
die "${saveDir} exists but is not a directory"
fi
if [[ ! -d "${saveDir}" ]]; then
seek_confirmation "${saveDir} does not exist. Create?"
if is_confirmed; then
mkdir ${v} "${saveDir}"
else
die "Can't run without a place to save the files."
fi
fi
# remove trailing slash if included. Add back to ensure it's always there.
outputDir="${saveDir%/}/"
else
outputDir=$(dirname "${file}")
outputDir="${outputDir#*/}"
outputDir="${outputDir%/}/"
fi
}
doConvert # Run the conversion function
function setOutputFile() {
# Unset variables
unset format
unset formatName
unset audioCodec
unset audioCodecLong
unset audioSampleRate
unset audioBitRate
breakLoop
done
breakLoop
done
}
function doConvert() {
# Set the output name, format, and directory
# ###############################################
if $verbose; then v="-v" ; fi
# This function creates the name of new file to be generated by the conversion
# ##################
# Set output filename
output="$(basename "${f%.*}").$outputFormat" && verbose "output="${output}""
# Add user's output save directory if used
if [[ -n "${outputDir}" ]]; then
verbose "outputDir=${outputDir}"
output="${outputDir}${output}" && verbose "output=${outputDir}${output}"
fi
output="$(basename "${file%.*}").${outputFormat}"
# Add the output directory
output="${outputDir}${output}"
# Confirm we're not overwriting an existing file
if [[ "${safeRun}" -ne "1" ]]; then
# If we are, append '.new' to the name
fileFlag=0
while [[ fileFlag -eq 0 ]]; do
if [ -e "${output}" ]; then
# rename the new file to '.new'
output="$(basename "${f%.*}").new."${outputFormat}"" && verbose "Adding '.new' to the new file name"
if [[ -n "${outputDir}" ]]; then
output="${outputDir}${output}" && verbose "output=${outputDir}${output}"
fi
fi
# output="$(basename "${file%.*}").new."${outputFormat}""
output="$(basename "${output%.*}").new.${outputFormat}"
# Add the directory back to the file
output="${outputDir}${output}"
# Set a flag so that we can rename this file back to the original name if
# a user elects to delete the original file
newFileFlag=true
else
fileFlag=1
fi
done
verbose "new file name will be: ${output}"
}
function doConvert() {
if ${verbose}; then v="-v" ; fi
# Respect the 'Quiet' flag
if "${quiet}"; then
@@ -598,79 +585,98 @@ function doConvert() {
fi
# Respect the 'logfile' flag
if ${printLog}; then
ffmpegLog=">> ${logFile}"
fi
# Invoke the conversion
# ##################################
if ${printLog}; then ffmpegLog=">> ${logFile}"; fi
# Use XLD for audio file conversion if available
if [[ "$XLD" == "1" ]]; then
verbose "Running XLD commands for audio. No FFMPEG"
if [[ "${XLD}" == "1" ]]; then
verbose "Running XLD commands for audio. No FFMPEG."
# Respect --safe flag.
if [[ "${safeRun}" == "1" ]]; then
notice "xld -o "${output}" ${audioConvertCommand} "${f}""
notice "xld -o "${output}" ${audioConvertCommand} "${file}""
else
verbose "xld -o "${output}" ${audioConvertCommand} "${f}""
xld -o "${output}" ${audioConvertCommand} "${f}"
deleteOriginalFile
verbose "xld -o "${output}" ${audioConvertCommand} "${file}""
xld -o "${output}" ${audioConvertCommand} "${file}"
fi
else # Use ffmpeg when XLD is set to 0
# Respect --safe flag.
if [[ "${safeRun}" == "1" ]]; then
notice "ffmpeg -i "${f}" ${videoResize} ${videoCommand} ${videoAudioCommand} ${audioConvertCommand} "${output}" ${ffquiet}"
notice "ffmpeg -i "${file}" ${videoResize} ${videoCommand} ${videoAudioCommand} ${audioConvertCommand} "${output}" ${ffquiet}"
else
verbose "ffmpeg -i "${f}" ${videoResize} ${videoCommand} ${videoAudioCommand} ${audioConvertCommand} "${output}" ${ffquiet}"
ffmpeg -i "${f}" ${videoResize} ${videoCommand} ${videoAudioCommand} ${audioConvertCommand} "${output}" ${ffquiet}
deleteOriginalFile
verbose "ffmpeg -i "${file}" ${videoResize} ${videoCommand} ${videoAudioCommand} ${audioConvertCommand} "${output}" ${ffquiet}"
ffmpeg -i "${file}" ${videoResize} ${videoCommand} ${videoAudioCommand} ${audioConvertCommand} "${output}" ${ffquiet}
fi
fi
}
# Unset variables to get ready for the next file
unset jsonFilename
unset formatBit_Rate
unset numStreams
unset videoCodec
unset videoCodecLong
unset format
unset formatName
unset videoHeight
unset videoWidth
unset videoPreset
unset audioCodec
unset audioCodecLong
unset audioSampleRate
unset audioBitRate
}
function deleteOriginalFile() {
function deleteOriginalFile() {
local f
local newFile
if ${verbose}; then v="-v" ; fi
if [[ "${safeRun}" == "0" ]]; then
if ${deleteOriginal}; then
rm -f $v "${f}"
#remove '.new' from filename
if [[ -n "${outputDir}" ]]; then
for file in "${outputDir}*.new.*"; do
rename $v 's/.new//g' "${file}"
done
else
for file in *.new.*; do
rename $v 's/.new//g' "${file}"
done
rm -f ${v} "${file}"
mv ${v} "${output}" "${outputDir}${file}"
fi
fi
}
## RUN THE SCRIPT ##
####################################
# First we need to identify the files to be converted
identifyFiles
# Then we test that all files can be operated upon
for fileToTest in "${filesToConvert[@]}"; do testFiles; done
# Then we work on the individual files. This is the fun part.
for file in "${filesToConvert[@]}"; do
info "Working on ${file}"
# First we grab the metadata of the file and assign it to variables
parseJSON
# Then we set the expected output format
convertToFormat
# Then we set the appropriate conversion commands
if [[ "${videoTypes[*]}" =~ "${file##*.}" ]]; then convertVideo; fi
if [[ "${audioTypes[*]}" =~ "${file##*.}" ]]; then convertAudio; fi
# Then we tell the script where to output the file
setOutputDirectory
# Then we generate the name for the new file
setOutputFile
# Then we actually do the conversion
doConvert
# Then we delete the original file (if requested)
deleteOriginalFile
done
####################################################
############### End Script Here ####################
}
runScript() {
# All functions within the script are here
identifyUserFile
userFormat
outputDir
convertVideo
convertMusic
}
# Run the functions
if ${recursive}; then
recursiveSearch # Run the recursive search function
else
runScript
fi
####################################################
############### End Script Here ####################
}
############## Begin Options and Usage ###################
# Print usage
usage() {
echo -n "${scriptName} ${version} [OPTION]... [ARGUMENT]...
# Print usage
echo -n "${scriptName} ${version} [OPTION]... [ARGUMENT]...
${bold}DESCRIPTION${reset}
This is a media conversion script which converts audio and video into many
@@ -740,10 +746,10 @@ Convert a Windows Media file (file.wmv) to h264 (mp4).
$ convertMedia -o mp4 file.wmv
Do a recursive search for all directories beneath the current one. In each
directory, search for .avi iles and convert them to .mp4
$ convertMedia --recursive -o mp4 -i avi
directory, search for .avi files and convert them to .mp4
"
$ convertMedia -o mp4 -i avi --recursive
"
}
# Iterate over options breaking -ab into -a -b when needed and --foo=bar into
@@ -784,11 +790,12 @@ unset options
# Print help if no arguments were passed.
# Uncomment to force arguments when invoking the script
[[ $# -eq 0 ]] && set -- "--help"
# [[ $# -eq 0 ]] && set -- "--help"
# Read the options and set stuff
while [[ $1 = -?* ]]; do
case $1 in
while [[ ${1} = -?* ]]; do
case ${1} in
-f|--file) shift; userFile="$1" ;;
-i|--input) shift; MEDIATYPE="$1" ;;
-o|--output) shift; userOutput="$1" ;;
@@ -817,11 +824,6 @@ done
# Store the remaining part as arguments.
args+=("$@")
############## End Options and Usage ###################
# ############# ############# #############
# ## TIME TO RUN THE SCRIPT ##
# ## ##
@@ -834,7 +836,7 @@ args+=("$@")
trap trapCleanup EXIT INT TERM
# Set IFS to preferred implementation
#IFS=$'\n\t'
IFS=$' \n\t'
# Exit on error. Append '||true' when you run the script if you expect an error.
set -o errexit
@@ -849,8 +851,11 @@ if ${strict}; then set -o nounset ; fi
# This way you can catch the error in case mysqldump fails in `mysqldump |gzip`, for example.
set -o pipefail
checkDependencies # Invoke the checkDependenices function to test for Bash packages
# Invoke the checkDependenices function to test for Bash packages. Uncomment if needed.
checkDependencies
mainScript # Run your script
# Run your script
mainScript
safeExit # Exit cleanly
# Exit cleanly
safeExit