리펙토링: Node.js 프로젝트 폴더 구조 적용

This commit is contained in:
2026-05-14 11:01:11 +09:00
parent 65ac35929a
commit dcd3c9a6e9
13 changed files with 4 additions and 4 deletions
+74
View File
@@ -0,0 +1,74 @@
const { ipcMain } = require('electron');
const path = require('path');
const fs = require('fs');
const EXTS = new Set(['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.tif', '.webp', '.heic', '.heif']);
function register() {
ipcMain.handle('list-images', async (_event, folderPath) => {
try {
const files = fs.readdirSync(folderPath)
.filter(f => EXTS.has(path.extname(f).toLowerCase()))
.map(f => {
const fullPath = path.join(folderPath, f);
const stat = fs.statSync(fullPath);
return { name: f, path: fullPath, mtime: stat.mtimeMs, size: stat.size };
})
.sort((a, b) => a.name.localeCompare(b.name, 'ko'));
return files;
} catch (e) {
return [];
}
});
ipcMain.handle('read-image', async (_event, filePath) => {
try {
const data = fs.readFileSync(filePath);
const ext = path.extname(filePath).toLowerCase().replace('.', '');
const mime = (ext === 'jpg' || ext === 'jpeg') ? 'jpeg'
: ext === 'png' ? 'png'
: ext === 'gif' ? 'gif'
: ext === 'webp' ? 'webp'
: 'jpeg';
return `data:image/${mime};base64,${data.toString('base64')}`;
} catch (e) {
return null;
}
});
ipcMain.handle('rename-files', async (_event, { folderPath, files, prefix, digits }) => {
const errors = [];
const pad = (n) => String(n + 1).padStart(digits, '0');
// 1단계: 임시 이름으로 이동 (충돌 방지)
const tmpMap = [];
for (let i = 0; i < files.length; i++) {
const src = files[i].path;
const ext = path.extname(files[i].name).toLowerCase();
const tmp = path.join(folderPath, `__tmp_rename_${i}_${Date.now()}${ext}`);
try {
fs.renameSync(src, tmp);
tmpMap.push({ tmp, ext, idx: i });
} catch (e) {
errors.push(`${files[i].name}: ${e.message}`);
}
}
// 2단계: 최종 이름으로 이동
const renamed = [];
for (const { tmp, ext, idx } of tmpMap) {
const newName = `${prefix}_${pad(idx)}${ext}`;
const dest = path.join(folderPath, newName);
try {
fs.renameSync(tmp, dest);
renamed.push({ oldPath: tmp, newPath: dest, newName });
} catch (e) {
errors.push(`${newName}: ${e.message}`);
}
}
return { renamed, errors };
});
}
module.exports = { register };
+18
View File
@@ -0,0 +1,18 @@
const { ipcMain, dialog, shell } = require('electron');
function register(mainWindow) {
ipcMain.handle('select-folder', async () => {
const result = await dialog.showOpenDialog(mainWindow, {
properties: ['openDirectory'],
title: '이미지 폴더 선택',
});
if (result.canceled) return null;
return result.filePaths[0];
});
ipcMain.handle('reveal-folder', async (_event, folderPath) => {
shell.openPath(folderPath);
});
}
module.exports = { register };
+9
View File
@@ -0,0 +1,9 @@
const folder = require('./folder');
const files = require('./files');
function registerAll(mainWindow) {
folder.register(mainWindow);
files.register();
}
module.exports = { registerAll };