Sign inSign up

j3ko/gainbridge

By j3ko

โ€ขUpdated 9 days ago

Syncs ReplayGain/loudness tags from Plex or Jellyfin into your music files.

Image
1

5.4K

j3ko/gainbridge repository overview

โ Gainbridge

Gainbridge keeps ReplayGain/loudness tags on your music library in sync with what Plex or Jellyfin already knows, so every player that respects ReplayGain plays your library at a consistent volume.

Point it at one or more Plex or Jellyfin servers, and it periodically reads the loudness data those servers already compute and writes standard ReplayGain tags into the actual audio files - no separate loudness scan needed.

โ Why

Plex and Jellyfin both analyze audio loudness for their own volume-leveling features, but that data lives in their databases, not in your files. If you ever move your library, play it through something other than Plex/Jellyfin, or just want tags that work everywhere, that analysis is locked away. Gainbridge pulls it out and writes it where it belongs: directly into the file's own ReplayGain tags (ID3 TXXX, MP4 freeform atoms, Vorbis comments).

โ Features

  • ๐ŸŽง Syncs ReplayGain tags from Plex and Jellyfin libraries.
  • ๐Ÿ” Scheduled or on-demand sync jobs, scoped to a whole server or a single library.
  • ๐Ÿงช Dry-run mode to preview what would change before writing anything.
  • โœ๏ธ Configurable write behavior: skip existing tags, fix only what's missing, or overwrite everything.
  • ๐Ÿ—‚๏ธ Remote-to-local path mappings, for when your media server sees a different filesystem path than Gainbridge does.
  • ๐Ÿ“‹ A Jobs view to track sync runs, and a Logs view to debug connection or file-write issues.
  • ๐Ÿฆ‡ Dark mode.

โ Screenshots

โ Sources

Sources

โ Jobs

Jobs

โ Logs

Logs

โ Interactive API Documentation

API docs

โ Technology Stack

โ Quick Start

docker compose watch

Then open:

From there, add a Plex or Jellyfin source with its server URL and an API token, optionally scope it to one library and set a sync schedule, and run a sync.

โ Running with Docker

For production, pull the published image, which bundles the backend and frontend into a single container:

docker pull j3ko/gainbridge:latest

Use :edge instead of :latest to track the tip of main between releases.

docker run -d \
  --name gainbridge \
  -p 9210:9210 \
  -v ./data:/app/data \
  -v /path/to/music:/music \
  -v /etc/localtime:/etc/localtime:ro \
  -v /etc/timezone:/etc/timezone:ro \
  j3ko/gainbridge:latest

The data/ volume mount keeps the SQLite database and log file across container restarts and upgrades. The /etc/localtime and /etc/timezone mounts match the container's timezone to the host's, so timestamps shown in the UI are in local time instead of UTC, and source schedules (schedule_cron) run at the wall-clock time you'd expect rather than UTC. See Configurationโ  below for other environment variables.

โ Configuration

Configuration lives in the top-level .env file. At minimum, review:

  • SQLITE_DB_FILE / LOG_FILE - paths to the SQLite database and log file, by default under the top-level data/ folder, which is bind-mounted into the backend container so it persists across restarts and redeploys.
  • BACKEND_CORS_ORIGINS - required if the frontend is served from a different origin than the backend.
  • TIMEZONE - IANA zone name (e.g. America/Toronto) that source schedules (schedule_cron) are evaluated in. Auto-detected from the TZ env var or the container's system timezone (see the /etc/localtime//etc/timezone mounts above) if unset - only set this to override that detection.

โ Documentation

โ License

Gainbridge is licensed under the terms of the MIT license.

Tag summary

Content type

Image

Digest

sha256:e4a9be1c7โ€ฆ

Size

474.9 MB

Last updated

9 days ago

docker pull j3ko/gainbridge