チャットプラグイン
チャットで発言したり、視聴者に反応したり、メッセージをモデレートしたりするプラグインを作りたいなら、ここから始めてください。 コードサンプルは両方のサポートされている言語で示されています。 まず JavaScript または Python の SDK ページでツールチェーンを設定してください。
Owncast はチャット機能を3つのレイヤーで公開します:
- チャットイベントハンドラー - プラグインが発言、参加、退室、名前変更に反応できるようにします。
- チャットおよびユーザーAPI - プラグインがメッセージを投稿し、チャット状態を検査し、ユーザーをモデレートできるようにします。
- チャットフィルター - プラグインが視聴者が見る前にメッセージを書き換えたり破棄したりできるようにします。
作れるもの
- コマンドやキーワードに応答するチャットボット。
- 参加時に挨拶するウェルカムボット。
- 配信開始時にメッセージを投稿するリマインダーボット。
owncast.timerまたは tick ハンドラー によるカウントダウンやタイマーボット。- メッセージを非表示にしたり、クライアントの接続を切断したり、不正行為をするユーザーを無効化したりするモデレーション補助ツール。
- 配信される前にメッセージを書き換え、翻訳、または破棄するフィルター。
リプライボットは単に1つのハンドラーです:
- JavaScript
- Python
const { definePlugin, owncast } = require("@owncast/plugin-sdk");
module.exports = definePlugin({
onChatMessage(msg) {
const name = msg.user?.displayName ?? "someone";
owncast.chat.send(`${name} said: ${msg.body}`);
},
});
from owncast_plugin import plugin, owncast
@plugin.on_chat_message
def echo(msg):
name = msg.user.display_name if msg.user else "someone"
owncast.chat.send(f"{name} said: {msg.body}")
チャットへの反応
フィルター実行後、視聴者に配信される直前のメッセージを確認するには onChatMessage(Python では @plugin.on_chat_message)を定義します:
- JavaScript
- Python
module.exports = definePlugin({
onChatMessage(msg) {
owncast.chat.send(`echo: ${msg.body}`);
},
});
@plugin.on_chat_message
def echo(msg):
owncast.chat.send(f"echo: {msg.body}")
よく使うフィールドは msg.body(生のテキスト)、msg.user(送信者の識別情報、ユーザーごとの状態には user.id、モデレーターチェックには user.scopes を使用)、および msg.timestamp(決定論的なので、経過時間を比較したりテストでアサートする際は時計よりこちらを優先してください)。 表示名を基準に状態や権限を管理しないでください。
チャットプラグインが購読できるフルメッセージペイロードやその他すべてのイベント(ユーザーの参加/離脱、名前変更、モデレーションなど)については、イベントリファレンス を参照してください。
チャットメッセージの送信
owncast.chat.send
チャットメッセージを投稿します。 プラグインのボットIDとして送信されます。 プレーンテキストを受け取ります(マークアップではありません):チャット UI は表示時に HTML エスケープするため、<、&、および " のような文字は HTML としてではなくテキストとして表示されます。
- JavaScript
- Python
owncast.chat.send("hello chat");
owncast.chat.sendAction("waves"); // /me-style action message
owncast.chat.system("Stream starting in 5 minutes");
owncast.chat.send("hello chat")
owncast.chat.send_action("waves") # /me-style action message
owncast.chat.system("Stream starting in 5 minutes")
chat.send 権限が必要です。
owncast.chat.sendAction
アクション形式(/me)のメッセージを投稿します: JavaScript では sendAction、Python では send_action。 send と同様にプレーンテキストを受け取り、表示時にチャット UI が HTML エスケープします。
chat.send 権限が必要です。
owncast.chat.system
サーバー告知メッセージを投稿します。 ボットの識別情報は付与されません。 本文はインラインで HTML としてレンダリングされます。 「配信は5分後に開始します」のような短いサーバー通知に使用してください。 本文は信頼できない HTML 出力として扱ってください:視聴者が操作できる入力をエスケープせずに埋め込まないでください。
chat.send 権限が必要です。
チャットの識別情報
各プラグインにはちょうど1つのチャット識別があり、プラグインがインストールされると Owncast がそのボットをプロビジョニングします。 表示名はマニフェストの bot.displayName が設定されていればそれを使用し、そうでなければ name です。
send と sendAction の両方が、この識別を用いて Owncast の通常のチャットパイプライン(フィルター、レート制限、モデレーションを含む)を通して投稿されます。 プラグインは任意の名前で投稿したり、実在のユーザーを偽装したりすることはできません。
ボットユーザーはプラグインの slug をキーにしているため、name や bot.displayName のマニフェスト編集後も識別は維持されます。 複数のチャットペルソナが必要な場合は、複数のプラグインを提供してください。
チャット状態の読み取り
owncast.chat.history
最新のチャットメッセージを返します(オプションの上限はデフォルトで50)。 各エントリは { id, user?, clientId?, body, timestamp } の形をしています。
chat.history 権限が必要です。
owncast.chat.clients
Return the list of currently connected chat clients: { id, userId?, displayName?, connectedAt?, userAgent?, ipAddress?, messageCount? }. id は接続ごとのクライアントIDで、owncast.chat.kick で使用されます。
chat.history 権限が必要です。
owncast.server.emotes
ボットがエモートカタログを参照またはミラーリングしたい場合に、サーバーのカスタムチャットエモート({ name, url })を読み取ります。
server.read 権限が必要です。
owncast.users.list and owncast.users.get
チャットユーザーのリスト、または id による単一のユーザーレコードを読み取ります。
users.read 権限が必要です。
モデレーション API
これらは JavaScript では deleteMessage / kick / sendTo / replyTo、Python では delete_message / kick / send_to / reply_to です。
owncast.chat.deleteMessage
メッセージ ID によってチャットメッセージを視聴者から非表示にします。
chat.moderate 権限が必要です。
owncast.chat.kick
クライアント ID によってチャットクライアントの接続を切断します。
chat.moderate 権限が必要です。
owncast.chat.sendTo
クライアント ID を指定して、接続中の単一クライアントにプライベートメッセージを送信します。
chat.send 権限が必要です。
owncast.chat.replyTo
チャットメッセージを送信した相手に対してウィスパーで返信します。 chat-message / filter ハンドラーからの完全なメッセージオブジェクト、またはそれしかない場合は生のクライアント ID を渡すことができます。 送信者の接続が既知でなくなった場合は偽値を返し、その場合は公開メッセージへのクリーンなフォールバックが可能になります。
- JavaScript
- Python
module.exports = definePlugin({
onChatMessage(msg) {
if (!owncast.chat.replyTo(msg, "psst: got your message")) {
owncast.chat.send("got your message"); // sender already disconnected
}
},
});
@plugin.on_chat_message
def whisper(msg):
if not owncast.chat.reply_to(msg, "psst: got your message"):
owncast.chat.send("got your message") # sender already disconnected
chat.send 権限が必要です。
コマンド
チャットコマンドでは、エイリアス、クールダウン、モデレーター制御、および自動的な !help リストを含むコマンドテーブルを宣言します。 詳細はチャットコマンドを参照してください。
ユーザーのモデレーション
owncast.users.setEnabled
id によりチャットユーザーを有効化または無効化し、オプションで理由を付けられます。JavaScript では setEnabled、Python では set_enabled。
users.moderate 権限が必要です。
owncast.users.banIP
チャット参加を IP 単位で禁止します: JavaScript では banIP、Python では ban_ip。
users.moderate 権限が必要です。
チャットフィルター
フィルターはチャットメッセージが配信される前にメッセージを見て、書き換えたり破棄したりすることができます。 フィルターは最低優先度のものから実行されます。 drop はチェーンを終了し、そのメッセージは以降のフィルターや通知に到達しません。 modify は新しいペイロードを次のフィルターに渡します。
filterChatMessage
chat-message ハンドラーと同じ ChatMessage 形状を受け取り、filter ヘルパーで作られた3つの結果のいずれかを返します:
- pass: メッセージを変更せずに通します。
- modify: 新しいペイロードに置き換えます。
- drop: 破棄します(理由付き)。 ここでチェーンは停止します。
- JavaScript
- Python
const { definePlugin, filter } = require("@owncast/plugin-sdk");
module.exports = definePlugin({
filterChatMessage(msg) {
if (msg.body.includes("spam")) return filter.drop("spam keyword");
if (msg.body.includes("damn")) {
return filter.modify({ ...msg, body: msg.body.replace("damn", "****") });
}
return filter.pass();
},
});
from owncast_plugin import plugin, filter
@plugin.filter_chat_message
def clean(msg):
if "spam" in msg.body:
return filter.drop("spam keyword")
if "damn" in msg.body:
return filter.modify({**msg.raw, "body": msg.body.replace("damn", "****")})
return filter.pass_() # trailing underscore: pass is a keyword
chat.filter 権限が必要です。 プラグインがその権限を宣言せずに filter ハンドラーを定義すると、ホストは読み込みを拒否します。
フィルタ優先度(オプション)
数値が小さいほど早く実行されます。 デフォルトは 100 です。 Set it with filterPriority (JavaScript) on the plugin definition, or by calling plugin.set_filter_priority(priority) (Python).
他のフィルターが既に実行されたかどうかにプラグインの動作が依存する場合にこれを使用してください。 例えば、汚言フィルターは通常翻訳フィルターより先に実行されるべきです。
フィルターの安全性
- エラーは pass として扱われます。 例外を投げるフィルターはチャットをブロックしません。
- フィルターは50 msでタイムキャップされています。 遅いフィルターはキャンセルされ、pass として扱われます。
- 5 回連続の失敗(エラーまたはタイムアウト)の後、そのプラグインはセッションの残り期間自動的に無効化されます。 フィルターの成功呼び出しはカウンターをリセットします。
チャットプラグインに関係するホスト強制の制限
設計時に考慮すべきいくつかのホスト制限:
- フィルター実行時間: 50 ms(メッセージあたり)
- イベントハンドラ実行時間(chat-message、user-joined など): 500 ms(呼び出しあたり)
- ハードな呼び出し上限: 10 s
- フィルター出力サイズ: 1 MiB
- 保留中のタイマー: 同時に 64
- タイマー遅延範囲: 100 ms から 24 h
つまり、チャットボットやフィルターは軽量であるべきであり、ホットパスでの遅いネットワーク往復を避け、書き換えたペイロードを小さく保つべきです。
一般的に必要となる権限
chat.send: チャットメッセージおよびプライベート返信を投稿します。chat.history: 最近のチャットメッセージと接続中のクライアントを読み取ります。chat.moderate: メッセージを非表示にし、クライアントの接続を切断します。chat.filter: 配信前にメッセージを書き換えるか破棄します。users.read: ユーザーレコードを調査します。users.moderate: チャットユーザーを無効化するか、IP を禁止します。
完全なセキュリティモデルについては権限を参照してください。
チャットプラグインの例
プラグイン SDK にはこのページのパターンに密接に対応した小さなチャット向けの例が含まれています(各例は JavaScript と Python の両方のバージョンがあります):
echo-bot: chat-message ハンドラーとowncast.chat.sendを使用する、最小のリプライボット。chat-logger: 返信せずにすべてのチャットメッセージをログに記録します。stream-tracker: チャットコマンド、チャットユーザーのライフサイクルハンドラー、アクション告知を組み合わせます。profanity-filter: メッセージを破棄せずに書き換えます。slow-mode: レート制限にmsg.timestampを使用してメッセージを破棄します。engagement-bot: メッセージを削除してモデレートします。timer-bot: タイマーと tick ハンドラーを使用してチャットから駆動されるリマインダ/カウントダウンボット。
以下で参照してください: examples/js · examples/python。
他のプラグインドキュメントとの関係
- SDK の選択 と JavaScript / Python のページは、言語固有のセットアップ、CLI、および構文をカバーします。
- チャットコマンド はコマンドテーブル、自動の
!help、およびコマンドと独自のチャットハンドラーを混在させる方法を扱います。 - イベントハンドラー は すべての プラグインイベントの完全なハンドラーリファレンスです。
- Owncast APIs は すべての
owncast.*メソッドの完全な API リファレンスです。 - マニフェストリファレンス は権限、ボット識別フィールド、およびすべてのマニフェストプロパティをカバーします。
- Contributing UI は、チャットプラグインがフロントエンドの要素を提供する場合のビューア側の UI、オーバーレイ、ボタン、スクリプト、スタイルを扱います。
初めての場合は、まずクイックスタートを読んでからここに戻ってきてください。
Improve this page
See something missing or incorrect? Edit this page and improve the documentation for everyone.
