diff --git a/public/assets/ai-assistant-figma/video/20250904-1414-49.4157894.webm b/public/assets/ai-assistant-figma/video/20250904-1414-49.4157894.webm index b73db62..da577b0 100644 Binary files a/public/assets/ai-assistant-figma/video/20250904-1414-49.4157894.webm and b/public/assets/ai-assistant-figma/video/20250904-1414-49.4157894.webm differ diff --git a/scripts/convert-videos.mjs b/scripts/convert-videos.mjs index 335aa16..781c2cf 100644 --- a/scripts/convert-videos.mjs +++ b/scripts/convert-videos.mjs @@ -190,6 +190,9 @@ async function toWebm(inputPath, outPath, statusCtx) { } else { a.push("-an"); } + // Резервируем место под Cues в начале файла, чтобы браузер мог перематывать + // (иначе Cues пишутся в конец и duration=N/A, seek не работает). + a.push("-reserve_index_space", "50000"); a.push(outPath); const d = getDurationSec(inputPath); await runFfmpegProgress(a, { diff --git a/scripts/serve-dev.mjs b/scripts/serve-dev.mjs index ea45c70..db00934 100644 --- a/scripts/serve-dev.mjs +++ b/scripts/serve-dev.mjs @@ -237,11 +237,37 @@ function serveStatic(req, res) { } const ext = path.extname(filePath).toLowerCase(); const mime = MIME[ext] || "application/octet-stream"; - fs.readFile(filePath, (e2, data) => { - if (e2) { res.writeHead(500); res.end("Error"); return; } - res.writeHead(200, { "Content-Type": mime }); - res.end(data); + const total = stat.size; + const range = req.headers.range; + + // Поддержка Range-запросов — нужна браузеру для перемотки видео/аудио + if (range) { + const m = /^bytes=(\d*)-(\d*)$/.exec(range); + if (m) { + let start = m[1] ? parseInt(m[1], 10) : 0; + let end = m[2] ? parseInt(m[2], 10) : total - 1; + if (isNaN(start) || isNaN(end) || start > end || end >= total) { + res.writeHead(416, { "Content-Range": `bytes */${total}` }); + res.end(); + return; + } + res.writeHead(206, { + "Content-Type": mime, + "Content-Range": `bytes ${start}-${end}/${total}`, + "Accept-Ranges": "bytes", + "Content-Length": end - start + 1, + }); + fs.createReadStream(filePath, { start, end }).pipe(res); + return; + } + } + + res.writeHead(200, { + "Content-Type": mime, + "Accept-Ranges": "bytes", + "Content-Length": total, }); + fs.createReadStream(filePath).pipe(res); }); }