Maloja → Lidarr Importer
🎯 Overview
A small API service that syncs listening history from a self-hosted Maloja instance and exposes a JSON list of MusicBrainz Artist IDs suitable for Lidarr's Custom Import feature. The service periodically fetches unique artists from Maloja, resolves MusicBrainz IDs where needed, and serves them for automatic import into Lidarr.
✨ Features
- Automatic sync: fetches and updates artist lists on a schedule (configurable).
- MusicBrainz resolution: resolves artist MBIDs even if individual tracks lack them.
- Docker-ready: pull and run a pre-built image — no local build required.
- Lightweight and easy to integrate with Lidarr's import lists.
📦 Prerequisites
- Docker & Docker Compose (v2 recommended)
- A running Maloja instance with API access enabled
- A running Lidarr instance (on same Docker network or reachable from the importer)
🚀 Quick Start (pull the hosted image)
- Copy the sample environment template and edit it:
cp .env.template .env
# edit .env and set SOURCE_API_URL and SOURCE_API_KEY at minimum
-
Edit
docker-compose.yml
(example shown below) to pointimage:
to your hosted image (replaceIMAGE_NAME
). -
Pull the image and start the container:
docker compose pull
docker compose up -d
If you want to make sure Compose does not try to build anything locally:
docker compose up -d --no-build
⚙️ Example .env.template
# Maloja API details
SOURCE_API_URL=https://<your-maloja-url>/apis/mlj_1/scrobbles
SOURCE_API_KEY=<your_api_key>
# Service settings
LISTEN_HOST=0.0.0.0
LISTEN_PORT=5000
# Poll interval in minutes (how often Maloja is queried)
POLL_INTERVAL_MINUTES=60
# Logging: DEBUG, INFO, WARNING, ERROR
LOG_LEVEL=INFO
🐳 Example docker-compose.yml
Replace IMAGE_NAME
with your hosted image (for example: ghcr.io/youruser/maloja-lidarr-importer:latest
).
version: "3.8"
services:
maloja-lidarr-importer:
image: gitea.kansaigaijin.com/KansaiGaijin/Majola-Lidarr-Importer:latest
container_name: maloja-lidarr-importer
restart: unless-stopped
env_file: .env
ports:
- "5000:5000" # optional: expose if you need external access; omit to keep internal only
networks:
- appnet
networks:
appnet:
driver: bridge
- If Lidarr runs in Docker on the same
appnet
network, use the service name as hostname (see Lidarr setup below). - If you prefer not to expose port 5000 externally, remove the
ports:
mapping and keep communication internal to your Docker network.
🎶 Lidarr Setup
- In Lidarr: Settings → Import Lists.
- Click + to add a new list. Choose Custom provider.
- Configure:
- Name:
Maloja List
(or any name) - Tags: optional (e.g.
maloja
) - URL:
- If both services are on the same Docker network:
(Use the service name you used in
http://maloja-lidarr-importer:5000/artists
docker-compose.yml
as hostname.) - If the importer is exposed externally (host port):
http://<host-or-domain>:5000/artists
- If both services are on the same Docker network:
- Minimum Time:
60 Minutes
(or as you prefer) - Password: leave blank (unless you've added authentication via a reverse proxy)
Save and enable the list. Lidarr will poll the URL on its schedule and import new artists present in the JSON array.
🔌 API Endpoints
-
GET /artists
- Returns a JSON array of dictionaries, each containing a
foreignId
field with a MusicBrainz Artist ID.[ {"foreignId": "0b987f3c-7264-439a-a1b9-62a69c9b1d91"}, {"foreignId": "0ebdc5f5-0a11-415a-b6f3-efe0d36c6e9d"} ]
- Lidarr expects objects with a
foreignId
key pointing to the MBID.
- Returns a JSON array of dictionaries, each containing a
-
GET /health
(optional)- Returns basic service health/status (if implemented) — check for
200 OK
.
- Returns basic service health/status (if implemented) — check for
If your running container exposes additional endpoints (metrics, debug), document them here.
🪲 Logs & Troubleshooting
- View logs:
docker compose logs -f maloja-lidarr-importer
- Common issues:
- Empty list in Lidarr: check
.env
values and logs for Maloja API errors (401/403/404). - Lidarr can't reach URL: if using Docker internal hostname, both containers must share a network. If using host exposure, confirm port mapping and firewall.
- CORS / Proxy: If you run a reverse proxy in front of the importer, ensure
GET /artists
is forwarded and not blocked by auth. For public exposure, consider adding basic auth or IP restrictions at the proxy. - MusicBrainz resolution failures: look for log warnings indicating failed lookups; a short retry or increased
POLL_INTERVAL_MINUTES
may help.
- Empty list in Lidarr: check
🛡 Security Notes
- Do not publicly expose the
/artists
endpoint unless behind a reverse proxy or IP restriction if your Maloja or import lists contain sensitive info. - Use HTTPS/secure proxy in production.
- If you add authentication at the proxy layer, configure Lidarr to include credentials or use a private network.
🧰 Deployment tips
- For a single-host Docker setup, the compose example is sufficient.
- For Kubernetes or other orchestrators, convert the compose file to equivalent manifests and mount
.env
as secrets/configmaps where needed. - Use a small monitoring probe that checks
/health
and restarts the container on failures.
🤝 Contributing
Contributions welcome. Please:
- Open an issue for bugs or feature requests.
- Fork the repo, make changes on a topic branch, and submit a PR with a clear description.
- Follow existing code style and add tests for non-trivial logic.
📜 License
This project is provided under the MIT License — see LICENSE
for details.
Contact / Support
If you hit an issue or would like a feature, open an issue in the repo or contact the maintainer listed in commit metadata.