OBS附加重播缓冲区Python脚本中出错

2024-09-29 21:46:30 发布

您现在位置:Python中文网/ 问答频道 /正文

有一个Python脚本,它通过将完整的重播调整到一个设定的长度来添加3个额外的重播缓冲区长度。以下是完整的脚本:

#!/usr/bin/env python
# title             : AdditionalReplays.py
# description       : Adds 3 \"additional\" ReplayBuffer.
# author            : Bootscreen
# date              : 2019 05 11
# version           : 0.1
# dependencies      : - Python 3.6 (https://www.python.org/ or https://www.python.org/ftp/python/3.6.0/python-3.6.0-amd64-webinstall.exe)
# notes             : Follow this step for this script to work:
#                   : Python:
#                   :   1. Install python (v3.6 and 64 bits, this is important)
#                   :   2. Install moviepy (pip install moviepy)
#                   : OBS:
#                   :   1. Go to Tools › Scripts
#                   :   2. Click the "Python Settings" tab
#                   :   3. Select your python install path
#                   :   4. Click the "Scripts" tab
#                   :   5. Click the "+" button and add this script
#                   :   6. Set the seconds and where it should be saved
#                   :   7. Set Hotkeys in OBS Settings
#                   :   8. Check "Enable"
#                   :
# python_version    : 3.6+
# ==============================================================================

import obspython as obs
import os, sys, subprocess, time
from time import sleep
from shutil import copyfile 
from importlib import util 
from datetime import datetime

enabled = True
debug_mode = False
replay1_hotkey = obs.OBS_INVALID_HOTKEY_ID
replay1_seconds = 60
replay1_path = "R:/"
replay1_remove = False
replay1_from_end = False
replay2_hotkey = obs.OBS_INVALID_HOTKEY_ID
replay2_seconds = 180
replay2_path = "R:/"
replay2_remove = True
replay2_from_end = False
replay3_hotkey = obs.OBS_INVALID_HOTKEY_ID
replay3_seconds = 300
replay3_path = "R:/"
replay3_remove = True
replay3_from_end = False

def file_in_use(fpath):
    if os.path.exists(fpath):
        try:
            os.rename(fpath, fpath)
            return False
        except:
            return True
    
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
    """ Makes a new video file playing video file ``filename`` between
        the times ``t1`` and ``t2``. """
    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 check_and_install_package(package):
    if not check_package(package):
        install_package(package)
        
def check_package(package):
    if util.find_spec(package) is None:
        return False
    else:
        return True
        
def install_package(package):
    python_path = os.path.join(sys.prefix ,"python.exe")
    subprocess.call([python_path , "-m", "pip", "install", package])
    
def install_needed(prop, props):
    install_package("moviepy")
    from moviepy.config import get_setting
    from moviepy.tools import subprocess_call
    from moviepy.editor import VideoFileClip

def save_and_get_last_replay():
    timestamp = time.time()
    obs.obs_frontend_replay_buffer_save()
    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():
    sleep(10)
    replay_buffer = obs.obs_frontend_get_replay_buffer_output()
    cd = obs.calldata_create()
    ph = obs.obs_output_get_proc_handler(replay_buffer)
    path = obs.calldata_string(cd, "path")
    obs.proc_handler_call(ph, "get_last_replay", cd)
    obs.calldata_destroy(cd)
    obs.obs_output_release(replay_buffer)
    return path
    
def save_replay1(pressed):
    if pressed and enabled:
        save_replay(replay1_seconds, replay1_path, replay1_remove, replay1_from_end)
    
def save_replay2(pressed):
    if pressed and enabled:
        save_replay(replay2_seconds, replay2_path, replay2_remove, replay2_from_end)
    
def save_replay3(pressed):
    if pressed and enabled:
        save_replay(replay3_seconds, replay3_path, replay3_remove, replay3_from_end)
    
def save_replay(seconds, new_path, remove, from_end):
    global debug_mode
    if debug_mode: 
        print("[AR] save_replay")
        print("[AR] seconds=" + str(seconds) )
        print("[AR] path=" + new_path)
        print("[AR] remove=%s" %(remove))
        print("[AR] from_end=%s" %(from_end))
        
    if not enabled:
        return
        
    if obs.obs_frontend_replay_buffer_active() is False:
        if debug_mode: print("[AR] replaybuffer not active")
        return
    
    if seconds > 0:
        if "VideoFileClip" not in sys.modules:
            from moviepy.config import get_setting
            from moviepy.tools import subprocess_call
            from moviepy.editor import VideoFileClip
        
        last_replay = save_and_get_last_replay()
        if last_replay is not None and len(last_replay) > 0:
            if debug_mode: 
                print("[AR] last_replay=" + last_replay)
                
            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
            
            if debug_mode: 
                print("[AR] last_replay_folder=" + last_replay_folder)
                print("[AR] last_replay_name=" + last_replay_name)
                print("[AR] last_replay_type=" + last_replay_type)
                print("[AR] new_path=" + new_path)
                
            if last_replay_folder == new_path:
                new_replay = os.path.join(new_path, last_replay_name + "_" + seconds + "s" + last_replay_type)
            else:
                new_replay = os.path.join(new_path, last_replay_name + last_replay_type)
               
            if debug_mode: 
                print("[AR] last_replay=" + last_replay)
                print("[AR] new_replay=" + new_replay)
            
            clip = VideoFileClip(last_replay)
            duration = clip.duration
            
            if duration > seconds:
                if from_end:
                    if debug_mode: print("[AR] from_end")
                    ffmpeg_extract_subclip(last_replay, duration - seconds, duration, targetname=new_replay)
                else:
                    if debug_mode: print("[AR] from_begin")
                    ffmpeg_extract_subclip(last_replay, 0, seconds, targetname=new_replay)
            else:
                copyfile(last_replay, new_replay)
                
            clip.reader.close()
            if clip.audio and clip.audio.reader:
                clip.audio.reader.close_proc()
            del clip.reader
            del clip
            
            if remove and os.path.exists(new_replay):
                try:
                    if debug_mode: print("[AR] try remove")
                    for x in range(10):
                        if not file_in_use(last_replay):
                            break
                        if debug_mode: print("[AR] file not writeable, wait 0.5 seconds")
                        sleep(0.5)
                    if debug_mode: print("[AR] delete file:" + last_replay)
                    os.remove(last_replay)
                except:
                    print("[AR] error ", sys.exc_info()[0], " on remove : ", last_replay)
                    
def script_defaults(settings):
    global global_settings
    global debug_mode
    if debug_mode: print("[AR] Loaded defaults.")
    
    obs.obs_data_set_default_bool(settings, "enabled", enabled)
    obs.obs_data_set_default_bool(settings, "debug_mode", debug_mode)
    obs.obs_data_set_default_int(settings, "replay1_seconds", replay1_seconds)
    obs.obs_data_set_default_int(settings, "replay2_seconds", replay2_seconds)
    obs.obs_data_set_default_int(settings, "replay3_seconds", replay3_seconds)
    obs.obs_data_set_default_bool(settings, "replay1_remove", replay1_remove)
    obs.obs_data_set_default_bool(settings, "replay2_remove", replay2_remove)
    obs.obs_data_set_default_bool(settings, "replay3_remove", replay3_remove)
    obs.obs_data_set_default_bool(settings, "replay1_from_end", replay1_from_end)
    obs.obs_data_set_default_bool(settings, "replay2_from_end", replay2_from_end)
    obs.obs_data_set_default_bool(settings, "replay3_from_end", replay3_from_end)
    
def script_description():
    return "Adds 3 \"additional\" replay buffers by saving the normal replay buffer clip and cutting out time from the beginning or the end.<br/>" +\
    "The times entered should be lower than the current replay buffer time.<br/>" +\
    "When you leave the save path empty, the path of the orginial replay is used and the seconds are attached at the end." + \
    "<hr/>"
    
def script_properties():
    global debug_mode
    if debug_mode: print("[AR] Loaded properties.")
    
    props = obs.obs_properties_create()
    if not check_package("moviepy"):
        obs.obs_properties_add_button(props, "install_libs", "installs moviepy with pip", install_needed)
    obs.obs_properties_add_bool(props, "enabled", "Enabled")
    obs.obs_properties_add_bool(props, "debug_mode", "Debug Mode")
    obs.obs_properties_add_int(props, "replay1_seconds", "Replay 1 time (seconds)", 1, 600, 1 )
    obs.obs_properties_add_path(props, "replay1_path", "Replay 1 save path", obs.OBS_PATH_DIRECTORY, "", None )
    obs.obs_properties_add_bool(props, "replay1_remove", "Remove original replay?")
    obs.obs_properties_add_bool(props, "replay1_from_end", "Cut time from end instead of beginning?")
    obs.obs_properties_add_int(props, "replay2_seconds", "Replay 2 time (seconds)", 1, 600, 1 )
    obs.obs_properties_add_path(props, "replay2_path", "Replay 1 save path", obs.OBS_PATH_DIRECTORY, "", None )
    obs.obs_properties_add_bool(props, "replay2_remove", "Remove original replay?")
    obs.obs_properties_add_bool(props, "replay2_from_end", "Cut time from end instead of begin?")
    obs.obs_properties_add_int(props, "replay3_seconds", "Replay 3 time (seconds)", 1, 600, 1 )
    obs.obs_properties_add_path(props, "replay3_path", "Replay 3 save path", obs.OBS_PATH_DIRECTORY, "", None )
    obs.obs_properties_add_bool(props, "replay3_remove", "Remove original replay?")
    obs.obs_properties_add_bool(props, "replay3_from_end", "Cut time from end instead of begin?")

    return props

def script_save(settings):
    global debug_mode
    if debug_mode: print("[AR] Saved properties.")
    
    script_update(settings)

def script_load(settings):
    global debug_mode
    global replay1_hotkey
    global replay2_hotkey
    global replay3_hotkey
    
    if debug_mode: print("[AR] Loaded script .")
    
    replay1_hotkey = obs.obs_hotkey_register_frontend("additional_replays.replay1", "Replay 1", save_replay1)
    hotkey_save_array = obs.obs_data_get_array(settings, "additional_replays.replay1")
    obs.obs_hotkey_load(replay1_hotkey, hotkey_save_array)
    obs.obs_data_array_release(hotkey_save_array)
    
    replay2_hotkey = obs.obs_hotkey_register_frontend("additional_replays.replay2", "Replay 2", save_replay2)
    hotkey_save_array = obs.obs_data_get_array(settings, "additional_replays.replay2")
    obs.obs_hotkey_load(replay2_hotkey, hotkey_save_array)
    obs.obs_data_array_release(hotkey_save_array)
    
    replay3_hotkey = obs.obs_hotkey_register_frontend("additional_replays.replay3", "Replay 3", save_replay3)
    hotkey_save_array = obs.obs_data_get_array(settings, "additional_replays.replay3")
    obs.obs_hotkey_load(replay3_hotkey, hotkey_save_array)
    obs.obs_data_array_release(hotkey_save_array)
    
    script_update(settings)
    
def script_unload():
    global debug_mode
    if debug_mode: print("[AR] Unloaded script.")
    
    obs.obs_hotkey_unregister(save_replay1)

def script_update(settings):
    global debug_mode
    if debug_mode: print("[AR] Updated properties.")
    
    global enabled
    global replay1_path
    global replay1_remove
    global replay1_from_end
    global replay1_seconds
    global replay2_path
    global replay2_remove
    global replay2_from_end
    global replay2_seconds
    global replay3_path
    global replay3_remove
    global replay3_from_end
    global replay3_seconds
            
    debug_mode = obs.obs_data_get_bool(settings, "debug_mode")
    enabled = obs.obs_data_get_bool(settings, "enabled")
    
    replay1_path = obs.obs_data_get_string(settings, "replay1_path")
    replay1_remove = obs.obs_data_get_bool(settings, "replay1_remove")
    replay1_from_end = obs.obs_data_get_bool(settings, "replay1_from_end")
    replay1_seconds = obs.obs_data_get_int(settings, "replay1_seconds")
    hotkey_save_array = obs.obs_hotkey_save(replay1_hotkey)
    obs.obs_data_set_array(settings, "additional_replays.replay1", hotkey_save_array)
    obs.obs_data_array_release(hotkey_save_array)
    
    replay2_path = obs.obs_data_get_string(settings, "replay2_path")
    replay2_remove = obs.obs_data_get_bool(settings, "replay2_remove")
    replay2_from_end = obs.obs_data_get_bool(settings, "replay2_from_end")
    replay2_seconds = obs.obs_data_get_int(settings, "replay2_seconds")
    hotkey_save_array = obs.obs_hotkey_save(replay2_hotkey)
    obs.obs_data_set_array(settings, "additional_replays.replay2", hotkey_save_array)
    obs.obs_data_array_release(hotkey_save_array)
    
    replay3_path = obs.obs_data_get_string(settings, "replay3_path")
    replay3_remove = obs.obs_data_get_bool(settings, "replay3_remove")
    replay3_from_end = obs.obs_data_get_bool(settings, "replay3_from_end")
    replay3_seconds = obs.obs_data_get_int(settings, "replay3_seconds")
    hotkey_save_array = obs.obs_hotkey_save(replay3_hotkey)
    obs.obs_data_set_array(settings, "additional_replays.replay3", hotkey_save_array)
    obs.obs_data_array_release(hotkey_save_array)

但是,当热键执行脚本时,日志显示:

[AdditionalReplays.py] [AR] save_replay
[AdditionalReplays.py] [AR] seconds=60
[AdditionalReplays.py] [AR] path=R:/
[AdditionalReplays.py] [AR] remove=True
[AdditionalReplays.py] [AR] from_end=False
[AdditionalReplays.py] Traceback (most recent call last):
[AdditionalReplays.py]   File "C:/Program Files/obs-studio/data/obs-plugins/frontend-tools/scripts\AdditionalReplays.py", line 136, in save_replay1
[AdditionalReplays.py]     save_replay(replay1_seconds, replay1_path, replay1_remove, replay1_from_end)
[AdditionalReplays.py]   File "C:/Program Files/obs-studio/data/obs-plugins/frontend-tools/scripts\AdditionalReplays.py", line 168, in save_replay
[AdditionalReplays.py]     last_replay = save_and_get_last_replay()
[AdditionalReplays.py]   File "C:/Program Files/obs-studio/data/obs-plugins/frontend-tools/scripts\AdditionalReplays.py", line 110, in save_and_get_last_replay
[AdditionalReplays.py]     file_timestamp = os.path.getctime(path)
[AdditionalReplays.py]   File "C:/Users/chris/AppData/Local/Programs/Python/Python36\lib\genericpath.py", line 65, in getctime
[AdditionalReplays.py]     return os.stat(filename).st_ctime
[AdditionalReplays.py] TypeError: stat: path should be string, bytes, os.PathLike or integer, not NoneType

有人知道如何修复这个错误吗?我一直在OBS论坛页面上提问,但没有得到任何人的回答,我自己也有一点Python知识,但还没有解决这个问题


Tags: pathfromreplaydataifsettingssaveend

热门问题