kukicha 0.1.0a1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kukicha-0.1.0a1/LICENSE +21 -0
- kukicha-0.1.0a1/PKG-INFO +286 -0
- kukicha-0.1.0a1/README.md +272 -0
- kukicha-0.1.0a1/pyproject.toml +29 -0
- kukicha-0.1.0a1/setup.cfg +4 -0
- kukicha-0.1.0a1/src/kukicha/__init__.py +1 -0
- kukicha-0.1.0a1/src/kukicha/__main__.py +5 -0
- kukicha-0.1.0a1/src/kukicha/album_artists.py +113 -0
- kukicha-0.1.0a1/src/kukicha/app_metadata.py +7 -0
- kukicha-0.1.0a1/src/kukicha/cli.py +115 -0
- kukicha-0.1.0a1/src/kukicha/commands/__init__.py +2 -0
- kukicha-0.1.0a1/src/kukicha/commands/opensubsonic.py +25 -0
- kukicha-0.1.0a1/src/kukicha/commands/player.py +25 -0
- kukicha-0.1.0a1/src/kukicha/commands/tools.py +98 -0
- kukicha-0.1.0a1/src/kukicha/commands/youtube_audio.py +821 -0
- kukicha-0.1.0a1/src/kukicha/data/taxonomy.tsv +1914 -0
- kukicha-0.1.0a1/src/kukicha/discogs.py +155 -0
- kukicha-0.1.0a1/src/kukicha/display.py +11 -0
- kukicha-0.1.0a1/src/kukicha/file_metadata.py +23 -0
- kukicha-0.1.0a1/src/kukicha/models.py +105 -0
- kukicha-0.1.0a1/src/kukicha/opensubsonic_web_adapter.py +1125 -0
- kukicha-0.1.0a1/src/kukicha/player_common.py +88 -0
- kukicha-0.1.0a1/src/kukicha/player_config.py +873 -0
- kukicha-0.1.0a1/src/kukicha/player_errors.py +10 -0
- kukicha-0.1.0a1/src/kukicha/player_jobs.py +238 -0
- kukicha-0.1.0a1/src/kukicha/player_media.py +72 -0
- kukicha-0.1.0a1/src/kukicha/player_navigation.py +453 -0
- kukicha-0.1.0a1/src/kukicha/player_platform.py +25 -0
- kukicha-0.1.0a1/src/kukicha/player_playlists.py +275 -0
- kukicha-0.1.0a1/src/kukicha/player_presenters.py +1018 -0
- kukicha-0.1.0a1/src/kukicha/player_runtime.py +335 -0
- kukicha-0.1.0a1/src/kukicha/player_views.py +647 -0
- kukicha-0.1.0a1/src/kukicha/player_web_adapter.py +740 -0
- kukicha-0.1.0a1/src/kukicha/playlist_art.py +69 -0
- kukicha-0.1.0a1/src/kukicha/scanner.py +1114 -0
- kukicha-0.1.0a1/src/kukicha/search.py +82 -0
- kukicha-0.1.0a1/src/kukicha/static/favicon.svg +23 -0
- kukicha-0.1.0a1/src/kukicha/static/player.css +2867 -0
- kukicha-0.1.0a1/src/kukicha/static/player.js +4241 -0
- kukicha-0.1.0a1/src/kukicha/taxonomy_data.py +88 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/_icons.html +111 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/_page_title.html +33 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/_track_table.html +176 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/album.html +108 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/album_edit.html +200 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/artist_split_rules.html +25 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/artists.html +23 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/base.html +200 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/cache.html +19 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/help.html +72 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/home.html +253 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/index.html +167 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/jobs.html +53 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/musicbrainz_overrides.html +80 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/not_found.html +14 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/playlist.html +53 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/queue.html +20 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/roots.html +43 -0
- kukicha-0.1.0a1/src/kukicha/templates/player/simple_page.html +5 -0
- kukicha-0.1.0a1/src/kukicha/text.py +33 -0
- kukicha-0.1.0a1/src/kukicha/use_case/__init__.py +215 -0
- kukicha-0.1.0a1/src/kukicha/use_case/commands/__init__.py +99 -0
- kukicha-0.1.0a1/src/kukicha/use_case/commands/album_edits.py +1341 -0
- kukicha-0.1.0a1/src/kukicha/use_case/commands/jobs.py +361 -0
- kukicha-0.1.0a1/src/kukicha/use_case/commands/player.py +879 -0
- kukicha-0.1.0a1/src/kukicha/use_case/commands/playlists.py +229 -0
- kukicha-0.1.0a1/src/kukicha/use_case/commands/roots.py +586 -0
- kukicha-0.1.0a1/src/kukicha/use_case/commands/startup.py +10 -0
- kukicha-0.1.0a1/src/kukicha/use_case/coverartarchive.py +317 -0
- kukicha-0.1.0a1/src/kukicha/use_case/database.py +1697 -0
- kukicha-0.1.0a1/src/kukicha/use_case/itunes.py +382 -0
- kukicha-0.1.0a1/src/kukicha/use_case/library.py +1876 -0
- kukicha-0.1.0a1/src/kukicha/use_case/listening.py +1229 -0
- kukicha-0.1.0a1/src/kukicha/use_case/musicbrainz.py +727 -0
- kukicha-0.1.0a1/src/kukicha/use_case/queries/__init__.py +81 -0
- kukicha-0.1.0a1/src/kukicha/use_case/queries/artists.py +44 -0
- kukicha-0.1.0a1/src/kukicha/use_case/queries/filters.py +488 -0
- kukicha-0.1.0a1/src/kukicha/use_case/queries/library.py +1596 -0
- kukicha-0.1.0a1/src/kukicha/use_case/queries/models.py +358 -0
- kukicha-0.1.0a1/src/kukicha/use_case/queries/musicbrainz.py +11 -0
- kukicha-0.1.0a1/src/kukicha/use_case/queries/params.py +105 -0
- kukicha-0.1.0a1/src/kukicha/use_case/queries/sorting.py +135 -0
- kukicha-0.1.0a1/src/kukicha/use_case/queries/sql.py +41 -0
- kukicha-0.1.0a1/src/kukicha.egg-info/PKG-INFO +286 -0
- kukicha-0.1.0a1/src/kukicha.egg-info/SOURCES.txt +96 -0
- kukicha-0.1.0a1/src/kukicha.egg-info/dependency_links.txt +1 -0
- kukicha-0.1.0a1/src/kukicha.egg-info/entry_points.txt +2 -0
- kukicha-0.1.0a1/src/kukicha.egg-info/requires.txt +5 -0
- kukicha-0.1.0a1/src/kukicha.egg-info/top_level.txt +1 -0
- kukicha-0.1.0a1/tests/test_album_artists.py +52 -0
- kukicha-0.1.0a1/tests/test_library.py +4052 -0
- kukicha-0.1.0a1/tests/test_musicbrainz.py +69 -0
- kukicha-0.1.0a1/tests/test_opensubsonic.py +660 -0
- kukicha-0.1.0a1/tests/test_player.py +8596 -0
- kukicha-0.1.0a1/tests/test_playlist_art.py +23 -0
- kukicha-0.1.0a1/tests/test_scanner.py +652 -0
- kukicha-0.1.0a1/tests/test_search.py +718 -0
- kukicha-0.1.0a1/tests/test_tools.py +896 -0
kukicha-0.1.0a1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 zanyoats
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
kukicha-0.1.0a1/PKG-INFO
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kukicha
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: Scan and query a SQLite-backed music metadata database.
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: Flask>=3.1.0
|
|
9
|
+
Requires-Dist: Jinja2>=3.1.0
|
|
10
|
+
Requires-Dist: mutagen>=1.47.0
|
|
11
|
+
Requires-Dist: Pillow>=10.0.0
|
|
12
|
+
Requires-Dist: yt-dlp[default]==2026.3.17
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# kukicha
|
|
16
|
+
|
|
17
|
+
`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.
|
|
18
|
+
|
|
19
|
+
Some noteworthy features:
|
|
20
|
+
- It supports both POSIX and Windows.
|
|
21
|
+
- Text/token based search & filters.
|
|
22
|
+
- Artist tag cloud page
|
|
23
|
+
- Albums grid page
|
|
24
|
+
- Easily sync library root paths
|
|
25
|
+
- Supports most audio formats
|
|
26
|
+
- Never transcodes audio streams
|
|
27
|
+
- Playlist are ordinary m3u, m3u8, pls files
|
|
28
|
+
- Genre/style taxonomy provides clean data
|
|
29
|
+
- Artist split patterns overrides (avoid artist names like `Brian Eno with Jon Hopkins & Leo Abrahams`)
|
|
30
|
+
- iTunes cover art lookup
|
|
31
|
+
- Musicbrainz release group & release IDs overrides
|
|
32
|
+
- Overwrite album-level audio tags for album artist, genre
|
|
33
|
+
- Overwrite track-level audio tags for artist, album title
|
|
34
|
+
|
|
35
|
+
Roadmap
|
|
36
|
+
- Mount remote library roots (S3, etc.)
|
|
37
|
+
- Support subset of Opensonic API to support different clients
|
|
38
|
+
- Live stream a playlist
|
|
39
|
+
|
|
40
|
+
## Install With pipx
|
|
41
|
+
|
|
42
|
+
Kukicha is not published to PyPI yet. Install it from a checked-out project root with `pipx`:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# from the project root
|
|
46
|
+
pipx ensurepath
|
|
47
|
+
pipx install .
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Verify the install:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
which kukicha
|
|
54
|
+
pipx list
|
|
55
|
+
kukicha --help
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Updates can be installed using force flag:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# when we move to versions use `pipx upgrade kukicha`
|
|
62
|
+
pipx install --force .
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
For contributor setup with an editable install and test commands, see
|
|
66
|
+
[DEVELOPMENT.md](DEVELOPMENT.md).
|
|
67
|
+
|
|
68
|
+
## Configure The Player
|
|
69
|
+
|
|
70
|
+
By default the player reads its config from
|
|
71
|
+
`$XDG_CONFIG_HOME/kukicha/kukicha.toml` or `~/.config/kukicha/kukicha.toml`.
|
|
72
|
+
If that file is missing, Kukicha uses built-in defaults and stores the default
|
|
73
|
+
database at `kukicha.sqlite` in the same config directory.
|
|
74
|
+
|
|
75
|
+
Create the config directory and file:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
mkdir -p ~/.config/kukicha
|
|
79
|
+
$EDITOR ~/.config/kukicha/kukicha.toml
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Example config:
|
|
83
|
+
|
|
84
|
+
```toml
|
|
85
|
+
LogLevel = "INFO"
|
|
86
|
+
Roots = ["/Users/YOUR_USERNAME/Music"]
|
|
87
|
+
YoutubeDownloadPath = "/Users/YOUR_USERNAME/Music/YouTube"
|
|
88
|
+
PreferMusicBrainzEnglishAliases = true
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Supported keys:
|
|
92
|
+
|
|
93
|
+
- `LogLevel`: Python logging level name, such as `DEBUG`, `INFO`, or `WARNING`.
|
|
94
|
+
- `DatabasePath`: SQLite database path. Relative paths are resolved from the
|
|
95
|
+
config file directory.
|
|
96
|
+
- `Roots`: music library folders to scan. Relative paths are resolved from the
|
|
97
|
+
config file directory. Roots can also be managed from the Roots page.
|
|
98
|
+
- `FFmpegPath`: optional path to an executable `ffmpeg`; leave empty to unset.
|
|
99
|
+
- `YoutubeDownloadPath`: folder where YouTube chapter audio downloads are
|
|
100
|
+
written. Relative paths are resolved from the config file directory.
|
|
101
|
+
- `PreferMusicBrainzEnglishAliases`: when writing MusicBrainz album tags, prefer
|
|
102
|
+
the first English artist alias from the MusicBrainz payload. Defaults to
|
|
103
|
+
`true`.
|
|
104
|
+
- `Host`: interface to bind, defaulting to `127.0.0.1`.
|
|
105
|
+
- `Port`: TCP port from `1` to `65535`, defaulting to `65042`.
|
|
106
|
+
- `OpenSubsonicUsername`: username for the OpenSubsonic API, defaulting to
|
|
107
|
+
`guest`.
|
|
108
|
+
- `OpenSubsonicPassword`: password for the OpenSubsonic API, defaulting to
|
|
109
|
+
`guest`.
|
|
110
|
+
- `OpenSubsonicHost`: interface for the OpenSubsonic API, defaulting to
|
|
111
|
+
`127.0.0.1`.
|
|
112
|
+
- `OpenSubsonicPort`: TCP port for the OpenSubsonic API, defaulting to `4533`.
|
|
113
|
+
- `AccentColor`: palette name or matching hex code. Run `kukicha --help` for the
|
|
114
|
+
full palette list.
|
|
115
|
+
- `Appearance`: `light`, `dark`, `dim`, or `system`. `system` follows the
|
|
116
|
+
browser's `prefers-color-scheme`, using `light` for light mode and `dim` for
|
|
117
|
+
dark mode. Defaults to `system`.
|
|
118
|
+
- `ToastTimeoutMs`: positive toast timeout in milliseconds.
|
|
119
|
+
- `AlbumArtistSplitPatterns`: strings used when splitting album artist names.
|
|
120
|
+
|
|
121
|
+
Run `kukicha --help` to print the active config path, current values, supported
|
|
122
|
+
keys, accent colors, and appearance names.
|
|
123
|
+
|
|
124
|
+
## Run The Player
|
|
125
|
+
|
|
126
|
+
Launch the local browser player:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
kukicha
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Or point it at an explicit config file:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
kukicha -c /path/to/config/kukicha.toml
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The default player URL is:
|
|
139
|
+
|
|
140
|
+
```text
|
|
141
|
+
http://127.0.0.1:65042
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The player runs as a foreground HTTP service so launchd, systemd, and similar
|
|
145
|
+
service managers can supervise it directly. Logs go to normal stdout/stderr (with
|
|
146
|
+
timestamps).
|
|
147
|
+
|
|
148
|
+
The player provides album browsing, playback, full-text search, and filters for
|
|
149
|
+
library roots, artists, genres, styles, and album properties. Search indexes
|
|
150
|
+
album titles, album artists, and track titles. Quoted terms match exact token
|
|
151
|
+
phrases, spaces mean AND, semicolons mean OR, and a leading `-` excludes a term.
|
|
152
|
+
|
|
153
|
+
## Run The OpenSubsonic API
|
|
154
|
+
|
|
155
|
+
Launch the minimal OpenSubsonic-compatible API:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
kukicha opensubsonic
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The default OpenSubsonic URL is:
|
|
162
|
+
|
|
163
|
+
```text
|
|
164
|
+
http://127.0.0.1:4533
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The API supports basic album and artist browsing, direct streaming, downloads,
|
|
168
|
+
cover art, password auth, salted token auth, JSON responses, and GET or form
|
|
169
|
+
POST parameters.
|
|
170
|
+
|
|
171
|
+
## Bulk Tag Edit
|
|
172
|
+
|
|
173
|
+
Rewrite album-level tags for every supported music file under a folder:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
kukicha tools bulk-tag-edit \
|
|
177
|
+
--folder "/Users/YOUR_USERNAME/Library/Mobile Documents/com~apple~CloudDocs/music/downloaded2/Richard David James" \
|
|
178
|
+
--album-artist "Richard David James" \
|
|
179
|
+
--album "Soundcloud" \
|
|
180
|
+
--genre "Electronic"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The command recurses with the same supported audio extensions used by the scanner
|
|
184
|
+
and only writes album artist, album title, and genre tags. It has been convenient for a bulk tag edit (album level) in some circumstances
|
|
185
|
+
|
|
186
|
+
## YouTube Audio
|
|
187
|
+
|
|
188
|
+
Download audio-only YouTube media. Video URLs are split into chapter files:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
kukicha tools yt-download-audio "https://www.youtube.com/watch?v=VIDEO_ID"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
If yt-dlp does not report chapters, or you want to override them, provide a
|
|
195
|
+
manual chapter file:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
kukicha -c ~/kukicha.toml tools yt-download-audio \
|
|
199
|
+
--chapters-file chapters.txt \
|
|
200
|
+
"https://www.youtube.com/watch?v=VIDEO_ID"
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The chapter file uses one chapter per nonblank line. Lines starting with `#`
|
|
204
|
+
are ignored:
|
|
205
|
+
|
|
206
|
+
```text
|
|
207
|
+
0:00 Intro
|
|
208
|
+
03:12 - Track Two
|
|
209
|
+
1:02:03.5 Finale
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Playlist URLs are downloaded as one audio file per playlist item. Chapters
|
|
213
|
+
reported inside individual playlist items are ignored, and `--chapters-file`
|
|
214
|
+
cannot be used with playlist URLs.
|
|
215
|
+
|
|
216
|
+
Set `YoutubeDownloadPath` in `kukicha.toml` before running this command. The
|
|
217
|
+
tool checks that `ffmpeg`, `ffprobe`, and Deno 2.0.0 or newer are available.
|
|
218
|
+
yt-dlp temporary and staged files are kept in the user's OS temp folder and are
|
|
219
|
+
cleaned up when the command exits.
|
|
220
|
+
|
|
221
|
+
## Run With launchd
|
|
222
|
+
|
|
223
|
+
Save this as `~/Library/LaunchAgents/com.kukicha.player.plist` and adjust paths
|
|
224
|
+
as needed:
|
|
225
|
+
|
|
226
|
+
```xml
|
|
227
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
228
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
229
|
+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
230
|
+
<plist version="1.0">
|
|
231
|
+
<dict>
|
|
232
|
+
<key>Label</key>
|
|
233
|
+
<string>com.kukicha.player</string>
|
|
234
|
+
|
|
235
|
+
<key>ProgramArguments</key>
|
|
236
|
+
<array>
|
|
237
|
+
<string>/Users/YOUR_USERNAME/.local/bin/kukicha</string>
|
|
238
|
+
<string>-c</string>
|
|
239
|
+
<string>/Users/YOUR_USERNAME/.config/kukicha/kukicha.toml</string>
|
|
240
|
+
</array>
|
|
241
|
+
|
|
242
|
+
<key>RunAtLoad</key>
|
|
243
|
+
<true/>
|
|
244
|
+
|
|
245
|
+
<key>KeepAlive</key>
|
|
246
|
+
<dict>
|
|
247
|
+
<key>SuccessfulExit</key>
|
|
248
|
+
<false/>
|
|
249
|
+
</dict>
|
|
250
|
+
|
|
251
|
+
<key>StandardOutPath</key>
|
|
252
|
+
<string>/Users/YOUR_USERNAME/Library/Logs/kukicha-player.log</string>
|
|
253
|
+
|
|
254
|
+
<key>StandardErrorPath</key>
|
|
255
|
+
<string>/Users/YOUR_USERNAME/Library/Logs/kukicha-player.err.log</string>
|
|
256
|
+
</dict>
|
|
257
|
+
</plist>
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Load and start it:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.kukicha.player.plist
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Show the status
|
|
267
|
+
```bash
|
|
268
|
+
launchctl print gui/$(id -u)/com.kukicha.player
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Restart the running server:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
launchctl kickstart -k gui/$(id -u)/com.kukicha.player
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Shut it down and unload it:
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.kukicha.player.plist
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
After changing the plist, unload it with `bootout`, then load it again with
|
|
284
|
+
`bootstrap`. The `bootout` and `kickstart -k` commands trigger normal process
|
|
285
|
+
shutdown, and Kukicha logs shutdown with the same timestamped stdout/stderr
|
|
286
|
+
logging as startup.
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# kukicha
|
|
2
|
+
|
|
3
|
+
`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.
|
|
4
|
+
|
|
5
|
+
Some noteworthy features:
|
|
6
|
+
- It supports both POSIX and Windows.
|
|
7
|
+
- Text/token based search & filters.
|
|
8
|
+
- Artist tag cloud page
|
|
9
|
+
- Albums grid page
|
|
10
|
+
- Easily sync library root paths
|
|
11
|
+
- Supports most audio formats
|
|
12
|
+
- Never transcodes audio streams
|
|
13
|
+
- Playlist are ordinary m3u, m3u8, pls files
|
|
14
|
+
- Genre/style taxonomy provides clean data
|
|
15
|
+
- Artist split patterns overrides (avoid artist names like `Brian Eno with Jon Hopkins & Leo Abrahams`)
|
|
16
|
+
- iTunes cover art lookup
|
|
17
|
+
- Musicbrainz release group & release IDs overrides
|
|
18
|
+
- Overwrite album-level audio tags for album artist, genre
|
|
19
|
+
- Overwrite track-level audio tags for artist, album title
|
|
20
|
+
|
|
21
|
+
Roadmap
|
|
22
|
+
- Mount remote library roots (S3, etc.)
|
|
23
|
+
- Support subset of Opensonic API to support different clients
|
|
24
|
+
- Live stream a playlist
|
|
25
|
+
|
|
26
|
+
## Install With pipx
|
|
27
|
+
|
|
28
|
+
Kukicha is not published to PyPI yet. Install it from a checked-out project root with `pipx`:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# from the project root
|
|
32
|
+
pipx ensurepath
|
|
33
|
+
pipx install .
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Verify the install:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
which kukicha
|
|
40
|
+
pipx list
|
|
41
|
+
kukicha --help
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Updates can be installed using force flag:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# when we move to versions use `pipx upgrade kukicha`
|
|
48
|
+
pipx install --force .
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For contributor setup with an editable install and test commands, see
|
|
52
|
+
[DEVELOPMENT.md](DEVELOPMENT.md).
|
|
53
|
+
|
|
54
|
+
## Configure The Player
|
|
55
|
+
|
|
56
|
+
By default the player reads its config from
|
|
57
|
+
`$XDG_CONFIG_HOME/kukicha/kukicha.toml` or `~/.config/kukicha/kukicha.toml`.
|
|
58
|
+
If that file is missing, Kukicha uses built-in defaults and stores the default
|
|
59
|
+
database at `kukicha.sqlite` in the same config directory.
|
|
60
|
+
|
|
61
|
+
Create the config directory and file:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
mkdir -p ~/.config/kukicha
|
|
65
|
+
$EDITOR ~/.config/kukicha/kukicha.toml
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Example config:
|
|
69
|
+
|
|
70
|
+
```toml
|
|
71
|
+
LogLevel = "INFO"
|
|
72
|
+
Roots = ["/Users/YOUR_USERNAME/Music"]
|
|
73
|
+
YoutubeDownloadPath = "/Users/YOUR_USERNAME/Music/YouTube"
|
|
74
|
+
PreferMusicBrainzEnglishAliases = true
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Supported keys:
|
|
78
|
+
|
|
79
|
+
- `LogLevel`: Python logging level name, such as `DEBUG`, `INFO`, or `WARNING`.
|
|
80
|
+
- `DatabasePath`: SQLite database path. Relative paths are resolved from the
|
|
81
|
+
config file directory.
|
|
82
|
+
- `Roots`: music library folders to scan. Relative paths are resolved from the
|
|
83
|
+
config file directory. Roots can also be managed from the Roots page.
|
|
84
|
+
- `FFmpegPath`: optional path to an executable `ffmpeg`; leave empty to unset.
|
|
85
|
+
- `YoutubeDownloadPath`: folder where YouTube chapter audio downloads are
|
|
86
|
+
written. Relative paths are resolved from the config file directory.
|
|
87
|
+
- `PreferMusicBrainzEnglishAliases`: when writing MusicBrainz album tags, prefer
|
|
88
|
+
the first English artist alias from the MusicBrainz payload. Defaults to
|
|
89
|
+
`true`.
|
|
90
|
+
- `Host`: interface to bind, defaulting to `127.0.0.1`.
|
|
91
|
+
- `Port`: TCP port from `1` to `65535`, defaulting to `65042`.
|
|
92
|
+
- `OpenSubsonicUsername`: username for the OpenSubsonic API, defaulting to
|
|
93
|
+
`guest`.
|
|
94
|
+
- `OpenSubsonicPassword`: password for the OpenSubsonic API, defaulting to
|
|
95
|
+
`guest`.
|
|
96
|
+
- `OpenSubsonicHost`: interface for the OpenSubsonic API, defaulting to
|
|
97
|
+
`127.0.0.1`.
|
|
98
|
+
- `OpenSubsonicPort`: TCP port for the OpenSubsonic API, defaulting to `4533`.
|
|
99
|
+
- `AccentColor`: palette name or matching hex code. Run `kukicha --help` for the
|
|
100
|
+
full palette list.
|
|
101
|
+
- `Appearance`: `light`, `dark`, `dim`, or `system`. `system` follows the
|
|
102
|
+
browser's `prefers-color-scheme`, using `light` for light mode and `dim` for
|
|
103
|
+
dark mode. Defaults to `system`.
|
|
104
|
+
- `ToastTimeoutMs`: positive toast timeout in milliseconds.
|
|
105
|
+
- `AlbumArtistSplitPatterns`: strings used when splitting album artist names.
|
|
106
|
+
|
|
107
|
+
Run `kukicha --help` to print the active config path, current values, supported
|
|
108
|
+
keys, accent colors, and appearance names.
|
|
109
|
+
|
|
110
|
+
## Run The Player
|
|
111
|
+
|
|
112
|
+
Launch the local browser player:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
kukicha
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Or point it at an explicit config file:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
kukicha -c /path/to/config/kukicha.toml
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The default player URL is:
|
|
125
|
+
|
|
126
|
+
```text
|
|
127
|
+
http://127.0.0.1:65042
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The player runs as a foreground HTTP service so launchd, systemd, and similar
|
|
131
|
+
service managers can supervise it directly. Logs go to normal stdout/stderr (with
|
|
132
|
+
timestamps).
|
|
133
|
+
|
|
134
|
+
The player provides album browsing, playback, full-text search, and filters for
|
|
135
|
+
library roots, artists, genres, styles, and album properties. Search indexes
|
|
136
|
+
album titles, album artists, and track titles. Quoted terms match exact token
|
|
137
|
+
phrases, spaces mean AND, semicolons mean OR, and a leading `-` excludes a term.
|
|
138
|
+
|
|
139
|
+
## Run The OpenSubsonic API
|
|
140
|
+
|
|
141
|
+
Launch the minimal OpenSubsonic-compatible API:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
kukicha opensubsonic
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The default OpenSubsonic URL is:
|
|
148
|
+
|
|
149
|
+
```text
|
|
150
|
+
http://127.0.0.1:4533
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The API supports basic album and artist browsing, direct streaming, downloads,
|
|
154
|
+
cover art, password auth, salted token auth, JSON responses, and GET or form
|
|
155
|
+
POST parameters.
|
|
156
|
+
|
|
157
|
+
## Bulk Tag Edit
|
|
158
|
+
|
|
159
|
+
Rewrite album-level tags for every supported music file under a folder:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
kukicha tools bulk-tag-edit \
|
|
163
|
+
--folder "/Users/YOUR_USERNAME/Library/Mobile Documents/com~apple~CloudDocs/music/downloaded2/Richard David James" \
|
|
164
|
+
--album-artist "Richard David James" \
|
|
165
|
+
--album "Soundcloud" \
|
|
166
|
+
--genre "Electronic"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The command recurses with the same supported audio extensions used by the scanner
|
|
170
|
+
and only writes album artist, album title, and genre tags. It has been convenient for a bulk tag edit (album level) in some circumstances
|
|
171
|
+
|
|
172
|
+
## YouTube Audio
|
|
173
|
+
|
|
174
|
+
Download audio-only YouTube media. Video URLs are split into chapter files:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
kukicha tools yt-download-audio "https://www.youtube.com/watch?v=VIDEO_ID"
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
If yt-dlp does not report chapters, or you want to override them, provide a
|
|
181
|
+
manual chapter file:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
kukicha -c ~/kukicha.toml tools yt-download-audio \
|
|
185
|
+
--chapters-file chapters.txt \
|
|
186
|
+
"https://www.youtube.com/watch?v=VIDEO_ID"
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The chapter file uses one chapter per nonblank line. Lines starting with `#`
|
|
190
|
+
are ignored:
|
|
191
|
+
|
|
192
|
+
```text
|
|
193
|
+
0:00 Intro
|
|
194
|
+
03:12 - Track Two
|
|
195
|
+
1:02:03.5 Finale
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Playlist URLs are downloaded as one audio file per playlist item. Chapters
|
|
199
|
+
reported inside individual playlist items are ignored, and `--chapters-file`
|
|
200
|
+
cannot be used with playlist URLs.
|
|
201
|
+
|
|
202
|
+
Set `YoutubeDownloadPath` in `kukicha.toml` before running this command. The
|
|
203
|
+
tool checks that `ffmpeg`, `ffprobe`, and Deno 2.0.0 or newer are available.
|
|
204
|
+
yt-dlp temporary and staged files are kept in the user's OS temp folder and are
|
|
205
|
+
cleaned up when the command exits.
|
|
206
|
+
|
|
207
|
+
## Run With launchd
|
|
208
|
+
|
|
209
|
+
Save this as `~/Library/LaunchAgents/com.kukicha.player.plist` and adjust paths
|
|
210
|
+
as needed:
|
|
211
|
+
|
|
212
|
+
```xml
|
|
213
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
214
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
215
|
+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
216
|
+
<plist version="1.0">
|
|
217
|
+
<dict>
|
|
218
|
+
<key>Label</key>
|
|
219
|
+
<string>com.kukicha.player</string>
|
|
220
|
+
|
|
221
|
+
<key>ProgramArguments</key>
|
|
222
|
+
<array>
|
|
223
|
+
<string>/Users/YOUR_USERNAME/.local/bin/kukicha</string>
|
|
224
|
+
<string>-c</string>
|
|
225
|
+
<string>/Users/YOUR_USERNAME/.config/kukicha/kukicha.toml</string>
|
|
226
|
+
</array>
|
|
227
|
+
|
|
228
|
+
<key>RunAtLoad</key>
|
|
229
|
+
<true/>
|
|
230
|
+
|
|
231
|
+
<key>KeepAlive</key>
|
|
232
|
+
<dict>
|
|
233
|
+
<key>SuccessfulExit</key>
|
|
234
|
+
<false/>
|
|
235
|
+
</dict>
|
|
236
|
+
|
|
237
|
+
<key>StandardOutPath</key>
|
|
238
|
+
<string>/Users/YOUR_USERNAME/Library/Logs/kukicha-player.log</string>
|
|
239
|
+
|
|
240
|
+
<key>StandardErrorPath</key>
|
|
241
|
+
<string>/Users/YOUR_USERNAME/Library/Logs/kukicha-player.err.log</string>
|
|
242
|
+
</dict>
|
|
243
|
+
</plist>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Load and start it:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.kukicha.player.plist
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Show the status
|
|
253
|
+
```bash
|
|
254
|
+
launchctl print gui/$(id -u)/com.kukicha.player
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Restart the running server:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
launchctl kickstart -k gui/$(id -u)/com.kukicha.player
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Shut it down and unload it:
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.kukicha.player.plist
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
After changing the plist, unload it with `bootout`, then load it again with
|
|
270
|
+
`bootstrap`. The `bootout` and `kickstart -k` commands trigger normal process
|
|
271
|
+
shutdown, and Kukicha logs shutdown with the same timestamped stdout/stderr
|
|
272
|
+
logging as startup.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "kukicha"
|
|
7
|
+
version = "0.1.0a1"
|
|
8
|
+
description = "Scan and query a SQLite-backed music metadata database."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"Flask>=3.1.0",
|
|
13
|
+
"Jinja2>=3.1.0",
|
|
14
|
+
"mutagen>=1.47.0",
|
|
15
|
+
"Pillow>=10.0.0",
|
|
16
|
+
"yt-dlp[default]==2026.3.17",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
kukicha = "kukicha.cli:main"
|
|
21
|
+
|
|
22
|
+
[tool.setuptools]
|
|
23
|
+
package-dir = {"" = "src"}
|
|
24
|
+
|
|
25
|
+
[tool.setuptools.packages.find]
|
|
26
|
+
where = ["src"]
|
|
27
|
+
|
|
28
|
+
[tool.setuptools.package-data]
|
|
29
|
+
kukicha = ["data/*.tsv", "templates/player/*.html", "static/*.css", "static/*.js", "static/*.svg"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""kukicha package."""
|