Adiciona auto-reload do Chromium via CDP por stream

---

- Adicionado scripts/autoreload.sh: loop com reload via WebSocket CDP raw (net + frames manuais), sem dependências externas; trap de SIGTERM encerra limpo sem aguardar o sleep;
- Adicionado [program:autoreload-{{STREAM_ID}}] em stream.template.conf com autostart=false e autorestart=unexpected;
- Adicionados campos AUTO_RELOAD e AUTO_RELOAD_INTERVAL em reprovision.mjs e supervisor.ts (provisionStream);
- Adicionados campos autoReload e autoReloadInterval em src/types/stream.ts;
- Adicionado autoreload nas listas de startStream e stopStream em supervisor.ts; adicionada função applyAutoReload;
- Adicionado endpoint dedicado POST /api/streams/[id]/autoreload: salva, re-provisiona e aplica sem reiniciar o stream inteiro;
- Adicionado toggle + input de intervalo (minutos) no menu de 3 pontos do card em StreamCard.tsx; toggle pill corrigido com posicionamento left absoluto;
- Atualizado README e CHANGELOG com a nova feature;

---
This commit is contained in:
2026-04-27 22:05:41 -03:00
parent 6315cd1312
commit 14094cf5ed
9 changed files with 180 additions and 5 deletions
+66
View File
@@ -0,0 +1,66 @@
#!/bin/bash
SLEEP_PID=""
_cleanup() { [ -n "$SLEEP_PID" ] && kill "$SLEEP_PID" 2>/dev/null; exit 0; }
trap '_cleanup' TERM INT
[ "${AUTO_RELOAD:-false}" = "false" ] && exit 0
sleep "${STREAM_DELAY:-0}"
INTERVAL="${AUTO_RELOAD_INTERVAL:-3600}"
while true; do
sleep "$INTERVAL" &
SLEEP_PID=$!
wait $SLEEP_PID
SLEEP_PID=""
node -e "
const http = require('http');
const net = require('net');
const crypto = require('crypto');
http.get('http://localhost:${DEBUG_PORT}/json', res => {
let d = '';
res.on('data', c => d += c);
res.on('end', () => {
try {
const tabs = JSON.parse(d);
const page = tabs.find(t => t.type === 'page');
if (!page) return;
const u = new URL(page.webSocketDebuggerUrl);
const key = crypto.randomBytes(16).toString('base64');
const s = net.createConnection({ host: u.hostname, port: +u.port || 80 });
s.on('connect', () => {
s.write(
'GET ' + u.pathname + ' HTTP/1.1\r\n' +
'Host: ' + u.host + '\r\n' +
'Upgrade: websocket\r\n' +
'Connection: Upgrade\r\n' +
'Sec-WebSocket-Key: ' + key + '\r\n' +
'Sec-WebSocket-Version: 13\r\n\r\n'
);
});
let upgraded = false, buf = Buffer.alloc(0);
s.on('data', chunk => {
if (upgraded) return;
buf = Buffer.concat([buf, chunk]);
if (buf.indexOf('\r\n\r\n') === -1) return;
upgraded = true;
const msg = Buffer.from(JSON.stringify({ id: 1, method: 'Page.reload', params: {} }));
const mask = crypto.randomBytes(4);
const frame = Buffer.alloc(6 + msg.length);
frame[0] = 0x81;
frame[1] = 0x80 | msg.length;
mask.copy(frame, 2);
for (let i = 0; i < msg.length; i++) frame[6 + i] = msg[i] ^ mask[i % 4];
s.write(frame);
setTimeout(() => s.destroy(), 500);
});
s.on('error', () => {});
} catch (_) {}
});
}).on('error', () => {});
" 2>/dev/null || true
done
+3 -1
View File
@@ -48,7 +48,9 @@ for (const stream of streams) {
THREADS: stream.threads ?? 0,
USER: stream.user ?? '',
PASS: stream.pass ?? '',
GPU_FLAGS: stream.gpu ? '' : ' --disable-gpu \\\n',
GPU_FLAGS: stream.gpu ? '' : ' --disable-gpu \\\n',
AUTO_RELOAD: stream.autoReload ? 'true' : 'false',
AUTO_RELOAD_INTERVAL: stream.autoReloadInterval ?? 3600,
}
fs.writeFileSync(path.join(dir, 'stream.conf'), render(confTpl, vars), 'utf-8')
+10
View File
@@ -45,6 +45,16 @@ environment=DISPLAY="{{DISPLAY}}",LOGIN_USER="{{USER}}",LOGIN_PASS="{{PASS}}",DE
stdout_logfile=/app/data/logs/{{STREAM_ID}}/autologin.log
stderr_logfile=/app/data/logs/{{STREAM_ID}}/autologin.log
[program:autoreload-{{STREAM_ID}}]
command=/opt/scripts/autoreload.sh
autostart=false
autorestart=unexpected
priority=35
startsecs=0
environment=DEBUG_PORT="{{DEBUG_PORT}}",AUTO_RELOAD="{{AUTO_RELOAD}}",AUTO_RELOAD_INTERVAL="{{AUTO_RELOAD_INTERVAL}}",STREAM_DELAY="{{STREAM_DELAY}}"
stdout_logfile=/app/data/logs/{{STREAM_ID}}/autoreload.log
stderr_logfile=/app/data/logs/{{STREAM_ID}}/autoreload.log
[program:x11vnc-{{STREAM_ID}}]
environment=DISPLAY={{DISPLAY}}
command=bash -c "while [ ! -e /tmp/.X11-unix/X$(echo $DISPLAY | cut -d: -f2 | cut -d. -f1) ]; do sleep 0.2; done; exec x11vnc -nopw -listen 0.0.0.0 -rfbport {{VNC_PORT}} -xkb -forever -shared -threads"