Lossifier is a docker image that takes your lossless FLAC music collection and creates a "mirror" of it in a lossy format (.opus or .mp3), for use with DAPs or other mobile devices.
It's designed to work idempotently, so you can run it on a schedule as you add music to the flac collection - subsequent runs will only run faster.
The (currently) supported target formats are Opus (for best quality / lowest bitrates) and MP3 (for maximum compatibility). The default target format is Opus, but you can change it with an env var.
Some extra effort has been made to maintain the metadata of the original FLAC files in the resulting lossy collection. This includes tags like title, artist, album, track number, album artist, genre, and cover art.
You can use an arbitrary directory structure in the input collection and it will be maintained in the result - the main thing that will change is the file sizes and music format.
If the default target bitrate is 192kbps, and the opus encoder is configured with --no-phase-inv --downmix-stereo flags, to avoid any issues when played on mono systems (phones, bluetooth speakers, some DJ uses).
The encoder options can be set arbitrarily with env vars.
Ignoring hidden files
The script deliberately ignores hidden files and directories. This behaviour has a number of benefits, but the most noticeable is ignoring trash files created by MacOS.
You can specify extra file extensions to copy from the input directory to the output directory. This is useful for copying cover art, lyrics, playlists files, or music files that couldn't be obtained in FLAC, but should be included in the resulting lossy collection.
Mapping metadata tags can be tricky, but if any issues are found, we can add them to the bashunit integration tests to enforce correct behaviour
Available on DockerHub: https://hub.docker.com/r/nietaki/lossifier
The latest tag points to the most recent stable release, there's also versioned tags for each release, and master for the most recent master branch build.
Basic usage:
$ export UID=$(id -u)
$ export GID=$(id -g)
$ docker run -it --rm \
-u "$UID:$GID" \
-v /path/to/flac/music:/data/input:ro \
-v /path/of/target/directory:/data/output \
-e TARGET_FORMAT=opus \
nietaki/lossifier:latestYou can see the input/output directory mounts and a sample env var for configuration. The UID/GID helps make sure you don't get a bunch of root-owned files in the output directory. The input directory can be mounted read-only to ensure your source collection is safe from any harm.
So in the project root, a test run could look like this:
$ export UID=$(id -u)
$ export GID=$(id -g)
$ docker run -it --rm \
-u "$UID:$GID" \
-v ./test/input:/data/input:ro \
-v ./test/output:/data/output \
-e TARGET_FORMAT=opus \
nietaki/lossifier:latestFor convenience, the script is configured with environment variables. The following variables are available:
| ENV var name | description | values (default) |
|---|---|---|
TARGET_FORMAT |
the lossy format you want to convert to | opus, mp3 |
TARGET_BITRATE |
the target average bitrate of the converted files in kbps | usually between 11 and 320, 192 by default |
EXTRA_OPUS_FLAGS |
extra flags to pass to opusenc (ignored if TARGET_FORMAT is not opus) |
defaults to --no-phase-inv --downmix-stereo |
EXTRA_LAME_FLAGS |
extra flags to pass to lame (ignored if TARGET_FORMAT is not mp3) |
defaults to -q 2 |
OVERWRITE_MODE |
how to handle existing files in the output directory. | always, if_newer, never |
EXTRA_FILE_EXTENSIONS |
extra file extensions to copy from the input directory to the output directory (comma-separated) | comma-separated list, like jpg,jpeg,png,txt,mp3 |
PLAYLISTS_DIR |
directory, in which where each subdirectory represents a playlist. Must be a relative path (WRT the input directory) | "" |
M3U_DIRS |
comma-separated list of (relative) directories that should be filled with .m3u playlist files. If the directories don't exist, they will be created. Again, relative paths only |
"" |
You can see the supported ENV vars and their default values by inspecting the docker image:
$ docker pull nietaki/lossifier:latest
$ docker inspect nietaki/lossifier:latest | jq 'map(.Config.Env)[0]'
[
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"INPUT_DIR=/data/input",
"OUTPUT_DIR=/data/output",
"TARGET_FORMAT=opus",
"TARGET_BITRATE=192",
"EXTRA_LAME_FLAGS=-q 1",
"EXTRA_OPUS_FLAGS=--no-phase-inv --downmix-stereo",
"OVERWRITE_MODE=if_newer",
"EXTRA_FILE_EXTENSIONS=jpg,jpeg,png,txt,mp3"
]