main
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
- SSHes into the remote host and indexes the destination directory (
findwith sizes) - Walks the local scan directory and compares files by size
- Uploads only what is missing or has a different size, preserving directory structure
- Logs every action to
uploader_log.txtand 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, orbrew install python)rsync(brew install rsyncrecommended — macOS ships an outdated version)- SSH key-based access to the remote host (no password prompts)
Quick start
See 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
# 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
Description
Languages
Python
75.1%
Shell
24.9%