Merge pull request #94 from TheCaptain989/lidarr-flac2mp3

Lidarr: flac2mp3 initial release
This commit is contained in:
aptalca 2020-10-31 17:42:10 -04:00 committed by GitHub
commit 07530d37e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 410 additions and 71 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
.assets/lidarr-synology.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -6,8 +6,8 @@ jobs:
build:
env:
DOCKERHUB: "linuxserver/mods" #don't modify
BASEIMAGE: "baseimagename" #replace
MODNAME: "modname" #replace
BASEIMAGE: "lidarr" #replace
MODNAME: "flac2mp3" #replace
runs-on: ubuntu-latest
steps:
@ -17,7 +17,6 @@ jobs:
id: build
run: |
docker build --no-cache -t ${DOCKERHUB}:${BASEIMAGE}-${MODNAME}-${{ github.sha }} .
- name: Push image
if: ${{ github.ref == format('refs/heads/{0}-{1}', env.BASEIMAGE, env.MODNAME) }}
run: |

View File

@ -1,6 +1,20 @@
## Buildstage ##
FROM lsiobase/ubuntu:xenial as buildstage
# Build arguments
ARG VERSION
# Add version number for use in container init script
RUN mkdir -p /root-layer/etc && \
echo "$VERSION" > /root-layer/etc/version.tc989
# Stage local files
COPY root/ /root-layer/
## Single layer deployed image ##
FROM scratch
LABEL maintainer="username"
LABEL maintainer="TheCaptain989"
# copy local files
COPY root/ /
# Copy files from buildstage
COPY --from=buildstage /root-layer/ /

View File

@ -1,23 +0,0 @@
## Buildstage ##
FROM lsiobase/alpine:3.12 as buildstage
RUN \
echo "**** install packages ****" && \
apk add --no-cache \
curl && \
echo "**** grab rclone ****" && \
mkdir -p /root-layer && \
curl -o \
/root-layer/rclone.deb -L \
"https://downloads.rclone.org/v1.47.0/rclone-v1.47.0-linux-amd64.deb"
# copy local files
COPY root/ /root-layer/
## Single layer deployed image ##
FROM scratch
LABEL maintainer="username"
# Add files from buildstage
COPY --from=buildstage /root-layer/ /

View File

@ -1,17 +1,91 @@
# Rsync - Docker mod for openssh-server
A [Docker Mod](https://github.com/linuxserver/docker-mods) for the LinuxServer.io Lidarr Docker container that adds a script to automatically convert downloaded FLAC files to MP3s using ffmpeg. Default quality is 320Kbps.
This mod adds rsync to openssh-server, to be installed/updated during container start.
>**NOTE:** This mod support Linux OSes only.
In openssh-server docker arguments, set an environment variable `DOCKER_MODS=linuxserver/mods:openssh-server-rsync`
Container info:
![Docker Image Size (latest by date)](https://img.shields.io/docker/image-size/linuxserver/mods/lidarr-flac2mp3))
If adding multiple mods, enter them in an array separated by `|`, such as `DOCKER_MODS=linuxserver/mods:openssh-server-rsync|linuxserver/mods:openssh-server-mod2`
# Installation
1. Pull the [linuxserver/lidarr](https://hub.docker.com/r/linuxserver/lidarr "LinuxServer.io's Lidarr container") docker image from Docker Hub:
`docker pull linuxserver/lidarr:latest`
# Mod creation instructions
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 the **DOCKER_MODS** environment variable to the `docker create` command, as follows:
`-e DOCKER_MODS=linuxserver/mods:lidarr-flac2mp3`
* Fork the repo, create a new branch based on the branch `template`.
* Edit the `Dockerfile` for the mod. `Dockerfile.complex` is only an example and included for reference; it should be deleted when done.
* Inspect the `root` folder contents. Edit, add and remove as necessary.
* Edit this readme with pertinent info, delete these instructions.
* Finally edit the `.github/workflows/BuildImage.yml`. Customize the build branch, and the vars for `BASEIMAGE` and `MODNAME`.
* Ask the team to create a new branch named `<baseimagename>-<modname>`. Baseimage should be the name of the image the mod will be applied to. The new branch will be based on the `template` branch.
* Submit PR against the branch created by the team.
*Example Synology Configuration*
![flac2mp3](.assets/lidarr-synology.png "Synology container settings")
2. Start the container.
3. After all of the above configuration is complete, to use ffmpeg, configure a custom script from the Settings->Connect screen and type the following in the **Path** field:
`/usr/local/bin/flac2mp3.sh`
## Usage
New file(s) with an MP3 extension will be placed in the same directory as the original FLAC file(s). Existing MP3 files with the same track name will be overwritten.
If you've configured the Lidarr Recycle Bin path correctly, the original video will be moved there.
![warning24] **NOTE:** If you have *not* configured the Recycle Bin, the original FLAC audio file(s) will be deleted and permanently lost.
### Syntax
>**Note:** The **Arguments** field for Custom Scripts was removed in Lidarr release [v0.7.0.1347](https://github.com/lidarr/Lidarr/commit/b9d240924f8965ebb2c5e307e36b810ae076101e "Lidarr commit notes") due to security concerns.
To support options with this version and later, a wrapper script can be manually created that will call *flac2mp3.sh* with the required arguments.
The script accepts two options which may be placed in the **Arguments** field:
`[-d] [-b <bitrate>]`
The `-b bitrate` option, if specified, sets the output quality in bits per second. If no `-b` option is specified, the script will default to 320Kbps.
The `-d` option enables debug logging.
### Examples
```
-b 320k # Output 320 kilobits per second MP3 (same as default behavior)
-d -b 160k # Enable debugging, and output 160 kilobits per second MP3
```
### Included Wrapper Script
For your convenience, a wrapper script to enable debugging is included in the `/usr/local/bin/` directory.
Use this script in place of the `flac2mp3.sh` mentioned in the [Installation](./README.md#installation) section above.
```
flac2mp3-debug.sh # Enable debugging
```
### Example Wrapper Script
To configure the last entry from the [Examples](./README.md#examples) section above, create and save a file called `wrapper.sh` to `/usr/local/bin` containing the following text:
```
#!/bin/bash
. /usr/local/bin/flac2mp3.sh -d -b 160k
```
Then put `/usr/local/bin/wrapper.sh` in the **Path** field in place of `/usr/local/bin/flac2mp3.sh` mentioned in the [Installation](./README.md#installation) section above.
### Triggers
The only events/notification triggers that have been tested are **On Release Import** and **On Upgrade**
![lidarr-flac2mp3](.assets/lidarr-custom-script.png "Lidarr Custom Script dialog")
### Logs
A log file is created for the script activity called:
`/config/logs/flac2mp3.txt`
This log can be downloaded from the Lidarr GUI under System->Log Files
Log rotation is performed, with 5 log files of 1MB each kept, matching Lidarr's log retention.
>![warning24] **NOTE:** If debug logging is enabled, the log file can grow very large very quickly. *Do not leave debug logging enabled permanently.*
___
# Credits
This would not be possible without the following:
[Lidarr](https://lidarr.audio/ "Lidarr homepage")
[LinuxServer.io Lidarr](https://hub.docker.com/r/linuxserver/lidarr "Lidarr Docker container") container
[LinuxServer.io Docker Mods](https://hub.docker.com/r/linuxserver/mods "Docker Mods containers") project
[ffmpeg](https://ffmpeg.org/ "FFMpeg homepage")
[warning]: http://files.softicons.com/download/application-icons/32x32-free-design-icons-by-aha-soft/png/32/Warning.png "Warning"
[warning24]: http://files.softicons.com/download/toolbar-icons/24x24-free-pixel-icons-by-aha-soft/png/24x24/Warning.png "Warning"

View File

@ -0,0 +1,46 @@
#!/usr/bin/with-contenv bash
cat <<EOF
----------------
>>> Flac2MP3 Mod by TheCaptain989 <<<
Repo: https://github.com/linuxserver/docker-mods/tree/lidarr-flac2mp3
Version: $(cat /etc/version.tc989)
----------------
EOF
# Determine if setup is needed
if [ ! -f /usr/bin/ffmpeg ]; then
echo "Running first time setup."
if [ -f /usr/bin/apt ]; then
# Ubuntu
echo "Installing ffmpeg using apt-get"
apt-get update && \
apt-get -y install ffmpeg && \
rm -rf /var/lib/apt/lists/*
elif [ -f /sbin/apk ]; then
# Alpine
echo "Installing ffmpeg using apk"
apk add --no-cache ffmpeg && \
rm -rf /var/lib/apt/lists/*
else
# Unknown
echo "Unknown package manager. Attempting to install ffmpeg using apt-get"
apt-get update && \
apt-get -y install ffmpeg && \
rm -rf /var/lib/apt/lists/*
fi
fi
# Change ownership
if [ $(stat -c '%G' /usr/local/bin/flac2mp3.sh) != "abc" ]; then
echo "Changing ownership on scripts."
chown abc:abc /usr/local/bin/flac2mp3*.sh
fi
# Make executable
if [ ! -x /usr/local/bin/flac2mp3.sh ]; then
echo "Making scripts executable."
chmod +x /usr/local/bin/flac2mp3*.sh
fi

View File

@ -1,27 +0,0 @@
#!/usr/bin/with-contenv bash
# Determine if setup is needed
if [ ! -f /usr/local/lib/python***/dist-packages/sshuttle ] && \
[ -f /usr/bin/apt ]; then
## Ubuntu
apt-get update
apt-get install --no-install-recommends -y \
iptables \
openssh-client \
python3 \
python3-pip
pip3 install sshuttle
fi
if [ ! -f /usr/lib/python***/site-packages/sshuttle ] && \
[ -f /sbin/apk ]; then
# Alpine
apk add --no-cache \
iptables \
openssh \
py3-pip \
python3
pip3 install sshuttle
fi
chown -R root:root /root
chmod -R 600 /root/.ssh

View File

@ -1,3 +0,0 @@
#!/usr/bin/with-contenv bash
sshuttle --dns --remote root@${HOST}:${PORT} 0/0 -x 172.17.0.0/16

View File

@ -0,0 +1,3 @@
#!/bin/bash
. /usr/local/bin/flac2mp3.sh -d

View File

@ -0,0 +1,256 @@
#!/bin/bash
# Script to convert FLAC files to MP3 using FFMpeg
# https://github.com/linuxserver/docker-mods/tree/lidarr-flac2mp3
# Can also process MP3s and tag them appropriately
# Resultant MP3s are fully tagged
# Dependencies:
# ffmpeg
# awk
# stat
# nice
# Exit codes:
# 0 - success; or test
# 1 - no tracks files specified on command line
# 2 - mkvmerge not found
# 10 - awk script generated an error
### Variables
export flac2mp3_script=$(basename "$0")
export flac2mp3_pid=$$
export flac2mp3_config=/config/config.xml
export flac2mp3_log=/config/logs/flac2mp3.txt
export flac2mp3_maxlogsize=1024000
export flac2mp3_maxlog=4
export flac2mp3_debug=0
export flac2mp3_tracks="$lidarr_addedtrackpaths"
[ -z "$flac2mp3_tracks" ] && flac2mp3_tracks="$lidarr_trackfile_path" # For other event type
export flac2mp3_recyclebin=$(sqlite3 /config/lidarr.db 'SELECT Value FROM Config WHERE Key="recyclebin"')
RET=$?; [ "$RET" != 0 ] && >&2 echo "WARNING[$RET]: Unable to read recyclebin information from database \"/config/lidarr.db\""
### Functions
function usage {
usage="
$flac2mp3_script
Audio conversion script designed for use with Bazarr
Source: https://github.com/TheCaptain989/lidarr-flac2mp3
Usage:
$0 [-d] [-b <bitrate>]
Arguments:
bitrate # output quality in bits per second (SI units)
Options:
-d # enable debug logging
-b # set bitrate; default 320K
Examples:
$flac2mp3_script -b 320k # Output 320 kilobits per second MP3
(same as default behavior)
$flac2mp3_script -d -b 160k # Enable debugging, and output quality
160 kilobits per second
"
>&2 echo "$usage"
}
# Can still go over flac2mp3_maxlog if read line is too long
# Must include whole function in subshell for read to work!
function log {(
while read
do
echo $(date +"%y-%-m-%-d %H:%M:%S.%1N")\|"[$flac2mp3_pid]$REPLY" >>"$flac2mp3_log"
local FILESIZE=$(stat -c %s "$flac2mp3_log")
if [ $FILESIZE -gt $flac2mp3_maxlogsize ]
then
for i in `seq $((flac2mp3_maxlog-1)) -1 0`
do
[ -f "${flac2mp3_log::-4}.$i.txt" ] && mv "${flac2mp3_log::-4}."{$i,$((i+1))}".txt"
done
[ -f "${flac2mp3_log::-4}.txt" ] && mv "${flac2mp3_log::-4}.txt" "${flac2mp3_log::-4}.0.txt"
touch "$flac2mp3_log"
fi
done
)}
# Inspired by https://stackoverflow.com/questions/893585/how-to-parse-xml-in-bash
function read_xml {
local IFS=\>
read -d \< ENTITY CONTENT
}
# Initiate API Rescan request
function rescan {
MSG="Info|Calling Lidarr API to rescan artist"
echo "$MSG" | log
[ $flac2mp3_debug -eq 1 ] && echo "Debug|Forcing rescan of artist '$lidarr_artist_id'. Calling Lidarr API 'RefreshArtist' using POST and URL 'http://$flac2mp3_bindaddress:$flac2mp3_port$flac2mp3_urlbase/api/v1/command?apikey=(removed)'" | log
RESULT=$(curl -s -d "{name: 'RefreshArtist', artistId: $lidarr_artist_id}" -H "Content-Type: application/json" \
-X POST http://$flac2mp3_bindaddress:$flac2mp3_port$flac2mp3_urlbase/api/v1/command?apikey=$flac2mp3_apikey)
[ $flac2mp3_debug -eq 1 ] && echo "API returned: $RESULT" | awk '{print "Debug|"$0}' | log
JOBID="$(echo $RESULT | jq -crM .id)"
if [ "$JOBID" != "null" ]; then
local RET=0
else
local RET=1
fi
return $RET
}
# Check result of rescan job
function check_rescan {
local i=0
for ((i=1; i <= 15; i++)); do
[ $flac2mp3_debug -eq 1 ] && echo "Debug|Checking job $JOBID completion, try #$i. Calling Lidarr API using GET and URL 'http://$flac2mp3_bindaddress:$flac2mp3_port$flac2mp3_urlbase/api/command/$JOBID?apikey=(removed)'" | log
RESULT=$(curl -s -H "Content-Type: application/json" \
-X GET http://$flac2mp3_bindaddress:$flac2mp3_port$flac2mp3_urlbase/api/v1/command/$JOBID?apikey=$flac2mp3_apikey)
[ $flac2mp3_debug -eq 1 ] && echo "API returned: $RESULT" | awk '{print "Debug|"$0}' | log
if [ "$(echo $RESULT | jq -crM .status)" = "completed" ]; then
local RET=0
break
else
if [ "$(echo $RESULT | jq -crM .status)" = "failed" ]; then
local RET=2
break
else
local RET=1
sleep 1
fi
fi
done
return $RET
}
# Process options
while getopts ":db:" opt; do
case ${opt} in
d ) # For debug purposes only
MSG="Debug|Enabling debug logging."
echo "$MSG" | log
>&2 echo "$MSG"
flac2mp3_debug=1
printenv | sort | sed 's/^/Debug|/' | log
;;
b ) # Set bitrate
flac2mp3_bitrate="$OPTARG"
;;
: )
MSG="Error|Invalid option: -$OPTARG requires an argument"
echo "$MSG" | log
>&2 echo "$MSG"
;;
esac
done
shift $((OPTIND -1))
# Set default bitrate
[ -z "$flac2mp3_bitrate" ] && flac2mp3_bitrate="320k"
if [[ "$lidarr_eventtype" = "Test" ]]; then
echo "Info|Lidarr event: $lidarr_eventtype" | log
echo "Info|Script was test executed successfully." | log
exit 0
fi
if [ -z "$flac2mp3_tracks" ]; then
MSG="Error|No track file(s) specified! Not called from Lidarr?"
echo "$MSG" | log
>&2 echo "$MSG"
usage
exit 1
fi
if [ ! -f "/usr/bin/ffmpeg" ]; then
MSG="Error|/usr/bin/ffmpeg is required by this script"
echo "$MSG" | log
>&2 echo "$MSG"
exit 2
fi
# Legacy one-liner script
#find "$lidarr_artist_path" -name "*.flac" -exec bash -c 'ffmpeg -loglevel warning -i "{}" -y -acodec libmp3lame -b:a 320k "${0/.flac}.mp3" && rm "{}"' {} \;
#### MAIN
echo "Info|Lidarr event: $lidarr_eventtype, Artist: $lidarr_artist_name ($lidarr_artist_id), Album: $lidarr_album_title ($lidarr_album_id), Export bitrate: $flac2mp3_bitrate, Tracks: $flac2mp3_tracks" | log
echo "$flac2mp3_tracks" | awk -v Debug=$flac2mp3_debug \
-v Recycle="$flac2mp3_recyclebin" \
-v Bitrate=$flac2mp3_bitrate '
BEGIN {
FFMpeg="/usr/bin/ffmpeg"
FS="|"
RS="|"
IGNORECASE=1
}
/\.flac/ {
Track=$1
sub(/\n/,"",Track)
NewTrack=substr(Track, 1, length(Track)-5)".mp3"
print "Info|Writing: "NewTrack
if (Debug) print "Debug|Executing: nice "FFMpeg" -loglevel error -i \""Track"\" "CoverCmds1"-map 0 -y -acodec libmp3lame -b:a "Bitrate" -write_id3v1 1 -id3v2_version 3 "CoverCmds2"\""NewTrack"\""
Result=system("nice "FFMpeg" -loglevel error -i \""Track"\" "CoverCmds1"-map 0 -y -acodec libmp3lame -b:a "Bitrate" -write_id3v1 1 -id3v2_version 3 "CoverCmds2"\""NewTrack"\" 2>&1")
if (Result) {
print "Error|"Result" converting \""Track"\""
} else {
if (Recycle=="") {
if (Debug) print "Debug|Deleting: \""Track"\""
system("[ -s \""NewTrack"\" ] && [ -f \""Track"\" ] && rm \""Track"\"")
} else {
match(Track,/^\/?[^\/]+\//)
RecPath=substr(Track,RSTART+RLENGTH)
sub(/[^\/]+$/,"",RecPath)
RecPath=Recycle RecPath
if (Debug) print "Debug|Moving: \""Track"\" to \""RecPath"\""
system("[ ! -e \""RecPath"\" ] && mkdir -p \""RecPath"\"; [ -s \""NewTrack"\" ] && [ -f \""Track"\" ] && mv -t \""RecPath"\" \""Track"\"")
}
}
}
' | log
RET="${PIPESTATUS[1]}" # captures awk exit status
if [ $RET != "0" ]; then
# Check for script completion and non-empty file
MSG="Error|Script exited abnormally. File permissions issue?"
echo "$MSG" | log
>&2 echo "$MSG"
exit 10
fi
# Call Lidarr API to RescanArtist
if [ ! -z "$lidarr_artist_id" ]; then
if [ -f "$flac2mp3_config" ]; then
# Read Lidarr config.xml
while read_xml; do
[[ $ENTITY = "Port" ]] && flac2mp3_port=$CONTENT
[[ $ENTITY = "UrlBase" ]] && flac2mp3_urlbase=$CONTENT
[[ $ENTITY = "BindAddress" ]] && flac2mp3_bindaddress=$CONTENT
[[ $ENTITY = "ApiKey" ]] && flac2mp3_apikey=$CONTENT
done < $flac2mp3_config
[[ $flac2mp3_bindaddress = "*" ]] && flac2mp3_bindaddress=localhost
# Scan the disk for the new audio tracks
if rescan; then
# Check that the rescan completed
if ! check_rescan; then
# Timeout or failure
MSG="Warn|Lidarr job ID $JOBID timed out or failed."
echo "$MSG" | log
>&2 echo "$MSG"
fi
else
# Error from API
MSG="Error|The 'RefreshArtist' API with artist $lidarr_artist_id failed."
echo "$MSG" | log
>&2 echo "$MSG"
fi
else
MSG="Warn|Unable to locate Lidarr config file: '$flac2mp3_config'"
echo "$MSG" | log
>&2 echo "$MSG"
fi
else
MSG="Warn|Missing environment variable lidarr_artist_id"
echo "$MSG" | log
>&2 echo "$MSG"
fi
# Cool bash feature
MSG="Info|Completed in $(($SECONDS/60))m $(($SECONDS%60))s"
echo "$MSG" | log