Skip to main content

Scan and query a SQLite-backed music metadata database.

Project description

kukicha

Tests

kukicha focuses on managing and streaming your audio library using a http server backed by single sqlite database file. It comes with a simple and fast builtin web UI.

Some noteworthy features:

  • It supports both POSIX and Windows.
  • Text/token based search & filters.
  • Artist tag cloud page
  • Albums grid page
  • Easily sync library root paths
  • Supports most audio formats
  • Never transcodes audio streams
  • Playlist are ordinary m3u, m3u8, pls files
  • Genre/style taxonomy provides clean data
  • Artist split patterns overrides (avoid artist names like Brian Eno with Jon Hopkins & Leo Abrahams)
  • iTunes cover art lookup
  • Musicbrainz release group & release IDs overrides
  • Overwrite album-level audio tags for album artist, genre
  • Overwrite track-level audio tags for artist, album title

Roadmap

  • Mount remote library roots (S3, etc.)
  • Support subset of Opensonic API to support different clients
  • Live stream a playlist

Install With uv

Kukicha is not published to PyPI yet. Install it from a checked-out project root with uv:

# from the project root
uv tool install .

Verify the install:

which kukicha
uv tool list
kukicha --help

Updates can be installed using force flag:

uv tool install --force .

For contributor setup with an editable install and test commands, see DEVELOPMENT.md.

Configure The Player

By default the player reads its config from $XDG_CONFIG_HOME/kukicha/kukicha.toml or ~/.config/kukicha/kukicha.toml. If that file is missing, startup fails. Run kukicha init once to create the config file and password hash file.

Interactive setup prompts for a username and password, stores an Argon2id password hash at password.hash beside the config file, and writes a required [auth] section:

kukicha init

Automation can provide credentials through environment variables and pipe extra TOML config on stdin. The stdin TOML must not include [auth]; kukicha init generates that section.

KUKICHA_USERNAME=listener KUKICHA_PASSWORD="$PASSWORD" kukicha init <<'TOML'
log_level = "INFO"
roots = ["/Users/YOUR_USERNAME/Music"]
appearance = "dim"
accent_color = "dark-orange"
TOML

Example config after initialization:

log_level = "INFO"
roots = ["/Users/YOUR_USERNAME/Music"]
youtube_download_root = "/Users/YOUR_USERNAME/Music"
prefer_musicbrainz_english_aliases = true
radio_limit = 25

[auth]
username = "listener"
password_hash_file = "~/.config/kukicha/password.hash"
cookie_max_age = "180d"
cookie_name = "kukicha_cookie"

Supported keys:

  • log_level: Python logging level name, such as DEBUG, INFO, or WARNING.
  • database_path: SQLite database path. Relative paths are resolved from the config file directory.
  • roots: music library folders to scan. Relative paths are resolved from the config file directory. Roots can also be managed from the Roots page.
  • ffmpeg_path: optional path to an executable ffmpeg; leave empty to unset.
  • youtube_download_root: configured local root path or remote root name where YouTube audio downloads are written under .kukicha/yt.
  • prefer_musicbrainz_english_aliases: when writing MusicBrainz album tags, prefer the first English artist alias from the MusicBrainz payload. Defaults to true.
  • host: interface to bind, defaulting to 127.0.0.1.
  • port: TCP port from 1 to 65535, defaulting to 4533.
  • trusted_proxy_headers: trust X-Forwarded-For, X-Forwarded-Proto, and X-Forwarded-Host from one reverse proxy hop. Defaults to false; only enable when direct access to Kukicha is blocked, such as when bound to 127.0.0.1 behind a local reverse proxy.
  • accent_color: palette name or matching hex code. Run kukicha --help for the full palette list.
  • appearance: light, dark, dim, or system. system follows the browser's prefers-color-scheme, using light for light mode and dim for dark mode. Defaults to system.
  • toast_timeout_ms: positive toast timeout in milliseconds.
  • radio_limit: positive track limit for all radio playlist generation. Defaults to 25.
  • album_artist_split_patterns: strings used when splitting album artist names.
  • [auth].username: browser login username.
  • [auth].password_hash_file: Argon2id password hash path. Relative paths are resolved from the config file directory; the file must be owned by the current user with 0600 permissions on POSIX systems.
  • [auth].cookie_max_age: persistent login cookie age as days, such as 30d or 180d. Defaults to 180d.
  • [auth].cookie_name: browser login cookie name. Defaults to kukicha_cookie.
  • [opensubsonic].mount_prefix: optional OpenSubsonic mount prefix. Use / for /rest/ping, or /sonic for /sonic/rest/ping.
  • [opensubsonic].secret_file: plain shared OpenSubsonic password file. Relative paths are resolved from the config file directory; the file must be owned by the current user with 0600 permissions on POSIX systems.

Run kukicha --help to print the active config path, current values, supported keys, accent colors, and appearance names.

Run The Player

Launch the local browser player:

kukicha

Or point it at an explicit config file:

kukicha -c /path/to/config/kukicha.toml

The default player URL is:

http://127.0.0.1:4533

The player runs as a foreground HTTP service so launchd, systemd, and similar service managers can supervise it directly. Logs go to normal stdout/stderr (with timestamps).

The browser UI requires login. Successful login stores an HTTP-only SameSite=Strict cookie for the configured age.

To change the browser login password later, run:

kukicha --config /path/to/kukicha.toml auth password

This creates or rewrites only the configured password hash file and invalidates existing browser login cookies for that config. If you wrote [auth] into the config before creating password_hash_file, use this command to bootstrap that file.

The player provides album browsing, playback, full-text search, and filters for library roots, artists, genres, styles, and album properties. Search indexes album titles, album artists, and track titles. Quoted terms match exact token phrases, spaces mean AND, semicolons mean OR, and a leading - excludes a term.

Mount The OpenSubsonic API

OpenSubsonic endpoints are served by the same Kukicha HTTP server as the browser player. By default they are not mounted and /rest/... returns 404.

Initialize the optional [opensubsonic] config:

kukicha opensubsonic init

For scripts, provide the password and mount prefix through the environment:

OPENSUBSONIC_PASSWORD="$PASSWORD" OPENSUBSONIC_MOUNT="/" kukicha opensubsonic init

This appends a section like:

[opensubsonic]
mount_prefix = "/"
secret_file = "~/.config/kukicha/opensubsonic.secret"

With mount_prefix = "/", the ping endpoint is /rest/ping. With mount_prefix = "/sonic", it is /sonic/rest/ping.

To change the OpenSubsonic password later, run:

kukicha --config /path/to/kukicha.toml opensubsonic password

This creates or rewrites the configured secret_file, so it also supports declarative configs where [opensubsonic] exists before the secret file does.

The API supports basic album and artist browsing, direct streaming, downloads, cover art, password auth, salted token auth, JSON responses, and GET or form POST parameters.

Bulk Tag Edit

Rewrite album-level tags for every supported music file under a folder:

kukicha tools bulk-tag-edit \
  --folder "/Users/YOUR_USERNAME/Library/Mobile Documents/com~apple~CloudDocs/music/downloaded2/Richard David James" \
  --album-artist "Richard David James" \
  --album "Soundcloud" \
  --genre "Electronic"

The command recurses with the same supported audio extensions used by the scanner and only writes album artist, album title, and genre tags. It has been convenient for a bulk tag edit (album level) in some circumstances

YouTube Audio

Download audio-only YouTube media. Video URLs are downloaded as one audio file inside a video-named folder under the configured YouTube download root:

kukicha tools yt-download-audio "https://www.youtube.com/watch?v=VIDEO_ID"

To split a video into one audio file per chapter, pass --split-into-chapters:

kukicha tools yt-download-audio \
  --split-into-chapters \
  "https://www.youtube.com/watch?v=VIDEO_ID"

If yt-dlp does not report chapters, or you want to override them, provide a manual chapter file. --chapters-file implies --split-into-chapters:

kukicha -c ~/kukicha.toml tools yt-download-audio \
  --chapters-file chapters.txt \
  "https://www.youtube.com/watch?v=VIDEO_ID"

The chapter file uses one chapter per nonblank line. Lines starting with # are ignored:

0:00 Intro
03:12 - Track Two
1:02:03.5 Finale

Chapter-split video URLs are written to a folder named for the video. Playlist URLs are downloaded as one audio file per playlist item. Chapters reported inside individual playlist items are ignored, and --chapters-file and --split-into-chapters cannot be used with playlist URLs.

Set youtube_download_root in kukicha.toml before running this command. Local roots write under <root>/.kukicha/yt; remote roots upload under <prefix>.kukicha/yt. The tool checks that ffmpeg, ffprobe, and Deno 2.0.0 or newer are available. yt-dlp temporary and staged files are kept in the user's OS temp folder and are cleaned up when the command exits.

Run With launchd

Save this as ~/Library/LaunchAgents/com.kukicha.player.plist and adjust paths as needed:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.kukicha.player</string>

  <key>ProgramArguments</key>
  <array>
    <string>/Users/YOUR_USERNAME/.local/bin/kukicha</string>
    <string>-c</string>
    <string>/Users/YOUR_USERNAME/.config/kukicha/kukicha.toml</string>
  </array>

  <key>RunAtLoad</key>
  <true/>

  <key>KeepAlive</key>
  <dict>
    <key>SuccessfulExit</key>
    <false/>
  </dict>

  <key>StandardOutPath</key>
  <string>/Users/YOUR_USERNAME/Library/Logs/kukicha-player.log</string>

  <key>StandardErrorPath</key>
  <string>/Users/YOUR_USERNAME/Library/Logs/kukicha-player.err.log</string>
</dict>
</plist>

Load and start it:

launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.kukicha.player.plist

Show the status

launchctl print gui/$(id -u)/com.kukicha.player

Restart the running server:

launchctl kickstart -k gui/$(id -u)/com.kukicha.player

Shut it down and unload it:

launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.kukicha.player.plist

After changing the plist, unload it with bootout, then load it again with bootstrap. The bootout and kickstart -k commands trigger normal process shutdown, and Kukicha logs shutdown with the same timestamped stdout/stderr logging as startup.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kukicha-0.1.0a3.tar.gz (472.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kukicha-0.1.0a3-py3-none-any.whl (370.6 kB view details)

Uploaded Python 3

File details

Details for the file kukicha-0.1.0a3.tar.gz.

File metadata

  • Download URL: kukicha-0.1.0a3.tar.gz
  • Upload date:
  • Size: 472.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for kukicha-0.1.0a3.tar.gz
Algorithm Hash digest
SHA256 e173d769fec1fca6c91b74af746159508bb11c38719cd0af8254c938a038de40
MD5 a9956cf86cd779e2b6378cf78806065f
BLAKE2b-256 e23c65455ec591fd3b0da4161ef82498b5cca8e0a74336005d4d57db0f7479e0

See more details on using hashes here.

File details

Details for the file kukicha-0.1.0a3-py3-none-any.whl.

File metadata

  • Download URL: kukicha-0.1.0a3-py3-none-any.whl
  • Upload date:
  • Size: 370.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for kukicha-0.1.0a3-py3-none-any.whl
Algorithm Hash digest
SHA256 d5769286e9154cca63aa72ad532d7cbde183f40c99eb634be02c1aaf74f8cf60
MD5 bbcc1d10b44bb259fe4a2dfb433ebfdc
BLAKE2b-256 59312c18350654654e5c0d9b75c68271a8a6f31d6207a9c5bbbb18aee1fe77a5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page