So I used this script to add extra replay buffer lengths, ran into all kinds of issues, ended up getting a new code from chatGPT (with 6 extra lengths instead of 3) because I don't know s*** about coding. To my surprise it worked except it clears the hotkeys I have set for them all every time I close & reopen OBS. Here's the code I have:
I also can't for the life me get OBS to auto launch (as admin) on boot, and enable replay buffer automatically. It used to work but then stopped working after I changed it to run as admin. It also never enabled replay buffer when closing & relaunching manually
Code:
import obspython as obs
import os, sys, subprocess, time
from time import sleep
from importlib import util
# Global variables tracking system states
enabled = True
debug_mode = False
saved_settings = None
# Track all 6 hotkey pointer references safely inside an array
hotkey_references = [obs.OBS_INVALID_HOTKEY_ID] * 6
# Store internal properties mapping
replay_configs = []
for i in range(1, 7):
replay_configs.append({
"seconds": 15 if i==1 else (30 if i==2 else (60 if i==3 else (180 if i==4 else (300 if i==5 else 600)))),
"path": "",
"remove": True,
"from_end": False
})
def file_in_use(fpath):
if os.path.exists(fpath):
try:
os.rename(fpath, fpath)
return False
except:
return True
return False
def ffmpeg_extract_subclip(filename, t1, t2, targetname=None):
if "get_setting" not in sys.modules:
from moviepy.config import get_setting
if "get_setting" not in sys.modules:
from moviepy.tools import subprocess_call
name, ext = os.path.splitext(filename)
if not targetname:
T1, T2 = [int(1000*t) for t in [t1, t2]]
targetname = "%sSUB%d_%d.%s" % (name, T1, T2, ext)
cmd = [get_setting("FFMPEG_BINARY"), "-y",
"-ss", "%0.2f"%t1,
"-i", filename,
"-t", "%0.2f"%(t2-t1),
"-vcodec", "copy", "-acodec", "copy", targetname]
if debug_mode:
subprocess_call(cmd)
else:
subprocess_call(cmd, None)
def save_and_get_last_replay():
timestamp = time.time()
obs.obs_frontend_replay_buffer_save()
path = get_last_replay()
if path is None:
sleep(2)
path = get_last_replay()
if not os.path.exists(path):
sleep(2)
path = get_last_replay()
for i in range(20):
file_timestamp = os.path.getctime(path)
if file_timestamp < timestamp:
sleep(1)
path = get_last_replay()
else:
break
file_timestamp = os.path.getctime(path)
if file_timestamp < timestamp:
return None
else:
return path
def get_last_replay():
replay_buffer = obs.obs_frontend_get_replay_buffer_output()
if not replay_buffer:
return None
cd = obs.calldata_create()
ph = obs.obs_output_get_proc_handler(replay_buffer)
obs.proc_handler_call(ph, "get_last_replay", cd)
path = obs.calldata_string(cd, "path")
obs.calldata_destroy(cd)
obs.obs_output_release(replay_buffer)
return path
# Unique callback entry handlers mapping directly to target configuration indexes
def trigger_replay1(pressed):
if pressed and enabled: execute_clipping_sequence(0)
def trigger_replay2(pressed):
if pressed and enabled: execute_clipping_sequence(1)
def trigger_replay3(pressed):
if pressed and enabled: execute_clipping_sequence(2)
def trigger_replay4(pressed):
if pressed and enabled: execute_clipping_sequence(3)
def trigger_replay5(pressed):
if pressed and enabled: execute_clipping_sequence(4)
def trigger_replay6(pressed):
if pressed and enabled: execute_clipping_sequence(5)
def execute_clipping_sequence(idx):
if obs.obs_frontend_replay_buffer_active() is False:
return
config = replay_configs[idx]
seconds = config["seconds"]
new_path = config["path"]
remove_source = config["remove"]
from_end = config["from_end"]
if seconds <= 0:
return
if "VideoFileClip" not in sys.modules:
from moviepy.editor import VideoFileClip
last_replay = save_and_get_last_replay()
if last_replay is not None and len(last_replay) > 0:
last_replay_folder = os.path.dirname(os.path.abspath(last_replay))
last_replay_name, last_replay_type = os.path.splitext(os.path.basename(last_replay))
if len(new_path) <= 0 or not os.path.exists(new_path):
new_path = last_replay_folder
new_replay = os.path.normpath(os.path.join(new_path, last_replay_name + "_" + str(seconds) + "s" + last_replay_type))
src_replay = os.path.normpath(last_replay)
if src_replay.lower() == new_replay.lower():
new_replay = os.path.normpath(os.path.join(new_path, last_replay_name + "_" + str(seconds) + "s_clip" + last_replay_type))
clip = VideoFileClip(src_replay)
duration = clip.duration
if duration > seconds:
if from_end:
ffmpeg_extract_subclip(src_replay, duration - seconds, duration, targetname=new_replay)
else:
ffmpeg_extract_subclip(src_replay, 0, seconds, targetname=new_replay)
else:
ffmpeg_extract_subclip(src_replay, 0, duration, targetname=new_replay)
clip.reader.close()
if clip.audio and clip.audio.reader:
clip.audio.reader.close_proc()
del clip.reader
del clip
if remove_source:
sleep(1)
for i in range(10):
if not file_in_use(src_replay):
try:
os.remove(src_replay)
break
except:
pass
sleep(1)
def script_description():
return "Unified Management Panel for 6 Additional Custom ReplayBuffer lengths."
def script_update(settings):
global enabled, debug_mode
enabled = obs.obs_data_get_bool(settings, "enabled")
debug_mode = obs.obs_data_get_bool(settings, "debug_mode")
for i in range(1, 7):
cfg = replay_configs[i-1]
cfg["seconds"] = obs.obs_data_get_int(settings, f"replay{i}_seconds")
cfg["path"] = obs.obs_data_get_string(settings, f"replay{i}_path")
cfg["remove"] = obs.obs_data_get_bool(settings, f"replay{i}_remove")
cfg["from_end"] = obs.obs_data_get_bool(settings, f"replay{i}_from_end")
def script_properties():
props = obs.obs_properties_create()
obs.obs_properties_add_bool(props, "enabled", "Enable Script")
obs.obs_properties_add_bool(props, "debug_mode", "Debug Mode")
for i in range(1, 7):
obs.obs_properties_add_int(props, f"replay{i}_seconds", f"Replay {i} Duration (seconds)", 0, 2000, 1)
obs.obs_properties_add_path(props, f"replay{i}_path", f"Replay {i} Output Path", obs.OBS_PATH_DIRECTORY, None, None)
obs.obs_properties_add_bool(props, f"replay{i}_remove", f"Replay {i} Delete Original Buffer File")
obs.obs_properties_add_bool(props, f"replay{i}_from_end", f"Replay {i} Cut From End (Instead of Start)")
return props
def register_all_hotkeys():
global hotkey_references, saved_settings
if saved_settings is None:
return
callbacks = [trigger_replay1, trigger_replay2, trigger_replay3, trigger_replay4, trigger_replay5, trigger_replay6]
for i in range(1, 7):
idx = i - 1
hk_id = f"mega_replay_slot_{i}_hk"
label = f"Save Replay {i}"
hotkey_references[idx] = obs.obs_hotkey_register_frontend(hk_id, label, callbacks[idx])
hk_array = obs.obs_data_get_array(saved_settings, hk_id)
obs.obs_hotkey_load(hotkey_references[idx], hk_array)
obs.obs_data_array_release(hk_array)
def unified_frontend_event_callback(event):
# Locks hotkey assignments safely into execution memory only after system arrays instantiate
if event == obs.OBS_FRONTEND_EVENT_FINISHED_LOADING:
register_all_hotkeys()
def script_load(settings):
global saved_settings
saved_settings = settings
if not obs.obs_data_has_user_value(settings, "enabled"):
obs.obs_data_set_default_bool(settings, "enabled", True)
# Inject baseline defaults matching your structural choices
defaults = [15, 30, 60, 180, 300, 600]
for i in range(1, 7):
if not obs.obs_data_has_user_value(settings, f"replay{i}_seconds"):
obs.obs_data_set_default_int(settings, f"replay{i}_seconds", defaults[i-1])
if not obs.obs_data_has_user_value(settings, f"replay{i}_remove"):
obs.obs_data_set_default_bool(settings, f"replay{i}_remove", True)
obs.obs_frontend_add_event_callback(unified_frontend_event_callback)
register_all_hotkeys()
def script_save(settings):
global hotkey_references
for i in range(1, 7):
idx = i - 1
if hotkey_references[idx] == obs.OBS_INVALID_HOTKEY_ID:
continue
hk_id = f"mega_replay_slot_{i}_hk"
hk_array = obs.obs_hotkey_save(hotkey_references[idx])
obs.obs_data_set_array(settings, hk_id, hk_array)
obs.obs_data_array_release(hk_array)
I also can't for the life me get OBS to auto launch (as admin) on boot, and enable replay buffer automatically. It used to work but then stopped working after I changed it to run as admin. It also never enabled replay buffer when closing & relaunching manually
Last edited: