Release 2.2

- Switch to hybrid S6
- **Added --regex option** TheCaptain989/lidarr-flac2mp3#33
- **Added optional use of environment variable** TheCaptain989/lidarr-flac2mp3#33
- **Added new --tags option to resolve TheCaptain989/lidarr-flac2mp3#15**
- Added checks for identical track name
- Recycled files are now moved to subdirectory paths that more closely resemble the original path
- Better error handling in awk script when calling system commands
- Added logging for skipped tracks
- Corrected some logging anomalies
- Modified exit codes
- Updated command line help
- Fixed missing executable attribute on some script files
- Updated README
This commit is contained in:
TheCaptain989
2022-11-27 09:56:09 -06:00
parent a5b136d992
commit 64b36034ee
7 changed files with 313 additions and 100 deletions
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
. /usr/local/bin/flac2mp3.sh --tags disc,genre
+221 -65
View File
@@ -7,6 +7,7 @@
# Dependencies:
# ffmpeg
# ffprobe
# awk
# curl
# jq
@@ -18,7 +19,7 @@
# Exit codes:
# 0 - success; or test
# 1 - no audio file specified on command line
# 1 - no audio tracks detected
# 2 - ffmpeg not found
# 3 - invalid command line arguments
# 5 - specified audio file not found
@@ -48,20 +49,21 @@ Audio conversion script designed for use with Lidarr
Source: https://github.com/TheCaptain989/lidarr-flac2mp3
Usage:
$0 [OPTIONS] [-b <bitrate> | -v <quality> | -a \"<options>\" -e <extension>]
$0 [OPTIONS] {-f|--file} <audio_file>
$0 [{-d|--debug} [<level>]] [{-b|--bitrate} <bitrate> | {-v|--quality} <quality> | {-a|--advanced} \"<options>\" {-e|--extension} <extension>] [{-f|--file} <audio_file>] [{-k|--keepfile}] [{-o|--output} <directory>] [{-r|--regex} '<regex>'] [{-t|--tags} <taglist>]
Options:
-d, --debug [<level>] enable debug logging
Level is optional, default of 1 (low)
-b, --bitrate <bitrate> set output quality in constant bits per second
-d, --debug [<level>] Enable debug logging
level is optional, between 1-3
1 is lowest, 3 is highest
[default: 1]
-b, --bitrate <bitrate> Set output quality in constant bits per second
[default: 320k]
Ex: 160k, 240k, 300000
-v, --quality <quality> set variable bitrate; quality between 0-9
-v, --quality <quality> Set variable bitrate; quality between 0-9
0 is highest quality, 9 is lowest
For more details, see:
https://trac.ffmpeg.org/wiki/Encode/MP3
-a, --advanced \"<options>\" advanced ffmpeg options enclosed in quotes
-a, --advanced \"<options>\" Advanced ffmpeg options enclosed in quotes
Specified options replace all script defaults
and are sent as entered to ffmpeg for
processing.
@@ -73,32 +75,40 @@ Options:
Requires -e option to also be specified
For more details, see:
https://github.com/TheCaptain989/lidarr-flac2mp3
-e, --extension <extension> file extension for output file, with or without
-e, --extension <extension> File extension for output file, with or without
dot
Required when -a is specified!
-f, --file <audio_file> the script enters batch mode, using the
-f, --file <audio_file> The script enters batch mode, using the
specified audio file as input
WARNING: Do not use this argument when called
from Lidarr!
-o, --output <directory> specify a directory for the converted audio
file(s)
This will be created if it does not exist.
-k, --keep-file do not delete the source file or move it to the
-o, --output <directory> Specify a destination directory for the
converted audio file(s)
It will be created if it does not exist.
-k, --keep-file Do not delete the source file or move it to the
Lidarr Recycle bin
This also disables the Lidarr rescan.
--help display this help and exit
--version display script version and exit
-r, --regex '<regex>' Regular expression used to select input files
[default: \.flac$]
-t, --tags <taglist> Comma separated list of metadata tags to apply
automated corrections to.
Supports: disc, genre
--help Display this help and exit
--version Display script version and exit
Examples:
$flac2mp3_script -b 320k # Output 320 kbit/s MP3 (non-VBR; same as
default behavior)
$flac2mp3_script -v 0 # Output variable bitrate MP3, VBR 220-260
kbit/s
$flac2mp3_script -d -b 160k # Enable debugging level 1 and set output a
$flac2mp3_script -d -b 160k # Enable debugging level 1 and output a
160 kbit/s MP3
$flac2mp3_script -a \"-vn -c:a libopus -b:a 192K\" -e .opus
# Convert to Opus format, VBR 192 kbit/s, no
cover art
$flac2mp3_script -r '\\\\.[^.]*$' # Convert any file to MP3 (not just FLAC)
$flac2mp3_script -a \"-c:v libtheora -map 0 -q:v 10 -c:a libopus -b:a 192k\" -e .opus
# Convert to Opus format, 192 kbit/s, cover art
$flac2mp3_script -a \"-vn -c:a libopus -b:a 192K\" -e .opus -r '\.mp3$'
# Convert .mp3 files to Opus format, 192 kbit/s
no cover art
$flac2mp3_script -a \"-y -map 0 -c:a aac -b:a 240K -c:v copy\" -e mp4
# Convert to MP4 format, using AAC 240 kbit/s
audio, cover art, overwrite file
@@ -107,12 +117,23 @@ Examples:
Output 320 kbit/s MP3
$flac2mp3_script -o \"/path/to/audio\" -k
# Place the converted file(s) in specified
directory and do not delete the original audio
file(s).
directory and do not delete the original
audio file(s)
"
echo "$usage" >&2
}
# Check for environment variable arguments
if [ -n "$FLAC2MP3_ARGS" ]; then
if [ $# -ne 0 ]; then
flac2mp3_prelogmessage="Warning|FLAC2MP3_ARGS environment variable set but will be ignored because command line arguments were also specified."
else
# Move the environment variable arguments to the command line for processing
flac2mp3_prelogmessage="Info|Using settings from environment variable."
eval set -- "$FLAC2MP3_ARGS"
fi
fi
# Process arguments
while (( "$#" )); do
case "$1" in
@@ -142,7 +163,7 @@ while (( "$#" )); do
else
echo "Error|Invalid option: $1 requires an argument." >&2
usage
exit 1
exit 3
fi
;;
-b|--bitrate ) # Set constant bit rate
@@ -220,13 +241,33 @@ while (( "$#" )); do
usage
exit 3
fi
# Test for trailing slash
# Test for trailing backslash
[ "${flac2mp3_output: -1:1}" != "/" ] && flac2mp3_output="${flac2mp3_output}/"
;;
-k|--keep-file ) # Do not delete source file(s)
export flac2mp3_keep=1
shift
;;
-r|--regex ) # Sets the regex used to match input files
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
export flac2mp3_regex="$2"
shift 2
else
echo "Error|Invalid option: $1 requires an argument." >&2
usage
exit 3
fi
;;
-t|--tags ) # Metadata tags to correct
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
export flac2mp3_tags="$2"
shift 2
else
echo "Error|Invalid option: $1 requires an argument." >&2
usage
exit 3
fi
;;
-*|--*=) # Unknown option
echo "Error|Unknown option: $1" >&2
usage
@@ -258,7 +299,7 @@ elif [[ "${flac2mp3_type,,}" = "lidarr" ]]; then
[ -z "$flac2mp3_tracks" ] && flac2mp3_tracks="$lidarr_trackfile_path"
else
# Called in an unexpected way
echo -e "Error|Unknown or missing 'lidarr_eventtype' environment variable: ${flac2mp3_type}\nNot called within Lidarr.\nTry using Batch Mode option: -f <file>"
echo -e "Error|Unknown or missing 'lidarr_eventtype' environment variable: ${flac2mp3_type}\nNot called from Lidarr.\nTry using Batch Mode option: -f <file>"
exit 7
fi
@@ -323,7 +364,7 @@ function check_rescan {
else
# It may have timed out, so let's wait a second
local flac2mp3_return=1
[ $flac2mp3_debug -ge 1 ] && echo "Debug|Job not done. Waiting 1 second." | log
[ $flac2mp3_debug -ge 1 ] && echo "Debug|Job not done. Waiting 1 second." | log
sleep 1
fi
fi
@@ -339,12 +380,25 @@ if [ ! -f "/usr/bin/ffmpeg" ]; then
echo "$flac2mp3_message" >&2
exit 2
fi
if [ ! -f "/usr/bin/ffprobe" ]; then
flac2mp3_message="Error|/usr/bin/ffprobe is required by this script"
echo "$flac2mp3_message" | log
echo "$flac2mp3_message" >&2
exit 2
fi
# Log Debug state
if [ $flac2mp3_debug -ge 1 ]; then
flac2mp3_message="Debug|Enabling debug logging level ${flac2mp3_debug}. Starting ${lidarr_eventtype^} run."
echo "$flac2mp3_message" | log
echo "$flac2mp3_message" >&2
echo "$flac2mp3_message"
fi
# Log FLAC2MP3_ARGS usage
if [ -n "$flac2mp3_prelogmessage" ]; then
# flac2mp3_prelogmessage is set above, before argument processing
echo "$flac2mp3_prelogmessage" | log
[ $flac2mp3_debug -ge 1 ] && echo "Debug|FLAC2MP3_ARGS: ${FLAC2MP3_ARGS}" | log
fi
# Log environment
@@ -393,15 +447,32 @@ elif [ -f "$flac2mp3_config" ]; then
-H "Content-Type: application/json" \
-X GET "$flac2mp3_api_url/config/mediamanagement")
flac2mp3_return=$?; [ "$flac2mp3_return" != 0 ] && {
flac2mp3_message="Error|[$flac2mp3_return] curl error when parsing: \"$flac2mp3_api_url/v3/config/mediamanagement\""
flac2mp3_message="Error|[$flac2mp3_return] curl error when parsing: \"$flac2mp3_api_url/config/mediamanagement\""
echo "$flac2mp3_message" | log
echo "$flac2mp3_message" >&2
}
[ $flac2mp3_debug -ge 2 ] && echo "API returned: $flac2mp3_result" | awk '{print "Debug|"$0}' | log
flac2mp3_recyclebin="$(echo $flac2mp3_result | jq -crM .recycleBin)"
# Test for trailing backslash
[ "${flac2mp3_recyclebin: -1:1}" != "/" ] && flac2mp3_recyclebin="${flac2mp3_recyclebin}/"
[ $flac2mp3_debug -ge 1 ] && echo "Debug|Detected Lidarr RecycleBin '$flac2mp3_recyclebin'" | log
# Get root folder path from Artist info
if [ "$lidarr_artist_id" != "" ]; then
flac2mp3_result=$(curl -s -H "X-Api-Key: $flac2mp3_apikey" \
-H "Content-Type: application/json" \
-X GET $flac2mp3_api_url/artist/$lidarr_artist_id)
flac2mp3_return=$?; [ "$flac2mp3_return" != 0 ] && {
flac2mp3_message="Error|[$flac2mp3_return] curl error when parsing: \"$flac2mp3_api_url/artist/$lidarr_artist_id\""
echo "$flac2mp3_message" | log
echo "$flac2mp3_message" >&2
}
[ $flac2mp3_debug -ge 2 ] && echo "API returned: $flac2mp3_result" | awk '{print "Debug|"$0}' | log
flac2mp3_root="$(echo $flac2mp3_result | jq -crM .rootFolderPath)"
[ $flac2mp3_debug -ge 1 ] && echo "Debug|Detected Lidarr Root Folder '$flac2mp3_root'" | log
fi
else
# No config file means we can't call the API. Best effort at this point.
# No config file means we can't call the API. Best effort at this point.
flac2mp3_message="Warn|Unable to locate Lidarr config file: '$flac2mp3_config'"
echo "$flac2mp3_message" | log
echo "$flac2mp3_message" >&2
@@ -412,7 +483,7 @@ if [[ "$lidarr_eventtype" = "Test" ]]; then
echo "Info|Lidarr event: $lidarr_eventtype" | log
flac2mp3_message="Info|Script was test executed successfully."
echo "$flac2mp3_message" | log
echo "$flac2mp3_message" >&2
echo "$flac2mp3_message"
exit 0
fi
@@ -424,12 +495,20 @@ if [ "$flac2mp3_type" = "batch" -a ! -f "$flac2mp3_tracks" ]; then
exit 5
fi
# Check for empty track variable
if [ -z "$flac2mp3_tracks" ]; then
flac2mp3_message="Error|No audio tracks were detected or specified!"
echo "$flac2mp3_message" | log
echo "$flac2mp3_message" >&2
exit 1
fi
# If specified, check if destination folder exists and create if necessary
if [ "$flac2mp3_output" -a ! -d "$flac2mp3_output" ]; then
[ $flac2mp3_debug -ge 1 ] && echo "Debug|Destination directory does not exist. Creating: $flac2mp3_output" | log
[ $flac2mp3_debug -ge 1 ] && echo "Debug|Destination directory does not exist. Creating: $flac2mp3_output" | log
mkdir -p "$flac2mp3_output"
flac2mp3_return=$?; [ "$flac2mp3_return" != 0 ] && {
flac2mp3_message="Error|[$flac2mp3_return] mkdir returned an error. Unable to create output directory."
flac2mp3_message="Error|[$flac2mp3_return] mkdir returned an error. Unable to create output directory."
echo "$flac2mp3_message" | log
echo "$flac2mp3_message" >&2
exit 6
@@ -456,6 +535,9 @@ fi
if [ $flac2mp3_keep = 1 ]; then
flac2mp3_message+=", Keep source"
fi
if [ -n "$flac2mp3_regex" ]; then
flac2mp3_message+=", Matching regex: '${flac2mp3_regex}'"
fi
flac2mp3_message+=", Track(s): ${flac2mp3_tracks}"
echo "${flac2mp3_message}" | log
@@ -465,67 +547,141 @@ echo -n "$flac2mp3_tracks" | awk -v Debug=$flac2mp3_debug \
-v Bitrate="$flac2mp3_bitrate" \
-v VBR="$flac2mp3_vbrquality" \
-v FFmpegADV="$flac2mp3_ffmpegadv" \
-v EXT="$flac2mp3_extension" \
-v Ext="$flac2mp3_extension" \
-v Output="$flac2mp3_output" \
-v Keep="$flac2mp3_keep" '
-v Keep=$flac2mp3_keep \
-v Pat="$flac2mp3_regex" \
-v Root="$flac2mp3_root" \
-v Taglist="$flac2mp3_tags" '
BEGIN {
FFmpeg="/usr/bin/ffmpeg"
FS="|"
RS="|"
IGNORECASE=1
if (EXT == "") EXT=".mp3"
if (Debug == 0) FFmpegLOG="error"
else if (Debug == 1) FFmpegLOG="warning"
else if (Debug >= 2) FFmpegLOG="info"
FFmpeg = "/usr/bin/ffmpeg"
FS = "|"
RS = "|"
IGNORECASE = 1
# Set default extension, pattern, and logging values
if (Ext == "") Ext = ".mp3"
if (Pat == "") Pat = "\\.flac$"
if (Debug == 0) FFmpegLOG = "error"
else if (Debug == 1) FFmpegLOG = "warning"
else if (Debug >= 2) FFmpegLOG = "info"
if (Bitrate) {
if (Debug >= 1) print "Debug|Using constant bitrate of "Bitrate
BrCommand="-b:a "Bitrate
BrCommand = "-b:a "Bitrate
} else if (VBR >= 0) {
if (Debug >= 1) print "Debug|Using variable quality of "VBR
BrCommand="-q:a "VBR
BrCommand = "-q:a "VBR
} else if (FFmpegADV) {
if (Debug >= 1) print "Debug|Using advanced ffmpeg options: \""FFmpegADV"\""
if (Debug >= 1) print "Debug|Exporting with file extension "EXT
if (Debug >= 1) print "Debug|Using advanced ffmpeg options \""FFmpegADV"\""
if (Debug >= 1) print "Debug|Exporting with file extension \""Ext"\""
FFmpegOPTS = FFmpegADV
}
if (Debug >= 1) print "Debug|Matching tracks against regex \""Pat"\""
# Set default ffmpeg options
if (FFmpegOPTS == "") FFmpegOPTS = "-c:v copy -map 0 -y -acodec libmp3lame "BrCommand" -write_id3v1 1 -id3v2_version 3"
}
/\.flac$/ {
# Get each FLAC file name and create a new MP3 (or other) name
Track=$1
NewTrack=substr(Track, 1, length(Track)-5) EXT
$0 !~ Pat {
if (Debug >= 1) print "Debug|Skipping track that did not match regex: "$0
}
$0 ~ Pat {
# Get each audio file name and create a new track name with the given extension
Track = $0
Last = split(Track, Parts, ".")
NewTrack = substr(Track, 1, length(Track) - length(Parts[Last]) - 1) Ext
# Redirect output if asked
if (Output) sub(/^.*\//,Output ,NewTrack)
if (Output) sub(/^.*\//, Output, NewTrack)
# Check for same track name
if (Track == NewTrack) {
print "Error|The original track name and new name are the same! Skipping track: "Track
next
}
# Set metadata options to fix tags if asked
if (Taglist) {
Metadata = ""; JSON = ""
NumTags = split(Taglist, Tag, ",")
if (Debug >= 1) print "Debug|Detecting and fixing common problems with the following metadata tags: "Taglist
Command = "/usr/bin/ffprobe -hide_banner -loglevel fatal -print_format json=compact=1 -show_format -show_entries \"format=tags : format_tags=disc,genre\" -i \""Track"\" 2>&1"
if (Debug >= 2) print "Debug|Executing: "Command
# Concatenate FFprobe output into one line
while (Command | getline Line) JSON = JSON Line
for (i = 1; i <= NumTags; i++) {
if (Tag[i] == "disc") {
# Fix one disc by itself (\47 is single quote in octal)
Command = "echo \47"JSON"\47 | jq -crM \47.format.tags.disc\47 2>&1"
if (Debug >= 2) print "Debug|Executing: "Command
Command | getline Disc
sub(/\n/, "", Disc) # I do not yet know why this is needed
if (Debug >= 1) print "Debug|Discovered disc: "Disc
if (Disc ~ /^1$/) Metadata = "-metadata disc=\"1/1\" "Metadata
}
if (Tag[i] == "genre") {
# Fix multiple genres
Command = "echo \47"JSON"\47 | jq -crM \47.format.tags | to_entries[] | select(.key | match(\"genre\";\"i\")).value\47 2>&1"
if (Debug >= 2) print "Debug|Executing: "Command
Command | getline Genre
sub(/\n/, "", Genre) # I do not yet know why this is needed
if (Debug >= 1) print "Debug|Discovered genre: "Genre
if (Genre ~ /;/) {
if (Genre ~ /Pop/) Metadata = "-metadata genre=\"Pop\" "Metadata
else if (Genre ~ /Indie/) Metadata = "-metadata genre=\"Alternative & Indie\" "Metadata
else if (Genre ~ /Industrial/) Metadata = "-metadata genre=\"Industrial Rock\" "Metadata
else if (Genre ~ /Electronic/) Metadata = "-metadata genre=\"Electronica & Dance\" "Metadata
else if (Genre ~ /Punk|Alternative/) Metadata = "-metadata genre=\"Alternative & Punk\" "Metadata
else if (Genre ~ /Rock/) Metadata = "-metadata genre=\"Rock\" "Metadata
}
}
if (Debug >= 2) print "Debug|Metadata on pass "i"/"NumTags": "Metadata
}
}
print "Info|Writing: "NewTrack
# Check for advanced options
if (FFmpegADV) FFmpegOPTS=FFmpegADV
else FFmpegOPTS="-c:v copy -map 0 -y -acodec libmp3lame "BrCommand" -write_id3v1 1 -id3v2_version 3"
# Convert the track
if (Debug >= 1) print "Debug|Executing: nice "FFmpeg" -loglevel "FFmpegLOG" -nostdin -i \""Track"\" "FFmpegOPTS" \""NewTrack"\""
Result=system("nice "FFmpeg" -loglevel "FFmpegLOG" -nostdin -i \""Track"\" "FFmpegOPTS" \""NewTrack"\" 2>&1")
Command = "nice "FFmpeg" -loglevel "FFmpegLOG" -nostdin -i \""Track"\" "FFmpegOPTS" "Metadata"\""NewTrack"\" 2>&1"
if (Debug >= 1) print "Debug|Executing: "Command
Result = system(Command)
if (Debug >= 2) print "Debug|ffmpeg exited"
if (Result) {
print "Error|Exit code "Result" converting \""Track"\""
} else {
# Build system command to set owner and permissions, etc.
if (Keep == 1) {
# Do not delete the source file
if (Debug >= 1) print "Debug|Keeping original: \""Track"\" and setting permissions on \""NewTrack"\""
Command="if [ -s \""NewTrack"\" ]; then if [ -f \""Track"\" ]; then chown --reference=\""Track"\" \""NewTrack"\"; chmod --reference=\""Track"\" \""NewTrack"\"; fi; fi"
Command = "if [ -s \""NewTrack"\" ]; then if [ -f \""Track"\" ]; then chown --reference=\""Track"\" \""NewTrack"\"; chmod --reference=\""Track"\" \""NewTrack"\"; fi; fi"
} else {
if (Recycle == "") {
# No Recycle Bin, so check for non-zero size new file and delete the old one
if (Debug >= 1) print "Debug|Deleting: \""Track"\" and setting permissions on \""NewTrack"\""
Command="if [ -s \""NewTrack"\" ]; then if [ -f \""Track"\" ]; then chown --reference=\""Track"\" \""NewTrack"\"; chmod --reference=\""Track"\" \""NewTrack"\"; rm \""Track"\"; fi; fi"
Command = "if [ -s \""NewTrack"\" ]; then if [ -f \""Track"\" ]; then chown --reference=\""Track"\" \""NewTrack"\"; chmod --reference=\""Track"\" \""NewTrack"\"; rm \""Track"\"; fi; fi"
} else {
# Recycle Bin is configured, so check if it exists, append a relative path to it from the track, check for non-zero size new file, and move the old one to the Recycle Bin
match(Track,/^\/?[^\/]+\//)
RecPath=substr(Track,RSTART+RLENGTH)
sub(/[^\/]+$/,"",RecPath)
RecPath=Recycle RecPath
if (Root == "") {
# Legacy way in case the Root music folder cannot be determined
print "Warning|Root music folder is blank. Falling back to legacy split method."
match(Track, /^\/?[^\/]+\//)
} else {
# The following logic tests that the Root folder is a substring of the Track folder, though based on the observed Lidarr behavior this should be a safe assumption. A warning is displayed just in case.
RSTART = index(Track, Root)
if (RSTART) {
RLENGTH = length(Root)
} else {
print "Warning|The root music folder \""Root"\" is not part of \""Track"\". Recycled tracks may not appear as expected."
RLENGTH = 0
}
}
if (Debug >= 2) print "Debug|Splitting track name on RSTART: "RSTART", RLENGTH: "RLENGTH" to prepend recycle path."
RecPath = substr(Track, RSTART + RLENGTH)
sub(/^\/+/, "", RecPath) # remove trailing track name
sub(/[^\/]+$/, "", RecPath) # remove leading backslash
RecPath = Recycle RecPath
if (Debug >= 1) print "Debug|Recycling: \""Track"\" to \""RecPath"\" and setting permissions on \""NewTrack"\""
Command="if [ ! -e \""RecPath"\" ]; then mkdir -p \""RecPath"\"; fi; if [ -s \""NewTrack"\" ]; then if [ -f \""Track"\" ]; then chown --reference=\""Track"\" \""NewTrack"\"; chmod --reference=\""Track"\" \""NewTrack"\"; mv -t \""RecPath"\" \""Track"\"; fi; fi"
Command = "if [ ! -e \""RecPath"\" ]; then mkdir -p \""RecPath"\"; fi; if [ -s \""NewTrack"\" ]; then if [ -f \""Track"\" ]; then chown --reference=\""Track"\" \""NewTrack"\"; chmod --reference=\""Track"\" \""NewTrack"\"; mv -t \""RecPath"\" \""Track"\"; fi; fi"
}
}
# Set owner, permissions, etc.
if (Debug >= 2) print "Debug|Executing: "Command
system(Command)
Result = system(Command)
if (Result) {
print "Error|Exit code "Result" setting permissions and/or recycling on \""NewTrack"\""
}
}
}
' | log
@@ -535,7 +691,7 @@ BEGIN {
flac2mp3_return="${PIPESTATUS[1]}" # captures awk exit status
[ $flac2mp3_debug -ge 2 ] && echo "Debug|awk exited with code: $flac2mp3_return" | log
if [ "$flac2mp3_return" != 0 ]; then
flac2mp3_message="Error|[$flac2mp3_return] Script exited abnormally. File permissions issue?"
flac2mp3_message="Error|[$flac2mp3_return] Script exited abnormally. File permissions issue?"
echo "$flac2mp3_message" | log
echo "$flac2mp3_message" >&2
exit 10