URLhttps://learnscript.net/zh/obs-python-scripting/scripts/
    复制链接转到说明  示例

    如何编写可在 OBS 中运行的 Python 脚本

    我被代码海扁署名-非商业-禁演绎
    阅读 15:18·字数 4591·发布 

    前提

    阅读本节的前提是已经掌握了如何在 OBS 中运行 Python 脚本,你可以查看如何配置 OBS 运行 Python 脚本一节来了解相关信息。

    将 Python 脚本函数导出至 OBS

    当一个 Python 脚本拥有特定名称和参数的函数时,OBS 将发现并使用这些函数来实现某些效果,比如,在 OBS 中显示一段说明脚本作用的文字。Python 脚本与 OBS 之间的这种联系,被官方称为脚本函数导出(Script Function Exports)。

    将脚本函数导出至 OBS 是可选行为

    将脚本函数导出至 OBS 是一种可选行为,你所编写的 Python 脚本可以没有任何函数导出,这不会影响 OBS 对脚本的执行。

    在 OBS 中展示 Python 脚本说明

    每一个成功载入 OBS 的 Python 脚本,都会在脚本窗口中拥有一段说明信息。通过在脚本中定义一个名为script_description的函数,你可以设置该脚本的相关说明文字,当然,script_description应返回一个字符串。

    OBS 支持在脚本说明中包含空白字符

    script_description函数返回的字符串中可以包含某些空白字符,比如,制表符(\t),他们可以正常显示在脚本窗口中。

    exports.py
    # 导入模块 obspython
    import obspython as obs
    
    def script_description(): return '这是一个简单但没有任何效果的脚本\n作者:\t哎呦喂\n版本:\t0.1\n联系:\txxx'

    在 OBS 中展示 Python 脚本属性

    函数script_properties是非常重要的,当你希望 Python 脚本与用户可以交互时,该函数需要返回一个包含脚本相关属性信息的属性集对象。OBS 将根据script_properties返回的属性集对象,在脚本窗口中创建一系列的控件,比如文本框,按钮,复选框等。通过这些控件,用户可以修改调整脚本的属性,从而改变脚本所实现的功能。

    OBS 中的脚本属性是什么?

    OBS 中的脚本属性(Script Properties)可以指表现在脚本窗口中的控件,也可以指用于创建这些控件的对象(脚本属性对象)。每一个脚本属性都对应了一个脚本设置(Script Settings)项,用于存储属性对应的值,不过,按钮控件除外。

    OBS 中的脚本设置是什么?

    脚本设置被存储在一个数据设置对象中,该对象采用类似于键值对的方式来读写一些数据。在 OBS 官方文档中,并没有类似于“脚本设置”这样的正式称呼,我们采用他只是为了方便讲述。脚本设置中的一个项未必会对应一个脚本属性,虽然你可以依据脚本设置来影响 Python 脚本所实现的功能,但他们对于用户是不可见的。

    针对不同的场景集合,OBS 会在合适的时机,将脚本设置以某种形式保存至本地,或反转此过程,这样,脚本设置便具有了永久化效果。通过脚本窗口移除某个 Python 脚本文件后,其对应的脚本设置也将从本地删除。

    交互控件

    想要详细了解属性集对象以及如何在 OBS 中使用控件,你可以查看如何使用控件与 OBS 用户交互?属性集对象介绍一节。

    在函数script_properties中,我们使用obs_properties_create创建了一个属性集对象,并通过obs_properties_add_text为属性集添加了一个对应数字显示框的属性对象。

    exports.py
    def script_properties():
    	# 创建一个属性集对象
    	props = obs.obs_properties_create()
    
    # 添加一个对应数字显示框的脚本属性对象,用于表示小时 obs.obs_properties_add_int(props, 'hours', '小时:', 2, 5, 1) return props

    在 OBS 加载或卸载 Python 脚本时执行任务

    如果希望在 Python 脚本被 OBS 加载或卸载时执行某些任务,比如从文件读取或写入数据,那么你可以在脚本中定义函数script_loadscript_unload

    script_load(settings)

    settings 参数

    settings参数为 Python 脚本对应的脚本设置对象。

    什么情况下 OBS 会加载或卸载 Python 脚本?

    当你在脚本窗口添加脚本,重新载入脚本,恢复默认时,或 OBS 启动后,脚本就会被加载。当你在脚本窗口移除脚本,重新载入脚本时,恢复默认之前,或 OBS 关闭时,脚本就会被卸载。

    在下面的代码中,我们通过函数script_loadscript_unload,记录并显示了上一次脚本停止的时间。事实上,这种做法在直接关闭 OBS 时是无效的,原因会在稍后给予说明。

    exports.py
    # 变量 data 表示脚本设置
    data = None
    
    def script_load(settings): global data data = settings
    # 读取脚本设置项 closed_time,他是脚本的停止时间 closed_time = obs.obs_data_get_string(data, 'closed_time') if closed_time: obs.script_log(obs.LOG_INFO, f'上次脚本停止的时间为 {closed_time}')
    def script_unload(): # 将当前时间写入脚本设置项 closed_time,作为脚本的停止时间 from datetime import datetime obs.obs_data_set_string(data, 'closed_time', datetime.now().ctime())
    [exports.py] 上次脚本停止的时间为 Mon Mar 4 07:12:37 2024

    obspython 模块的 obs_data_get_string,obs_data_set_string 函数

    obspython模块的obs_data_get_stringobs_data_set_string函数,用于对数据设置对象中字符串类型的数据项进行读写操作。

    与之类似的函数还有obs_data_get_intobs_data_set_int等。

    在 OBS 用户修改 Python 脚本属性后执行任务

    如果希望在用户修改脚本属性(通过脚本窗口)后执行某些任务,比如,根据修改后的脚本属性调整实现的功能,那么你可以在 Python 脚本中定义函数script_update,该函数的执行时间点在script_load函数与script_unload函数之间。

    需要指出的是,任何脚本属性的修改都会导致script_update函数的调用。如果仅监视某一个脚本属性的变化,那么可以使用obspython模块的obs_property_set_modified_callback函数。

    script_update(settings)

    settings 参数

    settings参数为 Python 脚本对应的脚本设置对象。

    什么情况下 OBS 会调用 script_update 函数?

    除了在用户修改脚本属性后,script_update函数还会在添加脚本,重新载入脚本,恢复默认或 OBS 启动时被调用。

    脚本窗口中控件显示的值与脚本设置项对应的值可能不相同

    在用户对脚本窗口中的控件进行有效编辑之前,控件所显示的值不会同步至对应的脚本设置项。这会产生困扰,因为用户从该控件看到的值,可能与你从脚本设置中读取到的值并不相同。一旦脚本属性对应的窗口控件被有效编辑,那么可从脚本设置安全的读取对应控件中的值。

    要避免以上不相同的情况,可以定义script_defaults函数,并在该函数中为控件对应的脚本设置项设置默认值。

    之前,在函数script_properties中,我们添加了最小值为2的数字显示框,但读取其对应的脚本设置项后,其结果可能显示为0,如果该数字显示框未被有效编辑的话。

    exports.py
    def script_update(settings):
    	# 读取脚本设置项 hours 并显示
    	hours = obs.obs_data_get_int(settings, 'hours')
    	obs.script_log(obs.LOG_INFO, f'当前小时为 {hours}')
    [exports.py] 当前小时为 0

    在 OBS 关闭时将数据写入 Python 脚本设置

    在 OBS 关闭时,Python 脚本中的script_save函数会被调用,此时可将一些重要的数据写入脚本设置,以便下次启动时读取他们。

    script_save(settings)

    settings 参数

    settings参数为 Python 脚本对应的脚本设置对象。

    在关闭 OBS 时通过 script_unload 函数写入的脚本设置项不会被存储至本地

    虽然 OBS 在关闭时,会调用script_unload函数,但对脚本设置项的写入操作可能会“无效”,因为他们不会被 OBS 存储至本地,这不同于点击脚本窗口重新载入脚本按钮

    保存重要数据的最佳方式是定义函数script_save而非script_unload,虽然之前的示例中演示了相反的做法。

    我们使用script_save函数代替script_unload函数,这将使得 OBS 的关闭时间被视为脚本停止时间,而其他用户操作(比如,点击重新载入脚本按钮)的时间,不再被视为脚本的停止时间。

    exports.py
    def script_save(settings):
    	# 将当前时间写入脚本设置项 closed_time,作为脚本的停止时间
    	from datetime import datetime
    	obs.obs_data_set_string(settings, 'closed_time', datetime.now().ctime())

    为 Python 脚本属性指定默认值

    在 OBS 官方提供的obspython模块中,你无法直接通过参数为脚本属性指定默认值,虽然一些添加脚本属性的函数可以达到近似的效果。要为脚本窗口中的控件设置默认值,应该在 Python 脚本中定义函数script_defaults,并在该函数中为脚本属性对应的脚本设置项指定默认值。

    script_defaults(settings)

    settings 参数

    settings参数为 Python 脚本对应的脚本设置对象。

    脚本设置项的默认值仅在其没有具体值时被使用

    需要指出,一旦脚本设置项拥有了具体的值,其默认值将不再被使用,这会发生在用户编辑了某个控件后,或你通过函数为脚本设置项指定了一个值后。

    当你点击脚本窗口默认按钮后,脚本设置项的默认值将重新发挥作用,因为脚本设置项的具体值已经被清除。

    在函数script_defaults中,我们将脚本设置项hours的默认值指定为3,这会使脚本窗口中的数字显示框默认显示3。如果之前编辑过该数字显示框,那么需要点击默认按钮,才能看到该效果。

    exports.py
    def script_defaults(settings):
    	# 将设置项 hours 的默认值设置为 3
    	obs.obs_data_set_default_int(settings, 'hours', 3)

    obspython 模块的 obs_data_set_default_int 函数

    obspython模块的obs_data_set_default_int函数,用于为数据设置对象中整数类型的数据项设置默认值。

    在 OBS 绘制每一帧时执行任务

    如果你希望在 OBS 绘制每一帧时执行某些任务,那么可以在 Python 脚本中定义函数script_tick

    script_tick(seconds)

    seconds 参数

    seconds参数是上一帧到本帧所经历的秒数。

    使用 script_tick 函数可能为 OBS 带来性能问题

    OBS 对script_tick函数的调用频率较高,因此,使用该函数完成复杂任务并不是一个好主意,如果你通过script_log函数不断向脚本日志窗口输出信息,那么 OBS 可能会无法响应用户,在长时间运行之后。

    obspython模块提供了另外一些关于计时器的函数,使用他们可以有效避免script_tick函数所产生的问题。

    exports.py
    def script_tick(seconds):
    	obs.script_log(obs.LOG_INFO, f'{seconds} OBS 就要无法响应了!!!')

    获取 Python 脚本所在的目录

    对于添加的 Python 脚本,OBS 会为其定义一个名为script_path的函数(不属于obspython模块),该函数可用于获取当前脚本所在的目录。

    script_path 函数与 Python 模块的 __file__ 特性之间的区别

    __file__特性表示了 Python 模块对应的文件路径,而script_path函数返回的是脚本文件所在文件夹的路径。

    我们调整之前的代码,在script_load中调用script_path函数,并显示返回的目录。

    exports.py
    def script_load(settings):
    	# …
    	obs.script_log(obs.LOG_INFO, script_path())
    # Windows 中的输出结果
    [exports.py] /scripts/

    为 OBS 添加或移除脚本计时器

    通过obspython模块的timer_addtimer_remove函数,你可以为 OBS 添加或移除脚本计时器(Script Timers)。脚本计时器将在指定时间间隔下,反复调用给出的回调函数或方法,这不同于script_tick函数。

    一旦使用了timer_add函数,被添加的脚本计时器就会开始工作。如果希望脚本计时器停止,可以通过timer_remove函数将其移除,或在回调函数和方法中调用obspython模块的remove_current_callback函数。

    timer_add(callback, milliseconds)
    timer_remove(callback)

    callback 参数

    callback参数是被脚本计时器回调的函数或方法,在timer_remove函数中,callback对应的脚本计时器将被移除。

    milliseconds 参数

    milliseconds参数是计时器触发的时间间隔,以毫秒为单位,接受整数类型的值。

    timer_remove 函数无法移除实例方法对应的脚本计时器

    如果将模块中的 Python 函数作为回调目标,那么timer_addtimer_remove可以正确运行,如果将 Python 类的实例方法作为回调目标,那么timer_remove可能失效,其对应的脚本计时器不会被移除。

    在下面的代码中,welcome是脚本计时器的回调函数,我们通过remove_current_callback使该函数只被调用一次。

    exports.py
    # 脚本计时器的回调函数 welcome
    def welcome():
    	obs.script_log(obs.LOG_INFO, '这是只被调用一次的回调函数')
    	# 移除 welcome 对应的脚本计时器
    	obs.remove_current_callback()
    
    # 添加脚本计时器,触发时间间隔为 3 秒 obs.timer_add(welcome, 3000)
    [exports.py] 这是只被调用一次的回调函数

    源码

    exports.py·codebeatme/obs-python-scripting·GitHub