diff --git a/main.js b/main.js index 062159a..8825317 100644 --- a/main.js +++ b/main.js @@ -1,5 +1,7 @@ -const { app, BrowserWindow, ipcMain, dialog } = require('electron'); +const { app, BrowserWindow, ipcMain, dialog, session } = require('electron'); const path = require('path'); +const fs = require('fs'); +const https = require('https'); let store; let mainWindow; @@ -8,9 +10,11 @@ let mainWindow; (async () => { const Store = await import('electron-store'); store = new Store.default(); + console.log('Store initialized'); })(); function createWindow() { + console.log('Creating main window...'); mainWindow = new BrowserWindow({ width: 1200, height: 800, @@ -21,8 +25,79 @@ function createWindow() { } }); + // Set up network request monitoring + console.log('Setting up network request monitoring...'); + session.defaultSession.webRequest.onBeforeRequest( + { urls: ['*://*.onedrive.com/*', '*://*.1drv.com/*', '*://*.microsoftpersonalcontent.com/*'] }, + (details, callback) => { + console.log('Intercepted request:', details.url); + // Check if this is a video request (typically .mov for Live Photos) + if (details.url.toLowerCase().includes('.mov') || details.url.toLowerCase().includes('mp4')) { + console.log('✓ Detected video URL:', details.url); + if (store) { + const destFolder = store.get('destFolder', ''); + if (destFolder) { + // Extract item ID from URL + const urlObj = new URL(details.url); + const pathParts = urlObj.pathname.split('/'); + const itemIndex = pathParts.findIndex(part => part === 'items'); + const itemId = itemIndex !== -1 ? pathParts[itemIndex + 1] : null; + + // Create filename with item ID and extension + const extension = details.url.toLowerCase().includes('.mov') ? '.mov' : '.mp4'; + const filename = itemId ? `${itemId}${extension}` : `video_${Date.now()}${extension}`; + + console.log('Downloading video as:', filename); + console.log('To folder:', destFolder); + downloadVideo(details.url, path.join(destFolder, filename)); + } else { + console.warn('⚠ No destination folder configured'); + } + } else { + console.error('⚠ Store not initialized'); + } + } + callback({ cancel: false }); + } + ); + mainWindow.loadFile(path.join(__dirname, 'renderer/index.html')); mainWindow.setTitle('OneDrive Photos'); + console.log('Main window created and loaded'); +} + +function downloadVideo(url, filepath) { + console.log('Starting video download:', url); + console.log('Save path:', filepath); + + const dir = path.dirname(filepath); + if (!fs.existsSync(dir)) { + console.log('Creating directory:', dir); + fs.mkdirSync(dir, { recursive: true }); + } + + const file = fs.createWriteStream(filepath); + https.get(url, (response) => { + console.log('Download started, status:', response.statusCode); + console.log('Content type:', response.headers['content-type']); + console.log('Content length:', response.headers['content-length']); + + response.pipe(file); + file.on('finish', () => { + file.close(); + console.log('✓ Video saved successfully:', filepath); + mainWindow.webContents.send('video-saved', { + filename: path.basename(filepath), + path: filepath + }); + }); + }).on('error', (err) => { + console.error('⚠ Download error:', err); + fs.unlink(filepath, () => { + console.log('Cleaned up failed download file'); + }); + mainWindow.webContents.send('video-save-error', err.message); + }); } app.whenReady().then(createWindow); @@ -39,26 +114,34 @@ app.on('activate', () => { } }); -// Modified IPC handlers +// IPC Handlers with debug logs ipcMain.on('toggle-config', () => { + console.log('Toggle config panel requested'); mainWindow.webContents.send('toggle-config'); }); ipcMain.on('set-config', (event, config) => { + console.log('Saving configuration:', config); if (store) { store.set('destFolder', config.destFolder); store.set('onedriveSource', config.onedriveSource); - console.log('Configuration saved:', config); + console.log('✓ Configuration saved successfully'); + } else { + console.error('⚠ Store not initialized, cannot save config'); } }); ipcMain.on('load-config', (event) => { + console.log('Loading configuration...'); if (store) { const config = { destFolder: store.get('destFolder', ''), onedriveSource: store.get('onedriveSource', '') }; + console.log('Configuration loaded:', config); event.reply('config-loaded', config); + } else { + console.error('⚠ Store not initialized, cannot load config'); } }); diff --git a/renderer/renderer.js b/renderer/renderer.js index 60616f4..9fcc3f1 100644 --- a/renderer/renderer.js +++ b/renderer/renderer.js @@ -2,36 +2,54 @@ const { ipcRenderer } = require('electron'); // Wait for webview to load const webview = document.getElementById('main-content'); +console.log('Setting up webview event listeners...'); + +webview.addEventListener('did-start-loading', () => { + console.log('Webview started loading'); +}); + webview.addEventListener('did-finish-load', () => { + console.log('Webview finished loading'); // Create and add the configuration button + console.log('Creating configuration button'); const button = document.createElement('button'); button.id = 'config-button'; button.innerHTML = ' Configuration'; document.body.appendChild(button); + console.log('Configuration button added to DOM'); - // Add click handler to the dynamically created button button.addEventListener('click', () => { + console.log('Configuration button clicked'); ipcRenderer.send('toggle-config'); }); }); +webview.addEventListener('did-fail-load', (event) => { + console.error('Webview failed to load:', event); +}); + // Configuration panel toggle ipcRenderer.on('toggle-config', () => { + console.log('Toggling configuration panel'); const panel = document.getElementById('config-panel'); + const isOpening = !panel.classList.contains('open'); panel.classList.toggle('open'); + console.log(isOpening ? 'Panel opened' : 'Panel closed'); - // Load saved config when panel opens - if (panel.classList.contains('open')) { + if (isOpening) { + console.log('Loading saved configuration...'); ipcRenderer.send('load-config'); } }); // Folder selection document.getElementById('select-folder').addEventListener('click', () => { + console.log('Folder selection requested'); ipcRenderer.send('select-folder'); }); ipcRenderer.on('folder-selected', (event, path) => { + console.log('Folder selected:', path); document.getElementById('dest-folder').value = path; }); @@ -40,18 +58,46 @@ document.getElementById('config-form').addEventListener('submit', (event) => { event.preventDefault(); const destFolder = document.getElementById('dest-folder').value; const onedriveSource = document.getElementById('onedrive-source').value; + console.log('Saving configuration:', { destFolder, onedriveSource }); ipcRenderer.send('set-config', { destFolder, onedriveSource }); - // Close the panel after saving - document.getElementById('config-panel').classList.remove('open'); -}); - -// Close button handler -document.getElementById('close-config').addEventListener('click', () => { document.getElementById('config-panel').classList.remove('open'); + console.log('Configuration panel closed'); }); // Config loaded handler ipcRenderer.on('config-loaded', (event, config) => { + console.log('Received saved configuration:', config); document.getElementById('dest-folder').value = config.destFolder; document.getElementById('onedrive-source').value = config.onedriveSource; -}); \ No newline at end of file +}); + +// Video handling +ipcRenderer.on('video-saved', (event, { filename, path }) => { + console.log('✓ Video saved successfully:', { filename, path }); + showStatus(`Saved: ${filename}`); +}); + +ipcRenderer.on('video-save-error', (event, error) => { + console.error('⚠ Video save error:', error); + showStatus(`Error: ${error}`, true); +}); + +function showStatus(message, isError = false) { + console.log(`Showing status: ${message} (${isError ? 'error' : 'success'})`); + const statusDiv = document.getElementById('status-display') || createStatusDisplay(); + statusDiv.textContent = message; + statusDiv.className = `show ${isError ? 'error' : 'success'}`; + + // Reset animation + statusDiv.style.animation = 'none'; + statusDiv.offsetHeight; + statusDiv.style.animation = null; +} + +function createStatusDisplay() { + console.log('Creating status display element'); + const div = document.createElement('div'); + div.id = 'status-display'; + document.body.appendChild(div); + return div; +} \ No newline at end of file diff --git a/renderer/styles.css b/renderer/styles.css index 938868b..43be84f 100644 --- a/renderer/styles.css +++ b/renderer/styles.css @@ -186,3 +186,35 @@ body { .submit-button:active { background: #005a9e; } + +#status-display { + position: fixed; + bottom: 20px; + right: 20px; + padding: 10px 20px; + border-radius: 4px; + font-size: 14px; + z-index: 1002; + display: none; +} + +#status-display.show { + display: block; + animation: fadeOut 3s forwards; +} + +#status-display.success { + background: rgba(0, 120, 212, 0.9); + color: white; +} + +#status-display.error { + background: rgba(232, 17, 35, 0.9); + color: white; +} + +@keyframes fadeOut { + 0% { opacity: 1; } + 70% { opacity: 1; } + 100% { opacity: 0; } +}