diff --git a/nodejs/sender-monitor/main.js b/nodejs/sender-monitor/main.js index 5c9945f..b3b2d64 100644 --- a/nodejs/sender-monitor/main.js +++ b/nodejs/sender-monitor/main.js @@ -1,4 +1,4 @@ -const { app, Tray, Menu, shell, clipboard, BrowserWindow, ipcMain } = require("electron"); +const { app, Tray, Menu, shell, clipboard, BrowserWindow, ipcMain, screen} = require("electron"); const path = require("path"); const fs = require("fs"); const webrtc = require("./webrtc"); @@ -6,6 +6,7 @@ const QRCode = require("qrcode"); const { Monitor } = require("node-screenshots"); const { performOCR } = require("./ocr"); const { Translator } = require("google-translate-api-x"); +const sharp = require("sharp"); let tray; let qrWindow; @@ -18,6 +19,7 @@ let clipboardMonitorInterval; let ocrMonitorInterval; const maxRetries = 10; const retryInterval = 3000; +let overlayWindow = null; const logFilePath = path.join(app.getPath("userData"), "log.txt"); @@ -38,6 +40,45 @@ ipcMain.on("close-qr-window", () => { } }); +function createOverlayWindow() { + overlayWindow = new BrowserWindow({ + fullscreen: true, + frame: false, + transparent: true, + alwaysOnTop: true, + resizable: false, + webPreferences: { + contextIsolation: true, + preload: path.join(__dirname, "overlay-preload.js"), + }, + }); + + overlayWindow.loadURL(`file://${__dirname}/overlay.html`); + overlayWindow.on("closed", () => { + overlayWindow = null; + console.log("Overlay window closed"); + }); +} + +// Updated `set-capture-area` handler +ipcMain.on("set-capture-area", (event, bounds) => { + console.log("Received capture area bounds from overlay:", bounds); + if (!bounds || !bounds.width || !bounds.height) { + console.error("Invalid capture area bounds received:", bounds); + return; + } + + config.captureArea = bounds; + fs.writeFileSync(configFilePath, JSON.stringify(config, null, 2), "utf-8"); + console.log(`Updated capture area to new values: ${JSON.stringify(bounds)}`); + + // Close the overlay window after capturing bounds + if (overlayWindow) { + overlayWindow.close(); + } +}); + + async function createQRWindow(qrDataUrl) { if (qrWindow) { qrWindow.close(); @@ -82,7 +123,39 @@ function reloadConfig() { config = JSON.parse(fs.readFileSync(configFilePath, "utf-8")); console.log("Configuration reloaded."); logMessage("Configuration reloaded from config.json."); - // You may want to reinitialize any settings here that depend on the config + + // Stop any existing monitoring intervals + if (clipboardMonitorInterval) { + clearInterval(clipboardMonitorInterval); + clipboardMonitorInterval = null; + } + if (ocrMonitorInterval) { + clearInterval(ocrMonitorInterval); + ocrMonitorInterval = null; + } + + // Start the appropriate monitoring based on the reloaded config + if (config.monitorMode === "clipboard") { + clipboardMonitorInterval = setInterval(() => { + const currentText = clipboard.readText(); + processAndSendText(currentText); + }, config.captureInterval); + console.log("Switched to clipboard monitoring mode."); + logMessage("Switched to clipboard monitoring mode."); + } else if (config.monitorMode === "ocr") { + ocrMonitorInterval = setInterval(async () => { + const recognizedText = await captureAndProcessScreen(); + processAndSendText(recognizedText); + }, config.captureInterval); + console.log("Switched to OCR monitoring mode."); + logMessage("Switched to OCR monitoring mode."); + } + + // Update translation settings based on the reloaded config + const isTranslationEnabled = config.translation?.enabled || false; + console.log(`Translation enabled: ${isTranslationEnabled}`); + logMessage(`Translation enabled: ${isTranslationEnabled}`); + } catch (error) { console.error("Failed to reload config:", error); logMessage("Failed to reload config."); @@ -91,65 +164,105 @@ function reloadConfig() { // Capture and OCR function with return of recognized text async function captureAndProcessScreen() { - const { x, y, width, height } = config.captureArea; - const useEdgeForOCR = config.useEdgeForOCR; + const { x, y, width, height } = config.captureArea; + const useEdgeForOCR = config.useEdgeForOCR; + const fullImagePath = path.join(app.getPath("temp"), "full-image.png"); + const croppedImagePath = path.join(app.getPath("temp"), "cropped-image.png"); + + try { + console.log("Starting screen capture and cropping process..."); + + const monitor = Monitor.all().find(m => m.isPrimary); + if (!monitor) { + console.error("No primary monitor found."); + return; + } - const filePath = path.join(app.getPath("temp"), "ocr-capture.png"); + const fullImage = await monitor.captureImage(); + if (!fullImage) { + console.error("Image capture failed."); + return; + } - try { - const monitor = Monitor.all().find(m => m.isPrimary); - if (!monitor) { - console.error("No primary monitor found."); - return ""; - } + // Convert the full captured image to a PNG buffer + const fullImageBuffer = await fullImage.toPng().catch(err => { + console.error("Failed to create fullImageBuffer:", err); + throw err; + }); - // Capture the full image - const fullImage = await monitor.captureImage(); - if (!fullImage) { - console.error("Image capture failed."); - return ""; - } - - // Crop the image to the specified capture area - const croppedImage = await fullImage.crop(x, y, width, height); - if (!croppedImage) { - console.error("Image cropping failed."); - return ""; - } + // Save the full image + await fs.promises.writeFile(fullImagePath, fullImageBuffer); + console.log("Full screenshot saved at", fullImagePath); - // Write the cropped image to the temp path - const imageBuffer = await croppedImage.toPng(); - fs.writeFileSync(filePath, imageBuffer); + if (!fs.existsSync(fullImagePath)) { + console.error("Full screenshot file does not exist at", fullImagePath); + return; + } - // Confirm file existence - if (!fs.existsSync(filePath)) { - console.error("File does not exist at", filePath); - return ""; // Exit early if file creation failed - } + // Get image dimensions using sharp to verify metadata + const imageMetadata = await sharp(fullImagePath).metadata(); + console.log("Full image dimensions:", imageMetadata); - console.log("Image successfully saved at", filePath); + // Get the primary display's scaling factor + const primaryDisplay = screen.getPrimaryDisplay(); + const scaleFactor = primaryDisplay.scaleFactor; + console.log("Primary display scale factor:", scaleFactor); - // Call performOCR with the useEdgeForOCR flag - const recognizedText = await performOCR(filePath, useEdgeForOCR); + // Adjust bounds to account for scaling + const scaledX = Math.round(x * scaleFactor); + const scaledY = Math.round(y * scaleFactor); + const scaledWidth = Math.round(width * scaleFactor); + const scaledHeight = Math.round(height * scaleFactor); - // Log recognized text - console.log("OCR completed, recognized text:", recognizedText); + console.log(`Scaled crop bounds: x=${scaledX}, y=${scaledY}, width=${scaledWidth}, height=${scaledHeight}`); - return recognizedText || ""; // Return the OCR text or an empty string + // Adjust bounds to ensure they are within the image dimensions + const adjustedX = Math.min(Math.max(scaledX, 0), imageMetadata.width); + const adjustedY = Math.min(Math.max(scaledY, 0), imageMetadata.height); + const adjustedWidth = Math.min(scaledWidth, imageMetadata.width - adjustedX); + const adjustedHeight = Math.min(scaledHeight, imageMetadata.height - adjustedY); - } catch (error) { - console.error("Screen capture or OCR failed:", error); - logMessage("Error during screen capture or OCR"); - return ""; - } finally { - // Clean up the temp file after everything is done - if (fs.existsSync(filePath)) { - fs.unlinkSync(filePath); - console.log("Temporary OCR file cleaned up:", filePath); - } + console.log(`Adjusted crop bounds for the image: x=${adjustedX}, y=${adjustedY}, width=${adjustedWidth}, height=${adjustedHeight}`); + + // Now proceed to crop the image using sharp with the adjusted dimensions + await sharp(fullImagePath) + .extract({ left: adjustedX, top: adjustedY, width: adjustedWidth, height: adjustedHeight }) + .toFile(croppedImagePath); + + console.log("Cropped image successfully saved at", croppedImagePath); + + if (!fs.existsSync(croppedImagePath)) { + console.error("Cropped image file does not exist at", croppedImagePath); + return; + } + + const recognizedText = await performOCR(croppedImagePath, useEdgeForOCR); + + if (recognizedText === undefined) { + console.log("OCR result was undefined. Opening image directory for inspection..."); + } else { + console.log("OCR completed, recognized text:", recognizedText); } + + return recognizedText || ""; + + } catch (error) { + console.error("Error occurred during capture or cropping process:", error); + } finally { + // Clean up temporary files if they exist + if (fs.existsSync(croppedImagePath)) { + fs.unlinkSync(croppedImagePath); + console.log("Temporary OCR file cleaned up:", croppedImagePath); + } + + if (fs.existsSync(fullImagePath)) { + fs.unlinkSync(fullImagePath); + console.log("Temporary OCR file cleaned up of screen:", fullImagePath); + } + } } + const translator = new Translator({ from: config.translation?.sourceLang || "en", to: config.translation?.targetLang || "es", @@ -267,6 +380,10 @@ function updateTrayMenu() { click: () => shell.openPath(configFilePath) .catch(err => console.error("Failed to open config file:", err)) }, + { + label: "Define OCR Area", // New option to define OCR area + click: createOverlayWindow, + }, { label: "Reload Config", click: reloadConfig, diff --git a/nodejs/sender-monitor/ocr.js b/nodejs/sender-monitor/ocr.js index de2acea..c70275e 100644 --- a/nodejs/sender-monitor/ocr.js +++ b/nodejs/sender-monitor/ocr.js @@ -20,18 +20,30 @@ const ocrImageEdge = edge.func({ { public async Task Invoke(dynamic input) { - string filePath = (string)input; - var storageFile = await StorageFile.GetFileFromPathAsync(filePath); - - using (IRandomAccessStream stream = await storageFile.OpenAsync(FileAccessMode.Read)) + try { - var decoder = await BitmapDecoder.CreateAsync(stream); - var bitmap = await decoder.GetSoftwareBitmapAsync(); + string filePath = (string)input; + var storageFile = await StorageFile.GetFileFromPathAsync(filePath); + + using (IRandomAccessStream stream = await storageFile.OpenAsync(FileAccessMode.Read)) + { + var decoder = await BitmapDecoder.CreateAsync(stream); + var bitmap = await decoder.GetSoftwareBitmapAsync(); + + if (bitmap == null) return "Bitmap loading failed"; + + var ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages(); + if (ocrEngine == null) return "OCR Engine creation failed"; - var ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages(); - var ocrResult = await ocrEngine.RecognizeAsync(bitmap); + var ocrResult = await ocrEngine.RecognizeAsync(bitmap); + if (ocrResult == null || ocrResult.Text == null) return "OCR result is empty or null"; - return ocrResult.Text; + return ocrResult.Text; + } + } + catch (Exception ex) + { + return "Error: " + ex.Message; } } } @@ -47,11 +59,13 @@ const ocrImageEdge = edge.func({ // Main OCR function that switches based on config async function performOCR(filePath, useEdgeForOCR) { + console.log("performOCR called with useEdgeForOCR:", useEdgeForOCR); + if (useEdgeForOCR) { try { const text = await ocrImageEdge(filePath); console.log("Recognized text (Windows.Media.Ocr):", text); - return text; + return text || ""; // Return text or an empty string if text is undefined } catch (error) { console.error("Windows.Media.Ocr failed:", error); return null; diff --git a/nodejs/sender-monitor/overlay-preload.js b/nodejs/sender-monitor/overlay-preload.js new file mode 100644 index 0000000..85d3a60 --- /dev/null +++ b/nodejs/sender-monitor/overlay-preload.js @@ -0,0 +1,42 @@ +const { ipcRenderer } = require('electron'); + +let isSelecting = false; +let startX, startY, endX, endY; + +// This listens for the mouse events to capture the coordinates +window.addEventListener('mousedown', (event) => { + isSelecting = true; + startX = event.clientX; + startY = event.clientY; + console.log('Selection started at:', { x: startX, y: startY }); +}); + +window.addEventListener('mousemove', (event) => { + if (isSelecting) { + endX = event.clientX; + endY = event.clientY; + console.log('Selection moving:', { endX, endY }); + } +}); + +window.addEventListener('mouseup', (event) => { + if (isSelecting) { + isSelecting = false; + endX = event.clientX; + endY = event.clientY; + console.log('Selection ended at:', { x: endX, y: endY }); + + // Calculate the bounds + const bounds = { + x: Math.min(startX, endX), + y: Math.min(startY, endY), + width: Math.abs(endX - startX), + height: Math.abs(endY - startY) + }; + + console.log('Bounds calculated:', bounds); + + // Send bounds to the main process + ipcRenderer.send('set-capture-area', bounds); + } +}); diff --git a/nodejs/sender-monitor/overlay.html b/nodejs/sender-monitor/overlay.html new file mode 100644 index 0000000..9f5602d --- /dev/null +++ b/nodejs/sender-monitor/overlay.html @@ -0,0 +1,31 @@ + + + + + + Select OCR Area + + + + + + + + + \ No newline at end of file diff --git a/nodejs/sender-monitor/overlay.js b/nodejs/sender-monitor/overlay.js new file mode 100644 index 0000000..acdf442 --- /dev/null +++ b/nodejs/sender-monitor/overlay.js @@ -0,0 +1,51 @@ +// overlay.js + +const canvas = document.getElementById("selectionCanvas"); +const ctx = canvas.getContext("2d"); + +// Set canvas dimensions to match the window +canvas.width = window.innerWidth; +canvas.height = window.innerHeight; + +let startX, startY, isDrawing = false; + +canvas.addEventListener("mousedown", (e) => { + startX = e.clientX; + startY = e.clientY; + isDrawing = true; +}); + +canvas.addEventListener("mousemove", (e) => { + if (!isDrawing) return; + + // Clear the canvas before drawing a new rectangle + ctx.clearRect(0, 0, canvas.width, canvas.height); + + const width = e.clientX - startX; + const height = e.clientY - startY; + + // Draw the rectangle + ctx.strokeStyle = "red"; + ctx.lineWidth = 2; + ctx.strokeRect(startX, startY, width, height); +}); + +canvas.addEventListener("mouseup", (e) => { + if (!isDrawing) return; + isDrawing = false; + + const width = e.clientX - startX; + const height = e.clientY - startY; + + // Send the coordinates to the main process via electronAPI + window.electronAPI.sendOCRBounds({ x: startX, y: startY, width, height }); + + // Close the overlay window after sending the data + window.close(); +}); + +// Ensure the canvas resizes correctly if the window size changes +window.addEventListener("resize", () => { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; +}); \ No newline at end of file diff --git a/nodejs/sender-monitor/package-lock.json b/nodejs/sender-monitor/package-lock.json index be525dc..ebdf7e2 100644 --- a/nodejs/sender-monitor/package-lock.json +++ b/nodejs/sender-monitor/package-lock.json @@ -14,6 +14,7 @@ "google-translate-api-x": "^10.7.1", "node-screenshots": "^0.2.2", "qrcode": "^1.5.4", + "sharp": "^0.33.5", "socket.io-client": "^4.8.1", "tesseract.js": "^5.1.1", "wrtc": "^0.4.7" @@ -384,6 +385,16 @@ "node": ">= 10.0.0" } }, + "node_modules/@emnapi/runtime": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", + "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@faker-js/faker": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.1.0.tgz", @@ -406,6 +417,367 @@ "dev": true, "license": "MIT" }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1885,6 +2257,19 @@ "node": ">=0.10.0" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1903,6 +2288,16 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", @@ -3506,6 +3901,12 @@ "node": ">= 12" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" + }, "node_modules/is-ci": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", @@ -5568,11 +5969,71 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "license": "ISC" }, + "node_modules/sharp": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" + } + }, + "node_modules/sharp/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", @@ -5998,6 +6459,13 @@ "utf8-byte-length": "^1.0.1" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, "node_modules/type-fest": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", diff --git a/nodejs/sender-monitor/package.json b/nodejs/sender-monitor/package.json index 7cf1dc8..b435ddb 100644 --- a/nodejs/sender-monitor/package.json +++ b/nodejs/sender-monitor/package.json @@ -24,6 +24,9 @@ "files": [ "main.js", "webrtc.js", + "overlay.html", + "overlay.js", + "overlay-preload.js", "ocr.js", "iceServers.js", "preload.js", @@ -56,6 +59,7 @@ "google-translate-api-x": "^10.7.1", "node-screenshots": "^0.2.2", "qrcode": "^1.5.4", + "sharp": "^0.33.5", "socket.io-client": "^4.8.1", "tesseract.js": "^5.1.1", "wrtc": "^0.4.7"