diff --git a/Dockerfile b/Dockerfile index c794dbd..6cb7013 100644 --- a/Dockerfile +++ b/Dockerfile @@ -588,8 +588,15 @@ EXPOSE 3000/tcp # ============================================================================== # 環境變數 # ============================================================================== -# Calibre 需要 +# Headless 環境設定(解決 GTK/Qt 在無 DISPLAY 環境的問題) +# ⚠️ 某些 GUI 工具(Inkscape、Calibre、LibreOffice)需要這些設定 +ENV QT_QPA_PLATFORM="offscreen" +ENV DISPLAY=":99" + +# Calibre 需要(禁用 Chromium sandbox,Docker 環境無法使用) ENV QTWEBENGINE_CHROMIUM_FLAGS="--no-sandbox" +ENV CALIBRE_USE_SYSTEM_THEME="0" + # Pandoc PDF 引擎(使用 pdflatex 以獲得最佳相容性) ENV PANDOC_PDF_ENGINE=pdflatex # Node 環境 diff --git a/src/converters/calibre.ts b/src/converters/calibre.ts index 1d06695..c69b39f 100644 --- a/src/converters/calibre.ts +++ b/src/converters/calibre.ts @@ -58,6 +58,17 @@ export const properties = { }, }; +/** + * Calibre ebook-convert 轉換器 + * + * ⚠️ Headless 環境注意事項: + * Calibre 是 Qt 應用,某些操作需要 display。 + * 使用 xvfb-run 確保在無 DISPLAY 環境下也能運作。 + * + * 環境變數設定(Dockerfile): + * QT_QPA_PLATFORM=offscreen + * QTWEBENGINE_CHROMIUM_FLAGS="--no-sandbox" + */ export async function convert( filePath: string, fileType: string, @@ -67,7 +78,16 @@ export async function convert( execFile: ExecFileFn = execFileOriginal, // to make it mockable ): Promise { return new Promise((resolve, reject) => { - execFile("ebook-convert", [filePath, targetPath], (error, stdout, stderr) => { + // 使用 xvfb-run 包裝 ebook-convert,確保在無 DISPLAY 環境下也能運作 + const args = [ + "-a", + "--server-args=-screen 0 1024x768x24", + "ebook-convert", + filePath, + targetPath, + ]; + + execFile("xvfb-run", args, (error, stdout, stderr) => { if (error) { reject(`error: ${error}`); }