feat: restructure client-side code

This commit is contained in:
2025-09-04 12:33:17 +02:00
parent edaf9ea94e
commit bbce3cbadf
21 changed files with 854 additions and 20 deletions

View File

@@ -0,0 +1,58 @@
import fs from 'fs';
import path from 'path';
import mime from 'mime';
import { DATA_DIR } from '../config.js';
export function registerAudioRoutes(app) {
app.head('/audio/:name', (req, res) => {
const name = req.params.name;
const filePath = path.join(DATA_DIR, name);
if (!filePath.startsWith(DATA_DIR)) return res.status(400).end();
if (!fs.existsSync(filePath)) return res.status(404).end();
const stat = fs.statSync(filePath);
const type = mime.getType(filePath) || 'audio/mpeg';
res.setHeader('Accept-Ranges', 'bytes');
res.setHeader('Content-Type', type);
res.setHeader('Content-Length', stat.size);
res.setHeader('Cache-Control', 'no-store');
return res.status(200).end();
});
app.get('/audio/:name', (req, res) => {
const name = req.params.name;
const filePath = path.join(DATA_DIR, name);
if (!filePath.startsWith(DATA_DIR)) return res.status(400).send('Invalid path');
if (!fs.existsSync(filePath)) return res.status(404).send('Not found');
const stat = fs.statSync(filePath);
const range = req.headers.range;
const type = mime.getType(filePath) || 'audio/mpeg';
res.setHeader('Accept-Ranges', 'bytes');
res.setHeader('Cache-Control', 'no-store');
if (range) {
const match = /bytes=(\d+)-(\d+)?/.exec(range);
let start = match && match[1] ? parseInt(match[1], 10) : 0;
let end = match && match[2] ? parseInt(match[2], 10) : stat.size - 1;
if (Number.isNaN(start)) start = 0;
if (Number.isNaN(end)) end = stat.size - 1;
start = Math.min(Math.max(0, start), Math.max(0, stat.size - 1));
end = Math.min(Math.max(start, end), Math.max(0, stat.size - 1));
if (start > end || start >= stat.size) {
res.setHeader('Content-Range', `bytes */${stat.size}`);
return res.status(416).end();
}
const chunkSize = end - start + 1;
res.writeHead(206, {
'Content-Range': `bytes ${start}-${end}/${stat.size}`,
'Content-Length': chunkSize,
'Content-Type': type,
});
fs.createReadStream(filePath, { start, end }).pipe(res);
} else {
res.writeHead(200, {
'Content-Length': stat.size,
'Content-Type': type,
});
fs.createReadStream(filePath).pipe(res);
}
});
}