From e5d581909886b71a76443a77256b5b63688251ae Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sat, 7 Feb 2026 22:19:06 +0000 Subject: [PATCH] Rename and fix screenshots --- docker-compose.yml | 12 ++-- {og-screenshot => screenshot}/Dockerfile | 7 ++- .../package-lock.json | 4 +- {og-screenshot => screenshot}/package.json | 2 +- {og-screenshot => screenshot}/src/cache.ts | 0 .../src/screenshot.ts | 59 +++++++++++++++++-- {og-screenshot => screenshot}/src/server.ts | 15 ++++- {og-screenshot => screenshot}/tsconfig.json | 0 8 files changed, 81 insertions(+), 18 deletions(-) rename {og-screenshot => screenshot}/Dockerfile (55%) rename {og-screenshot => screenshot}/package-lock.json (99%) rename {og-screenshot => screenshot}/package.json (93%) rename {og-screenshot => screenshot}/src/cache.ts (100%) rename {og-screenshot => screenshot}/src/screenshot.ts (65%) rename {og-screenshot => screenshot}/src/server.ts (83%) rename {og-screenshot => screenshot}/tsconfig.json (100%) diff --git a/docker-compose.yml b/docker-compose.yml index ca78932..e30c8ba 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,19 +20,19 @@ services: - cargo-target:/app/server-rs/target environment: POCKETBASE_URL: http://pocketbase:8090 - OG_SIDECAR_URL: http://og-screenshot:8002 + SCREENSHOT_URL: http://screenshot:8002 OLLAMA_URL: http://host.docker.internal:11434 depends_on: pocketbase: condition: service_healthy - og-screenshot: - build: /volumes/syncthing/Projects/property-map/og-screenshot + screenshot: + build: /volumes/syncthing/Projects/property-map/screenshot environment: - NARROWIT_URL: http://server:8001 + NARROWIT_URL: http://frontend:3001 CACHE_DIR: /cache volumes: - - og-cache:/cache + - screenshot-cache:/cache networks: - dev-network healthcheck: @@ -88,7 +88,7 @@ volumes: cargo-registry: cargo-target: frontend-node-modules: - og-cache: + screenshot-cache: networks: dev-network: diff --git a/og-screenshot/Dockerfile b/screenshot/Dockerfile similarity index 55% rename from og-screenshot/Dockerfile rename to screenshot/Dockerfile index 65a3383..26880c2 100644 --- a/og-screenshot/Dockerfile +++ b/screenshot/Dockerfile @@ -9,9 +9,14 @@ WORKDIR /app COPY package.json package-lock.json* ./ RUN npm install -# Install Chromium for Playwright +# Install Chromium for Playwright (including system deps for headless rendering) RUN npx playwright install --with-deps chromium +# Ensure EGL/GLES libraries are available for SwiftShader WebGL rendering +RUN apt-get update && \ + apt-get install -y --no-install-recommends libegl1 libgles2 && \ + rm -rf /var/lib/apt/lists/* + COPY tsconfig.json ./ COPY src/ src/ RUN npm run build diff --git a/og-screenshot/package-lock.json b/screenshot/package-lock.json similarity index 99% rename from og-screenshot/package-lock.json rename to screenshot/package-lock.json index 091199c..2683569 100644 --- a/og-screenshot/package-lock.json +++ b/screenshot/package-lock.json @@ -1,11 +1,11 @@ { - "name": "og-screenshot", + "name": "screenshot", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "og-screenshot", + "name": "screenshot", "version": "1.0.0", "dependencies": { "express": "^4.21.0", diff --git a/og-screenshot/package.json b/screenshot/package.json similarity index 93% rename from og-screenshot/package.json rename to screenshot/package.json index aed645e..7c8b961 100644 --- a/og-screenshot/package.json +++ b/screenshot/package.json @@ -1,5 +1,5 @@ { - "name": "og-screenshot", + "name": "screenshot", "version": "1.0.0", "private": true, "scripts": { diff --git a/og-screenshot/src/cache.ts b/screenshot/src/cache.ts similarity index 100% rename from og-screenshot/src/cache.ts rename to screenshot/src/cache.ts diff --git a/og-screenshot/src/screenshot.ts b/screenshot/src/screenshot.ts similarity index 65% rename from og-screenshot/src/screenshot.ts rename to screenshot/src/screenshot.ts index f097aa5..b9ef97e 100644 --- a/og-screenshot/src/screenshot.ts +++ b/screenshot/src/screenshot.ts @@ -36,14 +36,19 @@ function detectGpu(): boolean { const hasGpu = detectGpu(); function getBrowserArgs(): string[] { - const baseArgs = ['--no-sandbox', '--disable-dev-shm-usage']; + const baseArgs = [ + '--no-sandbox', + '--disable-dev-shm-usage', + '--enable-webgl', + '--ignore-gpu-blocklist', + ]; if (hasGpu) { // Use hardware GPU acceleration - return [...baseArgs, '--enable-gpu', '--enable-webgl']; + return [...baseArgs, '--enable-gpu', '--use-gl=egl']; } else { // Fall back to SwiftShader software rendering - return [...baseArgs, '--use-gl=angle', '--use-angle=swiftshader']; + return [...baseArgs, '--disable-gpu', '--use-gl=swiftshader']; } } @@ -116,17 +121,34 @@ async function releasePage(page: Page): Promise { export async function takeScreenshot(url: string): Promise { const page = await acquirePage(); + // Log browser console messages for diagnostics + page.on('console', (msg) => { + if (msg.type() === 'error' || msg.type() === 'warning') { + console.log(`[browser ${msg.type()}] ${msg.text()}`); + } + }); + page.on('pageerror', (err) => { + console.log(`[browser exception] ${err.message}`); + }); + try { // Use domcontentloaded instead of networkidle - let __og_ready handle readiness - await page.goto(url, { waitUntil: 'domcontentloaded', timeout: NAVIGATION_TIMEOUT }); + const response = await page.goto(url, { + waitUntil: 'domcontentloaded', + timeout: NAVIGATION_TIMEOUT, + }); + if (response) { + console.log(`Page loaded: ${response.status()} ${response.statusText()}`); + } // Wait for the frontend to signal readiness try { await page.waitForFunction('window.__og_ready === true', { timeout: NAVIGATION_TIMEOUT, }); + console.log('Frontend signalled ready'); } catch { - // Proceed anyway — partial screenshot is better than nothing + console.warn('Timed out waiting for __og_ready, proceeding with partial screenshot'); } // Extra buffer for map tiles to finish rendering @@ -134,6 +156,33 @@ export async function takeScreenshot(url: string): Promise { const screenshot = await page.screenshot({ type: 'png' }); return Buffer.from(screenshot); + } finally { + // Remove listeners before releasing page back to pool + page.removeAllListeners('console'); + page.removeAllListeners('pageerror'); + await releasePage(page); + } +} + +export async function checkWebGL(): Promise> { + const page = await acquirePage(); + try { + await page.setContent(''); + const info = await page.evaluate(() => { + const canvas = document.getElementById('c') as HTMLCanvasElement; + const gl = + canvas.getContext('webgl2') || canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); + if (!gl) return { webgl: false, error: 'No WebGL context available' }; + const g = gl as WebGLRenderingContext; + const debugExt = g.getExtension('WEBGL_debug_renderer_info'); + return { + webgl: true, + version: g.getParameter(g.VERSION), + renderer: debugExt ? g.getParameter(debugExt.UNMASKED_RENDERER_WEBGL) : 'unknown', + vendor: debugExt ? g.getParameter(debugExt.UNMASKED_VENDOR_WEBGL) : 'unknown', + }; + }); + return info; } finally { await releasePage(page); } diff --git a/og-screenshot/src/server.ts b/screenshot/src/server.ts similarity index 83% rename from og-screenshot/src/server.ts rename to screenshot/src/server.ts index 72fb3df..1ed2c50 100644 --- a/og-screenshot/src/server.ts +++ b/screenshot/src/server.ts @@ -1,6 +1,6 @@ import express from 'express'; import { ScreenshotCache } from './cache.js'; -import { takeScreenshot, closeBrowser } from './screenshot.js'; +import { takeScreenshot, checkWebGL, closeBrowser } from './screenshot.js'; const PORT = parseInt(process.env.PORT || '8002', 10); const NARROWIT_URL = process.env.NARROWIT_URL || 'http://localhost:8001'; @@ -13,10 +13,19 @@ app.get('/health', (_req, res) => { res.status(200).send('ok'); }); +app.get('/debug', async (_req, res) => { + try { + const info = await checkWebGL(); + res.json(info); + } catch (err) { + res.status(500).json({ error: String(err) }); + } +}); + app.get('/screenshot', async (req, res) => { try { const params: Record = {}; - for (const key of ['v', 'f', 'poi', 'tab']) { + for (const key of ['v', 'f', 'poi', 'tab', 'og']) { const val = req.query[key]; if (typeof val === 'string' && val) { params[key] = val; @@ -57,7 +66,7 @@ app.get('/screenshot', async (req, res) => { }); const server = app.listen(PORT, () => { - console.log(`OG screenshot service listening on port ${PORT}`); + console.log(`Screenshot service listening on port ${PORT}`); console.log(` NARROWIT_URL: ${NARROWIT_URL}`); console.log(` CACHE_DIR: ${CACHE_DIR}`); }); diff --git a/og-screenshot/tsconfig.json b/screenshot/tsconfig.json similarity index 100% rename from og-screenshot/tsconfig.json rename to screenshot/tsconfig.json