diff --git a/Makefile b/Makefile index d2140b6..d0c244d 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,9 @@ build: - go build -ldflags="-X 'git.asdf.cafe/abs3nt/gspot/src/components/cli.Version=$(shell git show -s --date=short --pretty='format:%h (%ad)' HEAD)'" -o dist/ . + go build -ldflags="-X 'git.asdf.cafe/abs3nt/gspot/src/components/cli.Version=$(shell git show -s --date=short --pretty='format:%h (%ad)' HEAD)'" -o dist/ ./cmd/gspot + go build -o dist/ ./cmd/gspot-daemon + +rundaemon: build + ./dist/gspot-daemon run: build ./dist/gspot @@ -12,10 +16,12 @@ clean: uninstall: rm -f /usr/bin/gspot + rm -f /usr/bin/gspot-daemon rm -f /usr/share/zsh/site-functions/_gspot rm -f /usr/share/bash-completion/completions/gspot install: cp ./dist/gspot /usr/bin + cp ./dist/gspot-daemon /usr/bin cp ./completions/_gspot /usr/share/zsh/site-functions/_gspot cp ./completions/gspot /usr/share/bash-completion/completionsgspotg diff --git a/src/components/cli/cli.go b/src/components/cli/cli.go index e831d4e..054d1d6 100644 --- a/src/components/cli/cli.go +++ b/src/components/cli/cli.go @@ -13,6 +13,7 @@ import ( "go.uber.org/fx" "git.asdf.cafe/abs3nt/gspot/src/components/commands" + "git.asdf.cafe/abs3nt/gspot/src/components/daemon" "git.asdf.cafe/abs3nt/gspot/src/components/tui" "git.asdf.cafe/abs3nt/gspot/src/components/tuitview" ) @@ -39,7 +40,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return sendCommandRPC("Play", "hello") + return sendCommandRPC("Play", daemon.PlayArgs{}) }, Category: "Playback", }, @@ -55,7 +56,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.NArg() > 1 { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.PlayURL(cmd.Args().First()) + return sendCommandRPC("PlayURL", daemon.PlayURLArgs{URL: cmd.Args().First()}) }, Category: "Playback", }, @@ -67,7 +68,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.Pause() + return sendCommandRPC("Pause", daemon.PauseArgs{}) }, Category: "Playback", }, @@ -79,7 +80,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.TogglePlay() + return sendCommandRPC("TogglePlay", daemon.TogglePlayArgs{}) }, Category: "Playback", }, @@ -91,7 +92,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.PrintLink() + return sendCommandRPC("PrintLink", daemon.LinkArgs{}) }, Category: "Sharing", }, @@ -103,7 +104,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.PrintLinkContext() + return sendCommandRPC("PrintLinkContext", daemon.LinkContextArgs{}) }, Category: "Sharing", }, @@ -115,7 +116,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.PrintYoutubeLink() + return sendCommandRPC("PrintYoutubeLink", daemon.YoutubeLinkArgs{}) }, Category: "Sharing", }, @@ -128,14 +129,15 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.NArg() > 1 { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } + amount := 1 if cmd.NArg() > 0 { amt, err := strconv.Atoi(cmd.Args().First()) if err != nil { return err } - return c.Next(amt, false) + amount = amt } - return c.Next(1, false) + return sendCommandRPC("Next", daemon.NextArgs{Amount: amount}) }, Category: "Playback", }, @@ -147,7 +149,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.Previous() + return sendCommandRPC("Previous", daemon.PreviousArgs{}) }, Category: "Playback", }, @@ -159,7 +161,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.Like() + return sendCommandRPC("Like", daemon.LikeArgs{}) }, Category: "Library Management", }, @@ -171,7 +173,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.UnLike() + return sendCommandRPC("UnLike", daemon.UnlikeArgs{}) }, Category: "Library Management", }, @@ -191,7 +193,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.NowPlaying(cmd.Bool("force")) + return sendCommandRPC("NowPlaying", daemon.NowPlayingArgs{Force: cmd.Bool("force")}) }, Category: "Info", }, @@ -213,7 +215,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if err != nil { return err } - return c.ChangeVolume(amt) + return sendCommandRPC("ChangeVolume", daemon.VolumeArgs{Amount: amt}) }, }, { @@ -229,7 +231,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if err != nil { return err } - return c.ChangeVolume(-amt) + return sendCommandRPC("ChangeVolume", daemon.VolumeArgs{Amount: -amt}) }, }, { @@ -240,7 +242,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.Mute() + return sendCommandRPC("Mute", daemon.MuteArgs{}) }, }, { @@ -251,7 +253,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.UnMute() + return sendCommandRPC("UnMute", daemon.UnmuteArgs{}) }, }, { @@ -262,7 +264,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.ToggleMute() + return sendCommandRPC("ToggleMute", daemon.ToggleMuteArgs{}) }, }, }, @@ -281,7 +283,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.NArg() > 1 { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.DownloadCover(cmd.Args().First()) + return sendCommandRPC("DownloadCover", daemon.DownloadCoverArgs{Path: cmd.Args().First()}) }, Category: "Info", }, @@ -293,7 +295,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.Radio() + return sendCommandRPC("Radio", daemon.RadioArgs{}) }, Category: "Radio", }, @@ -305,7 +307,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.ClearRadio() + return sendCommandRPC("ClearRadio", daemon.ClearRadioArgs{}) }, Category: "Radio", }, @@ -317,7 +319,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.RefillRadio() + return sendCommandRPC("RefillRadio", daemon.RefillRadioArgs{}) }, Category: "Radio", }, @@ -328,7 +330,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.Status() + return sendCommandRPC("Status", daemon.StatusArgs{}) }, Category: "Info", }, @@ -340,7 +342,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.ListDevices() + return sendCommandRPC("ListDevices", daemon.ListDevicesArgs{}) }, Category: "Info", }, @@ -355,7 +357,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.NArg() > 1 { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.SetDevice(spotify.ID(cmd.Args().First())) + return sendCommandRPC("SetDevice", daemon.SetDeviceArgs{DeviceID: spotify.ID(cmd.Args().First())}) }, Category: "Playback", }, @@ -366,7 +368,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.Repeat() + return sendCommandRPC("Repeat", daemon.RepeatArgs{}) }, Category: "Playback", }, @@ -377,7 +379,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.Shuffle() + return sendCommandRPC("Shuffle", daemon.ShuffleArgs{}) }, Category: "Playback", }, @@ -415,7 +417,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if err != nil { return err } - return c.SetPosition(pos) + return sendCommandRPC("SetPosition", daemon.SetPositionArgs{Position: pos}) }, Commands: []*cli.Command{ { @@ -426,7 +428,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.Seek(true) + return sendCommandRPC("Seek", daemon.SeekArgs{Fwd: true}) }, }, { @@ -437,7 +439,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) { if cmd.Args().Present() { return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " ")) } - return c.Seek(false) + return sendCommandRPC("Seek", daemon.SeekArgs{Fwd: false}) }, }, }, @@ -451,10 +453,6 @@ func Run(c *commands.Commander, s fx.Shutdowner) { s.Shutdown() } -type GenericReply struct { - Message string -} - func sendCommandRPC(method string, args interface{}) error { client, err := rpc.Dial("unix", "/tmp/gspot.sock") if err != nil { @@ -468,6 +466,9 @@ func sendCommandRPC(method string, args interface{}) error { return fmt.Errorf("error calling %s: %v", method, err) } - fmt.Println(reply) + if reply != "" { + fmt.Println(reply) + } + return nil } diff --git a/src/components/commands/devices.go b/src/components/commands/devices.go index b045b47..acbfd76 100644 --- a/src/components/commands/devices.go +++ b/src/components/commands/devices.go @@ -9,21 +9,16 @@ import ( "github.com/zmb3/spotify/v2" ) -func (c *Commander) ListDevices() error { +func (c *Commander) ListDevices() (string, error) { devices, err := c.Client().PlayerDevices(c.Context) if err != nil { - return err + return "", err } - return PrintDevices(devices) -} - -func PrintDevices(devices []spotify.PlayerDevice) error { out, err := json.MarshalIndent(devices, "", " ") if err != nil { - return err + return "", err } - fmt.Println(string(out)) - return nil + return string(out), nil } func (c *Commander) SetDevice(device spotify.ID) error { diff --git a/src/components/commands/link.go b/src/components/commands/link.go index 8ca483e..6d86616 100644 --- a/src/components/commands/link.go +++ b/src/components/commands/link.go @@ -1,21 +1,17 @@ package commands -import "fmt" - -func (c *Commander) PrintLink() error { +func (c *Commander) PrintLink() (string, error) { state, err := c.Client().PlayerState(c.Context) if err != nil { - return err + return "", err } - fmt.Println(state.Item.ExternalURLs["spotify"]) - return nil + return state.Item.ExternalURLs["spotify"], nil } -func (c *Commander) PrintLinkContext() error { +func (c *Commander) PrintLinkContext() (string, error) { state, err := c.Client().PlayerState(c.Context) if err != nil { - return err + return "", err } - fmt.Println(state.PlaybackContext.ExternalURLs["spotify"]) - return nil + return state.PlaybackContext.ExternalURLs["spotify"], nil } diff --git a/src/components/commands/nowPlaying.go b/src/components/commands/nowPlaying.go index 94c6461..fe4fe26 100644 --- a/src/components/commands/nowPlaying.go +++ b/src/components/commands/nowPlaying.go @@ -7,16 +7,15 @@ import ( "github.com/zmb3/spotify/v2" ) -func (c *Commander) NowPlaying(force bool) error { +func (c *Commander) NowPlaying(force bool) (string, error) { if force { current, err := c.Client().PlayerCurrentlyPlaying(c.Context) if err != nil { - return err + return "", err } str := FormatSong(current) - fmt.Println(str) - _, err = c.Cache.Put("now_playing", str, 5*time.Second) - return err + go c.Cache.Put("now_playing", str, 5*time.Second) + return str, nil } song, err := c.Cache.GetOrDo("now_playing", func() (string, error) { current, err := c.Client().PlayerCurrentlyPlaying(c.Context) @@ -27,10 +26,9 @@ func (c *Commander) NowPlaying(force bool) error { return str, nil }, 5*time.Second) if err != nil { - return err + return "", err } - fmt.Println(song) - return nil + return song, nil } func FormatSong(current *spotify.CurrentlyPlaying) string { diff --git a/src/components/commands/status.go b/src/components/commands/status.go index ebd80a7..50a30b4 100644 --- a/src/components/commands/status.go +++ b/src/components/commands/status.go @@ -2,13 +2,12 @@ package commands import ( "encoding/json" - "fmt" "time" "github.com/zmb3/spotify/v2" ) -func (c *Commander) Status() error { +func (c *Commander) Status() (string, error) { state, err := c.Cache.GetOrDo("state", func() (string, error) { state, err := c.Client().PlayerState(c.Context) if err != nil { @@ -21,10 +20,9 @@ func (c *Commander) Status() error { return str, nil }, 5*time.Second) if err != nil { - return err + return "", err } - fmt.Println(state) - return nil + return state, nil } func (c *Commander) FormatState(state *spotify.PlayerState) (string, error) { diff --git a/src/components/commands/youtube-link.go b/src/components/commands/youtube-link.go index e95b0ab..782737f 100644 --- a/src/components/commands/youtube-link.go +++ b/src/components/commands/youtube-link.go @@ -1,17 +1,14 @@ package commands import ( - "fmt" - "git.asdf.cafe/abs3nt/gspot/src/components/youtube" ) -func (c *Commander) PrintYoutubeLink() error { +func (c *Commander) PrintYoutubeLink() (string, error) { state, err := c.Client().PlayerState(c.Context) if err != nil { - return err + return "", err } link := youtube.Search(state.Item.Artists[0].Name + state.Item.Name) - fmt.Println(link) - return nil + return link, nil } diff --git a/src/components/daemon/handler.go b/src/components/daemon/handler.go index 2603fad..312f5cc 100644 --- a/src/components/daemon/handler.go +++ b/src/components/daemon/handler.go @@ -1,13 +1,200 @@ package daemon -import "git.asdf.cafe/abs3nt/gspot/src/components/commands" +import ( + "git.asdf.cafe/abs3nt/gspot/src/components/commands" + "github.com/zmb3/spotify/v2" +) type Handler struct { Commander *commands.Commander } -func (h *Handler) Play(args string, reply *string) error { - err := h.Commander.Play() - *reply = "hello fucker" +type PlayArgs struct{} + +func (h *Handler) Play(args *PlayArgs, reply *string) error { + return h.Commander.Play() +} + +type PlayURLArgs struct { + URL string +} + +func (h *Handler) PlayURL(args *PlayURLArgs, reply *string) error { + return h.Commander.PlayURL(args.URL) +} + +type PauseArgs struct{} + +func (h *Handler) Pause(args *PauseArgs, reply *string) error { + return h.Commander.Pause() +} + +type TogglePlayArgs struct{} + +func (h *Handler) TogglePlay(args *TogglePlayArgs, reply *string) error { + return h.Commander.TogglePlay() +} + +type LinkArgs struct{} + +func (h *Handler) Link(args *LinkArgs, reply *string) error { + link, err := h.Commander.PrintLink() + *reply = link return err } + +type LinkContextArgs struct{} + +func (h *Handler) LinkContext(args *LinkContextArgs, reply *string) error { + link, err := h.Commander.PrintLinkContext() + *reply = link + return err +} + +type YoutubeLinkArgs struct{} + +func (h *Handler) YoutubeLink(args *YoutubeLinkArgs, reply *string) error { + link, err := h.Commander.PrintYoutubeLink() + *reply = link + return err +} + +type NextArgs struct { + Amount int +} + +func (h *Handler) Next(args *NextArgs, reply *string) error { + return h.Commander.Next(args.Amount, false) +} + +type PreviousArgs struct{} + +func (h *Handler) Previous(args *PreviousArgs, reply *string) error { + return h.Commander.Previous() +} + +type LikeArgs struct{} + +func (h *Handler) Like(args *LikeArgs, reply *string) error { + return h.Commander.Like() +} + +type UnlikeArgs struct{} + +func (h *Handler) Unlike(args *UnlikeArgs, reply *string) error { + return h.Commander.UnLike() +} + +type NowPlayingArgs struct { + Force bool +} + +func (h *Handler) NowPlaying(args *NowPlayingArgs, reply *string) error { + resp, err := h.Commander.NowPlaying(args.Force) + *reply = resp + return err +} + +type VolumeArgs struct { + Amount int +} + +func (h *Handler) ChangeVolume(args *VolumeArgs, reply *string) error { + return h.Commander.ChangeVolume(args.Amount) +} + +type MuteArgs struct{} + +func (h *Handler) Mute(args *MuteArgs, reply *string) error { + return h.Commander.Mute() +} + +type UnmuteArgs struct{} + +func (h *Handler) Unmute(args *UnmuteArgs, reply *string) error { + return h.Commander.UnMute() +} + +type ToggleMuteArgs struct{} + +func (h *Handler) ToggleMute(args *ToggleMuteArgs, reply *string) error { + return h.Commander.ToggleMute() +} + +type DownloadCoverArgs struct { + Path string +} + +func (h *Handler) DownloadCover(args *DownloadCoverArgs, reply *string) error { + return h.Commander.DownloadCover(args.Path) +} + +type RadioArgs struct{} + +func (h *Handler) Radio(args *RadioArgs, reply *string) error { + return h.Commander.Radio() +} + +type ClearRadioArgs struct{} + +func (h *Handler) ClearRadio(args *ClearRadioArgs, reply *string) error { + return h.Commander.ClearRadio() +} + +type RefillRadioArgs struct{} + +func (h *Handler) RefillRadio(args *RefillRadioArgs, reply *string) error { + return h.Commander.RefillRadio() +} + +type StatusArgs struct{} + +func (h *Handler) Status(args *StatusArgs, reply *string) error { + status, err := h.Commander.Status() + *reply = status + return err +} + +type ListDevicesArgs struct{} + +func (h *Handler) Devices(args *ListDevicesArgs, reply *string) error { + devices, err := h.Commander.ListDevices() + *reply = devices + return err +} + +type SetDeviceArgs struct { + DeviceID spotify.ID +} + +func (h *Handler) SetDevice(args *SetDeviceArgs, reply *string) error { + return h.Commander.SetDevice(args.DeviceID) +} + +type RepeatArgs struct{} + +func (h *Handler) Repeat(args *RepeatArgs, reply *string) error { + return h.Commander.Repeat() +} + +type ShuffleArgs struct{} + +func (h *Handler) Shuffle(args *ShuffleArgs, reply *string) error { + return h.Commander.Shuffle() +} + +type SetPositionArgs struct { + Position int +} + +func (h *Handler) SetPosition(args *SetPositionArgs, reply *string) error { + return h.Commander.SetPosition(args.Position) +} + +type SeekArgs struct { + Fwd bool +} + +func (h *Handler) Seek(args *SeekArgs, reply *string) error { + return h.Commander.Seek(args.Fwd) +}