Musikat

Musikat

Docker app from grtgbln's Repository

Overview

A modern web application that allows users to search for songs on Spotify and automatically download them from YouTube, then seamlessly add them to your Navidrome music server. Perfect for building your personal music library with proper metadata, album art, and organized file structure.

Musikat — Navidrome and local downloads

Search Deezer (default, no API key) or Spotify (optional credentials) for tracks and albums, download audio from YouTube with yt-dlp, apply ID3 tags and artwork, then save to your browser downloads or copy into one or more Navidrome music library folders on the server.

Choose the catalog in the web UI (Catalog) or set DEFAULT_METADATA_PROVIDER in .env.

Screenshots

Main Interface

Main Interface

Download Queue with Progress Bars

Download Queue

Features

  • Search Deezer or Spotify for tracks and albums
  • Download from YouTube using catalog metadata; optional YouTube cookies when YouTube blocks automation
  • ID3 tagging (artist, album, cover art) via the metadata service
  • Download to: local (browser) or any configured Navidrome music root (multiple libraries supported — no need to run separate app instances)
  • Web UI with download queue and status polling
  • Background library sync (optional): scan Navidrome folders and align “already downloaded” state with the catalog

Architecture

Layer Technology
Frontend HTML, CSS, vanilla JavaScript
Backend Python FastAPI
Catalog Deezer (public search) or Spotify Web API (optional)
Audio yt-dlp + FFmpeg
Tags mutagen
Server library Files copied under Navidrome music path(s); optional Navidrome API for scans

Prerequisites

Docker: Docker and Docker Compose

Manual: Python 3.8+ (3.11+ recommended), FFmpeg on PATH, optional Navidrome instance

Spotify in the UI requires SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET in backend/.env.

Installation

Docker Compose (recommended)

git clone https://github.com/soggy8/musikat.git
cd musikat

cp backend/env.example backend/.env
# Edit backend/.env: Navidrome path(s), optional Spotify, DEFAULT_METADATA_PROVIDER

docker-compose up -d

Open http://localhost:8000.

Mount your Navidrome music directory in docker-compose.yml (see DOCKER.md).

Manual install

See SETUP.md.

cd backend
python -m venv venv
source venv/bin/activate   # Windows: venv\Scripts\activate
pip install -r requirements.txt

Install FFmpeg (e.g. sudo apt install ffmpeg on Debian/Ubuntu, brew install ffmpeg on macOS).

Configuration (backend/.env)

Copy backend/env.example to backend/.env and adjust.

Metadata catalog

Variable Description
DEFAULT_METADATA_PROVIDER deezer (default) or spotify
SPOTIFY_CLIENT_ID / SPOTIFY_CLIENT_SECRET Required if you use Spotify in the UI
SPOTIFY_REDIRECT_URI OAuth redirect (default http://localhost:8000/callback)

Navidrome — one or multiple library folders

The app writes files on disk under paths the server is allowed to use. Navidrome should use the same folder(s) as its music library.

Variable Description
NAVIDROME_MUSIC_PATH Single absolute path (default in code: /music if unset). Used when NAVIDROME_MUSIC_PATHS is not set.
NAVIDROME_MUSIC_PATHS Optional. Comma- or newline-separated absolute paths. Each appears as a separate Download to target.
NAVIDROME_MUSIC_LABELS Optional. Same order as NAVIDROME_MUSIC_PATHS; labels shown in the UI (defaults to folder basename).
NAVIDROME_API_URL Navidrome base URL (for scans), e.g. http://localhost:4533
NAVIDROME_USERNAME / NAVIDROME_PASSWORD Optional; for triggering library scans via API
NAVIDROME_SYNC_ENABLED true/false — background scan of library paths to sync “already downloaded” hints (default on)
NAVIDROME_SYNC_INTERVAL_HOURS Between sync runs
NAVIDROME_SYNC_INITIAL_DELAY_SEC Delay before first sync after startup

Examples

Single folder (typical Docker mount):

NAVIDROME_MUSIC_PATH=/music

Multiple libraries:

NAVIDROME_MUSIC_PATHS=/data/music/rock,/data/music/classical
NAVIDROME_MUSIC_LABELS=Rock,Classical

Downloads and API

Variable Description
DOWNLOAD_DIR Server temp/staging for downloads (default ./downloads)
OUTPUT_FORMAT / AUDIO_QUALITY Default encode settings
YOUTUBE_COOKIES_PATH Netscape cookies file for yt-dlp when YouTube blocks requests
API_HOST / API_PORT Bind address
CORS_ORIGINS Comma-separated allowed origins

Running

cd backend
uvicorn app:app --host 0.0.0.0 --port 8000 --reload

Or python app.py if your entrypoint wraps uvicorn. The UI is served from the same process (no separate frontend server).

Usage

  1. Open the app in the browser.
  2. Under Download to, choose My Downloads Folder (System) or a Navidrome path (loaded from GET /api/navidrome/libraries / your env).
  3. Pick Catalog (Deezer or Spotify).
  4. Search tracks or albums, then download. Watch the queue for progress.
  5. Local: the browser saves the finished file. Navidrome: the server copies the file under the selected music root (Artist/Album layout).

How it works

  1. Search — Deezer or Spotify returns track/album metadata and IDs.
  2. Match — YouTube candidates are chosen (with optional confirmation if confidence is low).
  3. Download — yt-dlp fetches audio; FFmpeg converts if needed.
  4. Tag — Metadata service writes tags and artwork.
  5. Deliver — Either serve to the browser or copy into the chosen Navidrome root; optional Navidrome API notification for scanning.

API (selected)

Method Path Notes
GET /api/health Status, navidrome_path, navidrome_libraries, etc.
GET /api/metadata/providers Deezer / Spotify and whether Spotify is configured
GET /api/navidrome/libraries { "libraries": [ { "path", "label" }, ... ] } — roots from env
GET /api/formats Audio format and quality defaults
POST /api/search Body: query, provider, limit
POST /api/search/albums Album search
POST /api/download Body includes track_id, location (local | navidrome), optional navidrome_library (absolute path; must match server config), provider, format/quality
POST /api/download/album Album download; same location / navidrome_library pattern
POST /api/reverse/download YouTube → metadata flow
GET /api/track/{id}/exists Duplicate check; supports location and optional navidrome_library
GET /api/download/status/{track_id} Job status

Full behavior is defined in backend/app.py.

Project structure

musikat/
├── backend/
│   ├── app.py
│   ├── config.py
│   ├── requirements.txt
│   ├── env.example
│   ├── static/              # app.js, styles.css
│   ├── templates/           # index.html
│   ├── services/            # deezer, spotify, youtube, metadata, navidrome
│   ├── utils/               # file_handler, job_store, navidrome_library_sync
│   └── tests/
├── images/
├── Dockerfile
├── docker-compose.yml
├── DOCKER.md
├── DEPLOYMENT.md
├── SETUP.md
└── README.md

Troubleshooting

No search results

  • Try the other catalog or a more specific query (artist + title).

YouTube errors (“Sign in to confirm you’re not a bot”, 403, etc.)

  • Install FFmpeg and ensure it is on PATH.
  • Export cookies (Netscape format) and set YOUTUBE_COOKIES_PATH (see yt-dlp FAQ). Cookies expire; re-export if downloads start failing.

Navidrome: file not appearing or upload fails

  • Paths must be writable by the process running Musikat.
  • For multiple roots, each path in NAVIDROME_MUSIC_PATHS must match what you select in the UI (server validates against the allowlist).
  • Check GET /api/navidrome/libraries matches your Docker mounts and permissions.

CORS

  • Add your site origin to CORS_ORIGINS in .env (required if the browser loads the UI from a different origin than the API, e.g. another port or domain).

Reverse proxy (HTTPS, subpath)

If Musikat is served under a path such as https://example.com/musikat/, nginx must forward requests to the app and ideally send X-Forwarded-Prefix: /musikat so links and env match. The frontend also infers /musikat from the browser URL when that header is missing, so API calls target /musikat/api/... instead of /api/... (which would 404).

Legal

Use for personal use only. Respect copyright and the terms of Deezer, Spotify, YouTube, and your jurisdiction.

License

MIT — see LICENSE.

Contributing

Pull requests are welcome.

More docs

Media gallery

1 / 2

Install Musikat on Unraid in a few clicks.

Find Musikat in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.

Open the Apps tab on your Unraid server Search Community Apps for Musikat Review the template variables and paths Click Install

Requirements


        Requires a `config.json` file to be mounted at `/app/config.json` before starting the container. See configuration details: https://github.com/soggy8/music-downloader/blob/main/config.json
        

        Requires a number of JSON files to be created on the host system BEFORE the container is started. These files can be created with the `touch` command.
    

Details

Repository
ghcr.io/soggy8/musikat:latest
Last Updated2026-07-17
First Seen2026-03-29

Runtime arguments

Web UI
http://[IP]:[PORT:8000]/
Network
bridge
Privileged
false

Template configuration

Web UI PortPorttcp

Container Port: 8000

Target
8000
Default
8000
Value
8000
Navidrome Music PathPath

Path to your Navidrome music folder

Target
/music
Temp Downloads PathPath

Path to temporary downloads folder

Target
/app/downloads
Default
/mnt/user/appdata/music_downloader/downloads
Value
/mnt/user/appdata/music-downloader/downloads
YouTube Cookies PathPathro

Path to your YouTube cookies file

Target
/app/youtube_cookies.txt
Default
/mnt/user/appdata/music_downloader/youtube_cookies.txt
Value
/mnt/user/appdata/music-downloader/youtube_cookies.txt
Navidrome - URLVariable

URL to your Navidrome server

Target
NAVIDROME_API_URL
Default
http://IP_ADDRESS:4533
Value
http://IP_ADDRESS:4533
Navidrome - Admin UsernameVariable

Your Navidrome admin username

Target
NAVIDROME_USERNAME
Navidrome - Admin PasswordVariable

Your Navidrome admin password

Target
NAVIDROME_PASSWORD
Navidrome - Enable SyncVariable

Periodically scan Navidrome path and mark matching catalog tracks as downloaded

Target
NAVIDROME_SYNC_ENABLED
Default
false|true
Spotify - Client IDVariable

Your Spotify Client ID

Target
SPOTIFY_CLIENT_ID
Spotify - Client SecretVariable

Your Spotify Client Secret

Target
SPOTIFY_CLIENT_SECRET
Spotify - Redirect URIVariable

Your Spotify Redirect URI

Target
SPOTIFY_REDIRECT_URI
Default
http://localhost:8000/callback
Value
http://localhost:8000/callback
Music FormatVariable

Desired music format for downloads

Target
OUTPUT_FORMAT
Default
mp3
Value
mp3
Music QualityVariable

Desired audio quality in kbps

Target
AUDIO_QUALITY
Default
128
Value
128
Navidrome - Sync Interval (Hours)Variable

Interval in hours for syncing with Navidrome

Target
NAVIDROME_SYNC_INTERVAL_HOURS
Default
4
Value
4
Navidrome - Sync Initial Delay (Seconds)Variable

Initial delay in seconds before first sync with Navidrome

Target
NAVIDROME_SYNC_INITIAL_DELAY_SEC
Default
120
Value
120
Navidrome - Sync API Delay (Seconds)Variable

Delay in seconds between API calls during Navidrome sync

Target
NAVIDROME_SYNC_API_DELAY_SEC
Default
0.12
Value
0.12
Internal HostVariable

Internal host for the web server. Not recommended to change.

Target
API_HOST
Default
0.0.0.0
Value
0.0.0.0
Internal PortVariable

Internal port for the web server. Not recommended to change.

Target
API_PORT
Default
8000
Value
8000
Internal Music PathVariable

Internal path to your Navidrome music folder. Not recommended to change.

Target
NAVIDROME_MUSIC_PATH
Default
/music
Value
/music
Internal YouTube Cookies PathVariable

Internal path to your YouTube cookies file. Not recommended to change.

Target
YOUTUBE_COOKIES_PATH
Default
/app/youtube_cookies.txt
Value
/app/youtube_cookies.txt
CORS OriginsVariable

Comma-separated list of allowed CORS origins

Target
CORS_ORIGINS
Default
http://localhost:3000,http://127.0.0.1:3000
Value
http://localhost:3000,http://127.0.0.1:3000