Add target FPS slider to Capture Settings and remove unused HACS workflow
- Add Target FPS slider (range 10-90) to Capture Settings dialog - Fix settings PUT to merge with current values instead of resetting defaults - Update FPS validation range to 10-90 in schema and config - Remove irrelevant .github/workflows/validate.yml (HACS leftover) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
17
.github/workflows/validate.yml
vendored
17
.github/workflows/validate.yml
vendored
@@ -1,17 +0,0 @@
|
|||||||
name: Validate
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
schedule:
|
|
||||||
- cron: "0 0 * * *"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
validate:
|
|
||||||
runs-on: "ubuntu-latest"
|
|
||||||
steps:
|
|
||||||
- uses: "actions/checkout@v3"
|
|
||||||
- name: HACS validation
|
|
||||||
uses: "hacs/action@main"
|
|
||||||
with:
|
|
||||||
category: "integration"
|
|
||||||
@@ -79,7 +79,7 @@ class ProcessingSettings(BaseModel):
|
|||||||
"""Processing settings for a device."""
|
"""Processing settings for a device."""
|
||||||
|
|
||||||
display_index: int = Field(default=0, description="Display to capture", ge=0)
|
display_index: int = Field(default=0, description="Display to capture", ge=0)
|
||||||
fps: int = Field(default=30, description="Target frames per second", ge=1, le=60)
|
fps: int = Field(default=30, description="Target frames per second", ge=10, le=90)
|
||||||
border_width: int = Field(default=10, description="Border width in pixels", ge=1, le=100)
|
border_width: int = Field(default=10, description="Border width in pixels", ge=1, le=100)
|
||||||
brightness: float = Field(default=1.0, description="Global brightness (0.0-1.0)", ge=0.0, le=1.0)
|
brightness: float = Field(default=1.0, description="Global brightness (0.0-1.0)", ge=0.0, le=1.0)
|
||||||
state_check_interval: int = Field(
|
state_check_interval: int = Field(
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ class ProcessingConfig(BaseSettings):
|
|||||||
"""Processing configuration."""
|
"""Processing configuration."""
|
||||||
|
|
||||||
default_fps: int = 30
|
default_fps: int = 30
|
||||||
max_fps: int = 60
|
max_fps: int = 90
|
||||||
min_fps: int = 1
|
min_fps: int = 10
|
||||||
border_width: int = 10
|
border_width: int = 10
|
||||||
interpolation_mode: Literal["average", "median", "dominant"] = "average"
|
interpolation_mode: Literal["average", "median", "dominant"] = "average"
|
||||||
|
|
||||||
|
|||||||
@@ -871,11 +871,12 @@ let captureSettingsInitialValues = {};
|
|||||||
|
|
||||||
async function showCaptureSettings(deviceId) {
|
async function showCaptureSettings(deviceId) {
|
||||||
try {
|
try {
|
||||||
// Fetch device data, displays, and templates in parallel
|
// Fetch device data, displays, templates, and settings in parallel
|
||||||
const [deviceResponse, displaysResponse, templatesResponse] = await Promise.all([
|
const [deviceResponse, displaysResponse, templatesResponse, settingsResponse] = await Promise.all([
|
||||||
fetch(`${API_BASE}/devices/${deviceId}`, { headers: getHeaders() }),
|
fetch(`${API_BASE}/devices/${deviceId}`, { headers: getHeaders() }),
|
||||||
fetch(`${API_BASE}/config/displays`, { headers: getHeaders() }),
|
fetch(`${API_BASE}/config/displays`, { headers: getHeaders() }),
|
||||||
fetchWithAuth('/capture-templates'),
|
fetchWithAuth('/capture-templates'),
|
||||||
|
fetch(`${API_BASE}/devices/${deviceId}/settings`, { headers: getHeaders() }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (deviceResponse.status === 401) {
|
if (deviceResponse.status === 401) {
|
||||||
@@ -889,6 +890,7 @@ async function showCaptureSettings(deviceId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const device = await deviceResponse.json();
|
const device = await deviceResponse.json();
|
||||||
|
const currentSettings = settingsResponse.ok ? await settingsResponse.json() : {};
|
||||||
|
|
||||||
// Populate display index select
|
// Populate display index select
|
||||||
const displaySelect = document.getElementById('capture-settings-display-index');
|
const displaySelect = document.getElementById('capture-settings-display-index');
|
||||||
@@ -910,6 +912,11 @@ async function showCaptureSettings(deviceId) {
|
|||||||
}
|
}
|
||||||
displaySelect.value = String(device.settings.display_index ?? 0);
|
displaySelect.value = String(device.settings.display_index ?? 0);
|
||||||
|
|
||||||
|
// Populate FPS slider
|
||||||
|
const fpsValue = Math.max(10, Math.min(90, currentSettings.fps ?? 30));
|
||||||
|
document.getElementById('capture-settings-fps').value = fpsValue;
|
||||||
|
document.getElementById('capture-settings-fps-value').textContent = fpsValue;
|
||||||
|
|
||||||
// Populate capture template select
|
// Populate capture template select
|
||||||
const templateSelect = document.getElementById('capture-settings-template');
|
const templateSelect = document.getElementById('capture-settings-template');
|
||||||
templateSelect.innerHTML = '';
|
templateSelect.innerHTML = '';
|
||||||
@@ -931,11 +938,13 @@ async function showCaptureSettings(deviceId) {
|
|||||||
}
|
}
|
||||||
templateSelect.value = device.capture_template_id || 'tpl_mss_default';
|
templateSelect.value = device.capture_template_id || 'tpl_mss_default';
|
||||||
|
|
||||||
// Store device ID and snapshot initial values
|
// Store device ID, current settings snapshot, and initial values for dirty check
|
||||||
document.getElementById('capture-settings-device-id').value = device.id;
|
document.getElementById('capture-settings-device-id').value = device.id;
|
||||||
captureSettingsInitialValues = {
|
captureSettingsInitialValues = {
|
||||||
display_index: String(device.settings.display_index ?? 0),
|
display_index: String(device.settings.display_index ?? 0),
|
||||||
|
fps: String(currentSettings.fps ?? 30),
|
||||||
capture_template_id: device.capture_template_id || 'tpl_mss_default',
|
capture_template_id: device.capture_template_id || 'tpl_mss_default',
|
||||||
|
_currentSettings: currentSettings,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Show modal
|
// Show modal
|
||||||
@@ -952,6 +961,7 @@ async function showCaptureSettings(deviceId) {
|
|||||||
function isCaptureSettingsDirty() {
|
function isCaptureSettingsDirty() {
|
||||||
return (
|
return (
|
||||||
document.getElementById('capture-settings-display-index').value !== captureSettingsInitialValues.display_index ||
|
document.getElementById('capture-settings-display-index').value !== captureSettingsInitialValues.display_index ||
|
||||||
|
document.getElementById('capture-settings-fps').value !== captureSettingsInitialValues.fps ||
|
||||||
document.getElementById('capture-settings-template').value !== captureSettingsInitialValues.capture_template_id
|
document.getElementById('capture-settings-template').value !== captureSettingsInitialValues.capture_template_id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -976,6 +986,7 @@ async function closeCaptureSettingsModal() {
|
|||||||
async function saveCaptureSettings() {
|
async function saveCaptureSettings() {
|
||||||
const deviceId = document.getElementById('capture-settings-device-id').value;
|
const deviceId = document.getElementById('capture-settings-device-id').value;
|
||||||
const display_index = parseInt(document.getElementById('capture-settings-display-index').value) || 0;
|
const display_index = parseInt(document.getElementById('capture-settings-display-index').value) || 0;
|
||||||
|
const fps = parseInt(document.getElementById('capture-settings-fps').value) || 30;
|
||||||
const capture_template_id = document.getElementById('capture-settings-template').value;
|
const capture_template_id = document.getElementById('capture-settings-template').value;
|
||||||
const error = document.getElementById('capture-settings-error');
|
const error = document.getElementById('capture-settings-error');
|
||||||
|
|
||||||
@@ -999,11 +1010,18 @@ async function saveCaptureSettings() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update display index in settings
|
// Merge changed fields with current settings to avoid resetting other values
|
||||||
|
const mergedSettings = {
|
||||||
|
...(captureSettingsInitialValues._currentSettings || {}),
|
||||||
|
display_index,
|
||||||
|
fps,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update settings
|
||||||
const settingsResponse = await fetch(`${API_BASE}/devices/${deviceId}/settings`, {
|
const settingsResponse = await fetch(`${API_BASE}/devices/${deviceId}/settings`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: getHeaders(),
|
headers: getHeaders(),
|
||||||
body: JSON.stringify({ display_index })
|
body: JSON.stringify(mergedSettings)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (settingsResponse.status === 401) {
|
if (settingsResponse.status === 401) {
|
||||||
|
|||||||
@@ -261,6 +261,15 @@
|
|||||||
<small class="input-hint" data-i18n="settings.display_index.hint">Which screen to capture for this device</small>
|
<small class="input-hint" data-i18n="settings.display_index.hint">Which screen to capture for this device</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="capture-settings-fps" data-i18n="settings.fps">Target FPS:</label>
|
||||||
|
<div class="slider-row">
|
||||||
|
<input type="range" id="capture-settings-fps" min="10" max="90" value="30" oninput="document.getElementById('capture-settings-fps-value').textContent = this.value">
|
||||||
|
<span id="capture-settings-fps-value" class="slider-value">30</span>
|
||||||
|
</div>
|
||||||
|
<small class="input-hint" data-i18n="settings.fps.hint">Target frames per second (10-90)</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="capture-settings-template" data-i18n="settings.capture_template">Capture Template:</label>
|
<label for="capture-settings-template" data-i18n="settings.capture_template">Capture Template:</label>
|
||||||
<select id="capture-settings-template"></select>
|
<select id="capture-settings-template"></select>
|
||||||
|
|||||||
@@ -152,6 +152,8 @@
|
|||||||
"settings.url.hint": "IP address or hostname of your WLED device",
|
"settings.url.hint": "IP address or hostname of your WLED device",
|
||||||
"settings.display_index": "Display:",
|
"settings.display_index": "Display:",
|
||||||
"settings.display_index.hint": "Which screen to capture for this device",
|
"settings.display_index.hint": "Which screen to capture for this device",
|
||||||
|
"settings.fps": "Target FPS:",
|
||||||
|
"settings.fps.hint": "Target frames per second (10-90)",
|
||||||
"settings.capture_template": "Capture Template:",
|
"settings.capture_template": "Capture Template:",
|
||||||
"settings.capture_template.hint": "Screen capture engine and configuration for this device",
|
"settings.capture_template.hint": "Screen capture engine and configuration for this device",
|
||||||
"settings.button.cancel": "Cancel",
|
"settings.button.cancel": "Cancel",
|
||||||
|
|||||||
@@ -152,6 +152,8 @@
|
|||||||
"settings.url.hint": "IP адрес или имя хоста вашего WLED устройства",
|
"settings.url.hint": "IP адрес или имя хоста вашего WLED устройства",
|
||||||
"settings.display_index": "Дисплей:",
|
"settings.display_index": "Дисплей:",
|
||||||
"settings.display_index.hint": "Какой экран захватывать для этого устройства",
|
"settings.display_index.hint": "Какой экран захватывать для этого устройства",
|
||||||
|
"settings.fps": "Целевой FPS:",
|
||||||
|
"settings.fps.hint": "Целевая частота кадров (10-90)",
|
||||||
"settings.capture_template": "Шаблон Захвата:",
|
"settings.capture_template": "Шаблон Захвата:",
|
||||||
"settings.capture_template.hint": "Движок захвата экрана и конфигурация для этого устройства",
|
"settings.capture_template.hint": "Движок захвата экрана и конфигурация для этого устройства",
|
||||||
"settings.button.cancel": "Отмена",
|
"settings.button.cancel": "Отмена",
|
||||||
|
|||||||
@@ -997,6 +997,24 @@ input:-webkit-autofill:focus {
|
|||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.slider-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider-row input[type="range"] {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider-value {
|
||||||
|
min-width: 28px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
.error-message {
|
.error-message {
|
||||||
background: rgba(244, 67, 54, 0.1);
|
background: rgba(244, 67, 54, 0.1);
|
||||||
border: 1px solid var(--danger-color);
|
border: 1px solid var(--danger-color);
|
||||||
|
|||||||
Reference in New Issue
Block a user