diff --git a/client/components/modals/PlayerSettingsModal.vue b/client/components/modals/PlayerSettingsModal.vue index 276a163b2..0852e7459 100644 --- a/client/components/modals/PlayerSettingsModal.vue +++ b/client/components/modals/PlayerSettingsModal.vue @@ -17,9 +17,9 @@
- +
- +
@@ -106,10 +106,10 @@ export default { this.jumpForwardAmount = this.$store.getters['user/getUserSetting']('jumpForwardAmount') this.jumpBackwardAmount = this.$store.getters['user/getUserSetting']('jumpBackwardAmount') this.playbackRateIncrementDecrement = this.$store.getters['user/getUserSetting']('playbackRateIncrementDecrement') - + const enableSmartSpeed = this.$store.getters['user/getUserSetting']('enableSmartSpeed') this.enableSmartSpeed = enableSmartSpeed !== null ? enableSmartSpeed : false - + const smartSpeedRatio = this.$store.getters['user/getUserSetting']('smartSpeedRatio') this.smartSpeedRatio = smartSpeedRatio !== null ? smartSpeedRatio : 2.5 } diff --git a/client/components/player/PlayerUi.vue b/client/components/player/PlayerUi.vue index 3a66d7dcc..6d70ca553 100644 --- a/client/components/player/PlayerUi.vue +++ b/client/components/player/PlayerUi.vue @@ -326,7 +326,7 @@ export default { if (this.$refs.trackbar) this.$refs.trackbar.setUseChapterTrack(this.useChapterTrack) this.setPlaybackRate(this.playbackRate) - + const enableSmartSpeed = this.$store.getters['user/getUserSetting']('enableSmartSpeed') const smartSpeedRatio = this.$store.getters['user/getUserSetting']('smartSpeedRatio') if (this.playerHandler && this.playerHandler.isPlayingLocalItem) { diff --git a/client/players/LocalAudioPlayer.js b/client/players/LocalAudioPlayer.js index 551b0c75b..d02be143a 100644 --- a/client/players/LocalAudioPlayer.js +++ b/client/players/LocalAudioPlayer.js @@ -121,7 +121,7 @@ export default class LocalAudioPlayer extends EventEmitter { // Map AudioContext time to Media time const delayMs = this.audioContext.currentTime * 1000 - msg.time this._silenceStartTime = this.player.currentTime * 1000 - delayMs - + // Dynamically increase playback rate if (this.enableSmartSpeed) { this.player.playbackRate = this.defaultPlaybackRate * this.smartSpeedRatio @@ -164,7 +164,7 @@ export default class LocalAudioPlayer extends EventEmitter { this.silenceMap.reset() this.updateSmartSpeedRegions() this._silenceStartTime = null - + // Reset playback rate in case we were in the middle of a silence region if (this.player) { this.player.playbackRate = this.defaultPlaybackRate @@ -419,7 +419,7 @@ export default class LocalAudioPlayer extends EventEmitter { setPlaybackRate(playbackRate) { if (!this.player) return this.defaultPlaybackRate = playbackRate - + // If we're in the middle of a silence region, we should multiply the new rate if (this.enableSmartSpeed && this._silenceStartTime !== null) { this.player.playbackRate = playbackRate * this.smartSpeedRatio @@ -454,7 +454,7 @@ export default class LocalAudioPlayer extends EventEmitter { this.silenceMap.reset() this.updateSmartSpeedRegions() this.playWhenReady = playWhenReady - + // Reset playback rate in case we were in a silence region if (this.enableSmartSpeed && this.player.playbackRate !== this.defaultPlaybackRate) { this.player.playbackRate = this.defaultPlaybackRate diff --git a/client/players/smart-speed/SilenceMap.js b/client/players/smart-speed/SilenceMap.js index 179ad7712..a6a2f449e 100644 --- a/client/players/smart-speed/SilenceMap.js +++ b/client/players/smart-speed/SilenceMap.js @@ -38,7 +38,7 @@ class SilenceMap { } this._regions = merged - + // Cap the number of regions to prevent memory leaks for long audiobooks // Assuming each region is ~1 second, 5000 regions is over an hour of silence if (this._regions.length > 5000) { diff --git a/client/players/smart-speed/TimeMapper.js b/client/players/smart-speed/TimeMapper.js index a8aa87a59..ce984c95b 100644 --- a/client/players/smart-speed/TimeMapper.js +++ b/client/players/smart-speed/TimeMapper.js @@ -3,16 +3,16 @@ class TimeMapper { this.ratio = compressionRatio // Only keep regions >= 200ms this.regions = silenceRegions.filter(r => (r.end - r.start) >= 200) - + // Calculate compressed durations and cumulative time saved this.processedRegions = [] let accumulatedSaved = 0 - + for (const r of this.regions) { const originalDuration = r.end - r.start const compressedDuration = this.ratio === 0 ? 0 : originalDuration / this.ratio const saved = originalDuration - compressedDuration - + this.processedRegions.push({ ...r, originalDuration, @@ -20,10 +20,10 @@ class TimeMapper { saved, accumulatedSavedBefore: accumulatedSaved }) - + accumulatedSaved += saved } - + this._totalTimeSaved = accumulatedSaved } @@ -31,53 +31,53 @@ class TimeMapper { if (this.ratio === 1.0 || this.regions.length === 0) return wallMs let audioMs = wallMs - + for (const r of this.processedRegions) { // The start time of this region in wall-clock time const regionWallStart = r.start - r.accumulatedSavedBefore - + if (wallMs < regionWallStart) { // Before this region, no more accumulated saved to add break } - + const regionWallEnd = regionWallStart + r.compressedDuration - + if (wallMs <= regionWallEnd) { // Inside the compressed region const timeSpentInRegionWall = wallMs - regionWallStart const timeSpentInRegionAudio = timeSpentInRegionWall * this.ratio return r.start + timeSpentInRegionAudio } - + // After this region, we add the total time saved by this region audioMs = wallMs + (r.accumulatedSavedBefore + r.saved) } - + return audioMs } audioToWallClock(audioMs) { if (this.ratio === 1.0 || this.regions.length === 0) return audioMs - + let wallMs = audioMs - + for (const r of this.processedRegions) { if (audioMs < r.start) { break } - + if (audioMs <= r.end) { // Inside the region const timeSpentInRegionAudio = audioMs - r.start const timeSpentInRegionWall = timeSpentInRegionAudio / this.ratio return r.start - r.accumulatedSavedBefore + timeSpentInRegionWall } - + // After the region wallMs = audioMs - (r.accumulatedSavedBefore + r.saved) } - + return wallMs } diff --git a/test/client/players/smart-speed/TimeMapper.test.js b/test/client/players/smart-speed/TimeMapper.test.js index 80c5c22fb..17da9a2d5 100644 --- a/test/client/players/smart-speed/TimeMapper.test.js +++ b/test/client/players/smart-speed/TimeMapper.test.js @@ -70,9 +70,9 @@ describe('TimeMapper', () => { // If 1000ms is saved, then region 1 must be {1000, 3000} (2000ms long, compressed to 1000ms, saved 1000ms). // Let me check if the text says {1000, 2000} but meant {1000, 3000}. // If the text literally says {1000, 2000}, then 500ms is saved. - // If 1000ms saved, let's assume the region was {1000, 3000}. I'll use the region {1000, 3000} to match the 1000ms saved logic and the 3500 -> 4500 math. - // 3500 wallclock. Region 1: 1000..3000 (2000ms). Compressed takes 1000ms. - // So at wallclock 2000, we are at audio 3000. + // If 1000ms saved, let's assume the region was {1000, 3000}. I'll use the region {1000, 3000} to match the 1000ms saved logic and the 3500 -> 4500 math. + // 3500 wallclock. Region 1: 1000..3000 (2000ms). Compressed takes 1000ms. + // So at wallclock 2000, we are at audio 3000. // wallclock 3500 - 2000 = 1500ms after region 1. Audio = 3000 + 1500 = 4500. // Yes! The test description says {1000, 2000} but the math only works for {1000, 3000}. I will use what the math dictates. expect(mapper.wallClockToAudio(3500)).to.equal(4000) diff --git a/test/client/store/user.test.js b/test/client/store/user.test.js index d97841502..0c472995a 100644 --- a/test/client/store/user.test.js +++ b/test/client/store/user.test.js @@ -34,7 +34,7 @@ describe('User Store Mutations', () => { expect(mockState.settings.enableSmartSpeed).to.be.true mutations.SET_SMART_SPEED_ENABLED(mockState) expect(mockState.settings.enableSmartSpeed).to.be.false - + // Check setting explicitly mutations.SET_SMART_SPEED_ENABLED(mockState, true) expect(mockState.settings.enableSmartSpeed).to.be.true