使用流式视频传输

This commit is contained in:
CN-JS-HuiBai
2026-04-02 21:38:07 +08:00
parent 6569ef1e19
commit c2a8cf79c8
3 changed files with 14 additions and 365 deletions

View File

@@ -3,7 +3,6 @@ document.addEventListener('DOMContentLoaded', () => {
const loadingSpinner = document.getElementById('loading-spinner');
const refreshBtn = document.getElementById('refresh-btn');
const clearDownloadCacheBtn = document.getElementById('clear-download-cache-btn');
const clearTranscodeCacheBtn = document.getElementById('clear-transcode-cache-btn');
const bucketSelect = document.getElementById('bucket-select');
const loginScreen = document.getElementById('login-screen');
const appContainer = document.getElementById('app-container');
@@ -224,47 +223,6 @@ document.addEventListener('DOMContentLoaded', () => {
}
};
const clearTranscodeCache = async () => {
if (!clearTranscodeCacheBtn) return;
clearTranscodeCacheBtn.disabled = true;
clearTranscodeCacheBtn.textContent = '清空中...';
stopPolling();
selectedKey = null;
currentVideoKey = null;
subscribedKey = null;
if (transcodeBtn) {
transcodeBtn.disabled = true;
transcodeBtn.classList.add('hidden');
}
if (playBtn) {
playBtn.classList.add('hidden');
}
if (playerOverlay) {
playerOverlay.classList.remove('hidden');
}
if (nowPlaying) {
nowPlaying.classList.add('hidden');
}
resetProgress();
try {
const res = await fetch('/api/clear-transcode-cache', { method: 'POST' });
if (!res.ok) {
const data = await res.json().catch(() => ({}));
throw new Error(data.error || '清空转码缓存失败');
}
await fetchVideos(selectedBucket);
alert('转码缓存已清空');
} catch (err) {
console.error('Clear transcode cache failed:', err);
alert(`清空转码缓存失败: ${err.message}`);
} finally {
clearTranscodeCacheBtn.disabled = false;
clearTranscodeCacheBtn.textContent = '清空转码缓存';
}
};
if (transcodeBtn) {
transcodeBtn.addEventListener('click', () => {
startTranscode();
@@ -440,24 +398,24 @@ document.addEventListener('DOMContentLoaded', () => {
}
stopPolling();
transcodingOverlay.classList.remove('hidden');
setProgress({ status: 'Starting download...', percent: 0, details: 'Starting download...' });
setProgress({ status: 'Starting stream...', percent: 0, details: 'Starting stream...' });
try {
const codec = codecSelect?.value || 'h264';
const encoder = encoderSelect?.value || 'software';
if (!selectedBucket) throw new Error('No bucket selected');
const res = await fetch('/api/transcode', {
method: 'POST',
headers: { 'Content-Type': 'application/json', ...s3AuthHeaders },
body: JSON.stringify({ bucket: selectedBucket, key: selectedKey, codec, encoder })
});
const data = await res.json();
if (data.error) throw new Error(data.error);
if (!wsConnected) {
pollForMp4Ready(selectedKey, data.mp4Url);
}
const streamUrl = `/api/stream?bucket=${encodeURIComponent(selectedBucket)}&key=${encodeURIComponent(selectedKey)}&codec=${encodeURIComponent(codec)}&encoder=${encodeURIComponent(encoder)}`;
videoPlayer.src = streamUrl;
videoPlayer.load();
videoPlayer.addEventListener('loadedmetadata', () => {
transcodingOverlay.classList.add('hidden');
videoPlayer.classList.remove('hidden');
if (playBtn) {
playBtn.disabled = false;
playBtn.textContent = 'Play';
playBtn.classList.remove('hidden');
}
}, { once: true });
} catch (err) {
console.error(err);
transcodingOverlay.innerHTML = `<p style="color: #ef4444;">Transcode Failed: ${err.message}</p>`;
@@ -496,36 +454,6 @@ document.addEventListener('DOMContentLoaded', () => {
}
};
// Poll the backend to check if the generated MP4 file is accessible
const pollForMp4Ready = (key, mp4Url) => {
let attempts = 0;
const maxAttempts = 120; // 60 seconds max wait for first segment
const pollIntervalMs = 500;
currentPollInterval = setInterval(async () => {
attempts++;
try {
const res = await fetch(`/api/status?key=${encodeURIComponent(key)}`);
const data = await res.json();
if (data.progress) {
setProgress(data.progress);
}
if (data.ready) {
stopPolling();
setProgress({ status: 'Ready to play', percent: 100, details: 'Ready to play' });
playMp4Stream(data.mp4Url);
} else if (attempts >= maxAttempts) {
stopPolling();
transcodingOverlay.innerHTML = `<p style="color: #ef4444;">Timeout waiting for MP4 file.</p>`;
}
} catch (err) {
console.error("Poll Error:", err);
}
}, pollIntervalMs);
};
const stopPolling = () => {
if (currentPollInterval) {
clearInterval(currentPollInterval);
@@ -559,9 +487,6 @@ document.addEventListener('DOMContentLoaded', () => {
if (clearDownloadCacheBtn) {
clearDownloadCacheBtn.addEventListener('click', clearDownloadCache);
}
if (clearTranscodeCacheBtn) {
clearTranscodeCacheBtn.addEventListener('click', clearTranscodeCache);
}
if (stopTranscodeBtn) {
stopTranscodeBtn.addEventListener('click', stopTranscode);
}