An opinionated, containerized beets distribution.
The beets container image is provided in two flavours:
ghcr.io/mgoltzsche/beets
: beets without additional plugins but the web API installed.ghcr.io/mgoltzsche/beets-plugins
: beets with additional plugins (using the configuration within the library directory):- ytimport: Adds a command to import (liked) tracks from Youtube/SoundCloud into your beets library.
- chroma: Generates/matches an acoustic fingerprint on track import.
- lastgenre: Gets the genre for a track Last.fm on import.
- discogs: Allows to match tracks against Discogs (optional; requires credentials to be configured).
- xtractor: Adds a command to analyze your library using Essentia and store the results as additional track fields within your library.
- describe: Adds a command to visualize the data distribution of a given field within your beets library.
- mpdstats: Adds a command to connect with an MPD player to automatically rate tracks based on play and skip actions.
The following examples assume you have configured a directory as your beets music library as follows:
BEETS_LIBRARY=path/to/your/music/library
mkdir -p $BEETS_LIBRARY
The beets container will store the imported music as well as an SQLite DB and the Beet configuration within that directory.
The ghcr.io/mgoltzsche/beets-plugins
container creates the configuration file $BEETS_LIBRARY/beets/config.yaml
if it does not exist yet.
For more information, see the beets documentation.
To initialize/manage your beets library, you can use the ghcr.io/mgoltzsche/beets-plugins
container image.
You can start a containerized shell as follows:
docker run -it --rm -u `id -u`:`id -g` \
--mount "type=bind,src=${BEETS_LIBRARY},dst=/data" \
ghcr.io/mgoltzsche/beets-plugins
Within the containerized shell you can perform maintenance operations with your music library interactively, e.g.:
# Import songs from Youtube:
beet ytimport https://www.youtube.com/watch?v=8soQkubMk1g \
https://www.youtube.com/watch?v=gtiZL33hoTY
# Import 3 liked songs from Youtube (prompts for login):
beet ytimport --likes --max-likes 3
# List the tracks within your library:
beet ls -f '$artist - $title ($genre)'
# Inspect a particular track:
beet info -l "Ça plane pour moi"
# Assign genres to all tracks:
beet autogenre
# Generate M3U playlists (based on configured rules/queries):
beet splupdate
# Inspect the distribution of genres within your library:
beet describe genre
# Analyze your library using Essentia and save the results as metadata:
beet xtractor
# List supported fields
beet fields
# List the danceable tracks within your library, sorted by danceability:
beet ls -f '$danceable - $artist - $title' danceable:0.8..1 danceable-
# Get a random danceable track:
beet random danceable:0.8..1
To import a local music directory into your beets audio library, run e.g.:
IMPORT_SÒURCE_DIR=path/to/import/audio/from
docker run -it --rm -u `id -u`:`id -g` \
--mount "type=bind,src=${BEETS_LIBRARY},dst=/data" \
--mount "type=bind,src=${IMPORT_SOURCE_DIR},dst=/import" \
ghcr.io/mgoltzsche/beets-plugins import /import -si
Please note that the import
command is prompting you for input for each track without a strong match.
To play tracks via pulseaudio, run e.g.:
docker run -ti --rm -u `id -u`:`id -g` \
--mount "type=bind,src=${BEETS_LIBRARY},dst=/data" \
-v /run:/host/run \
-e PULSE_SERVER=unix:/host/run/user/`id -u`/pulse/native \
ghcr.io/mgoltzsche/beets-plugins play mood_happy:0.8..1 --args=--shuffle
Please note that the PULSE_SERVER
env var has to be specified and, when using a unix socket, the socket to be mounted.
You can access the audio files and generated m3u playlists within your library locally directly using a player of your choice. Similarly, you can copy/sync the library to your mobile phone or export it to an mp3 player in order to be able to listen to your music library even when there's no internet connectivity.
Alternatively, the beets web plugin serves a minimal web GUI and an API that enables (remote) players to browse, search and stream music from your library via HTTP. To serve the beets web API, run:
docker run --rm -u `id -u`:`id -g` -p 8337:8337 \
--mount "type=bind,src=${BEETS_LIBRARY},dst=/data" \
ghcr.io/mgoltzsche/beets
Now you can access your library at e.g. http://localhost:8337
.
When you generated playlists using the beet-splupdate
script within the maintenance container previously, you can access them at http://localhost:8337/m3u/
.
To list all supported targets, run make help
.
- git
- make
- docker 20+
- kubectl (optional; if you want to deploy to Kubernetes)
To build the application container image using skaffold, run:
make image
make beets-sh
make beets-web
To deploy the application using skaffold, run:
make deploy
To deploy the application in debug mode (debug ports forwarded), stream its logs and redeploy on source code changes automatically, run:
make debug
To undeploy the application, run:
make undeploy
To apply blueprint updates to the application codebase, update the kpt package:
- Before updating the package, make sure you don't have uncommitted changes in order to be able to distinguish package update changes from others.
- Call
make blueprint-update
or ratherkpt pkg update
andkpt fn render
(applies the configuration withinsetters.yaml
to the manifests andskaffold.yaml
). - Before committing the changes, review them carefully and make manual changes if necessary.
TL;DR: Variant Constructor Pattern
The release process is driven by Conventional Commits, letting the CI pipeline generate a version and publish a release depending on the commit messages on the main
branch.
The ghcr.io/mgoltzsche/beets-plugins
container image produced by this repository includes a custom build of Essentia extractors as well as a copy of the models.
Essentia is licensed under the GNU Affero General Public License v3.0.