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:
@ -255,7 +255,22 @@ class SourceManager {
|
||||
`;
|
||||
}
|
||||
|
||||
return nameField + urlField;
|
||||
const enigmaOptions = type === 'm3u' ? `
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="source-zap-before-streaming" ${source.zapBeforeStreaming ? 'checked' : ''}>
|
||||
Zap before streaming (Enigma2/OpenWebif)
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="source-zap-delay">Zap delay (ms)</label>
|
||||
<input type="number" id="source-zap-delay" class="form-input"
|
||||
value="${source.zapDelay || 1500}" min="0" step="100">
|
||||
</div>
|
||||
` : '';
|
||||
|
||||
return nameField + urlField + enigmaOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -266,6 +281,8 @@ class SourceManager {
|
||||
const url = document.getElementById('source-url').value.trim();
|
||||
const username = document.getElementById('source-username')?.value.trim() || null;
|
||||
const password = document.getElementById('source-password')?.value.trim() || null;
|
||||
const zapBeforeStreaming = document.getElementById('source-zap-before-streaming')?.checked || false;
|
||||
const zapDelay = parseInt(document.getElementById('source-zap-delay')?.value) || 1500;
|
||||
|
||||
if (!name || !url) {
|
||||
alert('Name and URL are required');
|
||||
@ -295,7 +312,7 @@ class SourceManager {
|
||||
}
|
||||
}
|
||||
|
||||
await API.sources.create({ type, name, url, username, password });
|
||||
await API.sources.create({ type, name, url, username, password, zapBeforeStreaming, zapDelay });
|
||||
document.getElementById('modal').classList.remove('active');
|
||||
await this.loadSources();
|
||||
|
||||
@ -322,14 +339,16 @@ class SourceManager {
|
||||
alert('Name and URL are required');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = { name, url };
|
||||
if (type === 'xtream') {
|
||||
data.username = username;
|
||||
if (password) data.password = password;
|
||||
}
|
||||
|
||||
if (type === 'm3u') {
|
||||
data.zapBeforeStreaming = document.getElementById('source-zap-before-streaming')?.checked || false;
|
||||
data.zapDelay = parseInt(document.getElementById('source-zap-delay')?.value) || 1500;
|
||||
}
|
||||
await API.sources.update(id, data);
|
||||
document.getElementById('modal').classList.remove('active');
|
||||
await this.loadSources();
|
||||
|
||||
Reference in New Issue
Block a user