Skip to content

Commit

Permalink
2.2.25 dev (#40)
Browse files Browse the repository at this point in the history
* color picking fix

* us ethumbnail for img color detection not working

* win10 tested thumbnail path + color pallete thumbnail

* search fixed

* render stop

* updated version
  • Loading branch information
MartinBarker authored Feb 4, 2025
1 parent 70e1f3e commit 41ebe93
Show file tree
Hide file tree
Showing 9 changed files with 1,425 additions and 584 deletions.
154 changes: 122 additions & 32 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import readline from 'readline';
import musicMetadata from 'music-metadata';
import sizeOf from 'image-size';
import os from 'node:os';
import { Vibrant } from 'node-vibrant/node';

const { autoUpdater } = pkg;
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

let mainWindow;
let ffmpegProcesses = new Map();

// disable gpu acceleration
app.disableHardwareAcceleration();
Expand All @@ -24,6 +26,22 @@ app.disableHardwareAcceleration();
const audioExtensions = ['mp3', 'wav', 'flac', 'ogg', 'm4a', 'aac', 'aiff', 'wma', 'amr', 'opus', 'alac', 'pcm', 'mid', 'midi', 'aif', 'caf'];
const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff', 'webp', 'heif', 'heic', 'ico', 'svg', 'raw', 'cr2', 'nef', 'orf', 'arw', 'raf', 'dng', 'pef', 'sr2'];

const thumbnailCacheDir = path.join(os.tmpdir(), 'RenderTune-thumbnails');
if (!fs.existsSync(thumbnailCacheDir)) {
fs.mkdirSync(thumbnailCacheDir, { recursive: true });
}
console.log(`Thumbnail cache directory is set to: ${thumbnailCacheDir}`);

const thumbnailMapPath = path.join(thumbnailCacheDir, 'thumbnails.json');
let thumbnailMap = {};
if (fs.existsSync(thumbnailMapPath)) {
thumbnailMap = JSON.parse(fs.readFileSync(thumbnailMapPath, 'utf-8'));
}

function saveThumbnailMap() {
fs.writeFileSync(thumbnailMapPath, JSON.stringify(thumbnailMap, null, 2));
}

// Custom protocol registration
protocol.registerSchemesAsPrivileged([
{ scheme: 'app', privileges: { secure: true, standard: true } },
Expand All @@ -44,39 +62,56 @@ app.whenReady().then(() => {
console.log('Thumbnail request for:', url);

try {

const fallbackImage = nativeImage.createFromPath(url).resize({ width: 200 });
const thumbnailPath = path.join(thumbnailCacheDir, path.basename(url));
console.log('Generated thumbnail path:', thumbnailPath);

callback({
mimeType: 'image/png',
data: fallbackImage.toPNG(),
});


/* //https://github.com/electron/electron/issues/45102
if (!fs.existsSync(url)) {
throw new Error(`File not found: ${url}`);
}
const thumbnailSize = { width: 200, height: 200 }; // Only width matters on Windows
const thumbnail = await nativeImage.createThumbnailFromPath(url, { width: thumbnailSize.width });
callback({
mimeType: 'image/png',
data: thumbnail.toPNG(),
});
*/
} catch (error) {
console.error('Error generating thumbnail:', error);
// Provide an empty buffer and a valid MIME type to avoid breaking the app
callback({
mimeType: 'image/png',
data: Buffer.alloc(0), // Empty image buffer
});
}
});

ipcMain.on('get-color-palette', async (event, imagePath) => {
try {
console.log('Received request to get color palette for:', imagePath);

const thumbnailPath = thumbnailMap[imagePath] || imagePath;
console.log('Fetching color info using thumbnail path:', thumbnailPath);
const swatches = await Vibrant.from(thumbnailPath).getPalette();
let colors = {};

for (const [key, value] of Object.entries(swatches)) {
if (value) { // Ensure the swatch is not null/undefined
const rgbColor = value.rgb;
const hexColor = rgbToHex(rgbColor);
colors[key] = { hex: hexColor, rgb: rgbColor };
}
}

console.log('Extracted color palette:', colors.Vibrant.hex);
event.reply(`color-palette-response-${imagePath}`, colors);
} catch (error) {
console.error('Error extracting color palette:', error);
event.reply(`color-palette-response-${imagePath}`, {});
}
});

// Helper function to convert RGB array to HEX
function rgbToHex(rgb) {
return `#${rgb.map((x) => x.toString(16).padStart(2, '0')).join('')}`;
}


createWindow();

// Content security policy
Expand Down Expand Up @@ -117,23 +152,23 @@ function createWindow() {
});

// load window

mainWindow.loadURL(
app.isPackaged ? `file://${path.join(__dirname, "../build/index.html")}` :
'http://localhost:3000'
);
/*
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: path.join(__dirname, '../build/index.html'),
protocol: 'file:',
slashes: true
});
mainWindow.loadURL(startUrl);
app.isPackaged ? `file://${path.join(__dirname, "../build/index.html")}` :
'http://localhost:3000'
);

/*
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: path.join(__dirname, '../build/index.html'),
protocol: 'file:',
slashes: true
});
mainWindow.loadURL(startUrl);
*/

// macos only
//mainWindow.loadURL(`file://${path.join(__dirname, '../build/index.html')}`);
// macos only
//mainWindow.loadURL(`file://${path.join(__dirname, '../build/index.html')}`);


// Open the DevTools if in development mode
Expand Down Expand Up @@ -178,6 +213,8 @@ ipcMain.on('run-ffmpeg-command', async (event, ffmpegArgs) => {
}

const process = execa(ffmpegPath, cmdArgsList);
ffmpegProcesses.set(renderId, process); // Store the process

const rl = readline.createInterface({ input: process.stderr });

let progress = 0;
Expand Down Expand Up @@ -206,8 +243,19 @@ ipcMain.on('run-ffmpeg-command', async (event, ffmpegArgs) => {
}
});

const result = await process;
event.reply('ffmpeg-output', { stdout: result.stdout, progress: 100 });
process.on('exit', (code, signal) => {
if (signal === 'SIGTERM') {
console.log(`FFmpeg process with ID: ${renderId} was stopped by user`);
event.reply('ffmpeg-stop-response', { renderId, status: 'Stopped' });
} else if (code === 0) {
ffmpegProcesses.delete(renderId); // Remove the process when done
event.reply('ffmpeg-output', { stdout: process.stdout, progress: 100 });
} else {
const errorOutput = process.stderr ? process.stderr.split('\n').slice(-10).join('\n') : 'No error details';
event.reply('ffmpeg-error', { message: `FFmpeg exited with code ${code}`, lastOutput: errorOutput, ffmpegPath: getFfmpegPath() });
}
});

} catch (error) {
console.error('FFmpeg command failed:', error.message);
if (!app.isPackaged) {
Expand All @@ -218,10 +266,38 @@ ipcMain.on('run-ffmpeg-command', async (event, ffmpegArgs) => {
}
});

ipcMain.on('stop-ffmpeg-render', (event, { renderId }) => {
console.log(`Received request to stop FFmpeg render with ID: ${renderId}`);
const process = ffmpegProcesses.get(renderId);
if (process) {
console.log(`Stopping FFmpeg process with PID: ${process.pid}`);
process.kill('SIGTERM');
ffmpegProcesses.delete(renderId);
console.log(`FFmpeg process with ID: ${renderId} stopped successfully`);
event.reply('ffmpeg-stop-response', { renderId, status: 'Stopped' });
} else {
console.log(`Error: FFmpeg process with ID: ${renderId} not found`);
event.reply('ffmpeg-stop-response', { renderId, status: 'Error: Process not found' });
}
});

ipcMain.on('delete-render-file', async (event, { outputFilePath }) => {
try {
if (fs.existsSync(outputFilePath)) {
fs.unlinkSync(outputFilePath);
console.log(`Deleted file: ${outputFilePath}`);
} else {
console.log(`File not found: ${outputFilePath}`);
}
} catch (error) {
console.error(`Error deleting file: ${outputFilePath}`, error);
}
});

// Function to determine FFmpeg path
function getFfmpegPath() {
console.log('getFfmpegPath()')

var arch = os.arch();
var platform = process.platform;

Expand Down Expand Up @@ -287,6 +363,13 @@ ipcMain.on('open-folder-dialog', async (event) => {
}
});

ipcMain.on('set-output-folder', (event, folderPath) => {
event.reply('output-folder-set', folderPath);
});
ipcMain.on('set-output-folder', (event, folderPath) => {
event.reply('output-folder-set', folderPath);
});

ipcMain.on('open-file-dialog', async (event) => {

try {
Expand All @@ -301,6 +384,7 @@ ipcMain.on('open-file-dialog', async (event) => {
const ext = path.extname(normalizedPath).toLowerCase().substring(1);
let fileType = 'other';
let dimensions = null;
let thumbnailPath = null;

if (audioExtensions.includes(ext)) {
fileType = 'audio';
Expand All @@ -309,6 +393,11 @@ ipcMain.on('open-file-dialog', async (event) => {
try {
const metadata = sizeOf(normalizedPath);
dimensions = `${metadata.width}x${metadata.height}`;
const image = nativeImage.createFromPath(normalizedPath).resize({ width: 100, height: 100 });
thumbnailPath = path.join(thumbnailCacheDir, path.basename(normalizedPath));
fs.writeFileSync(thumbnailPath, image.toPNG());
thumbnailMap[normalizedPath] = thumbnailPath;
saveThumbnailMap();
} catch (error) {
console.error('Error reading image dimensions:', error);
}
Expand All @@ -319,6 +408,7 @@ ipcMain.on('open-file-dialog', async (event) => {
filepath: normalizedPath,
filetype: fileType,
dimensions,
thumbnailPath,
};
})
);
Expand Down
14 changes: 8 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "RenderTune",
"version": "1.1.48",
"version": "1.1.49",
"description": "My Electron app",
"type": "module",
"main": "main.js",
Expand Down Expand Up @@ -212,7 +212,7 @@
}
],
"signAndEditExecutable": true,
"icon": "icon-build/app.ico"
"icon": "icon-build/app.ico"
},
"linux": {
"executableName": "rendertune",
Expand Down Expand Up @@ -263,6 +263,7 @@
"@tanstack/react-table": "^8.20.6",
"axios": "^1.7.9",
"cross-env": "^7.0.3",
"electron-reload": "^2.0.0-alpha.1",
"electron-serve": "^2.1.1",
"electron-updater": "^6.3.9",
"execa": "^9.5.2",
Expand All @@ -271,26 +272,27 @@
"i18next-fs-backend": "^2.6.0",
"image-size": "^1.2.0",
"music-metadata-browser": "^2.5.11",
"node-vibrant": "^4.0.3",
"nth-check": "^2.0.1",
"postcss": "^8.4.49",
"react-router-dom": "^7.0.2",
"readline": "^1.3.0"
},
"devDependencies": {
"icon-gen": "^4.0.0",
"sharp": "^0.32.6",
"concurrently": "^9.1.0",
"cross-spawn": "^7.0.5",
"electron": "^33.2.1",
"electron-builder": "^25.1.8",
"eslint": "^9.16.0",
"icon-gen": "^4.0.0",
"os-browserify": "^0.3.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-scripts": "^5.0.1",
"rimraf": "^5.0.0",
"sharp": "^0.32.6",
"tsx": "^4.19.2",
"wait-on": "^8.0.1",
"rimraf": "^5.0.0"
"wait-on": "^8.0.1"
},
"browserslist": {
"production": [
Expand Down
12 changes: 9 additions & 3 deletions preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ contextBridge.exposeInMainWorld('api', {
'get-audio-metadata',
'open-file-dialog',
'open-folder-dialog',
'get-path-separator'
'get-path-separator',
'set-output-folder',
'get-color-palette',
'stop-ffmpeg-render',
'delete-render-file'
];
if (validSendChannels.includes(channel)) {
ipcRenderer.send(channel, data);
Expand All @@ -27,9 +31,11 @@ contextBridge.exposeInMainWorld('api', {
'selected-file-paths',
'selected-folder',
'path-separator-response',
'ffmpeg-progress'
'ffmpeg-progress',
'output-folder-set',
'ffmpeg-stop-response'
];
if (validReceiveChannels.includes(channel)) {
if (validReceiveChannels.includes(channel) || channel.startsWith('color-palette-response-')) {
ipcRenderer.on(channel, (event, ...args) => func(...args));
}
},
Expand Down
5 changes: 5 additions & 0 deletions src/FileUploader/FileUploader.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ const FileUploader = ({ onFilesMetadata }) => {
}
});

if (filesArray.length > 0) {
const firstFileFolder = filesArray[0].filepath.replace(/\\/g, '/').split('/').slice(0, -1).join('/');
window.api.send('set-output-folder', firstFileFolder);
}

// Pass the files metadata to the parent component
onFilesMetadata(filesArray);
};
Expand Down
Loading

0 comments on commit 41ebe93

Please sign in to comment.