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' })