diff --git a/materialious/electron/package-lock.json b/materialious/electron/package-lock.json index fd23c2d2..67a84a7f 100644 --- a/materialious/electron/package-lock.json +++ b/materialious/electron/package-lock.json @@ -1,12 +1,12 @@ { "name": "Materialious", - "version": "1.13.16", + "version": "1.13.17", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Materialious", - "version": "1.13.16", + "version": "1.13.17", "license": "MIT", "dependencies": { "@capacitor-community/electron": "^5.0.0", diff --git a/materialious/electron/src/setup.ts b/materialious/electron/src/setup.ts index 6a3cb751..e9089d23 100644 --- a/materialious/electron/src/setup.ts +++ b/materialious/electron/src/setup.ts @@ -190,7 +190,6 @@ export class ElectronCapacitorApp { globalShortcut.register('Control+Shift+I', () => { this.MainWindow.webContents.toggleDevTools(); }); - // Security this.MainWindow.webContents.setWindowOpenHandler((details) => { shell.openExternal(details.url); diff --git a/materialious/src/lib/components/Player.svelte b/materialious/src/lib/components/Player.svelte index 0aadf2e3..957a1803 100644 --- a/materialious/src/lib/components/Player.svelte +++ b/materialious/src/lib/components/Player.svelte @@ -128,20 +128,27 @@ let playerTimelineTooltip: HTMLDivElement | undefined = $state(); let playerTimelineThumbnails: TimelineThumbnail[] = $state([]); let playerTimelineThumbnailsCache = new ImageCache(); - let playerTimelineThumbnailCanvas: HTMLCanvasElement | undefined = $state(); + let playerTimelineThumbnailCanvas: { + timeline?: HTMLCanvasElement; + thumb?: HTMLCanvasElement; + } = $state({}); let playerInitalInteract = true; const playerTimelineSlider = new Slider({ min: 0, step: 0.1, value: () => currentTime, - onValueChange: (timeToSet) => { + onValueChange: async (timeToSet) => { userManualSeeking = true; currentTime = timeToSet; showPlayerUI(); setPlayerTimelineChapters(currentTime); + if (playerTimelineThumbnailCanvas.thumb) { + await setPlayerTimelineThumbnails(currentTime, playerTimelineThumbnailCanvas.thumb); + } + if (playerSliderDebounce) clearTimeout(playerSliderDebounce); playerSliderDebounce = setTimeout(() => { @@ -515,13 +522,14 @@ dashUrl += '?local=true'; } - if (data.video.storyboards && data.video.storyboards.length > 1) { - // Use best possible thumbnails - playerTimelineThumbnails = await storyboardThumbnails( - data.video.storyboards[data.video.storyboards.length - 1], + if (data.video.storyboards && data.video.storyboards.length > 2) { + storyboardThumbnails( + data.video.storyboards[2], playerTimelineThumbnailsCache, playerMaxKnownTime - ); + ).then((thumbnails) => { + playerTimelineThumbnails = thumbnails; + }); } if ( @@ -1127,6 +1135,19 @@ } } + async function setPlayerTimelineThumbnails(time: number, canvas: HTMLCanvasElement) { + const canvasContext = canvas.getContext('2d'); + + if (canvasContext) { + await drawTimelineThumbnail( + canvasContext, + playerTimelineThumbnailsCache, + playerTimelineThumbnails, + time + ); + } + } + async function updateTooltip() { if (!playerSliderElement || latestMouseX === undefined) { requestAnimationTooltip = undefined; @@ -1139,17 +1160,11 @@ playerTimelineTimeHover = percent * (data.video.lengthSeconds ?? 0); setPlayerTimelineChapters(playerTimelineTimeHover); - if (playerTimelineThumbnailCanvas) { - const canvasContext = playerTimelineThumbnailCanvas.getContext('2d'); - - if (canvasContext) { - await drawTimelineThumbnail( - canvasContext, - playerTimelineThumbnailsCache, - playerTimelineThumbnails, - playerTimelineTimeHover - ); - } + if (playerTimelineThumbnailCanvas.timeline) { + await setPlayerTimelineThumbnails( + playerTimelineTimeHover, + playerTimelineThumbnailCanvas.timeline + ); } if (playerTimelineTooltip) { @@ -1350,35 +1365,31 @@ onmousemove={timelineMouseMove} bind:this={playerSliderElement} > - {#snippet timelineTooltip()} + {#snippet timelineTooltip(key: 'thumb' | 'timeline')} + {#if playerTimelineThumbnails.length > 0} + + {/if} {#if playerCloestSponsor} - {sponsorSegments[playerCloestSponsor.category]} -
+

{sponsorSegments[playerCloestSponsor.category]}

{:else if playerCloestTimestamp} - {truncate(playerCloestTimestamp.title, 22)} -
+

{truncate(playerCloestTimestamp.title, 22)}

{/if} {/snippet}
{#if !userManualSeeking}
- {#if playerTimelineThumbnails.length > 0} - - > - {/if} - {@render timelineTooltip()} + {@render timelineTooltip('timeline')} {videoLength(playerTimelineTimeHover)}
{/if}
-
- {@render timelineTooltip()} +
+ {@render timelineTooltip('thumb')} {videoLength(currentTime)}
@@ -1748,10 +1759,6 @@ transform: translate(-50%, -50%); } - .thumb-tooltip { - left: var(--percentage); - } - .seek-double-click { background-color: var(--secondary-container); height: var(--video-player-height); @@ -1873,13 +1880,20 @@ pointer-events: none; will-change: transform; padding: 0; - border-radius: 0.25rem; display: block; } - .timeline.tooltip canvas { + .timeline.tooltip canvas, + .tooltip.thumb canvas { display: block; margin-bottom: 0.1rem; height: 100px; + border-radius: 0.25rem; + } + + .tooltip.thumb { + left: var(--percentage); + display: block; + padding: 0; } diff --git a/materialious/src/lib/timelineThumbnails.ts b/materialious/src/lib/timelineThumbnails.ts index 81147a30..d783e501 100644 --- a/materialious/src/lib/timelineThumbnails.ts +++ b/materialious/src/lib/timelineThumbnails.ts @@ -40,9 +40,6 @@ export async function storyboardThumbnails( for (let sheetIndex = 0; sheetIndex < storyboardCount; sheetIndex++) { const url = templateUrl.replace('M$M', `M${sheetIndex}`); - // Preload all images. - imageCache.load(url); - for (let i = 0; i < count; i++) { const localIndex = i % (cols * rows); const row = Math.floor(localIndex / cols); @@ -51,6 +48,9 @@ export async function storyboardThumbnails( const time = Math.floor((globalIndex / totalThumbnails) * videoDurationMs); + // Pre-cache sheet + imageCache.load(url); + thumbnails.push({ url, time, diff --git a/materialious/src/routes/(app)/+layout.svelte b/materialious/src/routes/(app)/+layout.svelte index d81a7d2f..20f620c9 100644 --- a/materialious/src/routes/(app)/+layout.svelte +++ b/materialious/src/routes/(app)/+layout.svelte @@ -352,7 +352,7 @@ {#if isLoggedIn}