express-bitrate-streamer
Version:
Express-based HLS multi-bitrate streaming backend + tiny frontend player.
61 lines (51 loc) • 1.82 kB
HTML
import express from 'express';
import morgan from 'morgan';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { nanoid } from 'nanoid';
import { createServer } from 'node:http';
import createStreamingRouter from '../src/server/router.js';
import createFFmpegIngest from '../src/server/ffmpeg.js';
import createCleaner from '../src/server/cleaner.js';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const app = express();
const httpServer = createServer(app);
app.use(morgan('dev'));
app.use(express.static(path.join(__dirname, 'public')));
// Mount HLS router
app.use('/streams', createStreamingRouter({
outputRoot: path.join(__dirname, '..', 'streams-data'),
playlistType: 'event',
segmentSeconds: 4,
liveWindowSeconds: 60,
}));
// Simple ingest endpoint for demo
app.get('/ingest-demo', async (req, res) => {
try {
const streamId = req.query.stream || nanoid(8);
const input = path.join(__dirname, 'inputs', 'sample.mp4'); // put a file here
const ff = createFFmpegIngest({
outputRoot: path.join(__dirname, '..', 'streams-data'),
});
// For VOD demo; for live, point to RTMP/URL and run in a daemon
await ff.ingest(input, streamId, { live: false });
// Start cleaner (no-op for VOD, useful if you set playlistType=live)
const cleaner = createCleaner({
outputRoot: path.join(__dirname, '..', 'streams-data'),
});
cleaner.start(streamId);
res.json({
ok: true,
streamId,
master: `/streams/${streamId}/master.m3u8`
});
} catch (e) {
console.error(e);
res.status(500).json({ ok: false, error: e.message });
}
});
const port = process.env.PORT || 4000;
httpServer.listen(port, () => {
console.log(`Demo server running: http://localhost:${port}`);
console.log(`Try: http://localhost:${port}/ingest-demo`);
});