Files
SnapOtter/apps/web/src/components/tools/media-player-view.tsx
T
SnapOtterandGitHub d8cf979d4b fix: resolve 18 QA-discovered bugs across tools, previews, and the AI pipeline (#242)
Exhaustive QA sweep of all 157 tools. Fixes: CSP blob media, csv-excel ExcelJS interop, ocr-pdf segfault, chart-maker upload, non-PDF doc preview, RAW decode, merge-tool multi-file path, html-to-image chromium, ogv/wma/amr/ac3 preview fallbacks, meme/gif/stabilize codecs, nav+home a11y. Plus orphan-format and test-debt cleanup, the AI bundle build script, and a reusable Playwright QA harness under tests/qa/.
2026-06-15 22:26:24 +08:00

64 lines
2.1 KiB
TypeScript

import { useRef, useState } from "react";
import { NonNativePreview } from "@/components/common/non-native-preview";
import { useTranslation } from "@/contexts/i18n-context";
import { useFileStore } from "@/stores/file-store";
/**
* Native <video>/<audio> playback over the Range-capable download endpoint
* (spec 4.6). Shows the processed result when present, else the source file.
* Falls back to NonNativePreview (server transcode) when the browser cannot
* decode the codec (e.g. Theora in .ogv -- videoWidth is 0).
*/
export function MediaPlayerView() {
const { t } = useTranslation();
const entry = useFileStore((s) => s.entries[s.selectedIndex]);
const videoRef = useRef<HTMLVideoElement>(null);
const [unsupportedCodec, setUnsupportedCodec] = useState(false);
if (!entry) return null;
const src = entry.processedUrl ?? entry.blobUrl;
const isAudio = entry.modality === "audio";
// F7: if the browser loaded the container but cannot decode the codec,
// videoWidth will be 0. Fall back to the server-transcode preview.
if (!isAudio && unsupportedCodec) {
return (
<div className="flex h-full w-full items-center justify-center p-4">
<NonNativePreview
file={entry.file}
src={src}
filename={entry.file?.name ?? "video"}
fileSize={entry.file?.size ?? 0}
modality="video"
/>
</div>
);
}
return (
<div className="flex h-full w-full items-center justify-center p-4">
{isAudio ? (
<audio controls src={src} className="w-full max-w-xl" data-testid="media-player-audio">
<track kind="captions" />
</audio>
) : (
<video
ref={videoRef}
controls
src={src}
className="max-h-full max-w-full rounded-lg"
data-testid="media-player-video"
onLoadedMetadata={() => {
if (videoRef.current && videoRef.current.videoWidth === 0) {
setUnsupportedCodec(true);
}
}}
>
<track kind="captions" />
{t.tools.mediaPlayer.unsupported}
</video>
)}
</div>
);
}