diff --git a/webui/src/components/display/blobs/VideoViewer.svelte b/webui/src/components/display/blobs/VideoViewer.svelte index dc1e11e..6924156 100644 --- a/webui/src/components/display/blobs/VideoViewer.svelte +++ b/webui/src/components/display/blobs/VideoViewer.svelte @@ -16,10 +16,22 @@ let state = State.LOADING; let videoEl: HTMLVideoElement; + let currentTime: number; + + let timeCodeWidth: number; + let timeCodeLeft: string; const seek = throttle((progress: number) => { if (state === State.PREVIEWING && videoEl.duration) { - videoEl.currentTime = videoEl.duration * progress; + currentTime = videoEl.duration * progress; + + if (timeCodeWidth) { + let timeCodeLeftPx = Math.min( + Math.max(videoEl.clientWidth * progress, timeCodeWidth / 2), + videoEl.clientWidth - timeCodeWidth / 2 + ); + timeCodeLeft = `${timeCodeLeftPx}px`; + } } }, 100); @@ -73,6 +85,7 @@ on:click|preventDefault={startPlaying} controls={state === State.PLAYING} bind:this={videoEl} + bind:currentTime /> {/if}
@@ -80,6 +93,21 @@
+
+ {#if videoEl?.duration && currentTime} + {#if videoEl.duration > 3600}{String( + Math.floor(currentTime / 3600) + ).padStart(2, "0")}:{/if}{String( + Math.floor((currentTime % 3600) / 60) + ).padStart(2, "0")}:{String( + Math.floor((currentTime % 3600) % 60) + ).padStart(2, "0")} + {/if} +
@@ -141,6 +169,31 @@ pointer-events: none; } + .timecode { + display: none; + pointer-events: none; + + position: absolute; + top: 50%; + left: var(--left); + transform: translate(-50%, -50%); + + font-feature-settings: "tnum"; + font-weight: bold; + font-size: 24px; + color: white; + opacity: 0.85; + } + + &.loading { + .player > * { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + } + } + &.standby, &.preview { img, @@ -152,8 +205,13 @@ } } - &.previewing video { - cursor: pointer; + &.previewing { + .timecode { + display: block; + } + video { + cursor: pointer; + } } }