From 39b7fb59aabff11635a8eac9072c58b80fd5f12b Mon Sep 17 00:00:00 2001 From: Geert Rademakes Date: Thu, 28 Aug 2025 11:38:14 +0200 Subject: [PATCH] feat: Improve UI spacing and layout - Increase window size from 1200x800 to 1400x900 - Add more padding and gaps between UI elements - Improve button sizing and spacing - Better status panel layout with flex distribution - Enhanced activity log readability - Remove unnecessary start/stop buttons (auto-sync only) - Remove progress bar (not needed for continuous sync) - Clean up unused sync methods --- packages/desktop-sync/.env | 22 ++ packages/desktop-sync/.env.backup | 22 ++ packages/desktop-sync/README.md | 255 ++++++++++++++++++ packages/desktop-sync/assets/icon.png | 5 + packages/desktop-sync/assets/icon.svg | 36 +++ packages/desktop-sync/env.example | 29 ++ packages/desktop-sync/install-aws-cli.sh | 53 ++++ packages/desktop-sync/renderer/index.html | 14 +- packages/desktop-sync/renderer/renderer.js | 67 +---- packages/desktop-sync/renderer/styles.css | 82 +++--- .../desktop-sync/scripts/check-aws-cli.js | 61 +++++ packages/desktop-sync/scripts/check-minio.js | 87 ++++++ packages/desktop-sync/scripts/check-rclone.js | 89 ++++++ packages/desktop-sync/setup-env.sh | 152 +++++++++++ packages/desktop-sync/src/main.ts | 8 +- .../desktop-sync/src/services/awsS3Service.ts | 1 + 16 files changed, 853 insertions(+), 130 deletions(-) create mode 100644 packages/desktop-sync/.env create mode 100644 packages/desktop-sync/.env.backup create mode 100644 packages/desktop-sync/README.md create mode 100644 packages/desktop-sync/assets/icon.png create mode 100644 packages/desktop-sync/assets/icon.svg create mode 100644 packages/desktop-sync/env.example create mode 100755 packages/desktop-sync/install-aws-cli.sh create mode 100644 packages/desktop-sync/scripts/check-aws-cli.js create mode 100644 packages/desktop-sync/scripts/check-minio.js create mode 100644 packages/desktop-sync/scripts/check-rclone.js create mode 100755 packages/desktop-sync/setup-env.sh diff --git a/packages/desktop-sync/.env b/packages/desktop-sync/.env new file mode 100644 index 0000000..b05251b --- /dev/null +++ b/packages/desktop-sync/.env @@ -0,0 +1,22 @@ +# Rekordbox Sync Desktop Application Configuration +# Generated on Sat Aug 16 15:03:29 CEST 2025 + +# S3 Configuration +S3_ENDPOINT=https://garage.geertrademakers.nl +S3_REGION=garage +S3_ACCESS_KEY_ID=GK1c1a4a30946eb1e7f8d60847 +S3_SECRET_ACCESS_KEY=2ed6673f0e3c42d347adeb54ba6b95a1ebc6414750f2a95e1d3d89758f1add63 +S3_BUCKET_NAME=music +S3_USE_SSL=true + +# Sync Configuration +SYNC_LOCAL_PATH=/Users/geertrademakers/Music/s3-sync-test +SYNC_INTERVAL=30000 +SYNC_AUTO_START=true +SYNC_CONFLICT_RESOLUTION=newer-wins + +# UI Configuration +UI_THEME=system +UI_LANGUAGE=en +UI_NOTIFICATIONS=true +UI_MINIMIZE_TO_TRAY=true diff --git a/packages/desktop-sync/.env.backup b/packages/desktop-sync/.env.backup new file mode 100644 index 0000000..fdc1308 --- /dev/null +++ b/packages/desktop-sync/.env.backup @@ -0,0 +1,22 @@ +# Rekordbox Sync Desktop Application Configuration +# Generated on Sat Aug 16 15:03:29 CEST 2025 + +# S3 Configuration +S3_ENDPOINT=https://garage.geertrademakers.nl +S3_REGION=garage +S3_ACCESS_KEY_ID=GK1c1a4a30946eb1e7f8d60847 +S3_SECRET_ACCESS_KEY=2ed6673f0e3c42d347adeb54ba6b95a1ebc6414750f2a95e1d3d89758f1add63 +S3_BUCKET_NAME=music +S3_USE_SSL=true + +# Sync Configuration +SYNC_LOCAL_PATH=/Users/geertrademakers/Desktop/s3-music-sync-dir +SYNC_INTERVAL=30000 +SYNC_AUTO_START=true +SYNC_CONFLICT_RESOLUTION=newer-wins + +# UI Configuration +UI_THEME=system +UI_LANGUAGE=en +UI_NOTIFICATIONS=true +UI_MINIMIZE_TO_TRAY=true diff --git a/packages/desktop-sync/README.md b/packages/desktop-sync/README.md new file mode 100644 index 0000000..c014420 --- /dev/null +++ b/packages/desktop-sync/README.md @@ -0,0 +1,255 @@ +# Rekordbox Sync - Desktop Companion + +A desktop application for bidirectional synchronization between a Garage-hosted S3 instance and your local computer, specifically designed for Rekordbox music libraries. + +## šŸš€ Features + +- **Bidirectional S3 Sync**: Seamlessly sync files between your local machine and S3 storage +- **Incremental Sync**: Only sync files that have changed since the last sync +- **Automatic Cleanup**: Removes temporary files before syncing +- **Real-time Monitoring**: Continuous sync with configurable intervals +- **Error Handling**: Robust error handling with automatic retries +- **Progress Tracking**: Real-time progress updates and file counting +- **Cross-platform**: Built with Electron for macOS, Windows, and Linux + +## šŸ”§ Prerequisites + +### AWS CLI v2 +This tool requires AWS CLI v2 to be installed on your system. The AWS CLI provides the `aws s3 sync` command which offers superior performance and reliability compared to other S3 sync tools. + +#### Installation Options: + +**Option 1: Automatic Installation (macOS)** +```bash +npm run install-aws-cli +``` + +**Option 2: Manual Installation** +- Download from: https://awscli.amazonaws.com/ +- Follow the installation guide: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html + +**Option 3: Homebrew (macOS)** +```bash +brew install awscli +``` + +#### Verify Installation +```bash +aws --version +``` + +## šŸ“¦ Installation + +1. **Clone the repository** + ```bash + git clone + cd rekordbox-reader/packages/desktop-sync + ``` + +2. **Install dependencies** + ```bash + npm install + ``` + +3. **Configure environment** + ```bash + cp .env.example .env + # Edit .env with your S3 configuration + ``` + +4. **Build the application** + ```bash + npm run build + ``` + +5. **Start the application** + ```bash + npm run dev + ``` + +## āš™ļø Configuration + +Create a `.env` file in the project root with the following variables: + +```env +# S3 Configuration (Garage) +S3_ENDPOINT=http://your-garage-instance:3900 +S3_REGION=garage +S3_ACCESS_KEY_ID=your-access-key +S3_SECRET_ACCESS_KEY=your-secret-key +S3_BUCKET_NAME=your-bucket-name +S3_USE_SSL=false + +# Sync Configuration +SYNC_LOCAL_PATH=/path/to/your/local/music/folder +SYNC_INTERVAL=30000 +SYNC_AUTO_START=false +SYNC_CONFLICT_RESOLUTION=newer-wins + +# UI Configuration +UI_THEME=dark +UI_LANGUAGE=en +``` + +### Garage S3 Configuration + +For Garage S3 compatibility, ensure your configuration includes: +- **Endpoint**: Your Garage instance URL (e.g., `http://localhost:3900`) +- **Region**: Usually `garage` or `us-east-1` +- **SSL**: Set to `false` for local Garage instances + +## šŸŽÆ Usage + +### Starting Sync +1. Launch the application +2. Click "Start Sync" to begin bidirectional synchronization +3. The app will: + - Download all files from S3 to local (first time) + - Upload new/changed local files to S3 + - Start continuous bidirectional sync + +### Sync Modes + +#### **Initial Sync** +- Downloads all files from S3 to local +- Ensures local folder matches S3 bucket contents +- Excludes temporary files (`.tmp`, `.temp`, `.part`, `.DS_Store`) + +#### **Continuous Sync** +- Monitors both local and S3 for changes +- Automatically syncs new, modified, or deleted files +- Runs every 30 seconds by default +- Maintains bidirectional consistency + +#### **Force Full Sync** +- Completely resynchronizes all files +- Useful for resolving sync conflicts +- Deletes and re-downloads all files + +### File Handling + +- **Temporary Files**: Automatically excluded and cleaned up +- **Conflict Resolution**: Newer timestamp wins by default +- **Delete Propagation**: Files deleted locally are removed from S3 and vice versa +- **Incremental Updates**: Only changed files are transferred + +## šŸ” Monitoring + +### Real-time Status +- Current sync phase (downloading, uploading, watching) +- Progress percentage and file counts +- Transfer speed and ETA +- Error messages and retry attempts + +### Activity Log +- Detailed AWS CLI output +- File operations and sync events +- Error tracking and resolution + +### File Counts +- Accurate local file counting +- S3 bucket file statistics +- Sync progress tracking + +## šŸ› ļø Development + +### Project Structure +``` +src/ +ā”œā”€ā”€ main.ts # Main Electron process +ā”œā”€ā”€ preload.ts # Preload script for IPC +ā”œā”€ā”€ services/ +│ ā”œā”€ā”€ awsS3Service.ts # AWS S3 sync service +│ ā”œā”€ā”€ configManager.ts # Configuration management +│ ā”œā”€ā”€ fileWatcher.ts # Local file system monitoring +│ └── syncManager.ts # Sync orchestration +└── renderer/ # UI components + ā”œā”€ā”€ index.html + ā”œā”€ā”€ renderer.js + └── styles.css +``` + +### Available Scripts +- `npm run dev` - Development mode with hot reload +- `npm run build` - Build TypeScript to JavaScript +- `npm run start` - Start the built application +- `npm run package` - Package for distribution +- `npm run install-aws-cli` - Install AWS CLI (macOS) + +### Building +```bash +npm run build +npm start +``` + +## 🚨 Troubleshooting + +### Common Issues + +**AWS CLI Not Found** +```bash +# Check if AWS CLI is installed +aws --version + +# Install if missing +npm run install-aws-cli +``` + +**Sync Fails to Start** +- Verify S3 credentials in `.env` +- Check network connectivity to Garage instance +- Ensure local sync path exists and is writable + +**Files Not Syncing** +- Check file permissions +- Verify S3 bucket access +- Review activity log for error messages + +**Performance Issues** +- AWS CLI v2 provides optimal performance +- Consider adjusting sync interval +- Monitor network bandwidth usage + +### Debug Mode +Enable detailed logging by setting environment variables: +```bash +DEBUG=* npm run dev +``` + +## šŸ“Š Performance + +- **AWS CLI v2**: Optimized for S3 operations +- **Incremental Sync**: Only transfers changed files +- **Parallel Operations**: Efficient file transfer +- **Memory Management**: Minimal memory footprint +- **Network Optimization**: Intelligent retry and backoff + +## šŸ”’ Security + +- **Credential Management**: Secure storage of S3 credentials +- **Local Storage**: Credentials stored locally, never transmitted +- **SSL Support**: Configurable SSL/TLS for S3 endpoints +- **Access Control**: Follows S3 bucket policies and IAM permissions + +## šŸ¤ Contributing + +1. Fork the repository +2. Create a feature branch +3. Make your changes +4. Add tests if applicable +5. Submit a pull request + +## šŸ“„ License + +MIT License - see LICENSE file for details + +## šŸ™ Acknowledgments + +- **AWS CLI**: Powerful S3 sync capabilities +- **Electron**: Cross-platform desktop framework +- **Garage**: Self-hosted S3-compatible storage +- **Rekordbox**: Professional DJ software + +--- + +**Note**: This tool is designed for personal and professional use with Garage S3 storage. Ensure compliance with your organization's data policies and S3 usage guidelines. diff --git a/packages/desktop-sync/assets/icon.png b/packages/desktop-sync/assets/icon.png new file mode 100644 index 0000000..b41361c --- /dev/null +++ b/packages/desktop-sync/assets/icon.png @@ -0,0 +1,5 @@ +# This is a placeholder for the PNG icon +# You can convert the SVG to PNG using: +# - Online tools like convertio.co +# - Command line: convert icon.svg icon.png (if ImageMagick is installed) +# - Or use any image editor that supports SVG import diff --git a/packages/desktop-sync/assets/icon.svg b/packages/desktop-sync/assets/icon.svg new file mode 100644 index 0000000..75b78df --- /dev/null +++ b/packages/desktop-sync/assets/icon.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/desktop-sync/env.example b/packages/desktop-sync/env.example new file mode 100644 index 0000000..99655be --- /dev/null +++ b/packages/desktop-sync/env.example @@ -0,0 +1,29 @@ +# Rekordbox Sync Desktop Application Configuration +# Copy this file to .env and fill in your values + +# S3 Configuration +S3_ENDPOINT=https://garage.geertrademakers.nl +S3_REGION=garage +S3_ACCESS_KEY_ID=your_access_key_here +S3_SECRET_ACCESS_KEY=your_secret_key_here +S3_BUCKET_NAME=music +S3_USE_SSL=true + +# Sync Configuration +SYNC_LOCAL_PATH=/path/to/your/music/folder +SYNC_INTERVAL=30000 +SYNC_AUTO_START=false +SYNC_CONFLICT_RESOLUTION=newer-wins + +# UI Configuration +UI_THEME=system +UI_LANGUAGE=en +UI_NOTIFICATIONS=true +UI_MINIMIZE_TO_TRAY=true + +# Notes: +# - SYNC_INTERVAL is in milliseconds (30000 = 30 seconds) +# - SYNC_CONFLICT_RESOLUTION options: newer-wins, local-wins, remote-wins +# - UI_THEME options: system, light, dark +# - Boolean values: true/false (as strings) +# - Paths should use forward slashes (/) even on Windows diff --git a/packages/desktop-sync/install-aws-cli.sh b/packages/desktop-sync/install-aws-cli.sh new file mode 100755 index 0000000..69d7560 --- /dev/null +++ b/packages/desktop-sync/install-aws-cli.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +# AWS CLI v2 Installer for macOS +# This script downloads and installs AWS CLI v2 on macOS + +set -e + +echo "šŸš€ Installing AWS CLI v2 for macOS..." + +# Check if AWS CLI is already installed +if command -v aws &> /dev/null; then + echo "āœ… AWS CLI is already installed:" + aws --version + exit 0 +fi + +# Check if we're on macOS +if [[ "$OSTYPE" != "darwin"* ]]; then + echo "āŒ This script is for macOS only. Please install AWS CLI manually for your platform." + exit 1 +fi + +# Create temporary directory +TEMP_DIR=$(mktemp -d) +cd "$TEMP_DIR" + +echo "šŸ“„ Downloading AWS CLI v2..." + +# Download AWS CLI v2 for macOS +curl -O https://awscli.amazonaws.com/AWSCLIV2.pkg + +echo "šŸ”§ Installing AWS CLI v2..." + +# Install the package +sudo installer -pkg AWSCLIV2.pkg -target / + +# Clean up +cd - > /dev/null +rm -rf "$TEMP_DIR" + +echo "āœ… AWS CLI v2 installed successfully!" + +# Verify installation +if command -v aws &> /dev/null; then + echo "šŸ” AWS CLI version:" + aws --version + echo "" + echo "šŸŽ‰ Installation completed! You can now use the desktop sync tool." +else + echo "āŒ Installation failed. Please try installing manually:" + echo " https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" + exit 1 +fi diff --git a/packages/desktop-sync/renderer/index.html b/packages/desktop-sync/renderer/index.html index b535b0e..09cf6ab 100644 --- a/packages/desktop-sync/renderer/index.html +++ b/packages/desktop-sync/renderer/index.html @@ -33,7 +33,7 @@
Sync Status: - Stopped + Initializing...
Last Sync: @@ -44,22 +44,14 @@ 0
- Progress: -
-
-
+ Sync Mode: + Auto-sync
- - diff --git a/packages/desktop-sync/renderer/renderer.js b/packages/desktop-sync/renderer/renderer.js index 8a6ab42..36c11e2 100644 --- a/packages/desktop-sync/renderer/renderer.js +++ b/packages/desktop-sync/renderer/renderer.js @@ -11,8 +11,6 @@ class RekordboxSyncRenderer { */ initializeElements() { // Buttons - this.startBtn = document.getElementById('startSyncBtn'); - this.stopBtn = document.getElementById('stopSyncBtn'); this.exportEnvBtn = document.getElementById('exportEnvBtn'); // Status elements @@ -20,6 +18,7 @@ class RekordboxSyncRenderer { this.filesSyncedElement = document.getElementById('filesSynced'); this.lastSyncElement = document.getElementById('lastSync'); this.syncDetailsElement = document.getElementById('syncDetails'); + this.syncModeElement = document.getElementById('syncMode'); // Activity log this.activityLogElement = document.getElementById('activityLog'); @@ -76,30 +75,14 @@ class RekordboxSyncRenderer { * Setup Electron IPC listeners */ setupElectronListeners() { - console.log('šŸ”Œ Setting up Electron IPC listeners...'); - console.log('šŸ” Window object:', window); - console.log('šŸ” Electron API object:', window.electronAPI); - if (!window.electronAPI) { console.error('āŒ Electron API not available'); - console.error('āŒ This means the preload script failed to load'); return; } - console.log('āœ… Electron API is available, setting up listeners...'); - // Sync status updates window.electronAPI.on('sync-status-changed', (status) => { - console.log('šŸ“Š Received sync status update:', status); - console.log('šŸ” Status details:', { - isRunning: status.isRunning, - currentPhase: status.currentPhase, - actualFileCount: status.actualFileCount, - stats: status.stats - }); - console.log('šŸ”„ Calling updateSyncStatus...'); this.updateSyncStatus(status); - console.log('āœ… updateSyncStatus completed'); }); // File change events @@ -159,11 +142,7 @@ class RekordboxSyncRenderer { if (this.startBtn) this.startBtn.disabled = false; if (this.stopBtn) this.stopBtn.disabled = true; - // Reset progress bar on error - const progressBar = document.getElementById('progressBar'); - if (progressBar) { - progressBar.style.width = '0%'; - } + }); // Engine events @@ -213,33 +192,7 @@ class RekordboxSyncRenderer { } } - /** - * Start sync - */ - async startSync() { - try { - this.addActivityLog('info', 'Starting sync...'); - await window.electronAPI.invoke('sync:start'); - this.addActivityLog('success', 'Sync started successfully'); - } catch (error) { - console.error('āŒ Failed to start sync:', error); - this.addActivityLog('error', `Failed to start sync: ${error.message || 'Unknown error'}`); - } - } - /** - * Stop sync - */ - async stopSync() { - try { - this.addActivityLog('info', 'Stopping sync...'); - await window.electronAPI.invoke('sync:stop'); - this.addActivityLog('info', 'Sync stopped'); - } catch (error) { - console.error('āŒ Failed to stop sync:', error); - this.addActivityLog('error', `Failed to stop sync: ${error.message || 'Unknown error'}`); - } - } /** * Force full sync @@ -278,8 +231,6 @@ class RekordboxSyncRenderer { this.syncStatusElement.textContent = statusText; this.syncStatusElement.className = 'status-value running'; - if (this.startBtn) this.startBtn.disabled = true; - if (this.stopBtn) this.stopBtn.disabled = false; } else { if (status.completedCount > 0 && status.pendingCount === 0 && status.inProgressCount === 0) { this.syncStatusElement.textContent = 'Completed'; @@ -288,11 +239,7 @@ class RekordboxSyncRenderer { this.syncStatusElement.textContent = 'Stopped'; this.syncStatusElement.className = 'status-value stopped'; - // Reset progress bar when stopped - const progressBar = document.getElementById('progressBar'); - if (progressBar) { - progressBar.style.width = '0%'; - } + } if (this.startBtn) this.startBtn.disabled = false; if (this.stopBtn) this.stopBtn.disabled = true; @@ -347,14 +294,8 @@ class RekordboxSyncRenderer { this.addActivityLog('info', `${status.currentPhase}: ${status.progressMessage}`); } - // Update progress bar + // Log progress changes to reduce spam if (status.progress && status.progress.percent > 0) { - const progressBar = document.getElementById('progressBar'); - if (progressBar) { - progressBar.style.width = `${status.progress.percent}%`; - } - - // Only log progress changes to reduce spam const currentProgress = status.progress.percent; if (!this.lastLoggedProgress || Math.abs(currentProgress - this.lastLoggedProgress) >= 10) { const progressText = `Progress: ${currentProgress}% - ${status.progress.message || 'Syncing files...'}`; diff --git a/packages/desktop-sync/renderer/styles.css b/packages/desktop-sync/renderer/styles.css index a5e8f6f..ed244ee 100644 --- a/packages/desktop-sync/renderer/styles.css +++ b/packages/desktop-sync/renderer/styles.css @@ -52,17 +52,19 @@ body { /* Buttons */ .btn { - padding: 0.5rem 1rem; + padding: 1rem 2rem; border: none; - border-radius: 6px; + border-radius: 10px; cursor: pointer; - font-size: 0.9rem; + font-size: 1rem; font-weight: 500; transition: all 0.2s ease; display: inline-flex; align-items: center; - gap: 0.5rem; + gap: 0.75rem; text-decoration: none; + min-width: 140px; + justify-content: center; } .btn:hover { @@ -124,12 +126,12 @@ body { /* Main content */ .main-content { flex: 1; - padding: 1.5rem; + padding: 2rem; overflow-y: auto; display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: auto auto 1fr; - gap: 1.5rem; + gap: 2rem; grid-template-areas: "status control" "activity activity" @@ -140,32 +142,37 @@ body { .status-panel { grid-area: status; background: white; - padding: 1.5rem; + padding: 2rem; border-radius: 12px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); display: flex; justify-content: space-around; align-items: center; + gap: 1.5rem; } .status-item { text-align: center; + flex: 1; + min-width: 0; } .status-label { display: block; - font-size: 0.8rem; + font-size: 0.85rem; color: #7f8c8d; - margin-bottom: 0.5rem; + margin-bottom: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px; + font-weight: 500; } .status-value { display: block; - font-size: 1.2rem; + font-size: 1.3rem; font-weight: 600; color: #2c3e50; + line-height: 1.2; } #syncStatus { @@ -195,49 +202,17 @@ body { color: #721c24; } -/* Progress Bar */ -.progress-container { - width: 100%; - height: 8px; - background: #e0e0e0; - border-radius: 4px; - overflow: hidden; - margin-top: 0.5rem; -} -.progress-bar { - height: 100%; - background: linear-gradient(90deg, #3498db, #2ecc71); - border-radius: 4px; - transition: width 0.3s ease; - position: relative; -} - -.progress-bar::after { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); - animation: shimmer 2s infinite; -} - -@keyframes shimmer { - 0% { transform: translateX(-100%); } - 100% { transform: translateX(100%); } -} /* Control Panel */ .control-panel { grid-area: control; background: white; - padding: 1.5rem; + padding: 2rem; border-radius: 12px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); display: flex; - gap: 1rem; + gap: 1.5rem; justify-content: center; align-items: center; } @@ -248,7 +223,7 @@ body { .activity-panel { grid-area: activity; background: white; - padding: 1.5rem; + padding: 2rem; border-radius: 12px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); display: flex; @@ -256,11 +231,12 @@ body { } .activity-panel h3 { - margin-bottom: 1rem; + margin-bottom: 1.5rem; color: #2c3e50; display: flex; align-items: center; - gap: 0.5rem; + gap: 0.75rem; + font-size: 1.2rem; } .activity-log { @@ -272,16 +248,18 @@ body { text-align: center; color: #95a5a6; font-style: italic; - padding: 2rem; + padding: 3rem 2rem; + font-size: 1.1rem; } .activity-item { - padding: 0.75rem; - margin-bottom: 0.5rem; - border-radius: 6px; + padding: 1rem; + margin-bottom: 0.75rem; + border-radius: 8px; background: #f8f9fa; border-left: 4px solid #95a5a6; - font-size: 0.9rem; + font-size: 0.95rem; + line-height: 1.4; } .activity-item.info { diff --git a/packages/desktop-sync/scripts/check-aws-cli.js b/packages/desktop-sync/scripts/check-aws-cli.js new file mode 100644 index 0000000..be795d5 --- /dev/null +++ b/packages/desktop-sync/scripts/check-aws-cli.js @@ -0,0 +1,61 @@ +#!/usr/bin/env node + +/** + * Check if AWS CLI is available on the system + * This script is run during postinstall to ensure AWS CLI is available + */ + +const { spawn } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +console.log('šŸ” Checking AWS CLI availability...'); + +// Check if AWS CLI is available +function checkAwsCli() { + return new Promise((resolve) => { + const process = spawn('aws', ['--version'], { stdio: 'pipe' }); + + process.on('close', (code) => { + resolve(code === 0); + }); + + process.on('error', () => { + resolve(false); + }); + }); +} + +async function main() { + const isAvailable = await checkAwsCli(); + + if (isAvailable) { + console.log('āœ… AWS CLI is available'); + + // Get version + const versionProcess = spawn('aws', ['--version'], { stdio: 'pipe' }); + versionProcess.stdout.on('data', (data) => { + console.log(`šŸ“‹ Version: ${data.toString().trim()}`); + }); + + console.log('šŸŽ‰ You can now use the desktop sync tool with AWS S3!'); + } else { + console.log('āŒ AWS CLI is not available'); + console.log(''); + console.log('šŸ“‹ To install AWS CLI v2:'); + console.log(''); + console.log(' Option 1: Run the installer script:'); + console.log(' npm run install-aws-cli'); + console.log(''); + console.log(' Option 2: Install manually:'); + console.log(' https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html'); + console.log(''); + console.log(' Option 3: Use Homebrew (macOS):'); + console.log(' brew install awscli'); + console.log(''); + console.log('āš ļø The desktop sync tool requires AWS CLI to function properly.'); + console.log(' Please install AWS CLI before using the sync functionality.'); + } +} + +main().catch(console.error); diff --git a/packages/desktop-sync/scripts/check-minio.js b/packages/desktop-sync/scripts/check-minio.js new file mode 100644 index 0000000..cf294d5 --- /dev/null +++ b/packages/desktop-sync/scripts/check-minio.js @@ -0,0 +1,87 @@ +#!/usr/bin/env node + +const { spawn } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +console.log('šŸ” Checking MinIO Client installation...'); + +function checkMinio() { + return new Promise((resolve) => { + const minio = spawn('mc', ['--version'], { stdio: 'pipe' }); + + let output = ''; + let error = ''; + + minio.stdout.on('data', (data) => { + output += data.toString(); + }); + + minio.stderr.on('data', (data) => { + error += data.toString(); + }); + + minio.on('close', (code) => { + if (code === 0) { + const versionMatch = output.match(/mc version (RELEASE\.\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}Z)/); + if (versionMatch) { + console.log(`āœ… MinIO Client is installed: ${versionMatch[1]}`); + resolve(true); + } else { + console.log('āœ… MinIO Client is installed (version unknown)'); + resolve(true); + } + } else { + console.log('āŒ MinIO Client is not installed or not in PATH'); + resolve(false); + } + }); + + minio.on('error', () => { + console.log('āŒ MinIO Client is not installed or not in PATH'); + resolve(false); + }); + }); +} + +function showInstallInstructions() { + console.log('\nšŸ“„ MinIO Client Installation Instructions:'); + console.log('=========================================='); + + if (process.platform === 'darwin') { + console.log('\nšŸŽ macOS:'); + console.log(' brew install minio/stable/mc'); + console.log(' # Or download from: https://min.io/download'); + } else if (process.platform === 'win32') { + console.log('\n🪟 Windows:'); + console.log(' # Download from: https://min.io/download'); + console.log(' # Extract and add to PATH'); + } else if (process.platform === 'linux') { + console.log('\n🐧 Linux:'); + console.log(' # Ubuntu/Debian:'); + console.log(' wget https://dl.min.io/client/mc/release/linux-amd64/mc'); + console.log(' chmod +x mc'); + console.log(' sudo mv mc /usr/local/bin/'); + console.log(' # Or: curl https://dl.min.io/client/mc/release/linux-amd64/mc -o mc && chmod +x mc && sudo mv mc /usr/local/bin/'); + } + + console.log('\nšŸ“š After installation:'); + console.log(' 1. Run: mc alias set garage https://your-garage-endpoint access-key secret-key'); + console.log(' 2. Test with: mc ls garage/bucket-name'); + console.log('\nšŸ”— Documentation: https://min.io/docs/minio/linux/reference/minio-mc.html'); +} + +async function main() { + const isInstalled = await checkMinio(); + + if (!isInstalled) { + showInstallInstructions(); + process.exit(1); + } else { + console.log('\nšŸŽ‰ MinIO Client is ready to use!'); + console.log('šŸ’” You can now run: npm start'); + } +} + +main().catch(console.error); + diff --git a/packages/desktop-sync/scripts/check-rclone.js b/packages/desktop-sync/scripts/check-rclone.js new file mode 100644 index 0000000..79e908a --- /dev/null +++ b/packages/desktop-sync/scripts/check-rclone.js @@ -0,0 +1,89 @@ +#!/usr/bin/env node + +const { spawn } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +console.log('šŸ” Checking rclone installation...'); + +function checkRclone() { + return new Promise((resolve) => { + const rclone = spawn('rclone', ['version'], { stdio: 'pipe' }); + + let output = ''; + let error = ''; + + rclone.stdout.on('data', (data) => { + output += data.toString(); + }); + + rclone.stderr.on('data', (data) => { + error += data.toString(); + }); + + rclone.on('close', (code) => { + if (code === 0) { + const versionMatch = output.match(/rclone v(\d+\.\d+\.\d+)/); + if (versionMatch) { + console.log(`āœ… Rclone is installed: ${versionMatch[1]}`); + resolve(true); + } else { + console.log('āœ… Rclone is installed (version unknown)'); + resolve(true); + } + } else { + console.log('āŒ Rclone is not installed or not in PATH'); + resolve(false); + } + }); + + rclone.on('error', () => { + console.log('āŒ Rclone is not installed or not in PATH'); + resolve(false); + }); + }); +} + +function showInstallInstructions() { + console.log('\nšŸ“„ Rclone Installation Instructions:'); + console.log('====================================='); + + if (process.platform === 'darwin') { + console.log('\nšŸŽ macOS:'); + console.log(' brew install rclone'); + console.log(' # Or download from: https://rclone.org/downloads/'); + } else if (process.platform === 'win32') { + console.log('\n🪟 Windows:'); + console.log(' # Download from: https://rclone.org/downloads/'); + console.log(' # Extract and add to PATH'); + } else if (process.platform === 'linux') { + console.log('\n🐧 Linux:'); + console.log(' # Ubuntu/Debian:'); + console.log(' curl https://rclone.org/install.sh | sudo bash'); + console.log(' # Or: sudo apt install rclone'); + console.log(' # CentOS/RHEL:'); + console.log(' sudo yum install rclone'); + } + + console.log('\nšŸ“š After installation:'); + console.log(' 1. Run: rclone config'); + console.log(' 2. Create a new remote named "music"'); + console.log(' 3. Choose S3 provider'); + console.log(' 4. Enter your Garage S3 credentials'); + console.log('\nšŸ”— Documentation: https://rclone.org/s3/'); +} + +async function main() { + const isInstalled = await checkRclone(); + + if (!isInstalled) { + showInstallInstructions(); + process.exit(1); + } else { + console.log('\nšŸŽ‰ Rclone is ready to use!'); + console.log('šŸ’” You can now run: npm start'); + } +} + +main().catch(console.error); + diff --git a/packages/desktop-sync/setup-env.sh b/packages/desktop-sync/setup-env.sh new file mode 100755 index 0000000..15bc26b --- /dev/null +++ b/packages/desktop-sync/setup-env.sh @@ -0,0 +1,152 @@ +#!/bin/bash + +# Rekordbox Sync .env Setup Script + +echo "šŸ”§ Setting up Rekordbox Sync .env configuration file..." + +# Check if .env already exists +if [ -f ".env" ]; then + echo "āš ļø .env file already exists!" + read -p "Do you want to overwrite it? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "āŒ Setup cancelled." + exit 1 + fi +fi + +# Get S3 configuration +echo "" +echo "🌐 S3 Configuration:" +read -p "S3 Endpoint (default: https://garage.geertrademakers.nl): " s3_endpoint +s3_endpoint=${s3_endpoint:-https://garage.geertrademakers.nl} + +read -p "S3 Region (default: garage): " s3_region +s3_region=${s3_region:-garage} + +read -p "S3 Access Key ID: " s3_access_key +if [ -z "$s3_access_key" ]; then + echo "āŒ S3 Access Key ID is required!" + exit 1 +fi + +read -s -p "S3 Secret Access Key: " s3_secret_key +echo +if [ -z "$s3_secret_key" ]; then + echo "āŒ S3 Secret Access Key is required!" + exit 1 +fi + +read -p "S3 Bucket Name (default: music): " s3_bucket +s3_bucket=${s3_bucket:-music} + +read -p "Use SSL? (Y/n): " -n 1 -r +echo +s3_use_ssl="true" +if [[ $REPLY =~ ^[Nn]$ ]]; then + s3_use_ssl="false" +fi + +# Get sync configuration +echo "" +echo "šŸ”„ Sync Configuration:" +read -p "Local Music Folder Path: " sync_local_path +if [ -z "$sync_local_path" ]; then + echo "āŒ Local music folder path is required!" + exit 1 +fi + +read -p "Sync Interval in seconds (default: 30): " sync_interval +sync_interval=${sync_interval:-30} +sync_interval=$((sync_interval * 1000)) # Convert to milliseconds + +read -p "Auto-start sync on app launch? (y/N): " -n 1 -r +echo +sync_auto_start="false" +if [[ $REPLY =~ ^[Yy]$ ]]; then + sync_auto_start="true" +fi + +echo "" +echo "Conflict Resolution Strategy:" +echo "1) newer-wins (recommended)" +echo "2) local-wins" +echo "3) remote-wins" +read -p "Choose strategy (1-3, default: 1): " conflict_resolution +case $conflict_resolution in + 2) conflict_resolution="local-wins" ;; + 3) conflict_resolution="remote-wins" ;; + *) conflict_resolution="newer-wins" ;; +esac + +# Get UI configuration +echo "" +echo "šŸŽØ UI Configuration:" +echo "Theme options:" +echo "1) system (follows OS theme)" +echo "2) light" +echo "3) dark" +read -p "Choose theme (1-3, default: 1): " ui_theme +case $ui_theme in + 2) ui_theme="light" ;; + 3) ui_theme="dark" ;; + *) ui_theme="system" ;; +esac + +read -p "Show notifications? (Y/n): " -n 1 -r +echo +ui_notifications="true" +if [[ $REPLY =~ ^[Nn]$ ]]; then + ui_notifications="false" +fi + +read -p "Minimize to system tray? (Y/n): " -n 1 -r +echo +ui_minimize_to_tray="true" +if [[ $REPLY =~ ^[Nn]$ ]]; then + ui_minimize_to_tray="false" +fi + +# Create .env file +echo "" +echo "šŸ“ Creating .env file..." + +cat > .env << EOF +# Rekordbox Sync Desktop Application Configuration +# Generated on $(date) + +# S3 Configuration +S3_ENDPOINT=$s3_endpoint +S3_REGION=$s3_region +S3_ACCESS_KEY_ID=$s3_access_key +S3_SECRET_ACCESS_KEY=$s3_secret_key +S3_BUCKET_NAME=$s3_bucket +S3_USE_SSL=$s3_use_ssl + +# Sync Configuration +SYNC_LOCAL_PATH=$sync_local_path +SYNC_INTERVAL=$sync_interval +SYNC_AUTO_START=$sync_auto_start +SYNC_CONFLICT_RESOLUTION=$conflict_resolution + +# UI Configuration +UI_THEME=$ui_theme +UI_LANGUAGE=en +UI_NOTIFICATIONS=$ui_notifications +UI_MINIMIZE_TO_TRAY=$ui_minimize_to_tray +EOF + +echo "āœ… .env file created successfully!" +echo "" +echo "šŸ” Configuration summary:" +echo " S3 Endpoint: $s3_endpoint" +echo " S3 Region: $s3_region" +echo " S3 Bucket: $s3_bucket" +echo " Local Path: $sync_local_path" +echo " Sync Interval: $((sync_interval / 1000)) seconds" +echo " Auto-start: $sync_auto_start" +echo " Conflict Resolution: $conflict_resolution" +echo " Theme: $ui_theme" +echo "" +echo "šŸš€ You can now start the application with: npm run dev" +echo "šŸ“– The .env file will be automatically loaded on startup." diff --git a/packages/desktop-sync/src/main.ts b/packages/desktop-sync/src/main.ts index dfff7ea..0f42bc4 100644 --- a/packages/desktop-sync/src/main.ts +++ b/packages/desktop-sync/src/main.ts @@ -61,10 +61,10 @@ class RekordboxSyncApp { */ private async createMainWindow(): Promise { this.mainWindow = new BrowserWindow({ - width: 1200, - height: 800, - minWidth: 800, - minHeight: 600, + width: 1400, + height: 900, + minWidth: 1000, + minHeight: 700, webPreferences: { nodeIntegration: false, contextIsolation: true, diff --git a/packages/desktop-sync/src/services/awsS3Service.ts b/packages/desktop-sync/src/services/awsS3Service.ts index 4b9be2f..0bd278b 100644 --- a/packages/desktop-sync/src/services/awsS3Service.ts +++ b/packages/desktop-sync/src/services/awsS3Service.ts @@ -469,6 +469,7 @@ export class AwsS3Service extends EventEmitter { '--exclude', '*.temp', '--exclude', '*.part', '--exclude', '.DS_Store', + '--exclude', '**/.DS_Store', '--exclude', '*.crdownload' ]);