# Downloads Auto-Uploader Watches your `~/Downloads` folder and automatically syncs new or changed files to a remote server over SSH/rsync. Runs every 5 minutes as a macOS launchd agent. ## How it works 1. SSHes into the remote host and indexes the destination directory (`find` with sizes) 2. Walks the local scan directory and compares files by size 3. Uploads only what is missing or has a different size, preserving directory structure 4. Logs every action to `uploader_log.txt` and records successful uploads in `.uploader_state.json` Files are skipped if they: - Match a skip pattern (hidden files, `.crdownload`, `.part`, `.tmp`, etc.) - Were modified less than 30 seconds ago (still being written) - Already exist on the remote with the same size ## Requirements - macOS (uses launchd) - `python3` (built-in on macOS, or `brew install python`) - `rsync` (`brew install rsync` recommended — macOS ships an outdated version) - SSH key-based access to the remote host (no password prompts) ## Quick start See [INSTALL.md](INSTALL.md). ## Configuration Edit `downloads_uploader_config.json`: | Key | Default | Description | |-----|---------|-------------| | `remote_destination` | `filez@10.10.8.1:/mnt/ssd2t/shared/torrent/Downloads/` | `user@host:/path` on the remote | | `ssh_key_path` | `""` | Path to SSH private key; empty = system default (`~/.ssh/id_rsa`) | | `ssh_port` | `22` | SSH port | | `scan_directory` | `""` | Directory to watch; empty = parent of `uploader/` folder | | `skip_patterns` | see config | Shell glob patterns for files/dirs to ignore | | `min_file_age_seconds` | `30` | Skip files newer than this (still being downloaded) | | `timeout_seconds` | `7200` | Per-file rsync timeout (2 hours) | | `remote_scan_timeout` | `120` | Timeout for the remote `find` command | | `dry_run` | `false` | Log what would be uploaded without transferring anything | ## Files ``` uploader/ downloads_uploader.py # main sync script downloads_uploader_install.sh # launchd installer downloads_uploader_config.json # configuration .uploader_state.json # upload audit log (auto-created) uploader_log.txt # application log (auto-created) uploader_stdout.log # launchd stdout (auto-created) uploader_stderr.log # launchd stderr (auto-created) ``` ## Manual usage ```bash # Run once right now ./downloads_uploader_install.sh run # Dry run (no transfers) # Set "dry_run": true in config, then: ./downloads_uploader_install.sh run # Check agent status + recent log ./downloads_uploader_install.sh status ```