mediaLoaded(assetManager)}
+ onerror={() => mediaLoadError(assetManager)}
+ />
+ {#if !assetManager.isLoaded}
({})}
onswipe={onSwipe}
class="h-full w-full"
@@ -245,7 +181,7 @@
>
{#if $slideshowState !== SlideshowState.None && $slideshowLook === SlideshowLook.BlurredBackground}

- {#each getBoundingBox($boundingBoxesArray, $photoZoomState, $photoViewerImgElement) as boundingbox}
+ {#each getBoundingBox($boundingBoxesArray, zoomImageState!, $photoViewerImgElement) as boundingbox}
{#if isFaceEditMode.value}
-
+
{/if}
{/if}
diff --git a/web/src/lib/components/asset-viewer/video-native-viewer.svelte b/web/src/lib/components/asset-viewer/video-native-viewer.svelte
index 4b8bb40f77..2a6218afaf 100644
--- a/web/src/lib/components/asset-viewer/video-native-viewer.svelte
+++ b/web/src/lib/components/asset-viewer/video-native-viewer.svelte
@@ -3,6 +3,7 @@
import VideoRemoteViewer from '$lib/components/asset-viewer/video-remote-viewer.svelte';
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
import { assetViewerFadeDuration } from '$lib/constants';
+ import { AssetManager } from '$lib/managers/asset-manager/asset-manager.svelte';
import { castManager } from '$lib/managers/cast-manager.svelte';
import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
import { loopVideo as loopVideoPreference, videoViewerMuted, videoViewerVolume } from '$lib/stores/preferences.store';
@@ -16,9 +17,8 @@
import { fade } from 'svelte/transition';
interface Props {
- assetId: string;
+ assetManager: AssetManager;
loopVideo: boolean;
- cacheKey: string | null;
onPreviousAsset?: () => void;
onNextAsset?: () => void;
onVideoEnded?: () => void;
@@ -27,9 +27,8 @@
}
let {
- assetId,
+ assetManager = $bindable(),
loopVideo,
- cacheKey,
onPreviousAsset = () => {},
onNextAsset = () => {},
onVideoEnded = () => {},
diff --git a/web/src/lib/components/asset-viewer/video-panorama-viewer.svelte b/web/src/lib/components/asset-viewer/video-panorama-viewer.svelte
index 2cf8e65871..65af34e321 100644
--- a/web/src/lib/components/asset-viewer/video-panorama-viewer.svelte
+++ b/web/src/lib/components/asset-viewer/video-panorama-viewer.svelte
@@ -3,12 +3,13 @@
import { t } from 'svelte-i18n';
import { fade } from 'svelte/transition';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
+ import type { AssetManager } from '$lib/managers/asset-manager/asset-manager.svelte';
interface Props {
- assetId: string;
+ assetManager: AssetManager;
}
- const { assetId }: Props = $props();
+ const { assetManager = $bindable() }: Props = $props();
const modules = Promise.all([
import('./photo-sphere-viewer-adapter.svelte').then((module) => module.default),
diff --git a/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte b/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte
index a5a94d85d4..b243b6ae55 100644
--- a/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte
+++ b/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte
@@ -1,12 +1,12 @@
{#if projectionType === ProjectionType.EQUIRECTANGULAR}
-
+
{:else}
{
- const laterAsset = await timelineManager.getLaterAsset(asset);
-
- if (laterAsset) {
- // TODO: If preloadAsset is undefined, throw an exception.
- // assetManager.preloadAssets = [await timelineManager.getLaterAsset(laterAsset)];
- await navigate({ targetRoute: 'current', assetId: laterAsset.id });
+ let laterAsset = undefined;
+ if (asset) {
+ laterAsset = await timelineManager.getLaterAsset(asset);
+ if (laterAsset) {
+ // TODO: If preloadAsset is undefined, throw an exception.
+ // assetManager.preloadAssets = [await timelineManager.getLaterAsset(laterAsset)];
+ await navigate({ targetRoute: 'current', assetId: laterAsset.id });
+ }
}
-
return !!laterAsset;
};
const handleNext = async () => {
- const earlierAsset = await timelineManager.getEarlierAsset(asset);
-
- if (earlierAsset) {
- // assetManager.preloadAssets = [await timelineManager.getEarlierAsset(earlierAsset)];
- await navigate({ targetRoute: 'current', assetId: earlierAsset.id });
+ let earlierAsset = undefined;
+ if (asset) {
+ earlierAsset = await timelineManager.getEarlierAsset(asset);
+ if (earlierAsset) {
+ // assetManager.preloadAssets = [await timelineManager.getEarlierAsset(earlierAsset)];
+ await navigate({ targetRoute: 'current', assetId: earlierAsset.id });
+ }
}
-
return !!earlierAsset;
};
const handleRandom = async () => {
- const randomAsset = await timelineManager.getRandomAsset();
-
- if (randomAsset) {
- await navigate({ targetRoute: 'current', assetId: randomAsset.id });
+ let randomAsset = undefined;
+ if (asset) {
+ randomAsset = await timelineManager.getRandomAsset();
+ if (randomAsset) {
+ await navigate({ targetRoute: 'current', assetId: randomAsset.id });
+ }
}
-
return !!randomAsset;
};
@@ -777,7 +780,7 @@
});
$effect(() => {
- if (assetManager.showAssetViewer) {
+ if (assetManager.showAssetViewer && asset) {
const { localDateTime } = getTimes(asset.fileCreatedAt, DateTime.local().offset / 60);
void timelineManager.loadMonthGroup({ year: localDateTime.year, month: localDateTime.month });
}
diff --git a/web/src/lib/components/share-page/individual-shared-viewer.svelte b/web/src/lib/components/share-page/individual-shared-viewer.svelte
index 2b955812bd..6e925e99e0 100644
--- a/web/src/lib/components/share-page/individual-shared-viewer.svelte
+++ b/web/src/lib/components/share-page/individual-shared-viewer.svelte
@@ -3,7 +3,7 @@
import type { Action } from '$lib/components/asset-viewer/actions/action';
import ImmichLogoSmallLink from '$lib/components/shared-components/immich-logo-small-link.svelte';
import { AppRoute, AssetAction } from '$lib/constants';
- import type { AssetManager } from '$lib/managers/asset-manager.svelte';
+ import type { AssetManager } from '$lib/managers/asset-manager/asset-manager.svelte';
import { authManager } from '$lib/managers/auth-manager.svelte';
import type { Viewport } from '$lib/managers/timeline-manager/types';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
diff --git a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte
index 34e5252b18..9a1e8363db 100644
--- a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte
+++ b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte
@@ -4,7 +4,7 @@
import type { Action } from '$lib/components/asset-viewer/actions/action';
import Thumbnail from '$lib/components/assets/thumbnail/thumbnail.svelte';
import { AppRoute, AssetAction } from '$lib/constants';
- import type { AssetManager } from '$lib/managers/asset-manager.svelte';
+ import type { AssetManager } from '$lib/managers/asset-manager/asset-manager.svelte';
import { modalManager } from '$lib/managers/modal-manager.svelte';
import type { TimelineAsset, Viewport } from '$lib/managers/timeline-manager/types';
import ShortcutsModal from '$lib/modals/ShortcutsModal.svelte';
diff --git a/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte b/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte
index fb14c56e09..3a1171c8c0 100644
--- a/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte
+++ b/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte
@@ -2,7 +2,7 @@
import { shortcuts } from '$lib/actions/shortcut';
import Portal from '$lib/components/shared-components/portal/portal.svelte';
import DuplicateAsset from '$lib/components/utilities-page/duplicates/duplicate-asset.svelte';
- import type { AssetManager } from '$lib/managers/asset-manager.svelte';
+ import type { AssetManager } from '$lib/managers/asset-manager/asset-manager.svelte';
import { handlePromiseError } from '$lib/utils';
import { suggestDuplicate } from '$lib/utils/duplicate-utils';
import { navigate } from '$lib/utils/navigation';
diff --git a/web/src/lib/managers/asset-manager.svelte.ts b/web/src/lib/managers/asset-manager.svelte.ts
deleted file mode 100644
index b294a02d1a..0000000000
--- a/web/src/lib/managers/asset-manager.svelte.ts
+++ /dev/null
@@ -1,143 +0,0 @@
-import { authManager } from '$lib/managers/auth-manager.svelte';
-import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
-import { CancellableTask } from '$lib/utils/cancellable-task';
-import type { AssetGridRouteSearchParams } from '$lib/utils/navigation';
-import {
- AssetMediaSize,
- AssetTypeEnum,
- AssetVisibility,
- getAllAlbums,
- getAssetInfo,
- getAssetOriginalPath,
- getAssetPlaybackPath,
- getAssetThumbnailPath,
- getBaseUrl,
- type AlbumResponseDto,
- type AssetResponseDto,
-} from '@immich/sdk';
-import { isEqual } from 'lodash-es';
-
-export type AssetManagerOptions = {
- assetId?: string;
- preloadAssetIds?: string[];
- size?: AssetMediaSize;
-};
-
-export class AssetManager {
- isInitialized = $state(false);
- #asset: AssetResponseDto | undefined = $state();
- preloadAssets: TimelineAsset[] = $state([]);
- cacheKey: string | null = $state(null);
- albums: AlbumResponseDto[] = $state([]);
-
- showAssetViewer: boolean = $state(false);
- gridScrollTarget: AssetGridRouteSearchParams | undefined = $state();
-
- initTask = new CancellableTask(
- () => (this.isInitialized = true),
- () => (this.isInitialized = false),
- () => void 0,
- );
-
- // TODO: Delete this after development
- #emptyAsset: AssetResponseDto = {
- checksum: '',
- deviceAssetId: '',
- deviceId: '',
- duration: '',
- fileCreatedAt: '',
- fileModifiedAt: '',
- hasMetadata: true,
- id: '',
- isArchived: false,
- isFavorite: false,
- isOffline: false,
- isTrashed: false,
- localDateTime: '',
- originalFileName: '',
- originalPath: '',
- ownerId: '',
- thumbhash: null,
- type: AssetTypeEnum.Image,
- updatedAt: '',
- visibility: AssetVisibility.Timeline,
- };
-
- static #INIT_OPTIONS = {};
- #options: AssetManagerOptions = AssetManager.#INIT_OPTIONS;
-
- constructor() {}
-
- async #initializeAsset(id: string) {
- const assetResponse = await getAssetInfo({ id, key: authManager.key });
-
- if (!assetResponse) {
- return;
- }
- this.#asset = assetResponse;
-
- const albumsResponse = await getAllAlbums({ assetId: this.asset.id });
-
- if (!albumsResponse) {
- return;
- }
- this.albums = albumsResponse;
- }
-
- async refreshAlbums() {}
-
- async refreshAsset() {}
-
- async updateOptions(options: AssetManagerOptions) {
- if (this.#options !== AssetManager.#INIT_OPTIONS && isEqual(this.#options, options)) {
- return;
- }
- await this.initTask.reset();
- await this.#init(options);
- }
-
- async #init(options: AssetManagerOptions) {
- this.isInitialized = false;
- await this.initTask.execute(async () => {
- this.#options = options;
- // TODO: If assetId is undefined, throw an exception.
- await this.#initializeAsset(this.#options.assetId!);
- // TODO: Preload assets.
- }, true);
- }
-
- public destroy() {
- this.isInitialized = false;
- }
-
- #createUrl(path: string, parameters?: Record) {
- const searchParameters = new URLSearchParams();
- for (const key in parameters) {
- const value = parameters[key];
- if (value !== undefined && value !== null) {
- searchParameters.set(key, value.toString());
- }
- }
- return getBaseUrl() + path + searchParameters.toString();
- }
-
- get asset() {
- return this.#asset ?? this.#emptyAsset;
- }
-
- get originalUrl() {
- return this.#createUrl(getAssetOriginalPath(this.asset.id), { key: authManager.key, c: this.cacheKey });
- }
-
- get thumbnailUrl() {
- return this.#createUrl(getAssetThumbnailPath(this.asset.id), {
- key: authManager.key,
- c: this.cacheKey,
- size: this.#options.size,
- });
- }
-
- get playbackUrl() {
- return this.#createUrl(getAssetPlaybackPath(this.asset.id), { key: authManager.key, c: this.cacheKey });
- }
-}
diff --git a/web/src/lib/managers/asset-manager/asset-manager.svelte.ts b/web/src/lib/managers/asset-manager/asset-manager.svelte.ts
new file mode 100644
index 0000000000..5550ff4b44
--- /dev/null
+++ b/web/src/lib/managers/asset-manager/asset-manager.svelte.ts
@@ -0,0 +1,204 @@
+import { authManager } from '$lib/managers/auth-manager.svelte';
+import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
+import { CancellableTask } from '$lib/utils/cancellable-task';
+import type { AssetGridRouteSearchParams } from '$lib/utils/navigation';
+import { toTimelineAsset } from '$lib/utils/timeline-util';
+import {
+ getAllAlbums,
+ getAssetInfo,
+ getAssetOriginalPath,
+ getAssetPlaybackPath,
+ getAssetThumbnailPath,
+ getBaseUrl,
+ type AlbumResponseDto,
+ type AssetResponseDto,
+} from '@immich/sdk';
+import { type ZoomImageWheelState } from '@zoom-image/core';
+import { isEqual } from 'lodash-es';
+
+export enum AssetMediaSize {
+ Original = 'original',
+ Fullsize = 'fullsize',
+ Preview = 'preview',
+ Thumbnail = 'thumbnail',
+ Playback = 'playback',
+}
+
+export type AssetManagerOptions = {
+ assetId?: string;
+ preloadAssetIds?: string[];
+ loadAlbums?: boolean;
+ size?: AssetMediaSize;
+};
+
+export class AssetManager {
+ isInitialized = $state(false);
+ isLoaded = $state(false);
+ loadError = $state(false);
+ asset: AssetResponseDto | undefined = $state();
+ preloadAssets: TimelineAsset[] = $state([]);
+ albums: AlbumResponseDto[] = $state([]);
+
+ cacheKey: string | null = $derived(this.asset?.thumbhash ?? null);
+
+ url: string | undefined = $derived.by(() => {
+ if (this.asset) {
+ return this.#getAssetUrl(toTimelineAsset(this.asset!));
+ }
+ });
+
+ showAssetViewer: boolean = $state(false);
+ gridScrollTarget: AssetGridRouteSearchParams | undefined = $state();
+ zoomImageState: ZoomImageWheelState | undefined = $state();
+
+ initTask = new CancellableTask(
+ () => (this.isInitialized = true),
+ () => {
+ this.asset = undefined;
+ this.preloadAssets = [];
+ this.albums = [];
+ this.isInitialized = false;
+ },
+ () => void 0,
+ );
+
+ static #INIT_OPTIONS = {};
+ #options: AssetManagerOptions = AssetManager.#INIT_OPTIONS;
+
+ constructor() {}
+
+ async #initializeAsset() {
+ if (this.#options.assetId) {
+ const assetResponse = await getAssetInfo({ id: this.#options.assetId, key: authManager.key });
+ if (!assetResponse) {
+ return;
+ }
+ this.asset = assetResponse;
+ } else {
+ throw new Error('The assetId in required in options.');
+ }
+
+ // TODO: Preload assets.
+
+ if (this.#options.loadAlbums ?? true) {
+ const albumsResponse = await getAllAlbums({ assetId: this.#options.assetId });
+ if (!albumsResponse) {
+ return;
+ }
+ this.albums = albumsResponse;
+ }
+ }
+
+ async updateOptions(options: AssetManagerOptions) {
+ if (this.#options !== AssetManager.#INIT_OPTIONS && isEqual(this.#options, options)) {
+ return;
+ }
+ await this.initTask.reset();
+ await this.#init(options);
+ }
+
+ #checkOptions() {
+ this.#options.size = AssetMediaSize.Original;
+
+ if (!this.asset || !this.zoomImageState) {
+ return;
+ }
+
+ if (this.asset.originalMimeType === 'image/gif' || this.zoomImageState.currentZoom > 1) {
+ // TODO: use original image forcely and according to the setting.
+ }
+ }
+
+ async #init(options: AssetManagerOptions) {
+ this.isInitialized = false;
+ this.asset = undefined;
+ this.preloadAssets = [];
+ this.albums = [];
+ await this.initTask.execute(async () => {
+ this.#options = options;
+ await this.#initializeAsset();
+ this.#checkOptions();
+ }, true);
+ }
+
+ public destroy() {
+ this.isInitialized = false;
+ }
+
+ async refreshAlbums() {}
+
+ async refreshAsset() {}
+
+ #preload() {
+ for (const preloadAsset of this.preloadAssets) {
+ if (preloadAsset.isImage) {
+ let img = new Image();
+ const preloadUrl = this.#getAssetUrl(preloadAsset);
+ if (preloadUrl) {
+ img.src = preloadUrl;
+ } else {
+ throw new Error('AssetManager is not initialized.');
+ }
+ }
+ }
+ }
+
+ #getAssetUrl(asset: TimelineAsset) {
+ if (!this.asset) {
+ return;
+ }
+
+ let path = undefined;
+ const searchParameters = new URLSearchParams();
+ if (authManager.key) {
+ searchParameters.set('key', authManager.key);
+ }
+ if (this.cacheKey) {
+ searchParameters.set('c', this.cacheKey);
+ }
+
+ switch (this.#options.size) {
+ case AssetMediaSize.Original: {
+ path = getAssetOriginalPath(this.asset.id);
+ break;
+ }
+ case AssetMediaSize.Fullsize:
+ case AssetMediaSize.Thumbnail:
+ case AssetMediaSize.Preview: {
+ path = getAssetThumbnailPath(this.asset.id);
+ break;
+ }
+ case AssetMediaSize.Playback: {
+ path = getAssetPlaybackPath(this.asset.id);
+ break;
+ }
+ default:
+ // TODO: default AssetMediaSize
+ }
+
+ return getBaseUrl() + path + '?' + searchParameters.toString();
+ }
+
+ get isOriginalImage() {
+ return this.#options.size === AssetMediaSize.Original || this.#options.size === AssetMediaSize.Fullsize;
+ }
+}
+
+// const getAssetUrl = (id: string, targetSize: AssetMediaSize | 'original', cacheKey: string | null) => {
+// if (sharedLink && (!sharedLink.allowDownload || !sharedLink.showMetadata)) {
+// return getAssetThumbnailUrl({ id, size: AssetMediaSize.Preview, cacheKey });
+// }
+
+// return targetSize === 'original'
+// ? getAssetOriginalUrl({ id, cacheKey })
+// : getAssetThumbnailUrl({ id, size: targetSize, cacheKey });
+// };
+
+// $effect(() => {
+// if ($alwaysLoadOriginalFile || forceUseOriginal || originalImageLoaded) {
+// assetManager.updateOptions({
+// size: isWebCompatibleImage(asset) ? AssetMediaSize.Original : AssetMediaSize.Fullsize,
+// });
+// }
+// assetManager.updateOptions({ size: AssetMediaSize.Preview });
+// });
diff --git a/web/src/lib/managers/asset-manager/internal/load-support.svelte.ts b/web/src/lib/managers/asset-manager/internal/load-support.svelte.ts
new file mode 100644
index 0000000000..eebf28e120
--- /dev/null
+++ b/web/src/lib/managers/asset-manager/internal/load-support.svelte.ts
@@ -0,0 +1,17 @@
+import type { AssetManager } from '$lib/managers/asset-manager/asset-manager.svelte';
+import { cancelImageUrl } from '$lib/utils/sw-messaging';
+
+export function mediaLoaded(assetManager: AssetManager) {
+ assetManager.isLoaded = true;
+}
+
+export function mediaLoadError(assetManager: AssetManager) {
+ assetManager.isLoaded = assetManager.loadError = true;
+}
+
+export function cancelImageLoad(assetManager: AssetManager) {
+ if (assetManager.url) {
+ cancelImageUrl(assetManager.url);
+ }
+ assetManager.isLoaded = assetManager.loadError = false;
+}
diff --git a/web/src/lib/managers/asset-manager/internal/zoom-support.svelte.ts b/web/src/lib/managers/asset-manager/internal/zoom-support.svelte.ts
new file mode 100644
index 0000000000..f07959dd15
--- /dev/null
+++ b/web/src/lib/managers/asset-manager/internal/zoom-support.svelte.ts
@@ -0,0 +1,24 @@
+import type { AssetManager } from '$lib/managers/asset-manager/asset-manager.svelte';
+import { useZoomImageWheel } from '@zoom-image/svelte';
+import type { Attachment } from 'svelte/attachments';
+
+export function zoomImageAttachment(assetManager: AssetManager): Attachment {
+ return (element) => {
+ let zoomImage = $derived(assetManager.zoomImageState);
+ const { createZoomImage, zoomImageState, setZoomImageState } = useZoomImageWheel();
+
+ createZoomImage(element, { maxZoom: 10 });
+
+ $effect(() => {
+ if (zoomImage) {
+ setZoomImageState(zoomImage);
+ }
+ });
+
+ const unsubscribe = zoomImageState.subscribe((value) => (zoomImage = value));
+
+ return () => {
+ unsubscribe();
+ };
+ };
+}
diff --git a/web/src/lib/stores/zoom-image.store.ts b/web/src/lib/stores/zoom-image.store.ts
deleted file mode 100644
index 2c6ee18972..0000000000
--- a/web/src/lib/stores/zoom-image.store.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import type { ZoomImageWheelState } from '@zoom-image/core';
-import { writable } from 'svelte/store';
-
-export const photoZoomState = writable();
diff --git a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte
index fe9d3bd718..e0942fed5a 100644
--- a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte
+++ b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte
@@ -34,7 +34,7 @@
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
import { AlbumPageViewMode, AppRoute } from '$lib/constants';
import { activityManager } from '$lib/managers/activity-manager.svelte';
- import { AssetManager } from '$lib/managers/asset-manager.svelte';
+ import { AssetManager } from '$lib/managers/asset-manager/asset-manager.svelte';
import { modalManager } from '$lib/managers/modal-manager.svelte';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
diff --git a/web/src/routes/(user)/archive/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/archive/[[photos=photos]]/[[assetId=id]]/+page.svelte
index 8d9a2fca3f..2ae67da6d4 100644
--- a/web/src/routes/(user)/archive/[[photos=photos]]/[[assetId=id]]/+page.svelte
+++ b/web/src/routes/(user)/archive/[[photos=photos]]/[[assetId=id]]/+page.svelte
@@ -14,7 +14,7 @@
import { AssetAction } from '$lib/constants';
import SetVisibilityAction from '$lib/components/photos-page/actions/set-visibility-action.svelte';
- import { AssetManager } from '$lib/managers/asset-manager.svelte';
+ import { AssetManager } from '$lib/managers/asset-manager/asset-manager.svelte';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { AssetVisibility } from '@immich/sdk';
diff --git a/web/src/routes/(user)/favorites/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/favorites/[[photos=photos]]/[[assetId=id]]/+page.svelte
index 3684fa5599..9f265323c8 100644
--- a/web/src/routes/(user)/favorites/[[photos=photos]]/[[assetId=id]]/+page.svelte
+++ b/web/src/routes/(user)/favorites/[[photos=photos]]/[[assetId=id]]/+page.svelte
@@ -17,7 +17,7 @@
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import { AssetAction } from '$lib/constants';
- import { AssetManager } from '$lib/managers/asset-manager.svelte';
+ import { AssetManager } from '$lib/managers/asset-manager/asset-manager.svelte';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { preferences } from '$lib/stores/user.store';
diff --git a/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte
index 3fdd7268b4..896bb00391 100644
--- a/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte
+++ b/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte
@@ -32,7 +32,7 @@
import { mdiDotsVertical, mdiFolder, mdiFolderHome, mdiFolderOutline, mdiPlus, mdiSelectAll } from '@mdi/js';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
- import { AssetManager } from '$lib/managers/asset-manager.svelte';
+ import { AssetManager } from '$lib/managers/asset-manager/asset-manager.svelte';
import { onDestroy } from 'svelte';
interface Props {
diff --git a/web/src/routes/(user)/locked/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/locked/[[photos=photos]]/[[assetId=id]]/+page.svelte
index 8a4346bf8d..b2e471ffa8 100644
--- a/web/src/routes/(user)/locked/[[photos=photos]]/[[assetId=id]]/+page.svelte
+++ b/web/src/routes/(user)/locked/[[photos=photos]]/[[assetId=id]]/+page.svelte
@@ -12,7 +12,7 @@
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import { AppRoute, AssetAction } from '$lib/constants';
- import { AssetManager } from '$lib/managers/asset-manager.svelte';
+ import { AssetManager } from '$lib/managers/asset-manager/asset-manager.svelte';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { AssetVisibility, lockAuthSession } from '@immich/sdk';
diff --git a/web/src/routes/(user)/map/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/map/[[photos=photos]]/[[assetId=id]]/+page.svelte
index 24ddd09665..c77ceb010c 100644
--- a/web/src/routes/(user)/map/[[photos=photos]]/[[assetId=id]]/+page.svelte
+++ b/web/src/routes/(user)/map/[[photos=photos]]/[[assetId=id]]/+page.svelte
@@ -4,7 +4,7 @@
import Map from '$lib/components/shared-components/map/map.svelte';
import Portal from '$lib/components/shared-components/portal/portal.svelte';
import { AppRoute } from '$lib/constants';
- import { AssetManager } from '$lib/managers/asset-manager.svelte';
+ import { AssetManager } from '$lib/managers/asset-manager/asset-manager.svelte';
import { featureFlags } from '$lib/stores/server-config.store';
import { handlePromiseError } from '$lib/utils';
import { navigate } from '$lib/utils/navigation';
diff --git a/web/src/routes/(user)/memory/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/memory/[[photos=photos]]/[[assetId=id]]/+page.svelte
index 1503bfa7fe..9c169a676c 100644
--- a/web/src/routes/(user)/memory/[[photos=photos]]/[[assetId=id]]/+page.svelte
+++ b/web/src/routes/(user)/memory/[[photos=photos]]/[[assetId=id]]/+page.svelte
@@ -1,6 +1,6 @@