CLI tool to download Zoom cloud recordings and extract audio for transcription
Project description
dlzoom
Download Zoom cloud recordings from the command line.
Simple CLI tool to download audio recordings and metadata from Zoom meetings using meeting IDs.
Features
- ๐ต Download audio recordings (M4A format)
- ๐ Download transcripts, chat logs, and timelines
- ๐ Automatic audio extraction from video files (MP4 โ M4A)
- ๐ Server-to-Server OAuth authentication
- ๐ JSON output for automation
- ๐ฏ Support for recurring meetings and PMI
- โณ Wait for recording processing with
--wait - ๐ Check recording availability before downloading
- ๐ก๏ธ Secure (credentials never exposed in logs)
- ๐ Automatic retry with exponential backoff
- ๐ช Production-ready with 119 tests
Installation
Choose your preferred method:
๐ Quick Try (uvx - Instant Run, No Install)
Fastest way to try dlzoom - requires Python 3.11+ and ffmpeg:
# Install uv first (if not installed)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Run dlzoom instantly (no installation needed!)
uvx dlzoom 123456789 --check-availability
๐ฆ PyPI Install (Recommended for Regular Use)
# Install with pip
pip install dlzoom
# Or with uv (10-100x faster)
uv pip install dlzoom
# Or with uv tool (isolated installation)
uv tool install dlzoom
Note: Requires Python 3.11+ and ffmpeg (see below).
๐ณ Docker (Zero Dependencies - Everything Included!)
Best for: Production, CI/CD, no local dependencies
# Run with Docker (includes Python + ffmpeg)
docker run -it --rm \
-v $(pwd)/recordings:/app/downloads \
-e ZOOM_ACCOUNT_ID="your_account_id" \
-e ZOOM_CLIENT_ID="your_client_id" \
-e ZOOM_CLIENT_SECRET="your_secret" \
yanivgolan1/dlzoom:latest \
123456789```
**Or use GitHub Container Registry:**
```bash
docker run -it --rm \
-v $(pwd)/recordings:/app/downloads \
-e ZOOM_ACCOUNT_ID="your_account_id" \
-e ZOOM_CLIENT_ID="your_client_id" \
-e ZOOM_CLIENT_SECRET="your_secret" \
ghcr.io/yaniv-golan/dlzoom:latest \
123456789```
### ๐ง From Source (Development)
```bash
# Clone the repository
git clone https://github.com/yaniv-golan/dlzoom.git
cd dlzoom
# Create virtual environment (recommended)
python3.11 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install
pip install -e .
Prerequisites (for non-Docker installations)
- Python 3.11+ (required)
- ffmpeg (required for audio extraction from video files)
Install ffmpeg:
# macOS
brew install ffmpeg
# Ubuntu/Debian
sudo apt install ffmpeg
# Windows (via Chocolatey)
choco install ffmpeg
# Windows (via winget)
winget install ffmpeg
Docker users: No need to install Python or ffmpeg - everything is included!
Quick Start
1. Get Zoom API Credentials
Coming in v0.2: One-click authentication! No more manual app setup. See Roadmap.
Current method (Server-to-Server OAuth):
- Go to Zoom Marketplace
- Sign in โ Develop โ Build App
- Create a Server-to-Server OAuth app
- Copy your credentials:
- Account ID
- Client ID
- Client Secret
- Add required scopes:
recording:read:adminmeeting:read:admin
Why this is temporary: This approach requires manual OAuth app creation and credential management. In v0.2, we're adding one-click OAuth authentication (like gh auth login) where you just authorize dlzoom in your browser and you're done!
2. Configure Credentials
Create a .env file in your working directory:
ZOOM_ACCOUNT_ID=your_account_id_here
ZOOM_CLIENT_ID=your_client_id_here
ZOOM_CLIENT_SECRET=your_client_secret_here
Or set environment variables:
export ZOOM_ACCOUNT_ID="your_account_id"
export ZOOM_CLIENT_ID="your_client_id"
export ZOOM_CLIENT_SECRET="your_client_secret"
Or use a config file:
# config.yaml
zoom_account_id: "your_account_id"
zoom_client_id: "your_client_id"
zoom_client_secret: "your_client_secret"
log_level: "INFO"
3. Download a Recording
dlzoom 123456789
Usage
Basic Commands
Check if recording is available:
dlzoom 123456789 --check-availability
List all recordings for a meeting:
dlzoom 123456789 --list
Download recording (audio + transcript + chat + timeline):
dlzoom 123456789
Download with custom output name:
dlzoom 123456789 --output-name "my_meeting"
Download to specific directory:
dlzoom 123456789 --output-dir ~/Downloads/zoom
Wait for recording to finish processing:
dlzoom 123456789 --wait 30
Password-protected recordings:
dlzoom 123456789 --password "meeting_password"
Advanced Options
Use config file:
dlzoom 123456789 --config config.yaml
Verbose output (see detailed logs):
dlzoom 123456789 --verbose
Debug mode (full API responses):
dlzoom 123456789 --debug
JSON output (for automation):
dlzoom 123456789 --json
Dry run (see what would be downloaded):
dlzoom 123456789 --dry-run
Custom filename template:
dlzoom 123456789\
--filename-template "{topic}_{start_time:%Y%m%d}"
Custom folder structure:
dlzoom 123456789\
--folder-template "{start_time:%Y}/{start_time:%m}"
Select specific recording instance (for recurring meetings):
dlzoom 123456789 --recording-id "abc123def456"
Skip Downloads
Skip transcript download:
dlzoom 123456789 --skip-transcript
Skip chat log download:
dlzoom 123456789 --skip-chat
Skip timeline download:
dlzoom 123456789 --skip-timeline
All Options
dlzoom [OPTIONS] MEETING_ID
Options:
--output-dir, -o PATH Output directory (default: current directory)
--output-name, -n TEXT Base filename (default: meeting_id)
--verbose, -v Show detailed operation information
--debug, -d Show full API responses and trace
--json, -j JSON output mode (machine-readable)
--list, -l List all recordings with timestamps
--check-availability, -c Check if recording is ready
--recording-id TEXT Select specific recording by UUID
--wait MINUTES Wait for recording processing (timeout)
--skip-transcript Skip transcript download
--skip-chat Skip chat log download
--skip-timeline Skip timeline download
--dry-run Show what would be downloaded
--password, -p TEXT Password for protected recordings
--log-file PATH Write structured log (JSONL format)
--config PATH Path to config file (JSON/YAML)
--filename-template TEXT Custom filename template
--folder-template TEXT Custom folder structure template
--from-date TEXT Start date for batch (YYYY-MM-DD)
--to-date TEXT End date for batch (YYYY-MM-DD)
--help Show this message and exit
--version Show version and exit
Template Variables
Use in --filename-template and --folder-template:
{topic}- Meeting topic{meeting_id}- Meeting ID{host_email}- Host email address{start_time:%Y%m%d}- Start time (format with strftime codes){duration}- Meeting duration
Examples:
# Date-based filename
--filename-template "{start_time:%Y%m%d}_{topic}"
# Organized by date
--folder-template "{start_time:%Y}/{start_time:%m}"
# Include host
--filename-template "{host_email}_{topic}_{start_time:%Y%m%d}"
Common Use Cases
Download Latest Recording from Recurring Meeting
dlzoom 123456789 --verbose
Download Specific Instance
# List all instances first
dlzoom 123456789 --list
# Download specific one
dlzoom 123456789 --recording-id "abc123def456"
Automated Pipeline (JSON Output)
dlzoom 123456789 --json > recording.json
Batch Processing
#!/bin/bash
for meeting_id in 111111111 222222222 333333333; do
dlzoom $meeting_id --output-dir ./recordings
done
Wait for Recording to Process
# Wait up to 60 minutes for processing
dlzoom 123456789 --wait 60
Troubleshooting
Authentication Failed
Error: Authentication failed
Solution: Check your credentials in .env or environment variables.
Meeting ID Format Invalid
Error: Invalid meeting ID format
Solution: Meeting IDs must be:
- 9-12 digit numbers (e.g.,
123456789) - Or UUID format (e.g.,
abc123XYZ+/=_-)
Recording Not Found
Error: Recording not found
Possible causes:
- Meeting wasn't recorded
- Recording not yet processed (use
--wait) - No permission to access recording
- Wrong meeting ID
Check availability first:
dlzoom 123456789 --check-availability
ffmpeg Not Found
Error: ffmpeg not found in PATH
Solution: Install ffmpeg:
# macOS
brew install ffmpeg
# Ubuntu/Debian
sudo apt install ffmpeg
Rate Limit Exceeded
Error: Rate limit exceeded
Solution: Wait a few minutes and try again. The tool automatically retries with exponential backoff.
Insufficient Disk Space
Error: Insufficient disk space
Solution: Free up space or use --output-dir to save to a different location.
Configuration Files
JSON Config
{
"zoom_account_id": "your_account_id",
"zoom_client_id": "your_client_id",
"zoom_client_secret": "your_client_secret",
"output_dir": "./recordings",
"log_level": "INFO"
}
YAML Config
zoom_account_id: "your_account_id"
zoom_client_id: "your_client_id"
zoom_client_secret: "your_client_secret"
output_dir: "./recordings"
log_level: "INFO"
Use with:
dlzoom 123456789 --config config.yaml
Output Files
Audio file:
- Format: M4A (AAC audio)
- Naming:
{meeting_id}.m4aor custom via--output-name
Transcript file:
- Format: VTT (WebVTT)
- Naming:
{meeting_id}_transcript.vtt
Chat log:
- Format: TXT
- Naming:
{meeting_id}_chat.txt
Timeline:
- Format: JSON
- Naming:
{meeting_id}_timeline.json - Contains: Meeting events (joins, leaves, screen shares, etc.)
Metadata:
- Format: JSON
- Naming:
{meeting_id}_metadata.json - Contains: Meeting info, participants, recording details
Requirements
- Python 3.8 or higher
- ffmpeg (for audio extraction)
- Zoom Server-to-Server OAuth app
Development
# Clone repository
git clone <repo-url>
cd dlzoom
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # or `.venv\Scripts\activate` on Windows
# Install in development mode
pip install -e .
# Run tests
pytest tests/ -v
# Run with coverage
pytest tests/ --cov=src/dlzoom --cov-report=term-missing
Version
v0.1.0 - Initial release (2025-10-02)
See CHANGELOG.md for detailed release notes.
Roadmap
Planned for future releases:
v0.2 (Next) - OAuth Authentication ๐
-
๐ One-click authentication - No more manual OAuth app setup!
dlzoom auth login # Opens browser, authorize, done! dlzoom 123456789 # Just works
-
๐ Automatic token refresh
-
๐ค Per-user authentication (no shared credentials)
-
๐ Secure token storage in
~/.dlzoom/credentials -
๐ฑ Multiple profiles support
v0.3
- ๐ Batch download by date range
- ๐จ More output formats (CSV, TSV)
- ๐ Token encryption (system keychain)
Known Limitations
Feature Limitations
- No standalone "list all recordings" command (requires meeting ID)
- Audio quality parameter not exposed via CLI (internal only)
- No batch download by date range
- No listing of all meetings/recordings
License
MIT License - see LICENSE file for details.
Contributing
We welcome contributions! Here's how you can help:
Quick Start for Contributors
-
Fork and clone the repository
-
Set up development environment:
python3.11 -m venv .venv source .venv/bin/activate pip install -e ".[dev]"
-
Run tests:
pytest tests/ -v
-
Make your changes and ensure tests pass
-
Submit a pull request
Guidelines
- Follow Conventional Commits for commit messages
- Add tests for new features
- Update documentation as needed
- Ensure all CI checks pass
Commit Message Format
<type>(<scope>): <subject>
Examples:
feat(cli): add support for CSV export
fix(auth): handle expired OAuth tokens
docs: update installation instructions
Types:
feat- New featurefix- Bug fixdocs- Documentationtest- Testsrefactor- Code refactoringchore- Maintenance
For detailed guidelines, see CONTRIBUTING.md.
Security
Security is important to us. If you discover a security vulnerability:
- Do not open a public issue
- Email yaniv@golan.name with details
- See SECURITY.md for our security policy
Security Features
- โ Credentials never logged or exposed
- โ Input validation (prevents injection attacks)
- โ Atomic file operations
- โ Automatic security scanning (Trivy)
- โ Docker images run as non-root user
Support
For issues and questions:
- ๐ Report bugs
- ๐ก Request features
- ๐ฌ GitHub Discussions
- ๐ Documentation
Credits
Built with:
- Click / Rich-Click - CLI framework
- Rich - Terminal output
- Requests - HTTP client
- pytest - Testing framework
Acknowledgments
Thanks to all contributors and the open source community.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dlzoom-0.1.0.tar.gz.
File metadata
- Download URL: dlzoom-0.1.0.tar.gz
- Upload date:
- Size: 49.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a990ce7d8f4cde26dbbefd0da862730c653efd8779178a5708fccb2d20753a3d
|
|
| MD5 |
420801b2969458416f98558d2b4ffff2
|
|
| BLAKE2b-256 |
406110125774aa0bbce2453f7485e07f53c82838cd882fbaab0327afe3334b78
|
Provenance
The following attestation bundles were made for dlzoom-0.1.0.tar.gz:
Publisher:
release.yml on yaniv-golan/dlzoom
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dlzoom-0.1.0.tar.gz -
Subject digest:
a990ce7d8f4cde26dbbefd0da862730c653efd8779178a5708fccb2d20753a3d - Sigstore transparency entry: 580153588
- Sigstore integration time:
-
Permalink:
yaniv-golan/dlzoom@315cb32f03da328283477a997bcf0efc7ebaebb3 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/yaniv-golan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@315cb32f03da328283477a997bcf0efc7ebaebb3 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dlzoom-0.1.0-py3-none-any.whl.
File metadata
- Download URL: dlzoom-0.1.0-py3-none-any.whl
- Upload date:
- Size: 36.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d67dcd9a1521aa8d586fa49ca62b5c4e468fa9a4ca457d87cfdf6c4ba9107fb6
|
|
| MD5 |
c8c6be1575a74925ee222dc91a02a6c5
|
|
| BLAKE2b-256 |
fa430ee622b8e973cf8fe408f7e88cc03d431f0490c9ac10797c95acd18cc7bf
|
Provenance
The following attestation bundles were made for dlzoom-0.1.0-py3-none-any.whl:
Publisher:
release.yml on yaniv-golan/dlzoom
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dlzoom-0.1.0-py3-none-any.whl -
Subject digest:
d67dcd9a1521aa8d586fa49ca62b5c4e468fa9a4ca457d87cfdf6c4ba9107fb6 - Sigstore transparency entry: 580153655
- Sigstore integration time:
-
Permalink:
yaniv-golan/dlzoom@315cb32f03da328283477a997bcf0efc7ebaebb3 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/yaniv-golan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@315cb32f03da328283477a997bcf0efc7ebaebb3 -
Trigger Event:
push
-
Statement type: