# 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