commit bcf435372228b3e746d8be2357e9ba5876127a21 Author: Maxx Cherevko Date: Thu Apr 30 08:40:34 2026 +0200 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..07fb801 --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +# 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 +```