Skip to content

Commit

Permalink
Added the device selection feature. (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
szktkfm committed Jan 22, 2024
1 parent 67990c5 commit 8c209e0
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 34 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ Here are the key bindings for sptui:
| `:pause` | Pause playback |
| `:next` | Next track |
| `:prev` | Previous track |
| `:device` | Select a device |

4 changes: 2 additions & 2 deletions animtext.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ type AnimTextModel struct {
}

func (m AnimTextModel) UpdateAnimText(msg tea.Msg) (AnimTextModel, tea.Cmd) {
switch msg.(type) {
switch msg := msg.(type) {
case animTextTickMsg:
if m.id != msg.(animTextTickMsg).id {
if m.id != msg.id {
return m, nil
}
m.offset = (m.offset + 1) % len(m.text)
Expand Down
1 change: 1 addition & 0 deletions auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ var (
spotifyauth.WithScopes(
spotifyauth.ScopeUserReadPrivate,
spotifyauth.ScopeUserModifyPlaybackState,
spotifyauth.ScopeUserReadPlaybackState,
spotifyauth.ScopeUserLibraryRead,
spotifyauth.ScopePlaylistReadCollaborative,
spotifyauth.ScopePlaylistReadPrivate,
Expand Down
4 changes: 4 additions & 0 deletions bar.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,7 @@ func tickCmd(id string) tea.Cmd {
}
})
}

func (m BarModel) PositionMs() int {
return int(1000 / m.deltaDur * m.percent)
}
17 changes: 12 additions & 5 deletions help.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import (
)

type KeyMap struct {
Play key.Binding
Pause key.Binding
Next key.Binding
Prev key.Binding
Help key.Binding
Play key.Binding
Pause key.Binding
Next key.Binding
Prev key.Binding
Help key.Binding
Device key.Binding
}

type HelpModel struct {
Expand Down Expand Up @@ -45,6 +46,10 @@ func NewHelp() HelpModel {
key.WithKeys(""),
key.WithHelp(":help", ""),
),
Device: key.NewBinding(
key.WithKeys(""),
key.WithHelp(":device", ""),
),
//TODO: add more keybindings
},
}
Expand All @@ -59,6 +64,7 @@ func (m HelpModel) ShortHelp() []key.Binding {
m.KeyMap.Pause,
m.KeyMap.Next,
m.KeyMap.Prev,
m.KeyMap.Device,
}
}

Expand All @@ -69,6 +75,7 @@ func (m HelpModel) FullHelp() [][]key.Binding {
m.KeyMap.Pause,
m.KeyMap.Next,
m.KeyMap.Prev,
m.KeyMap.Device,
m.KeyMap.Help,
},
}
Expand Down
2 changes: 1 addition & 1 deletion list.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list
return
}

str := CleanString(fmt.Sprintf("%s", i))
str := CleanString(string(i))

var fn func(strs ...string) string
if index == m.Index() {
Expand Down
14 changes: 14 additions & 0 deletions spotify.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ type CurrentlyPlayingMsg struct {
Track *spotify.CurrentlyPlaying
}

type PlayerDevicesMsg struct {
PlayerDevices []spotify.PlayerDevice
}

type PlaybackMsg struct {
}

Expand Down Expand Up @@ -114,6 +118,16 @@ func GetCurrentlyPlayingTrackCmd(client *spotify.Client) tea.Cmd {
}
}

func GetAvailableDevicesCmd(client *spotify.Client) tea.Cmd {
return func() tea.Msg {
device, err := client.PlayerDevices(context.Background())
if err != nil {
return ErrMsg{Err: err}
}
return PlayerDevicesMsg{PlayerDevices: device}
}
}

func StartPlaybackCmd(client *spotify.Client, opts *spotify.PlayOptions) tea.Cmd {
return func() tea.Msg {
err := client.PlayOpt(context.Background(),
Expand Down
6 changes: 1 addition & 5 deletions style.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ var (
inactiveTabStyle = lipgloss.NewStyle().Border(inactiveTabBorder, true).
BorderForeground(highlightColor).Padding(0, 1)
activeTabStyle = inactiveTabStyle.Copy().Border(activeTabBorder, true)
borderStyle = lipgloss.NewStyle().
Border(lipgloss.NormalBorder(), false, false, false, true).
BorderForeground(lipgloss.Color("5"))

windowStyle = lipgloss.NewStyle().
windowStyle = lipgloss.NewStyle().
BorderForeground(highlightColor).
Padding(1, 5).
Align(lipgloss.Left).
Expand Down
78 changes: 65 additions & 13 deletions tab.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ type TabModel struct {
tabs []string
activeTab int
tabContents []ListModel
trackList ListModel
listView ListModel

progress BarModel

Expand All @@ -65,6 +65,9 @@ type TabModel struct {
selectedPlaylist *spotify.FullPlaylist

currentlyPlaying *spotify.CurrentlyPlaying
currentDevice *spotify.PlayerDevice
devices []spotify.PlayerDevice
deviceMode bool
}

func (m TabModel) Init() tea.Cmd {
Expand Down Expand Up @@ -132,6 +135,10 @@ func (m TabModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return execTxtCommand(m)
}

if m.deviceMode {
return playOnDevice(m)
}

if m.depth == TRACKLIST {
return playTrack(m)
}
Expand All @@ -156,6 +163,14 @@ func (m TabModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, tea.Batch(tickCmd(tickID),
AnimTextTickCmd(tickID, 2000*time.Millisecond))

case PlayerDevicesMsg:
m.listView = NewListModel(playerDeviceToItemList(msg.PlayerDevices),
WithTitle("Select Device"),
)
m.deviceMode = true
m.devices = msg.PlayerDevices
m.depth = TRACKLIST

case PlaybackMsg:
//TODO: Fix
time.Sleep(500 * time.Millisecond)
Expand All @@ -180,6 +195,22 @@ func (m TabModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

}

func playOnDevice(m TabModel) (tea.Model, tea.Cmd) {
m.currentDevice = &m.devices[m.listView.list.Index()]
m.deviceMode = false
m.depth = TOP
if m.currentlyPlaying != nil && m.currentlyPlaying.Playing {
return m, StartPlaybackCmd(m.client,
&spotify.PlayOptions{
DeviceID: &m.currentDevice.ID,
URIs: []spotify.URI{m.currentlyPlaying.Item.URI},
PositionMs: m.progress.PositionMs(),
},
)
}
return m, nil
}

func execTxtCommand(m TabModel) (tea.Model, tea.Cmd) {
txtCmd := m.textInput.textInput.Value()
m.textMode = NONE
Expand All @@ -193,26 +224,39 @@ func execTxtCommand(m TabModel) (tea.Model, tea.Cmd) {
if m.progress.IsPlaying {
return m, nil
}
return m, StartPlaybackCmd(m.client,
&spotify.PlayOptions{

var opt *spotify.PlayOptions
if m.devices != nil {
opt = &spotify.PlayOptions{
DeviceID: &m.currentDevice.ID,
URIs: []spotify.URI{m.currentlyPlaying.Item.URI},
PositionMs: m.currentlyPlaying.Progress,
},
)
}

} else {
opt = &spotify.PlayOptions{
URIs: []spotify.URI{m.currentlyPlaying.Item.URI},
PositionMs: m.currentlyPlaying.Progress,
}
}
return m, StartPlaybackCmd(m.client, opt)

case "pause":
return m, PausePlaybackCmd(m.client)
case "next":
return m, NextPlaybackCmd(m.client)
case "prev":
return m, PreviousPlaybackCmd(m.client)
case "device":
return m, GetAvailableDevicesCmd(m.client)

default:
return m, nil
}
}

func playTrack(m TabModel) (tea.Model, tea.Cmd) {
selected := m.trackList.list.Index()
selected := m.listView.list.Index()
switch m.activeTab {
case PLAYLIST:
return m, StartPlaybackCmd(m.client,
Expand Down Expand Up @@ -250,20 +294,20 @@ func listUpdate(m TabModel, msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case AlbumDetailMsg:
m.selectedAlbum = msg.Album
m.trackList = NewListModel(
m.listView = NewListModel(
albumTracksToItemList(msg.Album.Tracks.Tracks),
WithTitle(msg.Album.Name+" ("+msg.Album.Artists[0].Name+")"),
)

case ShowDetailMsg:
m.episodes = msg.Show.Episodes.Episodes
m.trackList = NewListModel(episodesToItemList(m.episodes),
m.listView = NewListModel(episodesToItemList(m.episodes),
WithTitle(msg.Show.Name),
)

case PlaylistDetailMsg:
m.selectedPlaylist = msg.Playlist
m.trackList = NewListModel(playlistTracksToItemList(msg.Playlist.Tracks.Tracks),
m.listView = NewListModel(playlistTracksToItemList(msg.Playlist.Tracks.Tracks),
WithTitle(msg.Playlist.Name),
)

Expand All @@ -275,8 +319,8 @@ func listUpdate(m TabModel, msg tea.Msg) (tea.Model, tea.Cmd) {
}
}

newListModel, cmd := m.trackList.UpdateList(msg, m.depth)
m.trackList = newListModel
newListModel, cmd := m.listView.UpdateList(msg, m.depth)
m.listView = newListModel
return m, cmd
}

Expand Down Expand Up @@ -383,7 +427,7 @@ func tabUpdate(msg tea.Msg, m TabModel) (tea.Model, tea.Cmd) {
func getTracks(m TabModel) (tea.Model, tea.Cmd) {

m.depth = TRACKLIST
m.trackList = NewListModel([]list.Item{item(loading)})
m.listView = NewListModel([]list.Item{item(loading)})

selected := m.tabContents[m.activeTab].list.Index()
switch m.activeTab {
Expand All @@ -398,6 +442,14 @@ func getTracks(m TabModel) (tea.Model, tea.Cmd) {
}
}

func playerDeviceToItemList(devices []spotify.PlayerDevice) []list.Item {
var itemList []list.Item
for _, d := range devices {
itemList = append(itemList, item(d.Name))
}
return itemList
}

func playlistTracksToItemList(tracks []spotify.PlaylistTrack) []list.Item {
var itemList []list.Item
for _, t := range tracks {
Expand Down Expand Up @@ -522,7 +574,7 @@ func tracksView(m TabModel) string {

doc.WriteString(
windowStyleDtl.
Render(m.trackList.View(m.depth)))
Render(m.listView.View(m.depth)))
return docStyle.Render(doc.String())
}

Expand Down
5 changes: 1 addition & 4 deletions textinput.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package sptui

import (
"fmt"
"strings"

"github.com/charmbracelet/bubbles/textinput"
Expand Down Expand Up @@ -56,9 +55,7 @@ func (m TextModel) UpdateText(msg tea.Msg) (TextModel, tea.Cmd) {
func (m TextModel) ViewText(textMode int) string {
pad := strings.Repeat(" ", padding)
if textMode == INPUT || textMode == ERROR {
return pad + fmt.Sprintf(
m.textInput.View(),
)
return pad + m.textInput.View()
}
return ""
}
5 changes: 1 addition & 4 deletions util.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package sptui

import (
"fmt"
"strings"

"github.com/mattn/go-runewidth"
Expand All @@ -24,8 +23,6 @@ const (
empty = ""
)

var replacer = strings.NewReplacer(string(ZWSP), empty)

func RemoveZeroWidthSpace(s string) string {
return strings.Replace(s, string(ZWSP), empty, -1)
}
Expand Down Expand Up @@ -63,7 +60,7 @@ func WrapText(s string, width int, line int) string {

func PadOrTruncate(s string, n int) string {
if runewidth.StringWidth(s) > listWidth {
return fmt.Sprintf("%s", runewidth.Truncate(s, n, ""))
return runewidth.Truncate(s, n, "")
} else {
return s + strings.Repeat(" ", listWidth-runewidth.StringWidth(s))
}
Expand Down

0 comments on commit 8c209e0

Please sign in to comment.