refac
This commit is contained in:
parent
567fb54ac2
commit
affb5fbaba
@ -18,7 +18,7 @@ builds:
|
|||||||
- goos: windows
|
- goos: windows
|
||||||
goarch: "386"
|
goarch: "386"
|
||||||
ldflags:
|
ldflags:
|
||||||
- -s -w -X git.asdf.cafe/abs3nt/gospt-ng/src/components/cli.Version={{.Version}}
|
- -s -w -X git.asdf.cafe/abs3nt/gspot/src/components/cli.Version=({{.Version}} - {{.Now}})
|
||||||
|
|
||||||
archives:
|
archives:
|
||||||
- format: tar.gz
|
- format: tar.gz
|
||||||
|
@ -3,7 +3,7 @@ steps:
|
|||||||
image: golang:1.22
|
image: golang:1.22
|
||||||
commands:
|
commands:
|
||||||
- go mod tidy
|
- go mod tidy
|
||||||
- go build -o gospt-ng
|
- go build -o gspot
|
||||||
|
|
||||||
publish:
|
publish:
|
||||||
image: goreleaser/goreleaser:nightly
|
image: goreleaser/goreleaser:nightly
|
||||||
|
18
Makefile
18
Makefile
@ -1,7 +1,7 @@
|
|||||||
build: gospt-ng
|
build: gspot
|
||||||
|
|
||||||
gospt-ng: $(shell find . -name '*.go')
|
gspot: $(shell find . -name '*.go')
|
||||||
go build -ldflags="-X 'git.asdf.cafe/abs3nt/gospt-ng/src/components/cli.Version=$(shell git rev-parse --short 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/ .
|
||||||
|
|
||||||
run:
|
run:
|
||||||
go run main.go
|
go run main.go
|
||||||
@ -13,11 +13,11 @@ clean:
|
|||||||
rm -rf bin
|
rm -rf bin
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f /usr/bin/gospt-ng
|
rm -f /usr/bin/gspot
|
||||||
rm -f /usr/share/zsh/site-functions/_gospt-ng
|
rm -f /usr/share/zsh/site-functions/_gspot
|
||||||
rm -f /usr/share/bash-completion/completions/gospt-ng
|
rm -f /usr/share/bash-completion/completions/gspot
|
||||||
|
|
||||||
install:
|
install:
|
||||||
cp ./dist/gospt-ng /usr/bin
|
cp ./dist/gspot /usr/bin
|
||||||
cp ./completions/_gospt-ng /usr/share/zsh/site-functions/_gospt-ng
|
cp ./completions/_gspot /usr/share/zsh/site-functions/_gspot
|
||||||
cp ./completions/gospt-ng /usr/share/bash-completion/completions/gospt-ng
|
cp ./completions/gspot /usr/share/bash-completion/completionsgspotg
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#compdef gospt-ng
|
#compdef gspot
|
||||||
|
|
||||||
_cli_zsh_autocomplete() {
|
_cli_zsh_autocomplete() {
|
||||||
local -a opts
|
local -a opts
|
||||||
@ -17,4 +17,4 @@ _cli_zsh_autocomplete() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
compdef _cli_zsh_autocomplete gospt-ng
|
compdef _cli_zsh_autocomplete gspot
|
2
go.mod
2
go.mod
@ -1,4 +1,4 @@
|
|||||||
module git.asdf.cafe/abs3nt/gospt-ng
|
module git.asdf.cafe/abs3nt/gspot
|
||||||
|
|
||||||
go 1.22.0
|
go 1.22.0
|
||||||
|
|
||||||
|
8
main.go
8
main.go
@ -3,10 +3,10 @@ package main
|
|||||||
import (
|
import (
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
|
||||||
"git.asdf.cafe/abs3nt/gospt-ng/src/app"
|
"git.asdf.cafe/abs3nt/gspot/src/app"
|
||||||
"git.asdf.cafe/abs3nt/gospt-ng/src/components/cache"
|
"git.asdf.cafe/abs3nt/gspot/src/components/cache"
|
||||||
"git.asdf.cafe/abs3nt/gospt-ng/src/components/cli"
|
"git.asdf.cafe/abs3nt/gspot/src/components/cli"
|
||||||
"git.asdf.cafe/abs3nt/gospt-ng/src/components/commands"
|
"git.asdf.cafe/abs3nt/gspot/src/components/commands"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -9,8 +9,8 @@ import (
|
|||||||
"github.com/lmittmann/tint"
|
"github.com/lmittmann/tint"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
|
||||||
"git.asdf.cafe/abs3nt/gospt-ng/src/config"
|
"git.asdf.cafe/abs3nt/gspot/src/config"
|
||||||
"git.asdf.cafe/abs3nt/gospt-ng/src/services"
|
"git.asdf.cafe/abs3nt/gspot/src/services"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Services = fx.Options(
|
var Services = fx.Options(
|
||||||
@ -31,7 +31,7 @@ var Config = fx.Options(
|
|||||||
fx.Provide(
|
fx.Provide(
|
||||||
func() *config.Config {
|
func() *config.Config {
|
||||||
c := &config.Config{}
|
c := &config.Config{}
|
||||||
gunner.LoadApp(c, "gospt")
|
gunner.LoadApp(c, "gspot")
|
||||||
return c
|
return c
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
2
src/components/cache/cache.go
vendored
2
src/components/cache/cache.go
vendored
@ -35,7 +35,7 @@ type CacheParams struct {
|
|||||||
|
|
||||||
func NewCache(p CacheParams) CacheResult {
|
func NewCache(p CacheParams) CacheResult {
|
||||||
c := &Cache{
|
c := &Cache{
|
||||||
Root: filepath.Join(os.TempDir(), "gospt.cache"),
|
Root: filepath.Join(os.TempDir(), "gspot.cache"),
|
||||||
Log: p.Log,
|
Log: p.Log,
|
||||||
}
|
}
|
||||||
return CacheResult{
|
return CacheResult{
|
||||||
|
@ -9,8 +9,8 @@ import (
|
|||||||
"github.com/zmb3/spotify/v2"
|
"github.com/zmb3/spotify/v2"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
|
||||||
"git.asdf.cafe/abs3nt/gospt-ng/src/components/commands"
|
"git.asdf.cafe/abs3nt/gspot/src/components/commands"
|
||||||
"git.asdf.cafe/abs3nt/gospt-ng/src/components/tui"
|
"git.asdf.cafe/abs3nt/gspot/src/components/tui"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Version = "dev"
|
var Version = "dev"
|
||||||
@ -23,6 +23,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
app := &cli.App{
|
app := &cli.App{
|
||||||
|
Name: "gspot",
|
||||||
EnableBashCompletion: true,
|
EnableBashCompletion: true,
|
||||||
Version: Version,
|
Version: Version,
|
||||||
Action: func(ctx *cli.Context) error {
|
Action: func(ctx *cli.Context) error {
|
||||||
@ -95,11 +96,20 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
|
|||||||
Category: "Sharing",
|
Category: "Sharing",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "next",
|
Name: "next",
|
||||||
Aliases: []string{"n", "skip"},
|
Aliases: []string{"n", "skip"},
|
||||||
Usage: "Skips to the next song",
|
Usage: "Skips to the next song",
|
||||||
|
Args: true,
|
||||||
|
ArgsUsage: "amount",
|
||||||
Action: func(cCtx *cli.Context) error {
|
Action: func(cCtx *cli.Context) error {
|
||||||
return c.Next()
|
if cCtx.NArg() > 0 {
|
||||||
|
amt, err := strconv.Atoi(cCtx.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Next(amt, false)
|
||||||
|
}
|
||||||
|
return c.Next(1, false)
|
||||||
},
|
},
|
||||||
Category: "Playback",
|
Category: "Playback",
|
||||||
},
|
},
|
||||||
|
@ -12,8 +12,8 @@ import (
|
|||||||
func (c *Commander) activateDevice() (spotify.ID, error) {
|
func (c *Commander) activateDevice() (spotify.ID, error) {
|
||||||
var device *spotify.PlayerDevice
|
var device *spotify.PlayerDevice
|
||||||
configDir, _ := os.UserConfigDir()
|
configDir, _ := os.UserConfigDir()
|
||||||
if _, err := os.Stat(filepath.Join(configDir, "gospt/device.json")); err == nil {
|
if _, err := os.Stat(filepath.Join(configDir, "gspot/device.json")); err == nil {
|
||||||
deviceFile, err := os.Open(filepath.Join(configDir, "gospt/device.json"))
|
deviceFile, err := os.Open(filepath.Join(configDir, "gspot/device.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ func (c *Commander) activateDevice() (spotify.ID, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.Log.Error("COMMANDER", "failed to activated device", "YOU MUST RUN gospt setdevice FIRST")
|
c.Log.Error("COMMANDER", "failed to activated device", "YOU MUST RUN gspot setdevice FIRST")
|
||||||
}
|
}
|
||||||
return device.ID, nil
|
return device.ID, nil
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/zmb3/spotify/v2"
|
"github.com/zmb3/spotify/v2"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
|
||||||
"git.asdf.cafe/abs3nt/gospt-ng/src/components/cache"
|
"git.asdf.cafe/abs3nt/gspot/src/components/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CommanderResult struct {
|
type CommanderResult struct {
|
||||||
|
@ -42,7 +42,7 @@ func (c *Commander) SetDevice(device spotify.ID) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
configDir, _ := os.UserConfigDir()
|
configDir, _ := os.UserConfigDir()
|
||||||
err = os.WriteFile(filepath.Join(configDir, "gospt/device.json"), out, 0o600)
|
err = os.WriteFile(filepath.Join(configDir, "gspot/device.json"), out, 0o600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,117 @@
|
|||||||
package commands
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/zmb3/spotify/v2"
|
"github.com/zmb3/spotify/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Commander) Next() error {
|
func (c *Commander) Next(amt int, inqueue bool) error {
|
||||||
err := c.Client.Next(c.Context)
|
if inqueue {
|
||||||
if err != nil {
|
for i := 0; i < amt; i++ {
|
||||||
if isNoActiveError(err) {
|
err := c.Client.Next(c.Context)
|
||||||
deviceId, err := c.activateDevice()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = c.Client.NextOpt(c.Context, &spotify.PlayOptions{
|
|
||||||
DeviceID: &deviceId,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if amt == 1 {
|
||||||
|
err := c.Client.Next(c.Context)
|
||||||
|
if err != nil {
|
||||||
|
if isNoActiveError(err) {
|
||||||
|
deviceId, err := c.activateDevice()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = c.Client.NextOpt(c.Context, &spotify.PlayOptions{
|
||||||
|
DeviceID: &deviceId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// found := false
|
||||||
|
// playingIndex := 0
|
||||||
|
current, err := c.Client.PlayerCurrentlyPlaying(c.Context)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
playbackContext := current.PlaybackContext.Type
|
||||||
|
switch playbackContext {
|
||||||
|
case "playlist":
|
||||||
|
found := false
|
||||||
|
currentTrackIndex := 0
|
||||||
|
page := 1
|
||||||
|
for !found {
|
||||||
|
playlist, err := c.Client.
|
||||||
|
GetPlaylistItems(
|
||||||
|
c.Context,
|
||||||
|
spotify.ID(strings.Split(string(current.PlaybackContext.URI), ":")[2]),
|
||||||
|
spotify.Limit(50),
|
||||||
|
spotify.Offset((page-1)*50),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for idx, track := range playlist.Items {
|
||||||
|
if track.Track.Track.ID == current.Item.ID {
|
||||||
|
currentTrackIndex = idx + (50 * (page - 1))
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
page++
|
||||||
|
}
|
||||||
|
pos := currentTrackIndex + amt
|
||||||
|
return c.Client.PlayOpt(c.Context, &spotify.PlayOptions{
|
||||||
|
PlaybackContext: ¤t.PlaybackContext.URI,
|
||||||
|
PlaybackOffset: &spotify.PlaybackOffset{
|
||||||
|
Position: &pos,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
case "album":
|
||||||
|
found := false
|
||||||
|
currentTrackIndex := 0
|
||||||
|
page := 1
|
||||||
|
for !found {
|
||||||
|
playlist, err := c.Client.
|
||||||
|
GetAlbumTracks(
|
||||||
|
c.Context,
|
||||||
|
spotify.ID(strings.Split(string(current.PlaybackContext.URI), ":")[2]),
|
||||||
|
spotify.Limit(50),
|
||||||
|
spotify.Offset((page-1)*50),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for idx, track := range playlist.Tracks {
|
||||||
|
if track.ID == current.Item.ID {
|
||||||
|
currentTrackIndex = idx + (50 * (page - 1))
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
page++
|
||||||
|
}
|
||||||
|
pos := currentTrackIndex + amt
|
||||||
|
return c.Client.PlayOpt(c.Context, &spotify.PlayOptions{
|
||||||
|
PlaybackContext: ¤t.PlaybackContext.URI,
|
||||||
|
PlaybackOffset: &spotify.PlaybackOffset{
|
||||||
|
Position: &pos,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
for i := 0; i < amt; i++ {
|
||||||
|
err := c.Client.Next(c.Context)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,12 @@ func (c *Commander) RadioFromPlaylist(playlist spotify.SimplePlaylist) error {
|
|||||||
if pages > 1 {
|
if pages > 1 {
|
||||||
randomPage = frand.Intn(pages-1) + 1
|
randomPage = frand.Intn(pages-1) + 1
|
||||||
}
|
}
|
||||||
playlistPage, err := c.Client.GetPlaylistItems(c.Context, playlist.ID, spotify.Limit(50), spotify.Offset((randomPage-1)*50))
|
playlistPage, err := c.Client.GetPlaylistItems(
|
||||||
|
c.Context,
|
||||||
|
playlist.ID,
|
||||||
|
spotify.Limit(50),
|
||||||
|
spotify.Offset((randomPage-1)*50),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -287,14 +292,14 @@ func (c *Commander) ClearRadio() error {
|
|||||||
}
|
}
|
||||||
_, _ = db.Query("DROP TABLE IF EXISTS radio")
|
_, _ = db.Query("DROP TABLE IF EXISTS radio")
|
||||||
configDir, _ := os.UserConfigDir()
|
configDir, _ := os.UserConfigDir()
|
||||||
os.Remove(filepath.Join(configDir, "gospt/radio.json"))
|
os.Remove(filepath.Join(configDir, "gspot/radio.json"))
|
||||||
_ = c.Client.Pause(c.Context)
|
_ = c.Client.Pause(c.Context)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commander) GetRadioPlaylist(name string) (*spotify.FullPlaylist, *sql.DB, error) {
|
func (c *Commander) GetRadioPlaylist(name string) (*spotify.FullPlaylist, *sql.DB, error) {
|
||||||
configDir, _ := os.UserConfigDir()
|
configDir, _ := os.UserConfigDir()
|
||||||
playlistFile, err := os.ReadFile(filepath.Join(configDir, "gospt/radio.json"))
|
playlistFile, err := os.ReadFile(filepath.Join(configDir, "gspot/radio.json"))
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
return c.CreateRadioPlaylist(name)
|
return c.CreateRadioPlaylist(name)
|
||||||
}
|
}
|
||||||
@ -306,7 +311,7 @@ func (c *Commander) GetRadioPlaylist(name string) (*spotify.FullPlaylist, *sql.D
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
db, err := sql.Open("sqlite", filepath.Join(configDir, "gospt/radio.db"))
|
db, err := sql.Open("sqlite", filepath.Join(configDir, "gspot/radio.db"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -325,11 +330,11 @@ func (c *Commander) CreateRadioPlaylist(name string) (*spotify.FullPlaylist, *sq
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
err = os.WriteFile(filepath.Join(configDir, "gospt/radio.json"), raw, 0o600)
|
err = os.WriteFile(filepath.Join(configDir, "gspot/radio.json"), raw, 0o600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
db, err := sql.Open("sqlite", filepath.Join(configDir, "gospt/radio.db"))
|
db, err := sql.Open("sqlite", filepath.Join(configDir, "gspot/radio.db"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package commands
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.asdf.cafe/abs3nt/gospt-ng/src/components/youtube"
|
"git.asdf.cafe/abs3nt/gspot/src/components/youtube"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Commander) PrintYoutubeLink() error {
|
func (c *Commander) PrintYoutubeLink() error {
|
||||||
|
@ -1,120 +0,0 @@
|
|||||||
package tui
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zmb3/spotify/v2"
|
|
||||||
|
|
||||||
"git.asdf.cafe/abs3nt/gospt-ng/src/components/commands"
|
|
||||||
)
|
|
||||||
|
|
||||||
func HandlePlayWithContext(commands *commands.Commander, uri *spotify.URI, pos *int) {
|
|
||||||
err := commands.PlaySongInPlaylist(uri, pos)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleRadio(commands *commands.Commander, song spotify.SimpleTrack) {
|
|
||||||
err := commands.RadioGivenSong(song, 0)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleAlbumRadio(commands *commands.Commander, album spotify.SimpleAlbum) {
|
|
||||||
err := commands.RadioFromAlbum(album)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleSeek(commands *commands.Commander, fwd bool) {
|
|
||||||
err := commands.Seek(fwd)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleVolume(commands *commands.Commander, up bool) {
|
|
||||||
vol := 10
|
|
||||||
if !up {
|
|
||||||
vol = -10
|
|
||||||
}
|
|
||||||
err := commands.ChangeVolume(vol)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleArtistRadio(commands *commands.Commander, artist spotify.SimpleArtist) {
|
|
||||||
err := commands.RadioGivenArtist(artist)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleAlbumArtist(commands *commands.Commander, artist spotify.SimpleArtist) {
|
|
||||||
err := commands.RadioGivenArtist(artist)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandlePlaylistRadio(commands *commands.Commander, playlist spotify.SimplePlaylist) {
|
|
||||||
err := commands.RadioFromPlaylist(playlist)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleLibraryRadio(commands *commands.Commander) {
|
|
||||||
err := commands.RadioFromSavedTracks()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandlePlayLikedSong(commands *commands.Commander, position int) {
|
|
||||||
err := commands.PlayLikedSongs(position)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandlePlayTrack(commands *commands.Commander, track spotify.ID) {
|
|
||||||
err := commands.QueueSong(track)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = commands.Next()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleNextInQueue(commands *commands.Commander, amt int) {
|
|
||||||
err := commands.Next()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleQueueItem(commands *commands.Commander, item spotify.ID) {
|
|
||||||
err := commands.QueueSong(item)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleDeleteTrackFromPlaylist(commands *commands.Commander, item, playlist spotify.ID) {
|
|
||||||
err := commands.DeleteTracksFromPlaylist([]spotify.ID{item}, playlist)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleSetDevice(commands *commands.Commander, player spotify.PlayerDevice) {
|
|
||||||
err := commands.SetDevice(player.ID)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,7 +14,7 @@ import (
|
|||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
"github.com/zmb3/spotify/v2"
|
"github.com/zmb3/spotify/v2"
|
||||||
|
|
||||||
"git.asdf.cafe/abs3nt/gospt-ng/src/components/commands"
|
"git.asdf.cafe/abs3nt/gspot/src/components/commands"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -93,37 +93,92 @@ func (m *mainModel) PlayRadio() {
|
|||||||
selectedItem := m.list.SelectedItem().(mainItem).SpotifyItem
|
selectedItem := m.list.SelectedItem().(mainItem).SpotifyItem
|
||||||
switch item := selectedItem.(type) {
|
switch item := selectedItem.(type) {
|
||||||
case spotify.SimplePlaylist:
|
case spotify.SimplePlaylist:
|
||||||
go HandlePlaylistRadio(m.commands, item)
|
go func() {
|
||||||
|
err := m.commands.RadioFromPlaylist(item)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
return
|
return
|
||||||
case *spotify.SavedTrackPage:
|
case *spotify.SavedTrackPage:
|
||||||
go HandleLibraryRadio(m.commands)
|
go func() {
|
||||||
|
err := m.commands.RadioFromSavedTracks()
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
return
|
return
|
||||||
case spotify.SimpleAlbum:
|
case spotify.SimpleAlbum:
|
||||||
go HandleAlbumRadio(m.commands, item)
|
go func() {
|
||||||
|
err := m.commands.RadioFromAlbum(item)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
return
|
return
|
||||||
case spotify.FullAlbum:
|
case spotify.FullAlbum:
|
||||||
go HandleAlbumRadio(m.commands, item.SimpleAlbum)
|
go func() {
|
||||||
|
err := m.commands.RadioFromAlbum(item.SimpleAlbum)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
return
|
return
|
||||||
case spotify.SimpleArtist:
|
case spotify.SimpleArtist:
|
||||||
go HandleArtistRadio(m.commands, item)
|
go func() {
|
||||||
|
err := m.commands.RadioGivenArtist(item)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
return
|
return
|
||||||
case spotify.FullArtist:
|
case spotify.FullArtist:
|
||||||
go HandleArtistRadio(m.commands, item.SimpleArtist)
|
go func() {
|
||||||
|
err := m.commands.RadioGivenArtist(item.SimpleArtist)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
return
|
return
|
||||||
case spotify.SimpleTrack:
|
case spotify.SimpleTrack:
|
||||||
go HandleRadio(m.commands, item)
|
go func() {
|
||||||
|
err := m.commands.RadioGivenSong(item, 0)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
return
|
return
|
||||||
case spotify.FullTrack:
|
case spotify.FullTrack:
|
||||||
go HandleRadio(m.commands, item.SimpleTrack)
|
go func() {
|
||||||
|
err := m.commands.RadioGivenSong(item.SimpleTrack, 0)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
return
|
return
|
||||||
case spotify.PlaylistTrack:
|
case spotify.PlaylistTrack:
|
||||||
go HandleRadio(m.commands, item.Track.SimpleTrack)
|
go func() {
|
||||||
|
err := m.commands.RadioGivenSong(item.Track.SimpleTrack, 0)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
return
|
return
|
||||||
case spotify.PlaylistItem:
|
case spotify.PlaylistItem:
|
||||||
go HandleRadio(m.commands, item.Track.Track.SimpleTrack)
|
go func() {
|
||||||
|
err := m.commands.RadioGivenSong(item.Track.Track.SimpleTrack, 0)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
return
|
return
|
||||||
case spotify.SavedTrack:
|
case spotify.SavedTrack:
|
||||||
go HandleRadio(m.commands, item.SimpleTrack)
|
go func() {
|
||||||
|
err := m.commands.RadioGivenSong(item.SimpleTrack, 0)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,29 +309,38 @@ func (m *mainModel) SendMessage(msg string, duration time.Duration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mainModel) QueueItem() error {
|
func (m *mainModel) QueueItem() error {
|
||||||
|
var id spotify.ID
|
||||||
|
var name string
|
||||||
switch item := m.list.SelectedItem().(mainItem).SpotifyItem.(type) {
|
switch item := m.list.SelectedItem().(mainItem).SpotifyItem.(type) {
|
||||||
case spotify.PlaylistTrack:
|
case spotify.PlaylistTrack:
|
||||||
go m.SendMessage("Adding "+item.Track.Name+" to queue", 2*time.Second)
|
name = item.Track.Name
|
||||||
go HandleQueueItem(m.commands, item.Track.ID)
|
id = item.Track.ID
|
||||||
case spotify.SavedTrack:
|
case spotify.SavedTrack:
|
||||||
go m.SendMessage("Adding "+item.Name+" to queue", 2*time.Second)
|
name = item.Name
|
||||||
go HandleQueueItem(m.commands, item.ID)
|
id = item.ID
|
||||||
case spotify.SimpleTrack:
|
case spotify.SimpleTrack:
|
||||||
go m.SendMessage("Adding "+item.Name+" to queue", 2*time.Second)
|
name = item.Name
|
||||||
go HandleQueueItem(m.commands, item.ID)
|
id = item.ID
|
||||||
case spotify.FullTrack:
|
case spotify.FullTrack:
|
||||||
go m.SendMessage("Adding "+item.Name+" to queue", 2*time.Second)
|
name = item.Name
|
||||||
go HandleQueueItem(m.commands, item.ID)
|
id = item.ID
|
||||||
case *spotify.FullTrack:
|
case *spotify.FullTrack:
|
||||||
go m.SendMessage("Adding "+item.Name+" to queue", 2*time.Second)
|
name = item.Name
|
||||||
go HandleQueueItem(m.commands, item.ID)
|
id = item.ID
|
||||||
case *spotify.SimpleTrack:
|
case *spotify.SimpleTrack:
|
||||||
go m.SendMessage("Adding "+item.Name+" to queue", 2*time.Second)
|
name = item.Name
|
||||||
go HandleQueueItem(m.commands, item.ID)
|
id = item.ID
|
||||||
case *spotify.SimplePlaylist:
|
case *spotify.SimplePlaylist:
|
||||||
go m.SendMessage("Adding "+item.Name+" to queue", 2*time.Second)
|
name = item.Name
|
||||||
go HandleQueueItem(m.commands, item.ID)
|
id = item.ID
|
||||||
}
|
}
|
||||||
|
go m.SendMessage("Adding "+name+" to queue", 2*time.Second)
|
||||||
|
go func() {
|
||||||
|
err := m.commands.QueueSong(id)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
if m.mode == Queue {
|
if m.mode == Queue {
|
||||||
go func() {
|
go func() {
|
||||||
new_items, err := QueueView(m.commands)
|
new_items, err := QueueView(m.commands)
|
||||||
@ -296,10 +360,13 @@ func (m *mainModel) DeleteTrackFromPlaylist() error {
|
|||||||
track := m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.PlaylistTrack).Track
|
track := m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.PlaylistTrack).Track
|
||||||
go m.SendMessage("Deleteing "+track.Name+" from "+m.playlist.Name, 2*time.Second)
|
go m.SendMessage("Deleteing "+track.Name+" from "+m.playlist.Name, 2*time.Second)
|
||||||
go func() {
|
go func() {
|
||||||
HandleDeleteTrackFromPlaylist(m.commands, track.ID, m.playlist.ID)
|
err := m.commands.DeleteTracksFromPlaylist([]spotify.ID{track.ID}, m.playlist.ID)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
new_items, err := PlaylistView(m.commands, m.playlist)
|
new_items, err := PlaylistView(m.commands, m.playlist)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
}
|
}
|
||||||
m.list.SetItems(new_items)
|
m.list.SetItems(new_items)
|
||||||
}()
|
}()
|
||||||
@ -311,10 +378,13 @@ func (m *mainModel) SelectItem() error {
|
|||||||
case Queue:
|
case Queue:
|
||||||
page = 1
|
page = 1
|
||||||
go func() {
|
go func() {
|
||||||
HandleNextInQueue(m.commands, m.list.Index())
|
err := m.commands.Next(m.list.Index(), true)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
new_items, err := QueueView(m.commands)
|
new_items, err := QueueView(m.commands)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
}
|
}
|
||||||
m.list.SetItems(new_items)
|
m.list.SetItems(new_items)
|
||||||
m.list.ResetSelected()
|
m.list.ResetSelected()
|
||||||
@ -471,17 +541,43 @@ func (m *mainModel) SelectItem() error {
|
|||||||
m.list.ResetSelected()
|
m.list.ResetSelected()
|
||||||
case Album, ArtistAlbum, SearchArtistAlbum, SearchAlbum:
|
case Album, ArtistAlbum, SearchArtistAlbum, SearchAlbum:
|
||||||
pos := m.list.Cursor() + (m.list.Paginator.Page * m.list.Paginator.TotalPages)
|
pos := m.list.Cursor() + (m.list.Paginator.Page * m.list.Paginator.TotalPages)
|
||||||
go HandlePlayWithContext(m.commands, &m.album.URI, &pos)
|
go func() {
|
||||||
|
_ = m.commands.PlaySongInPlaylist(&m.album.URI, &pos)
|
||||||
|
}()
|
||||||
case Playlist, SearchPlaylist:
|
case Playlist, SearchPlaylist:
|
||||||
pos := m.list.Cursor() + (m.list.Paginator.Page * m.list.Paginator.PerPage)
|
pos := m.list.Cursor() + (m.list.Paginator.Page * m.list.Paginator.PerPage)
|
||||||
go HandlePlayWithContext(m.commands, &m.playlist.URI, &pos)
|
go func() {
|
||||||
|
_ = m.commands.PlaySongInPlaylist(&m.playlist.URI, &pos)
|
||||||
|
}()
|
||||||
case Tracks:
|
case Tracks:
|
||||||
go HandlePlayLikedSong(m.commands, m.list.Cursor()+(m.list.Paginator.Page*m.list.Paginator.PerPage))
|
go func() {
|
||||||
|
err := m.commands.PlayLikedSongs(m.list.Cursor() + (m.list.Paginator.Page * m.list.Paginator.PerPage))
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
case SearchTracks:
|
case SearchTracks:
|
||||||
go HandlePlayTrack(m.commands, m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.FullTrack).ID)
|
go func() {
|
||||||
|
err := m.commands.QueueSong(m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.FullTrack).ID)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = m.commands.Next(1, false)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
case Devices:
|
case Devices:
|
||||||
go HandleSetDevice(m.commands, m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.PlayerDevice))
|
go func() {
|
||||||
go m.SendMessage("Setting device to "+m.list.SelectedItem().FilterValue(), 2*time.Second)
|
err := m.commands.SetDevice(m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.PlayerDevice).ID)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
} else {
|
||||||
|
m.SendMessage("Setting device to "+m.list.SelectedItem().FilterValue(), 2*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
m.mode = "main"
|
m.mode = "main"
|
||||||
new_items, err := MainView(m.commands)
|
new_items, err := MainView(m.commands)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -654,16 +750,36 @@ func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if msg.String() == ">" {
|
if msg.String() == ">" {
|
||||||
go HandleSeek(m.commands, true)
|
go func() {
|
||||||
|
err := m.commands.Seek(true)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
if msg.String() == "<" {
|
if msg.String() == "<" {
|
||||||
go HandleSeek(m.commands, false)
|
go func() {
|
||||||
|
err := m.commands.Seek(false)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
if msg.String() == "+" {
|
if msg.String() == "+" {
|
||||||
go HandleVolume(m.commands, true)
|
go func() {
|
||||||
|
err := m.commands.ChangeVolume(10)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
if msg.String() == "-" {
|
if msg.String() == "-" {
|
||||||
go HandleVolume(m.commands, false)
|
go func() {
|
||||||
|
err := m.commands.ChangeVolume(-10)
|
||||||
|
if err != nil {
|
||||||
|
m.SendMessage(err.Error(), 5*time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
// search input
|
// search input
|
||||||
if m.input.Focused() {
|
if m.input.Focused() {
|
||||||
@ -769,7 +885,7 @@ func InitMain(c *commands.Commander, mode Mode) (tea.Model, error) {
|
|||||||
mode: mode,
|
mode: mode,
|
||||||
progress: prog,
|
progress: prog,
|
||||||
}
|
}
|
||||||
m.list.Title = "GOSPT"
|
m.list.Title = "GSPOT"
|
||||||
go m.TickPlayback()
|
go m.TickPlayback()
|
||||||
Tick()
|
Tick()
|
||||||
m.list.DisableQuitKeybindings()
|
m.list.DisableQuitKeybindings()
|
||||||
|
@ -3,7 +3,7 @@ package tui
|
|||||||
import (
|
import (
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
|
||||||
"git.asdf.cafe/abs3nt/gospt-ng/src/components/commands"
|
"git.asdf.cafe/abs3nt/gspot/src/components/commands"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StartTea the entry point for the UI. Initializes the model.
|
// StartTea the entry point for the UI. Initializes the model.
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/zmb3/spotify/v2"
|
"github.com/zmb3/spotify/v2"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
"git.asdf.cafe/abs3nt/gospt-ng/src/components/commands"
|
"git.asdf.cafe/abs3nt/gspot/src/components/commands"
|
||||||
)
|
)
|
||||||
|
|
||||||
const regex = `<.*?>`
|
const regex = `<.*?>`
|
||||||
|
@ -94,7 +94,7 @@ func Search(query string) string {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
confDir, _ := os.UserConfigDir()
|
confDir, _ := os.UserConfigDir()
|
||||||
b, err := os.ReadFile(filepath.Join(confDir, "gospt", "client_secret.json"))
|
b, err := os.ReadFile(filepath.Join(confDir, "gspot", "client_secret.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Unable to read client secret file: %v", err)
|
log.Fatalf("Unable to read client secret file: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ import (
|
|||||||
"golang.org/x/exp/slog"
|
"golang.org/x/exp/slog"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
|
||||||
"git.asdf.cafe/abs3nt/gospt-ng/src/config"
|
"git.asdf.cafe/abs3nt/gspot/src/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SpotifyClientResult struct {
|
type SpotifyClientResult struct {
|
||||||
@ -79,8 +79,8 @@ func NewSpotifyClient(conf *config.Config) (c SpotifyClientResult, err error) {
|
|||||||
spotifyauth.ScopeStreaming,
|
spotifyauth.ScopeStreaming,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if _, err := os.Stat(filepath.Join(configDir, "gospt/auth.json")); err == nil {
|
if _, err := os.Stat(filepath.Join(configDir, "gspot/auth.json")); err == nil {
|
||||||
authFilePath := filepath.Join(configDir, "gospt/auth.json")
|
authFilePath := filepath.Join(configDir, "gspot/auth.json")
|
||||||
authFile, err := os.Open(authFilePath)
|
authFile, err := os.Open(authFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return SpotifyClientResult{}, err
|
return SpotifyClientResult{}, err
|
||||||
@ -157,7 +157,7 @@ func completeAuth(w http.ResponseWriter, r *http.Request) {
|
|||||||
slog.Error("AUTHENTICATOR", "failed to unmarshal", err)
|
slog.Error("AUTHENTICATOR", "failed to unmarshal", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
err = os.WriteFile(filepath.Join(configDir, "gospt/auth.json"), out, 0o600)
|
err = os.WriteFile(filepath.Join(configDir, "gspot/auth.json"), out, 0o600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("AUTHENTICATOR", "failed to save auth", err)
|
slog.Error("AUTHENTICATOR", "failed to save auth", err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user