OBS video recording uploader to Cloudflare R2 with live streaming support
Go to file
Jeff Emmett 76b9485d2c Initial commit: OBS R2 video uploader and streaming service
- Cloudflare Worker for video serving from R2 bucket
- Admin panel with authentication and video management
- OBS integration for automatic video uploads
- HLS live streaming support with nginx-rtmp
- KV namespace for video metadata (visibility settings)
- Video gallery with thumbnails and playback
- Support for multiple video formats (mp4, mkv, mov, etc.)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 03:37:35 -08:00
obs_scripts Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
obs_uploader Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
scripts Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
streaming Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
worker Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
.dockerignore Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
.env.example Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
.gitignore Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
ADMIN.md Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
ADMIN_QUICKSTART.md Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
DEPLOY_UPDATES.md Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
Dockerfile Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
LICENSE Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
OBS_SETUP.md Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
QUICK_SETUP.md Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
README.md Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
SETUP.md Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
UPLOAD_FEATURE.md Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
cors-config.json Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
docker-compose.yml Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
package.json Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
requirements.txt Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00
start-obs-watcher.sh Initial commit: OBS R2 video uploader and streaming service 2025-11-25 03:37:35 -08:00

README.md

OBS to Cloudflare R2 Direct Upload System

Upload OBS Studio recordings directly to Cloudflare R2 storage with public video sharing capabilities. No YouTube required!

Features

  • Direct Upload: Upload video files to Cloudflare R2 with a single command
  • Progress Tracking: Real-time upload progress with visual feedback
  • Auto-Upload: File watcher automatically uploads new OBS recordings
  • Public Sharing: Instantly shareable video URLs via videos.jeffemmett.com
  • Video Gallery: Beautiful web gallery to browse all your videos
  • Admin Panel: Web-based admin interface to manage video visibility
  • Privacy Controls: Set videos as Private, Shareable, or Clip-Shareable
  • Clip Generation: Create shareable time-based clips from longer videos
  • Clipboard Integration: Public URLs automatically copied to clipboard
  • Large File Support: Multipart uploads for videos over 100MB
  • Cross-Platform: Works on Windows, macOS, and Linux

Quick Start

1. Installation

# Run the setup script
./scripts/setup.sh

# Authenticate with Cloudflare
wrangler login

2. Configuration

Edit .env file with your Cloudflare R2 credentials:

R2_ACCOUNT_ID=your_account_id
R2_ACCESS_KEY_ID=your_access_key
R2_SECRET_ACCESS_KEY=your_secret_key
R2_BUCKET_NAME=obs-videos
PUBLIC_DOMAIN=videos.jeffemmett.com

3. Deploy

# Create R2 bucket and deploy worker
./scripts/deploy.sh

4. Upload Your First Video

# Upload a video
./scripts/upload.sh /path/to/video.mp4

# The public URL will be displayed and copied to your clipboard

Usage

Manual Upload

Upload a single video file:

./scripts/upload.sh /path/to/video.mp4

Upload with custom name:

./scripts/upload.sh /path/to/video.mp4 my-awesome-video.mp4

Automatic Upload (File Watcher)

Watch a directory and auto-upload new recordings:

# Watch a specific directory
./scripts/start-watcher.sh /path/to/obs/recordings

# Or set OBS_RECORDING_DIR in .env and run:
./scripts/start-watcher.sh

The file watcher will:

  • Monitor the directory for new video files
  • Wait until recording is complete (file size stable)
  • Automatically upload the video
  • Copy the public URL to clipboard
  • Optionally delete the local file (if AUTO_DELETE_AFTER_UPLOAD=true)

View Your Videos

  • Direct Access: https://videos.jeffemmett.com/video-name.mp4
  • Gallery View: https://videos.jeffemmett.com/gallery
  • JSON API: https://videos.jeffemmett.com/ or https://videos.jeffemmett.com/api/list
  • Admin Panel: https://videos.jeffemmett.com/admin (requires authentication)

Admin Panel

Manage your video library with a powerful web-based admin interface.

Features

  • 📤 Manual Upload: Drag-and-drop video files directly in the browser

  • Video Visibility Control

    • 🔒 Private: Only you can view
    • 🔗 Shareable: Anyone with link can view
    • ✂️ Clip Shareable: Only time-based clips are shareable
  • Clip Generation: Create shareable clips with start/end times

  • Bulk Management: Search, filter, and manage multiple videos

  • Delete Videos: Remove videos directly from the admin panel

  • Statistics Dashboard: See breakdown of video visibility

  • Upload Progress: Real-time progress tracking for uploads

  • Empty State: Helpful UI when no videos exist

Setup Admin Panel

# Setup KV namespace and admin password
./scripts/setup-admin.sh

# Build worker with embedded admin interface
python3 scripts/build-worker.py

# Deploy
cd worker && wrangler deploy

Access admin panel at: https://videos.jeffemmett.com/admin

See ADMIN.md for complete admin documentation.

Project Structure

obs-r2-uploader/
├── obs_uploader/          # Python upload package
│   ├── upload.py          # Core upload script
│   ├── file_watcher.py    # Auto-upload daemon
│   └── config.py          # Configuration management
├── worker/                # Cloudflare Worker
│   ├── video-server.js    # Video serving logic
│   └── wrangler.toml      # Worker configuration
├── scripts/               # Convenience scripts
│   ├── setup.sh           # One-command setup
│   ├── deploy.sh          # Deploy worker
│   ├── upload.sh          # Upload wrapper
│   └── start-watcher.sh   # Start file watcher
├── .env                   # Your configuration (not in git)
├── .env.example           # Configuration template
└── requirements.txt       # Python dependencies

Configuration Options

All configuration is done via .env file:

Variable Required Description
R2_ACCOUNT_ID Yes Your Cloudflare account ID
R2_ACCESS_KEY_ID Yes R2 API access key
R2_SECRET_ACCESS_KEY Yes R2 API secret key
R2_BUCKET_NAME Yes Name of R2 bucket (default: obs-videos)
R2_ENDPOINT Auto R2 endpoint URL (auto-generated)
PUBLIC_DOMAIN Yes Your public domain (videos.jeffemmett.com)
OBS_RECORDING_DIR No Default directory for file watcher
AUTO_DELETE_AFTER_UPLOAD No Delete local file after upload (default: false)

Supported Video Formats

  • MP4 (.mp4)
  • MKV (.mkv)
  • MOV (.mov)
  • AVI (.avi)
  • WebM (.webm)
  • FLV (.flv)
  • WMV (.wmv)

Advanced Usage

Python Module

Use as a Python module in your own scripts:

from obs_uploader.config import Config
from obs_uploader.upload import R2Uploader

# Load configuration
config = Config()

# Create uploader
uploader = R2Uploader(config)

# Upload a file
public_url = uploader.upload_file(Path("/path/to/video.mp4"))
print(f"Uploaded: {public_url}")

Custom Worker Routes

Edit worker/wrangler.toml to customize routes and domains:

[env.production]
routes = [
  { pattern = "videos.jeffemmett.com/*", custom_domain = true }
]

Edit worker/video-server.js to customize the gallery appearance and functionality.

Troubleshooting

Upload fails with "Invalid credentials"

  • Verify your R2 API credentials in .env
  • Ensure the API token has read/write permissions for R2
  • Check that the bucket name matches

Videos not accessible via public URL

  • Verify CORS is configured (see SETUP.md)
  • Check that custom domain is set up in Cloudflare dashboard
  • Ensure worker is deployed: cd worker && wrangler deploy

File watcher not detecting new files

  • Verify the watch directory path is correct
  • Check file permissions on the directory
  • Ensure video file format is supported

Clipboard not working on Linux

Install xclip or xsel:

sudo apt-get install xclip
# or
sudo apt-get install xsel

Performance

  • Small files (<100MB): Simple upload with progress bar
  • Large files (>100MB): Automatic multipart upload with 10MB chunks
  • Network resilience: Automatic retries with exponential backoff
  • CDN caching: Cloudflare automatically caches videos globally

Security

  • All R2 credentials stored in .env (gitignored)
  • Videos are publicly accessible by URL (no authentication)
  • Consider signed URLs for sensitive content (not implemented yet)
  • CORS configured for browser access

Cost Considerations

Cloudflare R2 pricing (as of 2024):

  • Storage: $0.015/GB per month
  • Class A Operations (writes): $4.50 per million requests
  • Class B Operations (reads): $0.36 per million requests
  • Egress: FREE (no bandwidth charges!)

Example costs for 100GB of videos:

  • Storage: $1.50/month
  • 1000 uploads: ~$0.005
  • 10,000 views: ~$0.004

Contributing

This is a personal project, but feel free to fork and adapt for your own use!

License

MIT License - See LICENSE file for details

Acknowledgments

Built with:


Made with ❤️ by Jeff Emmett