diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3884b73 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +mpc-extra diff --git a/cmd/current-rate.go b/cmd/current-rate.go new file mode 100644 index 0000000..5e2cbfa --- /dev/null +++ b/cmd/current-rate.go @@ -0,0 +1,58 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "errors" + "strconv" + + "codeberg.org/danjones000/mpc-extra/mpd" + "github.com/spf13/cobra" +) + +// rateCmd represents the rate command +var rateCmd = &cobra.Command{ + Use: "rate [rating]", + Short: "Rates the current playing song: 0-10", + /* + Long: `A longer description that spans multiple lines and likely contains examples + and usage of using your command. For example: + + Cobra is a CLI library for Go that empowers applications. + This application is a tool to generate the needed files + to quickly create a Cobra application.`, + */ + Args: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return errors.New("Missing rating") + } + num, err := strconv.Atoi(args[0]) + if err != nil { + return err + } + if num < 0 || num > 10 { + return errors.New("Rating must be between zero and ten") + } + return nil + }, + Run: func(cmd *cobra.Command, args []string) { + curr, _ := mpd.GetCurrent() + curr.AddSticker("rating", args[0]) + curr.PrintAll(true) + }, +} + +func init() { + currentCmd.AddCommand(rateCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // rateCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // rateCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/current-sticker.go b/cmd/current-sticker.go new file mode 100644 index 0000000..fa08623 --- /dev/null +++ b/cmd/current-sticker.go @@ -0,0 +1,51 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "codeberg.org/danjones000/mpc-extra/mpd" + "github.com/spf13/cobra" +) + +// stickerCmd represents the sticker command +var currStickerCmd = &cobra.Command{ + Use: "sticker name value", + Args: cobra.MinimumNArgs(2), + Short: "Adds a sticker to the current song", + /* + Long: `A longer description that spans multiple lines and likely contains examples + and usage of using your command. For example: + + Cobra is a CLI library for Go that empowers applications. + This application is a tool to generate the needed files + to quickly create a Cobra application.`, + */ + RunE: func(cmd *cobra.Command, args []string) error { + name := args[0] + if name == "rating" { + root := cmd.Root() + root.SetArgs([]string{"current", "rate", "--", args[1]}) + root.TraverseChildren = false + return root.Execute() + } + curr, _ := mpd.GetCurrent() + curr.AddSticker(name, args[1]) + curr.PrintAll(true) + return nil + }, +} + +func init() { + currentCmd.AddCommand(currStickerCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // stickerCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // stickerCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/current.go b/cmd/current.go index 5af596c..2b218ca 100644 --- a/cmd/current.go +++ b/cmd/current.go @@ -4,28 +4,25 @@ Copyright © 2023 NAME HERE package cmd import ( - "fmt" - - "codeberg.org/danjones000/mpc-plus/mpd" + "codeberg.org/danjones000/mpc-extra/mpd" "github.com/spf13/cobra" ) // currentCmd represents the current command var currentCmd = &cobra.Command{ Use: "current", - Short: "A brief description of your command", - Long: `A longer description that spans multiple lines and likely contains examples -and usage of using your command. For example: + Short: "Shows information about the currently playing song", + /* + Long: `A longer description that spans multiple lines and likely contains examples + and usage of using your command. For example: -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, + Cobra is a CLI library for Go that empowers applications. + This application is a tool to generate the needed files + to quickly create a Cobra application.`, + */ Run: func(cmd *cobra.Command, args []string) { - conn, _ := mpd.GetConn() - curr, _ := conn.CurrentSong() - for k, v := range curr { - fmt.Println(k, ":", v) - } + curr, _ := mpd.GetCurrent() + curr.PrintAll(true) }, } diff --git a/cmd/find-sticker.go b/cmd/find-sticker.go new file mode 100644 index 0000000..b9bb984 --- /dev/null +++ b/cmd/find-sticker.go @@ -0,0 +1,47 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "fmt" + + "codeberg.org/danjones000/mpc-extra/mpd" + "github.com/spf13/cobra" +) + +// stickerCmd represents the sticker command +var stickerCmd = &cobra.Command{ + Use: "sticker [sticker-name]", + Args: cobra.MinimumNArgs(1), + Short: "A brief description of your command", + /* + Long: `A longer description that spans multiple lines and likely contains examples + and usage of using your command. For example: + + Cobra is a CLI library for Go that empowers applications. + This application is a tool to generate the needed files + to quickly create a Cobra application.`, + */ + Run: func(cmd *cobra.Command, args []string) { + name := args[0] + songs, _ := mpd.StickerFind(name) + for _, song := range songs { + fmt.Println(song.Path, name, ":", song.GetSticker(name)) + } + }, +} + +func init() { + findCmd.AddCommand(stickerCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // stickerCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // stickerCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/find.go b/cmd/find.go new file mode 100644 index 0000000..90d8500 --- /dev/null +++ b/cmd/find.go @@ -0,0 +1,47 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "fmt" + + "codeberg.org/danjones000/mpc-extra/mpd" + "github.com/spf13/cobra" +) + +// findCmd represents the find command +var findCmd = &cobra.Command{ + Use: "find", + Short: "A brief description of your command", + /* + Long: `A longer description that spans multiple lines and likely contains examples + and usage of using your command. For example: + + Cobra is a CLI library for Go that empowers applications. + + This application is a tool to generate the needed files + to quickly create a Cobra application.`, + */ + Run: func(cmd *cobra.Command, args []string) { + ret, _ := mpd.Find(args...) + for _, song := range ret { + song.PrintAll(false) + fmt.Println("-------") + } + }, +} + +func init() { + rootCmd.AddCommand(findCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // findCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // findCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/rate-skip.go b/cmd/rate-skip.go new file mode 100644 index 0000000..097d946 --- /dev/null +++ b/cmd/rate-skip.go @@ -0,0 +1,31 @@ +/* +Copyright © 2023 Dan Jones +*/ +package cmd + +import ( + "codeberg.org/danjones000/mpc-extra/mpd" + "github.com/spf13/cobra" +) + +// rateSkipCmd represents the rate-skip command +var rateSkipCmd = &cobra.Command{ + Use: "rate-skip [rating]", + Args: cobra.MinimumNArgs(1), + Short: "Rate the current song, and skip to the next", + RunE: func(cmd *cobra.Command, args []string) error { + root := cmd.Root() + root.SetArgs([]string{"current", "rate", "--", args[0]}) + root.TraverseChildren = false + err := root.Execute() + if err != nil { + return err + } + + return mpd.Next() + }, +} + +func init() { + rootCmd.AddCommand(rateSkipCmd) +} diff --git a/cmd/root.go b/cmd/root.go index 371cda9..a569232 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -14,7 +14,7 @@ import ( // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ - Use: "mpc-plus", + Use: "mpc-extra", Short: "A brief description of your application", Long: `A longer description that spans multiple lines and likely contains examples and usage of using your application. For example: @@ -41,7 +41,7 @@ func init() { // Cobra supports persistent flags, which, if defined here, // will be global for your application. - // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.mpc-plus.yaml)") + // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.mpc-extra.yaml)") // Cobra also supports local flags, which will only run // when this action is called directly. diff --git a/go.mod b/go.mod index 18f7c1a..f94f952 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,9 @@ -module codeberg.org/danjones000/mpc-plus +module codeberg.org/danjones000/mpc-extra go 1.20 require ( + github.com/akrennmair/slice v0.0.0-20220105203817-49445747ab81 github.com/fhs/gompd/v2 v2.3.0 github.com/spf13/cobra v1.7.0 ) diff --git a/go.sum b/go.sum index b6552d2..543371f 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,18 @@ +github.com/akrennmair/slice v0.0.0-20220105203817-49445747ab81 h1:HnuAxArB0uUxqjRvZdjhBxE3uPXNeJvNNbuaV4QhHMU= +github.com/akrennmair/slice v0.0.0-20220105203817-49445747ab81/go.mod h1:jk5mJ+KFznfxbCEsOPgmJkozvBfVGeaqIMs31NhXlv0= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/fhs/gompd/v2 v2.3.0 h1:wuruUjmOODRlJhrYx73rJnzS7vTSXSU7pWmZtM3VPE0= github.com/fhs/gompd/v2 v2.3.0/go.mod h1:nNdZtcpD5VpmzZbRl5rV6RhxeMmAWTxEsSIMBkmMIy4= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index afc80a2..7f885b5 100644 --- a/main.go +++ b/main.go @@ -4,8 +4,8 @@ Copyright © 2023 NAME HERE package main import ( - "codeberg.org/danjones000/mpc-plus/cmd" - "codeberg.org/danjones000/mpc-plus/mpd" + "codeberg.org/danjones000/mpc-extra/cmd" + "codeberg.org/danjones000/mpc-extra/mpd" ) func main() { diff --git a/mpd/conn.go b/mpd/conn.go index 6b46242..bb60faa 100644 --- a/mpd/conn.go +++ b/mpd/conn.go @@ -1,8 +1,6 @@ package mpd -import ( - "github.com/fhs/gompd/v2/mpd" -) +import "github.com/fhs/gompd/v2/mpd" var conn *mpd.Client var connerror error @@ -22,3 +20,17 @@ func CloseConn() error { } return conn.Close() } + +func Next() error { + if connerror != nil { + return connerror + } + return conn.Next() +} + +func Previous() error { + if connerror != nil { + return connerror + } + return conn.Previous() +} diff --git a/mpd/current.go b/mpd/current.go new file mode 100644 index 0000000..d6f7237 --- /dev/null +++ b/mpd/current.go @@ -0,0 +1,13 @@ +package mpd + +func GetCurrent() (*Song, error) { + if connerror != nil { + return nil, connerror + } + curr, err := conn.CurrentSong() + if err != nil { + return nil, err + } + + return newSong(curr), nil +} diff --git a/mpd/find.go b/mpd/find.go new file mode 100644 index 0000000..9729bc1 --- /dev/null +++ b/mpd/find.go @@ -0,0 +1,16 @@ +package mpd + +import "github.com/akrennmair/slice" + +func Find(args ...string) ([]*Song, error) { + if connerror != nil { + return nil, connerror + } + + songs, err := conn.Search(args...) + if err != nil { + return nil, err + } + + return slice.Map(songs, newSong), nil +} diff --git a/mpd/song.go b/mpd/song.go new file mode 100644 index 0000000..0e4cf5c --- /dev/null +++ b/mpd/song.go @@ -0,0 +1,85 @@ +package mpd + +import ( + "fmt" + "github.com/akrennmair/slice" + "github.com/fhs/gompd/v2/mpd" +) + +type Song struct { + Path string + Attrs mpd.Attrs + stickers []mpd.Sticker + // @todo refactor as a map so there's no dupes +} + +func newSong(attrs mpd.Attrs) *Song { + return &Song{ + Path: attrs["file"], + Attrs: attrs, + } +} + +func (s *Song) GetStickers() ([]mpd.Sticker, error) { + if s.stickers != nil { + return s.stickers, nil + } + + if connerror != nil { + return nil, connerror + } + + sticks, err := StickersGetFor(s.Path) + s.stickers = sticks + + return s.stickers, err +} + +func (s *Song) PrintAll(withStickers bool) { + for k, v := range s.Attrs { + fmt.Println(k, ":", v) + } + if withStickers { + sticks, _ := s.GetStickers() + for _, v := range sticks { + fmt.Println(v.Name, "*:", v.Value) + } + } +} + +func (s *Song) GetSticker(name string) string { + if s.stickers != nil { + ret := slice.Filter(s.stickers, func(sticker mpd.Sticker) bool { + return sticker.Name == name + }) + if ret != nil && len(ret) > 0 { + last := ret[len(ret)-1] + return last.Value + } + } + + if connerror != nil { + return "" + } + + found, err := conn.StickerGet(s.Path, name) + if err != nil { + return "" + } + + s.stickers = append(s.stickers, *found) + + return found.Value +} + +func (s *Song) AddSticker(name, value string) error { + ret := conn.StickerSet(s.Path, name, value) + if ret == nil { + if s.stickers == nil || len(s.stickers) == 0 { + s.GetStickers() + } else { + s.stickers = append(s.stickers, mpd.Sticker{Name: name, Value: value}) + } + } + return ret +} diff --git a/mpd/stickers.go b/mpd/stickers.go new file mode 100644 index 0000000..16b487d --- /dev/null +++ b/mpd/stickers.go @@ -0,0 +1,30 @@ +package mpd + +import "github.com/fhs/gompd/v2/mpd" + +func StickersGetFor(file string) ([]mpd.Sticker, error) { + if connerror != nil { + return nil, connerror + } + + return conn.StickerList(file) +} + +func StickerFind(name string) ([]*Song, error) { + if connerror != nil { + return nil, connerror + } + + paths, sticks, err := conn.StickerFind("", name) + if err != nil { + return nil, err + } + + ret := make([]*Song, len(paths)) + for i := 0; i < len(paths); i++ { + ret[i] = newSong(mpd.Attrs{"file": paths[i]}) + ret[i].stickers = []mpd.Sticker{sticks[i]} + } + + return ret, nil +}