Song server: central song library with on-demand downloads

- VocaluxeSongServer: ASP.NET Core server that scans an UltraStar library and
  serves the song list (ETag), single files (Range) and zip bundles; optional
  API key; Dockerfile and Gitea workflow for git.disi.dev/projects/vocaluxe-song-server
- Game: config section SongServer (Url, ApiKey). At song loading, the song text
  files are mirrored into a local cache that is loaded like a song folder;
  without connection the last library is used
- VocaluxeLib: CSongFiles hook for all song file access; media are downloaded on
  demand (covers in the background, preview audio, everything before singing
  with progress in the sing screen)
- Tests for scanner, API and downloads (incl. resume); AGENTS.md for the fork

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Simon DiesenreiterandClaude Opus 5.5 committed 2026-11-05 17:23:00 +01:00
1 parent cf2fa796e2
commit efcc63a640
29 files changed
+1753 -20

No files matched your search

+48
View File
@@ -0,0 +1,48 @@
# Vocaluxe (fork at git.disi.dev/Projects/Vocaluxe)
Fork of [Vocaluxe/Vocaluxe](https://github.com/Vocaluxe/Vocaluxe), a karaoke game (C#, .NET 10). Default branch
`develop` tracks upstream; the fork's own work happens on feature branches. Keep changes to upstream code small and
hook-based, so upstream can still be merged.
## Goal of the fork
1. **Song server** (`VocaluxeSongServer/`, in progress): a central song library on the homelab. The game becomes the
frontend and downloads song files on demand. See `VocaluxeSongServer/README.md`.
2. Later: serve the guest WebApp ("browse by phone", `WebApp/` + `VocaluxeWeb/`) directly from the server.
3. Later: search and download songs that aren't in the library, from common internet sources (possibly UltraSinger
to create songs from audio).
## Layout
| Folder | What |
|---|---|
| `Vocaluxe/` | The game. Song server client: `Base/SongServer/` (`CSongServer` sync, `CRemoteSongFileProvider` downloads) |
| `VocaluxeLib/` | Shared library. `Songs/CSongFiles.cs` is the hook every song file access goes through |
| `VocaluxeSongServer/` | ASP.NET Core server, Docker image `git.disi.dev/projects/vocaluxe-song-server` |
| `VocaluxeWeb/`, `WebApp/` | Built-in webserver of the game and the guest WebApp (Vue), upstream |
| `Tests/` | NUnit; song server tests in `Tests/SongServer` |
## How the song server integration works
- `CSongs.LoadSongs` calls `CSongServer.Sync()`: fetches `/api/v1/library` (ETag), mirrors the song `.txt` files into
`<DataFolder>/SongServer/<host>_<port>` (zip bundles), deletes files no longer on the server, and installs
`CRemoteSongFileProvider` as `CSongFiles.Provider`. The cache folder is then loaded like a normal song folder.
- `CSongFiles.Exists` (loader header checks) is true for files that only exist on the server. `IsLocal` means the file
is downloaded and current (size and mtime match the server).
- Downloads on demand: covers (`CSong.LoadSmallCover`, background threads, blocking), preview audio
(`CBackgroundMusic.LoadPreview` + `Update`), everything before singing (`CScreenSing._LoadAndStartCurrentSong`,
progress via `TR_SCREENSING_DOWNLOADING`). Downloads resume from `.part` files with Range requests.
- Config: `config.xml` section `SongServer` (`Url`, `ApiKey`). The contracts (`VocaluxeSongServer/Contracts`) are
linked into `Vocaluxe.csproj`; the test project references the server with `extern alias songserver`.
## Build and test (Windows)
- `dotnet build Vocaluxe/Vocaluxe.csproj -c DebugWin -p:Platform=x64` (the whole solution also builds the native
`PitchTracker`, which needs Visual Studio's C++ tools).
- `dotnet test Tests/Tests.csproj -c DebugWin -p:Platform=x64`
- Building rewrites the copyright year in `Vocaluxe/Properties/AssemblyInfo.cs`; don't commit that.
- Don't use `dotnet sln add`: it rewrites the configuration table of `Vocaluxe.sln`. Copy the lines of `VocaluxeWeb`.
- New `config.xml` fields must also go into `Tests/VocaluxeLib/XML/TestFiles/SConfig.xml` (round-trip test; CRLF).
## Known gaps (song server)
- Cover/background auto-detection (`[CO]`/`[BG]` files without a tag, `CSong._CheckFiles`) only sees local files.
- Media in subfolders of a song folder are not served (only the song folder itself).
- On Linux clients, media whose name differs in case from the `.txt` reference won't be found after download.
- No cache size limit yet. The WebApp's cover images for server songs depend on the cover loader having fetched them.
- No in-game UI for the server address yet (only `config.xml`).