"Add soundtrack…" in the statistics toolbar, or a folder dropped anywhere on
the window, opens a popup that lists the folder's songs and uploads them to
the server, which adds the soundtrack at once (Sansan/MusicServer#33).
- The name comes from the folder and can be changed; characters the server
refuses are replaced.
- Only MP3s are uploaded, as the server takes no other; other song files
are listed greyed out as left out. Hidden files are skipped.
- Disc folders are flattened with the disc's number first ("1-01 Title.mp3"),
as the server wants one folder. With one disc folder, names stay as
they are.
- Songs are sent one at a time with a progress bar, reading one file at a
time. A failed song is sent again twice, then the upload is cancelled
and the server's reason shown. Closing the popup cancels it too.
- Not offered while the server syncs, offline, or without MP3s.
- Afterwards search, the inspiration list and the statistics reload.
The API types come from the server's spec (Upload, UploadFile,
UploadRequest).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Version X is available" in the top bar is now a button that opens an
Update popup:
- Update and restart gets the download link from the server (the redirect
is not followed, as the Gitea link needs no token), downloads the new game
next to the running one with a progress bar, checks it (complete, and an
MZ or ELF file), swaps it in and restarts. The quiz is saved first and
continues. On Windows the running .exe is renamed to .old, put back if
the swap fails, and deleted at the next start.
- Download in browser opens the .exe, the Linux package, or the release
page on other platforms.
- From the editor, an unwritable folder or another platform, only the
browser download is offered, with the reason.
The message now fits between the tabs and the buttons in every theme; in
Nord and Christmas it ran into Sync. The macOS export preset is removed,
and the unused download_client_* functions are replaced by
fetch_client_download_url.
Closes#13
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cover menu in the soundtrack popup ("Change cover"):
- Choose picture uploads a JPEG, PNG or WebP picture (up to 10 MB).
- Pick by ID uses a game's cover on SteamGridDB or an anime's on AniList.
- Remove cover deletes it, so the server searches for a new one.
- The server's reason is shown when it refuses a change.
After a change the new cover time is fetched, and the popup, the
statistics card and the quiz show the new cover.
Quiz: once the answer is shown, the soundtrack's cover shows to the left of
the titles. Cover and titles are centered together, left and right and up
and down, and each title keeps to two lines. Cover times come from the
soundtrack list, and songs keep their soundtrack's UUID, also in saves.
Requests can now send any body with its content type, and every 2xx answer
counts as success. Cover frames are 2:3 like the server's covers. Small
copies of real covers are used by the tests and screenshots.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Covers: statistics cards show the soundtrack's cover on the left, and the
statistics popup shows it large. Until it arrives, and without a cover, the
soundtrack's initials stand in. Covers load only for cards on or near the
screen, three at a time, and are cached in covers/ next to the settings
(CoverCache), downloaded again only when cover_modified changes. The index and
file handling are shared with CharacterCache in a new FileCache.
Alternative names: the popup shows them and has an editor (add, remove, save)
that sends PUT /soundtracks/{uuid}/alternative-names. The statistics search and
the Search popup find soundtracks by them; Search shows the matching name after
the real one. Search now loads /soundtracks, falling back to the plain list.
The API types are regenerated from the server's spec, with a SoundtrackCover
theme style in every theme.
Closes#49
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The server keeps a play queue per client, identified by the X-Queue-Id
header. The client sends the ID it has for the selected server with every
request and keeps the one in each response, which is new after a reset or a
sync. The IDs are saved per server in the [queues] section of settings.cfg,
so the game goes on with the same queue after a restart.
HttpTransport now passes the response headers on to the client.
Closes#38, #39 and #40; adds the client side of #41.
- Every request goes to /api/v1. MusicServerClient gets a token with
Settings.api_password the first time one is needed, reuses it, and on a
401 gets a new one and sends the request once more. Switching server gets
a new token too. Callers never see the token.
- Sync is started with POST, as MusicServer 5.0 requires.
- The client has every endpoint in the server's OpenAPI spec, including
statistics, soundtracks and songs by UUID, version, downloads and tokens.
- tools/generate_api_types.gd generates a typed class per schema in
server/openapi.json into server/generated/. Song info, statistics and
versions are passed to callers as these classes. A list the server sends
as null is an empty list.
- FakeHttpTransport hands out tokens and answers 401 without one, so every
test goes through the token flow. New tests cover the token handling,
every endpoint and each generated class.
At startup and after resetting the playlist, loading the song list and
preloading the first song started at the same time. When the list
answered last, it cleared the playlist and dropped the preloaded song.
Preloading now starts once the list has loaded, and loading the list is
retried if it fails.
Covers a cache size above 1: songs are preloaded until the setting is
reached, playing a song tops the cache up again, and the cache keeps
filling after a failed download once the server answers again.
The previous tests never compiled: they used GUT's assert functions,
Godot 3 APIs and reassigned autoload functions, so no test ran.
- 90 tests: unit tests for the playlist, songs, player scoring, time
formatting, search and the server client, plus integration tests
that run MainWindow and SyncWindow against a fake server
- Keybind tests check that Alt+<number> and Ctrl+Alt+<number> keep
following the player rows while players are added and removed
- run_tests.sh finds Godot and runs the suite headless (~10 seconds)
- CI runs the tests before the build job in gitea-build.yaml; the
separate test.yml used a GitHub action that does not exist
- GdUnit4 is committed instead of ignored, since the project enables
it, and .gitea/ is no longer ignored
- Exported builds leave out tests/ and addons/gdUnit4/