From 4b81804a304ea75d50e27f31ff7ba873d0ab3496 Mon Sep 17 00:00:00 2001 From: devgianlu Date: Fri, 9 Feb 2024 14:46:28 +0100 Subject: [PATCH] feat: support set_options command --- cmd/daemon/controls.go | 86 +++++++++++++++++++++--------------------- cmd/daemon/player.go | 21 ++++++++--- cmd/daemon/state.go | 4 +- dealer/recv.go | 27 +++++++------ 4 files changed, 74 insertions(+), 64 deletions(-) diff --git a/cmd/daemon/controls.go b/cmd/daemon/controls.go index 2ea28ea..c1d63a1 100644 --- a/cmd/daemon/controls.go +++ b/cmd/daemon/controls.go @@ -179,61 +179,59 @@ func (p *AppPlayer) loadCurrentTrack(paused bool) error { return nil } -func (p *AppPlayer) setRepeatingContext(val bool) { - if val == p.state.player.Options.RepeatingContext { - return +func (p *AppPlayer) setOptions(repeatingContext *bool, repeatingTrack *bool, shufflingContext *bool) { + var requiresUpdate bool + if repeatingContext != nil && *repeatingContext != p.state.player.Options.RepeatingContext { + p.state.player.Options.RepeatingContext = *repeatingContext + + p.app.server.Emit(&ApiEvent{ + Type: ApiEventTypeRepeatContext, + Data: ApiEventDataRepeatContext{ + Value: *repeatingContext, + }, + }) + + requiresUpdate = true } - p.state.player.Options.RepeatingContext = val - p.updateState() + if repeatingTrack != nil && *repeatingTrack != p.state.player.Options.RepeatingTrack { + p.state.player.Options.RepeatingTrack = *repeatingTrack - p.app.server.Emit(&ApiEvent{ - Type: ApiEventTypeRepeatContext, - Data: ApiEventDataRepeatContext{ - Value: val, - }, - }) -} + p.app.server.Emit(&ApiEvent{ + Type: ApiEventTypeRepeatTrack, + Data: ApiEventDataRepeatTrack{ + Value: *repeatingTrack, + }, + }) -func (p *AppPlayer) setRepeatingTrack(val bool) { - if val == p.state.player.Options.RepeatingTrack { - return + requiresUpdate = true } - p.state.player.Options.RepeatingTrack = val - p.updateState() + if shufflingContext != nil && *shufflingContext != p.state.player.Options.ShufflingContext { + if err := p.state.tracks.ToggleShuffle(*shufflingContext); err != nil { + log.WithError(err).Errorf("failed toggling shuffle context (value: %t)", *shufflingContext) + return + } - p.app.server.Emit(&ApiEvent{ - Type: ApiEventTypeRepeatTrack, - Data: ApiEventDataRepeatTrack{ - Value: val, - }, - }) -} + p.state.player.Options.ShufflingContext = *shufflingContext + p.state.player.Track = p.state.tracks.CurrentTrack() + p.state.player.PrevTracks = p.state.tracks.PrevTracks() + p.state.player.NextTracks = p.state.tracks.NextTracks() + p.state.player.Index = p.state.tracks.Index() -func (p *AppPlayer) setShufflingContext(val bool) { - if val == p.state.player.Options.ShufflingContext { - return - } + p.app.server.Emit(&ApiEvent{ + Type: ApiEventTypeShuffleContext, + Data: ApiEventDataShuffleContext{ + Value: *shufflingContext, + }, + }) - if err := p.state.tracks.ToggleShuffle(val); err != nil { - log.WithError(err).Errorf("failed toggling shuffle context (value: %t)", val) - return + requiresUpdate = true } - p.state.player.Options.ShufflingContext = val - p.state.player.Track = p.state.tracks.CurrentTrack() - p.state.player.PrevTracks = p.state.tracks.PrevTracks() - p.state.player.NextTracks = p.state.tracks.NextTracks() - p.state.player.Index = p.state.tracks.Index() - p.updateState() - - p.app.server.Emit(&ApiEvent{ - Type: ApiEventTypeShuffleContext, - Data: ApiEventDataShuffleContext{ - Value: val, - }, - }) + if requiresUpdate { + p.updateState() + } } func (p *AppPlayer) addToQueue(track *connectpb.ContextTrack) { diff --git a/cmd/daemon/player.go b/cmd/daemon/player.go index b249701..48fa79b 100644 --- a/cmd/daemon/player.go +++ b/cmd/daemon/player.go @@ -250,13 +250,19 @@ func (p *AppPlayer) handlePlayerCommand(req dealer.RequestPayload) error { p.updateState() return nil case "set_repeating_context": - p.setRepeatingContext(req.Command.Value.(bool)) + val := req.Command.Value.(bool) + p.setOptions(&val, nil, nil) return nil case "set_repeating_track": - p.setRepeatingTrack(req.Command.Value.(bool)) + val := req.Command.Value.(bool) + p.setOptions(nil, &val, nil) return nil case "set_shuffling_context": - p.setShufflingContext(req.Command.Value.(bool)) + val := req.Command.Value.(bool) + p.setOptions(nil, nil, &val) + return nil + case "set_options": + p.setOptions(req.Command.RepeatingContext, req.Command.RepeatingTrack, req.Command.ShufflingContext) return nil case "set_queue": p.setQueue(req.Command.PrevTracks, req.Command.NextTracks) @@ -355,13 +361,16 @@ func (p *AppPlayer) handleApiRequest(req ApiRequest) (any, error) { p.updateVolume(vol * player.MaxStateVolume / *p.app.cfg.VolumeSteps) return nil, nil case ApiRequestTypeSetRepeatingContext: - p.setRepeatingContext(req.Data.(bool)) + val := req.Data.(bool) + p.setOptions(&val, nil, nil) return nil, nil case ApiRequestTypeSetRepeatingTrack: - p.setRepeatingTrack(req.Data.(bool)) + val := req.Data.(bool) + p.setOptions(nil, &val, nil) return nil, nil case ApiRequestTypeSetShufflingContext: - p.setShufflingContext(req.Data.(bool)) + val := req.Data.(bool) + p.setOptions(nil, nil, &val) return nil, nil case ApiRequestTypeAddToQueue: p.addToQueue(&connectpb.ContextTrack{Uri: req.Data.(string)}) diff --git a/cmd/daemon/state.go b/cmd/daemon/state.go index 92e9724..866d6ad 100644 --- a/cmd/daemon/state.go +++ b/cmd/daemon/state.go @@ -88,13 +88,13 @@ func (p *AppPlayer) initState() { SupportsPlaylistV2: true, IsControllable: true, SupportsExternalEpisodes: false, // TODO: support external episodes - SupportsSetBackendMetadata: false, + SupportsSetBackendMetadata: true, SupportsTransferCommand: true, SupportsCommandRequest: true, IsVoiceEnabled: false, NeedsFullPlayerState: false, SupportsGzipPushes: true, - SupportsSetOptionsCommand: false, + SupportsSetOptionsCommand: true, SupportsHifi: nil, // TODO: nice to have? ConnectCapabilities: "", }, diff --git a/dealer/recv.go b/dealer/recv.go index f55eae2..1c1d626 100644 --- a/dealer/recv.go +++ b/dealer/recv.go @@ -44,18 +44,21 @@ type RequestPayload struct { TargetAliasId string `json:"target_alias_id"` SentByDeviceId string `json:"sent_by_device_id"` Command struct { - Endpoint string `json:"endpoint"` - SessionId string `json:"session_id"` - Data []byte `json:"data"` - Value interface{} `json:"value"` - Position int64 `json:"position"` - Relative string `json:"relative"` - Context *connectpb.Context `json:"context"` - PlayOrigin *connectpb.PlayOrigin `json:"play_origin"` - Track *connectpb.ContextTrack `json:"track"` - PrevTracks []*connectpb.ContextTrack `json:"prev_tracks"` - NextTracks []*connectpb.ContextTrack `json:"next_tracks"` - LoggingParams struct { + Endpoint string `json:"endpoint"` + SessionId string `json:"session_id"` + Data []byte `json:"data"` + Value interface{} `json:"value"` + Position int64 `json:"position"` + Relative string `json:"relative"` + Context *connectpb.Context `json:"context"` + PlayOrigin *connectpb.PlayOrigin `json:"play_origin"` + Track *connectpb.ContextTrack `json:"track"` + PrevTracks []*connectpb.ContextTrack `json:"prev_tracks"` + NextTracks []*connectpb.ContextTrack `json:"next_tracks"` + RepeatingTrack *bool `json:"repeating_track"` + RepeatingContext *bool `json:"repeating_context"` + ShufflingContext *bool `json:"shuffling_context"` + LoggingParams struct { CommandInitiatedTime int64 `json:"command_initiated_time"` PageInstanceIds []string `json:"page_instance_ids"` InteractionIds []string `json:"interaction_ids"`