Remove per-source speed, fix device dirty check, and add frontend caching
Speed is now exclusively controlled via sync clocks — CSS sources no longer carry their own speed/cycle_speed fields. Streams default to 1.0× when no clock is assigned. Also fixes false-positive dirty check on the device settings modal (array reference comparison) and converts several frontend modules to use DataCache for consistent API response caching. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -247,10 +247,8 @@ function restoreCaptureDuration() {
|
||||
|
||||
export async function showTestTemplateModal(templateId) {
|
||||
try {
|
||||
const resp = await fetchWithAuth('/capture-templates');
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
||||
const data = await resp.json();
|
||||
const template = (data.templates || []).find(tp => tp.id === templateId);
|
||||
const templates = await captureTemplatesCache.fetch();
|
||||
const template = templates.find(tp => tp.id === templateId);
|
||||
|
||||
if (!template) {
|
||||
showToast(t('templates.error.load'), 'error');
|
||||
@@ -1597,34 +1595,25 @@ export async function editStream(streamId) {
|
||||
let _streamModalDisplaysEngine = null;
|
||||
|
||||
async function populateStreamModalDropdowns() {
|
||||
const [displaysRes, captureTemplatesRes, streamsRes, ppTemplatesRes] = await Promise.all([
|
||||
fetch(`${API_BASE}/config/displays`, { headers: getHeaders() }),
|
||||
fetchWithAuth('/capture-templates'),
|
||||
fetchWithAuth('/picture-sources'),
|
||||
fetchWithAuth('/postprocessing-templates'),
|
||||
const [captureTemplates, streams, ppTemplates] = await Promise.all([
|
||||
captureTemplatesCache.fetch().catch(() => []),
|
||||
streamsCache.fetch().catch(() => []),
|
||||
ppTemplatesCache.fetch().catch(() => []),
|
||||
displaysCache.fetch().catch(() => []),
|
||||
]);
|
||||
|
||||
// Cache desktop displays (used as default unless engine has own displays)
|
||||
if (displaysRes.ok) {
|
||||
const displaysData = await displaysRes.json();
|
||||
displaysCache.update(displaysData.displays || []);
|
||||
}
|
||||
_streamModalDisplaysEngine = null;
|
||||
|
||||
const templateSelect = document.getElementById('stream-capture-template');
|
||||
templateSelect.innerHTML = '';
|
||||
if (captureTemplatesRes.ok) {
|
||||
const data = await captureTemplatesRes.json();
|
||||
(data.templates || []).forEach(tmpl => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = tmpl.id;
|
||||
opt.dataset.name = tmpl.name;
|
||||
opt.dataset.engineType = tmpl.engine_type;
|
||||
opt.dataset.hasOwnDisplays = availableEngines.find(e => e.type === tmpl.engine_type)?.has_own_displays ? '1' : '';
|
||||
opt.textContent = `${tmpl.name} (${tmpl.engine_type})`;
|
||||
templateSelect.appendChild(opt);
|
||||
});
|
||||
}
|
||||
captureTemplates.forEach(tmpl => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = tmpl.id;
|
||||
opt.dataset.name = tmpl.name;
|
||||
opt.dataset.engineType = tmpl.engine_type;
|
||||
opt.dataset.hasOwnDisplays = availableEngines.find(e => e.type === tmpl.engine_type)?.has_own_displays ? '1' : '';
|
||||
opt.textContent = `${tmpl.name} (${tmpl.engine_type})`;
|
||||
templateSelect.appendChild(opt);
|
||||
});
|
||||
|
||||
// When template changes, refresh displays if engine type switched
|
||||
templateSelect.addEventListener('change', _onCaptureTemplateChanged);
|
||||
@@ -1640,32 +1629,25 @@ async function populateStreamModalDropdowns() {
|
||||
|
||||
const sourceSelect = document.getElementById('stream-source');
|
||||
sourceSelect.innerHTML = '';
|
||||
if (streamsRes.ok) {
|
||||
const data = await streamsRes.json();
|
||||
const editingId = document.getElementById('stream-id').value;
|
||||
(data.streams || []).forEach(s => {
|
||||
if (s.id === editingId) return;
|
||||
const opt = document.createElement('option');
|
||||
opt.value = s.id;
|
||||
opt.dataset.name = s.name;
|
||||
opt.textContent = s.name;
|
||||
sourceSelect.appendChild(opt);
|
||||
});
|
||||
}
|
||||
const editingId = document.getElementById('stream-id').value;
|
||||
streams.forEach(s => {
|
||||
if (s.id === editingId) return;
|
||||
const opt = document.createElement('option');
|
||||
opt.value = s.id;
|
||||
opt.dataset.name = s.name;
|
||||
opt.textContent = s.name;
|
||||
sourceSelect.appendChild(opt);
|
||||
});
|
||||
|
||||
set_streamModalPPTemplates([]);
|
||||
set_streamModalPPTemplates(ppTemplates);
|
||||
const ppSelect = document.getElementById('stream-pp-template');
|
||||
ppSelect.innerHTML = '';
|
||||
if (ppTemplatesRes.ok) {
|
||||
const data = await ppTemplatesRes.json();
|
||||
set_streamModalPPTemplates(data.templates || []);
|
||||
_streamModalPPTemplates.forEach(tmpl => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = tmpl.id;
|
||||
opt.textContent = tmpl.name;
|
||||
ppSelect.appendChild(opt);
|
||||
});
|
||||
}
|
||||
ppTemplates.forEach(tmpl => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = tmpl.id;
|
||||
opt.textContent = tmpl.name;
|
||||
ppSelect.appendChild(opt);
|
||||
});
|
||||
|
||||
_autoGenerateStreamName();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user