From f89d036ab8abb9f5e8e2ef538cf7eb89fb029d13 Mon Sep 17 00:00:00 2001 From: Eugene Fox Date: Sun, 4 May 2025 15:22:33 +0300 Subject: [PATCH] feat: captureVisibleTab fallback for tab previews --- entrypoints/background.ts | 37 +++++++++++++++++++ entrypoints/sidepanel/components/TabView.tsx | 2 +- eslint.config.js | 3 +- .../collectionStorage/utils/updateGraphics.ts | 3 ++ .../migration/utils/migrateCollections.ts | 6 +-- features/migration/utils/migrateStorage.ts | 4 +- models/CollectionModels.ts | 1 + 7 files changed, 49 insertions(+), 7 deletions(-) diff --git a/entrypoints/background.ts b/entrypoints/background.ts index 4214d9b..675f879 100644 --- a/entrypoints/background.ts +++ b/entrypoints/background.ts @@ -48,6 +48,7 @@ export default defineBackground(() => graphicsCache[tab.url] = { preview: graphicsCache[tab.url]?.preview, + capture: graphicsCache[tab.url]?.capture, icon: tab.favIconUrl ?? graphicsCache[tab.url]?.icon }; }); @@ -61,10 +62,46 @@ export default defineBackground(() => { graphicsCache[data.url] = { preview: data.thumbnail, + capture: graphicsCache[data.url]?.capture, icon: graphicsCache[data.url]?.icon }; }); + setupTabCaputre(); + async function setupTabCaputre(): Promise + { + const tryCaptureTab = async (tab: Tabs.Tab): Promise => + { + if (!tab.url || tab.status !== "complete" || !tab.active) + return; + + try + { + // We use chrome here because polyfill throws uncatchable errors for some reason + // It's a compatible API anyway + const capture: string = await chrome.tabs.captureVisibleTab(tab.windowId!, { format: "jpeg", quality: 1 }); + + if (capture) + { + graphicsCache[tab.url] = { + capture, + preview: graphicsCache[tab.url]?.preview, + icon: graphicsCache[tab.url]?.icon + }; + + logger("Captured tab", tab.url); + } + } + catch (ex) { logger(ex); } + }; + + setInterval(() => + { + browser.tabs.query({ active: true }) + .then(tabs => tabs.forEach(tab => tryCaptureTab(tab))); + }, 1000); + } + setupContextMenu(); async function setupContextMenu(): Promise { diff --git a/entrypoints/sidepanel/components/TabView.tsx b/entrypoints/sidepanel/components/TabView.tsx index 5bad05a..f122462 100644 --- a/entrypoints/sidepanel/components/TabView.tsx +++ b/entrypoints/sidepanel/components/TabView.tsx @@ -69,7 +69,7 @@ export default function TabView({ tab, indices, dragOverlay }: TabViewProps): Re > { tilesView && e.currentTarget.src = pagePlaceholder } className={ cls.image } draggable={ false } /> } diff --git a/eslint.config.js b/eslint.config.js index d31604d..835d941 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -87,7 +87,8 @@ export default defineConfig([ "@stylistic/no-mixed-spaces-and-tabs": ["warn"], "@typescript-eslint/no-unused-vars": ["warn"], "prefer-const": ["warn"], - "@stylistic/padded-blocks": ["warn"] + "@stylistic/padded-blocks": ["warn"], + "no-empty": ["off"] } }, { diff --git a/features/collectionStorage/utils/updateGraphics.ts b/features/collectionStorage/utils/updateGraphics.ts index 2b09ce1..a6669d0 100644 --- a/features/collectionStorage/utils/updateGraphics.ts +++ b/features/collectionStorage/utils/updateGraphics.ts @@ -13,6 +13,7 @@ export default async function updateGraphics( function getGraphics(url: string): GraphicsItem | null { const preview = tempGraphics[url]?.preview ?? localGraphics[url]?.preview; + const capture = tempGraphics[url]?.capture ?? localGraphics[url]?.capture; const icon = tempGraphics[url]?.icon ?? localGraphics[url]?.icon; const graphics: GraphicsItem = {}; @@ -21,6 +22,8 @@ export default async function updateGraphics( graphics.preview = preview; if (icon) graphics.icon = icon; + if (capture) + graphics.capture = capture; return preview || icon ? graphics : null; } diff --git a/features/migration/utils/migrateCollections.ts b/features/migration/utils/migrateCollections.ts index 6197794..d1a74d9 100644 --- a/features/migration/utils/migrateCollections.ts +++ b/features/migration/utils/migrateCollections.ts @@ -13,12 +13,12 @@ export default function migrateCollections(legacyCollections: LegacyCollection[] { const title: string | undefined = legacyCollection.titles[index]; const icon: string | undefined = legacyCollection.icons?.[index]; - const preview: string | undefined = legacyCollection.thumbnails?.[index]; + const capture: string | undefined = legacyCollection.thumbnails?.[index]; if (!graphics[url]) - graphics[url] = { icon, preview }; + graphics[url] = { icon, capture }; else - graphics[url] = { icon: graphics[url].icon ?? icon, preview: graphics[url].preview ?? preview }; + graphics[url] = { icon: graphics[url].icon ?? icon, capture: graphics[url].preview ?? capture }; return { type: "tab", diff --git a/features/migration/utils/migrateStorage.ts b/features/migration/utils/migrateStorage.ts index 92b5b9d..99eb257 100644 --- a/features/migration/utils/migrateStorage.ts +++ b/features/migration/utils/migrateStorage.ts @@ -38,11 +38,11 @@ export default async function migrateStorage(): Promise for (const [key, record] of Object.entries(v2Graphics)) { if (!graphics[key]) - graphics[key] = { icon: record.iconUrl, preview: record.pageCapture }; + graphics[key] = { icon: record.iconUrl, capture: record.pageCapture }; else { graphics[key].icon ??= record.iconUrl; - graphics[key].preview ??= record.pageCapture; + graphics[key].capture ??= record.pageCapture; } } diff --git a/models/CollectionModels.ts b/models/CollectionModels.ts index 31c4c30..0e0a1e5 100644 --- a/models/CollectionModels.ts +++ b/models/CollectionModels.ts @@ -37,5 +37,6 @@ export type GraphicsStorage = Record; export type GraphicsItem = { preview?: string; + capture?: string; icon?: string; };