fix(web): suppress auto-play errors (#21282)

This commit is contained in:
Jason Rasmussen 2025-08-25 23:51:56 -04:00 committed by GitHub
parent 8f1b505ba0
commit 0d0bb0e2d9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -7,12 +7,10 @@
import { isFaceEditMode } from '$lib/stores/face-edit.svelte'; import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
import { loopVideo as loopVideoPreference, videoViewerMuted, videoViewerVolume } from '$lib/stores/preferences.store'; import { loopVideo as loopVideoPreference, videoViewerMuted, videoViewerVolume } from '$lib/stores/preferences.store';
import { getAssetPlaybackUrl, getAssetThumbnailUrl } from '$lib/utils'; import { getAssetPlaybackUrl, getAssetThumbnailUrl } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { AssetMediaSize } from '@immich/sdk'; import { AssetMediaSize } from '@immich/sdk';
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
import type { SwipeCustomEvent } from 'svelte-gestures'; import type { SwipeCustomEvent } from 'svelte-gestures';
import { swipe } from 'svelte-gestures'; import { swipe } from 'svelte-gestures';
import { t } from 'svelte-i18n';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
interface Props { interface Props {
@ -40,7 +38,6 @@
let videoPlayer: HTMLVideoElement | undefined = $state(); let videoPlayer: HTMLVideoElement | undefined = $state();
let isLoading = $state(true); let isLoading = $state(true);
let assetFileUrl = $state(''); let assetFileUrl = $state('');
let forceMuted = $state(false);
let isScrubbing = $state(false); let isScrubbing = $state(false);
let showVideo = $state(false); let showVideo = $state(false);
@ -49,7 +46,6 @@
showVideo = true; showVideo = true;
assetFileUrl = getAssetPlaybackUrl({ id: assetId, cacheKey }); assetFileUrl = getAssetPlaybackUrl({ id: assetId, cacheKey });
if (videoPlayer) { if (videoPlayer) {
forceMuted = false;
videoPlayer.load(); videoPlayer.load();
} }
}); });
@ -67,23 +63,27 @@
onVideoStarted(); onVideoStarted();
} }
} catch (error) { } catch (error) {
if (error instanceof DOMException && error.name === 'NotAllowedError' && !forceMuted) { if (error instanceof DOMException && error.name === 'NotAllowedError') {
await tryForceMutedPlay(video); await tryForceMutedPlay(video);
return; return;
} }
handleError(error, $t('errors.unable_to_play_video')); // auto-play failed
} finally { } finally {
isLoading = false; isLoading = false;
} }
}; };
const tryForceMutedPlay = async (video: HTMLVideoElement) => { const tryForceMutedPlay = async (video: HTMLVideoElement) => {
if (video.muted) {
return;
}
try { try {
video.muted = true; video.muted = true;
await handleCanPlay(video); await handleCanPlay(video);
} catch (error) { } catch {
handleError(error, $t('errors.unable_to_play_video')); // muted auto-play failed
} }
}; };
@ -134,18 +134,14 @@
onswipe={onSwipe} onswipe={onSwipe}
oncanplay={(e) => handleCanPlay(e.currentTarget)} oncanplay={(e) => handleCanPlay(e.currentTarget)}
onended={onVideoEnded} onended={onVideoEnded}
onvolumechange={(e) => { onvolumechange={(e) => ($videoViewerMuted = e.currentTarget.muted)}
if (!forceMuted) {
$videoViewerMuted = e.currentTarget.muted;
}
}}
onseeking={() => (isScrubbing = true)} onseeking={() => (isScrubbing = true)}
onseeked={() => (isScrubbing = false)} onseeked={() => (isScrubbing = false)}
onplaying={(e) => { onplaying={(e) => {
e.currentTarget.focus(); e.currentTarget.focus();
}} }}
onclose={() => onClose()} onclose={() => onClose()}
muted={forceMuted || $videoViewerMuted} muted={$videoViewerMuted}
bind:volume={$videoViewerVolume} bind:volume={$videoViewerVolume}
poster={getAssetThumbnailUrl({ id: assetId, size: AssetMediaSize.Preview, cacheKey })} poster={getAssetThumbnailUrl({ id: assetId, size: AssetMediaSize.Preview, cacheKey })}
src={assetFileUrl} src={assetFileUrl}