obs-r2-uploader/obs_scripts/auto_upload.py

245 lines
6.9 KiB
Python

"""
OBS Python Script for Automatic R2 Upload
To use this script in OBS:
1. Open OBS Studio
2. Go to Tools → Scripts
3. Click the "+" button to add a script
4. Select this file (auto_upload.py)
5. Configure the settings in the script panel
6. Enable the script
Requirements:
- Python 3.8+ must be configured in OBS (Tools → Scripts → Python Settings)
- obs_uploader package must be installed
- .env file must be configured with R2 credentials
"""
import obspython as obs
import os
import sys
import subprocess
from pathlib import Path
# Script settings
enabled = True
upload_script_path = ""
project_root = ""
show_notifications = True
auto_delete = False
def script_description():
"""Return the description shown in OBS."""
return """<h2>OBS R2 Auto-Upload</h2>
<p>Automatically uploads completed recordings to Cloudflare R2.</p>
<p><b>Setup:</b></p>
<ol>
<li>Set the project root directory (where .env file is located)</li>
<li>Ensure Python dependencies are installed</li>
<li>Configure .env with R2 credentials</li>
<li>Enable the script</li>
</ol>
<p>When you stop recording, the video will be automatically uploaded.</p>
"""
def script_properties():
"""Define script properties shown in OBS settings."""
props = obs.obs_properties_create()
obs.obs_properties_add_bool(
props,
"enabled",
"Enable Auto-Upload"
)
obs.obs_properties_add_path(
props,
"project_root",
"Project Root Directory",
obs.OBS_PATH_DIRECTORY,
"",
""
)
obs.obs_properties_add_bool(
props,
"show_notifications",
"Show Upload Notifications"
)
obs.obs_properties_add_bool(
props,
"auto_delete",
"Delete Local File After Upload"
)
return props
def script_defaults(settings):
"""Set default values for settings."""
obs.obs_data_set_default_bool(settings, "enabled", True)
obs.obs_data_set_default_bool(settings, "show_notifications", True)
obs.obs_data_set_default_bool(settings, "auto_delete", False)
def script_update(settings):
"""Called when settings are updated."""
global enabled, project_root, show_notifications, auto_delete
enabled = obs.obs_data_get_bool(settings, "enabled")
project_root = obs.obs_data_get_string(settings, "project_root")
show_notifications = obs.obs_data_get_bool(settings, "show_notifications")
auto_delete = obs.obs_data_get_bool(settings, "auto_delete")
print(f"[R2 Upload] Settings updated:")
print(f" Enabled: {enabled}")
print(f" Project Root: {project_root}")
print(f" Notifications: {show_notifications}")
print(f" Auto-delete: {auto_delete}")
def script_load(settings):
"""Called when the script is loaded."""
print("[R2 Upload] Script loaded")
# Connect to recording stopped signal
obs.obs_frontend_add_event_callback(on_event)
def script_unload():
"""Called when the script is unloaded."""
print("[R2 Upload] Script unloaded")
def on_event(event):
"""Handle OBS events."""
if not enabled:
return
# Recording stopped event
if event == obs.OBS_FRONTEND_EVENT_RECORDING_STOPPED:
print("[R2 Upload] Recording stopped, preparing upload...")
# Get the last recording path
recording_path = get_last_recording_path()
if recording_path:
print(f"[R2 Upload] Found recording: {recording_path}")
upload_recording(recording_path)
else:
print("[R2 Upload] Could not determine recording path")
def get_last_recording_path():
"""Get the path of the last recording."""
# Get recording path from OBS output settings
output = obs.obs_frontend_get_recording_output()
if output:
settings = obs.obs_output_get_settings(output)
path = obs.obs_data_get_string(settings, "path")
obs.obs_data_release(settings)
obs.obs_output_release(output)
if path and os.path.exists(path):
return path
# Alternative: Get from config
config = obs.obs_frontend_get_profile_config()
if config:
# Try different possible config keys
keys = [
"AdvOut.RecFilePath",
"AdvOut.FFFilePath",
"SimpleOutput.FilePath"
]
for key in keys:
path = obs.config_get_string(config, "Output", key)
if path:
# This gives us the directory, not the file
# We'd need to find the most recent file
if os.path.isdir(path):
return get_most_recent_video(path)
return None
def get_most_recent_video(directory):
"""Get the most recently modified video file in a directory."""
video_extensions = ['.mp4', '.mkv', '.mov', '.avi', '.flv', '.wmv', '.webm']
video_files = []
for ext in video_extensions:
video_files.extend(Path(directory).glob(f'*{ext}'))
if not video_files:
return None
# Get most recent file
most_recent = max(video_files, key=lambda p: p.stat().st_mtime)
return str(most_recent)
def upload_recording(file_path):
"""Upload a recording to R2."""
if not project_root:
print("[R2 Upload] Error: Project root not configured")
return
if not os.path.exists(project_root):
print(f"[R2 Upload] Error: Project root does not exist: {project_root}")
return
# Construct command
upload_script = os.path.join(project_root, "obs_uploader", "upload.py")
if not os.path.exists(upload_script):
print(f"[R2 Upload] Error: Upload script not found: {upload_script}")
return
# Set environment variable for auto-delete
env = os.environ.copy()
if auto_delete:
env["AUTO_DELETE_AFTER_UPLOAD"] = "true"
# Build command
cmd = [sys.executable, upload_script, file_path]
print(f"[R2 Upload] Running: {' '.join(cmd)}")
try:
# Run upload in background
result = subprocess.Popen(
cmd,
cwd=project_root,
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
# Don't wait for completion - it can take a while
print(f"[R2 Upload] Upload started (PID: {result.pid})")
if show_notifications:
# Note: OBS doesn't have a built-in notification system
# This just prints to the log
print(f"[R2 Upload] Uploading {os.path.basename(file_path)} to R2...")
except Exception as e:
print(f"[R2 Upload] Error starting upload: {e}")
# Note: For this script to work properly in OBS, you need to:
# 1. Configure Python Settings in OBS to point to your Python installation
# 2. Ensure the Python environment has access to the obs_uploader package
# 3. Make sure .env file is properly configured
#
# Alternative approach: Use the file_watcher.py script instead, which runs
# independently of OBS and is more reliable.