doocus improvemnts

This commit is contained in:
Mariano Gabriel
2026-07-05 20:35:44 -03:00
parent 7b276e8f3d
commit 8606520ef2
22 changed files with 1328 additions and 61 deletions

View File

@@ -80,7 +80,7 @@ export function doocusApi(opts: Options): Plugin {
server.middlewares.use('/api', (req, res, next) => {
const url = new URL(req.url ?? '/', 'http://localhost')
const parts = url.pathname.split('/').filter(Boolean)
handle(res, parts, url.searchParams).catch((err) => {
handle(res, parts, url.searchParams, req.headers.range).catch((err) => {
server.config.logger.error(`[doocus-api] ${String(err)}`)
sendJson(res, 500, { error: String(err) })
}).then((handled) => { if (!handled) next() })
@@ -88,7 +88,7 @@ export function doocusApi(opts: Options): Plugin {
},
}
async function handle(res: ServerResponse, parts: string[], q: URLSearchParams): Promise<boolean> {
async function handle(res: ServerResponse, parts: string[], q: URLSearchParams, range?: string): Promise<boolean> {
if (parts[0] === 'tree') {
const index = readIndex()
if (!index) { sendJson(res, 404, { error: `index.json not found in ${outputDir}` }); return true }
@@ -102,7 +102,7 @@ export function doocusApi(opts: Options): Plugin {
}
if (parts[0] === 'original') {
await serveOriginal(res, q.get('path') ?? '')
await serveOriginal(res, q.get('path') ?? '', range)
return true
}
@@ -137,13 +137,34 @@ export function doocusApi(opts: Options): Plugin {
})
}
async function serveOriginal(res: ServerResponse, rel: string): Promise<void> {
async function serveOriginal(res: ServerResponse, rel: string, range?: string): Promise<void> {
const index = readIndex()
if (!index) { sendJson(res, 404, { error: 'no index' }); return }
const abs = originalAbs(index, rel)
if (!abs || !isFile(abs)) { sendJson(res, 404, { error: 'original not reachable' }); return }
res.setHeader('Content-Type', MIME[path.extname(abs).toLowerCase()] ?? 'application/octet-stream')
res.setHeader('Cache-Control', 'no-cache')
const mime = MIME[path.extname(abs).toLowerCase()] ?? 'application/octet-stream'
const size = fs.statSync(abs).size
res.setHeader('Content-Type', mime)
res.setHeader('Accept-Ranges', 'bytes')
// Range support — needed so large meeting videos can seek/stream.
const m = range?.match(/bytes=(\d*)-(\d*)/)
if (m) {
const start = m[1] ? parseInt(m[1], 10) : 0
const end = m[2] ? parseInt(m[2], 10) : size - 1
if (start >= size || end >= size || start > end) {
res.statusCode = 416
res.setHeader('Content-Range', `bytes */${size}`)
res.end()
return
}
res.statusCode = 206
res.setHeader('Content-Range', `bytes ${start}-${end}/${size}`)
res.setHeader('Content-Length', String(end - start + 1))
fs.createReadStream(abs, { start, end }).pipe(res)
return
}
res.setHeader('Content-Length', String(size))
fs.createReadStream(abs).pipe(res)
}
}