GeminiBot commited on
Commit ·
ed3288f
1
Parent(s): adb9567
Fix Docker build dependencies and improve Canvas mock
Browse files- Dockerfile +12 -0
- src/duckai.ts +77 -23
Dockerfile
CHANGED
|
@@ -2,6 +2,18 @@ FROM oven/bun:latest
|
|
| 2 |
|
| 3 |
WORKDIR /app
|
| 4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
# Копируем всё содержимое папки duckai в /app
|
| 6 |
COPY . .
|
| 7 |
|
|
|
|
| 2 |
|
| 3 |
WORKDIR /app
|
| 4 |
|
| 5 |
+
# Install system dependencies required for canvas and node-gyp
|
| 6 |
+
RUN apt-get update && apt-get install -y \
|
| 7 |
+
python3 \
|
| 8 |
+
make \
|
| 9 |
+
g++ \
|
| 10 |
+
build-essential \
|
| 11 |
+
libcairo2-dev \
|
| 12 |
+
libpango1.0-dev \
|
| 13 |
+
libjpeg-dev \
|
| 14 |
+
libgif-dev \
|
| 15 |
+
librsvg2-dev
|
| 16 |
+
|
| 17 |
# Копируем всё содержимое папки duckai в /app
|
| 18 |
COPY . .
|
| 19 |
|
src/duckai.ts
CHANGED
|
@@ -27,29 +27,83 @@ export class DuckAI {
|
|
| 27 |
window.screen = { width: 1920, height: 1080, availWidth: 1920, availHeight: 1080 };
|
| 28 |
window.chrome = { runtime: {} };
|
| 29 |
|
| 30 |
-
//
|
| 31 |
-
window.HTMLCanvasElement.prototype.getContext
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
|
| 54 |
dom.window.top.__DDG_BE_VERSION__ = 1;
|
| 55 |
dom.window.top.__DDG_FE_CHAT_HASH__ = 1;
|
|
|
|
| 27 |
window.screen = { width: 1920, height: 1080, availWidth: 1920, availHeight: 1080 };
|
| 28 |
window.chrome = { runtime: {} };
|
| 29 |
|
| 30 |
+
// Robust Canvas Mock
|
| 31 |
+
const originalGetContext = window.HTMLCanvasElement.prototype.getContext;
|
| 32 |
+
window.HTMLCanvasElement.prototype.getContext = function (type: string, options?: any) {
|
| 33 |
+
// 1. Try real canvas if available
|
| 34 |
+
try {
|
| 35 |
+
const ctx = originalGetContext.call(this, type, options);
|
| 36 |
+
if (ctx) return ctx;
|
| 37 |
+
} catch (e) {}
|
| 38 |
+
|
| 39 |
+
// 2. Fallback Mock for missing canvas
|
| 40 |
+
return {
|
| 41 |
+
canvas: this,
|
| 42 |
+
fillRect: () => {},
|
| 43 |
+
clearRect: () => {},
|
| 44 |
+
getImageData: (x: number, y: number, w: number, h: number) => ({
|
| 45 |
+
data: new Uint8ClampedArray(w * h * 4),
|
| 46 |
+
width: w,
|
| 47 |
+
height: h
|
| 48 |
+
}),
|
| 49 |
+
putImageData: () => {},
|
| 50 |
+
createImageData: () => ({ data: new Uint8ClampedArray(4) }),
|
| 51 |
+
setTransform: () => {},
|
| 52 |
+
drawImage: () => {},
|
| 53 |
+
save: () => {},
|
| 54 |
+
restore: () => {},
|
| 55 |
+
beginPath: () => {},
|
| 56 |
+
moveTo: () => {},
|
| 57 |
+
lineTo: () => {},
|
| 58 |
+
closePath: () => {},
|
| 59 |
+
stroke: () => {},
|
| 60 |
+
translate: () => {},
|
| 61 |
+
scale: () => {},
|
| 62 |
+
rotate: () => {},
|
| 63 |
+
arc: () => {},
|
| 64 |
+
fill: () => {},
|
| 65 |
+
measureText: () => ({ width: 0, actualBoundingBoxAscent: 0, actualBoundingBoxDescent: 0 }),
|
| 66 |
+
transform: () => {},
|
| 67 |
+
rect: () => {},
|
| 68 |
+
clip: () => {},
|
| 69 |
+
createLinearGradient: () => ({ addColorStop: () => {} }),
|
| 70 |
+
createRadialGradient: () => ({ addColorStop: () => {} }),
|
| 71 |
+
createPattern: () => ({}),
|
| 72 |
+
bezierCurveTo: () => {},
|
| 73 |
+
quadraticCurveTo: () => {},
|
| 74 |
+
fillText: () => {},
|
| 75 |
+
strokeText: () => {},
|
| 76 |
+
|
| 77 |
+
// Properties
|
| 78 |
+
globalAlpha: 1,
|
| 79 |
+
globalCompositeOperation: 'source-over',
|
| 80 |
+
fillStyle: '#000000',
|
| 81 |
+
strokeStyle: '#000000',
|
| 82 |
+
lineWidth: 1,
|
| 83 |
+
lineCap: 'butt',
|
| 84 |
+
lineJoin: 'miter',
|
| 85 |
+
miterLimit: 10,
|
| 86 |
+
shadowOffsetX: 0,
|
| 87 |
+
shadowOffsetY: 0,
|
| 88 |
+
shadowBlur: 0,
|
| 89 |
+
shadowColor: 'rgba(0, 0, 0, 0)',
|
| 90 |
+
font: '10px sans-serif',
|
| 91 |
+
textAlign: 'start',
|
| 92 |
+
textBaseline: 'alphabetic'
|
| 93 |
+
};
|
| 94 |
+
} as any;
|
| 95 |
+
|
| 96 |
+
// Mock toDataURL to prevent failures if canvas is missing
|
| 97 |
+
const originalToDataURL = window.HTMLCanvasElement.prototype.toDataURL;
|
| 98 |
+
window.HTMLCanvasElement.prototype.toDataURL = function(type?: string, quality?: any) {
|
| 99 |
+
try {
|
| 100 |
+
const result = originalToDataURL.call(this, type, quality);
|
| 101 |
+
// If JSDOM implementation returns "data:," it means failure/not implemented in some versions
|
| 102 |
+
if (result && result !== "data:,") return result;
|
| 103 |
+
} catch(e) {}
|
| 104 |
+
// Return a 1x1 transparent pixel base64
|
| 105 |
+
return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
|
| 106 |
+
};
|
| 107 |
|
| 108 |
dom.window.top.__DDG_BE_VERSION__ = 1;
|
| 109 |
dom.window.top.__DDG_FE_CHAT_HASH__ = 1;
|