From 3b2c7c65ae5a07c2a37c5fe18c8e32da1e990252 Mon Sep 17 00:00:00 2001 From: Momentry Studio Date: Wed, 21 Oct 2026 01:32:23 +0800 Subject: [PATCH] feat: clickable file name in video player for full file playback - File name in header is now clickable - Click reloads video with full file range (startFrame=0, endFrame=999999) - Added play icon and hover effect for visual feedback --- src/components/VideoPlayer.vue | 39 ++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/components/VideoPlayer.vue b/src/components/VideoPlayer.vue index a5a823b..25a33c7 100644 --- a/src/components/VideoPlayer.vue +++ b/src/components/VideoPlayer.vue @@ -3,7 +3,10 @@
-

{{ actualFileName }}

+

+ {{ actualFileName }} + +

@@ -1370,6 +1373,35 @@ function formatTime(sec: number): string { return `${m}:${s.toString().padStart(2, '0')}` } +async function playFullFile() { + videoLoading.value = true + videoError.value = '' + marks.value = marks.value.filter(m => m.source !== 'face') + try { + const data = await apiCall('get_video_stream', { + uuid: props.fileUuid, + startTime: null, + endTime: null, + startFrame: 0, + endFrame: 999999, + original: props.useOriginal, + }) + if (typeof data === 'string') { + videoSrc.value = data + } else { + const blob = new Blob([new Uint8Array(data)], { type: 'video/mp4' }) + videoSrc.value = URL.createObjectURL(blob) + } + frameOffset.value = 0 + await nextTick() + videoEl.value?.load() + } catch (e: any) { + videoError.value = e?.message || 'Failed to load full video' + } finally { + videoLoading.value = false + } +} + function onKeydown(e: KeyboardEvent) { if (!visible.value) return switch (e.key) { @@ -1538,7 +1570,10 @@ onUnmounted(() => { } .ms-modal-video-header { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; } .ms-video-header-row { display: flex; align-items: center; justify-content: space-between; } -.ms-video-file-name { font-size: 12px; font-weight: 500; color: var(--text-secondary); margin: 0; max-width: 70%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.ms-video-file-name { font-size: 12px; font-weight: 500; color: var(--text-secondary); margin: 0; max-width: 70%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; } +.ms-video-file-name:hover { color: var(--primary-color); } +.ms-video-fullfile-icon { opacity: 0.5; transition: opacity .15s; } +.ms-video-file-name:hover .ms-video-fullfile-icon { opacity: 1; } .ms-video-frame-info { font-size: 12px; color: var(--text-secondary); white-space: nowrap; flex-shrink: 0; } .ms-video-keyframe { color: #ff9800; font-weight: 600; cursor: pointer; } .ms-video-keyframe:hover { text-decoration: underline; }