fix(sloppak/ws_highway): drums stay in picker and show correct hit count

The editor strips drum arrangements from the manifest (converting them
to drum_tab), so a drum+bass sloppak had no drum arrangement at load
time. The placeholder-creation trigger was 'arrangements list is empty',
which only fired for drum-only packs. Broadened to 'no drum arrangement
exists' so drums get a placeholder even alongside bass/guitar.

Also display the actual drum_tab hit count on the placeholder
arrangement instead of showing 0 — the placeholder has no notes of its
own, but the drum_tab carries the real hit data.

Signed-off-by: =Scr4tch= <305609711+0-Scr4tch-0@users.noreply.github.com>
This commit is contained in:
=Scr4tch= 2026-07-19 19:55:40 -04:00
parent 1c077c9ab7
commit db04c4bab8
2 changed files with 23 additions and 9 deletions

View File

@ -476,12 +476,22 @@ async def highway_ws(websocket: WebSocket, filename: str, arrangement: int = -1,
_evict_audio_cache()
# Send song metadata
# For drum-only sloppaks the placeholder arrangement has 0 notes
# (drum_tab hits live separately). Surface the real hit count so
# the UI shows e.g. "Drums (1922)" instead of "Drums (0)".
_dt_hit_count = 0
if is_slop and loaded_slop is not None and loaded_slop.drum_tab is not None:
_dt_hit_count = len(loaded_slop.drum_tab.get("hits") or [])
arr_list = [
{
"index": i,
"name": a.name,
"smart_name": smart_names[i],
"notes": len(a.notes) + sum(len(c.notes) for c in a.chords),
"notes": (
_dt_hit_count
if (len(a.notes) == 0 and not a.chords and _dt_hit_count > 0)
else len(a.notes) + sum(len(c.notes) for c in a.chords)
),
}
for i, a in enumerate(song.arrangements)
]

View File

@ -895,16 +895,20 @@ def load_song(
log.warning("sloppak: drum_tab %r failed validation: %s",
drum_tab_rel, reason)
# Drum-only sloppak: every GP track was percussion, so it ships a
# drum_tab but no pitched arrangements. The highway WS rejects an empty
# arrangements list with "No arrangements found" *before* it serves the
# drum_tab, leaving the drums unplayable even in the drum highway.
# Synthesize a minimal placeholder arrangement so the stream proceeds and
# the drum_tab reaches the drum highway. It carries no notes (the guitar
# highway just shows an empty board) and, when the manifest omits a
# Drum sloppak: when a drum_tab is present but no existing arrangement is
# a drum part, synthesize a minimal placeholder so the drums appear in the
# arrangement picker and the drum_tab reaches the drum highway. The editor
# strips drum arrangements out of the manifest (converting them to
# drum_tab), so without this a drum+bass sloppak would show only Bass in
# the picker with no way to reach the drums. It carries no notes (the
# guitar highway just shows an empty board) and, when the manifest omits a
# duration, derives a song length from the last drum hit so the timeline
# isn't zero-length.
if not song.arrangements and drum_tab_data is not None:
_has_drum_arr = any(
(getattr(a, "name", "") or "").lower().startswith("drum")
for a in song.arrangements
)
if not _has_drum_arr and drum_tab_data is not None:
if song.song_length <= 0:
# validate_drum_tab() intentionally does NOT type-check individual
# hits (they're sanitized at WS-stream time), so a hit may carry a