From b52aa5b36fa48711142387fe3235afc384476a41 Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Sat, 7 Feb 2026 10:18:51 -0800 Subject: [PATCH] rate-current CLI option (#847) --- backend/app.go | 15 +++++++++++++++ backend/cmdlineoptions.go | 12 +++++++++++- backend/ipc/api.go | 5 +++++ backend/ipc/client.go | 5 +++++ backend/ipc/server.go | 20 ++++++++++++++++++-- 5 files changed, 54 insertions(+), 3 deletions(-) diff --git a/backend/app.go b/backend/app.go index 9d21d48..d182afd 100644 --- a/backend/app.go +++ b/backend/app.go @@ -203,8 +203,21 @@ func StartupApp(appName, displayAppName, appVersion, appVersionTag, latestReleas ipc.DestroyConn() // cleanup socket possibly orphaned by crashed process listener, err := ipc.Listen() if err == nil { + ipcRatingHandler := func(rating int) { + if s := a.ServerManager.GetServer(); s != nil { + if tr := a.PlaybackManager.NowPlaying(); tr != nil && tr.Metadata().Type == mediaprovider.MediaItemTypeTrack { + if supportsRating, ok := s.(mediaprovider.SupportsRating); ok { + supportsRating.SetRating(mediaprovider.RatingFavoriteParameters{ + TrackIDs: []string{tr.Metadata().ID}, + }, rating) + } + } + } + } + a.ipcServer = ipc.NewServer( a.PlaybackManager, + ipcRatingHandler, a.ServerManager, a.callOnReactivate, func() { _ = a.callOnExit() }) @@ -650,6 +663,8 @@ func (a *App) checkFlagsAndSendIPCMsg(cli *ipc.Client) error { fmt.Println(data) } return err + case RateCurrentCLIArg >= 0: + return cli.RateCurrentTrack(RateCurrentCLIArg) default: return nil } diff --git a/backend/cmdlineoptions.go b/backend/cmdlineoptions.go index b114276..6bcc489 100644 --- a/backend/cmdlineoptions.go +++ b/backend/cmdlineoptions.go @@ -12,6 +12,7 @@ import ( var ( VolumeCLIArg int = -1 SeekToCLIArg float64 = -1 + RateCurrentCLIArg int = -1 SeekByCLIArg float64 = 0 VolumePctCLIArg float64 = 0 PlayAlbumCLIArg string = "" @@ -84,7 +85,9 @@ func init() { } flag.Func("first-track", "start playing from given track (positive integer, to be used with either -play-album or -play-playlist)", func(s string) error { v, err := strconv.Atoi(s) - FirstTrackCLIArg = v + if err == nil { + FirstTrackCLIArg = v + } return err }) @@ -100,6 +103,13 @@ func init() { SearchTrackCLIArg = s return nil }) + flag.Func("rate-current", "rate the current track with the given rating (0-5)", func(s string) error { + v, err := strconv.Atoi(s) + if err == nil { + RateCurrentCLIArg = v + } + return err + }) } func HaveCommandLineOptions() bool { diff --git a/backend/ipc/api.go b/backend/ipc/api.go index d52e09a..60028d6 100644 --- a/backend/ipc/api.go +++ b/backend/ipc/api.go @@ -27,6 +27,7 @@ const ( VolumeAdjustPath = "/volume/adjust" // ?pct=<+/- percentage> ShowPath = "/window/show" QuitPath = "/window/quit" + RateCurrentTrackPath = "/current_track/rate" // ?r= ) type Response struct { @@ -76,3 +77,7 @@ func BuildSearchTrackPath(search string) string { s := url.QueryEscape(search) return fmt.Sprintf("%s?s=%s", SearchTrackPath, s) } + +func BuildRateCurrentTrackPath(rating int) string { + return fmt.Sprintf("%s?r=%d", RateCurrentTrackPath, rating) +} diff --git a/backend/ipc/client.go b/backend/ipc/client.go index 46582eb..41cb310 100644 --- a/backend/ipc/client.go +++ b/backend/ipc/client.go @@ -118,6 +118,11 @@ func (c *Client) AdjustVolumePct(pct float64) error { return err } +func (c *Client) RateCurrentTrack(rating int) error { + _, err := c.sendRequest(BuildRateCurrentTrackPath(rating)) + return err +} + func (c *Client) Show() error { _, err := c.sendRequest(ShowPath) return err diff --git a/backend/ipc/server.go b/backend/ipc/server.go index 02b5b03..3ded536 100644 --- a/backend/ipc/server.go +++ b/backend/ipc/server.go @@ -43,13 +43,14 @@ type ServerManager interface { type serverImpl struct { server *http.Server pbHandler PlaybackHandler + rateFn func(int) sm ServerManager showFn func() quitFn func() } -func NewServer(pbHandler PlaybackHandler, sm ServerManager, showFn, quitFn func()) IPCServer { - s := &serverImpl{pbHandler: pbHandler, sm: sm, showFn: showFn, quitFn: quitFn} +func NewServer(pbHandler PlaybackHandler, rateFn func(int), sm ServerManager, showFn, quitFn func()) IPCServer { + s := &serverImpl{pbHandler: pbHandler, rateFn: rateFn, sm: sm, showFn: showFn, quitFn: quitFn} s.server = &http.Server{ Handler: s.createHandler(), } @@ -172,6 +173,21 @@ func (s *serverImpl) createHandler() http.Handler { return tracks, nil })) + m.HandleFunc(RateCurrentTrackPath, func(w http.ResponseWriter, r *http.Request) { + v := r.URL.Query().Get("r") + if rating, err := strconv.Atoi(v); err == nil { + // convert to 0-5 range if needed + if rating > 5 { + rating = 5 + } else if rating < 0 { + rating = 0 + } + s.rateFn(rating) + s.writeOK(w) + } else { + s.writeErr(w, err) + } + }) return m }