mirror of
https://github.com/immich-app/immich.git
synced 2025-03-11 02:23:09 -05:00
feat(web): Video memories on web (#16500)
* Video memories on web * switched mixed up strings
This commit is contained in:
parent
8b24c31d20
commit
7bbc1d9f68
2 changed files with 65 additions and 10 deletions
|
@ -890,6 +890,7 @@
|
|||
"month": "Month",
|
||||
"more": "More",
|
||||
"moved_to_trash": "Moved to trash",
|
||||
"mute_memories": "Mute Memories",
|
||||
"my_albums": "My albums",
|
||||
"name": "Name",
|
||||
"name_or_nickname": "Name or nickname",
|
||||
|
@ -1304,6 +1305,7 @@
|
|||
"unnamed_album": "Unnamed Album",
|
||||
"unnamed_album_delete_confirmation": "Are you sure you want to delete this album?",
|
||||
"unnamed_share": "Unnamed Share",
|
||||
"unmute_memories": "Unmute Memories",
|
||||
"unsaved_change": "Unsaved change",
|
||||
"unselect_all": "Unselect all",
|
||||
"unselect_all_duplicates": "Unselect all duplicates",
|
||||
|
|
|
@ -28,13 +28,14 @@
|
|||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
import { type Viewport } from '$lib/stores/assets.store';
|
||||
import { loadMemories, memoryStore } from '$lib/stores/memory.store';
|
||||
import { locale } from '$lib/stores/preferences.store';
|
||||
import { locale, videoViewerMuted } from '$lib/stores/preferences.store';
|
||||
import { preferences } from '$lib/stores/user.store';
|
||||
import { getAssetThumbnailUrl, handlePromiseError, memoryLaneTitle } from '$lib/utils';
|
||||
import { getAssetPlaybackUrl, getAssetThumbnailUrl, handlePromiseError, memoryLaneTitle } from '$lib/utils';
|
||||
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
||||
import { fromLocalDateTime } from '$lib/utils/timeline-util';
|
||||
import {
|
||||
AssetMediaSize,
|
||||
AssetTypeEnum,
|
||||
deleteMemory,
|
||||
removeMemoryAssets,
|
||||
updateMemory,
|
||||
|
@ -57,6 +58,8 @@
|
|||
mdiPlay,
|
||||
mdiPlus,
|
||||
mdiSelectAll,
|
||||
mdiVolumeOff,
|
||||
mdiVolumeHigh,
|
||||
} from '@mdi/js';
|
||||
import type { NavigationTarget } from '@sveltejs/kit';
|
||||
import { DateTime } from 'luxon';
|
||||
|
@ -91,9 +94,10 @@
|
|||
const { isViewing } = assetViewingStore;
|
||||
const viewport: Viewport = $state({ width: 0, height: 0 });
|
||||
const assetInteraction = new AssetInteraction();
|
||||
const progressBarController = tweened<number>(0, {
|
||||
let progressBarController = tweened<number>(0, {
|
||||
duration: (from: number, to: number) => (to ? 5000 * (to - from) : 0),
|
||||
});
|
||||
let videoPlayer: HTMLVideoElement | undefined = $state();
|
||||
const memories = storeDerived(memoryStore, (memories) => {
|
||||
memories = memories ?? [];
|
||||
const memoryAssets: MemoryAsset[] = [];
|
||||
|
@ -139,8 +143,24 @@
|
|||
return;
|
||||
}
|
||||
|
||||
// Adjust the progress bar duration to the video length
|
||||
setProgressDuration(asset);
|
||||
|
||||
await goto(asHref(asset));
|
||||
};
|
||||
const setProgressDuration = (asset: AssetResponseDto) => {
|
||||
if (asset.type === AssetTypeEnum.Video) {
|
||||
const timeParts = asset.duration.split(':').map(Number);
|
||||
const durationInMilliseconds = (timeParts[0] * 3600 + timeParts[1] * 60 + timeParts[2]) * 1000;
|
||||
progressBarController = tweened<number>(0, {
|
||||
duration: (from: number, to: number) => (to ? durationInMilliseconds * (to - from) : 0),
|
||||
});
|
||||
} else {
|
||||
progressBarController = tweened<number>(0, {
|
||||
duration: (from: number, to: number) => (to ? 5000 * (to - from) : 0),
|
||||
});
|
||||
}
|
||||
};
|
||||
const handleNextAsset = () => handleNavigate(current?.next?.asset);
|
||||
const handlePreviousAsset = () => handleNavigate(current?.previous?.asset);
|
||||
const handleNextMemory = () => handleNavigate(current?.nextMemory?.assets[0]);
|
||||
|
@ -151,18 +171,21 @@
|
|||
switch (action) {
|
||||
case 'play': {
|
||||
paused = false;
|
||||
await videoPlayer?.play();
|
||||
await progressBarController.set(1);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'pause': {
|
||||
paused = true;
|
||||
videoPlayer?.pause();
|
||||
await progressBarController.set($progressBarController);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'reset': {
|
||||
paused = false;
|
||||
videoPlayer?.pause();
|
||||
resetPromise = progressBarController.set(0);
|
||||
break;
|
||||
}
|
||||
|
@ -203,6 +226,9 @@
|
|||
}
|
||||
|
||||
current = loadFromParams($memories, $page);
|
||||
|
||||
// Adjust the progress bar duration to the video length
|
||||
setProgressDuration(current.asset);
|
||||
};
|
||||
|
||||
const handleDeleteMemoryAsset = async (current?: MemoryAsset) => {
|
||||
|
@ -290,6 +316,12 @@
|
|||
$effect(() => {
|
||||
handlePromiseError(handleAction(galleryInView ? 'pause' : 'play'));
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (videoPlayer) {
|
||||
videoPlayer.muted = $videoViewerMuted;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:window
|
||||
|
@ -373,6 +405,11 @@
|
|||
{(current.assetIndex + 1).toLocaleString($locale)}/{current.memory.assets.length.toLocaleString($locale)}
|
||||
</p>
|
||||
</div>
|
||||
<CircleIconButton
|
||||
title={$videoViewerMuted ? $t('unmute_memories') : $t('mute_memories')}
|
||||
icon={$videoViewerMuted ? mdiVolumeOff : mdiVolumeHigh}
|
||||
onclick={() => ($videoViewerMuted = !$videoViewerMuted)}
|
||||
/>
|
||||
</div>
|
||||
</ControlAppBar>
|
||||
|
||||
|
@ -436,13 +473,29 @@
|
|||
>
|
||||
<div class="relative h-full w-full rounded-2xl bg-black">
|
||||
{#key current.asset.id}
|
||||
<img
|
||||
transition:fade
|
||||
class="h-full w-full rounded-2xl object-contain transition-all"
|
||||
src={getAssetThumbnailUrl({ id: current.asset.id, size: AssetMediaSize.Preview })}
|
||||
alt={current.asset.exifInfo?.description}
|
||||
draggable="false"
|
||||
/>
|
||||
<div transition:fade class="h-full w-full">
|
||||
{#if current.asset.type == AssetTypeEnum.Video}
|
||||
<video
|
||||
bind:this={videoPlayer}
|
||||
autoplay
|
||||
playsinline
|
||||
class="h-full w-full rounded-2xl object-contain transition-all"
|
||||
src={getAssetPlaybackUrl({ id: current.asset.id })}
|
||||
poster={getAssetThumbnailUrl({ id: current.asset.id, size: AssetMediaSize.Preview })}
|
||||
draggable="false"
|
||||
muted={$videoViewerMuted}
|
||||
transition:fade
|
||||
></video>
|
||||
{:else}
|
||||
<img
|
||||
class="h-full w-full rounded-2xl object-contain transition-all"
|
||||
src={getAssetThumbnailUrl({ id: current.asset.id, size: AssetMediaSize.Preview })}
|
||||
alt={current.asset.exifInfo?.description}
|
||||
draggable="false"
|
||||
transition:fade
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{/key}
|
||||
|
||||
<div
|
||||
|
|
Loading…
Add table
Reference in a new issue