Compare commits

...

4 Commits

Author SHA1 Message Date
Hördle Bot
cdd2ff15d5 Bump version to 0.1.6.22 2025-12-05 22:25:41 +01:00
Hördle Bot
adcfbfa811 Fix pause functionality for waveform editor playback buttons 2025-12-05 22:25:39 +01:00
Hördle Bot
0cdfe90476 Bump version to 0.1.6.21 2025-12-05 22:06:44 +01:00
Hördle Bot
1715ca02ed Remove duplicate back button from curator special editor 2025-12-05 22:06:42 +01:00
3 changed files with 76 additions and 29 deletions

View File

@@ -98,19 +98,6 @@ export default function CurateSpecialEditor({
return (
<div style={{ padding: '2rem', maxWidth: '1200px', margin: '0 auto' }}>
<div style={{ marginBottom: '2rem' }}>
<button
onClick={onBack}
style={{
padding: '0.5rem 1rem',
background: '#e5e7eb',
border: 'none',
borderRadius: '0.5rem',
cursor: 'pointer',
marginBottom: '1rem'
}}
>
{backLabel}
</button>
<h1 style={{ fontSize: '2rem', fontWeight: 'bold' }}>
{headerPrefix} {specialName}
</h1>

View File

@@ -17,6 +17,8 @@ export default function WaveformEditor({ audioUrl, startTime, duration, unlockSt
const [isPlaying, setIsPlaying] = useState(false);
const [playingSegment, setPlayingSegment] = useState<number | null>(null);
const [isPlayingFullTitle, setIsPlayingFullTitle] = useState(false);
const [pausedPosition, setPausedPosition] = useState<number | null>(null); // Position when paused
const [pausedType, setPausedType] = useState<'selection' | 'title' | null>(null); // Type of playback that was paused
const [zoom, setZoom] = useState(1); // 1 = full view, higher = zoomed in
const [viewOffset, setViewOffset] = useState(0); // Offset in seconds for panning
const [playbackPosition, setPlaybackPosition] = useState<number | null>(null); // Current playback position in seconds
@@ -234,12 +236,22 @@ export default function WaveformEditor({ audioUrl, startTime, duration, unlockSt
setHoverPreviewTime(null);
};
const stopPlayback = () => {
const stopPlayback = (savePosition = false) => {
if (savePosition && playbackPosition !== null) {
// Save current position for resume
setPausedPosition(playbackPosition);
} else {
// Clear paused position if stopping completely
setPausedPosition(null);
setPausedType(null);
}
sourceRef.current?.stop();
setIsPlaying(false);
setPlayingSegment(null);
setIsPlayingFullTitle(false);
setPlaybackPosition(null);
if (!savePosition) {
setPlaybackPosition(null);
}
if (animationFrameRef.current) {
cancelAnimationFrame(animationFrameRef.current);
animationFrameRef.current = null;
@@ -307,35 +319,55 @@ export default function WaveformEditor({ audioUrl, startTime, duration, unlockSt
const handlePlayFull = () => {
if (!audioBuffer || !audioContextRef.current) return;
// If full selection playback is already playing, stop it
// If full selection playback is already playing, pause it
if (isPlaying && playingSegment === null && !isPlayingFullTitle) {
stopPlayback();
stopPlayback(true); // Save position
setPausedType('selection');
return;
}
// Stop any current playback (segment, full selection, or full title)
stopPlayback();
// Determine start position (resume from pause or start from beginning)
const resumePosition = pausedType === 'selection' && pausedPosition !== null
? pausedPosition
: startTime;
const remainingDuration = resumePosition >= startTime + duration
? 0
: (startTime + duration) - resumePosition;
if (remainingDuration <= 0) {
// Already finished, reset
setPausedPosition(null);
setPausedType(null);
return;
}
// Start full selection playback
const source = audioContextRef.current.createBufferSource();
source.buffer = audioBuffer;
source.connect(audioContextRef.current.destination);
playbackStartTimeRef.current = audioContextRef.current.currentTime;
playbackOffsetRef.current = startTime;
playbackOffsetRef.current = resumePosition;
source.start(0, startTime, duration);
source.start(0, resumePosition, remainingDuration);
sourceRef.current = source;
setIsPlaying(true);
setPlayingSegment(null);
setIsPlayingFullTitle(false);
setPlaybackPosition(startTime);
setPausedPosition(null);
setPausedType(null);
setPlaybackPosition(resumePosition);
source.onended = () => {
setIsPlaying(false);
setPlayingSegment(null);
setIsPlayingFullTitle(false);
setPlaybackPosition(null);
setPausedPosition(null);
setPausedType(null);
if (animationFrameRef.current) {
cancelAnimationFrame(animationFrameRef.current);
animationFrameRef.current = null;
@@ -346,35 +378,55 @@ export default function WaveformEditor({ audioUrl, startTime, duration, unlockSt
const handlePlayFullTitle = () => {
if (!audioBuffer || !audioContextRef.current) return;
// If full title playback is already playing, stop it
// If full title playback is already playing, pause it
if (isPlaying && isPlayingFullTitle) {
stopPlayback();
stopPlayback(true); // Save position
setPausedType('title');
return;
}
// Stop any current playback (segment, full selection, or full title)
stopPlayback();
// Start full title playback (from 0 to audioDuration)
// Determine start position (resume from pause or start from beginning)
const resumePosition = pausedType === 'title' && pausedPosition !== null
? pausedPosition
: 0;
const remainingDuration = resumePosition >= audioDuration
? 0
: audioDuration - resumePosition;
if (remainingDuration <= 0) {
// Already finished, reset
setPausedPosition(null);
setPausedType(null);
return;
}
// Start full title playback (from resumePosition to audioDuration)
const source = audioContextRef.current.createBufferSource();
source.buffer = audioBuffer;
source.connect(audioContextRef.current.destination);
playbackStartTimeRef.current = audioContextRef.current.currentTime;
playbackOffsetRef.current = 0;
playbackOffsetRef.current = resumePosition;
source.start(0, 0, audioDuration);
source.start(0, resumePosition, remainingDuration);
sourceRef.current = source;
setIsPlaying(true);
setPlayingSegment(null);
setIsPlayingFullTitle(true);
setPlaybackPosition(0);
setPausedPosition(null);
setPausedType(null);
setPlaybackPosition(resumePosition);
source.onended = () => {
setIsPlaying(false);
setPlayingSegment(null);
setIsPlayingFullTitle(false);
setPlaybackPosition(null);
setPausedPosition(null);
setPausedType(null);
if (animationFrameRef.current) {
cancelAnimationFrame(animationFrameRef.current);
animationFrameRef.current = null;
@@ -470,7 +522,11 @@ export default function WaveformEditor({ audioUrl, startTime, duration, unlockSt
fontWeight: 'bold'
}}
>
{isPlaying && playingSegment === null && !isPlayingFullTitle ? '⏸ Pause' : '▶ Play Full Selection'}
{isPlaying && playingSegment === null && !isPlayingFullTitle
? '⏸ Pause'
: (pausedType === 'selection' && pausedPosition !== null
? '▶ Resume'
: '▶ Play Full Selection')}
</button>
<button
onClick={handlePlayFullTitle}
@@ -484,7 +540,11 @@ export default function WaveformEditor({ audioUrl, startTime, duration, unlockSt
fontWeight: 'bold'
}}
>
{isPlaying && isPlayingFullTitle ? '⏸ Pause' : '▶ Play Full Title'}
{isPlaying && isPlayingFullTitle
? '⏸ Pause'
: (pausedType === 'title' && pausedPosition !== null
? '▶ Resume'
: '▶ Play Full Title')}
</button>
<div style={{ fontSize: '0.875rem', color: '#666' }}>

View File

@@ -1,6 +1,6 @@
{
"name": "hoerdle",
"version": "0.1.6.20",
"version": "0.1.6.22",
"private": true,
"scripts": {
"dev": "next dev",