Files
tvapp2/server/dist/index.js
2026-06-11 16:40:21 -04:00

79 lines
3.2 KiB
JavaScript

import { existsSync } from 'node:fs';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import express from 'express';
import { loadConfig } from './config.js';
import { connect, disconnect } from './db.js';
import { healthRouter } from './routes/health.js';
import { playlistsRouter } from './routes/playlists.js';
import { epgSourcesRouter } from './routes/epgSources.js';
import { channelsRouter } from './routes/channels.js';
import { activeStreamsRouter } from './routes/activeStreams.js';
import { customPlaylistsRouter } from './routes/customPlaylists.js';
import { programsRouter } from './routes/programs.js';
import { activityRouter } from './routes/activity.js';
import { streamSessionsRouter } from './routes/streamSessions.js';
import { sourcesRouter } from './routes/sources.js';
import { bootInitSources } from './sources/seed.js';
async function main() {
const config = loadConfig();
try {
await connect(config.mongoUri);
}
catch (err) {
console.error('[startup] failed to connect to mongo:', err.message);
process.exit(1);
}
// Ingest the established (Default) source playlists: guarantee each from its committed bundle
// (idempotent), then kick a non-blocking live sync. Runs in both Docker variants via this single
// boot path. A failure here must not prevent the API from serving.
try {
await bootInitSources();
}
catch (err) {
console.error('[startup] source init error (continuing):', err.message);
}
const app = express();
app.use(express.json());
app.use('/api/health', healthRouter);
app.use('/api/playlists', playlistsRouter);
app.use('/api/epg-sources', epgSourcesRouter);
app.use('/api/channels', channelsRouter);
app.use('/api/active-streams', activeStreamsRouter);
app.use('/api/custom-playlists', customPlaylistsRouter);
app.use('/api/epg-programs', programsRouter);
app.use('/api/activity', activityRouter);
app.use('/api/stream-sessions', streamSessionsRouter);
// Generic source API (manifest, stream proxy, status, sync/reset) — mounted at root since its
// paths span /api/sources and /api/v1.
app.use(sourcesRouter);
const here = dirname(fileURLToPath(import.meta.url));
const publicDir = resolve(here, '..', 'public');
if (existsSync(publicDir)) {
app.use(express.static(publicDir));
app.get(/^\/(?!api\/).*/, (_req, res) => {
res.sendFile(resolve(publicDir, 'index.html'));
});
console.info(`[http] serving SPA from ${publicDir}`);
}
app.use((err, _req, res, _next) => {
console.error('[api] error:', err.message);
res.status(500).json({ error: 'internal_error' });
});
const server = app.listen(config.port, () => {
console.info(`[api] listening on :${config.port}`);
});
const shutdown = async (signal) => {
console.info(`[shutdown] received ${signal}`);
server.close();
await disconnect();
process.exit(0);
};
process.on('SIGTERM', () => void shutdown('SIGTERM'));
process.on('SIGINT', () => void shutdown('SIGINT'));
}
main().catch((err) => {
console.error('[startup] fatal:', err);
process.exit(1);
});
//# sourceMappingURL=index.js.map