diff options
| author | Maze <167211895+mazeincoding@users.noreply.github.com> | 2026-01-31 00:20:04 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-31 00:20:04 +0100 |
| commit | 7bf0984698e43b9aa2dd879f65951318ed410390 (patch) | |
| tree | ccf2cd590a47d550152afc07129cb55c71a9ec35 /apps/web/src/stores/playback-store.ts | |
| parent | 0173db99448d1c4c6415dcf15272e17551b48b04 (diff) | |
| download | opencut-7bf0984698e43b9aa2dd879f65951318ed410390.tar.gz | |
codebase overhaul (#697)
Diffstat (limited to 'apps/web/src/stores/playback-store.ts')
| -rw-r--r-- | apps/web/src/stores/playback-store.ts | 174 |
1 files changed, 0 insertions, 174 deletions
diff --git a/apps/web/src/stores/playback-store.ts b/apps/web/src/stores/playback-store.ts deleted file mode 100644 index c2b9cf4a..00000000 --- a/apps/web/src/stores/playback-store.ts +++ /dev/null @@ -1,174 +0,0 @@ -import { create } from "zustand"; -import type { PlaybackState, PlaybackControls } from "@/types/playback"; -import { useTimelineStore } from "@/stores/timeline-store"; -import { DEFAULT_FPS, useProjectStore } from "./project-store"; - -interface PlaybackStore extends PlaybackState, PlaybackControls { - setDuration: (duration: number) => void; - setCurrentTime: (time: number) => void; -} - -let playbackTimer: number | null = null; - -const startTimer = (store: () => PlaybackStore) => { - if (playbackTimer) cancelAnimationFrame(playbackTimer); - - // Use requestAnimationFrame for smoother updates - const updateTime = () => { - const state = store(); - if (state.isPlaying && state.currentTime < state.duration) { - const now = performance.now(); - const delta = (now - lastUpdate) / 1000; // Convert to seconds - lastUpdate = now; - - const newTime = state.currentTime + delta * state.speed; - - // Get actual content duration from timeline store - const actualContentDuration = useTimelineStore - .getState() - .getTotalDuration(); - - // Stop at actual content end, not timeline duration (which has 10s minimum) - // It was either this or reducing default min timeline to 1 second - const effectiveDuration = - actualContentDuration > 0 ? actualContentDuration : state.duration; - - if (newTime >= effectiveDuration) { - // When content completes, pause just before the end so we can see the last frame - const projectFps = useProjectStore.getState().activeProject?.fps; - if (!projectFps) - console.error("Project FPS is not set, assuming " + DEFAULT_FPS + "fps"); - - const frameOffset = 1 / (projectFps ?? DEFAULT_FPS); // Stop 1 frame before end based on project FPS - const stopTime = Math.max(0, effectiveDuration - frameOffset); - - state.pause(); - state.setCurrentTime(stopTime); - // Notify video elements to sync with end position - window.dispatchEvent( - new CustomEvent("playback-seek", { - detail: { time: stopTime }, - }) - ); - } else { - state.setCurrentTime(newTime); - // Notify video elements to sync - window.dispatchEvent( - new CustomEvent("playback-update", { detail: { time: newTime } }) - ); - } - } - playbackTimer = requestAnimationFrame(updateTime); - }; - - let lastUpdate = performance.now(); - playbackTimer = requestAnimationFrame(updateTime); -}; - -const stopTimer = () => { - if (playbackTimer) { - cancelAnimationFrame(playbackTimer); - playbackTimer = null; - } -}; - -export const usePlaybackStore = create<PlaybackStore>((set, get) => ({ - isPlaying: false, - currentTime: 0, - duration: 0, - volume: 1, - muted: false, - previousVolume: 1, - speed: 1.0, - - play: () => { - const state = get(); - - const actualContentDuration = useTimelineStore - .getState() - .getTotalDuration(); - const effectiveDuration = - actualContentDuration > 0 ? actualContentDuration : state.duration; - - if (effectiveDuration > 0) { - const fps = useProjectStore.getState().activeProject?.fps ?? DEFAULT_FPS; - const frameOffset = 1 / fps; - const endThreshold = Math.max(0, effectiveDuration - frameOffset); - - if (state.currentTime >= endThreshold) { - get().seek(0); - } - } - - set({ isPlaying: true }); - startTimer(get); - }, - - pause: () => { - set({ isPlaying: false }); - stopTimer(); - }, - - toggle: () => { - const { isPlaying } = get(); - if (isPlaying) { - get().pause(); - } else { - get().play(); - } - }, - - seek: (time: number) => { - const { duration } = get(); - const clampedTime = Math.max(0, Math.min(duration, time)); - set({ currentTime: clampedTime }); - - const event = new CustomEvent("playback-seek", { - detail: { time: clampedTime }, - }); - window.dispatchEvent(event); - }, - - setVolume: (volume: number) => - set((state) => ({ - volume: Math.max(0, Math.min(1, volume)), - muted: volume === 0, - previousVolume: volume > 0 ? volume : state.previousVolume, - })), - - setSpeed: (speed: number) => { - const newSpeed = Math.max(0.1, Math.min(2.0, speed)); - set({ speed: newSpeed }); - - const event = new CustomEvent("playback-speed", { - detail: { speed: newSpeed }, - }); - window.dispatchEvent(event); - }, - - setDuration: (duration: number) => set({ duration }), - setCurrentTime: (time: number) => set({ currentTime: time }), - - mute: () => { - const { volume, previousVolume } = get(); - set({ - muted: true, - previousVolume: volume > 0 ? volume : previousVolume, - volume: 0, - }); - }, - - unmute: () => { - const { previousVolume } = get(); - set({ muted: false, volume: previousVolume ?? 1 }); - }, - - toggleMute: () => { - const { muted } = get(); - if (muted) { - get().unmute(); - } else { - get().mute(); - } - }, -})); |
