Skip to content

Commit 64de822

Browse files
committed
Release 3.0.2
1 parent af0a056 commit 64de822

2 files changed

Lines changed: 109 additions & 26 deletions

File tree

.github/workflows/BuildImage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
echo "BASEIMAGE=${{ env.BASEIMAGE }}" >> $GITHUB_OUTPUT
2121
echo "MODNAME=${{ env.MODNAME }}" >> $GITHUB_OUTPUT
2222
# **** If the mod needs to be versioned, set the versioning logic below. Otherwise leave as is. ****
23-
MOD_VERSION="3.0.1"
23+
MOD_VERSION="3.0.2"
2424
echo "MOD_VERSION=${MOD_VERSION}" >> $GITHUB_OUTPUT
2525
outputs:
2626
GITHUB_REPO: ${{ steps.outputs.outputs.GITHUB_REPO }}

root/usr/local/bin/flac2mp3.sh

Lines changed: 108 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,71 @@ function initialize_variables {
233233
export flac2mp3_keep=0
234234
export flac2mp3_type=$(printenv | sed -n 's/_eventtype *=.*$//p')
235235
}
236+
function parse_arg_string {
237+
# Safely parse a shell-style argument string without eval
238+
local input="$1"
239+
240+
export flac2mp3_arg_array=()
241+
local char
242+
local token=""
243+
local in_single=false
244+
local in_double=false
245+
local escaped=false
246+
local i=0
247+
local len=${#input}
248+
249+
while [ $i -lt "$len" ]; do
250+
char=${input:i:1}
251+
if $escaped; then
252+
token+="$char"
253+
escaped=false
254+
elif [ "$char" = "\\" ]; then
255+
escaped=true
256+
elif $in_single; then
257+
if [ "$char" = "'" ]; then
258+
in_single=false
259+
else
260+
token+="$char"
261+
fi
262+
elif $in_double; then
263+
if [ "$char" = '"' ]; then
264+
in_double=false
265+
elif [ "$char" = "\\" ]; then
266+
escaped=true
267+
else
268+
token+="$char"
269+
fi
270+
else
271+
case "$char" in
272+
[[:space:]] )
273+
if [ -n "$token" ]; then
274+
flac2mp3_arg_array+=("$token")
275+
token=""
276+
fi
277+
;;
278+
"'" )
279+
in_single=true
280+
;;
281+
'"' )
282+
in_double=true
283+
;;
284+
*)
285+
token+="$char"
286+
;;
287+
esac
288+
fi
289+
i=$((i + 1))
290+
done
291+
292+
if [ -n "$token" ]; then
293+
flac2mp3_arg_array+=("$token")
294+
fi
295+
296+
if $escaped || $in_single || $in_double; then
297+
return 1
298+
fi
299+
return 0
300+
}
236301
function process_command_line {
237302
# Process arguments, either from the command line or from the environment variable
238303

@@ -246,9 +311,14 @@ function process_command_line {
246311
if [ $# -ne 0 ]; then
247312
export flac2mp3_prelogmessage="Warning|FLAC2MP3_ARGS environment variable set but will be ignored because command line arguments were also specified."
248313
else
249-
# Move the environment variable arguments to the command line for processing
314+
# Move the environment variable arguments to the command line for processing using a safe parser
250315
export flac2mp3_prelogmessage="Info|Using settings from environment variable."
251-
eval set -- "$FLAC2MP3_ARGS"
316+
if ! parse_arg_string "$FLAC2MP3_ARGS"; then
317+
echo_ansi "Error|Invalid quoting in FLAC2MP3_ARGS environment variable." >&2
318+
usage
319+
exit 3
320+
fi
321+
set -- "${flac2mp3_arg_array[@]}"
252322
fi
253323
fi
254324

@@ -567,7 +637,7 @@ function get_version {
567637
# Get Lidarr version
568638

569639
call_api 0 "Getting ${flac2mp3_type^} version." "GET" "system/status"
570-
local json_test="$(echo $flac2mp3_result | jq -crM '.version?')"
640+
local json_test="$(echo "$flac2mp3_result" | jq -crM '.version?')"
571641
[ "$json_test" != "null" ] && [ "$json_test" != "" ]
572642
return
573643
}
@@ -576,7 +646,7 @@ function get_trackfile_info {
576646

577647
# shellcheck disable=SC2154
578648
call_api 0 "Getting track file info for album id $lidarr_album_id." "GET" "trackFile" "albumId=$lidarr_album_id"
579-
local json_test="$(echo $flac2mp3_result | jq -crM '.[].id?')"
649+
local json_test="$(echo "$flac2mp3_result" | jq -crM '.[].id?')"
580650
[ "$json_test" != "null" ] && [ "$json_test" != "" ]
581651
return
582652
}
@@ -601,7 +671,7 @@ function check_job {
601671
}
602672

603673
# Job status checks
604-
local json_test="$(echo $flac2mp3_result | jq -crM '.status?')"
674+
local json_test="$(echo "$flac2mp3_result" | jq -crM '.status?')"
605675
case "$json_test" in
606676
completed) local return=0; break ;;
607677
failed) local return=2; break ;;
@@ -648,15 +718,15 @@ function get_import_info {
648718

649719
# shellcheck disable=SC2154
650720
call_api 1 "Getting list of files that can be imported." "GET" "manualimport" "artistId=$lidarr_artist_id" "folder=$lidarr_artist_path" "filterExistingFiles=true" "replaceExistingFiles=false"
651-
local json_test="$(echo $flac2mp3_result | jq -crM '.[]? | .tracks?')"
721+
local json_test="$(echo "$flac2mp3_result" | jq -crM '.[]? | .tracks?')"
652722
[ "$json_test" != "null" ] && [ "$json_test" != "" ] && [ "$json_test" != "[]" ]
653723
return
654724
}
655725
function import_tracks {
656726
# Import new track into Lidarr
657727

658728
call_api 0 "Importing $flac2mp3_import_count new files into ${flac2mp3_type^}." "POST" "command" "{\"name\":\"ManualImport\",\"files\":$flac2mp3_json,\"importMode\":\"auto\",\"replaceExistingFiles\":false}"
659-
local json_test="$(echo $flac2mp3_result | jq -crM '.id?')"
729+
local json_test="$(echo "$flac2mp3_result" | jq -crM '.id?')"
660730
[ "$json_test" != "null" ] && [ "$json_test" != "" ]
661731
return
662732
}
@@ -666,7 +736,7 @@ function ffprobe {
666736
local trackfile="$1" # Track file to inspect
667737

668738
local ffcommand="/usr/bin/ffprobe"
669-
execute_ff_command "inspecting file: '$trackfile'" "$ffcommand" -hide_banner -loglevel $flac2mp3_ffmpeg_log -print_format json=compact=1 -show_format -show_entries "format=tags : format_tags=title,disc,genre" -i "$trackfile"
739+
execute_ff_command "inspecting file: '$trackfile'" "$ffcommand" -hide_banner -loglevel "$flac2mp3_ffmpeg_log" -print_format json=compact=1 -show_format -show_entries "format=tags : format_tags=title,disc,genre" -i "$trackfile"
670740

671741
unset flac2mp3_ffprobe_json
672742
declare -g flac2mp3_ffprobe_json
@@ -697,8 +767,8 @@ function check_log {
697767
# Log file checks
698768

699769
# Check that log path exists
700-
if [ ! -d "$(dirname $flac2mp3_log)" ]; then
701-
[ $flac2mp3_debug -ge 1 ] && echo_ansi "Debug|Log file path does not exist: '$(dirname $flac2mp3_log)'. Using log file in current directory."
770+
if [ ! -d "$(dirname -- "$flac2mp3_log")" ]; then
771+
[ $flac2mp3_debug -ge 1 ] && echo_ansi "Debug|Log file path does not exist: '$(dirname -- "$flac2mp3_log")'. Using log file in current directory."
702772
export flac2mp3_log=./flac2mp3.txt
703773
fi
704774

@@ -871,7 +941,7 @@ function check_config_file {
871941
echo_ansi "$message" >&2
872942
end_script 17
873943
}
874-
export flac2mp3_version="$(echo $flac2mp3_result | jq -crM .version)"
944+
export flac2mp3_version="$(echo "$flac2mp3_result" | jq -crM .version)"
875945
[ $flac2mp3_debug -ge 1 ] && echo "Debug|Detected ${flac2mp3_type^} version $flac2mp3_version" | log
876946

877947
# Import mode will not have any audio tracks until after import
@@ -980,7 +1050,7 @@ function call_api {
9801050
# If database is locked, log and loop
9811051
if wait_if_locked; then
9821052
if [ $curl_return -ne 0 ]; then
983-
local error_message="$(echo $flac2mp3_result | jq -jcM 'if type=="array" then map(.errorMessage) | join(", ") else (if has("title") then "[HTTP \(.status?)] \(.title) \(.errors?)" elif has("message") then .message else "Unknown JSON format." end) end')"
1053+
local error_message="$(echo "$flac2mp3_result" | jq -jcM 'if type=="array" then map(.errorMessage) | join(", ") else (if has("title") then "[HTTP \(.status?)] \(.title) \(.errors?)" elif has("message") then .message else "Unknown JSON format." end) end')"
9841054
local message=$(echo -e "[$curl_return] curl error when calling: \"$url\"$data_info\nWeb server returned: $error_message" | awk '{print "Error|"$0}')
9851055
echo "$message" | log
9861056
echo_ansi "$message" >&2
@@ -1006,7 +1076,7 @@ function wait_if_locked {
10061076
# 0 - Database is not locked
10071077
# 1 - Database is locked
10081078

1009-
if [[ "$(echo $flac2mp3_result | jq -jcM '.message?')" =~ database\ is\ locked ]]; then
1079+
if [[ "$(echo "$flac2mp3_result" | jq -jcM '.message?')" =~ database\ is\ locked ]]; then
10101080
local return=1
10111081
echo "Warn|Database is locked; system is likely overloaded. Sleeping 1 minute." | log
10121082
sleep 60
@@ -1053,7 +1123,7 @@ function get_media_config {
10531123
# Get media management configuration
10541124

10551125
call_api 0 "Getting ${flac2mp3_type^} configuration." "GET" "config/mediamanagement"
1056-
local json_test="$(echo $flac2mp3_result | jq -crM '.id?')"
1126+
local json_test="$(echo "$flac2mp3_result" | jq -crM '.id?')"
10571127
[ "$json_test" != "null" ] && [ "$json_test" != "" ]
10581128
return
10591129
}
@@ -1097,20 +1167,30 @@ function set_ffmpeg_parameters {
10971167
2) export flac2mp3_ffmpeg_log="info" ;;
10981168
*) export flac2mp3_ffmpeg_log="debug" ;;
10991169
esac
1170+
1171+
local -a brCommand=()
1172+
flac2mp3_ffmpeg_opts=()
1173+
11001174
if [ -n "$flac2mp3_bitrate" ]; then
11011175
[ $flac2mp3_debug -ge 1 ] && echo "Debug|Using constant bitrate of $flac2mp3_bitrate" | log
1102-
local brCommand="-b:a $flac2mp3_bitrate "
1176+
brCommand=(-b:a "$flac2mp3_bitrate")
11031177
elif [ -n "$flac2mp3_vbrquality" ]; then
11041178
[ $flac2mp3_debug -ge 1 ] && echo "Debug|Using variable quality of $flac2mp3_vbrquality" | log
1105-
brCommand="-q:a $flac2mp3_vbrquality "
1179+
brCommand=(-q:a "$flac2mp3_vbrquality")
11061180
elif [ -n "$flac2mp3_ffmpegadv" ]; then
11071181
[ $flac2mp3_debug -ge 1 ] && echo "Debug|Using advanced ffmpeg options \"$flac2mp3_ffmpegadv\"" | log
11081182
[ $flac2mp3_debug -ge 1 ] && echo "Debug|Exporting with file extension \"$flac2mp3_extension\"" | log
1109-
export flac2mp3_ffmpeg_opts="$flac2mp3_ffmpegadv"
1183+
if ! parse_arg_string "$flac2mp3_ffmpegadv"; then
1184+
echo_ansi "Error|Invalid quoting in advanced ffmpeg options." >&2
1185+
usage
1186+
exit 3
1187+
fi
1188+
flac2mp3_ffmpeg_opts=("${flac2mp3_arg_array[@]}")
11101189
fi
11111190

1112-
# Set default ffmpeg options
1113-
[ -z "$flac2mp3_ffmpeg_opts" ] && export flac2mp3_ffmpeg_opts="-c:v copy -map 0 -y -acodec libmp3lame ${brCommand}-write_id3v1 1 -id3v2_version 3"
1191+
if [ ${#flac2mp3_ffmpeg_opts[@]} -eq 0 ]; then
1192+
flac2mp3_ffmpeg_opts=("-c:v" "copy" "-map" "0" "-y" "-acodec" "libmp3lame" "${brCommand[@]}" "-write_id3v1" "1" "-id3v2_version" "3")
1193+
fi
11141194
}
11151195
function process_tracks {
11161196
# Process tracks loop
@@ -1177,7 +1257,10 @@ function process_tracks {
11771257

11781258
# Get track metadata
11791259
if ffprobe "$track"; then
1180-
for tag in $(echo $flac2mp3_tags | tr ',' '|'); do
1260+
local IFS=','
1261+
local -a flac2mp3_tag_array=()
1262+
read -r -a flac2mp3_tag_array <<< "$flac2mp3_tags"
1263+
for tag in "${flac2mp3_tag_array[@]}"; do
11811264
# shellcheck disable=SC2089
11821265
case "$tag" in
11831266
title )
@@ -1229,7 +1312,7 @@ function process_tracks {
12291312
local ffcommand="nice /usr/bin/ffmpeg"
12301313
local IFS=$' \t\n' # Temporarily restore IFS
12311314
# shellcheck disable=SC2090
1232-
execute_ff_command "converting track: '$track' to '$tempTrack'" "$ffcommand" -loglevel $flac2mp3_ffmpeg_log -nostdin -i "$track" $flac2mp3_ffmpeg_opts "${metadata[@]}" "$tempTrack"
1315+
execute_ff_command "converting track: '$track' to '$tempTrack'" "$ffcommand" -loglevel "$flac2mp3_ffmpeg_log" -nostdin -i "$track" "${flac2mp3_ffmpeg_opts[@]}" "${metadata[@]}" "$tempTrack"
12331316
local return=$?; [ $return -ne 0 ] && {
12341317
change_exit_status 13
12351318
# Delete the temporary file if it exists
@@ -1295,7 +1378,7 @@ function process_tracks {
12951378
}
12961379
else
12971380
# Call Lidarr to delete the original file, or recycle if configured.
1298-
local track_id=$(echo $flac2mp3_trackfiles | jq -crM ".[] | select(.path == \"$track\") | .id")
1381+
local track_id=$(echo "$flac2mp3_trackfiles" | jq -crM ".[] | select(.path == \"$track\") | .id")
12991382
delete_track $track_id
13001383
local return=$?; [ $return -ne 0 ] && {
13011384
local message="Error|[$return] ${flac2mp3_type^} error when deleting the original track: '$track'. Not importing new track into ${flac2mp3_type^}."
@@ -1381,7 +1464,7 @@ function update_database {
13811464
# Build JSON data for all tracks
13821465
# NOTE: Tracks with empty track IDs will not appear in the resulting JSON and will therefore not be imported into Lidarr
13831466
[ $flac2mp3_debug -ge 1 ] && echo "Debug|Building JSON data to import" | log
1384-
export flac2mp3_json=$(echo $flac2mp3_result | jq -jcM "
1467+
export flac2mp3_json=$(echo "$flac2mp3_result" | jq -jcM "
13851468
map(
13861469
select(.path | inside(\"$flac2mp3_import_list\")) |
13871470
{path, \"artistId\":$lidarr_artist_id, \"albumId\":$lidarr_album_id, albumReleaseId,\"trackIds\":[.tracks[].id], quality, \"disableReleaseSwitching\":false}
@@ -1396,7 +1479,7 @@ function update_database {
13961479
echo_ansi "$message" >&2
13971480
change_exit_status 17
13981481
}
1399-
local jobid="$(echo $flac2mp3_result | jq -crM .id)"
1482+
local jobid=$(echo "$flac2mp3_result" | jq -crM .id)
14001483

14011484
# Check status of job (see issue #39)
14021485
check_job $jobid
@@ -1407,7 +1490,7 @@ function update_database {
14071490
2) local message="Warn|${flac2mp3_type^} job ID $jobid failed."
14081491
change_exit_status 17
14091492
;;
1410-
3) local message="Warn|Script timed out waiting on ${flac2mp3_type^} job ID $jobid. Last status was: $(echo $flac2mp3_result | jq -crM .status)"
1493+
3) local message="Warn|Script timed out waiting on ${flac2mp3_type^} job ID $jobid. Last status was: $(echo "$flac2mp3_result" | jq -crM .status)"
14111494
change_exit_status 18
14121495
;;
14131496
10) local message="Error|${flac2mp3_type^} job ID $jobid returned a curl error."

0 commit comments

Comments
 (0)