Mirrors your Navidrome starred songs to ListenBrainz recording loves on a schedule.
  • Go 99.1%
  • Dockerfile 0.9%
Find a file
devilreef a8ed2b9de6
All checks were successful
mirror to github / mirror (push) Successful in 8s
ci / build-image (push) Successful in 1m29s
ci: add forgejo workflows for image build/push and github mirror
2026-05-28 17:55:52 +06:00
.forgejo/workflows ci: add forgejo workflows for image build/push and github mirror 2026-05-28 17:55:52 +06:00
cmd/likesync refactor: normalize mbids, drop dead field, add cache ttl 2026-05-28 17:11:40 +06:00
internal refactor: normalize mbids, drop dead field, add cache ttl 2026-05-28 17:11:40 +06:00
.dockerignore chore: scaffold go module and ignore files 2026-05-28 15:52:08 +06:00
.env.example refactor: normalize mbids, drop dead field, add cache ttl 2026-05-28 17:11:40 +06:00
.gitignore chore: scaffold go module and ignore files 2026-05-28 15:52:08 +06:00
docker-compose.yml feat: add docker build, compose, and docs 2026-05-28 16:09:14 +06:00
Dockerfile feat: add docker build, compose, and docs 2026-05-28 16:09:14 +06:00
go.mod chore: scaffold go module and ignore files 2026-05-28 15:52:08 +06:00
go.sum chore: scaffold go module and ignore files 2026-05-28 15:52:08 +06:00
README.md refactor: normalize mbids, drop dead field, add cache ttl 2026-05-28 17:11:40 +06:00

likesync

Mirrors your Navidrome starred songs to ListenBrainz recording loves on a schedule.

One-way: Navidrome stars -> ListenBrainz love feedback. Un-starring a track in Navidrome removes the love on ListenBrainz — but only for loves this tool created (tracked in a local SQLite DB). Loves you made elsewhere are never touched.

How matching works

Each starred song is resolved to a MusicBrainz recording MBID:

  1. The musicBrainzId returned by Navidrome (present when your library is tagged).
  2. If absent and MBID_LOOKUP_ENABLED=true, the ListenBrainz metadata lookup is queried by artist + title (+ album). Results are cached.
  3. Otherwise the track is skipped and logged.

On a large, poorly-tagged library the first run issues one ListenBrainz metadata lookup per uncached track and can hit rate limits — expect a burst of resolve failed logs that clear on later cycles (results, including misses, are cached). To avoid this, tag your library with MusicBrainz IDs (e.g. via Picard) so the musicBrainzId is present, or set MBID_LOOKUP_ENABLED=false.

Configuration

Var Default Notes
NAVIDROME_URL required, e.g. https://music.example.com
NAVIDROME_USERNAME required
NAVIDROME_PASSWORD required
LISTENBRAINZ_TOKEN required, from https://listenbrainz.org/settings/
LISTENBRAINZ_URL https://api.listenbrainz.org override for self-hosted
SYNC_INTERVAL 1h Go duration (e.g. 30m, 6h)
RUN_ON_START true run a sync immediately on boot
MBID_LOOKUP_ENABLED true metadata-lookup fallback toggle
MBID_CACHE_TTL 720h how long lookup results (incl. misses) are cached; 0 = never expire
STATE_PATH /data/likesync.db SQLite file path
LOG_LEVEL info debug/info/warn/error
DRY_RUN false log intended changes, write nothing

Run

cp .env.example .env   # fill in your values
docker compose up -d --build
docker compose logs -f

Do a DRY_RUN=true pass first to preview what would change.