From e8b717ee79844828dff70eae7b2dea7ffc069a87 Mon Sep 17 00:00:00 2001 From: mertalev <101130780+mertalev@users.noreply.github.com> Date: Tue, 21 Apr 2026 15:28:16 -0400 Subject: [PATCH] web changes --- .../ui/generators/timeline/model-objects.ts | 8 ++- .../ui/generators/timeline/timeline-config.ts | 2 +- .../assets/thumbnail/Thumbnail.svelte | 3 +- .../lib/managers/timeline-manager/types.ts | 2 +- web/src/lib/utils/date-time.spec.ts | 50 +------------------ web/src/lib/utils/date-time.ts | 14 +----- .../[[assetId=id]]/MemoryViewer.svelte | 16 ++---- 7 files changed, 15 insertions(+), 80 deletions(-) diff --git a/e2e/src/ui/generators/timeline/model-objects.ts b/e2e/src/ui/generators/timeline/model-objects.ts index e300de1161..f5654afd5e 100644 --- a/e2e/src/ui/generators/timeline/model-objects.ts +++ b/e2e/src/ui/generators/timeline/model-objects.ts @@ -32,8 +32,12 @@ export function generateThumbhash(rng: SeededRandom): string { return Array.from({ length: 10 }, () => rng.nextInt(0, 256).toString(16).padStart(2, '0')).join(''); } -export function generateDuration(rng: SeededRandom): string { - return `${rng.nextInt(GENERATION_CONSTANTS.MIN_VIDEO_DURATION_SECONDS, GENERATION_CONSTANTS.MAX_VIDEO_DURATION_SECONDS)}.${rng.nextInt(0, 1000).toString().padStart(3, '0')}`; +export function generateDuration(rng: SeededRandom): number { + return ( + rng.nextInt(GENERATION_CONSTANTS.MIN_VIDEO_DURATION_SECONDS, GENERATION_CONSTANTS.MAX_VIDEO_DURATION_SECONDS) * + 1000 + + rng.nextInt(0, 1000) + ); } export function generateUUID(): string { diff --git a/e2e/src/ui/generators/timeline/timeline-config.ts b/e2e/src/ui/generators/timeline/timeline-config.ts index 992480eef9..4dea2f4f78 100644 --- a/e2e/src/ui/generators/timeline/timeline-config.ts +++ b/e2e/src/ui/generators/timeline/timeline-config.ts @@ -43,7 +43,7 @@ export type MockTimelineAsset = { isTrashed: boolean; isVideo: boolean; isImage: boolean; - duration: string | null; + duration: number | null; projectionType: string | null; livePhotoVideoId: string | null; city: string | null; diff --git a/web/src/lib/components/assets/thumbnail/Thumbnail.svelte b/web/src/lib/components/assets/thumbnail/Thumbnail.svelte index 99608eabcc..63e93169bb 100644 --- a/web/src/lib/components/assets/thumbnail/Thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/Thumbnail.svelte @@ -5,7 +5,6 @@ import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte'; import { locale, playVideoThumbnailOnHover } from '$lib/stores/preferences.store'; import { getAssetMediaUrl, getAssetPlaybackUrl } from '$lib/utils'; - import { timeToSeconds } from '$lib/utils/date-time'; import { moveFocus } from '$lib/utils/focus-util'; import { currentUrlReplaceAssetId } from '$lib/utils/navigation'; import { getAltText } from '$lib/utils/thumbnail-util'; @@ -274,7 +273,7 @@ url={getAssetPlaybackUrl({ id: asset.id, cacheKey: asset.thumbhash })} enablePlayback={mouseOver && $playVideoThumbnailOnHover} curve={selected} - durationInSeconds={asset.duration ? timeToSeconds(asset.duration) : 0} + durationInSeconds={asset.duration ? asset.duration / 1000 : 0} playbackOnIconHover={!$playVideoThumbnailOnHover} /> diff --git a/web/src/lib/managers/timeline-manager/types.ts b/web/src/lib/managers/timeline-manager/types.ts index 1437e5701b..0e85802900 100644 --- a/web/src/lib/managers/timeline-manager/types.ts +++ b/web/src/lib/managers/timeline-manager/types.ts @@ -29,7 +29,7 @@ export type TimelineAsset = { isVideo: boolean; isImage: boolean; stack: AssetStackResponseDto | null; - duration: string | null; + duration: number | null; projectionType: string | null; livePhotoVideoId: string | null; city: string | null; diff --git a/web/src/lib/utils/date-time.spec.ts b/web/src/lib/utils/date-time.spec.ts index 830d96d45c..f91a74c6b9 100644 --- a/web/src/lib/utils/date-time.spec.ts +++ b/web/src/lib/utils/date-time.spec.ts @@ -1,53 +1,5 @@ import { writable } from 'svelte/store'; -import { getAlbumDateRange, getShortDateRange, timeToSeconds } from './date-time'; - -describe('converting time to seconds', () => { - it('parses hh:mm:ss correctly', () => { - expect(timeToSeconds('01:02:03')).toBeCloseTo(3723); - }); - - it('parses hh:mm:ss.SSS correctly', () => { - expect(timeToSeconds('01:02:03.456')).toBeCloseTo(3723.456); - }); - - it('parses h:m:s.S correctly', () => { - expect(timeToSeconds('1:2:3.4')).toBe(0); // Non-standard format, Luxon returns NaN - }); - - it('parses hhh:mm:ss.SSS correctly', () => { - expect(timeToSeconds('100:02:03.456')).toBe(0); // Non-standard format, Luxon returns NaN - }); - - it('ignores ignores double milliseconds hh:mm:ss.SSS.SSSSSS', () => { - expect(timeToSeconds('01:02:03.456.123456')).toBe(0); // Non-standard format, Luxon returns NaN - }); - - // Test edge cases that can cause crashes - it('handles "0" string input', () => { - expect(timeToSeconds('0')).toBe(0); - }); - - it('handles empty string input', () => { - expect(timeToSeconds('')).toBe(0); - }); - - it('parses HH:MM format correctly', () => { - expect(timeToSeconds('01:02')).toBe(3720); // 1 hour 2 minutes = 3720 seconds - }); - - it('handles malformed time strings', () => { - expect(timeToSeconds('invalid')).toBe(0); - }); - - it('parses single hour format correctly', () => { - expect(timeToSeconds('01')).toBe(3600); // Luxon interprets "01" as 1 hour - }); - - it('handles time strings with invalid numbers', () => { - expect(timeToSeconds('aa:bb:cc')).toBe(0); - expect(timeToSeconds('01:bb:03')).toBe(0); - }); -}); +import { getAlbumDateRange, getShortDateRange } from './date-time'; describe('getShortDateRange', () => { beforeEach(() => { diff --git a/web/src/lib/utils/date-time.ts b/web/src/lib/utils/date-time.ts index f39697fa11..d06f92376b 100644 --- a/web/src/lib/utils/date-time.ts +++ b/web/src/lib/utils/date-time.ts @@ -1,20 +1,8 @@ -import { DateTime, Duration } from 'luxon'; +import { DateTime } from 'luxon'; import { get } from 'svelte/store'; import { dateFormats } from '$lib/constants'; import { locale } from '$lib/stores/preferences.store'; -/** - * Convert time like `01:02:03.456` to seconds. - */ -export function timeToSeconds(time: string) { - if (!time || time === '0') { - return 0; - } - - const seconds = Duration.fromISOTime(time).as('seconds'); - - return Number.isNaN(seconds) ? 0 : seconds; -} export function parseUtcDate(date: string) { return DateTime.fromISO(date, { zone: 'UTC' }).toUTC(); } diff --git a/web/src/routes/(user)/memory/[[photos=photos]]/[[assetId=id]]/MemoryViewer.svelte b/web/src/routes/(user)/memory/[[photos=photos]]/[[assetId=id]]/MemoryViewer.svelte index cd415fc704..f440207b26 100644 --- a/web/src/routes/(user)/memory/[[photos=photos]]/[[assetId=id]]/MemoryViewer.svelte +++ b/web/src/routes/(user)/memory/[[photos=photos]]/[[assetId=id]]/MemoryViewer.svelte @@ -95,18 +95,10 @@ }; const setProgressDuration = (asset: TimelineAsset) => { - if (asset.isVideo) { - const timeParts = asset.duration!.split(':').map(Number); - const durationInMilliseconds = (timeParts[0] * 3600 + timeParts[1] * 60 + timeParts[2]) * 1000; - progressBarController = new Tween(0, { - duration: (from: number, to: number) => (to ? durationInMilliseconds * (to - from) : 0), - }); - } else { - progressBarController = new Tween(0, { - duration: (from: number, to: number) => - to ? authManager.preferences.memories.duration * 1000 * (to - from) : 0, - }); - } + progressBarController = new Tween(0, { + duration: (from: number, to: number) => + to ? (asset.isVideo ? asset.duration! : authManager.preferences.memories.duration * 1000) * (to - from) : 0, + }); }; const handleNextAsset = () => handleNavigate(current?.next?.asset);