OBSスクリプトを書いてみる

# OBSスクリプトを書いてみる

## 背景

OBSのブラウザソースに指定したURLを自動で一括置換したくて調べていたところ、Luaで書いたスクリプトをOBSで読み込めることを知りました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84888/bae0b21e-2b2d-a8a6-8f75-251b1aae3e6a.png" width="320">

この機能を使って実際にOBSスクリプトを書いてみたので、書き方について紹介しようと思います。

ちなみに作ったもの

https://github.com/natmark/obs-ccfolia-url-replacer


## サンプルコード
OBSのツールバーからスクリプトを開くと下のような画面が開きます。

![スクリーンショット 2024-03-31 14.06.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84888/1b3dcff8-21f5-b124-d94d-9a280f4fd18b.png)

「+」を押してみると、あらかじめいくつかのスクリプトがサンプルとして用意されています。Lua以外にもPythonを使ってスクリプトを書くこともできるようです。

![スクリーンショット 2024-03-31 14.06.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84888/41ba6a38-7d4b-3d9e-f49b-8968e1bfe8fd.png)

## Hello World

それでは早速 Hello World をスクリプトログに表示するところからやってみます。

```lua: hello_world.lua
function script_load(settings)
    obslua.script_log(obslua.LOG_OUTPUT, "Hello World！")
end
```

`hello_world.lua` という名前をつけて、スクリプトをロードしてみると

![スクリーンショット 2024-03-31 14.14.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84888/5626075b-1617-b097-75b7-51f14d9bb96e.png)

スクリプトログが自動で表示され、「Hello World!」と出力されました :tada: 

## グローバル関数

https://docs.obsproject.com/scripting?highlight=script_load#script-function-exports

Hello Worldの章では `function script_load(settings)` の中にスクリプトログを表示するコードを書きましたが、他にもいくつかのグローバル関数が用意されており、これらを実装することで対応する処理を実行可能です。

- `script_description()`
  - 関数内で返却した文字列が [スクリプト] ウィンドウの説明の部分に表示されるようになります
- `script_load(settings)`
  - スクリプトのロード時に呼び出されます
- `script_unload()`
  - スクリプトのアンロード時に呼び出されます
- `script_save(settings)`
  - スクリプトの保存時に呼び出されます
- `script_defaults(settings)`
  - スクリプトの設定項目にデフォルト値を入れる時に利用します。[スクリプト] ウィンドウの「規定値」が押された際にも呼び出されます
- `script_update(settings)`
  - スクリプトの設定項目がユーザーによって変更されたときに呼び出されます
- `script_properties()`
  - 関数内で返却したプロパティが [スクリプト] ウィンドウに設定項目として表示されます
- `script_tick(seconds)`
  - 毎フレームごとに呼び出されます

## スクリプトに編集可能なプロパティを追加する

先ほど紹介した `script_properties` `script_defaults(settings)` を利用して設定してみます。

```lua: set_user_propeties.lua
-- 説明文
function script_description()
    return "プロパティを設定できるようにするサンプル"
end

-- ユーザープロパティ
function script_properties()
    local props = obslua.obs_properties_create()
    obslua.obs_properties_add_text(props, "text", "テキスト", obslua.OBS_TEXT_DEFAULT)
    obslua.obs_properties_add_text(props, "password", "パスワード", obslua.OBS_TEXT_PASSWORD)
    obslua.obs_properties_add_text(props, "multiline-text", "複数行テキスト", obslua.OBS_TEXT_MULTILINE)
    obslua.obs_properties_add_bool(props, "bool", "真偽値")
    obslua.obs_properties_add_int(props, "int", "整数 (0~100)", 0, 100, 1)
    obslua.obs_properties_add_float(props, "float", "小数(0~0.1)", 0, 1, 0.1)
    return props
end

-- デフォルト値
function script_defaults(settings)
    obslua.obs_data_set_default_string(settings, "text", "プレースホルダ")
	obslua.obs_data_set_default_int(settings, "int", 10)
	obslua.obs_data_set_default_bool(settings, "bool", true)
end
```

![スクリーンショット 2024-03-31 17.50.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84888/58affc5d-cd04-83ab-c7ee-a9207600f90d.png)

このようにスクリプト右側にプロパティが表示されるようになりました。

他にもリストやカラーピッカー、ボタンを配置したりといったことも可能です。

https://docs.obsproject.com/reference-properties#property-object-functions

設定されているプロパティの値に関しては `obslua.obs_data_get_string(settings, "text")` のように取り出すことが可能です。

## シーンにアクセスする
OBS Studio Frontend APIを利用してシーン名の取得をしてみます

```lua: get_scene_name.lua
-- 説明文
function script_description()
    return "シーン名を取得するサンプル"
end

function button_clicked(props, p)
    local scenes = obslua.obs_frontend_get_scenes()

    -- シーン一覧を取得してシーン名を表示
    for _, scene_source in ipairs(scenes) do
        local scene_name = obslua.obs_source_get_name(scene_source)
        obslua.script_log(obslua.LOG_OUTPUT, scene_name)
    end

    obslua.source_list_release(scenes)

	return false -- プロパティウィジェットを更新する必要がないのでfalse
end

-- スクリプトに対する編集可能なプロパティ
function script_properties()
    local props = obslua.obs_properties_create()
    obslua.obs_properties_add_button(props, "button", "シーン名を取得する", button_clicked)
    return props
end
```

シーン一覧にボタンを表示して、ボタンが押されるとスクリプトログにスクリーン名を表示するようにしてみました。
![スクリーンショット 2024-03-31 18.10.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84888/0d16b782-b051-76b2-836c-f953fe9efbd9.png)

![スクリーンショット 2024-03-31 18.10.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84888/2994b31b-ecbf-5199-58e7-f06ebb8f8d87.png)

## イベントのハンドリング
`obs_frontend_add_event_callback` を用いて、イベントのコールバックを受け取ることができます。

```lua: event_handling.lua
function on_event(event)
	if event == obs.OBS_FRONTEND_EVENT_SCENE_CHANGED then
      -- シーン変更された際に行う処理
	end
end

function script_load(settings)
	obslua.obs_frontend_add_event_callback(on_event)
end
```

イベントの一覧はこちらが参考にできます 

https://docs.obsproject.com/reference-frontend-api#c.obs_frontend_event 

## ソースを追加する
スクリプト機能によってカスタマイズしたソースを追加することも可能です。

https://docs.obsproject.com/scripting?highlight=obs_register_source#script-sources-lua-only

サンプルコードの `clock-source.lua` がカスタマイズしたソースを用意しているのでこちらが参考になると思います。