diff --git a/src/components/settings/SettingsTimelapseTab.vue b/src/components/settings/SettingsTimelapseTab.vue index 13cc39b70..b39f84d27 100644 --- a/src/components/settings/SettingsTimelapseTab.vue +++ b/src/components/settings/SettingsTimelapseTab.vue @@ -27,14 +27,19 @@ + :sub-title="$t('Settings.TimelapseTab.CameraDescriptionWithSnapshotUrl')"> + + {{ $t('Settings.TimelapseTab.CameraWarningAlreadySet') }} + ({{ $t('Settings.TimelapseTab.CameraWarningAlreadySetSmall') }}) + + :disabled="blockedsettings.includes('camera') || availableSnapshotWebcams.length === 0" /> webcam.snapshot_url !== '' + ) + } + get cameraOptions() { - const webcams = this.$store.getters['gui/webcams/getWebcams'] - const output: any = [] - - webcams - .filter((webcam: GuiWebcamStateWebcam) => webcam.snapshot_url !== '') - .forEach((webcam: GuiWebcamStateWebcam) => { - output.push({ - text: webcam.name, - value: webcam.name, - }) + let output: { text: string | TranslateResult; value: string | null }[] = [] + + if (this.availableSnapshotWebcams.length === 0) { + return [{ value: null, text: this.$t('Settings.TimelapseTab.NoWebcamFound') }] + } + + this.availableSnapshotWebcams.forEach((webcam: GuiWebcamStateWebcam) => { + output.push({ + text: webcam.name, + value: webcam.name, }) + }) - return caseInsensitiveSort(output, 'text') + output = caseInsensitiveSort(output, 'text') + + if (this.camera === null) { + output.unshift({ value: null, text: this.$t('Settings.TimelapseTab.SelectWebcam') }) + } + + return output } get blockedsettings() { @@ -853,6 +872,17 @@ export default class SettingsTimelapseTab extends Mixins(BaseMixin) { } get camera() { + const value = this.$store.state.server.timelapse.settings.camera ?? null + + if ( + value === null || + this.blockedsettings.includes('snapshoturl') || + this.availableSnapshotWebcams.length === 0 || + this.availableSnapshotWebcams.find((webcam) => webcam.name === value) === undefined + ) { + return null + } + return this.$store.state.server.timelapse.settings.camera } diff --git a/src/locales/en.json b/src/locales/en.json index 9cb4a0dad..50ba5a85f 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1112,7 +1112,9 @@ "Autorender": "Autorender", "AutorenderDescription": "If enabled, the timelapse video will automatically render at the end of the print", "Camera": "Camera", - "CameraDescription": "Select which camera should be used", + "CameraDescriptionWithSnapshotUrl": "Select which camera (with snapshot URL) should be used", + "CameraWarningAlreadySet": "This value is already set in the Moonraker configuration file.", + "CameraWarningAlreadySetSmall": "snapshoturl in the [timelapse] section", "ConstantRateFactor": "Constant Rate Factor", "ConstantRateFactorDescription": "This configure quality vs file size of the rendered video. The range of the CRF scale is 0–51, where 0 is lossless, 23 is the default and 51 is worst quality possible. A lower value generally leads to higher quality and a subjectively sane range is 17–28. Consider 17 or 18 to be visually lossless.", "duplicatelastframe": "Duplicate Last Frame", @@ -1130,6 +1132,7 @@ "HyperlapseCycleDescription": "A snapshot will be taken any X seconds", "Mode": "Mode", "ModeDescription": "Select between Layer macro and Hyperlapse (time-based) mode", + "NoWebcamFound": "No Webcam available", "OutputFramerate": "Output Framerate", "OutputFramerateDescription": "Defines the framerate of the video. Note: this will be ignored if variable_fps is enabled", "Parkhead": "Park Toolhead", @@ -1160,6 +1163,7 @@ "RulesZeroAndPositive": "Value must be 0 or greater!", "SaveFrames": "Save Frames", "SaveFramesDescription": "Save the frames to a zip-file for external rendering", + "SelectWebcam": "Select webcam...", "StreamDelayCompensation": "Stream Delay Compensation", "StreamDelayCompensationDescription": "Delay frame capture", "Targetlength": "Target Length", diff --git a/src/store/server/actions.ts b/src/store/server/actions.ts index 8fb762b75..75c11cc30 100644 --- a/src/store/server/actions.ts +++ b/src/store/server/actions.ts @@ -59,15 +59,15 @@ export const actions: ActionTree = { dispatch('socket/addInitModule', 'gui/init', { root: true }) dispatch('gui/init', null, { root: true }) } else dispatch('gui/initDb', null, { root: true }) - if (payload.namespaces?.includes('webcams')) { - dispatch('socket/addInitModule', 'gui/webcam/init', { root: true }) - dispatch('gui/webcams/init', null, { root: true }) - } if (payload.namespaces?.includes('maintenance')) { dispatch('socket/addInitModule', 'gui/maintenance/init', { root: true }) dispatch('gui/maintenance/init', null, { root: true }) } else dispatch('gui/maintenance/initDb', null, { root: true }) + // init webcams + dispatch('socket/addInitModule', 'gui/webcam/init', { root: true }) + dispatch('gui/webcams/init', null, { root: true }) + commit('saveDbNamespaces', payload.namespaces) Vue.$socket.emit('server.info', {}, { action: 'server/checkKlippyConnected' })