diff options
Diffstat (limited to 'src/utils/thumbnails.ts')
-rw-r--r-- | src/utils/thumbnails.ts | 60 |
1 files changed, 52 insertions, 8 deletions
diff --git a/src/utils/thumbnails.ts b/src/utils/thumbnails.ts index 61d28f18..68ad8169 100644 --- a/src/utils/thumbnails.ts +++ b/src/utils/thumbnails.ts @@ -1,10 +1,15 @@ import { isOnInvidious, parseYouTubeVideoIDFromURL } from "../../maze-utils/src/video"; import Config from "../config"; import { getVideoLabel } from "./videoLabels"; -import { setThumbnailListener } from "../../maze-utils/src/thumbnailManagement"; - -export async function labelThumbnails(thumbnails: HTMLImageElement[]): Promise<void> { - await Promise.all(thumbnails.map((t) => labelThumbnail(t))); +import { getThumbnailSelector, setThumbnailListener } from "../../maze-utils/src/thumbnailManagement"; +import { VideoID } from "../types"; +import { getSegmentsForVideo } from "./segmentData"; + +export async function handleThumbnails(thumbnails: HTMLImageElement[]): Promise<void> { + await Promise.all(thumbnails.map((t) => { + labelThumbnail(t); + setupThumbnailHover(t); + })); } export async function labelThumbnail(thumbnail: HTMLImageElement): Promise<HTMLElement | null> { @@ -13,9 +18,7 @@ export async function labelThumbnail(thumbnail: HTMLImageElement): Promise<HTMLE return null; } - const link = (isOnInvidious() ? thumbnail.parentElement : thumbnail.querySelector("#thumbnail")) as HTMLAnchorElement - if (!link || link.nodeName !== "A" || !link.href) return null; // no link found - const videoID = parseYouTubeVideoIDFromURL(link.href)?.videoID; + const videoID = extractVideoID(thumbnail); if (!videoID) { hideThumbnailLabel(thumbnail); return null; @@ -37,6 +40,47 @@ export async function labelThumbnail(thumbnail: HTMLImageElement): Promise<HTMLE return overlay; } +export async function setupThumbnailHover(thumbnail: HTMLImageElement): Promise<void> { + // Cache would be reset every load due to no SPA + if (isOnInvidious()) return; + + const mainElement = thumbnail.closest("#dismissible") as HTMLElement; + if (mainElement) { + mainElement.removeEventListener("mouseenter", thumbnailHoverListener); + mainElement.addEventListener("mouseenter", thumbnailHoverListener); + } +} + +function thumbnailHoverListener(e: MouseEvent) { + if (!chrome.runtime?.id) return; + + const thumbnail = (e.target as HTMLElement).querySelector(getThumbnailSelector()) as HTMLImageElement; + if (!thumbnail) return; + + // Pre-fetch data for this video + const videoID = extractVideoID(thumbnail); + if (videoID) { + void getSegmentsForVideo(videoID, false); + } +} + +function getLink(thumbnail: HTMLImageElement): HTMLAnchorElement | null { + if (isOnInvidious()) { + return thumbnail.parentElement as HTMLAnchorElement | null; + } else if (thumbnail.nodeName.toLowerCase() === "yt-thumbnail-view-model") { + return thumbnail.closest("yt-lockup-view-model")?.querySelector("a.yt-lockup-metadata-view-model-wiz__title"); + } else { + return thumbnail.querySelector("#thumbnail"); + } +} + +function extractVideoID(thumbnail: HTMLImageElement): VideoID | null { + const link = getLink(thumbnail); + if (!link || link.nodeName !== "A" || !link.href) return null; // no link found + + return parseYouTubeVideoIDFromURL(link.href)?.videoID; +} + function getOldThumbnailLabel(thumbnail: HTMLImageElement): HTMLElement | null { return thumbnail.querySelector(".sponsorThumbnailLabel") as HTMLElement | null; } @@ -109,7 +153,7 @@ function insertSBIconDefinition() { } export function setupThumbnailListener(): void { - setThumbnailListener(labelThumbnails, () => { + setThumbnailListener(handleThumbnails, () => { insertSBIconDefinition(); }, () => Config.isReady()); }
\ No newline at end of file |