前置き
この記事はQiita Advent Calendar 2025 / ひとりアドベントカレンダー 分野における ふぐおの配信関係多めひとり Advent Calendar 2025 の20日目記事となります。
はじめに
こんにちは! プログラミング配信をしているふぐおです。
現在、配信ツールを作り直す作業をやっているのですが、どのようなところにこだわって配信ツールを作り直しているのかを書いてみました。
作り直す前
機能
私の配信ツールは当初Windowsで動く、CLIツールとして始まりました。
当初の配信ツールに求めていた機能は以下の通りです。
- VOICEPEAK邪神ちゃんでコメントを読み上げる
- コメントで動画を流す
- 教育をする
実装
VOICEPEAK邪神ちゃんに音声合成指示をして読み上げさせるといった処理に関しては、Pythonで実装していました。
コメントの取得や、動画再生などのコマンド操作の実装に関してはNode.jsで書いており、これら2つは別プロセスで動いていました。
これは既存のシステムに新たにコマンド機能を加えたからです。
一番最初のツールは、元々コメント取得と読み上げだけでした。これらはプロセス間通信で処理内容を渡していました。
node comment.js | python voicepeak.py
ここに、コマンド機能をあとから加えました。
node comment.js | node command.js | python voicepeak.py
運用
この方式で2年ほど運用していたのですが、様々な面で限界が出てきました。
- VOICEPEAKの音声読み上げを他のプログラムからも利用したくなった
- 音声の再生部分を別のプログラムでやりたくなった
- 動画の他に字幕を出したり、配信上にポップアップを出現させたりと、配信上に表示するエフェクトを増やしたくなった
- 「今配信上で流れている曲を知りたい」といったコマンド面もさらに拡張したくなった
- コメント取得部分をAI Tuberなど他のプログラムと連携したくなってきた
これらの需要は一気に出てきたものではなく、1年半以上をかけて少しずつ出てきたものです。
なので、これらの要望が出た時点で機能を増やしていきました。
コメント連携用のサーバーを増やしたり、音声再生ソフト(音声合成ではない)と連携できるようにしたりといった形です。
課題
これらをすることによって、課題が見えてきました。
- 様々なツールと連携するようになったことで、不具合が起きたときに「どこのツールで不具合が起きたのか」が分かりにくい
- 配信ツールのセットアップに必要な作業が増えた(VOICEPEAKの設定、サーバー再起動時にVOICEPEAKを自動起動させる設定など)
- 配信起動時に立ち上げるツールの数が増え、わずらわしい(WindowsとLinuxのデュアルブート環境でブートを切り替える作業が多くなったのもある)
また、いくつか拡張したい機能もありました。
- プログラミング配信は何をやっているか途中からだと分かりにくいので、AIで要約をして今日の配信内容を伝えるツール
- コメントで送られてきたURLが開いていいやつなのかをチェックできるツール
- ニコ生はアナリティクスが無いので、それを提供するツール
このように外部のプログラムと連携したり、既存のシステムに色々組み込むといった必要が出てきました。
新ツール
設計思想
前ツールの課題や拡張したいことを踏まえ、設計思想を以下のように変更することにしました。
- 常駐型のサーバープロセスと、音声再生などのコントロールをするクライアントアプリという2つのシステムを導入する
- イベント駆動の設計にする
- 環境構築はDockerに任せる
- エラーをコンソールに出すだけでなく、分かりやすく示す
- テストコードでひとつひとつのロジックの品質を担保する
以下がこの設計思想を取り入れた理由です。
環境の再現性と管理の容易さ
VOICEPEAKのセットアップ、Node.jsのセットアップといった作業をDocker化することによって、環境の再現性と管理を簡単にしたいと思ったからです。
配信開始時に毎回立ち上げるツールをなくす
以前のツールはコメント取得コードに機能を付け足した形でした。この形だと、配信が始まってコメント取得が可能になってからでないと実行できず、配信が終わるとコメント取得ができなくなってツール自体が止まってしまう仕組みでした。
新しいツールでは、常駐型のサーバーが配信の開始を検知したら内部でコメント取得を開始し、配信が終わったらコメント取得を停止するといった動作を自動で行うことにしました。配信PCで起動するクライアント側のアプリは、サーバー側とソケット通信で接続され、サーバー側の指示に従うことだけに集中します。こうすることで、配信を始めるたびにツールを立ち上げ直す必要がなくなります。
条件分岐を減らす
昔のコードは「コメント取得→音声合成」という単純な処理の流れだったので、その通りにコードを組んでいました。
ところがコマンド機能が増えるにつれて、「このコメントは読まれない」「このコメントは一部分のみ読まれる」といった具合に、条件分岐が激しくなってきました。さらに、コマンドの処理で外部APIの内容を取ってきたりと、「コメント取得→音声合成」という一直線の流れでは語れない副作用部分が増えてしまい、設計の限界を感じていました。
そこで、個々のコメントに対して「どのようなイベントを発行するか」に関心を持つことだけにしました。
こうすることで、コマンドが実際に行う仕事がコメント処理のコードと分離されるようになり、コメント処理側は「どのコマンドを呼び出すか」ということだけに集中できるようになりました。
エラーを音声で知らせる
イベント駆動にしたことにより、エラーを知らせやすくなりました。
配信ツールでのエラーをユーザーに知らせる方法として、一番分かりやすいのがクライアント側にある音声再生機能を使って、音声でエラーを伝える方法です。
ところが、音声再生機能自体がエラーになると、音声でエラーを伝えることができなくなります。
よって、配信UI上でエラーを出すといった様々な方法でエラーを伝えることになります。
この際、イベント駆動であれば、エラーイベントを発行して「音声再生機能が使える場合は音声で伝え、使えない場合はUI上にエラーを表示する」といった柔軟な対応が可能になります。
各コンポーネントごとに品質を担保する
イベント駆動は各コンポーネントごとにイベントを受け取ってそれぞれ独自の挙動をするので、バグが混入した際に広い範囲で影響が出てしまい、どのような影響が出るかが読めません。よって、テストコードによって、それぞれのコンポーネントごとに品質を担保しています。
書いている中で悩んでいること
テストコードが書けない部分がある
テストコードを書けるようになってきて、テストコードを「動くドキュメント」っぽく書けるようになってきたのが、今回成長できたポイントかなと思っています。
ただ、「音声合成が正しくできているか」などは、どのようにテストコードを書けば良いのだろうと悩んでいます。
死活監視とエラーハンドリングが上手くできない
これまでここらへんにこだわってこなかったので、コードが汚くなりがちで困っています。
「このエラーのときはこうする」みたいな処理を書いているのですが、ネストが深くなりがちで、どうにかしたいなと思っています。
今後やりたいこと
「コメントとの接続を開始します」みたいなアナウンスが流れて配信が少し賑やかになりそうなのですが、まだ視聴者目線での新機能がないので、実装したいなと思っています。年末年始にできるかなと考えています。