294 lines
8.1 KiB
Markdown
294 lines
8.1 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# Run the setup script
|
|
./scripts/setup.sh
|
|
|
|
# Authenticate with Cloudflare
|
|
wrangler login
|
|
```
|
|
|
|
### 2. Configuration
|
|
|
|
Edit `.env` file with your Cloudflare R2 credentials:
|
|
|
|
```env
|
|
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
|
|
|
|
```bash
|
|
# Create R2 bucket and deploy worker
|
|
./scripts/deploy.sh
|
|
```
|
|
|
|
### 4. Upload Your First Video
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
./scripts/upload.sh /path/to/video.mp4
|
|
```
|
|
|
|
Upload with custom name:
|
|
|
|
```bash
|
|
./scripts/upload.sh /path/to/video.mp4 my-awesome-video.mp4
|
|
```
|
|
|
|
### Automatic Upload (File Watcher)
|
|
|
|
Watch a directory and auto-upload new recordings:
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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](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:
|
|
|
|
```python
|
|
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:
|
|
|
|
```toml
|
|
[env.production]
|
|
routes = [
|
|
{ pattern = "videos.jeffemmett.com/*", custom_domain = true }
|
|
]
|
|
```
|
|
|
|
### Gallery Customization
|
|
|
|
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:
|
|
```bash
|
|
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:
|
|
- [Cloudflare R2](https://www.cloudflare.com/products/r2/) - Object storage
|
|
- [Cloudflare Workers](https://workers.cloudflare.com/) - Edge computing
|
|
- [boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/index.html) - AWS SDK for Python
|
|
- [watchdog](https://python-watchdog.readthedocs.io/) - File system monitoring
|
|
|
|
---
|
|
|
|
Made with ❤️ by Jeff Emmett
|