fix: ABS proxy via backend to bypass CORS + settings button layout
- Add /api/abs-proxy/* endpoint in the backend that forwards all ABS API calls server-side (X-ABS-URL + X-ABS-Token headers). Browser never touches ABS directly for API calls — no CORS issue. - abs.js routes through proxy when backendUrl is set; falls back to direct if no backend (requires user to configure CORS on ABS server) - Audio streaming still uses direct <audio src> (HTML media bypasses CORS) - Settings: status text above buttons, buttons full-width flex row Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
7c6343e28e
commit
d70f649b90
3 files changed
+56
-9
No files matched your search
@@ -381,6 +381,37 @@ app.get('/api/jobs', (req, res) => {
|
||||
res.json(Array.from(jobs.values()).sort((a, b) => b.createdAt - a.createdAt).slice(0, 50));
|
||||
});
|
||||
|
||||
// ─── ABS PROXY ───────────────────────────────────────────────────────────────
|
||||
// Forwards API calls to Audiobookshelf to avoid CORS restrictions in the browser.
|
||||
// The browser sends X-ABS-URL and X-ABS-Token headers; audio streaming uses
|
||||
// direct <audio src> URLs and is unaffected by CORS.
|
||||
app.all('/api/abs-proxy/*', async (req, res) => {
|
||||
const absBase = req.headers['x-abs-url'];
|
||||
const absToken = req.headers['x-abs-token'];
|
||||
if (!absBase || !absToken) { res.status(400).json({ error: 'Missing X-ABS-URL or X-ABS-Token' }); return; }
|
||||
|
||||
// Strip the proxy prefix to get the ABS path (e.g. /api/me, /api/libraries/…)
|
||||
const absPath = req.path.replace(/^\/api\/abs-proxy/, '');
|
||||
const qs = Object.keys(req.query).length ? '?' + new URLSearchParams(req.query).toString() : '';
|
||||
const url = `${absBase}${absPath}${qs}`;
|
||||
|
||||
const fwdHeaders = { 'Authorization': `Bearer ${absToken}`, 'Content-Type': 'application/json' };
|
||||
const opts = { method: req.method, headers: fwdHeaders };
|
||||
if (req.method !== 'GET' && req.method !== 'HEAD' && req.body && Object.keys(req.body).length) {
|
||||
opts.body = JSON.stringify(req.body);
|
||||
}
|
||||
|
||||
try {
|
||||
const upstream = await fetch(url, opts);
|
||||
const text = await upstream.text();
|
||||
res.status(upstream.status)
|
||||
.setHeader('Content-Type', upstream.headers.get('Content-Type') || 'application/json')
|
||||
.send(text);
|
||||
} catch (e) {
|
||||
res.status(502).json({ error: `ABS proxy error: ${e.message}` });
|
||||
}
|
||||
});
|
||||
|
||||
// ─── START ────────────────────────────────────────────────────────────────────
|
||||
app.listen(CONFIG.port, () => {
|
||||
console.log(`\n🎵 NovaSonic Backend running on port ${CONFIG.port}`);
|
||||
|
||||
Reference in new issue
Block a user