Skip to content

Python script to download ALL Zoom cloud recordings with streaming download, SQLite progress tracking, resume on interruption, and auto-restart wrapper

License

Notifications You must be signed in to change notification settings

priz1920/zoom-cloud-backup

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Zoom Cloud Backup

A super-reliable Python script for backing up ALL Zoom cloud recordings to local storage (SSD/HDD).

Features

  • Streaming Download - Downloads in 8MB chunks directly to disk (no RAM buffering)
  • Resume Capability - Uses HTTP Range headers to continue interrupted downloads
  • SQLite Progress Tracking - Persistent database tracks every file's status
  • Integrity Verification - Verifies file size after download
  • Disk Health Checks - Monitors disk availability, free space, and write access
  • Graceful Shutdown - Ctrl+C saves progress, resume anytime
  • Auto-Restart Wrapper - Bash script with exponential backoff for unattended operation
  • Progress Bars - Visual progress for overall and per-file downloads
  • All User Types - Fetches recordings from active, inactive, and pending users

Requirements

  • Python 3.7+
  • Zoom Server-to-Server OAuth App credentials
  • External storage with sufficient space

Installation

# Clone the repository
git clone https://github.com/yourusername/zoom-cloud-backup.git
cd zoom-cloud-backup

# Install dependencies
pip install -r requirements.txt

# Copy and configure
cp config.example.json config.json
# Edit config.json with your Zoom credentials and storage path

Zoom API Setup

  1. Go to Zoom App Marketplace
  2. Click DevelopBuild App
  3. Choose Server-to-Server OAuth
  4. Fill in the app information
  5. Add scopes:
    • cloud_recording:read:list_user_recordings:admin
    • cloud_recording:read:list_recording_files:admin
    • user:read:list_users:admin
    • user:read:user:admin
  6. Copy Account ID, Client ID, and Client Secret to config.json

Configuration

Edit config.json:

{
    "zoom": {
        "account_id": "YOUR_ACCOUNT_ID",
        "client_id": "YOUR_CLIENT_ID",
        "client_secret": "YOUR_CLIENT_SECRET"
    },
    "storage": {
        "base_path": "/path/to/backup/folder",
        "min_free_space_gb": 5
    },
    "download": {
        "chunk_size_mb": 8,
        "max_retries": 5,
        "retry_delay_sec": 10,
        "rate_limit_delay": 0.1,
        "timeout_sec": 60
    },
    "scan": {
        "start_date": "2020-01-01",
        "end_date": null
    }
}

Configuration Options

Option Description Default
storage.base_path Where to save recordings Required
storage.min_free_space_gb Minimum free space to continue 5 GB
download.chunk_size_mb Download chunk size 8 MB
download.max_retries Max retries per file 5
download.retry_delay_sec Delay between retries 10 sec
download.rate_limit_delay Delay between API calls 0.1 sec
download.timeout_sec Request timeout 60 sec
scan.start_date Earliest date to scan 2020-01-01
scan.end_date Latest date (null = today) null

Usage

Basic Usage

# Full scan and download
python zoom_backup.py

# Resume interrupted download (skip scanning)
python zoom_backup.py --resume

# Scan only (no download)
python zoom_backup.py --scan-only

# Show statistics
python zoom_backup.py --status

Unattended Operation (Recommended)

Use the wrapper script for overnight/unattended backups:

# Make executable
chmod +x run_backup.sh

# Run with auto-restart
./run_backup.sh

# Watch logs in another terminal
tail -f zoom_backup.log

The wrapper script:

  • Automatically restarts on failure (up to 100 times)
  • Uses exponential backoff (10 sec → 5 min)
  • Checks disk availability before restart
  • Resets retry counter after 1 hour of successful operation
  • Exits when all files are downloaded

File Structure

Downloaded recordings are organized by user and date:

/backup/path/
├── user1@example.com/
│   ├── 2024-01-15/
│   │   ├── Meeting_Topic_10-30.mp4
│   │   ├── Meeting_Topic_10-30.m4a
│   │   ├── Meeting_Topic_10-30.vtt
│   │   └── Meeting_Topic_10-30.chat.txt
│   └── 2024-01-16/
│       └── ...
├── user2@example.com/
│   └── ...
├── progress.db          # SQLite progress database
├── zoom_backup.log      # Main log file
└── wrapper.log          # Wrapper script log

Supported File Types

  • MP4 - Video recordings
  • M4A - Audio only
  • VTT - Subtitles/captions
  • TRANSCRIPT - Meeting transcripts
  • CHAT - Chat logs
  • SHARED_SCREEN - Screen sharing recordings

Progress Database

The script uses SQLite to track progress:

-- Check pending files
sqlite3 progress.db "SELECT COUNT(*) FROM recordings WHERE status='pending'"

-- Check failed files
sqlite3 progress.db "SELECT local_path, error_message FROM recordings WHERE status='failed'"

-- Reset failed files to retry
sqlite3 progress.db "UPDATE recordings SET status='pending', retry_count=0 WHERE status='failed'"

Troubleshooting

Script stops with "Disk not mounted"

  • Ensure your external drive is connected and mounted
  • Check the mount point in config matches your system

Downloads are slow

  • Increase chunk_size_mb for faster networks
  • Check your internet connection

"Max retries exceeded" errors

  • Some files may be corrupted on Zoom's servers
  • Reset and retry: sqlite3 progress.db "UPDATE recordings SET status='pending', retry_count=0 WHERE status='failed'"

Missing users/recordings

  • Ensure scan.start_date covers your earliest recordings
  • The script fetches active, inactive, AND pending users
  • Deleted users are not recoverable via API

Reliability Features

Issue Solution
Disk disconnects Checks os.path.ismount() before each file
Network drops HTTP Range headers for resume + retry with backoff
Out of space Checks shutil.disk_usage() continuously
Ctrl+C interrupt Graceful shutdown saves progress to SQLite
Corrupted download Verifies file size, re-downloads on mismatch
Zoom rate limits Configurable delays + exponential backoff
Token expiration Auto-refresh OAuth token

License

MIT License - see LICENSE file.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Acknowledgments

This script was created to reliably back up ~300GB of Zoom recordings overnight. It has been tested with:

  • 8,800+ files
  • 290+ GB of data
  • 13 users (active, inactive, pending)
  • 10+ hours of continuous operation

About

Python script to download ALL Zoom cloud recordings with streaming download, SQLite progress tracking, resume on interruption, and auto-restart wrapper

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published