diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..f15b958 --- /dev/null +++ b/.golangci.yml @@ -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)" diff --git a/src/auth/auth.go b/src/auth/auth.go index 21ff4d8..1316c0e 100644 --- a/src/auth/auth.go +++ b/src/auth/auth.go @@ -8,6 +8,7 @@ import ( "os" "os/exec" "path/filepath" + "time" "tuxpa.in/a/zlog/log" @@ -91,7 +92,7 @@ func GetClient(ctx *gctx.Context) (*spotify.Client, error) { if err != nil { return nil, err } - err = os.WriteFile(authFilePath, out, 0o644) + err = os.WriteFile(authFilePath, out, 0o600) if err != nil { 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) { log.Println("Got request for:", r.URL.String()) }) + server := &http.Server{ + Addr: fmt.Sprintf(":%s", config.Values.Port), + ReadHeaderTimeout: 5 * time.Second, + } go func() { - err := http.ListenAndServe(fmt.Sprintf(":%s", config.Values.Port), nil) + err := server.ListenAndServe() if err != nil { panic(err) } @@ -115,6 +120,7 @@ func GetClient(ctx *gctx.Context) (*spotify.Client, error) { // wait for auth to complete client := <-ch + server.Shutdown(ctx) // use the client to make calls that require authorization user, err := client.CurrentUser(ctx) if err != nil { @@ -137,7 +143,7 @@ func completeAuth(w http.ResponseWriter, r *http.Request) { if err != nil { 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 { panic("FAILED TO SAVE AUTH") } diff --git a/src/cache/cache.go b/src/cache/cache.go index afd8005..51e4dc4 100644 --- a/src/cache/cache.go +++ b/src/cache/cache.go @@ -42,7 +42,7 @@ func (c *Cache) save(m map[string]CacheEntry) error { return err } 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 { return err } diff --git a/src/cmd/root.go b/src/cmd/root.go index 4b3b462..3263c61 100644 --- a/src/cmd/root.go +++ b/src/cmd/root.go @@ -21,11 +21,10 @@ import ( var ( // Used for flags. - ctx *gctx.Context - commands *cmds.Commands - cfgFile string - userLicense string - verbose bool + ctx *gctx.Context + commands *cmds.Commands + cfgFile string + verbose bool rootCmd = &cobra.Command{ Use: "gospt", @@ -90,7 +89,12 @@ func initConfig() { } if 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 { panic(err) } diff --git a/src/commands/commands.go b/src/commands/commands.go index 568618c..1603b9f 100644 --- a/src/commands/commands.go +++ b/src/commands/commands.go @@ -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) { song_id := string(song) 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 != sql.ErrNoRows { return false, err @@ -563,15 +563,12 @@ func (c *Commands) Radio(ctx *gctx.Context) error { return err } seed_song = tracks.Tracks[frand.Intn(len(tracks.Tracks))].SimpleTrack - } else { - if !current_song.Playing { - - tracks, err := c.Client().CurrentUsersTracks(ctx, spotify.Limit(10)) - if err != nil { - return err - } - seed_song = tracks.Tracks[frand.Intn(len(tracks.Tracks))].SimpleTrack + } else if !current_song.Playing { + tracks, err := c.Client().CurrentUsersTracks(ctx, spotify.Limit(10)) + if err != nil { + return err } + seed_song = tracks.Tracks[frand.Intn(len(tracks.Tracks))].SimpleTrack } 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{} radioPlaylist, db, err := c.GetRadioPlaylist(ctx, "") if err != nil { + return err } 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) } - found := false page := 0 - for !found { + for { tracks, err := c.Client().GetPlaylistItems(ctx, radioPlaylist.ID, spotify.Limit(50), spotify.Offset(page*50)) if err != nil { return fmt.Errorf("tracks: %w", err) } if len(tracks.Items) == 0 { - found = true break } for _, track := range tracks.Items { if track.Track.Track.ID == status.Item.ID { - found = true break } 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) } } - _, err = c.Client().RemoveTracksFromPlaylist(ctx, radioPlaylist.ID, trackGroups...) + c.Client().RemoveTracksFromPlaylist(ctx, radioPlaylist.ID, trackGroups...) } 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)) randomPage := 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)) if err != nil { @@ -684,6 +679,9 @@ func (c *Commands) RefillRadio(ctx *gctx.Context) error { break } _, err = db.QueryContext(ctx, fmt.Sprintf("INSERT INTO radio (id) VALUES('%s')", rec.String())) + if err != nil { + return err + } queue = append(queue, rec) } to_add -= len(queue) @@ -825,8 +823,8 @@ func (c *Commands) Next(ctx *gctx.Context, amt int) error { case "playlist": found := false currentTrackIndex := 0 + page := 1 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)) if err != nil { return err @@ -850,8 +848,8 @@ func (c *Commands) Next(ctx *gctx.Context, amt int) error { case "album": found := false currentTrackIndex := 0 + page := 1 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)) if err != nil { return err @@ -903,9 +901,6 @@ func (c *Commands) Status(ctx *gctx.Context) error { if err != nil { return err } - if err != nil { - return err - } fmt.Println(state) return nil } @@ -923,7 +918,7 @@ func (c *Commands) LinkContext(ctx *gctx.Context) (string, error) { if err != nil { return "", err } - return string(state.PlaybackContext.ExternalURLs["spotify"]), nil + return state.PlaybackContext.ExternalURLs["spotify"], nil } 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 { state, err := c.Client().PlayerState(ctx) 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) if err != nil { @@ -966,7 +961,7 @@ func (c *Commands) Shuffle(ctx *gctx.Context) error { func (c *Commands) Repeat(ctx *gctx.Context) error { state, err := c.Client().PlayerState(ctx) if err != nil { - return fmt.Errorf("Failed to get current playstate") + return fmt.Errorf("failed to get current playstate") } newState := "off" if state.RepeatState == "off" { @@ -1012,7 +1007,7 @@ func (c *Commands) PrintPlaying(current *spotify.CurrentlyPlaying) error { if !current.Playing { 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 } @@ -1031,7 +1026,7 @@ func (c *Commands) SetDevice(ctx *gctx.Context, device spotify.PlayerDevice) err return err } 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 { return err } @@ -1049,12 +1044,12 @@ func isNoActiveError(err error) bool { func (c *Commands) RadioFromPlaylist(ctx *gctx.Context, playlist spotify.SimplePlaylist) error { total := playlist.Tracks.Total if total == 0 { - return fmt.Errorf("This playlist is empty") + return fmt.Errorf("this playlist is empty") } pages := int(math.Ceil(float64(total) / 50)) randomPage := 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)) if err != nil { @@ -1083,12 +1078,12 @@ func (c *Commands) RadioFromAlbum(ctx *gctx.Context, album spotify.SimpleAlbum) } total := tracks.Total if total == 0 { - return fmt.Errorf("This playlist is empty") + return fmt.Errorf("this playlist is empty") } pages := int(math.Ceil(float64(total) / 50)) randomPage := 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) if err != nil { @@ -1116,12 +1111,12 @@ func (c *Commands) RadioFromSavedTracks(ctx *gctx.Context) error { return err } 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)) randomPage := 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)) if err != nil { @@ -1261,29 +1256,6 @@ func (c *Commands) activateDevice(ctx *gctx.Context) (spotify.ID, error) { 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) { configDir, _ := os.UserConfigDir() 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 } db, err := sql.Open("sqlite", filepath.Join(configDir, "gospt/radio.db")) + if err != nil { + return nil, nil, err + } return playlist, db, nil } @@ -1313,11 +1288,14 @@ func (c *Commands) CreateRadioPlaylist(ctx *gctx.Context, name string) (*spotify if err != nil { 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 { return nil, nil, err } 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, "CREATE TABLE IF NOT EXISTS radio (id string PRIMARY KEY)") return playlist, db, nil diff --git a/src/tui/handlers.go b/src/tui/handlers.go index 07e1485..1a393b4 100644 --- a/src/tui/handlers.go +++ b/src/tui/handlers.go @@ -8,8 +8,7 @@ import ( ) 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 { 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) { - var err error - err = commands.SetDevice(ctx, player) + err := commands.SetDevice(ctx, player) if err != nil { return } diff --git a/src/tui/main.go b/src/tui/main.go index 491736c..f7d1107 100644 --- a/src/tui/main.go +++ b/src/tui/main.go @@ -31,24 +31,24 @@ type Mode string const ( Album Mode = "album" - ArtistAlbum = "artistalbum" - Artist = "artist" - Artists = "artists" - Tracks = "tracks" - Albums = "albums" - Main = "main" - Playlists = "playlists" - Playlist = "playlist" - Devices = "devices" - Search = "search" - SearchAlbums = "searchalbums" - SearchAlbum = "searchalbum" - SearchArtists = "searchartists" - SearchArtist = "searchartist" - SearchArtistAlbum = "searchartistalbum" - SearchTracks = "searchtracks" - SearchPlaylists = "searchplaylsits" - SearchPlaylist = "searchplaylist" + ArtistAlbum Mode = "artistalbum" + Artist Mode = "artist" + Artists Mode = "artists" + Tracks Mode = "tracks" + Albums Mode = "albums" + Main Mode = "main" + Playlists Mode = "playlists" + Playlist Mode = "playlist" + Devices Mode = "devices" + Search Mode = "search" + SearchAlbums Mode = "searchalbums" + SearchAlbum Mode = "searchalbum" + SearchArtists Mode = "searchartists" + SearchArtist Mode = "searchartist" + SearchArtistAlbum Mode = "searchartistalbum" + SearchTracks Mode = "searchtracks" + SearchPlaylists Mode = "searchplaylsits" + SearchPlaylist Mode = "searchplaylist" ) type mainItem struct { @@ -90,36 +90,36 @@ type mainModel struct { func (m *mainModel) PlayRadio() { m.list.NewStatusMessage("Starting radio for " + m.list.SelectedItem().(mainItem).Title()) selectedItem := m.list.SelectedItem().(mainItem).SpotifyItem - switch selectedItem.(type) { + switch item := selectedItem.(type) { case spotify.SimplePlaylist: - go HandlePlaylistRadio(m.ctx, m.commands, selectedItem.(spotify.SimplePlaylist)) + go HandlePlaylistRadio(m.ctx, m.commands, item) return case *spotify.SavedTrackPage: go HandleLibraryRadio(m.ctx, m.commands) return case spotify.SimpleAlbum: - go HandleAlbumRadio(m.ctx, m.commands, selectedItem.(spotify.SimpleAlbum)) + go HandleAlbumRadio(m.ctx, m.commands, item) return case spotify.FullAlbum: - go HandleAlbumRadio(m.ctx, m.commands, selectedItem.(spotify.FullAlbum).SimpleAlbum) + go HandleAlbumRadio(m.ctx, m.commands, item.SimpleAlbum) return case spotify.SimpleArtist: - go HandleArtistRadio(m.ctx, m.commands, selectedItem.(spotify.SimpleArtist)) + go HandleArtistRadio(m.ctx, m.commands, item) return case spotify.FullArtist: - go HandleArtistRadio(m.ctx, m.commands, selectedItem.(spotify.FullArtist).SimpleArtist) + go HandleArtistRadio(m.ctx, m.commands, item.SimpleArtist) return case spotify.SimpleTrack: - go HandleRadio(m.ctx, m.commands, selectedItem.(spotify.SimpleTrack)) + go HandleRadio(m.ctx, m.commands, item) return case spotify.FullTrack: - go HandleRadio(m.ctx, m.commands, selectedItem.(spotify.FullTrack).SimpleTrack) + go HandleRadio(m.ctx, m.commands, item.SimpleTrack) return case spotify.PlaylistTrack: - go HandleRadio(m.ctx, m.commands, selectedItem.(spotify.PlaylistTrack).Track.SimpleTrack) + go HandleRadio(m.ctx, m.commands, item.Track.SimpleTrack) return case spotify.SavedTrack: - go HandleRadio(m.ctx, m.commands, selectedItem.(spotify.SavedTrack).SimpleTrack) + go HandleRadio(m.ctx, m.commands, item.SimpleTrack) return } } @@ -132,6 +132,7 @@ func (m *mainModel) GoBack() (tea.Cmd, error) { m.mode = Main new_items, err := MainView(m.ctx, m.commands) if err != nil { + return nil, err } m.list.SetItems(new_items) case Album: @@ -203,36 +204,36 @@ type SpotifyUrl struct { func (m *mainModel) CopyToClipboard() error { item := m.list.SelectedItem().(mainItem).SpotifyItem - switch item.(type) { + switch converted := item.(type) { 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()) 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()) 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()) 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()) 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()) 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()) 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()) 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()) 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()) 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()) } return nil @@ -241,10 +242,10 @@ func (m *mainModel) CopyToClipboard() error { func (m *mainModel) SelectItem() error { switch m.mode { case Search: - switch m.list.SelectedItem().(mainItem).SpotifyItem.(type) { + switch item := m.list.SelectedItem().(mainItem).SpotifyItem.(type) { case *spotify.FullArtistPage: 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 { return err } @@ -252,7 +253,7 @@ func (m *mainModel) SelectItem() error { m.list.ResetSelected() case *spotify.SimpleAlbumPage: 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 { return err } @@ -260,8 +261,7 @@ func (m *mainModel) SelectItem() error { m.list.ResetSelected() case *spotify.SimplePlaylistPage: m.mode = SearchPlaylists - playlists := m.list.SelectedItem().(mainItem).SpotifyItem.(*spotify.SimplePlaylistPage) - new_items, err := SearchPlaylistsView(m.ctx, m.commands, playlists) + new_items, err := SearchPlaylistsView(m.ctx, m.commands, item) if err != nil { return err } @@ -269,7 +269,7 @@ func (m *mainModel) SelectItem() error { m.list.ResetSelected() case *spotify.FullTrackPage: 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 { return err } @@ -314,7 +314,7 @@ func (m *mainModel) SelectItem() error { m.list.SetItems(new_items) m.list.ResetSelected() case Main: - switch m.list.SelectedItem().(mainItem).SpotifyItem.(type) { + switch item := m.list.SelectedItem().(mainItem).SpotifyItem.(type) { case *spotify.FullArtistCursorPage: m.mode = Artists new_items, err := ArtistsView(m.ctx, m.commands) @@ -333,9 +333,8 @@ func (m *mainModel) SelectItem() error { m.list.ResetSelected() case spotify.SimplePlaylist: m.mode = Playlist - playlist := m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimplePlaylist) - m.playlist = playlist - new_items, err := PlaylistView(m.ctx, m.commands, playlist) + m.playlist = item + new_items, err := PlaylistView(m.ctx, m.commands, item) if err != nil { return err } @@ -399,7 +398,7 @@ func (m *mainModel) SelectItem() error { return nil } -func (m mainModel) Init() tea.Cmd { +func (m *mainModel) Init() tea.Cmd { main_updates = make(chan *mainModel) return Tick() } @@ -437,7 +436,7 @@ func (m *mainModel) TickPlayback() { }() } -func (m mainModel) View() string { +func (m *mainModel) View() string { if m.input.Focused() { 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 } -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 select { case update := <-main_updates: @@ -647,7 +646,7 @@ func InitMain(ctx *gctx.Context, c *commands.Commands, mode Mode) (tea.Model, er return nil, err } } - m := mainModel{ + m := &mainModel{ list: list.New(items, list.NewDefaultDelegate(), 0, 0), ctx: ctx, commands: c, diff --git a/src/tui/views.go b/src/tui/views.go index 0cd935d..ee8e99b 100644 --- a/src/tui/views.go +++ b/src/tui/views.go @@ -84,27 +84,13 @@ func SearchView(ctx *gctx.Context, commands *commands.Commands, search string) ( if err != nil { return nil, nil, err } - items = append(items, mainItem{ - Name: "Tracks", - Desc: "Search results", - SpotifyItem: result.Tracks, - }) - items = append(items, mainItem{ - 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, - }) + items = append( + items, + mainItem{Name: "Tracks", Desc: "Search results", SpotifyItem: result.Tracks}, + mainItem{Name: "Albums", Desc: "Search results", SpotifyItem: result.Albums}, + mainItem{Name: "Artists", Desc: "Search results", SpotifyItem: result.Artists}, + mainItem{Name: "Playlists", Desc: "Search results", SpotifyItem: result.Playlists}, + ) results := &SearchResults{ Tracks: result.Tracks, Playlists: result.Playlists, @@ -149,7 +135,7 @@ func SearchAlbumsView(ctx *gctx.Context, commands *commands.Commands, albums *sp items = append(items, mainItem{ Name: album.Name, 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, }) }