Add master display UI with audio output management and styling
- Implement main.js for the master display functionality, including WebSocket connection, audio output management, and state handling. - Create style.css for the master display's visual design, ensuring a cohesive look and feel with a dark theme and responsive layout. - Integrate device management with a fallback for non-Electron environments, allowing users to select audio outputs. - Add features for managing favorites, including toggling favorites and filtering by genre. - Enhance user experience with a responsive favorites grid and drag-to-scroll functionality.
This commit is contained in:
@@ -10,12 +10,14 @@ import { authMiddleware, ensureBootstrapAdmin } from './auth.js';
|
||||
import { applySeedIfEmpty } from './sources/seed.js';
|
||||
import { scheduleHealthCheck } from './streams/checker.js';
|
||||
import { attachWs } from './ws.js';
|
||||
import { ensureImageDirs, getImageRoot } from './media/images.js';
|
||||
|
||||
import { router as authRoutes } from './routes/auth.js';
|
||||
import { router as stationRoutes } from './routes/stations.js';
|
||||
import { router as meRoutes } from './routes/me.js';
|
||||
import { router as adminRoutes } from './routes/admin.js';
|
||||
import { router as v1Routes } from './routes/v1.js';
|
||||
import { router as roomRoutes } from './routes/rooms.js';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const PORT = Number(process.env.PORT) || 4173;
|
||||
@@ -27,6 +29,7 @@ ensureBootstrapAdmin({
|
||||
});
|
||||
const seedResult = applySeedIfEmpty();
|
||||
console.log('[seed]', seedResult);
|
||||
ensureImageDirs();
|
||||
|
||||
const app = express();
|
||||
app.use(express.json({ limit: '512kb' }));
|
||||
@@ -36,15 +39,40 @@ app.use('/api/auth', authRoutes);
|
||||
app.use('/api/stations', stationRoutes);
|
||||
app.use('/api/me', meRoutes);
|
||||
app.use('/api/admin', adminRoutes);
|
||||
app.use('/api/rooms', roomRoutes);
|
||||
app.use('/api/v1', v1Routes);
|
||||
|
||||
// Locally-cached cover art and other media live under data/images and are
|
||||
// served unauthenticated on the LAN. Long cache OK — file names include the
|
||||
// station id and we rewrite the file on update (browsers also revalidate).
|
||||
app.use('/media', express.static(getImageRoot(), {
|
||||
maxAge: '1h',
|
||||
fallthrough: false,
|
||||
setHeaders(res) { res.setHeader('Cache-Control', 'public, max-age=3600'); }
|
||||
}));
|
||||
|
||||
// Static assets (built by Vite). In dev these don't exist; Vite serves them on :5173.
|
||||
// HTML entry files must NOT be cached — they reference hashed JS/CSS that changes
|
||||
// every build. Hashed assets under /assets/ can be cached aggressively.
|
||||
const publicDir = resolve(__dirname, 'public');
|
||||
const sendHtml = (file) => (_req, res) => {
|
||||
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
||||
res.sendFile(resolve(publicDir, file));
|
||||
};
|
||||
if (existsSync(publicDir)) {
|
||||
app.use(express.static(publicDir));
|
||||
app.get('/admin', (_req, res) => res.sendFile(resolve(publicDir, 'admin/index.html')));
|
||||
app.get('/docs', (_req, res) => res.sendFile(resolve(publicDir, 'docs/index.html')));
|
||||
app.get('*', (_req, res) => res.sendFile(resolve(publicDir, 'index.html')));
|
||||
app.use(express.static(publicDir, {
|
||||
setHeaders(res, filePath) {
|
||||
if (filePath.endsWith('.html')) {
|
||||
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
||||
} else if (filePath.includes(`${publicDir}\\assets\\`) || filePath.includes(`${publicDir}/assets/`)) {
|
||||
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
|
||||
}
|
||||
}
|
||||
}));
|
||||
app.get('/admin', sendHtml('admin/index.html'));
|
||||
app.get('/docs', sendHtml('docs/index.html'));
|
||||
app.get('/master', sendHtml('master/index.html'));
|
||||
app.get('*', sendHtml('index.html'));
|
||||
}
|
||||
|
||||
app.use((err, _req, res, _next) => {
|
||||
|
||||
Reference in New Issue
Block a user