search framework

This commit is contained in:
abs3nt 2023-01-13 01:12:31 -08:00
parent 0e01d77136
commit 1acc255c61
3 changed files with 198 additions and 13 deletions

View File

@ -64,6 +64,14 @@ func ArtistAlbums(ctx *gctx.Context, client *spotify.Client, artist spotify.ID,
return albums, nil return albums, nil
} }
func Search(ctx *gctx.Context, client *spotify.Client, search string, page int) (*spotify.SearchResult, error) {
result, err := client.Search(ctx, search, spotify.SearchTypeAlbum|spotify.SearchTypeArtist|spotify.SearchTypeTrack|spotify.SearchTypePlaylist, spotify.Limit(50), spotify.Offset((page-1)*50))
if err != nil {
return nil, err
}
return result, nil
}
func AlbumTracks(ctx *gctx.Context, client *spotify.Client, album spotify.ID, page int) (*spotify.SimpleTrackPage, error) { func AlbumTracks(ctx *gctx.Context, client *spotify.Client, album spotify.ID, page int) (*spotify.SimpleTrackPage, error) {
tracks, err := client.GetAlbumTracks(ctx, album, spotify.Limit(50), spotify.Offset((page-1)*50), spotify.Market(spotify.CountryUSA)) tracks, err := client.GetAlbumTracks(ctx, album, spotify.Limit(50), spotify.Offset((page-1)*50), spotify.Market(spotify.CountryUSA))
if err != nil { if err != nil {

View File

@ -8,6 +8,7 @@ import (
"github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/list" "github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
"github.com/zmb3/spotify/v2" "github.com/zmb3/spotify/v2"
@ -36,12 +37,14 @@ func (i mainItem) FilterValue() string { return i.Title() + i.Desc }
type mainModel struct { type mainModel struct {
list list.Model list list.Model
input textinput.Model
ctx *gctx.Context ctx *gctx.Context
client *spotify.Client client *spotify.Client
mode string mode string
playlist spotify.SimplePlaylist playlist spotify.SimplePlaylist
artist spotify.SimpleArtist artist spotify.SimpleArtist
album spotify.SimpleAlbum album spotify.SimpleAlbum
search string
fromArtist bool fromArtist bool
} }
@ -70,10 +73,14 @@ func (m *mainModel) Tick() {
} }
func (m mainModel) View() string { func (m mainModel) View() string {
return DocStyle.Render(m.list.View()) if m.input.Focused() {
return DocStyle.Render(m.list.View() + "\n" + m.input.View())
}
return DocStyle.Render(m.list.View() + "\n")
} }
func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
search := false
m.list.NewStatusMessage(currentlyPlaying) m.list.NewStatusMessage(currentlyPlaying)
select { select {
case update := <-main_updates: case update := <-main_updates:
@ -88,7 +95,28 @@ func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} }
switch msg := msg.(type) { switch msg := msg.(type) {
case tea.KeyMsg: case tea.KeyMsg:
if m.input.Focused() {
if msg.String() == "enter" {
m.list.NewStatusMessage("Setting view to search for " + m.input.Value())
items, err := SearchView(m.ctx, m.client, m.input.Value())
if err != nil {
fmt.Println(err.Error())
return m, tea.Quit
}
m.search = m.input.Value()
m.list.SetItems(items)
m.list.ResetSelected()
m.input.SetValue("")
m.input.Blur()
search = true
}
m.input, _ = m.input.Update(msg)
}
if msg.String() == "s" {
m.input.Focus()
}
if msg.String() == "d" { if msg.String() == "d" {
if !m.input.Focused() {
m.mode = "devices" m.mode = "devices"
new_items, err := DeviceView(m.ctx, m.client) new_items, err := DeviceView(m.ctx, m.client)
if err != nil { if err != nil {
@ -99,8 +127,22 @@ func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.list.ResetSelected() m.list.ResetSelected()
m.list.NewStatusMessage("Setting view to devices") m.list.NewStatusMessage("Setting view to devices")
} }
}
if msg.String() == "backspace" || msg.String() == "esc" || msg.String() == "q" { if msg.String() == "backspace" || msg.String() == "esc" || msg.String() == "q" {
if m.mode == "album" { if m.input.Focused() {
if msg.String() == "esc" {
m.input.SetValue("")
m.input.Blur()
m.list.SetShowPagination(true)
m.mode = "main"
m.list.NewStatusMessage("Setting view to main")
new_items, err := MainView(m.ctx, m.client)
if err != nil {
fmt.Println(err.Error())
}
m.list.SetItems(new_items)
}
} else if m.mode == "album" {
if m.fromArtist { if m.fromArtist {
m.mode = "albums" m.mode = "albums"
m.fromArtist = true m.fromArtist = true
@ -163,6 +205,51 @@ func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} }
if msg.String() == "enter" || msg.String() == "spacebar" { if msg.String() == "enter" || msg.String() == "spacebar" {
switch m.mode { switch m.mode {
case "search":
switch m.list.SelectedItem().(mainItem).SpotifyItem.(type) {
case *spotify.FullArtistPage:
m.mode = "searchartists"
m.list.NewStatusMessage("Setting view to artists")
new_items, err := SearchArtistsView(m.ctx, m.client, m.list.SelectedItem().(mainItem).SpotifyItem.(*spotify.FullArtistPage))
if err != nil {
fmt.Println(err.Error())
return m, tea.Quit
}
m.list.SetItems(new_items)
m.list.ResetSelected()
case *spotify.SimpleAlbumPage:
m.mode = "searchalbums"
m.list.NewStatusMessage("Setting view to albums")
new_items, err := SearchAlbumsView(m.ctx, m.client, m.list.SelectedItem().(mainItem).SpotifyItem.(*spotify.SimpleAlbumPage))
if err != nil {
fmt.Println(err.Error())
return m, tea.Quit
}
m.list.SetItems(new_items)
m.list.ResetSelected()
case *spotify.SimplePlaylistPage:
m.mode = "searchplaylist"
playlists := m.list.SelectedItem().(mainItem).SpotifyItem.(*spotify.SimplePlaylistPage)
m.list.NewStatusMessage("Setting view to playlist")
new_items, err := SearchPlaylistsView(m.ctx, m.client, playlists)
if err != nil {
fmt.Println(err.Error())
return m, tea.Quit
}
m.list.SetItems(new_items)
m.list.ResetSelected()
case *spotify.FullTrackPage:
m.mode = "searchtracks"
m.list.NewStatusMessage("Setting view to tracks")
new_items, err := SearchTracksView(m.ctx, m.client, m.list.SelectedItem().(mainItem).SpotifyItem.(*spotify.FullTrackPage))
if err != nil {
fmt.Println(err.Error())
return m, tea.Quit
}
m.list.SetItems(new_items)
m.list.ResetSelected()
m.list.NewStatusMessage("Setting view to tracks")
}
case "main": case "main":
switch m.list.SelectedItem().(mainItem).SpotifyItem.(type) { switch m.list.SelectedItem().(mainItem).SpotifyItem.(type) {
case *spotify.FullArtistCursorPage: case *spotify.FullArtistCursorPage:
@ -296,9 +383,11 @@ func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} }
case tea.WindowSizeMsg: case tea.WindowSizeMsg:
h, v := DocStyle.GetFrameSize() h, v := DocStyle.GetFrameSize()
m.list.SetSize(msg.Width-h, msg.Height-v) m.list.SetSize(msg.Width-h, msg.Height-v-1)
}
if search {
m.mode = "search"
} }
var cmd tea.Cmd var cmd tea.Cmd
m.list, cmd = m.list.Update(msg) m.list, cmd = m.list.Update(msg)
return m, cmd return m, cmd
@ -353,5 +442,11 @@ func InitMain(ctx *gctx.Context, client *spotify.Client, mode string) (tea.Model
key.NewBinding(key.WithKeys("d"), key.WithHelp("d", "select device")), key.NewBinding(key.WithKeys("d"), key.WithHelp("d", "select device")),
} }
} }
input := textinput.New()
input.Prompt = "$ "
input.Placeholder = "Search..."
input.CharLimit = 250
input.Width = 50
m.input = input
return m, nil return m, nil
} }

View File

@ -63,6 +63,49 @@ func ArtistsView(ctx *gctx.Context, client *spotify.Client) ([]list.Item, error)
return items, nil return items, nil
} }
func SearchArtistsView(ctx *gctx.Context, client *spotify.Client, artists *spotify.FullArtistPage) ([]list.Item, error) {
items := []list.Item{}
for _, artist := range artists.Artists {
items = append(items, mainItem{
Name: artist.Name,
ID: artist.ID,
Desc: fmt.Sprintf("%d followers, genres: %s, popularity: %d", artist.Followers.Count, artist.Genres, artist.Popularity),
SpotifyItem: artist.SimpleArtist,
})
}
return items, nil
}
func SearchView(ctx *gctx.Context, client *spotify.Client, search string) ([]list.Item, error) {
items := []list.Item{}
result, err := commands.Search(ctx, client, search, 1)
if err != nil {
return 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,
})
return items, nil
}
func AlbumsView(ctx *gctx.Context, client *spotify.Client) ([]list.Item, error) { func AlbumsView(ctx *gctx.Context, client *spotify.Client) ([]list.Item, error) {
items := []list.Item{} items := []list.Item{}
albums, err := commands.UserAlbums(ctx, client, 1) albums, err := commands.UserAlbums(ctx, client, 1)
@ -80,6 +123,31 @@ func AlbumsView(ctx *gctx.Context, client *spotify.Client) ([]list.Item, error)
return items, nil return items, nil
} }
func SearchPlaylistsView(ctx *gctx.Context, client *spotify.Client, playlists *spotify.SimplePlaylistPage) ([]list.Item, error) {
items := []list.Item{}
for _, playlist := range playlists.Playlists {
items = append(items, mainItem{
Name: playlist.Name,
Desc: playlist.Description,
SpotifyItem: playlist,
})
}
return items, nil
}
func SearchAlbumsView(ctx *gctx.Context, client *spotify.Client, albums *spotify.SimpleAlbumPage) ([]list.Item, error) {
items := []list.Item{}
for _, album := range albums.Albums {
items = append(items, mainItem{
Name: album.Name,
ID: album.ID,
Desc: fmt.Sprintf("%s, %d", album.Artists[0].Name, album.ReleaseDateTime()),
SpotifyItem: album,
})
}
return items, nil
}
func ArtistAlbumsView(ctx *gctx.Context, album spotify.ID, client *spotify.Client) ([]list.Item, error) { func ArtistAlbumsView(ctx *gctx.Context, album spotify.ID, client *spotify.Client) ([]list.Item, error) {
items := []list.Item{} items := []list.Item{}
albums, err := commands.ArtistAlbums(ctx, client, album, 1) albums, err := commands.ArtistAlbums(ctx, client, album, 1)
@ -115,6 +183,20 @@ func AlbumTracksView(ctx *gctx.Context, album spotify.ID, client *spotify.Client
return items, err return items, err
} }
func SearchTracksView(ctx *gctx.Context, client *spotify.Client, tracks *spotify.FullTrackPage) ([]list.Item, error) {
items := []list.Item{}
for _, track := range tracks.Tracks {
items = append(items, mainItem{
Name: track.Name,
Artist: track.Artists[0],
Duration: track.TimeDuration().Round(time.Second).String(),
ID: track.ID,
Desc: track.Artists[0].Name + " - " + track.TimeDuration().Round(time.Second).String(),
})
}
return items, nil
}
func SavedTracksView(ctx *gctx.Context, client *spotify.Client) ([]list.Item, error) { func SavedTracksView(ctx *gctx.Context, client *spotify.Client) ([]list.Item, error) {
items := []list.Item{} items := []list.Item{}
tracks, err := commands.TrackList(ctx, client, 1) tracks, err := commands.TrackList(ctx, client, 1)