0c9c30d1c2
* feat(ipc): report live radio metadata in status A stream's playlist entry only carries the station name, so status reported that with no artist while the TUI showed the actual song. Stations broadcast now-playing text inline as ICY metadata (the StreamTitle field of the SHOUTcast/Icecast protocol), which the UI polls but never reached the IPC response. Apply the UI's own resolution in both the TUI and daemon status handlers, and add TrackInfo.StreamTitle (the raw StreamTitle value) plus TrackInfo.Station so a client can show station, artist/song, and progress together. Resolved at the status handlers rather than in ipcTrackInfo/trackInfo, since only the now-playing track has stream context. * fix(ipc): keep the stored title when an ICY tag has no song A StreamTitle of "Artist - " cuts to an empty title, which blanked the display instead of falling back to the station name. Guard the split in resolveTrackDisplay (fixing the TUI and Lua events too, not just status) and in the daemon, and derive Station from the resolved title so both paths agree. Also handle a stream title with no artist in the docs jq example. Addresses review feedback on #319. * test(ipc): cover the daemon's stream-title contract Extract the daemon's stream branch into applyStreamTitle so the test exercises the real implementation rather than a copy of it, and cover the "Artist - Title", "Artist - ", title-only, no-metadata, and non-stream cases. statusResponse needs a live player, so the helper is the seam. Also guard the docs jq example against a missing .track, which printed a literal "null" when nothing was loaded. Addresses review feedback on #319.
79 lines
2.3 KiB
Go
79 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/bjarneo/cliamp/ipc"
|
|
"github.com/bjarneo/cliamp/playlist"
|
|
)
|
|
|
|
// TestDaemonStreamTitleFields pins the daemon's IPC contract against the TUI's:
|
|
// same split, same fallbacks, same Station derivation. statusResponse itself
|
|
// needs a live *player.Player, so it calls the extracted helper directly.
|
|
func TestDaemonStreamTitleFields(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
streamTitle string
|
|
track playlist.Track
|
|
wantTitle string
|
|
wantArtist string
|
|
wantStation string
|
|
wantStream string
|
|
}{
|
|
{
|
|
name: "artist and title split on separator",
|
|
streamTitle: "Tycho - Awake",
|
|
track: playlist.Track{Title: "NCS Trap Stream", Stream: true},
|
|
wantTitle: "Awake",
|
|
wantArtist: "Tycho",
|
|
wantStation: "NCS Trap Stream",
|
|
wantStream: "Tycho - Awake",
|
|
},
|
|
{
|
|
name: "empty title after the separator keeps the station",
|
|
streamTitle: "Tycho - ",
|
|
track: playlist.Track{Title: "Lofi Stream", Stream: true},
|
|
wantTitle: "Lofi Stream",
|
|
wantStream: "Tycho - ",
|
|
},
|
|
{
|
|
name: "title-only metadata becomes the title",
|
|
streamTitle: "Morning Session",
|
|
track: playlist.Track{Title: "Lofi Stream", Stream: true},
|
|
wantTitle: "Morning Session",
|
|
wantStation: "Lofi Stream",
|
|
wantStream: "Morning Session",
|
|
},
|
|
{
|
|
name: "no metadata leaves the entry untouched",
|
|
track: playlist.Track{Title: "Lofi Stream", Stream: true},
|
|
wantTitle: "Lofi Stream",
|
|
},
|
|
{
|
|
name: "non-stream track is never rewritten",
|
|
streamTitle: "Tycho - Awake",
|
|
track: playlist.Track{Title: "Alien Boy", Artist: "Oliver Tree"},
|
|
wantTitle: "Alien Boy",
|
|
wantArtist: "Oliver Tree",
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
info := ipc.TrackInfo{Title: tc.track.Title, Artist: tc.track.Artist}
|
|
applyStreamTitle(&info, tc.track, tc.streamTitle)
|
|
|
|
for _, f := range []struct{ field, got, want string }{
|
|
{"Title", info.Title, tc.wantTitle},
|
|
{"Artist", info.Artist, tc.wantArtist},
|
|
{"Station", info.Station, tc.wantStation},
|
|
{"StreamTitle", info.StreamTitle, tc.wantStream},
|
|
} {
|
|
if f.got != f.want {
|
|
t.Errorf("%s = %q, want %q", f.field, f.got, f.want)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|