mirror of
https://github.com/immich-app/immich.git
synced 2025-10-26 04:33:39 +09:00
feat(web): load original videos (#20041)
* added user preference for always loading original video added ability to toggle between transcoded/original in the video viewer add fix to static check error * address PR comments * Update asset-viewer-nav-bar.svelte Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com> --------- Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com> Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
c73e3dacea
commit
f721a62776
@@ -1540,6 +1540,9 @@
|
||||
"play_memories": "Play memories",
|
||||
"play_motion_photo": "Play Motion Photo",
|
||||
"play_or_pause_video": "Play or pause video",
|
||||
"play_original_video": "Play original video",
|
||||
"play_original_video_setting_description": "Prefer playback of original videos rather than transcoded videos. If original asset is not compatible it may not playback correctly.",
|
||||
"play_transcoded_video": "Play transcoded video",
|
||||
"please_auth_to_access": "Please authenticate to access",
|
||||
"port": "Port",
|
||||
"preferences_settings_subtitle": "Manage the app's preferences",
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
mdiMagnifyPlusOutline,
|
||||
mdiPresentationPlay,
|
||||
mdiUpload,
|
||||
mdiVideoOutline,
|
||||
} from '@mdi/js';
|
||||
import type { Snippet } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
@@ -78,6 +79,8 @@
|
||||
// export let showEditorHandler: () => void;
|
||||
onClose: () => void;
|
||||
motionPhoto?: Snippet;
|
||||
playOriginalVideo: boolean;
|
||||
setPlayOriginalVideo: (value: boolean) => void;
|
||||
}
|
||||
|
||||
let {
|
||||
@@ -97,6 +100,8 @@
|
||||
onShowDetail,
|
||||
onClose,
|
||||
motionPhoto,
|
||||
playOriginalVideo = false,
|
||||
setPlayOriginalVideo,
|
||||
}: Props = $props();
|
||||
|
||||
const sharedLink = getSharedLink();
|
||||
@@ -245,6 +250,15 @@
|
||||
{#if !asset.isTrashed}
|
||||
<SetVisibilityAction asset={toTimelineAsset(asset)} {onAction} {preAction} />
|
||||
{/if}
|
||||
|
||||
{#if asset.type === AssetTypeEnum.Video}
|
||||
<MenuOption
|
||||
icon={mdiVideoOutline}
|
||||
onClick={() => setPlayOriginalVideo(!playOriginalVideo)}
|
||||
text={playOriginalVideo ? $t('play_transcoded_video') : $t('play_original_video')}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<hr />
|
||||
<MenuOption
|
||||
icon={mdiHeadSyncOutline}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import { closeEditorCofirm } from '$lib/stores/asset-editor.store';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
import { isShowDetail } from '$lib/stores/preferences.store';
|
||||
import { alwaysLoadOriginalVideo, isShowDetail } from '$lib/stores/preferences.store';
|
||||
import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
|
||||
import { user } from '$lib/stores/user.store';
|
||||
import { websocketEvents } from '$lib/stores/websocket';
|
||||
@@ -110,6 +110,11 @@
|
||||
let stack: StackResponseDto | null = $state(null);
|
||||
|
||||
let zoomToggle = $state(() => void 0);
|
||||
let playOriginalVideo = $state($alwaysLoadOriginalVideo);
|
||||
|
||||
const setPlayOriginalVideo = (value: boolean) => {
|
||||
playOriginalVideo = value;
|
||||
};
|
||||
|
||||
const refreshStack = async () => {
|
||||
if (authManager.isSharedLink) {
|
||||
@@ -410,6 +415,8 @@
|
||||
onPlaySlideshow={() => ($slideshowState = SlideshowState.PlaySlideshow)}
|
||||
onShowDetail={toggleDetailPanel}
|
||||
onClose={closeViewer}
|
||||
{playOriginalVideo}
|
||||
{setPlayOriginalVideo}
|
||||
>
|
||||
{#snippet motionPhoto()}
|
||||
<MotionPhotoAction
|
||||
@@ -465,6 +472,7 @@
|
||||
onClose={closeViewer}
|
||||
onVideoEnded={() => navigateAsset()}
|
||||
onVideoStarted={handleVideoStarted}
|
||||
{playOriginalVideo}
|
||||
/>
|
||||
{/if}
|
||||
{/key}
|
||||
@@ -480,6 +488,7 @@
|
||||
onPreviousAsset={() => navigateAsset('previous')}
|
||||
onNextAsset={() => navigateAsset('next')}
|
||||
onVideoEnded={() => (shouldPlayMotionPhoto = false)}
|
||||
{playOriginalVideo}
|
||||
/>
|
||||
{:else if asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR || (asset.originalPath && asset.originalPath
|
||||
.toLowerCase()
|
||||
@@ -510,6 +519,7 @@
|
||||
onClose={closeViewer}
|
||||
onVideoEnded={() => navigateAsset()}
|
||||
onVideoStarted={handleVideoStarted}
|
||||
{playOriginalVideo}
|
||||
/>
|
||||
{/if}
|
||||
{#if $slideshowState === SlideshowState.None && isShared && ((album && album.isActivityEnabled) || activityManager.commentCount > 0) && !activityManager.isLoading}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
videoViewerMuted,
|
||||
videoViewerVolume,
|
||||
} from '$lib/stores/preferences.store';
|
||||
import { getAssetPlaybackUrl, getAssetThumbnailUrl } from '$lib/utils';
|
||||
import { getAssetOriginalUrl, getAssetPlaybackUrl, getAssetThumbnailUrl } from '$lib/utils';
|
||||
import { AssetMediaSize } from '@immich/sdk';
|
||||
import { LoadingSpinner } from '@immich/ui';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
@@ -21,6 +21,7 @@
|
||||
assetId: string;
|
||||
loopVideo: boolean;
|
||||
cacheKey: string | null;
|
||||
playOriginalVideo: boolean;
|
||||
onPreviousAsset?: () => void;
|
||||
onNextAsset?: () => void;
|
||||
onVideoEnded?: () => void;
|
||||
@@ -32,6 +33,7 @@
|
||||
assetId,
|
||||
loopVideo,
|
||||
cacheKey,
|
||||
playOriginalVideo,
|
||||
onPreviousAsset = () => {},
|
||||
onNextAsset = () => {},
|
||||
onVideoEnded = () => {},
|
||||
@@ -48,7 +50,12 @@
|
||||
onMount(() => {
|
||||
// Show video after mount to ensure fading in.
|
||||
showVideo = true;
|
||||
assetFileUrl = getAssetPlaybackUrl({ id: assetId, cacheKey });
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
assetFileUrl = playOriginalVideo
|
||||
? getAssetOriginalUrl({ id: assetId, cacheKey })
|
||||
: getAssetPlaybackUrl({ id: assetId, cacheKey });
|
||||
if (videoPlayer) {
|
||||
videoPlayer.load();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { ProjectionType } from '$lib/constants';
|
||||
import VideoNativeViewer from '$lib/components/asset-viewer/video-native-viewer.svelte';
|
||||
import VideoPanoramaViewer from '$lib/components/asset-viewer/video-panorama-viewer.svelte';
|
||||
import { ProjectionType } from '$lib/constants';
|
||||
|
||||
interface Props {
|
||||
assetId: string;
|
||||
projectionType: string | null | undefined;
|
||||
cacheKey: string | null;
|
||||
loopVideo: boolean;
|
||||
playOriginalVideo: boolean;
|
||||
onClose?: () => void;
|
||||
onPreviousAsset?: () => void;
|
||||
onNextAsset?: () => void;
|
||||
@@ -20,6 +21,7 @@
|
||||
projectionType,
|
||||
cacheKey,
|
||||
loopVideo,
|
||||
playOriginalVideo,
|
||||
onPreviousAsset,
|
||||
onClose,
|
||||
onNextAsset,
|
||||
@@ -35,6 +37,7 @@
|
||||
{loopVideo}
|
||||
{cacheKey}
|
||||
{assetId}
|
||||
{playOriginalVideo}
|
||||
{onPreviousAsset}
|
||||
{onNextAsset}
|
||||
{onVideoEnded}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { themeManager } from '$lib/managers/theme-manager.svelte';
|
||||
import {
|
||||
alwaysLoadOriginalFile,
|
||||
alwaysLoadOriginalVideo,
|
||||
autoPlayVideo,
|
||||
locale,
|
||||
loopVideo,
|
||||
@@ -119,7 +120,13 @@
|
||||
<div class="ms-4">
|
||||
<SettingSwitch title={$t('loop_videos')} subtitle={$t('loop_videos_description')} bind:checked={$loopVideo} />
|
||||
</div>
|
||||
|
||||
<div class="ms-4">
|
||||
<SettingSwitch
|
||||
title={$t('play_original_video')}
|
||||
subtitle={$t('play_original_video_setting_description')}
|
||||
bind:checked={$alwaysLoadOriginalVideo}
|
||||
/>
|
||||
</div>
|
||||
<div class="ms-4">
|
||||
<SettingSwitch
|
||||
title={$t('permanent_deletion_warning')}
|
||||
|
||||
@@ -148,4 +148,6 @@ export const loopVideo = persisted<boolean>('loop-video', true, {});
|
||||
|
||||
export const autoPlayVideo = persisted<boolean>('auto-play-video', true, {});
|
||||
|
||||
export const alwaysLoadOriginalVideo = persisted<boolean>('always-load-original-video', false, {});
|
||||
|
||||
export const recentAlbumsDropdown = persisted<boolean>('recent-albums-open', true, {});
|
||||
|
||||
Reference in New Issue
Block a user