From 6ba468235beb9f354ad619cf3c561cfb50d2b991 Mon Sep 17 00:00:00 2001 From: KingKDot Date: Thu, 23 Apr 2026 12:19:00 -0500 Subject: [PATCH] add more details to sharp + hopefully let me know if it's broken for people on linux. --- Overlord-Server/public/assets/data.js | 16 +++++++++++----- Overlord-Server/public/assets/state.js | 1 - Overlord-Server/src/thumbnails.ts | 21 +++++++++++++++------ 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/Overlord-Server/public/assets/data.js b/Overlord-Server/public/assets/data.js index fb0ca0c..95e6983 100644 --- a/Overlord-Server/public/assets/data.js +++ b/Overlord-Server/public/assets/data.js @@ -4,12 +4,14 @@ import { digestData } from "./utils.js"; const POLL_INTERVAL_MS = 5000; const FALLBACK_POLL_MS = 30000; const PREF_REFRESH_KEY = "overlord_refresh_interval_seconds"; +const THUMBNAIL_COOLDOWN_MS = 60000; let pollTimer = null; let render = () => {}; let dashboardWs = null; let dashboardWsConnected = false; let wsReconnectTimer = null; const manuallyDisconnecting = new Set(); +const thumbnailRequestedAt = new Map(); function moveClientCardImmediately(msg) { const clientId = typeof msg?.clientId === "string" ? msg.clientId : ""; @@ -74,10 +76,7 @@ export async function loadWithOptions(options = {}) { const pag = document.getElementById("pagination"); if (pag) pag.style.visibility = ""; - if (!state.thumbnailsRequested) { - state.thumbnailsRequested = true; - requestThumbnailsForClients(data.items); - } + requestThumbnailsForClients(data.items); } catch (err) { console.error("load clients", err); } finally { @@ -93,8 +92,14 @@ export async function loadWithOptions(options = {}) { } async function requestThumbnailsForClients(items) { - const onlineClientsWithoutThumbnail = items.filter(c => c.online && !c.thumbnail); + const now = Date.now(); + const onlineClientsWithoutThumbnail = items.filter(c => { + if (!c.online || c.thumbnail) return false; + const last = thumbnailRequestedAt.get(c.id); + return !last || now - last > THUMBNAIL_COOLDOWN_MS; + }); for (const client of onlineClientsWithoutThumbnail) { + thumbnailRequestedAt.set(client.id, now); await requestThumbnail(client.id); } } @@ -176,6 +181,7 @@ function connectDashboardWs() { console.warn("[dashboard] ws closed"); dashboardWs = null; dashboardWsConnected = false; + thumbnailRequestedAt.clear(); adjustPollingForWs(); scheduleDashboardReconnect(); }; diff --git a/Overlord-Server/public/assets/state.js b/Overlord-Server/public/assets/state.js index f53f0ac..8258a31 100644 --- a/Overlord-Server/public/assets/state.js +++ b/Overlord-Server/public/assets/state.js @@ -11,5 +11,4 @@ export const state = { isLoading: false, pendingForce: false, pendingReorder: false, - thumbnailsRequested: false, }; diff --git a/Overlord-Server/src/thumbnails.ts b/Overlord-Server/src/thumbnails.ts index f67abe6..0b94a80 100644 --- a/Overlord-Server/src/thumbnails.ts +++ b/Overlord-Server/src/thumbnails.ts @@ -1,9 +1,17 @@ -let _sharp: typeof import("sharp") extends { default: infer D } ? D : never; -async function getSharp() { - if (!_sharp) { - _sharp = (await import("sharp")).default; +let _sharp: (typeof import("sharp") extends { default: infer D } ? D : never) | null = null; +let _sharpLoadAttempted = false; + +async function getSharp(): Promise { + if (_sharp) return _sharp; + if (_sharpLoadAttempted) throw new Error("sharp module unavailable"); + _sharpLoadAttempted = true; + try { + _sharp = (await import("sharp")).default as any; + return _sharp!; + } catch (err) { + console.error("[thumbnails] Failed to load sharp module. Thumbnails will be unavailable.", err); + throw err; } - return _sharp; } const THUMBNAIL_WIDTH = Math.max(64, Number(process.env.OVERLORD_THUMBNAIL_WIDTH || 640)); @@ -80,7 +88,8 @@ export async function generateThumbnail(id: string): Promise { thumbnails.set(id, dataUrl); latestFrames.delete(id); return true; - } catch { + } catch (err) { + console.error(`[thumbnails] Failed to generate thumbnail for client ${id}:`, err); return false; } }