Reels: timed recording with auto-stop

recStart now carries the format and an optional maxMs; the output stops
itself when the time is up (15/30/60/90s picker in the control UI), so a
reel doesn't depend on a manual stop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
lucianoandClaude Fable 5 committed 2026-07-17 15:51:51 +02:00
1 parent 48ac3dfa85
commit 19aab4e61e
3 files changed
+21 -5

No files matched your search

+8
View File
@@ -320,6 +320,14 @@
<option value="1080x1440">3:4 verticale (1080×1440)</option>
<option value="2560x1080">21:9 cinema (2560×1080)</option>
</select>
<label>Durata (Reel: si ferma da solo)</label>
<select id="rec-dur">
<option value="0">∞ manuale</option>
<option value="15000">⏱ 15 secondi</option>
<option value="30000">⏱ 30 secondi</option>
<option value="60000">⏱ 60 secondi</option>
<option value="90000">⏱ 90 secondi</option>
</select>
<button id="btn-rec" class="wide">🔴 Avvia registrazione</button>
<button id="btn-rec-folder" class="wide">📁 Apri cartella registrazioni</button>
<div class="hint-mini">Registra ciò che vedi sull'output + l'audio (file o input live). Salvataggio in <b>Filmati ▸ DJ Visualizer</b>. La conversione in MP4 avviene allo stop.</div>
+3 -1
View File
@@ -1105,7 +1105,9 @@ function stopRecTimer() { if (recTimer) { clearInterval(recTimer); recTimer = nu
$('#btn-rec').addEventListener('click', () => {
if (!recOn) {
send({ type: 'recStart' });
// Pass format + optional max duration so the output can auto-stop (Reel mode).
const [w, h] = $('#rec-aspect').value.split('x').map(Number);
send({ type: 'recStart', w, h, maxMs: parseInt($('#rec-dur').value, 10) || 0 });
} else {
const [w, h] = $('#rec-aspect').value.split('x').map(Number);
send({ type: 'recStop', w, h });
+10 -4
View File
@@ -58,7 +58,7 @@ function restartSlideshow() {
// ---------------------------------------------------------------- recording
// Records the output canvas (video) + the audio tap into a WebM stream that
// main transcodes to MP4 at the chosen aspect ratio.
let recorder = null, recording = false, pendingRecOpts = null;
let recorder = null, recording = false, pendingRecOpts = null, recAutoStop = null;
let recCanvas = null, recCtx = null, composeRAF = null;
function pickMime() {
@@ -152,7 +152,7 @@ function stopCompose() {
if (composeRAF) { cancelAnimationFrame(composeRAF); composeRAF = null; }
}
async function startRecording() {
async function startRecording(opts) {
if (recording) return;
try {
await djv.recStart();
@@ -178,11 +178,16 @@ async function startRecording() {
const res = await djv.recStop(pendingRecOpts || {});
recording = false;
djv.report({ type: 'recState', recording: false });
if (res && res.ok) djv.report({ type: 'recSaved', path: res.path });
if (res && res.ok) djv.report({ type: 'recSaved', path: res.path, name: res.name, url: res.url });
else djv.report({ type: 'recError', message: (res && res.error) || 'errore sconosciuto' });
};
recorder.start(2000); // emit a chunk every 2s
recording = true;
// Reel mode: auto-stop after maxMs using the format chosen at start.
if (opts && opts.maxMs > 0) {
clearTimeout(recAutoStop);
recAutoStop = setTimeout(() => stopRecording({ w: opts.w, h: opts.h }), opts.maxMs);
}
djv.report({ type: 'recState', recording: true });
} catch (e) {
stopCompose();
@@ -191,6 +196,7 @@ async function startRecording() {
}
function stopRecording(opts) {
clearTimeout(recAutoStop); recAutoStop = null;
if (!recording || !recorder) return;
pendingRecOpts = { w: opts && opts.w, h: opts && opts.h };
recorder.stop();
@@ -312,7 +318,7 @@ djv.onControl(async (m) => {
djv.report({ type: 'autoVj', on: autoVj });
break;
case 'svg': loadCustomTexture(m.dataUrl); break;
case 'recStart': startRecording(); break;
case 'recStart': startRecording(m); break;
case 'recStop': stopRecording(m); break;
case 'gain': audio.gain = m.value; break;
case 'speed': speed = m.value; audio.scrollRate = m.value; break;