This commit is contained in:
abs3nt 2024-02-19 17:58:05 -08:00
parent ae4291032e
commit e6344bef01
Signed by: abs3nt
GPG Key ID: A7BD96A8BAB04C09
11 changed files with 135 additions and 163 deletions

31
main.go
View File

@ -1,31 +0,0 @@
package main
import (
"gfx.cafe/util/go/fxplus"
"go.uber.org/fx"
"git.asdf.cafe/abs3nt/gspot/src/components/cache"
"git.asdf.cafe/abs3nt/gspot/src/components/cli"
"git.asdf.cafe/abs3nt/gspot/src/components/commands"
"git.asdf.cafe/abs3nt/gspot/src/components/logger"
"git.asdf.cafe/abs3nt/gspot/src/services"
)
func main() {
var s fx.Shutdowner
app := fx.New(
fxplus.WithLogger,
fx.Populate(&s),
services.Config,
fx.Provide(
fxplus.Context,
cache.NewCache,
commands.NewCommander,
logger.NewLogger,
),
fx.Invoke(
cli.Run,
),
)
app.Run()
}

View File

@ -40,7 +40,7 @@ func Run(c *commands.Commander, s fx.Shutdowner) {
Usage: "Plays a spotify url", Usage: "Plays a spotify url",
ArgsUsage: "url", ArgsUsage: "url",
Action: func(ctx context.Context, cmd *cli.Command) error { Action: func(ctx context.Context, cmd *cli.Command) error {
return c.PlayUrl(cmd.Args().First()) return c.PlayURL(cmd.Args().First())
}, },
Category: "Playback", Category: "Playback",
}, },

View File

@ -20,12 +20,12 @@ func (c *Commander) Next(amt int, inqueue bool) error {
err := c.Client().Next(c.Context) err := c.Client().Next(c.Context)
if err != nil { if err != nil {
if isNoActiveError(err) { if isNoActiveError(err) {
deviceId, err := c.activateDevice() deviceID, err := c.activateDevice()
if err != nil { if err != nil {
return err return err
} }
err = c.Client().NextOpt(c.Context, &spotify.PlayOptions{ err = c.Client().NextOpt(c.Context, &spotify.PlayOptions{
DeviceID: &deviceId, DeviceID: &deviceID,
}) })
if err != nil { if err != nil {
return err return err

View File

@ -43,11 +43,11 @@ func (c *Commander) PlayLikedSongs(position int) error {
if err != nil { if err != nil {
return err return err
} }
to_add := []spotify.ID{} toAdd := []spotify.ID{}
for _, song := range songs.Tracks { for _, song := range songs.Tracks {
to_add = append(to_add, song.ID) toAdd = append(toAdd, song.ID)
} }
_, err = c.Client().AddTracksToPlaylist(c.Context, playlist.ID, to_add...) _, err = c.Client().AddTracksToPlaylist(c.Context, playlist.ID, toAdd...)
if err != nil { if err != nil {
return err return err
} }
@ -78,11 +78,11 @@ func (c *Commander) PlayLikedSongs(position int) error {
if err != nil { if err != nil {
return err return err
} }
to_add := []spotify.ID{} toAdd := []spotify.ID{}
for _, song := range songs.Tracks { for _, song := range songs.Tracks {
to_add = append(to_add, song.ID) toAdd = append(toAdd, song.ID)
} }
_, err = c.Client().AddTracksToPlaylist(c.Context, playlist.ID, to_add...) _, err = c.Client().AddTracksToPlaylist(c.Context, playlist.ID, toAdd...)
if err != nil { if err != nil {
return err return err
} }
@ -91,20 +91,20 @@ func (c *Commander) PlayLikedSongs(position int) error {
return err return err
} }
func (c *Commander) PlayUrl(urlString string) error { func (c *Commander) PlayURL(urlString string) error {
url, err := url.Parse(urlString) url, err := url.Parse(urlString)
if err != nil { if err != nil {
return err return err
} }
track_id := strings.Split(url.Path, "/")[2] trackID := strings.Split(url.Path, "/")[2]
err = c.Client().QueueSong(c.Context, spotify.ID(track_id)) err = c.Client().QueueSong(c.Context, spotify.ID(trackID))
if err != nil { if err != nil {
if isNoActiveError(err) { if isNoActiveError(err) {
deviceID, err := c.activateDevice() deviceID, err := c.activateDevice()
if err != nil { if err != nil {
return err return err
} }
err = c.Client().QueueSongOpt(c.Context, spotify.ID(track_id), &spotify.PlayOptions{ err = c.Client().QueueSongOpt(c.Context, spotify.ID(trackID), &spotify.PlayOptions{
DeviceID: &deviceID, DeviceID: &deviceID,
}) })
if err != nil { if err != nil {

View File

@ -8,12 +8,12 @@ func (c *Commander) Previous() error {
err := c.Client().Previous(c.Context) err := c.Client().Previous(c.Context)
if err != nil { if err != nil {
if isNoActiveError(err) { if isNoActiveError(err) {
deviceId, err := c.activateDevice() deviceID, err := c.activateDevice()
if err != nil { if err != nil {
return err return err
} }
err = c.Client().PreviousOpt(c.Context, &spotify.PlayOptions{ err = c.Client().PreviousOpt(c.Context, &spotify.PlayOptions{
DeviceID: &deviceId, DeviceID: &deviceID,
}) })
if err != nil { if err != nil {
return err return err

View File

@ -16,12 +16,12 @@ import (
) )
func (c *Commander) Radio() error { func (c *Commander) Radio() error {
current_song, err := c.Client().PlayerCurrentlyPlaying(c.Context) currentSong, err := c.Client().PlayerCurrentlyPlaying(c.Context)
if err != nil { if err != nil {
return err return err
} }
if current_song.Item != nil { if currentSong.Item != nil {
return c.RadioGivenSong(current_song.Item.SimpleTrack, current_song.Progress) return c.RadioGivenSong(currentSong.Item.SimpleTrack, currentSong.Progress)
} }
_, err = c.activateDevice() _, err = c.activateDevice()
if err != nil { if err != nil {
@ -153,12 +153,13 @@ func (c *Commander) RadioGivenArtist(artist spotify.SimpleArtist) error {
seed := spotify.Seeds{ seed := spotify.Seeds{
Tracks: []spotify.ID{recomendationIds[id]}, Tracks: []spotify.ID{recomendationIds[id]},
} }
additional_recs, err := c.Client().GetRecommendations(c.Context, seed, &spotify.TrackAttributes{}, spotify.Limit(100)) additionalRecs, err := c.Client().
GetRecommendations(c.Context, seed, &spotify.TrackAttributes{}, spotify.Limit(100))
if err != nil { if err != nil {
return err return err
} }
additionalRecsIds := []spotify.ID{} additionalRecsIds := []spotify.ID{}
for _, song := range additional_recs.Tracks { for _, song := range additionalRecs.Tracks {
exists, err := c.SongExists(db, song.ID) exists, err := c.SongExists(db, song.ID)
if err != nil { if err != nil {
return err return err
@ -255,12 +256,13 @@ func (c *Commander) RadioGivenSong(song spotify.SimpleTrack, pos int) error {
seed := spotify.Seeds{ seed := spotify.Seeds{
Tracks: []spotify.ID{recomendationIds[id]}, Tracks: []spotify.ID{recomendationIds[id]},
} }
additional_recs, err := c.Client().GetRecommendations(c.Context, seed, &spotify.TrackAttributes{}, spotify.Limit(100)) additionalRecs, err := c.Client().
GetRecommendations(c.Context, seed, &spotify.TrackAttributes{}, spotify.Limit(100))
if err != nil { if err != nil {
return err return err
} }
additionalRecsIds := []spotify.ID{} additionalRecsIds := []spotify.ID{}
for _, song := range additional_recs.Tracks { for _, song := range additionalRecs.Tracks {
exists, err := c.SongExists(db, song.ID) exists, err := c.SongExists(db, song.ID)
if err != nil { if err != nil {
return err return err
@ -344,9 +346,9 @@ func (c *Commander) CreateRadioPlaylist(name string) (*spotify.FullPlaylist, *sq
} }
func (c *Commander) SongExists(db *sql.DB, song spotify.ID) (bool, error) { func (c *Commander) SongExists(db *sql.DB, song spotify.ID) (bool, error) {
song_id := string(song) songID := string(song)
sqlStmt := `SELECT id FROM radio WHERE id = ?` sqlStmt := `SELECT id FROM radio WHERE id = ?`
err := db.QueryRow(sqlStmt, song_id).Scan(&song_id) err := db.QueryRow(sqlStmt, songID).Scan(&songID)
if err != nil { if err != nil {
if err != sql.ErrNoRows { if err != sql.ErrNoRows {
return false, err return false, err
@ -366,7 +368,7 @@ func (c *Commander) RefillRadio() error {
if !status.Playing { if !status.Playing {
return nil return nil
} }
to_remove := []spotify.ID{} toRemove := []spotify.ID{}
radioPlaylist, db, err := c.GetRadioPlaylist("") radioPlaylist, db, err := c.GetRadioPlaylist("")
if err != nil { if err != nil {
return err return err
@ -394,13 +396,13 @@ func (c *Commander) RefillRadio() error {
if track.Track.Track.ID == status.Item.ID { if track.Track.Track.ID == status.Item.ID {
break break
} }
to_remove = append(to_remove, track.Track.Track.ID) toRemove = append(toRemove, track.Track.Track.ID)
} }
page++ page++
} }
if len(to_remove) > 0 { if len(toRemove) > 0 {
var trackGroups []spotify.ID var trackGroups []spotify.ID
for idx, item := range to_remove { for idx, item := range toRemove {
if idx%100 == 0 { if idx%100 == 0 {
_, err = c.Client().RemoveTracksFromPlaylist(c.Context, radioPlaylist.ID, trackGroups...) _, err = c.Client().RemoveTracksFromPlaylist(c.Context, radioPlaylist.ID, trackGroups...)
trackGroups = []spotify.ID{} trackGroups = []spotify.ID{}
@ -416,7 +418,7 @@ func (c *Commander) RefillRadio() error {
} }
} }
to_add := 500 - (playlistItems.Total - len(to_remove)) toAdd := 500 - (playlistItems.Total - len(toRemove))
playlistItems, err = c.Client().GetPlaylistItems(c.Context, radioPlaylist.ID) playlistItems, err = c.Client().GetPlaylistItems(c.Context, radioPlaylist.ID)
if err != nil { if err != nil {
return fmt.Errorf("playlist items: %w", err) return fmt.Errorf("playlist items: %w", err)
@ -464,7 +466,7 @@ func (c *Commander) RefillRadio() error {
} }
queue := []spotify.ID{} queue := []spotify.ID{}
for idx, rec := range recomendationIds { for idx, rec := range recomendationIds {
if idx > to_add { if idx > toAdd {
break break
} }
_, err = db.QueryContext(c.Context, fmt.Sprintf("INSERT INTO radio (id) VALUES('%s')", rec.String())) _, err = db.QueryContext(c.Context, fmt.Sprintf("INSERT INTO radio (id) VALUES('%s')", rec.String()))
@ -473,7 +475,7 @@ func (c *Commander) RefillRadio() error {
} }
queue = append(queue, rec) queue = append(queue, rec)
} }
to_add -= len(queue) toAdd -= len(queue)
_, err = c.Client().AddTracksToPlaylist(c.Context, radioPlaylist.ID, queue...) _, err = c.Client().AddTracksToPlaylist(c.Context, radioPlaylist.ID, queue...)
if err != nil { if err != nil {
return fmt.Errorf("add tracks: %w", err) return fmt.Errorf("add tracks: %w", err)
@ -482,30 +484,31 @@ func (c *Commander) RefillRadio() error {
if err != nil { if err != nil {
return fmt.Errorf("repeat: %w", err) return fmt.Errorf("repeat: %w", err)
} }
for to_add > 0 { for toAdd > 0 {
id := frand.Intn(len(recomendationIds)-2) + 1 id := frand.Intn(len(recomendationIds)-2) + 1
seed := spotify.Seeds{ seed := spotify.Seeds{
Tracks: []spotify.ID{recomendationIds[id]}, Tracks: []spotify.ID{recomendationIds[id]},
} }
additional_recs, err := c.Client().GetRecommendations(c.Context, seed, &spotify.TrackAttributes{}, spotify.Limit(100)) additionalRecs, err := c.Client().
GetRecommendations(c.Context, seed, &spotify.TrackAttributes{}, spotify.Limit(100))
if err != nil { if err != nil {
return fmt.Errorf("get recs: %w", err) return fmt.Errorf("get recs: %w", err)
} }
additionalRecsIds := []spotify.ID{} additionalRecsIds := []spotify.ID{}
for idx, song := range additional_recs.Tracks { for idx, song := range additionalRecs.Tracks {
exists, err := c.SongExists(db, song.ID) exists, err := c.SongExists(db, song.ID)
if err != nil { if err != nil {
return fmt.Errorf("check song existence: %w", err) return fmt.Errorf("check song existence: %w", err)
} }
if !exists { if !exists {
if idx > to_add { if idx > toAdd {
break break
} }
additionalRecsIds = append(additionalRecsIds, song.ID) additionalRecsIds = append(additionalRecsIds, song.ID)
queue = append(queue, song.ID) queue = append(queue, song.ID)
} }
} }
to_add -= len(queue) toAdd -= len(queue)
_, err = c.Client().AddTracksToPlaylist(c.Context, radioPlaylist.ID, additionalRecsIds...) _, err = c.Client().AddTracksToPlaylist(c.Context, radioPlaylist.ID, additionalRecsIds...)
if err != nil { if err != nil {
return fmt.Errorf("add tracks to playlist: %w", err) return fmt.Errorf("add tracks to playlist: %w", err)
@ -548,9 +551,9 @@ func (c *Commander) RadioFromAlbum(album spotify.SimpleAlbum) error {
return c.RadioGivenList(seedIds[:seedCount], album.Name) return c.RadioGivenList(seedIds[:seedCount], album.Name)
} }
func (c *Commander) RadioGivenList(song_ids []spotify.ID, name string) error { func (c *Commander) RadioGivenList(songs []spotify.ID, name string) error {
seed := spotify.Seeds{ seed := spotify.Seeds{
Tracks: song_ids, Tracks: songs,
} }
recomendations, err := c.Client().GetRecommendations(c.Context, seed, &spotify.TrackAttributes{}, spotify.Limit(99)) recomendations, err := c.Client().GetRecommendations(c.Context, seed, &spotify.TrackAttributes{}, spotify.Limit(99))
if err != nil { if err != nil {
@ -568,7 +571,7 @@ func (c *Commander) RadioGivenList(song_ids []spotify.ID, name string) error {
if err != nil { if err != nil {
return err return err
} }
queue := []spotify.ID{song_ids[0]} queue := []spotify.ID{songs[0]}
for _, rec := range recomendationIds { for _, rec := range recomendationIds {
exists, err := c.SongExists(db, rec) exists, err := c.SongExists(db, rec)
if err != nil { if err != nil {
@ -591,13 +594,13 @@ func (c *Commander) RadioGivenList(song_ids []spotify.ID, name string) error {
}) })
if err != nil { if err != nil {
if isNoActiveError(err) { if isNoActiveError(err) {
deviceId, err := c.activateDevice() deviceID, err := c.activateDevice()
if err != nil { if err != nil {
return err return err
} }
err = c.Client().PlayOpt(c.Context, &spotify.PlayOptions{ err = c.Client().PlayOpt(c.Context, &spotify.PlayOptions{
PlaybackContext: &radioPlaylist.URI, PlaybackContext: &radioPlaylist.URI,
DeviceID: &deviceId, DeviceID: &deviceID,
}) })
if err != nil { if err != nil {
return err return err
@ -609,12 +612,12 @@ func (c *Commander) RadioGivenList(song_ids []spotify.ID, name string) error {
seed := spotify.Seeds{ seed := spotify.Seeds{
Tracks: []spotify.ID{recomendationIds[id]}, Tracks: []spotify.ID{recomendationIds[id]},
} }
additional_recs, err := c.Client().GetRecommendations(c.Context, seed, &spotify.TrackAttributes{}, spotify.Limit(100)) additionalRecs, err := c.Client().GetRecommendations(c.Context, seed, &spotify.TrackAttributes{}, spotify.Limit(100))
if err != nil { if err != nil {
return err return err
} }
additionalRecsIds := []spotify.ID{} additionalRecsIds := []spotify.ID{}
for _, song := range additional_recs.Tracks { for _, song := range additionalRecs.Tracks {
exists, err := c.SongExists(db, song.ID) exists, err := c.SongExists(db, song.ID)
if err != nil { if err != nil {
return err return err

View File

@ -32,7 +32,7 @@ func (m *mainModel) LoadMoreItems() {
for _, item := range items { for _, item := range items {
m.list.InsertItem(len(m.list.Items())+1, item) m.list.InsertItem(len(m.list.Items())+1, item)
} }
main_updates <- m mainUpdates <- m
return return
case "artists": case "artists":
artists, err := m.commands.Client().CurrentUsersFollowedArtists( artists, err := m.commands.Client().CurrentUsersFollowedArtists(
@ -60,7 +60,7 @@ func (m *mainModel) LoadMoreItems() {
for _, item := range items { for _, item := range items {
m.list.InsertItem(len(m.list.Items())+1, item) m.list.InsertItem(len(m.list.Items())+1, item)
} }
main_updates <- m mainUpdates <- m
return return
case "album": case "album":
tracks, err := m.commands.AlbumTracks(m.album.ID, (page + 1)) tracks, err := m.commands.AlbumTracks(m.album.ID, (page + 1))
@ -80,7 +80,7 @@ func (m *mainModel) LoadMoreItems() {
for _, item := range items { for _, item := range items {
m.list.InsertItem(len(m.list.Items())+1, item) m.list.InsertItem(len(m.list.Items())+1, item)
} }
main_updates <- m mainUpdates <- m
return return
case "albums": case "albums":
albums, err := m.commands.UserAlbums(page + 1) albums, err := m.commands.UserAlbums(page + 1)
@ -99,7 +99,7 @@ func (m *mainModel) LoadMoreItems() {
for _, item := range items { for _, item := range items {
m.list.InsertItem(len(m.list.Items())+1, item) m.list.InsertItem(len(m.list.Items())+1, item)
} }
main_updates <- m mainUpdates <- m
return return
case "main": case "main":
playlists, err := m.commands.Playlists(page + 1) playlists, err := m.commands.Playlists(page + 1)
@ -117,7 +117,7 @@ func (m *mainModel) LoadMoreItems() {
for _, item := range items { for _, item := range items {
m.list.InsertItem(len(m.list.Items())+1, item) m.list.InsertItem(len(m.list.Items())+1, item)
} }
main_updates <- m mainUpdates <- m
return return
case "playlist": case "playlist":
playlistItems, err := m.commands.PlaylistTracks(m.playlist.ID, (page + 1)) playlistItems, err := m.commands.PlaylistTracks(m.playlist.ID, (page + 1))
@ -139,7 +139,7 @@ func (m *mainModel) LoadMoreItems() {
for _, item := range items { for _, item := range items {
m.list.InsertItem(len(m.list.Items())+1, item) m.list.InsertItem(len(m.list.Items())+1, item)
} }
main_updates <- m mainUpdates <- m
return return
case "tracks": case "tracks":
tracks, err := m.commands.TrackList(page + 1) tracks, err := m.commands.TrackList(page + 1)
@ -159,7 +159,7 @@ func (m *mainModel) LoadMoreItems() {
for _, item := range items { for _, item := range items {
m.list.InsertItem(len(m.list.Items())+1, item) m.list.InsertItem(len(m.list.Items())+1, item)
} }
main_updates <- m mainUpdates <- m
return return
} }
} }

View File

@ -22,7 +22,7 @@ var (
DocStyle = lipgloss.NewStyle().Margin(0, 2).Border(lipgloss.DoubleBorder(), true, true, true, true) DocStyle = lipgloss.NewStyle().Margin(0, 2).Border(lipgloss.DoubleBorder(), true, true, true, true)
currentlyPlaying *spotify.CurrentlyPlaying currentlyPlaying *spotify.CurrentlyPlaying
playbackContext string playbackContext string
main_updates chan *mainModel mainUpdates chan *mainModel
page = 1 page = 1
loading = false loading = false
showingMessage = false showingMessage = false
@ -190,32 +190,32 @@ func (m *mainModel) GoBack() (tea.Cmd, error) {
return tea.Quit, nil return tea.Quit, nil
case Albums, Artists, Tracks, Playlist, Devices, Search, Queue: case Albums, Artists, Tracks, Playlist, Devices, Search, Queue:
m.mode = Main m.mode = Main
new_items, err := MainView(m.commands) newItems, err := MainView(m.commands)
if err != nil { if err != nil {
return nil, err return nil, err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
case Album: case Album:
m.mode = Albums m.mode = Albums
new_items, err := AlbumsView(m.commands) newItems, err := AlbumsView(m.commands)
if err != nil { if err != nil {
return nil, err return nil, err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
case Artist: case Artist:
m.mode = Artists m.mode = Artists
new_items, err := ArtistsView(m.commands) newItems, err := ArtistsView(m.commands)
if err != nil { if err != nil {
return nil, err return nil, err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
case ArtistAlbum: case ArtistAlbum:
m.mode = Artist m.mode = Artist
new_items, err := ArtistAlbumsView(m.artist.ID, m.commands) newItems, err := ArtistAlbumsView(m.artist.ID, m.commands)
if err != nil { if err != nil {
return nil, err return nil, err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
case SearchArtists, SearchTracks, SearchAlbums, SearchPlaylists: case SearchArtists, SearchTracks, SearchAlbums, SearchPlaylists:
m.mode = Search m.mode = Search
items, result, err := SearchView(m.commands, m.search) items, result, err := SearchView(m.commands, m.search)
@ -226,39 +226,39 @@ func (m *mainModel) GoBack() (tea.Cmd, error) {
m.list.SetItems(items) m.list.SetItems(items)
case SearchArtist: case SearchArtist:
m.mode = SearchArtists m.mode = SearchArtists
new_items, err := SearchArtistsView(m.commands, m.searchResults.Artists) newItems, err := SearchArtistsView(m.commands, m.searchResults.Artists)
if err != nil { if err != nil {
return nil, err return nil, err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
case SearchArtistAlbum: case SearchArtistAlbum:
m.mode = SearchArtist m.mode = SearchArtist
new_items, err := ArtistAlbumsView(m.artist.ID, m.commands) newItems, err := ArtistAlbumsView(m.artist.ID, m.commands)
if err != nil { if err != nil {
return nil, err return nil, err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
case SearchAlbum: case SearchAlbum:
m.mode = SearchAlbums m.mode = SearchAlbums
new_items, err := SearchAlbumsView(m.commands, m.searchResults.Albums) newItems, err := SearchAlbumsView(m.commands, m.searchResults.Albums)
if err != nil { if err != nil {
return nil, err return nil, err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
case SearchPlaylist: case SearchPlaylist:
m.mode = SearchPlaylists m.mode = SearchPlaylists
new_items, err := SearchPlaylistsView(m.commands, m.searchResults.Playlists) newItems, err := SearchPlaylistsView(m.commands, m.searchResults.Playlists)
if err != nil { if err != nil {
return nil, err return nil, err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
default: default:
page = 0 page = 0
} }
return nil, nil return nil, nil
} }
type SpotifyUrl struct { type SpotifyURL struct {
ExternalURLs map[string]string ExternalURLs map[string]string
} }
@ -343,11 +343,11 @@ func (m *mainModel) QueueItem() error {
}() }()
if m.mode == Queue { if m.mode == Queue {
go func() { go func() {
new_items, err := QueueView(m.commands) newItems, err := QueueView(m.commands)
if err != nil { if err != nil {
return return
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
}() }()
} }
return nil return nil
@ -364,11 +364,11 @@ func (m *mainModel) DeleteTrackFromPlaylist() error {
if err != nil { if err != nil {
m.SendMessage(err.Error(), 5*time.Second) m.SendMessage(err.Error(), 5*time.Second)
} }
new_items, err := PlaylistView(m.commands, m.playlist) newItems, err := PlaylistView(m.commands, m.playlist)
if err != nil { if err != nil {
m.SendMessage(err.Error(), 5*time.Second) m.SendMessage(err.Error(), 5*time.Second)
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
}() }()
return nil return nil
} }
@ -382,11 +382,11 @@ func (m *mainModel) SelectItem() error {
if err != nil { if err != nil {
m.SendMessage(err.Error(), 5*time.Second) m.SendMessage(err.Error(), 5*time.Second)
} }
new_items, err := QueueView(m.commands) newItems, err := QueueView(m.commands)
if err != nil { if err != nil {
m.SendMessage(err.Error(), 5*time.Second) m.SendMessage(err.Error(), 5*time.Second)
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
}() }()
case Search: case Search:
@ -394,150 +394,150 @@ func (m *mainModel) SelectItem() error {
switch item := 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.commands, item) newItems, err := SearchArtistsView(m.commands, item)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
case *spotify.SimpleAlbumPage: case *spotify.SimpleAlbumPage:
m.mode = SearchAlbums m.mode = SearchAlbums
new_items, err := SearchAlbumsView(m.commands, item) newItems, err := SearchAlbumsView(m.commands, item)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
case *spotify.SimplePlaylistPage: case *spotify.SimplePlaylistPage:
m.mode = SearchPlaylists m.mode = SearchPlaylists
new_items, err := SearchPlaylistsView(m.commands, item) newItems, err := SearchPlaylistsView(m.commands, item)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
case *spotify.FullTrackPage: case *spotify.FullTrackPage:
m.mode = SearchTracks m.mode = SearchTracks
new_items, err := SearchTracksView(item) newItems, err := SearchTracksView(item)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
} }
case SearchArtists: case SearchArtists:
page = 1 page = 1
m.mode = SearchArtist m.mode = SearchArtist
m.artist = m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimpleArtist) m.artist = m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimpleArtist)
new_items, err := ArtistAlbumsView(m.artist.ID, m.commands) newItems, err := ArtistAlbumsView(m.artist.ID, m.commands)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
case SearchArtist: case SearchArtist:
page = 1 page = 1
m.mode = SearchArtistAlbum m.mode = SearchArtistAlbum
m.album = m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimpleAlbum) m.album = m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimpleAlbum)
new_items, err := AlbumTracksView(m.album.ID, m.commands) newItems, err := AlbumTracksView(m.album.ID, m.commands)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
case SearchAlbums: case SearchAlbums:
page = 1 page = 1
m.mode = SearchAlbum m.mode = SearchAlbum
m.album = m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimpleAlbum) m.album = m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimpleAlbum)
new_items, err := AlbumTracksView(m.album.ID, m.commands) newItems, err := AlbumTracksView(m.album.ID, m.commands)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
case SearchPlaylists: case SearchPlaylists:
page = 1 page = 1
m.mode = SearchPlaylist m.mode = SearchPlaylist
playlist := m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimplePlaylist) playlist := m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimplePlaylist)
m.playlist = playlist m.playlist = playlist
new_items, err := PlaylistView(m.commands, playlist) newItems, err := PlaylistView(m.commands, playlist)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
case Main: case Main:
page = 1 page = 1
switch item := m.list.SelectedItem().(mainItem).SpotifyItem.(type) { switch item := m.list.SelectedItem().(mainItem).SpotifyItem.(type) {
case spotify.Queue: case spotify.Queue:
m.mode = Queue m.mode = Queue
new_items, err := QueueView(m.commands) newItems, err := QueueView(m.commands)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
case *spotify.FullArtistCursorPage: case *spotify.FullArtistCursorPage:
m.mode = Artists m.mode = Artists
new_items, err := ArtistsView(m.commands) newItems, err := ArtistsView(m.commands)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
case *spotify.SavedAlbumPage: case *spotify.SavedAlbumPage:
m.mode = Albums m.mode = Albums
new_items, err := AlbumsView(m.commands) newItems, err := AlbumsView(m.commands)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
case spotify.SimplePlaylist: case spotify.SimplePlaylist:
m.mode = Playlist m.mode = Playlist
m.playlist = item m.playlist = item
new_items, err := PlaylistView(m.commands, item) newItems, err := PlaylistView(m.commands, item)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
case *spotify.SavedTrackPage: case *spotify.SavedTrackPage:
m.mode = Tracks m.mode = Tracks
new_items, err := SavedTracksView(m.commands) newItems, err := SavedTracksView(m.commands)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
} }
case Albums: case Albums:
page = 1 page = 1
m.mode = Album m.mode = Album
m.album = m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimpleAlbum) m.album = m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimpleAlbum)
new_items, err := AlbumTracksView(m.album.ID, m.commands) newItems, err := AlbumTracksView(m.album.ID, m.commands)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
case Artist: case Artist:
m.mode = ArtistAlbum m.mode = ArtistAlbum
m.album = m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimpleAlbum) m.album = m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimpleAlbum)
new_items, err := AlbumTracksView(m.album.ID, m.commands) newItems, err := AlbumTracksView(m.album.ID, m.commands)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
case Artists: case Artists:
m.mode = Artist m.mode = Artist
m.artist = m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimpleArtist) m.artist = m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimpleArtist)
new_items, err := ArtistAlbumsView(m.artist.ID, m.commands) newItems, err := ArtistAlbumsView(m.artist.ID, m.commands)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
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)
@ -579,17 +579,17 @@ func (m *mainModel) SelectItem() error {
} }
}() }()
m.mode = "main" m.mode = "main"
new_items, err := MainView(m.commands) newItems, err := MainView(m.commands)
if err != nil { if err != nil {
return err return err
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
} }
return nil return nil
} }
func (m *mainModel) Init() tea.Cmd { func (m *mainModel) Init() tea.Cmd {
main_updates = make(chan *mainModel) mainUpdates = make(chan *mainModel)
return Tick() return Tick()
} }
@ -665,8 +665,8 @@ func (m *mainModel) Typing(msg tea.KeyMsg) (bool, tea.Cmd) {
func (m *mainModel) getContext(playing *spotify.CurrentlyPlaying) (string, error) { func (m *mainModel) getContext(playing *spotify.CurrentlyPlaying) (string, error) {
context := playing.PlaybackContext context := playing.PlaybackContext
uri_split := strings.Split(string(context.URI), ":") uriSplit := strings.Split(string(context.URI), ":")
if len(uri_split) < 3 { if len(uriSplit) < 3 {
return "", fmt.Errorf("NO URI") return "", fmt.Errorf("NO URI")
} }
id := strings.Split(string(context.URI), ":")[2] id := strings.Split(string(context.URI), ":")[2]
@ -699,7 +699,7 @@ func (m *mainModel) getContext(playing *spotify.CurrentlyPlaying) (string, error
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 := <-mainUpdates:
m.list.SetItems(update.list.Items()) m.list.SetItems(update.list.Items())
default: default:
} }
@ -721,11 +721,11 @@ func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if m.mode == Queue && len(m.list.Items()) != 0 { if m.mode == Queue && len(m.list.Items()) != 0 {
if m.list.Items()[0].(mainItem).SpotifyItem.(spotify.FullTrack).Name != playing.Item.Name { if m.list.Items()[0].(mainItem).SpotifyItem.(spotify.FullTrack).Name != playing.Item.Name {
go func() { go func() {
new_items, err := QueueView(m.commands) newItems, err := QueueView(m.commands)
if err != nil { if err != nil {
return return
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
}() }()
} }
} }
@ -806,11 +806,11 @@ func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// enter device selection // enter device selection
if msg.String() == "d" { if msg.String() == "d" {
m.mode = Devices m.mode = Devices
new_items, err := DeviceView(m.commands) newItems, err := DeviceView(m.commands)
if err != nil { if err != nil {
return m, tea.Quit return m, tea.Quit
} }
m.list.SetItems(new_items) m.list.SetItems(newItems)
m.list.ResetSelected() m.list.ResetSelected()
} }
// go back // go back

View File

@ -171,7 +171,7 @@ func SearchPlaylistsView(commands *commands.Commander, playlists *spotify.Simple
for _, playlist := range playlists.Playlists { for _, playlist := range playlists.Playlists {
items = append(items, mainItem{ items = append(items, mainItem{
Name: playlist.Name, Name: playlist.Name,
Desc: stripHtmlRegex(playlist.Description), Desc: stripHTMLRegex(playlist.Description),
SpotifyItem: playlist, SpotifyItem: playlist,
}) })
} }
@ -269,13 +269,13 @@ func SavedTracksView(commands *commands.Commander) ([]list.Item, error) {
func MainView(c *commands.Commander) ([]list.Item, error) { func MainView(c *commands.Commander) ([]list.Item, error) {
c.Log.Debug("SWITCHING TO MAIN VIEW") c.Log.Debug("SWITCHING TO MAIN VIEW")
wg := errgroup.Group{} wg := errgroup.Group{}
var saved_items *spotify.SavedTrackPage var savedItems *spotify.SavedTrackPage
var playlists *spotify.SimplePlaylistPage var playlists *spotify.SimplePlaylistPage
var artists *spotify.FullArtistCursorPage var artists *spotify.FullArtistCursorPage
var albums *spotify.SavedAlbumPage var albums *spotify.SavedAlbumPage
wg.Go(func() (err error) { wg.Go(func() (err error) {
saved_items, err = c.Client().CurrentUsersTracks(c.Context, spotify.Limit(50), spotify.Offset(0)) savedItems, err = c.Client().CurrentUsersTracks(c.Context, spotify.Limit(50), spotify.Offset(0))
return return
}) })
@ -300,11 +300,11 @@ func MainView(c *commands.Commander) ([]list.Item, error) {
} }
items := []list.Item{} items := []list.Item{}
if saved_items != nil && saved_items.Total != 0 { if savedItems != nil && savedItems.Total != 0 {
items = append(items, mainItem{ items = append(items, mainItem{
Name: "Saved Tracks", Name: "Saved Tracks",
Desc: fmt.Sprintf("%d saved songs", saved_items.Total), Desc: fmt.Sprintf("%d saved songs", savedItems.Total),
SpotifyItem: saved_items, SpotifyItem: savedItems,
}) })
} }
if albums != nil && albums.Total != 0 { if albums != nil && albums.Total != 0 {
@ -330,7 +330,7 @@ func MainView(c *commands.Commander) ([]list.Item, error) {
for _, playlist := range playlists.Playlists { for _, playlist := range playlists.Playlists {
items = append(items, mainItem{ items = append(items, mainItem{
Name: playlist.Name, Name: playlist.Name,
Desc: stripHtmlRegex(playlist.Description), Desc: stripHTMLRegex(playlist.Description),
SpotifyItem: playlist, SpotifyItem: playlist,
}) })
} }
@ -338,7 +338,7 @@ func MainView(c *commands.Commander) ([]list.Item, error) {
return items, nil return items, nil
} }
func stripHtmlRegex(s string) string { func stripHTMLRegex(s string) string {
r := regexp.MustCompile(regex) r := regexp.MustCompile(regex)
return r.ReplaceAllString(s, "") return r.ReplaceAllString(s, "")
} }

View File

@ -1,7 +1,7 @@
package config package config
type Config struct { type Config struct {
ClientId string `yaml:"client_id"` ClientID string `yaml:"client_id"`
ClientSecret string `yaml:"client_secret"` ClientSecret string `yaml:"client_secret"`
ClientSecretCmd string `yaml:"client_secret_cmd"` ClientSecretCmd string `yaml:"client_secret_cmd"`
Port string `yaml:"port"` Port string `yaml:"port"`

View File

@ -33,24 +33,24 @@ func (fn roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error)
} }
func GetClient(conf *config.Config) (c *spotify.Client, err error) { func GetClient(conf *config.Config) (c *spotify.Client, err error) {
if conf.ClientId == "" || (conf.ClientSecret == "" && conf.ClientSecretCmd == "") || conf.Port == "" { if conf.ClientID == "" || (conf.ClientSecret == "" && conf.ClientSecretCmd == "") || conf.Port == "" {
return nil, fmt.Errorf("INVALID CONFIG") return nil, fmt.Errorf("INVALID CONFIG")
} }
if conf.ClientSecretCmd != "" { if conf.ClientSecretCmd != "" {
args := strings.Fields(conf.ClientSecretCmd) args := strings.Fields(conf.ClientSecretCmd)
cmd := args[0] cmd := args[0]
secret_command := exec.Command(cmd) secretCommand := exec.Command(cmd)
if len(args) > 1 { if len(args) > 1 {
secret_command.Args = args secretCommand.Args = args
} }
secret, err := secret_command.Output() secret, err := secretCommand.Output()
if err != nil { if err != nil {
panic(err) panic(err)
} }
conf.ClientSecret = strings.TrimSpace(string(secret)) conf.ClientSecret = strings.TrimSpace(string(secret))
} }
auth = spotifyauth.New( auth = spotifyauth.New(
spotifyauth.WithClientID(conf.ClientId), spotifyauth.WithClientID(conf.ClientID),
spotifyauth.WithClientSecret(conf.ClientSecret), spotifyauth.WithClientSecret(conf.ClientSecret),
spotifyauth.WithRedirectURL(fmt.Sprintf("http://localhost:%s/callback", conf.Port)), spotifyauth.WithRedirectURL(fmt.Sprintf("http://localhost:%s/callback", conf.Port)),
spotifyauth.WithScopes( spotifyauth.WithScopes(
@ -93,11 +93,11 @@ func GetClient(conf *config.Config) (c *spotify.Client, err error) {
}) })
authClient := auth.Client(authCtx, tok) authClient := auth.Client(authCtx, tok)
client := spotify.New(authClient, spotify.WithRetry(true)) client := spotify.New(authClient, spotify.WithRetry(true))
new_token, err := client.Token() newToken, err := client.Token()
if err != nil { if err != nil {
return nil, err return nil, err
} }
out, err := json.MarshalIndent(new_token, "", " ") out, err := json.MarshalIndent(newToken, "", " ")
if err != nil { if err != nil {
return nil, err return nil, err
} }