Files
decap-stream/src/lib/db.ts
T
Kralot ca7299c646 Adiciona autenticação opcional, VNC integrado, GPU por stream, proxy HLS e melhorias de segurança
---

- Adicionado sistema de autenticação opcional via AUTH_USER/AUTH_PASS: middleware Next.js, página de login, cookie rolling de
30 dias, timingSafeEqual para comparação segura de credenciais;
- Adicionado proxy HLS em /api/hls/[...path] que roteia para localhost:8888 internamente; player e player-static atualizados
para usar a rota proxy;
- Adicionada página /vnc/[id] integrada na UI (iframe + botão Back com auto-hide), substituindo abertura em nova aba;
- Adicionado campo gpu: boolean por stream; controlado via {{GPU_FLAGS}} no template do Chromium e no reprovision.mjs;
- Ajustado delay da primeira thumbnail para stream.delay + 60 para garantir conclusão do autologin antes da captura;
- Atualizado docker-compose.yml: porta 6080 vinculada a localhost, portas 1935 e 8888 comentadas por padrão;
- Traduzidos todos os comentários de código do português para o inglês;
- Adicionado crédito riguetto.dev no header com underline no hover;
- README e CLAUDE.md atualizados com arquitetura, portas e features corretas;

---
2026-04-26 03:09:57 -03:00

63 lines
1.8 KiB
TypeScript

import fs from "fs"
import path from "path"
import type { Stream } from "@/types/stream"
const DATA_DIR = process.env.DATA_DIR ?? "/app/data"
const STREAMS_FILE = path.join(DATA_DIR, "streams", "streams.json")
function ensureFile() {
if (!fs.existsSync(DATA_DIR)) fs.mkdirSync(DATA_DIR, { recursive: true })
if (!fs.existsSync(STREAMS_FILE)) fs.writeFileSync(STREAMS_FILE, "[]", "utf-8")
}
export function readStreams(): Stream[] {
ensureFile()
const streams = JSON.parse(fs.readFileSync(STREAMS_FILE, "utf-8")) as Stream[]
// migration: assign order to streams that don't have it yet
let dirty = false
streams.forEach((s, i) => {
if (s.order === undefined) { s.order = i; dirty = true }
})
if (dirty) fs.writeFileSync(STREAMS_FILE, JSON.stringify(streams, null, 2), "utf-8")
return streams.sort((a, b) => a.order - b.order)
}
export function writeStreams(streams: Stream[]): void {
ensureFile()
fs.writeFileSync(STREAMS_FILE, JSON.stringify(streams, null, 2), "utf-8")
}
export function getStream(id: string): Stream | undefined {
return readStreams().find((s) => s.id === id)
}
export function saveStream(stream: Stream): void {
const streams = readStreams()
const idx = streams.findIndex((s) => s.id === stream.id)
if (idx >= 0) streams[idx] = stream
else streams.push(stream)
writeStreams(streams)
}
export function deleteStream(id: string): void {
writeStreams(readStreams().filter((s) => s.id !== id))
}
// Allocates display number and VNC/debug ports without conflicting with existing streams
export function allocatePorts(): {
display: string
vncPort: number
debugPort: number
} {
const streams = readStreams()
const usedDisplays = new Set(streams.map((s) => s.display))
let n = 1
while (usedDisplays.has(`:${n}`)) n++
return {
display: `:${n}`,
vncPort: 5900 + n,
debugPort: 9221 + n,
}
}