diff --git a/main.js b/main.js index a6729c1..65953da 100644 --- a/main.js +++ b/main.js @@ -1,68 +1,79 @@ // main.js -const { app, BrowserWindow } = require('electron'); +const { app, BrowserWindow, Menu } = require('electron'); const fs = require("fs"); +const fsp = require("fs").promises; const path = require("path"); const chokidar = require("chokidar"); const axios = require("axios"); -let OUT_DIR; // endgültiger Eingangsordner (wird in app.whenReady gesetzt) +let OUT_DIR; // Eingangsordner für ZPL let IMG_DIR; // Ausgabeordner für PNGs (History) - let win; +let watcher; +let busy = false; + +/* --- Fenstererstellung --- */ function createWindow() { win = new BrowserWindow({ width: 1000, height: 800, - webPreferences: { nodeIntegration: true, contextIsolation: false } + icon: path.join(__dirname, "assets/icon.ico"), + webPreferences: { nodeIntegration: true, contextIsolation: false }, + show: false // Fenster erst zeigen, wenn fertig }); + win.loadFile(path.join(__dirname, "index.html")); + win.once("ready-to-show", () => win.show()); + + // Menü entfernen (File, Edit usw.) + Menu.setApplicationMenu(null); } -app.whenReady().then(() => { - // Versuche zuerst C:\ZIR_Output (praktisch für Windows Local Port) +/* --- App Start --- */ +app.whenReady().then(async () => { const preferedRoot = "C:\\ZIR_Output"; let dataDir = app.getPath("userData"); // fallback try { - // Versuch: C:\ZIR_Output anlegen (falls möglich) - if (!fs.existsSync(preferedRoot)) { - fs.mkdirSync(preferedRoot, { recursive: true }); - } + await fsp.mkdir(preferedRoot, { recursive: true }); OUT_DIR = preferedRoot; - } catch (e) { - // Falls es schiefgeht (Rechte), fallback in userData + } catch { OUT_DIR = path.join(dataDir, "ZIR_Input"); + await fsp.mkdir(OUT_DIR, { recursive: true }); } - // IMG_DIR im userData (schützt vor Schreibrechten) IMG_DIR = path.join(dataDir, "zpl_out"); + await fsp.mkdir(IMG_DIR, { recursive: true }); - // Ordner anlegen, falls nicht existierend - try { if (!fs.existsSync(OUT_DIR)) fs.mkdirSync(OUT_DIR, { recursive: true }); } catch(e) {} - try { if (!fs.existsSync(IMG_DIR)) fs.mkdirSync(IMG_DIR, { recursive: true }); } catch(e) {} - - console.log("ZIR Input (Eingangsordner):", OUT_DIR); - console.log("ZIR Output (PNG-Ordner):", IMG_DIR); + console.log("ZIR Input:", OUT_DIR); + console.log("ZIR Output:", IMG_DIR); createWindow(); - const watcher = chokidar.watch(OUT_DIR, { ignoreInitial: true, awaitWriteFinish: {stabilityThreshold: 500, pollInterval: 100} }); - watcher.on("add", file => { - if (!file.toLowerCase().endsWith(".zpl")) return; - processFile(file); - }); - watcher.on("change", file => { - if (!file.toLowerCase().endsWith(".zpl")) return; - processFile(file); - }); - - app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow(); }); + // Watcher verzögert starten (macht Start schneller) + setTimeout(startWatcher, 300); }); -app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(); }); +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') app.quit(); +}); + +/* --- Watcher --- */ +function startWatcher() { + watcher = chokidar.watch(OUT_DIR, { + ignoreInitial: true, + awaitWriteFinish: { stabilityThreshold: 500, pollInterval: 100 } + }); + + watcher.on("add", file => { + if (file.toLowerCase().endsWith(".zpl")) processFile(file); + }); + watcher.on("change", file => { + if (file.toLowerCase().endsWith(".zpl")) processFile(file); + }); +} /* --- Helferfunktionen --- */ - function extractZPL(raw) { const start = raw.indexOf("^XA"); const end = raw.lastIndexOf("^XZ"); @@ -111,17 +122,15 @@ async function tryLabelaryRender(zpl, printerKey, widthInches, heightInches) { const resp = await axios.post(url, zpl, { headers: { "Accept": "image/png" }, responseType: "arraybuffer", - timeout: 15000 + timeout: 10000 }); return { ok: true, buffer: resp.data }; } catch (err) { - const status = err.response ? err.response.status : null; - return { ok: false, status, error: err.message }; + return { ok: false, status: err.response?.status, error: err.message }; } } /* --- Größen & Druckeroptionen --- */ - const STANDARD_SIZES = [ { w: 8.27, h: 11.69, name: "A4" }, { w: 8.5, h: 11, name: "Letter" }, @@ -138,7 +147,6 @@ const PRINTER_OPTIONS = [ ]; /* --- Hauptverarbeitung --- */ -let busy = false; async function processFile(filePath) { if (busy) { setTimeout(() => processFile(filePath), 400); @@ -147,16 +155,13 @@ async function processFile(filePath) { busy = true; try { - console.log("Verarbeite:", filePath); - let raw = fs.readFileSync(filePath, "utf-8"); + let raw = await fsp.readFile(filePath, "utf-8"); raw = cleanControlChars(raw); let zpl = extractZPL(raw); const { pw, ll } = parsePWLL(zpl); const { maxX, maxY } = parseMaxFO(zpl); - console.log("Parsed PW/LL:", pw, ll, "maxFO:", maxX, maxY); - // sizesToTry aufbauen (Priorität: PW/LL -> geschätzte große Formate -> Standardgrößen) const sizesToTry = []; if (pw && ll) { @@ -171,28 +176,27 @@ async function processFile(filePath) { } const estDefaultDPI = 203; - const estWIn = maxX ? dotsToInches(maxX + 100, estDefaultDPI) : null; // margin + const estWIn = maxX ? dotsToInches(maxX + 100, estDefaultDPI) : null; const estHIn = maxY ? dotsToInches(maxY + 100, estDefaultDPI) : null; - if (estWIn && estHIn) { - if (estWIn > 6 || estHIn > 8 || estWIn > 8 || estHIn > 6) { - for (const p of PRINTER_OPTIONS) { - sizesToTry.push({ w: 8.27, h: 11.69, printer: p, name: "A4" }); - sizesToTry.push({ w: 11.69, h: 8.27, printer: p, name: "A4_rot" }); - sizesToTry.push({ w: 8.5, h: 11, printer: p, name: "Letter" }); - sizesToTry.push({ w: 11, h: 8.5, printer: p, name: "Letter_rot" }); - } + if (estWIn && estHIn && (estWIn > 6 || estHIn > 8)) { + for (const p of PRINTER_OPTIONS) { + sizesToTry.push({ w: 8.27, h: 11.69, printer: p, name: "A4" }); + sizesToTry.push({ w: 11.69, h: 8.27, printer: p, name: "A4_rot" }); + sizesToTry.push({ w: 8.5, h: 11, printer: p, name: "Letter" }); + sizesToTry.push({ w: 11, h: 8.5, printer: p, name: "Letter_rot" }); } } for (const p of PRINTER_OPTIONS) { for (const s of STANDARD_SIZES) { - const exists = sizesToTry.some(x => Math.abs(x.w - s.w) < 0.01 && Math.abs(x.h - s.h) < 0.01 && x.printer.key === p.key); - if (!exists) sizesToTry.push({ w: s.w, h: s.h, printer: p, name: s.name || `${s.w}x${s.h}` }); + const exists = sizesToTry.some(x => + Math.abs(x.w - s.w) < 0.01 && Math.abs(x.h - s.h) < 0.01 && x.printer.key === p.key + ); + if (!exists) sizesToTry.push({ w: s.w, h: s.h, printer: p, name: s.name }); } } - // Duplikate entfernen & Reihenfolge behalten const uniqSizes = []; const seen = new Set(); for (const s of sizesToTry) { @@ -200,38 +204,29 @@ async function processFile(filePath) { if (!seen.has(key)) { seen.add(key); uniqSizes.push(s); } } - // Versuche rendern let renderResult = null; for (const s of uniqSizes) { - const wStr = fmtInches(s.w); - const hStr = fmtInches(s.h); - console.log(`Versuche rendern: printer=${s.printer.key} size=${wStr}x${hStr} (${s.name || ""})`); - renderResult = await tryLabelaryRender(zpl, s.printer.key, wStr, hStr); - if (renderResult.ok) { console.log(`Erfolg mit ${s.printer.key} ${wStr}x${hStr}`); break; } - else { console.log(`Fehler (${renderResult.status}) mit ${s.printer.key} ${wStr}x${hStr}`); } + renderResult = await tryLabelaryRender(zpl, s.printer.key, fmtInches(s.w), fmtInches(s.h)); + if (renderResult.ok) break; } - if (!renderResult || !renderResult.ok) { - console.error("Alle Render-Versuche fehlgeschlagen, Abbruch."); + if (!renderResult?.ok) { + console.error("Rendering fehlgeschlagen"); busy = false; return; } - // PNG speichern — neue Datei mit Timestamp (History) const pngBuffer = renderResult.buffer; const timestamp = Date.now(); const outFile = path.join(IMG_DIR, `label-${timestamp}.png`); - fs.writeFileSync(outFile, pngBuffer); - console.log("PNG erstellt:", outFile); + await fsp.writeFile(outFile, pngBuffer); - // ZPL-Datei löschen (optional) - try { fs.unlinkSync(filePath); } catch(e){ console.warn("Konnte ZPL nicht löschen:", e.message); } + try { await fsp.unlink(filePath); } catch {} - // Fenster benachrichtigen (sende neuen PNG-Pfad) win.webContents.send("show-png", outFile); } catch (err) { - console.error("Fehler beim Rendern:", err && err.message ? err.message : err); + console.error("Fehler beim Rendern:", err.message); } finally { busy = false; }