修复后端问题

This commit is contained in:
CN-JS-HuiBai
2026-04-03 23:46:16 +08:00
parent 3fa6e4ef4d
commit 85202e5b67

View File

@@ -92,6 +92,17 @@ const progressMap = {};
const transcodeProcesses = new Map(); const transcodeProcesses = new Map();
const wsSubscriptions = new Map(); const wsSubscriptions = new Map();
const progressApiLogMap = new Map(); const progressApiLogMap = new Map();
const progressStateLogMap = new Map();
const setProgressState = (progressKey, key, nextState, reason = '') => {
progressMap[progressKey] = nextState;
const signature = `${nextState?.status || 'null'}:${typeof nextState?.percent === 'number' ? nextState.percent : 'na'}:${nextState?.streamSessionId || 'na'}`;
if (progressStateLogMap.get(progressKey) !== signature) {
progressStateLogMap.set(progressKey, signature);
console.log(`[progress-state] key=${key} status=${nextState?.status || 'null'} percent=${typeof nextState?.percent === 'number' ? nextState.percent : 'na'} reason=${reason || 'unspecified'} session=${nextState?.streamSessionId || 'na'}`);
}
return nextState;
};
const AVAILABLE_VIDEO_ENCODERS = [ const AVAILABLE_VIDEO_ENCODERS = [
{ value: 'h264_rkmpp', label: 'h264_rkmpp (RKMPP H.264)' }, { value: 'h264_rkmpp', label: 'h264_rkmpp (RKMPP H.264)' },
@@ -800,12 +811,12 @@ app.post('/api/stop-transcode', (req, res) => {
return res.status(404).json({ error: 'No active transcode found for this key' }); return res.status(404).json({ error: 'No active transcode found for this key' });
} }
stopActiveTranscode(progressKey); stopActiveTranscode(progressKey);
progressMap[progressKey] = { setProgressState(progressKey, key, {
status: 'cancelled', status: 'cancelled',
percent: 0, percent: 0,
details: 'Transcode stopped by user', details: 'Transcode stopped by user',
mp4Url: null mp4Url: null
}; }, 'stop-transcode');
broadcastWs(progressKey, { type: 'progress', key, progress: progressMap[progressKey] }); broadcastWs(progressKey, { type: 'progress', key, progress: progressMap[progressKey] });
res.json({ message: 'Transcode stopped' }); res.json({ message: 'Transcode stopped' });
} catch (error) { } catch (error) {
@@ -868,7 +879,7 @@ app.get('/api/stream', async (req, res) => {
try { try {
const replacedExistingStream = stopActiveTranscode(progressKey); const replacedExistingStream = stopActiveTranscode(progressKey);
if (replacedExistingStream && startSeconds > 0) { if (replacedExistingStream && startSeconds > 0) {
progressMap[progressKey] = { setProgressState(progressKey, key, {
...(progressMap[progressKey] || {}), ...(progressMap[progressKey] || {}),
status: 'transcoding', status: 'transcoding',
percent: Math.min(Math.max(Math.round((startSeconds / Math.max(progressMap[progressKey]?.duration || startSeconds || 1, 1)) * 100), 0), 100), percent: Math.min(Math.max(Math.round((startSeconds / Math.max(progressMap[progressKey]?.duration || startSeconds || 1, 1)) * 100), 0), 100),
@@ -876,7 +887,7 @@ app.get('/api/stream', async (req, res) => {
streamSessionId, streamSessionId,
details: `Restarting transcode from ${startSeconds.toFixed(2)}s`, details: `Restarting transcode from ${startSeconds.toFixed(2)}s`,
mp4Url: null mp4Url: null
}; }, 'restart-seek');
broadcastWs(progressKey, { type: 'progress', key, progress: progressMap[progressKey] }); broadcastWs(progressKey, { type: 'progress', key, progress: progressMap[progressKey] });
} }
@@ -885,7 +896,7 @@ app.get('/api/stream', async (req, res) => {
const cacheExists = fs.existsSync(downloadPath); const cacheExists = fs.existsSync(downloadPath);
if (!cacheExists) { if (!cacheExists) {
progressMap[progressKey] = { setProgressState(progressKey, key, {
status: 'downloading', status: 'downloading',
percent: 0, percent: 0,
downloadedBytes: 0, downloadedBytes: 0,
@@ -893,7 +904,7 @@ app.get('/api/stream', async (req, res) => {
streamSessionId, streamSessionId,
details: 'Downloading full source before streaming...', details: 'Downloading full source before streaming...',
mp4Url: null mp4Url: null
}; }, 'download-start');
broadcastWs(progressKey, { type: 'progress', key, progress: progressMap[progressKey] }); broadcastWs(progressKey, { type: 'progress', key, progress: progressMap[progressKey] });
await ensureSourceCached({ await ensureSourceCached({
@@ -915,12 +926,12 @@ app.get('/api/stream', async (req, res) => {
details: totalBytes ? `Downloading source ${percent}%` : 'Downloading source...', details: totalBytes ? `Downloading source ${percent}%` : 'Downloading source...',
mp4Url: null mp4Url: null
}; };
progressMap[progressKey] = downloadState; setProgressState(progressKey, key, downloadState, 'download-progress');
broadcastWs(progressKey, { type: 'progress', key, progress: downloadState }); broadcastWs(progressKey, { type: 'progress', key, progress: downloadState });
} }
}); });
progressMap[progressKey] = { setProgressState(progressKey, key, {
status: 'downloaded', status: 'downloaded',
percent: 100, percent: 100,
downloadedBytes, downloadedBytes,
@@ -928,14 +939,14 @@ app.get('/api/stream', async (req, res) => {
streamSessionId, streamSessionId,
details: 'Source download complete, starting real-time transcode...', details: 'Source download complete, starting real-time transcode...',
mp4Url: null mp4Url: null
}; }, 'download-complete');
broadcastWs(progressKey, { type: 'progress', key, progress: progressMap[progressKey] }); broadcastWs(progressKey, { type: 'progress', key, progress: progressMap[progressKey] });
} else { } else {
const stats = fs.statSync(downloadPath); const stats = fs.statSync(downloadPath);
totalBytes = stats.size; totalBytes = stats.size;
downloadedBytes = totalBytes; downloadedBytes = totalBytes;
console.log(`[download] cache ready bucket=${bucket} key=${key} path=${downloadPath} bytes=${totalBytes}`); console.log(`[download] cache ready bucket=${bucket} key=${key} path=${downloadPath} bytes=${totalBytes}`);
progressMap[progressKey] = { setProgressState(progressKey, key, {
status: 'downloaded', status: 'downloaded',
percent: 100, percent: 100,
downloadedBytes, downloadedBytes,
@@ -943,7 +954,7 @@ app.get('/api/stream', async (req, res) => {
streamSessionId, streamSessionId,
details: 'Source already downloaded locally, starting real-time transcode...', details: 'Source already downloaded locally, starting real-time transcode...',
mp4Url: null mp4Url: null
}; }, 'download-cache-hit');
broadcastWs(progressKey, { type: 'progress', key, progress: progressMap[progressKey] }); broadcastWs(progressKey, { type: 'progress', key, progress: progressMap[progressKey] });
} }
@@ -953,11 +964,11 @@ app.get('/api/stream', async (req, res) => {
const metadata = await probeFile(downloadPath); const metadata = await probeFile(downloadPath);
sourceMetadata = metadata; sourceMetadata = metadata;
const duration = metadata.format?.duration || 0; const duration = metadata.format?.duration || 0;
progressMap[progressKey] = { setProgressState(progressKey, key, {
...(progressMap[progressKey] || {}), ...(progressMap[progressKey] || {}),
duration: parseFloat(duration) || 0, duration: parseFloat(duration) || 0,
streamSessionId streamSessionId
}; }, 'duration-probed');
broadcastWs(progressKey, { type: 'duration', key, duration: parseFloat(duration) }); broadcastWs(progressKey, { type: 'duration', key, duration: parseFloat(duration) });
} catch (probeErr) { } catch (probeErr) {
console.error('Probe failed:', probeErr); console.error('Probe failed:', probeErr);
@@ -1049,7 +1060,7 @@ app.get('/api/stream', async (req, res) => {
details: `Streaming transcode ${percent}%`, details: `Streaming transcode ${percent}%`,
mp4Url: null mp4Url: null
}; };
progressMap[progressKey] = progressState; setProgressState(progressKey, key, progressState, 'transcode-progress');
broadcastWs(progressKey, { type: 'progress', key, progress: progressState }); broadcastWs(progressKey, { type: 'progress', key, progress: progressState });
}) })
.on('stderr', (stderrLine) => { .on('stderr', (stderrLine) => {
@@ -1064,7 +1075,7 @@ app.get('/api/stream', async (req, res) => {
} }
console.log(`[transcode] complete bucket=${bucket} key=${key} encoder=${encoderName} cache=${convertPath}`); console.log(`[transcode] complete bucket=${bucket} key=${key} encoder=${encoderName} cache=${convertPath}`);
transcodeProcesses.delete(progressKey); transcodeProcesses.delete(progressKey);
progressMap[progressKey] = { setProgressState(progressKey, key, {
status: 'finished', status: 'finished',
percent: 100, percent: 100,
duration: progressMap[progressKey]?.duration || null, duration: progressMap[progressKey]?.duration || null,
@@ -1072,7 +1083,7 @@ app.get('/api/stream', async (req, res) => {
streamSessionId, streamSessionId,
details: 'Streaming transcode complete', details: 'Streaming transcode complete',
mp4Url: null mp4Url: null
}; }, 'transcode-finished');
broadcastWs(progressKey, { type: 'progress', key, progress: progressMap[progressKey] }); broadcastWs(progressKey, { type: 'progress', key, progress: progressMap[progressKey] });
}) })
.on('error', (err) => { .on('error', (err) => {
@@ -1090,7 +1101,7 @@ app.get('/api/stream', async (req, res) => {
details: err.message || 'Streaming transcode failed', details: err.message || 'Streaming transcode failed',
mp4Url: null mp4Url: null
}; };
progressMap[progressKey] = failedState; setProgressState(progressKey, key, failedState, 'transcode-failed');
broadcastWs(progressKey, { type: 'progress', key, progress: failedState }); broadcastWs(progressKey, { type: 'progress', key, progress: failedState });
if (!res.headersSent) { if (!res.headersSent) {
res.status(500).json({ error: 'Failed to stream transcoded video', detail: err.message }); res.status(500).json({ error: 'Failed to stream transcoded video', detail: err.message });