refac
Some checks failed
continuous-integration/drone/tag Build is failing

This commit is contained in:
jjohnstondev 2023-01-09 15:52:21 -08:00
parent e74a71749d
commit e5bef071c7
29 changed files with 600 additions and 74 deletions

View File

@ -7,6 +7,9 @@ steps:
image: golang:1.19
commands:
- go build -o gospt
- gospt completion zsh > gospt_zsh
- gospt completion shell > gospt_shell
- gospt completion fish > gospt_fish
- name: gitea_release
image: plugins/gitea-release
settings:
@ -16,6 +19,9 @@ steps:
base_url: https://gitea.asdf.cafe
files:
- gospt
- gospt_zsh
- gospt_shell
- gospt_fish
checksum: sha256
trigger:

View File

@ -5,7 +5,14 @@ srcinfo:
cd aur && makepkg -g >> PKGBUILD
build:
go build -o gospt .
mkdir -p bin
go build -o ./bin/gospt .
completions:
mkdir -p completions
bin/gospt completion zsh > completions/_gospt
bin/gospt completion bash > completions/gospt
bin/gospt completion fish > completions/gospt.fish
run:
go run main.go
@ -15,10 +22,14 @@ tidy:
clean:
rm -rf bin
rm -rf completions
uninstall:
rm -f /usr/local/bin/${BINARY_NAME}
rm -f /usr/bin/gospt
rm /usr/share/zsh/site-functions/_gospt
install:
cp bin/${BINARY_NAME} /usr/local/bin
cp bin/gospt /usr/bin
cp completions/_gospt /usr/share/zsh/site-functions/_gospt
cp completions/gospt /usr/share/bash-completion/completions/gospt
cp completions/gospt.fish /usr/share/fish/vendor_completions.d/gospt.fish

20
cmd/clearradio.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(clearRadioCmd)
}
var clearRadioCmd = &cobra.Command{
Use: "clearradio",
Short: "Wipes the radio playlist and creates an empty one",
Long: `Wipes the radio playlist and creates an empty one, mostly for debugging or if something goes wrong`,
Run: func(cmd *cobra.Command, args []string) {
commands.ClearRadio(ctx, client)
},
}

72
cmd/completion.go Normal file
View File

@ -0,0 +1,72 @@
/*
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
*/
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var completionCmd = &cobra.Command{
Use: "completion [bash|zsh|fish|powershell]",
Short: "Generate completion script",
Long: fmt.Sprintf(`To load completions:
Bash:
$ source <(%[1]s completion bash)
# To load completions for each session, execute once:
# Linux:
$ %[1]s completion bash > /etc/bash_completion.d/%[1]s
# macOS:
$ %[1]s completion bash > $(brew --prefix)/etc/bash_completion.d/%[1]s
Zsh:
# If shell completion is not already enabled in your environment,
# you will need to enable it. You can execute the following once:
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
# To load completions for each session, execute once:
$ %[1]s completion zsh > "${fpath[1]}/_%[1]s"
# You will need to start a new shell for this setup to take effect.
fish:
$ %[1]s completion fish | source
# To load completions for each session, execute once:
$ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish
PowerShell:
PS> %[1]s completion powershell | Out-String | Invoke-Expression
# To load completions for every new session, run:
PS> %[1]s completion powershell > %[1]s.ps1
# and source this file from your PowerShell profile.
`, rootCmd.Name()),
DisableFlagsInUseLine: true,
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
Run: func(cmd *cobra.Command, args []string) {
switch args[0] {
case "bash":
rootCmd.GenBashCompletion(os.Stdout)
case "zsh":
rootCmd.GenZshCompletion(os.Stdout)
case "fish":
rootCmd.GenFishCompletion(os.Stdout, true)
}
},
}
func init() {
rootCmd.AddCommand(completionCmd)
}

20
cmd/devices.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(devicesCmd)
}
var devicesCmd = &cobra.Command{
Use: "devices",
Short: "Prints out devices",
Long: `Prints out devices`,
Run: func(cmd *cobra.Command, args []string) {
commands.Devices(ctx, client)
},
}

20
cmd/like.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(likeCmd)
}
var likeCmd = &cobra.Command{
Use: "like",
Short: "Likes song",
Long: `Likes song`,
Run: func(cmd *cobra.Command, args []string) {
commands.Like(ctx, client)
},
}

20
cmd/nowplaying.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(nowPlayingCmd)
}
var nowPlayingCmd = &cobra.Command{
Use: "nowplaying",
Short: "Shows song and artist of currently playing song",
Long: `Shows song and artist of currently playing song, useful for scripting`,
Run: func(cmd *cobra.Command, args []string) {
commands.NowPlaying(ctx, client)
},
}

20
cmd/pause.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(pauseCmd)
}
var pauseCmd = &cobra.Command{
Use: "pause",
Short: "Pauses spotify",
Long: `Pauses currently playing song on spotify`,
Run: func(cmd *cobra.Command, args []string) {
commands.Pause(ctx, client)
},
}

20
cmd/play.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(playCmd)
}
var playCmd = &cobra.Command{
Use: "play",
Short: "Plays spotify",
Long: `Plays queued song on spotify, uses last used device and activates it if needed`,
Run: func(cmd *cobra.Command, args []string) {
commands.Play(ctx, client)
},
}

20
cmd/playlists.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/tui"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(playListsCmd)
}
var playListsCmd = &cobra.Command{
Use: "playlists",
Short: "Uses tui to show users playlists",
Long: `Opens tui showing all users playlists`,
Run: func(cmd *cobra.Command, args []string) {
tui.DisplayPlaylists(ctx, client)
},
}

21
cmd/playurl.go Normal file
View File

@ -0,0 +1,21 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(playurlCmd)
}
var playurlCmd = &cobra.Command{
Use: "playurl",
Short: "Plays song from provided url",
Args: cobra.MatchAll(cobra.ExactArgs(1)),
Long: `Plays song from provided url`,
Run: func(cmd *cobra.Command, args []string) {
commands.PlayUrl(ctx, client, args)
},
}

20
cmd/previous.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(previousCmd)
}
var previousCmd = &cobra.Command{
Use: "previous",
Short: "goes to previous song",
Long: `if song is playing it will start over, if close to begining of song it will go to previous song`,
Run: func(cmd *cobra.Command, args []string) {
commands.Previous(ctx, client)
},
}

20
cmd/radio.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(radioCmd)
}
var radioCmd = &cobra.Command{
Use: "radio",
Short: "Starts radio",
Long: `Starts radio`,
Run: func(cmd *cobra.Command, args []string) {
commands.Radio(ctx, client)
},
}

20
cmd/refillradio.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(refillRadioCmd)
}
var refillRadioCmd = &cobra.Command{
Use: "refillradio",
Short: "Refills the radio",
Long: `Deletes all songs up to your position in the radio and adds that many songs to the end of the radio`,
Run: func(cmd *cobra.Command, args []string) {
commands.RefillRadio(ctx, client)
},
}

20
cmd/repeat.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(repeatCmd)
}
var repeatCmd = &cobra.Command{
Use: "repeat",
Short: "Toggles repeat",
Long: `Switches between repeating your current context or not, spotifyd does not support single track loops`,
Run: func(cmd *cobra.Command, args []string) {
commands.Repeat(ctx, client)
},
}

83
cmd/root.go Normal file
View File

@ -0,0 +1,83 @@
package cmd
import (
"context"
"fmt"
"os"
"path/filepath"
"gospt/internal/auth"
"gospt/internal/config"
"gospt/internal/gctx"
"github.com/cristalhq/aconfig"
"github.com/cristalhq/aconfig/aconfigyaml"
"github.com/spf13/cobra"
"github.com/zmb3/spotify/v2"
)
var (
// Used for flags.
ctx *gctx.Context
client *spotify.Client
cfgFile string
userLicense string
rootCmd = &cobra.Command{
Use: "gospt",
Short: "A spotify TUI and CLI to manage playback, browse library, and generate radios",
Long: `A spotify TUI and CLI to manage playback, borwse library, and generate radios written in go`,
}
)
// Execute executes the root command.
func Execute(defCmd string) {
if len(os.Args) == 1 {
args := append([]string{defCmd}, os.Args[1:]...)
rootCmd.SetArgs(args)
}
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func init() {
configDir, _ := os.UserConfigDir()
cfgFile = filepath.Join(configDir, "gospt/client.yml")
cobra.OnInitialize(initConfig)
if !(len(os.Args) > 1) || os.Args[1] != "completion" {
initConfig()
var err error
ctx = gctx.NewContext(context.Background())
client, err = auth.GetClient(ctx)
if err != nil {
panic(err)
}
}
}
func initConfig() {
yamlDecoder := aconfigyaml.New()
loader := aconfig.LoaderFor(&config.Values, aconfig.Config{
AllowUnknownFields: true,
AllowUnknownEnvs: true,
AllowUnknownFlags: true,
SkipFlags: true,
DontGenerateTags: true,
MergeFiles: true,
EnvPrefix: "",
FlagPrefix: "",
Files: []string{
cfgFile,
},
FileDecoders: map[string]aconfig.FileDecoder{
".yml": yamlDecoder,
},
})
if err := loader.Load(); err != nil {
panic(err)
}
}

20
cmd/setdevice.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/tui"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(setDeviceCmd)
}
var setDeviceCmd = &cobra.Command{
Use: "setdevice",
Short: "Shows tui to pick active device",
Long: `Allows setting or changing the active spotify device, shown in a tui`,
Run: func(cmd *cobra.Command, args []string) {
tui.DisplayDevices(ctx, client)
},
}

20
cmd/shuffle.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(shuffleCmd)
}
var shuffleCmd = &cobra.Command{
Use: "shuffle",
Short: "Toggles shuffle",
Long: `Enables shuffle if it is currently disabled or disables it if it is currently active`,
Run: func(cmd *cobra.Command, args []string) {
commands.Shuffle(ctx, client)
},
}

20
cmd/skip.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(skipCmd)
}
var skipCmd = &cobra.Command{
Use: "skip",
Short: "Skip to next song",
Long: `Skip to next song`,
Run: func(cmd *cobra.Command, args []string) {
commands.Skip(ctx, client)
},
}

20
cmd/status.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(statusCmd)
}
var statusCmd = &cobra.Command{
Use: "status",
Short: "Returns player status in json",
Long: `Returns all player status in json, useful for scripting`,
Run: func(cmd *cobra.Command, args []string) {
commands.Status(ctx, client)
},
}

20
cmd/toggleplay.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(togglePlayCmd)
}
var togglePlayCmd = &cobra.Command{
Use: "toggleplay",
Short: "Toggles the play state of spotify",
Long: `If you are playing a song it will pause and if a song is paused it will play`,
Run: func(cmd *cobra.Command, args []string) {
commands.TogglePlay(ctx, client)
},
}

20
cmd/tracks.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/tui"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(tracksCmd)
}
var tracksCmd = &cobra.Command{
Use: "tracks",
Short: "Opens saved tracks",
Long: `Uses TUI to open a list of saved tracks`,
Run: func(cmd *cobra.Command, args []string) {
tui.DisplayList(ctx, client)
},
}

27
cmd/tui.go Normal file
View File

@ -0,0 +1,27 @@
package cmd
import (
"os"
"path/filepath"
"gospt/internal/tui"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(tuiCmd)
}
var tuiCmd = &cobra.Command{
Use: "tui",
Short: "Default command, launches the main menu",
Long: `Default command. this is what will run if no other commands are present. Shows the main menu.`,
RunE: func(cmd *cobra.Command, args []string) error {
configDir, _ := os.UserConfigDir()
if _, err := os.Stat(filepath.Join(configDir, "gospt/device.json")); err != nil {
return tui.StartTea(ctx, client)
}
return tui.DisplayMain(ctx, client)
},
}

20
cmd/unlike.go Normal file
View File

@ -0,0 +1,20 @@
package cmd
import (
"gospt/internal/commands"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(unlikeCmd)
}
var unlikeCmd = &cobra.Command{
Use: "unlike",
Short: "unlikes song",
Long: `unlikes song`,
Run: func(cmd *cobra.Command, args []string) {
commands.Unlike(ctx, client)
},
}

3
go.mod
View File

@ -18,6 +18,7 @@ require (
github.com/aymanbagabas/go-osc52 v1.0.3 // indirect
github.com/containerd/console v1.0.3 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
@ -28,6 +29,8 @@ require (
github.com/muesli/termenv v0.13.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/sahilm/fuzzy v0.1.0 // indirect
github.com/spf13/cobra v1.6.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect

9
go.sum
View File

@ -54,6 +54,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cristalhq/aconfig v0.17.0/go.mod h1:NXaRp+1e6bkO4dJn+wZ71xyaihMDYPtCSvEhMTm/H3E=
github.com/cristalhq/aconfig v0.18.3 h1:Or12LIWIF+2mQpcGWA2PQnNc55+WiHFAqRjYh/pQNtM=
github.com/cristalhq/aconfig v0.18.3/go.mod h1:NXaRp+1e6bkO4dJn+wZ71xyaihMDYPtCSvEhMTm/H3E=
@ -121,6 +122,9 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@ -162,8 +166,13 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
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/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=

View File

@ -44,10 +44,7 @@ func Play(ctx *gctx.Context, client *spotify.Client) error {
}
func PlayUrl(ctx *gctx.Context, client *spotify.Client, args []string) error {
if len(args) < 2 {
return fmt.Errorf("Please provide a url")
}
url, err := url.Parse(args[1])
url, err := url.Parse(args[0])
if err != nil {
return err
}

View File

@ -1,37 +1,6 @@
package config
import (
"path/filepath"
"github.com/cristalhq/aconfig"
"github.com/cristalhq/aconfig/aconfigyaml"
)
var Values struct {
ClientId string `yaml:"client_id"`
ClientSecret string `yaml:"client_secret"`
}
func LoadConfig(configDir string) {
yamlDecoder := aconfigyaml.New()
loader := aconfig.LoaderFor(&Values, aconfig.Config{
AllowUnknownFields: true,
AllowUnknownEnvs: true,
AllowUnknownFlags: true,
SkipFlags: true,
DontGenerateTags: true,
MergeFiles: true,
EnvPrefix: "",
FlagPrefix: "",
Files: []string{
filepath.Join(configDir, "client.yml"),
},
FileDecoders: map[string]aconfig.FileDecoder{
".yml": yamlDecoder,
},
})
if err := loader.Load(); err != nil {
panic(err)
}
}

38
main.go
View File

@ -1,40 +1,8 @@
package main
import (
"context"
"fmt"
"log"
"os"
"path/filepath"
"gospt/internal/api"
"gospt/internal/auth"
"gospt/internal/config"
"gospt/internal/gctx"
)
func init() {
configPath, _ := os.UserConfigDir()
configDir := filepath.Join(configPath, "gospt")
config.LoadConfig(configDir)
}
import "gospt/cmd"
func main() {
var err error
log.New(os.Stdout, "LOG:", 0)
ctx := gctx.NewContext(context.Background())
client, err := auth.GetClient(ctx)
if err != nil {
fmt.Println(err.Error())
return
}
currentUser, err := client.CurrentUser(ctx)
if err != nil {
panic(err.Error())
}
ctx.UserId = currentUser.ID
err = api.Run(ctx, client, os.Args[1:])
if err != nil {
fmt.Println(err)
}
defCmd := "tui"
cmd.Execute(defCmd)
}