165 lines
4.7 KiB
JavaScript
165 lines
4.7 KiB
JavaScript
const { app, BrowserWindow, dialog, ipcMain } = require("electron");
|
|
const fs = require("node:fs/promises");
|
|
const path = require("node:path");
|
|
const { indexFolder } = require("./folderIndex.cjs");
|
|
const autoUpdate = require("./autoUpdate.cjs");
|
|
|
|
const { version: appVersion } = require("../package.json");
|
|
|
|
const DOCUMENT_EXTENSIONS = new Set([".pdf", ".tif", ".tiff", ".png", ".jpg", ".jpeg"]);
|
|
const APP_ICON = path.join(__dirname, "icon.png");
|
|
|
|
/** @type {BrowserWindow | null} */
|
|
let mainWindow = null;
|
|
|
|
function createWindow() {
|
|
const win = new BrowserWindow({
|
|
width: 1280,
|
|
height: 860,
|
|
minWidth: 1080,
|
|
minHeight: 720,
|
|
title: `IPSExtractor Desktop v${appVersion}`,
|
|
icon: APP_ICON,
|
|
backgroundColor: "#f6f7f9",
|
|
webPreferences: {
|
|
preload: path.join(__dirname, "preload.cjs"),
|
|
contextIsolation: true,
|
|
nodeIntegration: false,
|
|
},
|
|
});
|
|
mainWindow = win;
|
|
win.on("closed", () => {
|
|
if (mainWindow === win) mainWindow = null;
|
|
});
|
|
|
|
if (!app.isPackaged) {
|
|
win.loadURL("http://127.0.0.1:5173");
|
|
win.webContents.openDevTools({ mode: "detach" });
|
|
} else {
|
|
win.loadFile(path.join(app.getAppPath(), "dist", "index.html"));
|
|
}
|
|
}
|
|
|
|
function sendUpdateProgress(payload) {
|
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
|
mainWindow.webContents.send("updater:progress", payload);
|
|
}
|
|
}
|
|
|
|
ipcMain.handle("updater:check", async () => {
|
|
if (!app.isPackaged) {
|
|
return {
|
|
updateAvailable: false,
|
|
currentVersion: appVersion,
|
|
error: "Auto-update desactivado en desarrollo",
|
|
};
|
|
}
|
|
return autoUpdate.checkForUpdates();
|
|
});
|
|
|
|
ipcMain.handle("updater:install", async (_event, manifest) => {
|
|
if (!app.isPackaged) {
|
|
throw new Error("Auto-update solo disponible en la app instalada");
|
|
}
|
|
return autoUpdate.downloadAndInstall(manifest, sendUpdateProgress);
|
|
});
|
|
|
|
app.whenReady().then(() => {
|
|
if (process.platform === "win32") {
|
|
app.setAppUserModelId("com.ipsextractor.desktop");
|
|
}
|
|
createWindow();
|
|
app.on("activate", () => {
|
|
if (BrowserWindow.getAllWindows().length === 0) createWindow();
|
|
});
|
|
});
|
|
|
|
app.on("window-all-closed", () => {
|
|
if (process.platform !== "darwin") app.quit();
|
|
});
|
|
|
|
ipcMain.handle("dialog:select-directory", async () => {
|
|
const result = await dialog.showOpenDialog({
|
|
properties: ["openDirectory"],
|
|
});
|
|
if (result.canceled || result.filePaths.length === 0) return null;
|
|
return result.filePaths[0];
|
|
});
|
|
|
|
ipcMain.handle("runtime:config", async () => {
|
|
return {
|
|
documentRootLocal: process.env.IPS_DOCUMENT_ROOT || "",
|
|
documentRootContainer: process.env.IPS_DOCUMENT_ROOT_CONTAINER || "/data",
|
|
};
|
|
});
|
|
|
|
ipcMain.handle("dialog:save-csv", async (_event, defaultPath) => {
|
|
const result = await dialog.showSaveDialog({
|
|
defaultPath: defaultPath || "extraccion.csv",
|
|
filters: [{ name: "CSV", extensions: ["csv"] }],
|
|
});
|
|
if (result.canceled || !result.filePath) return null;
|
|
return result.filePath;
|
|
});
|
|
|
|
ipcMain.handle("file:write-text", async (_event, filePath, content) => {
|
|
await fs.writeFile(filePath, content, "utf8");
|
|
return { ok: true, filePath };
|
|
});
|
|
|
|
ipcMain.handle("fs:first-document", async (_event, rootPath, keywords) => {
|
|
const matches = await findDocuments(rootPath, Array.isArray(keywords) ? keywords : []);
|
|
return matches[0] || null;
|
|
});
|
|
|
|
ipcMain.handle("fs:index-folder", async (_event, rootPath, structureMode, docTypes, keywords) => {
|
|
if (!rootPath) return [];
|
|
return indexFolder(rootPath, structureMode, Array.isArray(docTypes) ? docTypes : [], Array.isArray(keywords) ? keywords : []);
|
|
});
|
|
|
|
ipcMain.handle("fs:read-file", async (_event, filePath) => {
|
|
const buffer = await fs.readFile(filePath);
|
|
return {
|
|
filename: path.basename(filePath),
|
|
size: buffer.byteLength,
|
|
data: buffer,
|
|
};
|
|
});
|
|
|
|
async function findDocuments(rootPath, keywords) {
|
|
const normalizedKeywords = keywords
|
|
.map((item) => String(item || "").trim().toLowerCase())
|
|
.filter(Boolean);
|
|
const out = [];
|
|
|
|
async function walk(dir) {
|
|
let entries;
|
|
try {
|
|
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
} catch {
|
|
return;
|
|
}
|
|
|
|
entries.sort((a, b) => a.name.localeCompare(b.name, undefined, { numeric: true }));
|
|
for (const entry of entries) {
|
|
const fullPath = path.join(dir, entry.name);
|
|
if (entry.isDirectory()) {
|
|
await walk(fullPath);
|
|
if (out.length > 0) return;
|
|
continue;
|
|
}
|
|
const ext = path.extname(entry.name).toLowerCase();
|
|
if (!DOCUMENT_EXTENSIONS.has(ext)) continue;
|
|
const lowerName = entry.name.toLowerCase();
|
|
if (normalizedKeywords.length > 0 && !normalizedKeywords.some((kw) => lowerName.includes(kw))) {
|
|
continue;
|
|
}
|
|
out.push(fullPath);
|
|
return;
|
|
}
|
|
}
|
|
|
|
await walk(rootPath);
|
|
return out;
|
|
}
|