OBS video recording uploader to Cloudflare R2 with live streaming support
Go to file
Jeff Emmett fd5868f569 Fix video playback from R2 with proper range request handling
Critical fixes for video streaming:

- Fix range request handling by using HEAD request first
  - Get total file size before processing range requests
  - Properly calculate Content-Range header with accurate boundaries
  - Prevent issues where object.size wasn't available on range requests

- Add proper CORS headers for video streaming
  - Expose Content-Length, Content-Range, Accept-Ranges headers
  - Allow Range header in requests
  - Enables video seeking and progressive loading in browsers

- Improve range request logic
  - Ensure end byte doesn't exceed file size
  - Calculate correct Content-Length for partial responses
  - Always return accurate byte ranges in 206 responses

These fixes resolve issues where videos wouldn't play or seek properly
due to incorrect Content-Range headers and missing CORS headers.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 22:07:17 -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 Fix video playback from R2 with proper range request handling 2025-11-25 22:07:17 -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