make code less bad
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
abs3nt 2023-04-06 18:11:06 -07:00
parent 55f9c73966
commit 2fbeb6d21a
Signed by: abs3nt
GPG Key ID: FDC6662313FA9386
8 changed files with 202 additions and 144 deletions

87
.golangci.yml Normal file
View File

@ -0,0 +1,87 @@
run:
deadline: 10m
skip-dirs:
- hack
linters:
disable-all: true
enable:
- gofmt
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- gocritic
- bodyclose
- gosec
- prealloc
- unconvert
- unused
linters-settings:
gocritic:
# Which checks should be enabled; can't be combined with 'disabled-checks';
# See https://go-critic.github.io/overview#checks-overview
# To check which checks are enabled run `GL_DEBUG=gocritic ./build/bin/golangci-lint run`
# By default list of stable checks is used.
enabled-checks:
- ruleguard
- truncateCmp
# Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty
disabled-checks:
- captLocal
- assignOp
- paramTypeCombine
- importShadow
- commentFormatting
- rangeValCopy
# Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks.
# Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags".
enabled-tags:
- performance
- diagnostic
- opinionated
disabled-tags:
- experimental
settings:
hugeParam:
# size in bytes that makes the warning trigger (default 80)
sizeThreshold: 1000
rangeExprCopy:
# size in bytes that makes the warning trigger (default 512)
sizeThreshold: 512
# whether to check test functions (default true)
skipTestFuncs: true
truncateCmp:
# whether to skip int/uint/uintptr types (default true)
skipArchDependent: true
underef:
# whether to skip (*x).method() calls where x is a pointer receiver (default true)
skipRecvDeref: true
govet:
disable:
- deepequalerrors
- fieldalignment
- shadow
- unsafeptr
goconst:
min-len: 2
min-occurrences: 2
gofmt:
auto-fix: false
issues:
exclude-rules:
- linters:
- golint
text: "should be"
- linters:
- errcheck
text: "not checked"
- linters:
- staticcheck
text: "SA(1019|1029|5011)"

View File

@ -8,6 +8,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"time"
"tuxpa.in/a/zlog/log" "tuxpa.in/a/zlog/log"
@ -91,7 +92,7 @@ func GetClient(ctx *gctx.Context) (*spotify.Client, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = os.WriteFile(authFilePath, out, 0o644) err = os.WriteFile(authFilePath, out, 0o600)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to save auth") return nil, fmt.Errorf("failed to save auth")
} }
@ -102,8 +103,12 @@ func GetClient(ctx *gctx.Context) (*spotify.Client, error) {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
log.Println("Got request for:", r.URL.String()) log.Println("Got request for:", r.URL.String())
}) })
server := &http.Server{
Addr: fmt.Sprintf(":%s", config.Values.Port),
ReadHeaderTimeout: 5 * time.Second,
}
go func() { go func() {
err := http.ListenAndServe(fmt.Sprintf(":%s", config.Values.Port), nil) err := server.ListenAndServe()
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -115,6 +120,7 @@ func GetClient(ctx *gctx.Context) (*spotify.Client, error) {
// wait for auth to complete // wait for auth to complete
client := <-ch client := <-ch
server.Shutdown(ctx)
// use the client to make calls that require authorization // use the client to make calls that require authorization
user, err := client.CurrentUser(ctx) user, err := client.CurrentUser(ctx)
if err != nil { if err != nil {
@ -137,7 +143,7 @@ func completeAuth(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
panic(err.Error()) panic(err.Error())
} }
err = os.WriteFile(filepath.Join(configDir, "gospt/auth.json"), out, 0o644) err = os.WriteFile(filepath.Join(configDir, "gospt/auth.json"), out, 0o600)
if err != nil { if err != nil {
panic("FAILED TO SAVE AUTH") panic("FAILED TO SAVE AUTH")
} }

2
src/cache/cache.go vendored
View File

@ -42,7 +42,7 @@ func (c *Cache) save(m map[string]CacheEntry) error {
return err return err
} }
log.Trace().Str("tosave", string(payload)).Msg("saving cache") log.Trace().Str("tosave", string(payload)).Msg("saving cache")
err = os.WriteFile(c.Root, payload, 0640) err = os.WriteFile(c.Root, payload, 0o600)
if err != nil { if err != nil {
return err return err
} }

View File

@ -21,11 +21,10 @@ import (
var ( var (
// Used for flags. // Used for flags.
ctx *gctx.Context ctx *gctx.Context
commands *cmds.Commands commands *cmds.Commands
cfgFile string cfgFile string
userLicense string verbose bool
verbose bool
rootCmd = &cobra.Command{ rootCmd = &cobra.Command{
Use: "gospt", Use: "gospt",
@ -90,7 +89,12 @@ func initConfig() {
} }
if config.Values.ClientSecretCmd != "" { if config.Values.ClientSecretCmd != "" {
args := strings.Fields(config.Values.ClientSecretCmd) args := strings.Fields(config.Values.ClientSecretCmd)
secret, err := exec.Command(args[0], args[1:]...).Output() cmd := args[0]
secret_command := exec.Command(cmd)
if len(args) > 1 {
secret_command.Args = args
}
secret, err := secret_command.Output()
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -531,7 +531,7 @@ func (c *Commands) RadioGivenSong(ctx *gctx.Context, song spotify.SimpleTrack, p
func (c *Commands) SongExists(db *sql.DB, song spotify.ID) (bool, error) { func (c *Commands) SongExists(db *sql.DB, song spotify.ID) (bool, error) {
song_id := string(song) song_id := string(song)
sqlStmt := `SELECT id FROM radio WHERE id = ?` sqlStmt := `SELECT id FROM radio WHERE id = ?`
err := db.QueryRow(sqlStmt, string(song_id)).Scan(&song_id) err := db.QueryRow(sqlStmt, song_id).Scan(&song_id)
if err != nil { if err != nil {
if err != sql.ErrNoRows { if err != sql.ErrNoRows {
return false, err return false, err
@ -563,15 +563,12 @@ func (c *Commands) Radio(ctx *gctx.Context) error {
return err return err
} }
seed_song = tracks.Tracks[frand.Intn(len(tracks.Tracks))].SimpleTrack seed_song = tracks.Tracks[frand.Intn(len(tracks.Tracks))].SimpleTrack
} else { } else if !current_song.Playing {
if !current_song.Playing { tracks, err := c.Client().CurrentUsersTracks(ctx, spotify.Limit(10))
if err != nil {
tracks, err := c.Client().CurrentUsersTracks(ctx, spotify.Limit(10)) return err
if err != nil {
return err
}
seed_song = tracks.Tracks[frand.Intn(len(tracks.Tracks))].SimpleTrack
} }
seed_song = tracks.Tracks[frand.Intn(len(tracks.Tracks))].SimpleTrack
} }
return c.RadioGivenSong(ctx, seed_song, current_song.Progress) return c.RadioGivenSong(ctx, seed_song, current_song.Progress)
} }
@ -587,6 +584,7 @@ func (c *Commands) RefillRadio(ctx *gctx.Context) error {
to_remove := []spotify.ID{} to_remove := []spotify.ID{}
radioPlaylist, db, err := c.GetRadioPlaylist(ctx, "") radioPlaylist, db, err := c.GetRadioPlaylist(ctx, "")
if err != nil { if err != nil {
return err
} }
if status.PlaybackContext.URI != radioPlaylist.URI { if status.PlaybackContext.URI != radioPlaylist.URI {
@ -598,20 +596,17 @@ func (c *Commands) RefillRadio(ctx *gctx.Context) error {
return fmt.Errorf("orig playlist items: %w", err) return fmt.Errorf("orig playlist items: %w", err)
} }
found := false
page := 0 page := 0
for !found { for {
tracks, err := c.Client().GetPlaylistItems(ctx, radioPlaylist.ID, spotify.Limit(50), spotify.Offset(page*50)) tracks, err := c.Client().GetPlaylistItems(ctx, radioPlaylist.ID, spotify.Limit(50), spotify.Offset(page*50))
if err != nil { if err != nil {
return fmt.Errorf("tracks: %w", err) return fmt.Errorf("tracks: %w", err)
} }
if len(tracks.Items) == 0 { if len(tracks.Items) == 0 {
found = true
break break
} }
for _, track := range tracks.Items { for _, track := range tracks.Items {
if track.Track.Track.ID == status.Item.ID { if track.Track.Track.ID == status.Item.ID {
found = true
break break
} }
to_remove = append(to_remove, track.Track.Track.ID) to_remove = append(to_remove, track.Track.Track.ID)
@ -630,7 +625,7 @@ func (c *Commands) RefillRadio(ctx *gctx.Context) error {
return fmt.Errorf("error clearing playlist: %w", err) return fmt.Errorf("error clearing playlist: %w", err)
} }
} }
_, err = c.Client().RemoveTracksFromPlaylist(ctx, radioPlaylist.ID, trackGroups...) c.Client().RemoveTracksFromPlaylist(ctx, radioPlaylist.ID, trackGroups...)
} }
to_add := 500 - (playlistItems.Total - len(to_remove)) to_add := 500 - (playlistItems.Total - len(to_remove))
@ -642,7 +637,7 @@ func (c *Commands) RefillRadio(ctx *gctx.Context) error {
pages := int(math.Ceil(float64(total) / 50)) pages := int(math.Ceil(float64(total) / 50))
randomPage := 1 randomPage := 1
if pages > 1 { if pages > 1 {
randomPage = frand.Intn(int(pages-1)) + 1 randomPage = frand.Intn(pages-1) + 1
} }
playlistPage, err := c.Client().GetPlaylistItems(ctx, radioPlaylist.ID, spotify.Limit(50), spotify.Offset((randomPage-1)*50)) playlistPage, err := c.Client().GetPlaylistItems(ctx, radioPlaylist.ID, spotify.Limit(50), spotify.Offset((randomPage-1)*50))
if err != nil { if err != nil {
@ -684,6 +679,9 @@ func (c *Commands) RefillRadio(ctx *gctx.Context) error {
break break
} }
_, err = db.QueryContext(ctx, fmt.Sprintf("INSERT INTO radio (id) VALUES('%s')", rec.String())) _, err = db.QueryContext(ctx, fmt.Sprintf("INSERT INTO radio (id) VALUES('%s')", rec.String()))
if err != nil {
return err
}
queue = append(queue, rec) queue = append(queue, rec)
} }
to_add -= len(queue) to_add -= len(queue)
@ -825,8 +823,8 @@ func (c *Commands) Next(ctx *gctx.Context, amt int) error {
case "playlist": case "playlist":
found := false found := false
currentTrackIndex := 0 currentTrackIndex := 0
page := 1
for !found { for !found {
page := 1
playlist, err := c.Client().GetPlaylistItems(ctx, spotify.ID(strings.Split(string(current.PlaybackContext.URI), ":")[2]), spotify.Limit(50), spotify.Offset((page-1)*50)) playlist, err := c.Client().GetPlaylistItems(ctx, spotify.ID(strings.Split(string(current.PlaybackContext.URI), ":")[2]), spotify.Limit(50), spotify.Offset((page-1)*50))
if err != nil { if err != nil {
return err return err
@ -850,8 +848,8 @@ func (c *Commands) Next(ctx *gctx.Context, amt int) error {
case "album": case "album":
found := false found := false
currentTrackIndex := 0 currentTrackIndex := 0
page := 1
for !found { for !found {
page := 1
playlist, err := c.Client().GetAlbumTracks(ctx, spotify.ID(strings.Split(string(current.PlaybackContext.URI), ":")[2]), spotify.Limit(50), spotify.Offset((page-1)*50)) playlist, err := c.Client().GetAlbumTracks(ctx, spotify.ID(strings.Split(string(current.PlaybackContext.URI), ":")[2]), spotify.Limit(50), spotify.Offset((page-1)*50))
if err != nil { if err != nil {
return err return err
@ -903,9 +901,6 @@ func (c *Commands) Status(ctx *gctx.Context) error {
if err != nil { if err != nil {
return err return err
} }
if err != nil {
return err
}
fmt.Println(state) fmt.Println(state)
return nil return nil
} }
@ -923,7 +918,7 @@ func (c *Commands) LinkContext(ctx *gctx.Context) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
return string(state.PlaybackContext.ExternalURLs["spotify"]), nil return state.PlaybackContext.ExternalURLs["spotify"], nil
} }
func (c *Commands) NowPlaying(ctx *gctx.Context) error { func (c *Commands) NowPlaying(ctx *gctx.Context) error {
@ -953,7 +948,7 @@ func FormatSong(current *spotify.CurrentlyPlaying) string {
func (c *Commands) Shuffle(ctx *gctx.Context) error { func (c *Commands) Shuffle(ctx *gctx.Context) error {
state, err := c.Client().PlayerState(ctx) state, err := c.Client().PlayerState(ctx)
if err != nil { if err != nil {
return fmt.Errorf("Failed to get current playstate") return fmt.Errorf("failed to get current playstate")
} }
err = c.Client().Shuffle(ctx, !state.ShuffleState) err = c.Client().Shuffle(ctx, !state.ShuffleState)
if err != nil { if err != nil {
@ -966,7 +961,7 @@ func (c *Commands) Shuffle(ctx *gctx.Context) error {
func (c *Commands) Repeat(ctx *gctx.Context) error { func (c *Commands) Repeat(ctx *gctx.Context) error {
state, err := c.Client().PlayerState(ctx) state, err := c.Client().PlayerState(ctx)
if err != nil { if err != nil {
return fmt.Errorf("Failed to get current playstate") return fmt.Errorf("failed to get current playstate")
} }
newState := "off" newState := "off"
if state.RepeatState == "off" { if state.RepeatState == "off" {
@ -1012,7 +1007,7 @@ func (c *Commands) PrintPlaying(current *spotify.CurrentlyPlaying) error {
if !current.Playing { if !current.Playing {
icon = "⏸" icon = "⏸"
} }
fmt.Println(fmt.Sprintf("%s %s - %s", icon, current.Item.Name, current.Item.Artists[0].Name)) fmt.Printf("%s %s - %s\n", icon, current.Item.Name, current.Item.Artists[0].Name)
return nil return nil
} }
@ -1031,7 +1026,7 @@ func (c *Commands) SetDevice(ctx *gctx.Context, device spotify.PlayerDevice) err
return err return err
} }
configDir, _ := os.UserConfigDir() configDir, _ := os.UserConfigDir()
err = os.WriteFile(filepath.Join(configDir, "gospt/device.json"), out, 0o644) err = os.WriteFile(filepath.Join(configDir, "gospt/device.json"), out, 0o600)
if err != nil { if err != nil {
return err return err
} }
@ -1049,12 +1044,12 @@ func isNoActiveError(err error) bool {
func (c *Commands) RadioFromPlaylist(ctx *gctx.Context, playlist spotify.SimplePlaylist) error { func (c *Commands) RadioFromPlaylist(ctx *gctx.Context, playlist spotify.SimplePlaylist) error {
total := playlist.Tracks.Total total := playlist.Tracks.Total
if total == 0 { if total == 0 {
return fmt.Errorf("This playlist is empty") return fmt.Errorf("this playlist is empty")
} }
pages := int(math.Ceil(float64(total) / 50)) pages := int(math.Ceil(float64(total) / 50))
randomPage := 1 randomPage := 1
if pages > 1 { if pages > 1 {
randomPage = frand.Intn(int(pages-1)) + 1 randomPage = frand.Intn(pages-1) + 1
} }
playlistPage, err := c.Client().GetPlaylistItems(ctx, playlist.ID, spotify.Limit(50), spotify.Offset((randomPage-1)*50)) playlistPage, err := c.Client().GetPlaylistItems(ctx, playlist.ID, spotify.Limit(50), spotify.Offset((randomPage-1)*50))
if err != nil { if err != nil {
@ -1083,12 +1078,12 @@ func (c *Commands) RadioFromAlbum(ctx *gctx.Context, album spotify.SimpleAlbum)
} }
total := tracks.Total total := tracks.Total
if total == 0 { if total == 0 {
return fmt.Errorf("This playlist is empty") return fmt.Errorf("this playlist is empty")
} }
pages := int(math.Ceil(float64(total) / 50)) pages := int(math.Ceil(float64(total) / 50))
randomPage := 1 randomPage := 1
if pages > 1 { if pages > 1 {
randomPage = frand.Intn(int(pages-1)) + 1 randomPage = frand.Intn(pages-1) + 1
} }
albumTrackPage, err := c.AlbumTracks(ctx, album.ID, randomPage) albumTrackPage, err := c.AlbumTracks(ctx, album.ID, randomPage)
if err != nil { if err != nil {
@ -1116,12 +1111,12 @@ func (c *Commands) RadioFromSavedTracks(ctx *gctx.Context) error {
return err return err
} }
if savedSongs.Total == 0 { if savedSongs.Total == 0 {
return fmt.Errorf("You have no saved songs") return fmt.Errorf("you have no saved songs")
} }
pages := int(math.Ceil(float64(savedSongs.Total) / 50)) pages := int(math.Ceil(float64(savedSongs.Total) / 50))
randomPage := 1 randomPage := 1
if pages > 1 { if pages > 1 {
randomPage = frand.Intn(int(pages-1)) + 1 randomPage = frand.Intn(pages-1) + 1
} }
trackPage, err := c.Client().CurrentUsersTracks(ctx, spotify.Limit(50), spotify.Offset(randomPage*50)) trackPage, err := c.Client().CurrentUsersTracks(ctx, spotify.Limit(50), spotify.Offset(randomPage*50))
if err != nil { if err != nil {
@ -1261,29 +1256,6 @@ func (c *Commands) activateDevice(ctx *gctx.Context) (spotify.ID, error) {
return device.ID, nil return device.ID, nil
} }
func (c *Commands) getDefaultDevice(ctx *gctx.Context) (spotify.ID, error) {
configDir, _ := os.UserConfigDir()
if _, err := os.Stat(filepath.Join(configDir, "gospt/device.json")); err == nil {
deviceFile, err := os.Open(filepath.Join(configDir, "gospt/device.json"))
if err != nil {
return "", err
}
defer deviceFile.Close()
deviceValue, err := io.ReadAll(deviceFile)
if err != nil {
return "", err
}
var device *spotify.PlayerDevice
err = json.Unmarshal(deviceValue, &device)
if err != nil {
return "", err
}
return device.ID, nil
} else {
return "", err
}
}
func (c *Commands) GetRadioPlaylist(ctx *gctx.Context, name string) (*spotify.FullPlaylist, *sql.DB, error) { func (c *Commands) GetRadioPlaylist(ctx *gctx.Context, 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, "gospt/radio.json"))
@ -1299,6 +1271,9 @@ func (c *Commands) GetRadioPlaylist(ctx *gctx.Context, name string) (*spotify.Fu
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, "gospt/radio.db"))
if err != nil {
return nil, nil, err
}
return playlist, db, nil return playlist, db, nil
} }
@ -1313,11 +1288,14 @@ func (c *Commands) CreateRadioPlaylist(ctx *gctx.Context, name string) (*spotify
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
err = os.WriteFile(filepath.Join(configDir, "gospt/radio.json"), raw, 0o644) err = os.WriteFile(filepath.Join(configDir, "gospt/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, "gospt/radio.db"))
if err != nil {
return nil, nil, err
}
db.QueryContext(ctx, "DROP TABLE IF EXISTS radio") db.QueryContext(ctx, "DROP TABLE IF EXISTS radio")
db.QueryContext(ctx, "CREATE TABLE IF NOT EXISTS radio (id string PRIMARY KEY)") db.QueryContext(ctx, "CREATE TABLE IF NOT EXISTS radio (id string PRIMARY KEY)")
return playlist, db, nil return playlist, db, nil

View File

@ -8,8 +8,7 @@ import (
) )
func HandlePlayWithContext(ctx *gctx.Context, commands *commands.Commands, uri *spotify.URI, pos int) { func HandlePlayWithContext(ctx *gctx.Context, commands *commands.Commands, uri *spotify.URI, pos int) {
var err error err := commands.PlaySongInPlaylist(ctx, uri, pos)
err = commands.PlaySongInPlaylist(ctx, uri, pos)
if err != nil { if err != nil {
return return
} }
@ -94,8 +93,7 @@ func HandlePlayTrack(ctx *gctx.Context, commands *commands.Commands, track spoti
} }
func HandleSetDevice(ctx *gctx.Context, commands *commands.Commands, player spotify.PlayerDevice) { func HandleSetDevice(ctx *gctx.Context, commands *commands.Commands, player spotify.PlayerDevice) {
var err error err := commands.SetDevice(ctx, player)
err = commands.SetDevice(ctx, player)
if err != nil { if err != nil {
return return
} }

View File

@ -31,24 +31,24 @@ type Mode string
const ( const (
Album Mode = "album" Album Mode = "album"
ArtistAlbum = "artistalbum" ArtistAlbum Mode = "artistalbum"
Artist = "artist" Artist Mode = "artist"
Artists = "artists" Artists Mode = "artists"
Tracks = "tracks" Tracks Mode = "tracks"
Albums = "albums" Albums Mode = "albums"
Main = "main" Main Mode = "main"
Playlists = "playlists" Playlists Mode = "playlists"
Playlist = "playlist" Playlist Mode = "playlist"
Devices = "devices" Devices Mode = "devices"
Search = "search" Search Mode = "search"
SearchAlbums = "searchalbums" SearchAlbums Mode = "searchalbums"
SearchAlbum = "searchalbum" SearchAlbum Mode = "searchalbum"
SearchArtists = "searchartists" SearchArtists Mode = "searchartists"
SearchArtist = "searchartist" SearchArtist Mode = "searchartist"
SearchArtistAlbum = "searchartistalbum" SearchArtistAlbum Mode = "searchartistalbum"
SearchTracks = "searchtracks" SearchTracks Mode = "searchtracks"
SearchPlaylists = "searchplaylsits" SearchPlaylists Mode = "searchplaylsits"
SearchPlaylist = "searchplaylist" SearchPlaylist Mode = "searchplaylist"
) )
type mainItem struct { type mainItem struct {
@ -90,36 +90,36 @@ type mainModel struct {
func (m *mainModel) PlayRadio() { func (m *mainModel) PlayRadio() {
m.list.NewStatusMessage("Starting radio for " + m.list.SelectedItem().(mainItem).Title()) m.list.NewStatusMessage("Starting radio for " + m.list.SelectedItem().(mainItem).Title())
selectedItem := m.list.SelectedItem().(mainItem).SpotifyItem selectedItem := m.list.SelectedItem().(mainItem).SpotifyItem
switch selectedItem.(type) { switch item := selectedItem.(type) {
case spotify.SimplePlaylist: case spotify.SimplePlaylist:
go HandlePlaylistRadio(m.ctx, m.commands, selectedItem.(spotify.SimplePlaylist)) go HandlePlaylistRadio(m.ctx, m.commands, item)
return return
case *spotify.SavedTrackPage: case *spotify.SavedTrackPage:
go HandleLibraryRadio(m.ctx, m.commands) go HandleLibraryRadio(m.ctx, m.commands)
return return
case spotify.SimpleAlbum: case spotify.SimpleAlbum:
go HandleAlbumRadio(m.ctx, m.commands, selectedItem.(spotify.SimpleAlbum)) go HandleAlbumRadio(m.ctx, m.commands, item)
return return
case spotify.FullAlbum: case spotify.FullAlbum:
go HandleAlbumRadio(m.ctx, m.commands, selectedItem.(spotify.FullAlbum).SimpleAlbum) go HandleAlbumRadio(m.ctx, m.commands, item.SimpleAlbum)
return return
case spotify.SimpleArtist: case spotify.SimpleArtist:
go HandleArtistRadio(m.ctx, m.commands, selectedItem.(spotify.SimpleArtist)) go HandleArtistRadio(m.ctx, m.commands, item)
return return
case spotify.FullArtist: case spotify.FullArtist:
go HandleArtistRadio(m.ctx, m.commands, selectedItem.(spotify.FullArtist).SimpleArtist) go HandleArtistRadio(m.ctx, m.commands, item.SimpleArtist)
return return
case spotify.SimpleTrack: case spotify.SimpleTrack:
go HandleRadio(m.ctx, m.commands, selectedItem.(spotify.SimpleTrack)) go HandleRadio(m.ctx, m.commands, item)
return return
case spotify.FullTrack: case spotify.FullTrack:
go HandleRadio(m.ctx, m.commands, selectedItem.(spotify.FullTrack).SimpleTrack) go HandleRadio(m.ctx, m.commands, item.SimpleTrack)
return return
case spotify.PlaylistTrack: case spotify.PlaylistTrack:
go HandleRadio(m.ctx, m.commands, selectedItem.(spotify.PlaylistTrack).Track.SimpleTrack) go HandleRadio(m.ctx, m.commands, item.Track.SimpleTrack)
return return
case spotify.SavedTrack: case spotify.SavedTrack:
go HandleRadio(m.ctx, m.commands, selectedItem.(spotify.SavedTrack).SimpleTrack) go HandleRadio(m.ctx, m.commands, item.SimpleTrack)
return return
} }
} }
@ -132,6 +132,7 @@ func (m *mainModel) GoBack() (tea.Cmd, error) {
m.mode = Main m.mode = Main
new_items, err := MainView(m.ctx, m.commands) new_items, err := MainView(m.ctx, m.commands)
if err != nil { if err != nil {
return nil, err
} }
m.list.SetItems(new_items) m.list.SetItems(new_items)
case Album: case Album:
@ -203,36 +204,36 @@ type SpotifyUrl struct {
func (m *mainModel) CopyToClipboard() error { func (m *mainModel) CopyToClipboard() error {
item := m.list.SelectedItem().(mainItem).SpotifyItem item := m.list.SelectedItem().(mainItem).SpotifyItem
switch item.(type) { switch converted := item.(type) {
case spotify.SimplePlaylist: case spotify.SimplePlaylist:
clipboard.WriteAll(item.(spotify.SimplePlaylist).ExternalURLs["spotify"]) clipboard.WriteAll(converted.ExternalURLs["spotify"])
m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title()) m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title())
case *spotify.FullPlaylist: case *spotify.FullPlaylist:
clipboard.WriteAll(item.(*spotify.FullPlaylist).ExternalURLs["spotify"]) clipboard.WriteAll(converted.ExternalURLs["spotify"])
m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title()) m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title())
case spotify.SimpleAlbum: case spotify.SimpleAlbum:
clipboard.WriteAll(item.(spotify.SimpleAlbum).ExternalURLs["spotify"]) clipboard.WriteAll(converted.ExternalURLs["spotify"])
m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title()) m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title())
case *spotify.FullAlbum: case *spotify.FullAlbum:
clipboard.WriteAll(item.(*spotify.FullAlbum).ExternalURLs["spotify"]) clipboard.WriteAll(converted.ExternalURLs["spotify"])
m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title()) m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title())
case spotify.SimpleArtist: case spotify.SimpleArtist:
clipboard.WriteAll(item.(spotify.SimpleArtist).ExternalURLs["spotify"]) clipboard.WriteAll(converted.ExternalURLs["spotify"])
m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title()) m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title())
case *spotify.FullArtist: case *spotify.FullArtist:
clipboard.WriteAll(item.(*spotify.FullArtist).ExternalURLs["spotify"]) clipboard.WriteAll(converted.ExternalURLs["spotify"])
m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title()) m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title())
case spotify.SimpleTrack: case spotify.SimpleTrack:
clipboard.WriteAll(item.(spotify.SimpleTrack).ExternalURLs["spotify"]) clipboard.WriteAll(converted.ExternalURLs["spotify"])
m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title()) m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title())
case spotify.PlaylistTrack: case spotify.PlaylistTrack:
clipboard.WriteAll(item.(spotify.PlaylistTrack).Track.ExternalURLs["spotify"]) clipboard.WriteAll(converted.Track.ExternalURLs["spotify"])
m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title()) m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title())
case spotify.SavedTrack: case spotify.SavedTrack:
clipboard.WriteAll(item.(spotify.SavedTrack).ExternalURLs["spotify"]) clipboard.WriteAll(converted.ExternalURLs["spotify"])
m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title()) m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title())
case spotify.FullTrack: case spotify.FullTrack:
clipboard.WriteAll(item.(spotify.FullTrack).ExternalURLs["spotify"]) clipboard.WriteAll(converted.ExternalURLs["spotify"])
m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title()) m.list.NewStatusMessage("Copying link to " + m.list.SelectedItem().(mainItem).Title())
} }
return nil return nil
@ -241,10 +242,10 @@ func (m *mainModel) CopyToClipboard() error {
func (m *mainModel) SelectItem() error { func (m *mainModel) SelectItem() error {
switch m.mode { switch m.mode {
case Search: case Search:
switch m.list.SelectedItem().(mainItem).SpotifyItem.(type) { switch item := m.list.SelectedItem().(mainItem).SpotifyItem.(type) {
case *spotify.FullArtistPage: case *spotify.FullArtistPage:
m.mode = SearchArtists m.mode = SearchArtists
new_items, err := SearchArtistsView(m.ctx, m.commands, m.list.SelectedItem().(mainItem).SpotifyItem.(*spotify.FullArtistPage)) new_items, err := SearchArtistsView(m.ctx, m.commands, item)
if err != nil { if err != nil {
return err return err
} }
@ -252,7 +253,7 @@ func (m *mainModel) SelectItem() error {
m.list.ResetSelected() m.list.ResetSelected()
case *spotify.SimpleAlbumPage: case *spotify.SimpleAlbumPage:
m.mode = SearchAlbums m.mode = SearchAlbums
new_items, err := SearchAlbumsView(m.ctx, m.commands, m.list.SelectedItem().(mainItem).SpotifyItem.(*spotify.SimpleAlbumPage)) new_items, err := SearchAlbumsView(m.ctx, m.commands, item)
if err != nil { if err != nil {
return err return err
} }
@ -260,8 +261,7 @@ func (m *mainModel) SelectItem() error {
m.list.ResetSelected() m.list.ResetSelected()
case *spotify.SimplePlaylistPage: case *spotify.SimplePlaylistPage:
m.mode = SearchPlaylists m.mode = SearchPlaylists
playlists := m.list.SelectedItem().(mainItem).SpotifyItem.(*spotify.SimplePlaylistPage) new_items, err := SearchPlaylistsView(m.ctx, m.commands, item)
new_items, err := SearchPlaylistsView(m.ctx, m.commands, playlists)
if err != nil { if err != nil {
return err return err
} }
@ -269,7 +269,7 @@ func (m *mainModel) SelectItem() error {
m.list.ResetSelected() m.list.ResetSelected()
case *spotify.FullTrackPage: case *spotify.FullTrackPage:
m.mode = SearchTracks m.mode = SearchTracks
new_items, err := SearchTracksView(m.ctx, m.commands, m.list.SelectedItem().(mainItem).SpotifyItem.(*spotify.FullTrackPage)) new_items, err := SearchTracksView(m.ctx, m.commands, item)
if err != nil { if err != nil {
return err return err
} }
@ -314,7 +314,7 @@ func (m *mainModel) SelectItem() error {
m.list.SetItems(new_items) m.list.SetItems(new_items)
m.list.ResetSelected() m.list.ResetSelected()
case Main: case Main:
switch m.list.SelectedItem().(mainItem).SpotifyItem.(type) { switch item := m.list.SelectedItem().(mainItem).SpotifyItem.(type) {
case *spotify.FullArtistCursorPage: case *spotify.FullArtistCursorPage:
m.mode = Artists m.mode = Artists
new_items, err := ArtistsView(m.ctx, m.commands) new_items, err := ArtistsView(m.ctx, m.commands)
@ -333,9 +333,8 @@ func (m *mainModel) SelectItem() error {
m.list.ResetSelected() m.list.ResetSelected()
case spotify.SimplePlaylist: case spotify.SimplePlaylist:
m.mode = Playlist m.mode = Playlist
playlist := m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimplePlaylist) m.playlist = item
m.playlist = playlist new_items, err := PlaylistView(m.ctx, m.commands, item)
new_items, err := PlaylistView(m.ctx, m.commands, playlist)
if err != nil { if err != nil {
return err return err
} }
@ -399,7 +398,7 @@ func (m *mainModel) SelectItem() error {
return nil return nil
} }
func (m mainModel) Init() tea.Cmd { func (m *mainModel) Init() tea.Cmd {
main_updates = make(chan *mainModel) main_updates = make(chan *mainModel)
return Tick() return Tick()
} }
@ -437,7 +436,7 @@ func (m *mainModel) TickPlayback() {
}() }()
} }
func (m mainModel) View() string { func (m *mainModel) View() string {
if m.input.Focused() { if m.input.Focused() {
return DocStyle.Render(m.list.View() + "\n" + m.input.View()) return DocStyle.Render(m.list.View() + "\n" + m.input.View())
} }
@ -497,7 +496,7 @@ func (m *mainModel) getContext(playing *spotify.CurrentlyPlaying) (string, error
return "", nil return "", nil
} }
func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Update list items from LoadMore // Update list items from LoadMore
select { select {
case update := <-main_updates: case update := <-main_updates:
@ -647,7 +646,7 @@ func InitMain(ctx *gctx.Context, c *commands.Commands, mode Mode) (tea.Model, er
return nil, err return nil, err
} }
} }
m := mainModel{ m := &mainModel{
list: list.New(items, list.NewDefaultDelegate(), 0, 0), list: list.New(items, list.NewDefaultDelegate(), 0, 0),
ctx: ctx, ctx: ctx,
commands: c, commands: c,

View File

@ -84,27 +84,13 @@ func SearchView(ctx *gctx.Context, commands *commands.Commands, search string) (
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
items = append(items, mainItem{ items = append(
Name: "Tracks", items,
Desc: "Search results", mainItem{Name: "Tracks", Desc: "Search results", SpotifyItem: result.Tracks},
SpotifyItem: result.Tracks, mainItem{Name: "Albums", Desc: "Search results", SpotifyItem: result.Albums},
}) mainItem{Name: "Artists", Desc: "Search results", SpotifyItem: result.Artists},
items = append(items, mainItem{ mainItem{Name: "Playlists", Desc: "Search results", SpotifyItem: result.Playlists},
Name: "Albums", )
Desc: "Search results",
SpotifyItem: result.Albums,
})
items = append(items, mainItem{
Name: "Artists",
Desc: "Search results",
SpotifyItem: result.Artists,
})
items = append(items, mainItem{
Name: "Playlists",
Desc: "Search results",
SpotifyItem: result.Playlists,
})
results := &SearchResults{ results := &SearchResults{
Tracks: result.Tracks, Tracks: result.Tracks,
Playlists: result.Playlists, Playlists: result.Playlists,
@ -149,7 +135,7 @@ func SearchAlbumsView(ctx *gctx.Context, commands *commands.Commands, albums *sp
items = append(items, mainItem{ items = append(items, mainItem{
Name: album.Name, Name: album.Name,
ID: album.ID, ID: album.ID,
Desc: fmt.Sprintf("%s, %d", album.Artists[0].Name, album.ReleaseDateTime()), Desc: fmt.Sprintf("%s, %s", album.Artists[0].Name, album.ReleaseDateTime().String()),
SpotifyItem: album, SpotifyItem: album,
}) })
} }