From 8044b6cec20869b54b8cb08333817d2e9af846a9 Mon Sep 17 00:00:00 2001 From: CN-JS-HuiBai Date: Sat, 4 Apr 2026 01:19:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=89=8D=E7=AB=AF=E4=B8=8D?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E4=B8=8B=E8=BD=BD=E8=BF=9B=E5=BA=A6=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server.js | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index 84f52de..edc7eb0 100644 --- a/server.js +++ b/server.js @@ -480,21 +480,83 @@ app.get('/api/hls/playlist.m3u8', async (req, res) => { const auth = extractS3Credentials(req); const s3Client = createS3Client(auth); let totalBytes = 0; + const progressKey = getProgressKey(key); + const streamSessionId = createStreamSessionId(); + let downloadedBytes = 0; if (!fs.existsSync(tmpInputPath)) { try { const command = new GetObjectCommand({ Bucket: bucket, Key: key }); const response = await s3Client.send(command); totalBytes = response.ContentLength; + const s3Stream = response.Body; + + progressMap[progressKey] = { + status: 'downloading', + percent: 0, + downloadedBytes: 0, + totalBytes, + streamSessionId, + details: 'Downloading full source before streaming...', + mp4Url: null + }; + broadcastWs(progressKey, { type: 'progress', key, progress: progressMap[progressKey] }); + await new Promise((resolve, reject) => { const writeStream = fs.createWriteStream(tmpInputPath); - response.Body.pipe(writeStream); + + s3Stream.on('data', (chunk) => { + downloadedBytes += chunk.length; + const percent = totalBytes ? Math.min(100, Math.round((downloadedBytes / totalBytes) * 100)) : 0; + + const downloadState = { + status: 'downloading', + percent, + downloadedBytes, + totalBytes, + streamSessionId, + details: totalBytes ? `Downloading source ${percent}%` : 'Downloading source...', + mp4Url: null + }; + progressMap[progressKey] = downloadState; + broadcastWs(progressKey, { type: 'progress', key, progress: downloadState }); + }); + + s3Stream.on('error', reject); writeStream.on('error', reject); writeStream.on('finish', resolve); + s3Stream.pipe(writeStream); }); + + progressMap[progressKey] = { + status: 'downloaded', + percent: 100, + downloadedBytes, + totalBytes, + streamSessionId, + details: 'Source download complete, parsing for HLS...', + mp4Url: null + }; + broadcastWs(progressKey, { type: 'progress', key, progress: progressMap[progressKey] }); + } catch(err) { + console.error('S3 Download Failed:', err); return res.status(500).send('S3 Download Failed'); } + } else { + const stats = fs.statSync(tmpInputPath); + totalBytes = stats.size; + downloadedBytes = totalBytes; + progressMap[progressKey] = { + status: 'downloaded', + percent: 100, + downloadedBytes, + totalBytes, + streamSessionId, + details: 'Source already downloaded locally, parsing for HLS...', + mp4Url: null + }; + broadcastWs(progressKey, { type: 'progress', key, progress: progressMap[progressKey] }); } let duration = 0;