Build and publish container / build (pull_request) Successful in 5m13s
Six rules over the scrobble history and the library index, written as extended M3U into <mirror>/_playlists/ and rebuilt every pass. Three look at what gets played -- heavy rotation, all-time, and things played heavily once and silent for a year. Three look at what does not: album tracks skipped on records otherwise played constantly, unplayed tracks by the artists played most, and unplayed tracks from anywhere. Four fifths of the library has never been played, so both halves are needed. Ninety days was the obvious window for "recent" and is the wrong one. On a real history it holds a few hundred plays spread across a twenty-thousand track rotation, and nothing ranks meaningfully. Twelve months does. The two rotating playlists are shuffled by week rather than by pass. A pass runs every few hours; a playlist that reorders itself each time is one that has to be re-imported each time, because the Music app imports a snapshot of a file rather than tracking it. Lidarr knows where the lossless source is, and the playlists have to point at the MP3s music-mirror produced from it. The library root is derived from the common parent of the indexed artist folders, so it agrees with Lidarr by construction instead of being kept in step by hand, and can be overridden. Entries are relative to the playlist file, so one file works from the NAS, from a Mac over SMB and from Linux. A track is listed only once its mirror file has been confirmed to exist: Lidarr holding the FLAC says nothing about whether the MP3 has been encoded. When many are missing the run says so, because that is what a misconfigured root looks like -- every path mapping to nothing -- and silence there would present an empty playlist as a correct one.
41 lines
1.9 KiB
YAML
41 lines
1.9 KiB
YAML
# TrueNAS Scale "Custom App" definition.
|
|
#
|
|
# Adjust the host path and the user to match your pool. The Last.fm API key is
|
|
# a credential: set it through the app's environment in the TrueNAS UI rather
|
|
# than committing it here.
|
|
services:
|
|
music-curator:
|
|
image: code.emmathe.dev/lyrathorpe/music-curator:latest
|
|
container_name: music-curator
|
|
restart: unless-stopped
|
|
# The dataset owner, so the store is not written as root. `id apps` or the
|
|
# ownership of the dataset will tell you the right numbers.
|
|
user: "568:568"
|
|
environment:
|
|
MUSIC_CURATOR_LASTFM_USER: your-lastfm-username
|
|
# Get one at https://www.last.fm/api/account/create -- a key alone is
|
|
# enough, none of the endpoints used here authenticate a user.
|
|
MUSIC_CURATOR_LASTFM_API_KEY: set-me-in-the-truenas-ui
|
|
MUSIC_CURATOR_DB: /data/curator.db
|
|
# Lidarr, for indexing the library. Read-only: every call is a GET.
|
|
# Leave unset to ingest scrobbles and nothing else.
|
|
MUSIC_CURATOR_LIDARR_URL: http://lidarr:8686
|
|
MUSIC_CURATOR_LIDARR_API_KEY: set-me-in-the-truenas-ui
|
|
# How long to wait between passes. Each one catches up on new scrobbles
|
|
# and continues the backfill if it has not finished.
|
|
MUSIC_CURATOR_INTERVAL: 6h
|
|
# Seconds between API requests. Last.fm asks for no more than five a
|
|
# second; the default leaves plenty of room.
|
|
# MUSIC_CURATOR_REQUEST_DELAY: "0.25"
|
|
# Cap the backfill at this many requests per pass. Unlimited by default,
|
|
# which finishes a long history in one go.
|
|
# MUSIC_CURATOR_BACKFILL_LIMIT: "0"
|
|
# The MP3 mirror music-mirror maintains. Playlists are written into
|
|
# _playlists/ inside it; leave unset to skip them.
|
|
MUSIC_CURATOR_MIRROR: /mirror
|
|
# Most tracks in any one playlist.
|
|
# MUSIC_CURATOR_PLAYLIST_LIMIT: "100"
|
|
volumes:
|
|
- /mnt/tank/apps/music-curator:/data
|
|
- /mnt/tank/media/music-mp3:/mirror
|