Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Global search #40

Merged
merged 5 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Dev Branch:
- Browse by folder
- Queue songs and albums
- Create and play playlists
- Search music library
- Mark favorites
- Volume control
- Server-side scrobbling (e.g., on Navidrome, gonic)
Expand Down Expand Up @@ -81,7 +82,8 @@ spinner = '▁▂▃▄▅▆▇█▇▆▅▄▃▂▁'
- `1`: Folder view
- `2`: Queue view
- `3`: Playlist view
- `4`: Log (errors, etc.) view
- `4`: Search view
- `5`: Log (errors, etc.) view
- `Escape`/`Return`: Close modal if open

### Playback Controls
Expand Down Expand Up @@ -133,6 +135,25 @@ spinner = '⣾⣽⣻⢿⡿⣟⣯⣷'

The default is `▉▊▋▌▍▎▏▎▍▌▋▊▉`. Set only one of these at a time, and the glyphs must exist in the font that the terminal running stmps is using.

### Search Controls

The search tab performs a server-side search for text in metadata name fields.
The search results are filtered into three columns: artist, album, and song. 20
results (in each column) are fetched at a time; use `n` to load more results.

In any of the columns:

- `/`: Focus search field.
- `Enter` / `a`: Adds the selected item recursively to the queue.
- `n`: Load more search results.
- Left/right arrow keys (`←`, `→`) navigate between the columns
- Up/down arrow keys (`↓`, `↑`) navigate the selected column list

In the search field:

- `Enter`: Perform the query.
- `Escape`: Escapes into the columns, where the global key bindings work.

## Advanced Configuration and Features

### MPRIS2 Integration
Expand Down
2 changes: 1 addition & 1 deletion event_loop.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (ui *Ui) guiEventLoop() {
select {
case <-fpsTimer.C:
fpsTimer.Reset(10 * time.Second)
ui.logger.Printf("guiEventLoop: %f events per second", events/10.0)
// ui.logger.Printf("guiEventLoop: %f events per second", events/10.0)
events = 0

case msg := <-ui.logger.Prints:
Expand Down
8 changes: 8 additions & 0 deletions gui.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ type Ui struct {
// playlist page
playlistPage *PlaylistPage

// search page
searchPage *SearchPage

// log page
logPage *LogPage

Expand All @@ -61,6 +64,7 @@ const (
PageBrowser = "browser"
PageQueue = "queue"
PagePlaylists = "playlists"
PageSearch = "search"
PageLog = "log"

PageDeletePlaylist = "deletePlaylist"
Expand Down Expand Up @@ -149,12 +153,16 @@ func InitGui(indexes *[]subsonic.SubsonicIndex,
// playlist page
ui.playlistPage = ui.createPlaylistPage()

// search page
ui.searchPage = ui.createSearchPage()

// log page
ui.logPage = ui.createLogPage()

ui.pages.AddPage(PageBrowser, ui.browserPage.Root, true, true).
AddPage(PageQueue, ui.queuePage.Root, true, false).
AddPage(PagePlaylists, ui.playlistPage.Root, true, false).
AddPage(PageSearch, ui.searchPage.Root, true, false).
AddPage(PageDeletePlaylist, ui.playlistPage.DeletePlaylistModal, true, false).
AddPage(PageNewPlaylist, ui.playlistPage.NewPlaylistModal, true, false).
AddPage(PageAddToPlaylist, ui.browserPage.AddToPlaylistModal, true, false).
Expand Down
17 changes: 8 additions & 9 deletions gui_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
func (ui *Ui) handlePageInput(event *tcell.EventKey) *tcell.EventKey {
// we don't want any of these firing if we're trying to add a new playlist
focused := ui.app.GetFocus()
if ui.playlistPage.IsNewPlaylistInputFocused(focused) || ui.browserPage.IsSearchFocused(focused) {
if ui.playlistPage.IsNewPlaylistInputFocused(focused) || ui.browserPage.IsSearchFocused(focused) || focused == ui.searchPage.searchField {
return event
}

Expand All @@ -27,6 +27,9 @@ func (ui *Ui) handlePageInput(event *tcell.EventKey) *tcell.EventKey {
ui.ShowPage(PagePlaylists)

case '4':
ui.ShowPage(PageSearch)

case '5':
ui.ShowPage(PageLog)

case '?':
Expand All @@ -50,7 +53,6 @@ func (ui *Ui) handlePageInput(event *tcell.EventKey) *tcell.EventKey {
if err != nil {
ui.logger.PrintError("handlePageInput: Pause", err)
}
return nil

case 'P':
// stop playing without changes to queue
Expand All @@ -59,52 +61,49 @@ func (ui *Ui) handlePageInput(event *tcell.EventKey) *tcell.EventKey {
if err != nil {
ui.logger.PrintError("handlePageInput: Stop", err)
}
return nil

case 'X':
// debug stuff
ui.logger.Print("test")
//ui.player.Test()
ui.showMessageBox("foo bar")
return nil

case '-':
// volume-
if err := ui.player.AdjustVolume(-5); err != nil {
ui.logger.PrintError("handlePageInput: AdjustVolume-", err)
}
return nil

case '+', '=':
// volume+
if err := ui.player.AdjustVolume(5); err != nil {
ui.logger.PrintError("handlePageInput: AdjustVolume+", err)
}
return nil

case '.':
// <<
if err := ui.player.Seek(10); err != nil {
ui.logger.PrintError("handlePageInput: Seek+", err)
}
return nil

case ',':
// >>
if err := ui.player.Seek(-10); err != nil {
ui.logger.PrintError("handlePageInput: Seek-", err)
}
return nil

case '>':
// skip to next track
if err := ui.player.PlayNextTrack(); err != nil {
ui.logger.PrintError("handlePageInput: Next", err)
}
ui.queuePage.UpdateQueue()

default:
return event
}

return event
return nil
}

func (ui *Ui) ShowPage(name string) {
Expand Down
13 changes: 13 additions & 0 deletions help_text.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,16 @@ n new playlist
d delete playlist
a add playlist or song to queue
`

const helpSearchPage = `
artist, album, or song tab
Down focus search field
Left previous column
Right next column
Enter recursively add item to quue
a recursively add item to quue
/ start search
n load more results
search field
Enter search for text
`
4 changes: 1 addition & 3 deletions page_browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ func (ui *Ui) createBrowserPage(indexes *[]subsonic.SubsonicIndex) *BrowserPage
AddItem(browserPage.artistList, 0, 1, true).
AddItem(browserPage.entityList, 0, 1, false)

// TODO (A) add search-for-song, if feasible. Might be able to do server-side then drill-down, but we might also have all entities cached on the client already. To investigate.
browserPage.Root = tview.NewFlex().SetDirection(tview.FlexRow)
browserPage.showSearchField(false) // add artist/search items

Expand Down Expand Up @@ -254,8 +253,7 @@ func (b *BrowserPage) UpdateStars() {
}

func (b *BrowserPage) handleAddArtistToQueue() {
currentIndex := b.artistList.GetCurrentItem()
if currentIndex < 0 {
if b.artistList.GetCurrentItem() < 0 {
return
}

Expand Down
6 changes: 3 additions & 3 deletions page_playlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ func (p *PlaylistPage) UpdatePlaylists() {
spinnerText = []rune("▉▊▋▌▍▎▏▎▍▌▋▊▉")
}
spinnerMax := len(spinnerText) - 1
playlistsButton := buttonOrder[2]
playlistsButton := buttonOrder[PAGE_PLAYLISTS]
stop := make(chan bool)
go func() {
var idx int
Expand All @@ -219,7 +219,7 @@ func (p *PlaylistPage) UpdatePlaylists() {
} else {
format = "%d: [red]%c[white]%s"
}
label := fmt.Sprintf(format, 3, spinnerText[idx], playlistsButton)
label := fmt.Sprintf(format, PAGE_PLAYLISTS+1, spinnerText[idx], playlistsButton)
p.ui.menuWidget.buttons[playlistsButton].SetLabel(label)
idx++
if idx > spinnerMax {
Expand All @@ -234,7 +234,7 @@ func (p *PlaylistPage) UpdatePlaylists() {
} else {
format = "%d: %s"
}
label := fmt.Sprintf(format, 3, playlistsButton)
label := fmt.Sprintf(format, PAGE_PLAYLISTS+1, playlistsButton)
p.ui.menuWidget.buttons[playlistsButton].SetLabel(label)
})
close(stop)
Expand Down
Loading