diff --git a/src/components/mini-widgets/MiniVideoRecorder.vue b/src/components/mini-widgets/MiniVideoRecorder.vue index 3a7ea2e9e..eb53990ae 100644 --- a/src/components/mini-widgets/MiniVideoRecorder.vue +++ b/src/components/mini-widgets/MiniVideoRecorder.vue @@ -57,6 +57,7 @@ import { useMouseInElement, useTimestamp } from '@vueuse/core' import { format, intervalToDuration } from 'date-fns' import { saveAs } from 'file-saver' import fixWebmDuration from 'fix-webm-duration' +import localforage from 'localforage' import { storeToRefs } from 'pinia' import Swal, { type SweetAlertResult } from 'sweetalert2' import { computed, onBeforeMount, onBeforeUnmount, ref, toRefs, watch } from 'vue' @@ -101,6 +102,13 @@ const isRecording = computed(() => { return mediaRecorder.value !== undefined && mediaRecorder.value.state === 'recording' }) +const cockpitVideoDB = localforage.createInstance({ + driver: localforage.INDEXEDDB, + name: 'CockpitVideoDB', + storeName: 'cockpit-video-db', + version: 1.0, + description: 'Local backups of Cockpit video recordings to be retrieved in case of failure.', +}) onBeforeMount(async () => { // Set initial widget options if they don't exist if (Object.keys(miniWidget.value.options).length === 0) { @@ -109,6 +117,16 @@ onBeforeMount(async () => { } } addScreenStream() + + const videoKeys = await cockpitVideoDB.keys() + videoKeys.forEach(async (savedVideoName) => { + const videoBlobArray: Blob[] = (await cockpitVideoDB.getItem(savedVideoName)) as Blob[] + const blob = videoBlobArray.reduce((a, b) => new Blob([a, b], { type: 'video/webm' })) + fixWebmDuration(blob, Date.now() - timeRecordingStart.value.getTime()).then((fixedBlob) => { + saveAs(fixedBlob, savedVideoName) + }) + await cockpitVideoDB.removeItem(savedVideoName) + }) }) const toggleRecording = async (): Promise => { @@ -183,15 +201,20 @@ const startRecording = async (): Promise => { } timeRecordingStart.value = new Date() + const fileName = `${missionName || 'Cockpit'} (${format(timeRecordingStart.value, 'LLL dd, yyyy - HH꞉mm꞉ss O')})` mediaRecorder.value = new MediaRecorder(mediaStream.value) - mediaRecorder.value.start() + mediaRecorder.value.start(1000) let chunks: Blob[] = [] - mediaRecorder.value.ondataavailable = (e) => chunks.push(e.data) + mediaRecorder.value.ondataavailable = async (e) => { + chunks.push(e.data) + await cockpitVideoDB.setItem(fileName, chunks, () => + console.log('Saving...', chunks.map((b) => b.size).sum() / 10 ** 6) + ) + } mediaRecorder.value.onstop = () => { const blob = new Blob(chunks, { type: 'video/webm' }) fixWebmDuration(blob, Date.now() - timeRecordingStart.value.getTime()).then((fixedBlob) => { - const fileName = `${missionName || 'Cockpit'} (${format(timeRecordingStart.value, 'LLL dd, yyyy - HH꞉mm꞉ss O')})` saveAs(fixedBlob, fileName) }) chunks = []