2026-04-30 09:02:36 +02:00
2026-04-30 09:02:36 +02:00
2026-04-30 09:02:36 +02:00
2026-04-30 08:40:34 +02:00
2026-04-30 09:02:36 +02:00

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.

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
S
Description
No description provided
Readme 152 KiB
Languages
Python 75.1%
Shell 24.9%