Skip to content

Commit 711513d

Browse files
committed
feat: heavy WIP UI, need to tweak scdet
1 parent 8ebbc51 commit 711513d

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

ui/src/stores/streamTypes.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,21 @@ export interface Stream {
77
source: string;
88
}
99

10+
export interface Motion {
11+
/**
12+
* Time of the motion event in this recording, in seconds
13+
* @example 72 1m12s
14+
*/
15+
t: number;
16+
/**
17+
* The score of the motion event, 0-100
18+
* @example 2 low score
19+
* @example 8 high score
20+
* @example 16 extreme score
21+
*/
22+
s: number;
23+
}
24+
1025
export interface Recording {
1126
id: string;
1227
stream_id: string;
@@ -15,4 +30,10 @@ export interface Recording {
1530
end: string;
1631
path: string;
1732
thumbnail_path: string;
33+
/**
34+
* If false, motion detection hasn't been performed, and .motion will be empty.
35+
* If true, motion detection has been performed: if .motion is still empty, assume no motion.
36+
*/
37+
performed_motion_detect: boolean;
38+
motion: Motion[];
1839
}

ui/src/views/RecordingView.vue

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import { computed } from 'vue';
2+
import { computed, reactive, ref, onBeforeUnmount } from 'vue';
33
import { useRouter } from 'vue-router';
44
import { useStreamStore } from '@/stores/stream';
55
@@ -14,6 +14,38 @@ const props = defineProps<{
1414
}>();
1515
1616
const recording = computed(() => streamStore.recordings.find(r => r.id === props.recording));
17+
18+
const recordingDuration = computed(() => {
19+
if (!recording.value) {
20+
return 0;
21+
}
22+
return Math.round(((new Date(recording.value.end)).getTime() - (new Date(recording.value.start)).getTime()) / 1000)
23+
});
24+
25+
const data = reactive({
26+
sliderPos: 0,
27+
sliderPosInterval: null as ReturnType<typeof setInterval>|null,
28+
});
29+
30+
const video = ref<HTMLVideoElement|null>(null);
31+
32+
const setVideoPos = () => {
33+
if (!video.value) {
34+
return;
35+
}
36+
video.value.currentTime = data.sliderPos;
37+
};
38+
39+
data.sliderPosInterval = setInterval(() => {
40+
if (video.value) {
41+
data.sliderPos = video.value.currentTime;
42+
}
43+
}, 100);
44+
onBeforeUnmount(() => {
45+
if (data.sliderPosInterval !== null) {
46+
clearInterval(data.sliderPosInterval);
47+
}
48+
});
1749
</script>
1850

1951
<template>
@@ -34,6 +66,7 @@ const recording = computed(() => streamStore.recordings.find(r => r.id === props
3466
muted
3567
controls
3668
autoplay
69+
ref="video"
3770
/>
3871
</div>
3972
</div>
@@ -62,6 +95,13 @@ const recording = computed(() => streamStore.recordings.find(r => r.id === props
6295
</button>
6396
</div>
6497
</div> -->
98+
99+
<div v-if="recording && recording.performed_motion_detect" class="bg-gray-800 text-white p-4">
100+
<input class="range" type="range" list="range" step="any" :min="0" :max="recordingDuration" v-model="data.sliderPos" @input="setVideoPos" />
101+
<datalist id="range">
102+
<option v-for="m in recording.motion" :value="m.t" :label="`${m.s}`"></option>
103+
</datalist>
104+
</div>
65105

66106
<div v-if="recording" class="bg-gray-900 text-white p-4">
67107
<div class="flex items-center justify-between">
@@ -98,4 +138,10 @@ const recording = computed(() => streamStore.recordings.find(r => r.id === props
98138
</div>
99139
</div>
100140
</div>
101-
</template>
141+
</template>
142+
143+
<style scoped>
144+
.range {
145+
width: 100%;
146+
}
147+
</style>

0 commit comments

Comments
 (0)