Files
GhiVideo_v4/client/src/components/player/HlsConversionStatus.tsx
T
b23042andClaude Fable 5 d38b842e8d GhiVideo 소스 복제 — v4 작업 시작 기준
기존 GhiVideo 저장소 HEAD의 트래킹 소스 362개 파일을 복제.
(node_modules·storage·빌드 산출물·대용량 미디어는 .gitignore 규칙대로 제외)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 14:32:51 +09:00

64 lines
1.8 KiB
TypeScript

import React, { useState } from 'react';
interface Props {
videoId: string;
onConversionDone: () => void;
}
export default function HlsConversionStatus({ videoId, onConversionDone }: Props) {
const [status, setStatus] = useState<'idle' | 'converting' | 'done' | 'error'>('idle');
const [percent, setPercent] = useState(0);
const startConversion = async () => {
setStatus('converting');
await fetch(`/api/hls/${videoId}/convert`, { method: 'POST' });
const es = new EventSource(`/api/hls/${videoId}/progress`);
es.onmessage = (e) => {
try {
const data = JSON.parse(e.data);
setPercent(Math.round(data.percent ?? 0));
setStatus(data.status);
if (data.status === 'done') {
es.close();
onConversionDone();
} else if (data.status === 'error') {
es.close();
}
} catch {
// ignore parse errors
}
};
es.onerror = () => {
es.close();
setStatus('error');
};
};
return (
<div className="flex items-center gap-2 text-sm">
{status === 'idle' && (
<button
onClick={startConversion}
className="bg-green-700 hover:bg-green-600 text-white px-3 py-1.5 rounded"
>
HLS 변환
</button>
)}
{status === 'converting' && (
<div className="flex items-center gap-2">
<div className="w-24 bg-gray-700 rounded-full h-2">
<div
className="bg-green-500 h-2 rounded-full transition-all"
style={{ width: `${percent}%` }}
/>
</div>
<span className="text-gray-400">{percent}%</span>
</div>
)}
{status === 'done' && <span className="text-green-400">HLS 준비됨</span>}
{status === 'error' && <span className="text-red-400">변환 실패</span>}
</div>
);
}