personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add skip-back and playback speed controls to speakers audio player

- Add CSS for .spk-player-controls, .spk-skip-back, and .spk-speed-toggle.
- Wrap the audio element in a flex control bar with a 5s skip-back button and speed toggle button.
- Wire skip-back to clamp currentTime with Math.max(0, currentTime - 5).
- Wire speed toggle to cycle playbackRate through [1, 1.5, 2] and update button label.
- Keep no-audio-file behavior and sentence play button handling unchanged.

+56 -3
+56 -3
apps/speakers/workspace.html
··· 151 151 width: 100%; 152 152 } 153 153 154 + .spk-player-controls { 155 + display: flex; 156 + align-items: center; 157 + gap: 8px; 158 + } 159 + 160 + .spk-player-controls audio { 161 + flex: 1; 162 + min-width: 0; 163 + } 164 + 165 + .spk-skip-back, 166 + .spk-speed-toggle { 167 + padding: 4px 8px; 168 + background: #e5e7eb; 169 + border: none; 170 + border-radius: 4px; 171 + font-size: 12px; 172 + cursor: pointer; 173 + white-space: nowrap; 174 + color: #374151; 175 + transition: background 0.15s; 176 + } 177 + 178 + .spk-skip-back:hover, 179 + .spk-speed-toggle:hover { 180 + background: #d1d5db; 181 + } 182 + 154 183 /* Sentence list */ 155 184 .spk-sentences { 156 185 margin-top: 16px; ··· 644 673 const audioContainer = document.getElementById('spkAudioContainer'); 645 674 if (audio_file) { 646 675 audioContainer.innerHTML = ` 647 - <audio id="spkAudio" controls preload="metadata"> 648 - <source src="${audio_file}" type="audio/flac"> 649 - </audio> 676 + <div class="spk-player-controls"> 677 + <button class="spk-skip-back" id="spkSkipBack" title="Back 5s">&#8634; 5s</button> 678 + <audio id="spkAudio" controls preload="metadata"> 679 + <source src="${audio_file}" type="audio/flac"> 680 + </audio> 681 + <button class="spk-speed-toggle" id="spkSpeedToggle" title="Playback speed">1x</button> 682 + </div> 650 683 `; 651 684 audioPlayer = document.getElementById('spkAudio'); 652 685 setupAudioListeners(); ··· 706 739 playingSentenceId = null; 707 740 } 708 741 }); 742 + 743 + // Skip back 5 seconds 744 + const skipBackBtn = document.getElementById('spkSkipBack'); 745 + if (skipBackBtn) { 746 + skipBackBtn.addEventListener('click', () => { 747 + audioPlayer.currentTime = Math.max(0, audioPlayer.currentTime - 5); 748 + }); 749 + } 750 + 751 + // Playback speed toggle: 1x -> 1.5x -> 2x -> 1x 752 + const speedToggleBtn = document.getElementById('spkSpeedToggle'); 753 + if (speedToggleBtn) { 754 + const speeds = [1, 1.5, 2]; 755 + speedToggleBtn.addEventListener('click', () => { 756 + const currentIndex = speeds.indexOf(audioPlayer.playbackRate); 757 + const nextIndex = (currentIndex + 1) % speeds.length; 758 + audioPlayer.playbackRate = speeds[nextIndex]; 759 + speedToggleBtn.textContent = speeds[nextIndex] + 'x'; 760 + }); 761 + } 709 762 } 710 763 711 764 function updateActiveSentence(currentTime) {