mirror of
https://github.com/immich-app/immich.git
synced 2025-05-31 12:15:47 -04:00
feat: resolution selection and default preview playback for 360° panorama videos (#15747)
* original/preview switching in photo-sphere-viewer 1. default to preview in photo-sphere-viewer video mode 2. install and integrate @photo-sphere-viewer/settings-plugin & @photo-sphere-viewer/resolution-plugin * fix lint errors
This commit is contained in:
parent
92dff839d0
commit
08db77db23
21
web/package-lock.json
generated
21
web/package-lock.json
generated
@ -16,6 +16,8 @@
|
|||||||
"@mdi/js": "^7.4.47",
|
"@mdi/js": "^7.4.47",
|
||||||
"@photo-sphere-viewer/core": "^5.11.5",
|
"@photo-sphere-viewer/core": "^5.11.5",
|
||||||
"@photo-sphere-viewer/equirectangular-video-adapter": "^5.11.5",
|
"@photo-sphere-viewer/equirectangular-video-adapter": "^5.11.5",
|
||||||
|
"@photo-sphere-viewer/resolution-plugin": "^5.11.5",
|
||||||
|
"@photo-sphere-viewer/settings-plugin": "^5.11.5",
|
||||||
"@photo-sphere-viewer/video-plugin": "^5.11.5",
|
"@photo-sphere-viewer/video-plugin": "^5.11.5",
|
||||||
"@zoom-image/svelte": "^0.3.0",
|
"@zoom-image/svelte": "^0.3.0",
|
||||||
"dom-to-image": "^2.6.0",
|
"dom-to-image": "^2.6.0",
|
||||||
@ -1669,6 +1671,25 @@
|
|||||||
"@photo-sphere-viewer/video-plugin": "5.11.5"
|
"@photo-sphere-viewer/video-plugin": "5.11.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@photo-sphere-viewer/resolution-plugin": {
|
||||||
|
"version": "5.11.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@photo-sphere-viewer/resolution-plugin/-/resolution-plugin-5.11.5.tgz",
|
||||||
|
"integrity": "sha512-Dbvp5bBtozD3IWt1Q0wORVaZBcB1bV9xUeoOS9A7F7b3EkQ2pkC5/jot/1AyM4wtU5wJ63NWHskQ1d7m6WWazQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@photo-sphere-viewer/core": "5.11.5",
|
||||||
|
"@photo-sphere-viewer/settings-plugin": "5.11.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@photo-sphere-viewer/settings-plugin": {
|
||||||
|
"version": "5.11.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@photo-sphere-viewer/settings-plugin/-/settings-plugin-5.11.5.tgz",
|
||||||
|
"integrity": "sha512-ZgYaWjiBMhsoRH5ddW3h+v4J4LPmofsT7BBRq5UCssWw2Fsrvv7mFFRi4UbZ1qzeKmvNUOr8BaFQgX1ZLvUWfQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@photo-sphere-viewer/core": "5.11.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@photo-sphere-viewer/video-plugin": {
|
"node_modules/@photo-sphere-viewer/video-plugin": {
|
||||||
"version": "5.11.5",
|
"version": "5.11.5",
|
||||||
"resolved": "https://registry.npmjs.org/@photo-sphere-viewer/video-plugin/-/video-plugin-5.11.5.tgz",
|
"resolved": "https://registry.npmjs.org/@photo-sphere-viewer/video-plugin/-/video-plugin-5.11.5.tgz",
|
||||||
|
@ -72,6 +72,8 @@
|
|||||||
"@mdi/js": "^7.4.47",
|
"@mdi/js": "^7.4.47",
|
||||||
"@photo-sphere-viewer/core": "^5.11.5",
|
"@photo-sphere-viewer/core": "^5.11.5",
|
||||||
"@photo-sphere-viewer/equirectangular-video-adapter": "^5.11.5",
|
"@photo-sphere-viewer/equirectangular-video-adapter": "^5.11.5",
|
||||||
|
"@photo-sphere-viewer/resolution-plugin": "^5.11.5",
|
||||||
|
"@photo-sphere-viewer/settings-plugin": "^5.11.5",
|
||||||
"@photo-sphere-viewer/video-plugin": "^5.11.5",
|
"@photo-sphere-viewer/video-plugin": "^5.11.5",
|
||||||
"@zoom-image/svelte": "^0.3.0",
|
"@zoom-image/svelte": "^0.3.0",
|
||||||
"dom-to-image": "^2.6.0",
|
"dom-to-image": "^2.6.0",
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
{:then [data, { default: PhotoSphereViewer }]}
|
{:then [data, { default: PhotoSphereViewer }]}
|
||||||
<PhotoSphereViewer
|
<PhotoSphereViewer
|
||||||
panorama={data}
|
panorama={data}
|
||||||
originalImageUrl={isWebCompatibleImage(asset) ? getAssetOriginalUrl(asset.id) : undefined}
|
originalPanorama={isWebCompatibleImage(asset) ? getAssetOriginalUrl(asset.id) : undefined}
|
||||||
/>
|
/>
|
||||||
{:catch}
|
{:catch}
|
||||||
{$t('errors.failed_to_load_asset')}
|
{$t('errors.failed_to_load_asset')}
|
||||||
|
@ -7,18 +7,21 @@
|
|||||||
type AdapterConstructor,
|
type AdapterConstructor,
|
||||||
type PluginConstructor,
|
type PluginConstructor,
|
||||||
} from '@photo-sphere-viewer/core';
|
} from '@photo-sphere-viewer/core';
|
||||||
|
import { SettingsPlugin } from '@photo-sphere-viewer/settings-plugin';
|
||||||
|
import { ResolutionPlugin } from '@photo-sphere-viewer/resolution-plugin';
|
||||||
import '@photo-sphere-viewer/core/index.css';
|
import '@photo-sphere-viewer/core/index.css';
|
||||||
|
import '@photo-sphere-viewer/settings-plugin/index.css';
|
||||||
import { onDestroy, onMount } from 'svelte';
|
import { onDestroy, onMount } from 'svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
panorama: string | { source: string };
|
panorama: string | { source: string };
|
||||||
originalImageUrl?: string;
|
originalPanorama?: string | { source: string };
|
||||||
adapter?: AdapterConstructor | [AdapterConstructor, unknown];
|
adapter?: AdapterConstructor | [AdapterConstructor, unknown];
|
||||||
plugins?: (PluginConstructor | [PluginConstructor, unknown])[];
|
plugins?: (PluginConstructor | [PluginConstructor, unknown])[];
|
||||||
navbar?: boolean;
|
navbar?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { panorama, originalImageUrl, adapter = EquirectangularAdapter, plugins = [], navbar = false }: Props = $props();
|
let { panorama, originalPanorama, adapter = EquirectangularAdapter, plugins = [], navbar = false }: Props = $props();
|
||||||
|
|
||||||
let container: HTMLDivElement | undefined = $state();
|
let container: HTMLDivElement | undefined = $state();
|
||||||
let viewer: Viewer;
|
let viewer: Viewer;
|
||||||
@ -30,9 +33,33 @@
|
|||||||
|
|
||||||
viewer = new Viewer({
|
viewer = new Viewer({
|
||||||
adapter,
|
adapter,
|
||||||
plugins,
|
plugins: [
|
||||||
|
SettingsPlugin,
|
||||||
|
[
|
||||||
|
ResolutionPlugin,
|
||||||
|
{
|
||||||
|
defaultResolution: $alwaysLoadOriginalFile && originalPanorama ? 'original' : 'default',
|
||||||
|
resolutions: [
|
||||||
|
{
|
||||||
|
id: 'default',
|
||||||
|
label: 'Default',
|
||||||
|
panorama,
|
||||||
|
},
|
||||||
|
...(originalPanorama
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
id: 'original',
|
||||||
|
label: 'Original',
|
||||||
|
panorama: originalPanorama,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
...plugins,
|
||||||
|
],
|
||||||
container,
|
container,
|
||||||
panorama,
|
|
||||||
touchmoveTwoFingers: false,
|
touchmoveTwoFingers: false,
|
||||||
mousewheelCtrlKey: false,
|
mousewheelCtrlKey: false,
|
||||||
navbar,
|
navbar,
|
||||||
@ -40,15 +67,14 @@
|
|||||||
maxFov: 120,
|
maxFov: 120,
|
||||||
fisheye: false,
|
fisheye: false,
|
||||||
});
|
});
|
||||||
|
const resolutionPlugin = viewer.getPlugin(ResolutionPlugin) as ResolutionPlugin;
|
||||||
|
|
||||||
if (originalImageUrl && !$alwaysLoadOriginalFile) {
|
if (originalPanorama && !$alwaysLoadOriginalFile) {
|
||||||
const zoomHandler = ({ zoomLevel }: events.ZoomUpdatedEvent) => {
|
const zoomHandler = ({ zoomLevel }: events.ZoomUpdatedEvent) => {
|
||||||
// zoomLevel range: [0, 100]
|
// zoomLevel range: [0, 100]
|
||||||
if (Math.round(zoomLevel) >= 75) {
|
if (Math.round(zoomLevel) >= 75) {
|
||||||
// Replace the preview with the original
|
// Replace the preview with the original
|
||||||
viewer.setPanorama(originalImageUrl, { showLoader: false, speed: 150 }).catch(() => {
|
void resolutionPlugin.setResolution('original');
|
||||||
viewer.setPanorama(panorama, { showLoader: false, speed: 0 }).catch(() => {});
|
|
||||||
});
|
|
||||||
viewer.removeEventListener(events.ZoomUpdatedEvent.type, zoomHandler);
|
viewer.removeEventListener(events.ZoomUpdatedEvent.type, zoomHandler);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getAssetOriginalUrl } from '$lib/utils';
|
import { getAssetPlaybackUrl, getAssetOriginalUrl } from '$lib/utils';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
|
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
@ -22,7 +22,13 @@
|
|||||||
{#await modules}
|
{#await modules}
|
||||||
<LoadingSpinner />
|
<LoadingSpinner />
|
||||||
{:then [PhotoSphereViewer, adapter, videoPlugin]}
|
{:then [PhotoSphereViewer, adapter, videoPlugin]}
|
||||||
<PhotoSphereViewer panorama={{ source: getAssetOriginalUrl(assetId) }} plugins={[videoPlugin]} {adapter} navbar />
|
<PhotoSphereViewer
|
||||||
|
panorama={{ source: getAssetPlaybackUrl(assetId) }}
|
||||||
|
originalPanorama={{ source: getAssetOriginalUrl(assetId) }}
|
||||||
|
plugins={[videoPlugin]}
|
||||||
|
{adapter}
|
||||||
|
navbar
|
||||||
|
/>
|
||||||
{:catch}
|
{:catch}
|
||||||
{$t('errors.failed_to_load_asset')}
|
{$t('errors.failed_to_load_asset')}
|
||||||
{/await}
|
{/await}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user