diff --git a/web/src/lib/components/preview/PreviewOverlay.svelte b/web/src/lib/components/preview/PreviewOverlay.svelte index 98d40d4..94c6f26 100644 --- a/web/src/lib/components/preview/PreviewOverlay.svelte +++ b/web/src/lib/components/preview/PreviewOverlay.svelte @@ -8,10 +8,10 @@ previewNext, previewPrev } from '$lib/stores/preview.svelte'; - import { thumbUrl } from '$lib/stores/session.svelte'; + import { thumbUrl, videoUrl } from '$lib/stores/session.svelte'; import { setFocused } from '$lib/stores/selection.svelte'; import RightSidebar from '$lib/components/sidebar/RightSidebar.svelte'; - import { primaryFile, type PpPhoto } from '$lib/types/photoprism'; + import { isVideo, primaryFile, videoFile, type PpPhoto } from '$lib/types/photoprism'; const photoQuery = createQuery(() => ({ queryKey: ['photo', preview.uid ?? ''], @@ -141,11 +141,24 @@

Failed to load photo.

{:else if photoQuery.data} {@const pf = primaryFile(photoQuery.data)} - {photoQuery.data.OriginalName + {#if isVideo(photoQuery.data)} + {@const vf = videoFile(photoQuery.data)} + + + {:else} + {photoQuery.data.OriginalName + {/if} {/if} diff --git a/web/src/lib/stores/session.svelte.ts b/web/src/lib/stores/session.svelte.ts index cf32377..4ae5a4f 100644 --- a/web/src/lib/stores/session.svelte.ts +++ b/web/src/lib/stores/session.svelte.ts @@ -87,3 +87,14 @@ export function thumbUrl(hash: string, size = 'tile_500'): string { if (!session.previewToken) return ''; return `/api/v1/t/${hash}/${session.previewToken}/${size}`; } + +/** + * Build a video stream URL. PhotoPrism's endpoint is + * /api/v1/videos/:hash/:token/:format — same previewToken as thumbnails. + * `format=avc` is the standard h264 transcode; HEVC sources are + * transcoded on first request and cached server-side. + */ +export function videoUrl(hash: string, format = 'avc'): string { + if (!session.previewToken) return ''; + return `/api/v1/videos/${hash}/${session.previewToken}/${format}`; +} diff --git a/web/src/lib/types/photoprism.ts b/web/src/lib/types/photoprism.ts index 93fcc9d..f03be66 100644 --- a/web/src/lib/types/photoprism.ts +++ b/web/src/lib/types/photoprism.ts @@ -174,6 +174,19 @@ export function primaryFile(p: PpPhoto): PpFile { }; } +export function isVideo(p: PpPhoto): boolean { + return p.Type === 'video'; +} + +/** Return the Files[] entry that carries the actual video stream. Falls back + * to primaryFile() if no video MediaType is present (shouldn't happen for + * Type === 'video' but keeps the call site total). */ +export function videoFile(p: PpPhoto): PpFile { + const files = p.Files ?? []; + const v = files.find((f) => f.MediaType?.startsWith('video/')); + return v ?? primaryFile(p); +} + export interface PpFile { UID: string; Hash: string;