diff --git a/README.md b/README.md index d150156..616cb42 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,32 @@ Development Container info: 2. Configure the Docker container with all the port, volume, and environment settings from the *original container documentation* here: **[linuxserver/lidarr](https://hub.docker.com/r/linuxserver/lidarr "Docker container")** - 1. Add a **DOCKER_MODS** environment variable to the `docker run` command, as follows: - - Stable release: `-e DOCKER_MODS=linuxserver/mods:lidarr-flac2mp3` - - Dev/test release: `-e DOCKER_MODS=thecaptain989/lidarr-flac2mp3:latest` + 1. Add a **DOCKER_MODS** environment variable to your `compose.yml` file or `docker run` command, as follows: + - Stable release: `DOCKER_MODS=linuxserver/mods:lidarr-flac2mp3` + - Dev/test release: `DOCKER_MODS=thecaptain989/lidarr-flac2mp3:latest` - *Example Docker CLI Configuration* + *Example Docker Compose YAML Configuration* + ```yaml + version: "2.1" + services: + lidarr: + image: lscr.io/linuxserver/lidarr + container_name: lidarr + environment: + - PUID=1000 + - PGID=1000 + - TZ=America/Chicago + - DOCKER_MODS=linuxserver/mods:lidarr-flac2mp3 + volumes: + - /path/to/appdata/config:/config + - /path/to/music:/music + - /path/to/downloads:/downloads + ports: + - 8686:8686 + restart: unless-stopped + ``` + + *Example Docker Run Command* ```shell docker run -d \ --name=lidarr \ @@ -34,10 +55,10 @@ Development Container info: -v /path/to/downloads:/downloads \ --restart unless-stopped \ lscr.io/linuxserver/lidarr - ``` + ``` *Example Synology Configuration* - ![flac2mp3](.assets/lidarr-synology.png "Synology container settings") + ![flac2mp3](.assets/lidarr-synology.png "Synology container settings") 2. Start the container. @@ -66,13 +87,12 @@ To supply arguments to the script, you **must** either use one of the **[include The script may be called with optional command line arguments. The syntax for the command line is: -`flac2mp3 [{-d|--debug} []] [{-b|--bitrate} | {-v|--quality} | {-a|--advanced} "" {-e|--extension} ] [{-f|--file} ] [{-k|--keepfile}] [{-o|--output} ] [{-r|--regex} ''] [{-t|--tags} ]` +`flac2mp3 [{-b|--bitrate} | {-v|--quality} | {-a|--advanced} "" {-e|--extension} ] [{-f|--file} ] [{-k|--keep-file}] [{-o|--output} ] [{-r|--regex} ''] [{-t|--tags} ] [{-l|--log} ] [{-d|--debug} []]` Where: Option|Argument|Description ---|---|--- --d, --debug|\[\\]|Enables debug logging. Level is optional.
Default of 1 (low).
2 includes JSON and FFmpeg output.
3 contains even more JSON output. -b, --bitrate|\|Sets the output quality in constant bits per second (CBR).
Examples: 160k, 240k, 300000
**Note:** May not be specified with `-v`, `-a`, or `-e`. -v, --quality|\|Sets the output variable bit rate (VBR).
Specify a value between 0 and 9, with 0 being the highest quality.
See the [FFmpeg MP3 Encoding Guide](https://trac.ffmpeg.org/wiki/Encode/MP3) for more details.
**Note:** May not be specified with `-b`, `-a`, or `-e`. -a, --advanced|\"\\"|Advanced ffmpeg options.
The specified `options` replace all script defaults and are sent directly to ffmpeg.
The `options` value must be enclosed in quotes.
See [FFmpeg Options](https://ffmpeg.org/ffmpeg.html#Options) for details on valid options, and [Guidelines for high quality audio encoding](https://trac.ffmpeg.org/wiki/Encode/HighQualityAudio) for suggested usage.
**Note:** Requires the `-e` option to also be specified. May not be specified with `-v` or `-b`.
![warning] **WARNING:** You must specify an audio codec (by including a `-c:a ` ffmpeg option) or the resulting file will contain no audio!
![warning] **WARNING:** Invalid `options` could result in script failure! @@ -81,7 +101,9 @@ Option|Argument|Description -o, --output|\|Converted audio file(s) are saved to `directory` instead of being located in the same directory as the source audio file.
The path 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.
**Note:** This also disables importing the new files into Lidarr after conversion. -r, --regex|'\'|Sets the regular expression used to select input files.
The `regex` value should be enclosed in single quotes and escaped properly.
Defaults to `[.]flac$`. +-l, --log|\|The log filename
Default of /config/log/flac2mp3.txt -t, --tags|\|Comma separated list of metadata tags to apply automated corrections to.
See [Metadata Corrections](./README.md#metadata-corrections) section. +-d, --debug|\[\\]|Enables debug logging. Level is optional.
Default of 1 (low).
2 includes JSON and FFmpeg output.
3 contains even more JSON output. --help| |Display help and exit. --version| |Display version and exit. @@ -159,7 +181,7 @@ Then put `/config/flac2mp3-custom.sh` in the **Path** field in place of `/usr/lo ### Environment Variable The `flac2mp3.sh` script also allows the use of arguments provided by the `FLAC2MP3_ARGS` environment variable. This allows advanced use cases without having to provide a custom script. -For example, the following value would convert any .mp3 to Opus: +For example, the following value in your `docker run` command would convert any .mp3 to Opus: ``` -e FLAC2MP3_ARGS='-a "-vn -c:a libopus -b:a 192k" -e .opus -r "[.]mp3$"' ``` @@ -186,7 +208,7 @@ Using this function, you can easily process all of your audio files in any subdi #### Script Execution Differences in Batch Mode Because the script is not called from within Lidarr, expect the following behavior while in Batch Mode: -* *The file name must be specified on the command line*
(The `-f` option places the script in Batch Mode) +* *The filename must be specified on the command line*
(The `-f` option places the script in Batch Mode) * *Lidarr APIs are not called and its database is not updated.*
This may require a manual import of converted music files or an artist rescan. * *Original audio files are deleted.*
The Recycle Bin function is not available. (Modifiable using the `-k` option.) @@ -197,22 +219,23 @@ find /music/ -type f -name "*.flac" | while read file; do /usr/local/bin/flac2mp ``` ### Logs -A log file is created for the script activity called: +By default, a log file is created for the script activity called: `/config/logs/flac2mp3.txt` -This log can be downloaded from Lidarr under *System* > *Log Files* +This log can be downloaded from Lidarr under *System* > *Log Files*. The log filename can be modified with the `--log` command-line option. Log rotation is performed, with 5 log files of 1MB each kept, matching Lidarr's log retention. >![danger] **NOTE:** If debug logging is enabled with a level above 1, the log file can grow very large very quickly and is much more likely to be rotated. *Do not leave high-level debug logging enabled permanently.* #### Metadata Corrections -This feature is not meant for general purpose use. It is only documented for completeness. +This feature is not meant for general purpose use. It is only documented here for completeness. List of supported tags and metadata corrections that are applied: |Tag|Original|Correction |---|---|--- +|title|Parenthesis for live\|remix, etc. "()"|Square brackets "\[]" |disc|1|1/1 |genre|/Pop/|"Pop" | |/Indie/|"Alternative & Indie" @@ -221,7 +244,16 @@ List of supported tags and metadata corrections that are applied: | |/Punk\|Alternative/|"Alternative & Punk" | |/Rock/|"Rock" -## Credits +# Uninstall +To completely remove the mod: +1. Delete the custom script from Lidarr's *Settings* > *Connect* screen that you created in the [Installation](./README.md#installation) section above. +2. Stop and delete the Lidarr container. +3. Exclude the **DOCKER_MODS** environment variable from your `compose.yaml` file or the `docker run` command when re-creating the Lidarr container. + +___ + +# Credits + This would not be possible without the following: [Lidarr](https://lidarr.audio/ "Lidarr homepage") diff --git a/root/usr/local/bin/flac2mp3.sh b/root/usr/local/bin/flac2mp3.sh index 8a56094..b5e977c 100755 --- a/root/usr/local/bin/flac2mp3.sh +++ b/root/usr/local/bin/flac2mp3.sh @@ -14,15 +14,18 @@ # stat # nice # basename +# dirname # printenv # chmod # tr +# sed # Exit codes: # 0 - success; or test # 1 - no audio tracks detected # 2 - ffmpeg not found # 3 - invalid command line arguments +# 4 - log file is not writable # 5 - specified audio file not found # 6 - error when creating output directory # 7 - unknown eventtype environment variable @@ -58,13 +61,9 @@ Audio conversion script designed for use with Lidarr Source: https://github.com/TheCaptain989/lidarr-flac2mp3 Usage: - $0 [{-d|--debug} []] [{-b|--bitrate} | {-v|--quality} | {-a|--advanced} \"\" {-e|--extension} ] [{-f|--file} ] [{-k|--keepfile}] [{-o|--output} ] [{-r|--regex} ''] [{-t|--tags} ] + $0 [{-b|--bitrate} | {-v|--quality} | {-a|--advanced} \"\" {-e|--extension} ] [{-f|--file} ] [{-k|--keep-file}] [{-o|--output} ] [{-r|--regex} ''] [{-t|--tags} ] [{-l|--log} ] [{-d|--debug} []] Options: - -d, --debug [] Enable debug logging - level is optional, between 1-3 - 1 is lowest, 3 is highest - [default: 1] -b, --bitrate Set output quality in constant bits per second [default: 320k] Ex: 160k, 240k, 300000 @@ -102,6 +101,12 @@ Options: -t, --tags Comma separated list of metadata tags to apply automated corrections to. Supports: disc, genre + -l, --log log filename + [default: /config/log/flac2mp3.txt] + -d, --debug [] Enable debug logging + level is optional, between 1-3 + 1 is lowest, 3 is highest + [default: 1] --help Display this help and exit --version Display script version and exit @@ -163,6 +168,16 @@ while (( "$#" )); do echo "$flac2mp3_script $flac2mp3_ver" exit 0 ;; + -l|--log ) # Log file + if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then + export flac2mp3_log="$2" + shift 2 + else + echo "Error|Invalid option: $1 requires an argument." >&2 + usage + exit 1 + fi + ;; -f|--file ) # Batch Mode if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then # Overrides detected *_eventtype @@ -277,7 +292,7 @@ while (( "$#" )); do exit 3 fi ;; - -*|--*=) # Unknown option + -*) # Unknown option echo "Error|Unknown option: $1" >&2 usage exit 20 @@ -508,9 +523,9 @@ function import_tracks { } # Get track media info from ffprobe function ffprobe { - [ $flac2mp3_debug -ge 2 ] && echo "Debug|Executing: /usr/bin/ffprobe -hide_banner -loglevel $flac2mp3_ffmpeg_log -print_format json=compact=1 -show_format -show_entries \"format=tags : format_tags=disc,genre\" -i \"$1\"" | log + [ $flac2mp3_debug -ge 2 ] && echo "Debug|Executing: /usr/bin/ffprobe -hide_banner -loglevel $flac2mp3_ffmpeg_log -print_format json=compact=1 -show_format -show_entries \"format=tags : format_tags=title,disc,genre\" -i \"$1\"" | log unset flac2mp3_ffprobe_json - flac2mp3_ffprobe_json=$(/usr/bin/ffprobe -hide_banner -loglevel $flac2mp3_ffmpeg_log -print_format json=compact=1 -show_format -show_entries "format=tags : format_tags=disc,genre" -i "$1") + flac2mp3_ffprobe_json=$(/usr/bin/ffprobe -hide_banner -loglevel $flac2mp3_ffmpeg_log -print_format json=compact=1 -show_format -show_entries "format=tags : format_tags=title,disc,genre" -i "$1") flac2mp3_return=$?; [ $flac2mp3_return -ne 0 ] && { flac2mp3_message="Error|[$flac2mp3_return] ffprobe error when inspecting track: \"$1\"" echo "$flac2mp3_message" | log @@ -524,20 +539,48 @@ function ffprobe { fi return $flac2mp3_return } +# Exit program +function end_script { + # Cool bash feature + flac2mp3_message="Info|Completed in $((SECONDS/60))m $((SECONDS%60))s" + echo "$flac2mp3_message" | log + [ "$1" != "" ] && flac2mp3_exitstatus=$1 + [ $flac2mp3_debug -ge 1 ] && echo "Debug|Exit code ${flac2mp3_exitstatus:-0}" | log + exit ${flac2mp3_exitstatus:-0} +} ### End Functions +# Check that log path exists +if [ ! -d "$(dirname $flac2mp3_log)" ]; then + [ $flac2mp3_debug -ge 1 ] && echo "Debug|Log file path does not exist: '$(dirname $flac2mp3_log)'. Using log file in current directory." + flac2mp3_log=./flac2mp3.txt +fi + +# Check that the log file exists +if [ ! -f "$flac2mp3_log" ]; then + echo "Info|Creating a new log file: $flac2mp3_log" + touch "$flac2mp3_log" 2>&1 +fi + +# Check that the log file is writable +if [ ! -w "$flac2mp3_log" ]; then + echo "Error|Log file '$flac2mp3_log' is not writable or does not exist." >&2 + flac2mp3_log=/dev/null + flac2mp3_exitstatus=4 +fi + # Check for required binaries if [ ! -f "/usr/bin/ffmpeg" ]; then flac2mp3_message="Error|/usr/bin/ffmpeg is required by this script" echo "$flac2mp3_message" | log echo "$flac2mp3_message" >&2 - exit 2 + end_script 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 + end_script 2 fi # Log Debug state @@ -563,7 +606,7 @@ if [[ "$lidarr_eventtype" = "Test" ]]; then flac2mp3_message="Info|Script was test executed successfully." echo "$flac2mp3_message" | log echo "$flac2mp3_message" - exit 0 + end_script fi # Log Batch mode @@ -588,7 +631,7 @@ elif [ -f "$flac2mp3_config" ]; then [[ $flac2mp3_bindaddress = "*" ]] && flac2mp3_bindaddress=localhost # Build URL to Lidarr API - flac2mp3_api_url="http://$flac2mp3_bindaddress:$flac2mp3_port$flac2mp3_urlbase/api/v1" + flac2mp3_api_url="http://$flac2mp3_bindaddress:$flac2mp3_port${flac2mp3_urlbase:+/$flac2mp3_urlbase}/api/v1" # Check Lidarr version if get_version; then @@ -616,7 +659,7 @@ if [ "$flac2mp3_type" = "batch" -a ! -f "$flac2mp3_tracks" ]; then flac2mp3_message="Error|Input file not found: \"$flac2mp3_tracks\"" echo "$flac2mp3_message" | log echo "$flac2mp3_message" >&2 - exit 5 + end_script 5 fi # Check for empty tracks variable @@ -624,7 +667,7 @@ 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 + end_script 1 fi # If specified, check if destination folder exists and create if necessary @@ -635,7 +678,7 @@ if [ "$flac2mp3_output" -a ! -d "$flac2mp3_output" ]; then flac2mp3_message="Error|[$flac2mp3_return] mkdir returned an error. Unable to create output directory." echo "$flac2mp3_message" | log echo "$flac2mp3_message" >&2 - exit 6 + end_script 6 } fi @@ -724,15 +767,23 @@ for flac2mp3_track in $flac2mp3_tracks; do if ffprobe "$flac2mp3_track"; then for flac2mp3_tag in $(echo $flac2mp3_tags | tr ',' '|'); do case "$flac2mp3_tag" in + title ) # Fix for parenthesis in titles for live and mix names + flac2mp3_tag_title=$(echo "$flac2mp3_ffprobe_json" | jq -crM '.format.tags | to_entries[] | select(.key | match("title"; "i")).value') + [ $flac2mp3_debug -ge 1 ] && echo "Debug|Original metadata: title=$flac2mp3_tag_title" | log + flac2mp3_pattern='\([^)]+\)$' # Rough way to limit editing metadata for every track + if [[ "$flac2mp3_tag_title" =~ $flac2mp3_pattern ]]; then + flac2mp3_ffmpeg_metadata+="-metadata title=\"$(echo "$flac2mp3_tag_title" | sed -r 's/\((live|acoustic|demo|[^)]*((re)?mix(es)?|dub|version))\)$/[\1]/i')\" " + fi + ;; disc ) # Fix one disc by itself - flac2mp3_tag_disc=$(echo "$flac2mp3_ffprobe_json" | jq -crM '.format.tags.disc') + flac2mp3_tag_disc=$(echo "$flac2mp3_ffprobe_json" | jq -crM '.format.tags | to_entries[] | select(.key | match("disc"; "i")).value') [ $flac2mp3_debug -ge 1 ] && echo "Debug|Original metadata: disc=$flac2mp3_tag_disc" | log if [ "$flac2mp3_tag_disc" == "1" ]; then flac2mp3_ffmpeg_metadata+='-metadata disc="1/1" ' fi ;; genre ) # Fix multiple genres - flac2mp3_tag_genre=$(echo "$flac2mp3_ffprobe_json" | jq -crM '.format.tags | to_entries[] | select(.key | match("genre";"i")).value') + flac2mp3_tag_genre=$(echo "$flac2mp3_ffprobe_json" | jq -crM '.format.tags | to_entries[] | select(.key | match("genre"; "i")).value') [ $flac2mp3_debug -ge 1 ] && echo "Debug|Original metadata: genre=$flac2mp3_tag_genre" | log # Only trigger on multiple genres if [[ $flac2mp3_tag_genre =~ \; ]]; then @@ -821,9 +872,6 @@ for flac2mp3_track in $flac2mp3_tracks; do flac2mp3_import_list+="${flac2mp3_newTrack}|" done IFS=$' \t\n' -# Remove trailing pipe -flac2mp3_import_list="${flac2mp3_import_list%|}" -[ $flac2mp3_debug -ge 1 ] && echo "Debug|Track import list: \"$flac2mp3_import_list\"" | log #### END MAIN #### Call Lidarr API to update database @@ -835,6 +883,9 @@ elif [ $flac2mp3_keep -eq 1 ]; then elif [ -n "$flac2mp3_api_url" ]; then # Check for artist ID if [ -n "$lidarr_artist_id" ]; then + # Remove trailing pipe + flac2mp3_import_list="${flac2mp3_import_list%|}" + [ $flac2mp3_debug -ge 1 ] && echo "Debug|Track import list: \"$flac2mp3_import_list\"" | log # Scan for files to import into Lidarr export flac2mp3_import_count=$(echo $flac2mp3_import_list | awk -F\| '{print NF}') if [ $flac2mp3_import_count -ne 0 ]; then @@ -906,8 +957,4 @@ else flac2mp3_exitstatus=20 fi -# Cool bash feature -flac2mp3_message="Info|Completed in $(($SECONDS/60))m $(($SECONDS%60))s" -echo "$flac2mp3_message" | log -[ $flac2mp3_debug -ge 1 ] && echo "Debug|Exit code ${flac2mp3_exitstatus:-0}" | log -exit ${flac2mp3_exitstatus:-0} \ No newline at end of file +end_script