From a51f9860dab8d257f7dd320d6fdc80d17b9222e7 Mon Sep 17 00:00:00 2001 From: "Sean E. Russell" Date: Sun, 15 Sep 2024 11:50:42 -0500 Subject: [PATCH 1/3] Implements #36: adds ability to reorder the queue --- help_text.go | 2 ++ mpvplayer/player.go | 24 +++++++++++++++ page_queue.go | 73 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 96 insertions(+), 3 deletions(-) diff --git a/help_text.go b/help_text.go index 412674f..b317839 100644 --- a/help_text.go +++ b/help_text.go @@ -32,6 +32,8 @@ const helpPageQueue = ` d/DEL remove currently selected song from the queue D remove all songs from queue y toggle star on song +k move selected song up in queue +j move selected song down in queue ` const helpPagePlaylists = ` diff --git a/mpvplayer/player.go b/mpvplayer/player.go index fdff813..4c91aae 100644 --- a/mpvplayer/player.go +++ b/mpvplayer/player.go @@ -283,6 +283,30 @@ func (p *Player) AddToQueue(item *QueueItem) { p.queue = append(p.queue, *item) } +func (p *Player) MoveSongUp(index int) { + if index < 1 { + p.logger.Printf("MoveSongUp(%d) can't move top item", index) + return + } + if index >= len(p.queue) { + p.logger.Printf("MoveSongUp(%d) not that many songs in queue", index) + return + } + p.queue[index-1], p.queue[index] = p.queue[index], p.queue[index-1] +} + +func (p *Player) MoveSongDown(index int) { + if index < 0 { + p.logger.Printf("MoveSongUp(%d) invalid index", index) + return + } + if index >= len(p.queue)-1 { + p.logger.Printf("MoveSongUp(%d) can't move last song down", index) + return + } + p.queue[index], p.queue[index+1] = p.queue[index+1], p.queue[index] +} + func (p *Player) GetQueueItem(index int) (QueueItem, error) { if index < 0 || index >= len(p.queue) { return QueueItem{}, errors.New("invalid queue entry") diff --git a/page_queue.go b/page_queue.go index 01a8a20..576860b 100644 --- a/page_queue.go +++ b/page_queue.go @@ -58,9 +58,18 @@ func (ui *Ui) createQueuePage() *QueuePage { if event.Key() == tcell.KeyDelete || event.Rune() == 'd' { queuePage.handleDeleteFromQueue() return nil - } else if event.Rune() == 'y' { - queuePage.handleToggleStar() - return nil + } else { + switch event.Rune() { + case 'y': + queuePage.handleToggleStar() + return nil + case 'j': + queuePage.moveSongDown() + return nil + case 'k': + queuePage.moveSongUp() + return nil + } } return event @@ -151,6 +160,64 @@ func (q *QueuePage) updateQueue() { } } +// moveSongUp moves the currently selected song up in the queue +// If the selected song isn't the third or higher, this is a NOP +// and no error is reported. +func (q *QueuePage) moveSongUp() { + if len(q.queueData.playerQueue) == 0 { + return + } + + currentIndex, column := q.queueList.GetSelection() + if currentIndex < 0 || column < 0 { + q.logger.Printf("moveSongUp: invalid selection (%d, %d)", currentIndex, column) + return + } + + if currentIndex == 0 { + return + } + + if currentIndex == 1 { + q.ui.player.Stop() + } + + // remove the item from the queue + q.ui.player.MoveSongUp(currentIndex) + q.queueList.Select(currentIndex-1, column) + q.updateQueue() +} + +// moveSongUp moves the currently selected song up in the queue +// If the selected song is not the second-to-the-last or lower, this is a NOP, +// and no error is reported +func (q *QueuePage) moveSongDown() { + queueLen := len(q.queueData.playerQueue) + if queueLen == 0 { + return + } + + currentIndex, column := q.queueList.GetSelection() + if currentIndex < 0 || column < 0 { + q.logger.Printf("moveSongDown: invalid selection (%d, %d)", currentIndex, column) + return + } + + if currentIndex == 0 { + q.ui.player.Stop() + } + + if currentIndex > queueLen-2 { + q.logger.Printf("moveSongDown: can't move last song") + return + } + + // remove the item from the queue + q.ui.player.MoveSongDown(currentIndex) + q.queueList.Select(currentIndex+1, column) + q.updateQueue() +} + // queueData methods, used by tview to lazily render the table func (q *queueData) GetCell(row, column int) *tview.TableCell { if row >= len(q.playerQueue) || column >= queueDataColumns || row < 0 || column < 0 { From 54f75796156949df34902f8d08068231d11cf21c Mon Sep 17 00:00:00 2001 From: "Sean E. Russell" Date: Sun, 15 Sep 2024 11:56:06 -0500 Subject: [PATCH 2/3] Queue reordering: forgot to update the README. --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index edc5dfb..4a2083b 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,10 @@ These controls are accessible from any view: - `d`/`Delete`: Remove currently selected song from the queue - `D`: Remove all songs from queue - `y`: Toggle star on song +- `k`: Move song up in queue +- `j`: Move song down in queue + +If the currently playing song is moved, the music is stopped before the move, and must be re-started manually. ### Playlist Controls From 4757a3995c7f860e656b63c2fe967266c32565d9 Mon Sep 17 00:00:00 2001 From: "Sean E. Russell" Date: Tue, 17 Sep 2024 15:20:00 -0500 Subject: [PATCH 3/3] Adds "shuffle" function to queue --- help_text.go | 1 + mpvplayer/player.go | 10 ++++++++++ page_queue.go | 22 +++++++++++++++++----- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/help_text.go b/help_text.go index b317839..7b28ad4 100644 --- a/help_text.go +++ b/help_text.go @@ -34,6 +34,7 @@ D remove all songs from queue y toggle star on song k move selected song up in queue j move selected song down in queue +S shuffle the current queue ` const helpPagePlaylists = ` diff --git a/mpvplayer/player.go b/mpvplayer/player.go index 4c91aae..ed477f5 100644 --- a/mpvplayer/player.go +++ b/mpvplayer/player.go @@ -5,6 +5,7 @@ package mpvplayer import ( "errors" + "math/rand" "strconv" "github.com/spezifisch/stmps/logger" @@ -307,6 +308,15 @@ func (p *Player) MoveSongDown(index int) { p.queue[index], p.queue[index+1] = p.queue[index+1], p.queue[index] } +func (p *Player) Shuffle() { + max := len(p.queue) + for range max / 2 { + ra := rand.Intn(max) + rb := rand.Intn(max) + p.queue[ra], p.queue[rb] = p.queue[rb], p.queue[ra] + } +} + func (p *Player) GetQueueItem(index int) (QueueItem, error) { if index < 0 || index >= len(p.queue) { return QueueItem{}, errors.New("invalid queue entry") diff --git a/page_queue.go b/page_queue.go index 576860b..07f59b1 100644 --- a/page_queue.go +++ b/page_queue.go @@ -57,22 +57,22 @@ func (ui *Ui) createQueuePage() *QueuePage { queuePage.queueList.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { if event.Key() == tcell.KeyDelete || event.Rune() == 'd' { queuePage.handleDeleteFromQueue() - return nil } else { switch event.Rune() { case 'y': queuePage.handleToggleStar() - return nil case 'j': queuePage.moveSongDown() - return nil case 'k': queuePage.moveSongUp() - return nil + case 'S': + queuePage.shuffle() + default: + return event } } - return event + return nil }) // flex wrapper @@ -218,6 +218,18 @@ func (q *QueuePage) moveSongDown() { q.updateQueue() } +func (q *QueuePage) shuffle() { + if len(q.queueData.playerQueue) == 0 { + return + } + + q.ui.player.Stop() + q.ui.player.Shuffle() + + q.queueList.Select(0, 0) + q.updateQueue() +} + // queueData methods, used by tview to lazily render the table func (q *queueData) GetCell(row, column int) *tview.TableCell { if row >= len(q.playerQueue) || column >= queueDataColumns || row < 0 || column < 0 {