summaryrefslogtreecommitdiff
path: root/apps/web/src/core/managers/playback-manager.ts
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-04-26 17:31:28 +0200
committerMaze Winther <mazewinther@gmail.com>2026-04-26 17:31:28 +0200
commit56ca09692a308b22455420d11376ff8d41244c47 (patch)
tree4eca5ae032451c5db954801008aa9f164b2e2b1d /apps/web/src/core/managers/playback-manager.ts
parente6c6193638e4247ff1e6f2df40de2a057112c773 (diff)
downloadopencut-56ca09692a308b22455420d11376ff8d41244c47.tar.gz
refactor: thinner hooks
Diffstat (limited to 'apps/web/src/core/managers/playback-manager.ts')
-rw-r--r--apps/web/src/core/managers/playback-manager.ts33
1 files changed, 29 insertions, 4 deletions
diff --git a/apps/web/src/core/managers/playback-manager.ts b/apps/web/src/core/managers/playback-manager.ts
index 6748fd42..8275344f 100644
--- a/apps/web/src/core/managers/playback-manager.ts
+++ b/apps/web/src/core/managers/playback-manager.ts
@@ -4,9 +4,9 @@ import {
clampMediaTime,
type MediaTime,
mediaTimeFromSeconds,
+ roundFrameTime,
ZERO_MEDIA_TIME,
} from "@/wasm";
-import { roundToFrame } from "opencut-wasm";
export class PlaybackManager {
private isPlaying = false;
@@ -16,6 +16,8 @@ export class PlaybackManager {
private previousVolume = 1;
private isScrubbing = false;
private listeners = new Set<() => void>();
+ private updateListeners = new Set<(time: MediaTime) => void>();
+ private seekListeners = new Set<(time: MediaTime) => void>();
private playbackTimer: number | null = null;
private playbackStartWallTime = 0;
private playbackStartTime: MediaTime = ZERO_MEDIA_TIME;
@@ -139,6 +141,16 @@ export class PlaybackManager {
return () => this.listeners.delete(listener);
}
+ onUpdate(listener: (time: MediaTime) => void): () => void {
+ this.updateListeners.add(listener);
+ return () => this.updateListeners.delete(listener);
+ }
+
+ onSeek(listener: (time: MediaTime) => void): () => void {
+ this.seekListeners.add(listener);
+ return () => this.seekListeners.delete(listener);
+ }
+
private reconcileTimelineScope(): void {
const maxTime = this.editor.timeline.getTotalDuration();
const nextTime = this.clampTimeToTimeline(this.currentTime);
@@ -158,6 +170,7 @@ export class PlaybackManager {
this.notify();
if (timeChanged) {
+ this.notifySeek(this.currentTime);
this.dispatchSeekEvent(this.currentTime);
}
}
@@ -168,6 +181,18 @@ export class PlaybackManager {
});
}
+ private notifyUpdate(time: MediaTime): void {
+ this.updateListeners.forEach((fn) => {
+ fn(time);
+ });
+ }
+
+ private notifySeek(time: MediaTime): void {
+ this.seekListeners.forEach((fn) => {
+ fn(time);
+ });
+ }
+
private startTimer(): void {
if (this.playbackTimer) {
cancelAnimationFrame(this.playbackTimer);
@@ -195,20 +220,20 @@ export class PlaybackManager {
a: this.playbackStartTime,
b: mediaTimeFromSeconds({ seconds: elapsedSeconds }),
});
- const newTime = (fps
- ? (roundToFrame({ time: rawTime, rate: fps }) ?? rawTime)
- : rawTime) as MediaTime;
+ const newTime = fps ? roundFrameTime({ time: rawTime, fps }) : rawTime;
const maxTime = this.editor.timeline.getTotalDuration();
if (newTime >= maxTime) {
this.pause();
this.currentTime = maxTime;
this.notify();
+ this.notifySeek(maxTime);
this.dispatchSeekEvent(maxTime);
return;
}
this.currentTime = newTime;
+ this.notifyUpdate(newTime);
this.dispatchUpdateEvent(newTime);
this.playbackTimer = requestAnimationFrame(this.updateTime);
};