summaryrefslogtreecommitdiff
path: root/apps/web/src/stores/playback-store.ts
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2025-06-25 16:18:00 +0200
committerMaze Winther <mazewinther@gmail.com>2025-06-25 16:18:00 +0200
commit0ae852c185d5d3ff0bd94310bd8000de8bed5ccc (patch)
tree008549c7b27e3bfe7a6bcf265609b36a1e8ca855 /apps/web/src/stores/playback-store.ts
parentdb603543494cc55372191d723f1817e9c4f4b383 (diff)
parent067b6e3d7373d37dbc4542acf9f2ecce1dc1b9f6 (diff)
downloadopencut-0ae852c185d5d3ff0bd94310bd8000de8bed5ccc.tar.gz
Merge branch 'main' of https://github.com/mazeincoding/AppCut
Diffstat (limited to 'apps/web/src/stores/playback-store.ts')
-rw-r--r--apps/web/src/stores/playback-store.ts67
1 files changed, 54 insertions, 13 deletions
diff --git a/apps/web/src/stores/playback-store.ts b/apps/web/src/stores/playback-store.ts
index a4794b7f..0cc01cc1 100644
--- a/apps/web/src/stores/playback-store.ts
+++ b/apps/web/src/stores/playback-store.ts
@@ -10,7 +10,7 @@ let playbackTimer: number | null = null;
const startTimer = (store: any) => {
if (playbackTimer) cancelAnimationFrame(playbackTimer);
-
+
// Use requestAnimationFrame for smoother updates
const updateTime = () => {
const state = store();
@@ -18,14 +18,22 @@ const startTimer = (store: any) => {
const now = performance.now();
const delta = (now - lastUpdate) / 1000; // Convert to seconds
lastUpdate = now;
-
- const newTime = state.currentTime + (delta * state.speed);
+
+ const newTime = state.currentTime + delta * state.speed;
if (newTime >= state.duration) {
+ // When video completes, pause and reset playhead to start
state.pause();
+ state.setCurrentTime(0);
+ // Notify video elements to sync with reset
+ window.dispatchEvent(
+ new CustomEvent("playback-seek", { detail: { time: 0 } })
+ );
} else {
state.setCurrentTime(newTime);
// Notify video elements to sync
- window.dispatchEvent(new CustomEvent('playback-update', { detail: { time: newTime } }));
+ window.dispatchEvent(
+ new CustomEvent("playback-update", { detail: { time: newTime } })
+ );
}
}
playbackTimer = requestAnimationFrame(updateTime);
@@ -47,6 +55,8 @@ export const usePlaybackStore = create<PlaybackStore>((set, get) => ({
currentTime: 0,
duration: 0,
volume: 1,
+ muted: false,
+ previousVolume: 1,
speed: 1.0,
play: () => {
@@ -72,22 +82,53 @@ export const usePlaybackStore = create<PlaybackStore>((set, get) => ({
const { duration } = get();
const clampedTime = Math.max(0, Math.min(duration, time));
set({ currentTime: clampedTime });
-
- // Notify video elements to seek
- const event = new CustomEvent('playback-seek', { detail: { time: clampedTime } });
+
+ const event = new CustomEvent("playback-seek", {
+ detail: { time: clampedTime },
+ });
window.dispatchEvent(event);
},
-
- setVolume: (volume: number) => set({ volume: Math.max(0, Math.min(1, volume)) }),
-
+
+ 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 } });
+
+ const event = new CustomEvent("playback-speed", {
+ detail: { speed: newSpeed },
+ });
window.dispatchEvent(event);
},
setDuration: (duration: number) => set({ duration }),
setCurrentTime: (time: number) => set({ currentTime: time }),
-})); \ No newline at end of file
+
+ 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();
+ }
+ },
+}));