"use client"; import { useState, useRef } from "react"; import { Button } from "@/components/ui/button"; import { Upload, Trash2, CheckCircle2, AlertCircle, ExternalLink } from "lucide-react"; function formatBytes(bytes: number) { if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / 1024 / 1024).toFixed(1)} MB`; } interface TestResult { key: string; streamUrl: string; filename: string; fileSize: number; uploadMs: number; expiresAt: string; } export default function StorageTestPage() { const [file, setFile] = useState(null); const [uploading, setUploading] = useState(false); const [result, setResult] = useState(null); const [error, setError] = useState(null); const [deleting, setDeleting] = useState(false); const inputRef = useRef(null); const handleUpload = async () => { if (!file) return; setUploading(true); setError(null); setResult(null); const formData = new FormData(); formData.append("file", file); try { const res = await fetch("/api/storage-test", { method: "POST", body: formData, }); const data = await res.json(); if (!res.ok) throw new Error(data.error ?? "Upload failed"); setResult(data); } catch (e: unknown) { setError(e instanceof Error ? e.message : "Upload failed"); } finally { setUploading(false); } }; const handleDelete = async () => { if (!result) return; setDeleting(true); try { const res = await fetch(`/api/storage-test?key=${encodeURIComponent(result.key)}`, { method: "DELETE", }); if (!res.ok) { const data = await res.json(); throw new Error(data.error ?? "Delete failed"); } setResult(null); setFile(null); if (inputRef.current) inputRef.current.value = ""; } catch (e: unknown) { setError(e instanceof Error ? e.message : "Delete failed"); } finally { setDeleting(false); } }; return (

Object Storage Playback Test

Upload a video to Hetzner object storage and play it back directly. Use this to compare streaming performance against the local file server.

{/* Upload */}
inputRef.current?.click()} > {file ? (

{file.name}{" "} ({formatBytes(file.size)})

) : (

Click to select a video file

)} { setFile(e.target.files?.[0] ?? null); setResult(null); setError(null); }} />
{/* Error */} {error && (
{error}
)} {/* Result */} {result && (
Uploaded in {result.uploadMs}ms · {formatBytes(result.fileSize)} · URL expires at {new Date(result.expiresAt).toLocaleTimeString()}
{/* Player */}
{/* URL + cleanup */}
{result.streamUrl}
)}
); }