Refactor sync process to handle video items and improve error handling
- Updated 'start-sync' IPC event to process video files from OneDrive, filtering for .mov and .mp4 formats. - Enhanced logging to provide feedback on the number of video items found and downloaded. - Integrated Graph API client to retrieve folder contents before initiating sync. - Improved error handling for sync operations and added user feedback for sync completion and errors. - Updated renderer.js to manage button states during the sync process.
This commit is contained in:
parent
dec8e60a2f
commit
27e77d2998
73
main.js
73
main.js
|
|
@ -205,63 +205,36 @@ ipcMain.on('select-folder', (event) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('start-sync', async (event, config) => {
|
ipcMain.on('start-sync', async (event, { destFolder, onedriveSource, items }) => {
|
||||||
console.log('Starting sync with config:', config);
|
console.log('Starting sync with config:', { destFolder, onedriveSource });
|
||||||
|
console.log(`Processing ${items.length} items...`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get cookies from all relevant domains
|
// Filter for video files (Live Photos)
|
||||||
const cookies = await Promise.all([
|
const videoItems = items.filter(item =>
|
||||||
session.defaultSession.cookies.get({domain: '.onedrive.com'}),
|
item.name.toLowerCase().endsWith('.mov') ||
|
||||||
session.defaultSession.cookies.get({domain: '.live.com'}),
|
item.name.toLowerCase().endsWith('.mp4')
|
||||||
session.defaultSession.cookies.get({domain: '.microsoft.com'})
|
);
|
||||||
]);
|
|
||||||
|
|
||||||
const allCookies = [].concat(...cookies);
|
|
||||||
console.log('Available cookies:', allCookies.map(c => c.name));
|
|
||||||
|
|
||||||
// Try different possible token cookie names
|
console.log(`Found ${videoItems.length} video items`);
|
||||||
const accessToken = allCookies.find(
|
|
||||||
cookie =>
|
|
||||||
cookie.name === 'access_token' ||
|
|
||||||
cookie.name === 'AccessToken' ||
|
|
||||||
cookie.name.startsWith('AccessToken-') ||
|
|
||||||
cookie.name.includes('Graph')
|
|
||||||
)?.value;
|
|
||||||
|
|
||||||
if (!accessToken) {
|
// Process each video item
|
||||||
throw new Error('Access token not found in cookies');
|
for (const item of videoItems) {
|
||||||
}
|
if (item['@microsoft.graph.downloadUrl']) {
|
||||||
|
const filename = `${item.id}${path.extname(item.name)}`;
|
||||||
// Clean up and encode the OneDrive path
|
const filepath = path.join(destFolder, filename);
|
||||||
const cleanPath = config.onedriveSource
|
|
||||||
.replace(/^\/+|\/+$/g, '') // Remove leading/trailing slashes
|
console.log(`Downloading: ${item.name} as ${filename}`);
|
||||||
.split('/')
|
await downloadVideo(item['@microsoft.graph.downloadUrl'], filepath);
|
||||||
.map(segment => encodeURIComponent(segment))
|
} else {
|
||||||
.join('/');
|
console.warn(`No download URL for item: ${item.name}`);
|
||||||
|
|
||||||
const url = `https://graph.microsoft.com/v1.0/me/drive/root:/${cleanPath}:/children`;
|
|
||||||
console.log('Querying OneDrive items from:', url);
|
|
||||||
|
|
||||||
// Query OneDrive items using Graph API
|
|
||||||
const response = await fetch(url, {
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${accessToken}`,
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Origin': 'https://onedrive.live.com',
|
|
||||||
'Referer': 'https://onedrive.live.com/'
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json();
|
|
||||||
console.error('Graph API error details:', errorData);
|
|
||||||
throw new Error(`Graph API error: ${response.status} ${response.statusText}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
event.reply('sync-complete', {
|
||||||
console.log('Found items:', data.value.length);
|
totalItems: items.length,
|
||||||
|
videoItems: videoItems.length
|
||||||
event.reply('sync-items-found', data.value);
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Sync error:', error);
|
console.error('Sync error:', error);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
const { session } = require('electron');
|
||||||
|
|
||||||
|
class GraphApiClient {
|
||||||
|
constructor() {
|
||||||
|
this.baseUrl = 'https://graph.microsoft.com/v1.0';
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAccessToken() {
|
||||||
|
// Get cookies from all relevant domains
|
||||||
|
// return a fake token for now
|
||||||
|
return 'fake-token';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanPath(path) {
|
||||||
|
return path
|
||||||
|
.replace(/^\/+|\/+$/g, '') // Remove leading/trailing slashes
|
||||||
|
.split('/')
|
||||||
|
.map(segment => encodeURIComponent(segment))
|
||||||
|
.join('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
async listFolderContents(folderPath) {
|
||||||
|
try {
|
||||||
|
const accessToken = await this.getAccessToken();
|
||||||
|
const cleanPath = this.cleanPath(folderPath);
|
||||||
|
const url = `${this.baseUrl}/me/drive/root:/${cleanPath}:/children`;
|
||||||
|
|
||||||
|
console.log('Querying OneDrive items from:', url);
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${accessToken}`,
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Origin': 'https://onedrive.live.com',
|
||||||
|
'Referer': 'https://onedrive.live.com/'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorData = await response.json();
|
||||||
|
console.error('Graph API error details:', errorData);
|
||||||
|
throw new Error(`Graph API error: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
return data.value;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Graph API error:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new GraphApiClient();
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
const { ipcRenderer, session } = require('electron');
|
const { ipcRenderer, session } = require('electron');
|
||||||
|
const graphApi = require('./graphApi');
|
||||||
|
|
||||||
// Wait for webview to load
|
// Wait for webview to load
|
||||||
const webview = document.getElementById('main-content');
|
const webview = document.getElementById('main-content');
|
||||||
|
|
@ -65,7 +66,7 @@ document.getElementById('config-form').addEventListener('submit', (event) => {
|
||||||
console.log('Configuration panel closed');
|
console.log('Configuration panel closed');
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('sync-button').addEventListener('click', () => {
|
document.getElementById('sync-button').addEventListener('click', async () => {
|
||||||
const destFolder = document.getElementById('dest-folder').value;
|
const destFolder = document.getElementById('dest-folder').value;
|
||||||
const onedriveSource = document.getElementById('onedrive-source').value;
|
const onedriveSource = document.getElementById('onedrive-source').value;
|
||||||
|
|
||||||
|
|
@ -74,7 +75,33 @@ document.getElementById('sync-button').addEventListener('click', () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcRenderer.send('start-sync', { destFolder, onedriveSource });
|
try {
|
||||||
|
// Show loading state
|
||||||
|
const syncButton = document.getElementById('sync-button');
|
||||||
|
const originalText = syncButton.textContent;
|
||||||
|
syncButton.textContent = 'Syncing...';
|
||||||
|
syncButton.disabled = true;
|
||||||
|
|
||||||
|
// Get folder contents using GraphApiClient
|
||||||
|
const items = await graphApi.listFolderContents(onedriveSource);
|
||||||
|
console.log('Found items:', items.length);
|
||||||
|
|
||||||
|
// Process the items
|
||||||
|
// TODO: Handle the items as needed
|
||||||
|
showStatus(`Found ${items.length} items`);
|
||||||
|
|
||||||
|
// Send the items to the main process
|
||||||
|
ipcRenderer.send('start-sync', { destFolder, onedriveSource , items});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Sync error:', error);
|
||||||
|
showStatus(`Error: ${error.message}`, true);
|
||||||
|
} finally {
|
||||||
|
// Reset button state
|
||||||
|
const syncButton = document.getElementById('sync-button');
|
||||||
|
syncButton.textContent = originalText;
|
||||||
|
syncButton.disabled = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Config loaded handler
|
// Config loaded handler
|
||||||
|
|
@ -121,3 +148,15 @@ document.getElementById('close-config').addEventListener('click', () => {
|
||||||
document.getElementById('config-panel').classList.remove('open');
|
document.getElementById('config-panel').classList.remove('open');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add these event listeners with your other ipcRenderer.on handlers
|
||||||
|
|
||||||
|
ipcRenderer.on('sync-complete', (event, { totalItems, videoItems }) => {
|
||||||
|
console.log('Sync completed:', { totalItems, videoItems });
|
||||||
|
showStatus(`Sync complete: Downloaded ${videoItems} videos`);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('sync-error', (event, error) => {
|
||||||
|
console.error('Sync error:', error);
|
||||||
|
showStatus(`Sync error: ${error}`, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue