Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
017c1de197 | |||
d63d5ac778 | |||
785df8ee46 | |||
88af3135fc | |||
41b6637ede | |||
900670add0 |
8
Makefile
8
Makefile
@ -1,5 +1,9 @@
|
|||||||
build:
|
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
|
run: build
|
||||||
./dist/gspot
|
./dist/gspot
|
||||||
@ -12,10 +16,12 @@ clean:
|
|||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f /usr/bin/gspot
|
rm -f /usr/bin/gspot
|
||||||
|
rm -f /usr/bin/gspot-daemon
|
||||||
rm -f /usr/share/zsh/site-functions/_gspot
|
rm -f /usr/share/zsh/site-functions/_gspot
|
||||||
rm -f /usr/share/bash-completion/completions/gspot
|
rm -f /usr/share/bash-completion/completions/gspot
|
||||||
|
|
||||||
install:
|
install:
|
||||||
cp ./dist/gspot /usr/bin
|
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/zsh/site-functions/_gspot
|
||||||
cp ./completions/gspot /usr/share/bash-completion/completionsgspotg
|
cp ./completions/gspot /usr/share/bash-completion/completionsgspotg
|
||||||
|
@ -10,8 +10,8 @@ import (
|
|||||||
"go.uber.org/fx/fxevent"
|
"go.uber.org/fx/fxevent"
|
||||||
|
|
||||||
"git.asdf.cafe/abs3nt/gspot/src/components/cache"
|
"git.asdf.cafe/abs3nt/gspot/src/components/cache"
|
||||||
"git.asdf.cafe/abs3nt/gspot/src/components/cli"
|
|
||||||
"git.asdf.cafe/abs3nt/gspot/src/components/commands"
|
"git.asdf.cafe/abs3nt/gspot/src/components/commands"
|
||||||
|
"git.asdf.cafe/abs3nt/gspot/src/components/daemon"
|
||||||
"git.asdf.cafe/abs3nt/gspot/src/components/logger"
|
"git.asdf.cafe/abs3nt/gspot/src/components/logger"
|
||||||
"git.asdf.cafe/abs3nt/gspot/src/services"
|
"git.asdf.cafe/abs3nt/gspot/src/services"
|
||||||
)
|
)
|
||||||
@ -33,7 +33,7 @@ func main() {
|
|||||||
logger.NewLogger,
|
logger.NewLogger,
|
||||||
),
|
),
|
||||||
fx.Invoke(
|
fx.Invoke(
|
||||||
cli.Run,
|
daemon.Run,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
app.Run()
|
app.Run()
|
@ -3,6 +3,7 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/rpc"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -12,6 +13,7 @@ import (
|
|||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
|
||||||
"git.asdf.cafe/abs3nt/gspot/src/components/commands"
|
"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/tui"
|
||||||
"git.asdf.cafe/abs3nt/gspot/src/components/tuitview"
|
"git.asdf.cafe/abs3nt/gspot/src/components/tuitview"
|
||||||
)
|
)
|
||||||
@ -38,7 +40,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.Play()
|
return sendCommandRPC("Play", daemon.PlayArgs{})
|
||||||
},
|
},
|
||||||
Category: "Playback",
|
Category: "Playback",
|
||||||
},
|
},
|
||||||
@ -54,7 +56,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.NArg() > 1 {
|
if cmd.NArg() > 1 {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
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",
|
Category: "Playback",
|
||||||
},
|
},
|
||||||
@ -66,7 +68,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.Pause()
|
return sendCommandRPC("Pause", daemon.PauseArgs{})
|
||||||
},
|
},
|
||||||
Category: "Playback",
|
Category: "Playback",
|
||||||
},
|
},
|
||||||
@ -78,7 +80,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.TogglePlay()
|
return sendCommandRPC("TogglePlay", daemon.TogglePlayArgs{})
|
||||||
},
|
},
|
||||||
Category: "Playback",
|
Category: "Playback",
|
||||||
},
|
},
|
||||||
@ -90,7 +92,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.PrintLink()
|
return sendCommandRPC("Link", daemon.LinkArgs{})
|
||||||
},
|
},
|
||||||
Category: "Sharing",
|
Category: "Sharing",
|
||||||
},
|
},
|
||||||
@ -102,7 +104,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.PrintLinkContext()
|
return sendCommandRPC("LinkContext", daemon.LinkContextArgs{})
|
||||||
},
|
},
|
||||||
Category: "Sharing",
|
Category: "Sharing",
|
||||||
},
|
},
|
||||||
@ -114,7 +116,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.PrintYoutubeLink()
|
return sendCommandRPC("YoutubeLink", daemon.YoutubeLinkArgs{})
|
||||||
},
|
},
|
||||||
Category: "Sharing",
|
Category: "Sharing",
|
||||||
},
|
},
|
||||||
@ -127,14 +129,15 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.NArg() > 1 {
|
if cmd.NArg() > 1 {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
|
amount := 1
|
||||||
if cmd.NArg() > 0 {
|
if cmd.NArg() > 0 {
|
||||||
amt, err := strconv.Atoi(cmd.Args().First())
|
amt, err := strconv.Atoi(cmd.Args().First())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return c.Next(amt, false)
|
amount = amt
|
||||||
}
|
}
|
||||||
return c.Next(1, false)
|
return sendCommandRPC("Next", daemon.NextArgs{Amount: amount})
|
||||||
},
|
},
|
||||||
Category: "Playback",
|
Category: "Playback",
|
||||||
},
|
},
|
||||||
@ -146,7 +149,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.Previous()
|
return sendCommandRPC("Previous", daemon.PreviousArgs{})
|
||||||
},
|
},
|
||||||
Category: "Playback",
|
Category: "Playback",
|
||||||
},
|
},
|
||||||
@ -158,7 +161,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.Like()
|
return sendCommandRPC("Like", daemon.LikeArgs{})
|
||||||
},
|
},
|
||||||
Category: "Library Management",
|
Category: "Library Management",
|
||||||
},
|
},
|
||||||
@ -170,7 +173,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.UnLike()
|
return sendCommandRPC("UnLike", daemon.UnlikeArgs{})
|
||||||
},
|
},
|
||||||
Category: "Library Management",
|
Category: "Library Management",
|
||||||
},
|
},
|
||||||
@ -190,7 +193,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
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",
|
Category: "Info",
|
||||||
},
|
},
|
||||||
@ -212,7 +215,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return c.ChangeVolume(amt)
|
return sendCommandRPC("ChangeVolume", daemon.VolumeArgs{Amount: amt})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -228,7 +231,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return c.ChangeVolume(-amt)
|
return sendCommandRPC("ChangeVolume", daemon.VolumeArgs{Amount: -amt})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -239,7 +242,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.Mute()
|
return sendCommandRPC("Mute", daemon.MuteArgs{})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -250,7 +253,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.UnMute()
|
return sendCommandRPC("UnMute", daemon.UnmuteArgs{})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -261,7 +264,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.ToggleMute()
|
return sendCommandRPC("ToggleMute", daemon.ToggleMuteArgs{})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -280,7 +283,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.NArg() > 1 {
|
if cmd.NArg() > 1 {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
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",
|
Category: "Info",
|
||||||
},
|
},
|
||||||
@ -292,7 +295,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.Radio()
|
return sendCommandRPC("Radio", daemon.RadioArgs{})
|
||||||
},
|
},
|
||||||
Category: "Radio",
|
Category: "Radio",
|
||||||
},
|
},
|
||||||
@ -304,7 +307,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.ClearRadio()
|
return sendCommandRPC("ClearRadio", daemon.ClearRadioArgs{})
|
||||||
},
|
},
|
||||||
Category: "Radio",
|
Category: "Radio",
|
||||||
},
|
},
|
||||||
@ -316,7 +319,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.RefillRadio()
|
return sendCommandRPC("RefillRadio", daemon.RefillRadioArgs{})
|
||||||
},
|
},
|
||||||
Category: "Radio",
|
Category: "Radio",
|
||||||
},
|
},
|
||||||
@ -327,7 +330,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.Status()
|
return sendCommandRPC("Status", daemon.StatusArgs{})
|
||||||
},
|
},
|
||||||
Category: "Info",
|
Category: "Info",
|
||||||
},
|
},
|
||||||
@ -339,7 +342,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.ListDevices()
|
return sendCommandRPC("Devices", daemon.ListDevicesArgs{})
|
||||||
},
|
},
|
||||||
Category: "Info",
|
Category: "Info",
|
||||||
},
|
},
|
||||||
@ -354,7 +357,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.NArg() > 1 {
|
if cmd.NArg() > 1 {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
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",
|
Category: "Playback",
|
||||||
},
|
},
|
||||||
@ -365,7 +368,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.Repeat()
|
return sendCommandRPC("Repeat", daemon.RepeatArgs{})
|
||||||
},
|
},
|
||||||
Category: "Playback",
|
Category: "Playback",
|
||||||
},
|
},
|
||||||
@ -376,7 +379,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.Shuffle()
|
return sendCommandRPC("Shuffle", daemon.ShuffleArgs{})
|
||||||
},
|
},
|
||||||
Category: "Playback",
|
Category: "Playback",
|
||||||
},
|
},
|
||||||
@ -414,7 +417,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return c.SetPosition(pos)
|
return sendCommandRPC("SetPosition", daemon.SetPositionArgs{Position: pos})
|
||||||
},
|
},
|
||||||
Commands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
{
|
{
|
||||||
@ -425,7 +428,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.Seek(true)
|
return sendCommandRPC("Seek", daemon.SeekArgs{Fwd: true})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -436,7 +439,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
if cmd.Args().Present() {
|
if cmd.Args().Present() {
|
||||||
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
return fmt.Errorf("unexpected arguments: %s", strings.Join(cmd.Args().Slice(), " "))
|
||||||
}
|
}
|
||||||
return c.Seek(false)
|
return sendCommandRPC("Seek", daemon.SeekArgs{Fwd: false})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -449,3 +452,23 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
}
|
}
|
||||||
s.Shutdown()
|
s.Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sendCommandRPC(method string, args interface{}) error {
|
||||||
|
client, err := rpc.Dial("unix", "/tmp/gspot.sock")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not connect to daemon: %v", err)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
var reply string
|
||||||
|
err = client.Call("Handler."+method, args, &reply)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error calling %s: %v", method, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reply != "" {
|
||||||
|
fmt.Println(reply)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -9,21 +9,16 @@ import (
|
|||||||
"github.com/zmb3/spotify/v2"
|
"github.com/zmb3/spotify/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Commander) ListDevices() error {
|
func (c *Commander) ListDevices() (string, error) {
|
||||||
devices, err := c.Client().PlayerDevices(c.Context)
|
devices, err := c.Client().PlayerDevices(c.Context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
return PrintDevices(devices)
|
|
||||||
}
|
|
||||||
|
|
||||||
func PrintDevices(devices []spotify.PlayerDevice) error {
|
|
||||||
out, err := json.MarshalIndent(devices, "", " ")
|
out, err := json.MarshalIndent(devices, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
fmt.Println(string(out))
|
return string(out), nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commander) SetDevice(device spotify.ID) error {
|
func (c *Commander) SetDevice(device spotify.ID) error {
|
||||||
|
@ -1,21 +1,17 @@
|
|||||||
package commands
|
package commands
|
||||||
|
|
||||||
import "fmt"
|
func (c *Commander) PrintLink() (string, error) {
|
||||||
|
|
||||||
func (c *Commander) PrintLink() error {
|
|
||||||
state, err := c.Client().PlayerState(c.Context)
|
state, err := c.Client().PlayerState(c.Context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
fmt.Println(state.Item.ExternalURLs["spotify"])
|
return state.Item.ExternalURLs["spotify"], nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commander) PrintLinkContext() error {
|
func (c *Commander) PrintLinkContext() (string, error) {
|
||||||
state, err := c.Client().PlayerState(c.Context)
|
state, err := c.Client().PlayerState(c.Context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
fmt.Println(state.PlaybackContext.ExternalURLs["spotify"])
|
return state.PlaybackContext.ExternalURLs["spotify"], nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,15 @@ import (
|
|||||||
"github.com/zmb3/spotify/v2"
|
"github.com/zmb3/spotify/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Commander) NowPlaying(force bool) error {
|
func (c *Commander) NowPlaying(force bool) (string, error) {
|
||||||
if force {
|
if force {
|
||||||
current, err := c.Client().PlayerCurrentlyPlaying(c.Context)
|
current, err := c.Client().PlayerCurrentlyPlaying(c.Context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
str := FormatSong(current)
|
str := FormatSong(current)
|
||||||
fmt.Println(str)
|
go c.Cache.Put("now_playing", str, 5*time.Second)
|
||||||
_, err = c.Cache.Put("now_playing", str, 5*time.Second)
|
return str, nil
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
song, err := c.Cache.GetOrDo("now_playing", func() (string, error) {
|
song, err := c.Cache.GetOrDo("now_playing", func() (string, error) {
|
||||||
current, err := c.Client().PlayerCurrentlyPlaying(c.Context)
|
current, err := c.Client().PlayerCurrentlyPlaying(c.Context)
|
||||||
@ -27,10 +26,9 @@ func (c *Commander) NowPlaying(force bool) error {
|
|||||||
return str, nil
|
return str, nil
|
||||||
}, 5*time.Second)
|
}, 5*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
fmt.Println(song)
|
return song, nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func FormatSong(current *spotify.CurrentlyPlaying) string {
|
func FormatSong(current *spotify.CurrentlyPlaying) string {
|
||||||
|
@ -2,13 +2,12 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/zmb3/spotify/v2"
|
"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.Cache.GetOrDo("state", func() (string, error) {
|
||||||
state, err := c.Client().PlayerState(c.Context)
|
state, err := c.Client().PlayerState(c.Context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -21,10 +20,9 @@ func (c *Commander) Status() error {
|
|||||||
return str, nil
|
return str, nil
|
||||||
}, 5*time.Second)
|
}, 5*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
fmt.Println(state)
|
return state, nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commander) FormatState(state *spotify.PlayerState) (string, error) {
|
func (c *Commander) FormatState(state *spotify.PlayerState) (string, error) {
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
package commands
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.asdf.cafe/abs3nt/gspot/src/components/youtube"
|
"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)
|
state, err := c.Client().PlayerState(c.Context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
link := youtube.Search(state.Item.Artists[0].Name + state.Item.Name)
|
link := youtube.Search(state.Item.Artists[0].Name + state.Item.Name)
|
||||||
fmt.Println(link)
|
return link, nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
74
src/components/daemon/daemon.go
Normal file
74
src/components/daemon/daemon.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/rpc"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/fx"
|
||||||
|
|
||||||
|
"git.asdf.cafe/abs3nt/gspot/src/components/commands"
|
||||||
|
"git.asdf.cafe/abs3nt/gspot/src/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Run(c *commands.Commander, conf *config.Config, s fx.Shutdowner) {
|
||||||
|
for {
|
||||||
|
err := startServer(c, conf)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Server error: %v", err)
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func startServer(c *commands.Commander, conf *config.Config) error {
|
||||||
|
socketPath := conf.SocketPath
|
||||||
|
|
||||||
|
if _, err := os.Stat(socketPath); err == nil {
|
||||||
|
if err := os.Remove(socketPath); err != nil {
|
||||||
|
return fmt.Errorf("failed to remove existing socket: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
commandHandler := &Handler{Commander: c}
|
||||||
|
server := rpc.NewServer()
|
||||||
|
if err := server.Register(commandHandler); err != nil {
|
||||||
|
return fmt.Errorf("failed to register RPC handler: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
listener, err := net.Listen("unix", socketPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("listen error: %w", err)
|
||||||
|
}
|
||||||
|
defer listener.Close()
|
||||||
|
|
||||||
|
if err := os.Chmod(socketPath, 0o666); err != nil {
|
||||||
|
return fmt.Errorf("failed to set socket permissions: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Daemon is listening on", socketPath)
|
||||||
|
|
||||||
|
for {
|
||||||
|
conn, err := listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Accept error:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
codec := NewLoggingServerCodec(conn)
|
||||||
|
go handleConnection(server, codec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleConnection(server *rpc.Server, codec rpc.ServerCodec) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
log.Printf("Recovered in handleConnection: %v", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
server.ServeCodec(codec)
|
||||||
|
}
|
200
src/components/daemon/handler.go
Normal file
200
src/components/daemon/handler.go
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.asdf.cafe/abs3nt/gspot/src/components/commands"
|
||||||
|
"github.com/zmb3/spotify/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
Commander *commands.Commander
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
84
src/components/daemon/logger.go
Normal file
84
src/components/daemon/logger.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/gob"
|
||||||
|
"io"
|
||||||
|
"log/slog"
|
||||||
|
"net/rpc"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
var logger *slog.Logger
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
handler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
|
||||||
|
Level: slog.LevelInfo,
|
||||||
|
})
|
||||||
|
logger = slog.New(handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoggingServerCodec struct {
|
||||||
|
dec *gob.Decoder
|
||||||
|
enc *gob.Encoder
|
||||||
|
c io.Closer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLoggingServerCodec(conn io.ReadWriteCloser) *LoggingServerCodec {
|
||||||
|
return &LoggingServerCodec{
|
||||||
|
dec: gob.NewDecoder(conn),
|
||||||
|
enc: gob.NewEncoder(conn),
|
||||||
|
c: conn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatBody(body interface{}) slog.Value {
|
||||||
|
if body == nil {
|
||||||
|
return slog.StringValue("null")
|
||||||
|
}
|
||||||
|
v := reflect.ValueOf(body)
|
||||||
|
if v.Kind() == reflect.Ptr && !v.IsNil() {
|
||||||
|
v = v.Elem()
|
||||||
|
body = v.Interface()
|
||||||
|
}
|
||||||
|
return slog.AnyValue(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LoggingServerCodec) ReadRequestHeader(r *rpc.Request) error {
|
||||||
|
err := c.dec.Decode(r)
|
||||||
|
if err == nil {
|
||||||
|
logger.Info("Received Request",
|
||||||
|
"ServiceMethod", r.ServiceMethod,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LoggingServerCodec) ReadRequestBody(body interface{}) error {
|
||||||
|
err := c.dec.Decode(body)
|
||||||
|
if err == nil {
|
||||||
|
logger.Info("Request Body",
|
||||||
|
"Body", formatBody(body),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LoggingServerCodec) WriteResponse(r *rpc.Response, body interface{}) error {
|
||||||
|
if err := c.enc.Encode(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.enc.Encode(body); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Info("Sent Response",
|
||||||
|
"ServiceMethod", r.ServiceMethod,
|
||||||
|
"Error", r.Error,
|
||||||
|
"Body", formatBody(body),
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LoggingServerCodec) Close() error {
|
||||||
|
return c.c.Close()
|
||||||
|
}
|
@ -7,4 +7,5 @@ type Config struct {
|
|||||||
Port string `yaml:"port"`
|
Port string `yaml:"port"`
|
||||||
LogLevel string `yaml:"log_level" default:"info"`
|
LogLevel string `yaml:"log_level" default:"info"`
|
||||||
LogOutput string `yaml:"log_output" default:"stdout"`
|
LogOutput string `yaml:"log_output" default:"stdout"`
|
||||||
|
SocketPath string `yaml:"socket_path" default:"/tmp/gspot.sock"`
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user