URLhttps://learnscript.net/zh-hant/obs-python-scripting/scripts/
    複製連結移至說明  範例

    如何編寫可在 OBS 中執行的 Python 腳本

    閱讀 15:31·字數 4655·發佈 
    Youtube 頻道
    訂閱 480

    先決條件

    閱讀本節的先決條件是已經掌握了如何在 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