Add Enigma2/OpenWebif M3U support: program mapping and zap-before-streaming
- Parse #EXTVLCOPT:program=N from M3U playlists (both full and streaming parsers, per channel, strict mode) and store it on playlist items - Transcode multi-program MPEG-TS streams by mapping only the selected program's first video and audio stream (DVB teletext/subtitles in the program otherwise make FFmpeg fail to produce HLS) - Optional per-source "zap before streaming" with configurable delay: POST /api/openwebif/zap takes sourceId + streamId, requires an enabled, zap-enabled M3U source containing that channel, derives the receiver from the configured source URL (never from the client), validates the Enigma2 service reference, uses a timeout without redirects and does not echo the receiver response - Live TV: Stop button, and stop playback when leaving the page - Tests for ordinary and program-tagged playlists and the zap endpoint Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@ -63,7 +63,7 @@ router.get('/:id', async (req, res) => {
|
||||
// Create source
|
||||
router.post('/', async (req, res) => {
|
||||
try {
|
||||
const { type, name, url, username, password } = req.body;
|
||||
const { type, name, url, username, password, zapBeforeStreaming, zapDelay } = req.body;
|
||||
|
||||
if (!type || !name || !url) {
|
||||
return res.status(400).json({ error: 'Type, name, and URL are required' });
|
||||
@ -73,7 +73,7 @@ router.post('/', async (req, res) => {
|
||||
return res.status(400).json({ error: 'Invalid source type' });
|
||||
}
|
||||
|
||||
const source = await sources.create({ type, name, url, username, password });
|
||||
const source = await sources.create({ type, name, url, username, password, zapBeforeStreaming: zapBeforeStreaming === true, zapDelay: parseInt(zapDelay) || 1500 });
|
||||
// Trigger Sync
|
||||
syncService.syncSource(source.id).catch(console.error);
|
||||
res.status(201).json(source);
|
||||
@ -91,7 +91,7 @@ router.put('/:id', async (req, res) => {
|
||||
return res.status(404).json({ error: 'Source not found' });
|
||||
}
|
||||
|
||||
const { name, url, username, password } = req.body;
|
||||
const { name, url, username, password, zapBeforeStreaming, zapDelay } = req.body;
|
||||
// Omitted fields must be merged against the latest record inside the
|
||||
// database transaction, not the snapshot read before another edit.
|
||||
const updates = {};
|
||||
@ -99,6 +99,8 @@ router.put('/:id', async (req, res) => {
|
||||
if (url) updates.url = url;
|
||||
if (username !== undefined) updates.username = username;
|
||||
if (password !== undefined) updates.password = password;
|
||||
if (zapBeforeStreaming !== undefined) updates.zapBeforeStreaming = zapBeforeStreaming === true;
|
||||
if (zapDelay !== undefined) updates.zapDelay = parseInt(zapDelay) || 1500;
|
||||
const updated = await sources.update(req.params.id, updates);
|
||||
if (!updated) return res.status(404).json({ error: 'Source not found' });
|
||||
// Trigger Sync (if critical fields changed? safely just trigger it)
|
||||
|
||||
Reference in New Issue
Block a user