mirror of
https://github.com/immich-app/immich
synced 2026-08-29 13:15:45 +00:00
fix(web): face editor coordinates on a not-yet-loaded video (#31083)
This commit is contained in:
parent
c1a88dd9a3
commit
1a8fcf1b9f
3 changed files with 27 additions and 2 deletions
|
|
@ -76,6 +76,7 @@
|
|||
|
||||
let videoPlayer: HTMLVideoElement | undefined = $state();
|
||||
let isLoading = $state(true);
|
||||
let hasLoadedMetadata = $state(false);
|
||||
let assetFileUrl = $derived.by(() => {
|
||||
if (featureFlagsManager.value.realtimeTranscoding) {
|
||||
return getAssetHlsUrl(assetId);
|
||||
|
|
@ -241,6 +242,7 @@
|
|||
|
||||
$effect(() => {
|
||||
// reactive on `assetFileUrl` changes
|
||||
hasLoadedMetadata = false;
|
||||
if (videoPlayer && assetFileUrl) {
|
||||
hasFocused = false;
|
||||
rebuildCount = 0;
|
||||
|
|
@ -385,6 +387,7 @@
|
|||
{...useSwipe(onSwipe)}
|
||||
class="h-full object-contain"
|
||||
oncanplay={(e: Event) => handleCanPlay(e.currentTarget as HTMLVideoElement)}
|
||||
onloadedmetadata={() => (hasLoadedMetadata = true)}
|
||||
onended={onVideoEnded}
|
||||
onseeking={onSeeking}
|
||||
onplaying={(e: Event) => {
|
||||
|
|
@ -410,6 +413,7 @@
|
|||
{...useSwipe(onSwipe)}
|
||||
class="h-full object-contain"
|
||||
oncanplay={(e) => handleCanPlay(e.currentTarget)}
|
||||
onloadedmetadata={() => (hasLoadedMetadata = true)}
|
||||
onended={onVideoEnded}
|
||||
onseeking={onSeeking}
|
||||
onplaying={(e) => {
|
||||
|
|
@ -489,7 +493,7 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
{#if assetViewerManager.isFaceEditMode && videoPlayer}
|
||||
{#if assetViewerManager.isFaceEditMode && videoPlayer && hasLoadedMetadata}
|
||||
<FaceEditor htmlElement={videoPlayer} {containerWidth} {containerHeight} {assetId} />
|
||||
{/if}
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,12 @@ export type ContentMetrics = {
|
|||
offsetY: number;
|
||||
};
|
||||
|
||||
const isMeasurable = (dimensions: Size) => dimensions.width > 0 && dimensions.height > 0;
|
||||
|
||||
export const scaleToCover = (dimensions: Size, container: Size): Size => {
|
||||
if (!isMeasurable(dimensions)) {
|
||||
return { width: 0, height: 0 };
|
||||
}
|
||||
const scaleX = container.width / dimensions.width;
|
||||
const scaleY = container.height / dimensions.height;
|
||||
const scale = Math.max(scaleX, scaleY);
|
||||
|
|
@ -40,6 +45,9 @@ export const scaleToCover = (dimensions: Size, container: Size): Size => {
|
|||
};
|
||||
|
||||
export const scaleToFit = (dimensions: Size, container: Size): Size => {
|
||||
if (!isMeasurable(dimensions)) {
|
||||
return { width: 0, height: 0 };
|
||||
}
|
||||
const scaleX = container.width / dimensions.width;
|
||||
const scaleY = container.height / dimensions.height;
|
||||
const scale = Math.min(scaleX, scaleY);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { scaleToFit } from '$lib/utils/container-utils';
|
||||
import { scaleToCover, scaleToFit } from '$lib/utils/container-utils';
|
||||
|
||||
describe('scaleToFit', () => {
|
||||
const tests = [
|
||||
|
|
@ -51,4 +51,17 @@ describe('scaleToFit', () => {
|
|||
expect(scaleToFit(dimensions, container)).toEqual(expected);
|
||||
});
|
||||
}
|
||||
|
||||
const unmeasurable = [
|
||||
{ name: 'zero width and height', dimensions: { width: 0, height: 0 } },
|
||||
{ name: 'zero width', dimensions: { width: 0, height: 1000 } },
|
||||
{ name: 'zero height', dimensions: { width: 1000, height: 0 } },
|
||||
];
|
||||
|
||||
for (const { name, dimensions } of unmeasurable) {
|
||||
it(`should return an empty size for ${name}`, () => {
|
||||
expect(scaleToFit(dimensions, { width: 500, height: 500 })).toEqual({ width: 0, height: 0 });
|
||||
expect(scaleToCover(dimensions, { width: 500, height: 500 })).toEqual({ width: 0, height: 0 });
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue