README: make it generic (no host paths, IPs or personal examples)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
cdnutterandClaude Sonnet 5.5 committed 2026-10-20 15:09:12 -07:00
1 parent 1cf9341cda
commit d69c44eff9
1 file changed
+35 -35
+35 -35
View File
@@ -20,7 +20,7 @@ It runs on iPhone (with CarPlay), Android (with Android Auto) and Linux desktop.
## How it works ## How it works
The stems folder mirrors the music folder. If a song lives at `Kansas/Leftoverture/01 Carry On.flac`, its stems live in `Stems/Kansas/Leftoverture/01 Carry On/`. The stems folder mirrors the music folder. If a song lives at `Artist/Album/01 Song.flac`, its stems live in `Stems/Artist/Album/01 Song/`.
``` ```
your server your server
@@ -63,48 +63,48 @@ Mix presets are Full, Karaoke, A Cappella, No Drums, Rhythm, No Guitar and No Ba
## Setup ## Setup
Set up the server first, then the apps. The examples use Unraid paths and `192.168.86.2` for the server; use your own. Set up the server first, then the apps. The examples use `/srv/stemify` for app data, `/srv/music/library` for your music, `/srv/music/stems` for the output and `SERVER_IP` for the machine running the containers. Change them to match your setup.
### Server ### Server
You need Docker, and an NVIDIA GPU for stemd (on Unraid, install the Nvidia-Driver plugin). A CPU build exists for testing, but it's far too slow for a whole library. You need Docker, and an NVIDIA GPU for stemd (with the NVIDIA container toolkit installed). A CPU build exists for testing, but it's far too slow for a whole library.
Make the folders, owned by `99:100` (Unraid's nobody:users): Make the folders, owned by whatever user the containers run as (`1000:1000` here):
```sh ```sh
mkdir -p /mnt/user/appdata/stemserve/cache \ mkdir -p /srv/stemify/stemserve/cache \
/mnt/user/appdata/stemd/models \ /srv/stemify/stemd/models \
/mnt/user/appdata/stemd/state/queue /srv/stemify/stemd/state/queue
chown -R 99:100 /mnt/user/appdata/stemserve /mnt/user/appdata/stemd chown -R 1000:1000 /srv/stemify/stemserve /srv/stemify/stemd
``` ```
**stemd** builds from the repo root because it uses the `stemify` package. Copy the repo (at least `stemify/`, `server/` and `.dockerignore`) to `/mnt/user/appdata/stemd/src`, then: **stemd** builds from the repo root because it uses the `stemify` package. Copy the repo (at least `stemify/`, `server/` and `.dockerignore`) to `/srv/stemify/stemd/src`, then:
```sh ```sh
docker build -f /mnt/user/appdata/stemd/src/server/stemd.Dockerfile -t stemd /mnt/user/appdata/stemd/src docker build -f /srv/stemify/stemd/src/server/stemd.Dockerfile -t stemd /srv/stemify/stemd/src
docker run -d --name stemd --restart unless-stopped --stop-timeout 60 \ docker run -d --name stemd --restart unless-stopped --stop-timeout 60 \
--runtime=nvidia -e NVIDIA_VISIBLE_DEVICES=all -e NVIDIA_DRIVER_CAPABILITIES=compute,utility \ --runtime=nvidia -e NVIDIA_VISIBLE_DEVICES=all -e NVIDIA_DRIVER_CAPABILITIES=compute,utility \
-v "/mnt/user/Music/Actual music/Flacs":/music:ro \ -v /srv/music/library:/music:ro \
-v /mnt/user/Music/Stems:/stems \ -v /srv/music/stems:/stems \
-v /mnt/user/appdata/stemd/models:/models \ -v /srv/stemify/stemd/models:/models \
-v /mnt/user/appdata/stemd/state:/state \ -v /srv/stemify/stemd/state:/state \
stemd stemd
``` ```
The first song downloads the model (about 700 MB). After that the log shows what's left, what it's on, and how fast it's going. The first song downloads the model (about 700 MB). After that the log shows what's left, what it's on, and how fast it's going.
**stemserve** is one Python file using only the standard library. It also serves the web player from `web/`. Copy the repo's `server/` and `web/` folders to `/mnt/user/appdata/stemserve` and run `docker compose up -d --build` in `server/`, or by hand: **stemserve** is one Python file using only the standard library. It also serves the web player from `web/`. Copy the repo's `server/` and `web/` folders to `/srv/stemify/stemserve` and run `docker compose up -d --build` in `server/`, or by hand:
```sh ```sh
docker build -f /mnt/user/appdata/stemserve/server/Dockerfile -t stemserve /mnt/user/appdata/stemserve docker build -f /srv/stemify/stemserve/server/Dockerfile -t stemserve /srv/stemify/stemserve
docker run -d --name stemserve --restart unless-stopped -p 8765:8765 \ docker run -d --name stemserve --restart unless-stopped -p 8765:8765 \
-v /mnt/user/Music/Stems:/stems:ro \ -v /srv/music/stems:/stems:ro \
-v /mnt/user/appdata/stemserve/cache:/cache \ -v /srv/stemify/stemserve/cache:/cache \
-v /mnt/user/appdata/stemd/state/queue:/queue \ -v /srv/stemify/stemd/state/queue:/queue \
stemserve stemserve
``` ```
`curl http://192.168.86.2:8765/api/info` should return JSON with a track count. `curl http://SERVER_IP:8765/api/info` should return JSON with a track count.
To update, copy the new files, rebuild, `docker rm -f` the container and run it again. Everything that matters lives in the mounted folders. Update stemd before stemserve. To update, copy the new files, rebuild, `docker rm -f` the container and run it again. Everything that matters lives in the mounted folders. Update stemd before stemserve.
@@ -155,14 +155,14 @@ The apps check stemserve for newly separated songs every minute, so the library
## iOS ## iOS
A SwiftUI app for iOS 17 or newer, with CarPlay and Siri ("play Paranoid in Stemify"). A SwiftUI app for iOS 17 or newer, with CarPlay and Siri ("play <song> in Stemify").
### Install ### Install
Grab `stemify-<version>.ipa` from [Releases](https://git.iamchrisama.com/cdnutter/stemify/releases) and sideload it with AltStore, SideStore, Sideloadly or Feather. To get updates in AltStore, SideStore or Feather, add this source: Grab `stemify-<version>.ipa` from the repo's Releases page and sideload it with AltStore, SideStore, Sideloadly or Feather. `ios/source.json` is an AltStore-style source. Add its raw URL to AltStore, SideStore or Feather for updates:
``` ```
https://git.iamchrisama.com/cdnutter/stemify/raw/branch/main/ios/source.json https://<your-git-host>/<owner>/stemify/raw/branch/main/ios/source.json
``` ```
CarPlay and Siri need the `carplay-audio` and `siri` entitlements, which a free Apple ID can't sign. On a free sideload the app works on the phone but not in CarPlay or Siri. A paid developer account covers Siri; CarPlay audio also needs Apple to approve the entitlement for your team. CarPlay and Siri need the `carplay-audio` and `siri` entitlements, which a free Apple ID can't sign. On a free sideload the app works on the phone but not in CarPlay or Siri. A paid developer account covers Siri; CarPlay audio also needs Apple to approve the entitlement for your team.
@@ -186,7 +186,7 @@ CarPlay and Siri need the `carplay-audio` and `siri` entitlements, which a free
## Android ## Android
Kotlin and Jetpack Compose, built and tested on a OnePlus 15. Grab `Stemify.apk` from Releases (or [build it](#building-and-testing)) and `adb install -r Stemify.apk`. Kotlin and Jetpack Compose, [build it](#building-and-testing) or grab `Stemify.apk` from Releases if one is attached, and `adb install -r Stemify.apk`.
### Using it ### Using it
@@ -194,7 +194,7 @@ Kotlin and Jetpack Compose, built and tested on a OnePlus 15. Grab `Stemify.apk`
- **Badges:** songs without stems yet say NO STEMS, and albums and artists show NO STEMS or a count like 7/10 STEMS. They still play from the original file. - **Badges:** songs without stems yet say NO STEMS, and albums and artists show NO STEMS or a count like 7/10 STEMS. They still play from the original file.
- **Now Playing:** waveform seek bar (drag sideways to seek, up and down for volume), mixer, meters and queue. Your mix can carry over between songs or reset. - **Now Playing:** waveform seek bar (drag sideways to seek, up and down for volume), mixer, meters and queue. Your mix can carry over between songs or reset.
- **Stem Quality:** lossless FLAC, or Opus at a bitrate you choose (about an eighth of the size, transcoded and cached on the server). - **Stem Quality:** lossless FLAC, or Opus at a bitrate you choose (about an eighth of the size, transcoded and cached on the server).
- **Streaming** needs your home network, since Plex and stemserve are plain HTTP on the LAN. Downloads and already-streamed songs play anywhere. - **Streaming** works anywhere you can reach Plex and stemserve. Both are plain HTTP by default, so use HTTPS or a VPN away from home. Downloads and already-streamed songs play anywhere.
### Equalizer ### Equalizer
@@ -209,12 +209,12 @@ Profiles are tied to outputs (speaker, wired, each Bluetooth device, USB DACs) a
### Android Auto ### Android Auto
Built for a 2016 Mazda MX-5 with Mazda Connect: 800×480, no touch, knob and wheel buttons only. Designed for small non-touch head units (800×480, knob and wheel buttons only), and it works the same on larger screens.
- Tabs for Playlists, Albums, Artists and Downloads (Downloads first when you're away from home). - Tabs for Playlists, Albums, Artists and Downloads (Downloads first when you're away from home).
- Every song list starts with Shuffle all, and lists over 40 items split into A to Z folders. - Every song list starts with Shuffle all, and lists over 40 items split into A to Z folders.
- Now Playing has a Vocals on/off button and a Mix button that cycles presets. The mix shows on the artist line, like "Black Sabbath · Karaoke". - Now Playing has a Vocals on/off button and a Mix button that cycles presets. The mix shows on the artist line, like "Artist · Karaoke".
- Voice: "play Paranoid on Stemify" works for playlists, artists, albums and songs. - Voice: "play <song> on Stemify" works for playlists, artists, albums and songs.
- Away from home it notices the server is gone and only lists songs that will play. - Away from home it notices the server is gone and only lists songs that will play.
Android Auto hides sideloaded apps until you allow them: in the phone's Android Auto settings, tap Version ten times, then ⋮ → Developer settings → Unknown sources. Android Auto hides sideloaded apps until you allow them: in the phone's Android Auto settings, tap Version ten times, then ⋮ → Developer settings → Unknown sources.
@@ -279,11 +279,11 @@ Requests run oldest first and survive restarts. stemd matches Plex's paths to it
### Folder layout ### Folder layout
``` ```
Music/Kansas/Leftoverture/01 Carry On Wayward Son.flac Music/Artist/Album/01 Song.flac
Stems/Kansas/Leftoverture/01 Carry On Wayward Son/ Stems/Artist/Album/01 Song/
.stemify.json done marker .stemify.json done marker
01 Carry On Wayward Son - vocals.flac 01 Song - vocals.flac
01 Carry On Wayward Son - drums.flac 01 Song - drums.flac
... ...
``` ```
@@ -303,7 +303,7 @@ Stems/Kansas/Leftoverture/01 Carry On Wayward Son/
| `GET /file/K/<file>.flac[?fmt=opus&br=256]` | The stem, with range support | | `GET /file/K/<file>.flac[?fmt=opus&br=256]` | The stem, with range support |
| `GET /` | The web player from `web/` (or `WEB_DIR`), no token needed | | `GET /` | The web player from `web/` (or `WEB_DIR`), no token needed |
`K` is the song's folder under the stems root, like `Kansas/Leftoverture/01 Carry On Wayward Son`. Outside Docker: `K` is the song's folder under the stems root, like `Artist/Album/01 Song`. Outside Docker:
```sh ```sh
STEMS_DIR=/path/to/Stems CACHE_DIR=~/.cache/stemserve python3 server/stemserve.py STEMS_DIR=/path/to/Stems CACHE_DIR=~/.cache/stemserve python3 server/stemserve.py
@@ -358,7 +358,7 @@ QT_QPA_PLATFORM=offscreen uv run stemify-player --no-mpris --screenshot /tmp/p.p
**A song says NO STEMS.** Hold it and choose Stem Now. **A song says NO STEMS.** Hold it and choose Stem Now.
**Stem Now says "stemserve needs updating" or "queue folder isn't mounted".** stemserve is older than the app or is missing the `/queue` mount. The queue folder has to be owned by `99:100` before the container first starts, or Docker creates it as root. **Stem Now says "stemserve needs updating" or "queue folder isn't mounted".** stemserve is older than the app or is missing the `/queue` mount. The queue folder has to be writable by the container user before the container first starts, or Docker creates it as root.
**stemd is separating on the CPU.** The container can't see the GPU. Run it with `--runtime=nvidia` and the NVIDIA variables above. **stemd is separating on the CPU.** The container can't see the GPU. Run it with `--runtime=nvidia` and the NVIDIA variables above.
@@ -381,7 +381,7 @@ QT_QPA_PLATFORM=offscreen uv run stemify-player --no-mpris --screenshot /tmp/p.p
- [LRCLIB](https://lrclib.net) for synced lyrics - [LRCLIB](https://lrclib.net) for synced lyrics
- Inter, Selawik and Carlito fonts (licenses included alongside them) - Inter, Selawik and Carlito fonts (licenses included alongside them)
Stemify isn't affiliated with Plex, Apple, Google, Microsoft or Mazda. Stemify isn't affiliated with Plex, Apple, Google or Microsoft.
## License ## License