summaryrefslogtreecommitdiff
path: root/apps/web/src/components/ui/audio-player.tsx
diff options
context:
space:
mode:
authorHayden Bleasel <hello@haydenbleasel.com>2025-07-24 14:41:34 -0700
committerGitHub <noreply@github.com>2025-07-25 00:41:34 +0300
commit5931ddb77aac23ffe1b82d9d7c03afde3e671109 (patch)
tree3e2ead9cc6e13c01132a78c21b64f2be7b00e215 /apps/web/src/components/ui/audio-player.tsx
parent7b840e9b4e198212eb34861c21469b2215157914 (diff)
downloadopencut-5931ddb77aac23ffe1b82d9d7c03afde3e671109.tar.gz
feat: add ultracite (#452)
* Init ultracite * Update scripts and biome.jsonc * Update biome.jsonc * Update biome.jsonc * Update biome.jsonc * Run format
Diffstat (limited to 'apps/web/src/components/ui/audio-player.tsx')
-rw-r--r--apps/web/src/components/ui/audio-player.tsx254
1 files changed, 127 insertions, 127 deletions
diff --git a/apps/web/src/components/ui/audio-player.tsx b/apps/web/src/components/ui/audio-player.tsx
index 774dd95c..37bf8ca9 100644
--- a/apps/web/src/components/ui/audio-player.tsx
+++ b/apps/web/src/components/ui/audio-player.tsx
@@ -1,127 +1,127 @@
-"use client";
-
-import { useRef, useEffect } from "react";
-import { usePlaybackStore } from "@/stores/playback-store";
-
-interface AudioPlayerProps {
- src: string;
- className?: string;
- clipStartTime: number;
- trimStart: number;
- trimEnd: number;
- clipDuration: number;
- trackMuted?: boolean;
-}
-
-export function AudioPlayer({
- src,
- className = "",
- clipStartTime,
- trimStart,
- trimEnd,
- clipDuration,
- trackMuted = false,
-}: AudioPlayerProps) {
- const audioRef = useRef<HTMLAudioElement>(null);
- const { isPlaying, currentTime, volume, speed, muted } = usePlaybackStore();
-
- // Calculate if we're within this clip's timeline range
- const clipEndTime = clipStartTime + (clipDuration - trimStart - trimEnd);
- const isInClipRange =
- currentTime >= clipStartTime && currentTime < clipEndTime;
-
- // Sync playback events
- useEffect(() => {
- const audio = audioRef.current;
- if (!audio || !isInClipRange) return;
-
- const handleSeekEvent = (e: CustomEvent) => {
- // Always update audio time, even if outside clip range
- const timelineTime = e.detail.time;
- const audioTime = Math.max(
- trimStart,
- Math.min(
- clipDuration - trimEnd,
- timelineTime - clipStartTime + trimStart
- )
- );
- audio.currentTime = audioTime;
- };
-
- const handleUpdateEvent = (e: CustomEvent) => {
- // Always update audio time, even if outside clip range
- const timelineTime = e.detail.time;
- const targetTime = Math.max(
- trimStart,
- Math.min(
- clipDuration - trimEnd,
- timelineTime - clipStartTime + trimStart
- )
- );
-
- if (Math.abs(audio.currentTime - targetTime) > 0.5) {
- audio.currentTime = targetTime;
- }
- };
-
- const handleSpeed = (e: CustomEvent) => {
- audio.playbackRate = e.detail.speed;
- };
-
- window.addEventListener("playback-seek", handleSeekEvent as EventListener);
- window.addEventListener(
- "playback-update",
- handleUpdateEvent as EventListener
- );
- window.addEventListener("playback-speed", handleSpeed as EventListener);
-
- return () => {
- window.removeEventListener(
- "playback-seek",
- handleSeekEvent as EventListener
- );
- window.removeEventListener(
- "playback-update",
- handleUpdateEvent as EventListener
- );
- window.removeEventListener(
- "playback-speed",
- handleSpeed as EventListener
- );
- };
- }, [clipStartTime, trimStart, trimEnd, clipDuration, isInClipRange]);
-
- // Sync playback state
- useEffect(() => {
- const audio = audioRef.current;
- if (!audio) return;
-
- if (isPlaying && isInClipRange && !trackMuted) {
- audio.play().catch(() => {});
- } else {
- audio.pause();
- }
- }, [isPlaying, isInClipRange, trackMuted]);
-
- // Sync volume and speed
- useEffect(() => {
- const audio = audioRef.current;
- if (!audio) return;
-
- audio.volume = volume;
- audio.muted = muted || trackMuted;
- audio.playbackRate = speed;
- }, [volume, speed, muted, trackMuted]);
-
- return (
- <audio
- ref={audioRef}
- src={src}
- className={className}
- preload="auto"
- controls={false}
- style={{ display: "none" }} // Audio elements don't need visual representation
- onContextMenu={(e) => e.preventDefault()}
- />
- );
-}
+"use client";
+
+import { useRef, useEffect } from "react";
+import { usePlaybackStore } from "@/stores/playback-store";
+
+interface AudioPlayerProps {
+ src: string;
+ className?: string;
+ clipStartTime: number;
+ trimStart: number;
+ trimEnd: number;
+ clipDuration: number;
+ trackMuted?: boolean;
+}
+
+export function AudioPlayer({
+ src,
+ className = "",
+ clipStartTime,
+ trimStart,
+ trimEnd,
+ clipDuration,
+ trackMuted = false,
+}: AudioPlayerProps) {
+ const audioRef = useRef<HTMLAudioElement>(null);
+ const { isPlaying, currentTime, volume, speed, muted } = usePlaybackStore();
+
+ // Calculate if we're within this clip's timeline range
+ const clipEndTime = clipStartTime + (clipDuration - trimStart - trimEnd);
+ const isInClipRange =
+ currentTime >= clipStartTime && currentTime < clipEndTime;
+
+ // Sync playback events
+ useEffect(() => {
+ const audio = audioRef.current;
+ if (!audio || !isInClipRange) return;
+
+ const handleSeekEvent = (e: CustomEvent) => {
+ // Always update audio time, even if outside clip range
+ const timelineTime = e.detail.time;
+ const audioTime = Math.max(
+ trimStart,
+ Math.min(
+ clipDuration - trimEnd,
+ timelineTime - clipStartTime + trimStart
+ )
+ );
+ audio.currentTime = audioTime;
+ };
+
+ const handleUpdateEvent = (e: CustomEvent) => {
+ // Always update audio time, even if outside clip range
+ const timelineTime = e.detail.time;
+ const targetTime = Math.max(
+ trimStart,
+ Math.min(
+ clipDuration - trimEnd,
+ timelineTime - clipStartTime + trimStart
+ )
+ );
+
+ if (Math.abs(audio.currentTime - targetTime) > 0.5) {
+ audio.currentTime = targetTime;
+ }
+ };
+
+ const handleSpeed = (e: CustomEvent) => {
+ audio.playbackRate = e.detail.speed;
+ };
+
+ window.addEventListener("playback-seek", handleSeekEvent as EventListener);
+ window.addEventListener(
+ "playback-update",
+ handleUpdateEvent as EventListener
+ );
+ window.addEventListener("playback-speed", handleSpeed as EventListener);
+
+ return () => {
+ window.removeEventListener(
+ "playback-seek",
+ handleSeekEvent as EventListener
+ );
+ window.removeEventListener(
+ "playback-update",
+ handleUpdateEvent as EventListener
+ );
+ window.removeEventListener(
+ "playback-speed",
+ handleSpeed as EventListener
+ );
+ };
+ }, [clipStartTime, trimStart, trimEnd, clipDuration, isInClipRange]);
+
+ // Sync playback state
+ useEffect(() => {
+ const audio = audioRef.current;
+ if (!audio) return;
+
+ if (isPlaying && isInClipRange && !trackMuted) {
+ audio.play().catch(() => {});
+ } else {
+ audio.pause();
+ }
+ }, [isPlaying, isInClipRange, trackMuted]);
+
+ // Sync volume and speed
+ useEffect(() => {
+ const audio = audioRef.current;
+ if (!audio) return;
+
+ audio.volume = volume;
+ audio.muted = muted || trackMuted;
+ audio.playbackRate = speed;
+ }, [volume, speed, muted, trackMuted]);
+
+ return (
+ <audio
+ ref={audioRef}
+ src={src}
+ className={className}
+ preload="auto"
+ controls={false}
+ style={{ display: "none" }} // Audio elements don't need visual representation
+ onContextMenu={(e) => e.preventDefault()}
+ />
+ );
+}