245 lines
6.9 KiB
Python
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.
|