From be3c0c9d03c8257237121bfd89acf25dec36ff48 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sat, 17 Jul 2021 22:04:46 -0300 Subject: make next/previous buttons pay heed to timestamps! --- todo.txt | 6 ++++ ui.js | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 100 insertions(+), 6 deletions(-) diff --git a/todo.txt b/todo.txt index f8202c2..fa437df 100644 --- a/todo.txt +++ b/todo.txt @@ -607,3 +607,9 @@ TODO: Apparently, seeking to a timestamp under a previous track in the queue TODO: Next/previous buttons should seek between timestamps if there are more within the same track. + (Done!) + +TODO: Should skipping back to a previous track with timestamps automatically + seek to the final timestamp within that track? I'm undecided, but at the + moment leaning *slightly* towards "no". I may be biased due to it is + harder to code that behavior though! :P diff --git a/ui.js b/ui.js index b67fc8d..bc7f68d 100644 --- a/ui.js +++ b/ui.js @@ -1117,6 +1117,27 @@ class AppElement extends FocusElement { return this.timestampDictionary.get(item) || null } + getTimestampAtSec(item, sec) { + const timestampData = this.getTimestampData(item) + if (!timestampData) { + return null + } + + // Just like, start from the end, man. + // Why doesn't JavaScript have a findIndexFromEnd function??? + for (let i = timestampData.length - 1; i >= 0; i--) { + const ts = timestampData[i]; + if ( + ts.timestamp <= sec && + ts.timestampEnd >= sec + ) { + return ts + } + } + + return null + } + async readTimestampData(item) { const file = this.getTimestampsFile(item) @@ -1217,19 +1238,86 @@ class AppElement extends FocusElement { // all are before this position, skip to previous. let maxCurSec = 0 - this.forEachQueuePlayerToActOn(({ timeData }) => { - if (timeData) { - maxCurSec = Math.max(maxCurSec, timeData.curSecTotal) + this.forEachQueuePlayerToActOn(qp => { + if (qp.timeData) { + let effectiveCurSec = qp.timeData.curSecTotal + + const ts = this.getTimestampAtSec(qp.playingTrack, qp.timeData.curSecTotal) + if (ts) { + effectiveCurSec -= ts.timestamp + } + + maxCurSec = Math.max(maxCurSec, effectiveCurSec) } }) if (Math.floor(maxCurSec) < this.config.seekToStartThreshold) { - this.actOnQueuePlayers(qp => qp.playPrevious(qp.playingTrack, true)) + this.skipBack() } else { - this.actOnQueuePlayers(qp => qp.seekToStart()) + this.seekToStart() } } + seekToStart() { + this.actOnQueuePlayers(qp => qp.seekToStart()) + this.actOnQueuePlayers(qp => { + if (!qp.playingTrack) { + return + } + + const ts = this.getTimestampAtSec(qp.playingTrack, qp.timeData.curSecTotal) + if (ts) { + qp.seekTo(ts.timestamp) + return + } + + qp.seekToStart() + }) + } + + skipBack() { + this.actOnQueuePlayers(qp => { + if (!qp.playingTrack) { + return + } + + const ts = this.getTimestampAtSec(qp.playingTrack, qp.timeData.curSecTotal) + if (ts) { + const timestampData = this.getTimestampData(qp.playingTrack) + const playingTimestampIndex = timestampData.indexOf(ts) + const previous = timestampData[playingTimestampIndex - 1] + if (previous) { + qp.seekTo(previous.timestamp) + return + } + } + + qp.playPrevious(qp.playingTrack, true) + }) + } + + skipAhead() { + this.actOnQueuePlayers(qp => { + if (!qp.playingTrack) { + return + } + + const ts = this.getTimestampAtSec(qp.playingTrack, qp.timeData.curSecTotal) + + if (ts) { + const timestampData = this.getTimestampData(qp.playingTrack) + const playingTimestampIndex = timestampData.indexOf(ts) + const next = timestampData[playingTimestampIndex + 1] + if (next) { + qp.seekTo(next.timestamp) + return + } + } + + qp.playNext(qp.playingTrack, true) + }) + } + actOnQueuePlayers(fn) { this.forEachQueuePlayerToActOn(queuePlayer => { fn(queuePlayer) @@ -1610,7 +1698,7 @@ class AppElement extends FocusElement { } else if (input.isSkipBack(keyBuf)) { this.skipBackOrSeekToStart() } else if (input.isSkipAhead(keyBuf)) { - this.actOnQueuePlayers(qp => qp.playNext(qp.playingTrack, true)) + this.skipAhead() } } -- cgit 1.3.0-6-gf8a5