-
-
Notifications
You must be signed in to change notification settings - Fork 148
スライドの自動録画機能およびスライド中動画の自動再生機能 #329
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
The head ref may contain hidden characters: "feature/\u52D5\u753B\u306E\u81EA\u52D5\u518D\u751F"
Conversation
This reverts commit 4ddcab0.
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
Walkthrough今回の変更では、環境変数ファイルのVRMおよびLive2Dモデルのパスの更新と、新たにOBS Studio連携用の環境変数が追加されました。また、OBSおよびAivisspeech Engineサービスを定義するDocker Composeオーバーライドファイル、OBS連携の使い方を記述したドキュメント、OBS WebSocketライブラリの依存関係追加、ならびに各種UIコンポーネント(メニュー、スライド、スライド制御)においてautoplay状態やOBS接続、録画状態を管理するためのロジックが導入・更新されています。さらに、スライドストアとアプリケーションの初期化処理にURLパラメータの反映処理が追加されました。 Changes
Sequence Diagram(s)sequenceDiagram
participant ブラウザ as Browser
participant スライド as Slides Component
participant OBS as OBS WebSocket
participant 制御 as Slide Controls
ブラウザ->>スライド: スライド読み込み (OBS設定含む)
スライド->>OBS: connectToOBS() 呼び出し
OBS-->>スライド: 接続確立
スライド->>OBS: startRecording()/stopRecording() 実行
OBS-->>スライド: 録画状態の更新通知
スライド->>制御: 状態更新の反映
sequenceDiagram
participant ブラウザ as Browser
participant アプリ as _app Component
participant スライドストア as SlideStore
participant メニューストア as MenuStore
ブラウザ->>アプリ: URLパラメータ (slide, autoplay) を送信
アプリ->>スライドストア: スライド状態リセットおよび更新
アプリ->>メニューストア: メニュー表示設定の更新
Possibly related PRs
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
npm warn config production Use ✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (8)
.env.example (1)
359-361: OBS Studio設定の追加は適切ですが、セキュリティについて注意が必要ですOBS Studioとの連携に必要な環境変数が適切に追加されています。
ws://obs:4455というURLはDockerコンテナ間通信を想定しており、PR目的に合致しています。ただし、デフォルトパスワード
"obswebsocket"は本番環境では変更すべきです。セキュリティ上のリスクを減らすため、本番環境ではより強固なパスワードを設定することをユーザーに推奨するコメントを追加することを検討してください。# OBS Studio Settings NEXT_PUBLIC_OBS_WEBSOCKET_URL=ws://obs:4455 NEXT_PUBLIC_OBS_WEBSOCKET_PASSWORD="obswebsocket" +# 注意: 本番環境では、より強固なパスワードに変更してくださいdocker-compose.obs-url-recorder.override.yml (1)
1-25: Docker Composeファイルの確認と改善提案このDocker Composeオーバーライドファイルは、OBSとAivisSpeech Engineのサービスを適切に定義しています。いくつかの改善点があります:
ボリュームマウント
~/aituberkit-outputはチルダを使用してホームディレクトリを参照していますが、このディレクトリが存在しない場合エラーになります。PR説明にあるように、このディレクトリを事前に作成する必要があります。イメージタグが
masterやnvidia-latestのように固定バージョンではないため、将来的に互換性の問題が発生する可能性があります。OBS_BROWSER_URLが
http://app:3000/?slide=demo&autoplay=trueとハードコードされていますが、環境変数で設定できるようにすると柔軟性が向上します。services: obs: image: ghcr.io/stealthinu/obs-url-recorder:master environment: - OBS_BROWSER_URL: http://app:3000/?slide=demo&autoplay=true + OBS_BROWSER_URL: ${OBS_BROWSER_URL:-http://app:3000/?slide=demo&autoplay=true} ports: - "5900:5900" # VNC port volumes: - ~/aituberkit-output:/home/obsuser/outputまた、ドキュメントに「~/aituberkit-output ディレクトリを事前に作成する必要がある」ことを明記してください。
src/components/slideControls.tsx (1)
50-65: OBS接続と録画状態表示の実装OBS接続と録画状態を視覚的に表示する実装が追加されています。色分けされたドットとテキストで状態が直感的に理解できるよう工夫されています。ただし、いくつかの改善点があります:
- テキストが日本語でハードコードされていますが、国際化対応が必要かもしれません。
- 録画中の状態表示に
animate-pulseが使用されており、視覚的なフィードバックとして効果的です。テキストの国際化対応を追加することをお勧めします:
- <span className="text-xs font-medium">OBS {obsConnected ? '接続中' : '未接続'}</span> + <span className="text-xs font-medium">OBS {obsConnected ? t('connected') : t('disconnected')}</span> - {isRecording ? '🔴 録画中' : '⚪ 録画停止'} + {isRecording ? `🔴 ${t('recording')}` : `⚪ ${t('recordingStopped')}`}コンポーネントの先頭に次を追加:
const { t } = useTranslation()src/components/menu.tsx (1)
201-308: オートプレイモード時のUIコントロール非表示の実装オートプレイモード時にコントロールパネルを非表示にする条件分岐が追加されています。これは自動録画機能において視聴者体験を向上させるための適切な実装です。ただし、コードの可読性に関していくつかの改善点があります:
- 大きなJSXブロック全体が
!isAutoplayで条件分岐されているため、コードの入れ子が深くなっています。- 設定ボタンのアイコン名が
youtubePlayingの条件から静的な値"24/Settings"に変更されています。UIコンポーネントを小さな関数コンポーネントに分割することでコードの読みやすさを向上できます:
// コントロールパネルを別コンポーネントとして切り出す例 const ControlPanel = () => { // 必要な状態をここで取得 const showControlPanel = settingsStore((s) => s.showControlPanel) // ...その他の状態 if (!showControlPanel) return null; return ( <> <div className="md:order-1 order-2"> <IconButton iconName="24/Settings" isProcessing={false} onClick={() => setShowSettings(true)} ></IconButton> </div> {/* ...残りのコントロールパネル要素 */} </> ); }; // メイン部分での使用 return ( <> {/* ...既存のコード */} {!isAutoplay && ( <div className="absolute z-15 m-6"> <div className="grid md:grid-flow-col gap-[8px] mb-10" style={{ width: 'max-content' }} > <ControlPanel /> </div> </div> )} {/* ...残りのコード */} </> );src/pages/_app.tsx (1)
45-89: URLパラメータからのスライド設定取得の実装URLパラメータからスライドの選択と自動再生モードを設定する機能が実装されています。全体的に機能は適切に実装されていますが、いくつかの改善点があります:
- 本番環境に残されている
console.logステートメントがあります。- スライドパラメータの値の検証が不足しています。
- コメントは日本語でハードコードされています。
以下の改善を提案します:
// URLパラメータからスライド関連の設定を取得 useEffect(() => { // クエリパラメータが準備できたら処理 if (!router.isReady) return const { slide, autoplay } = router.query // スライド名が指定された場合 if (typeof slide === 'string' && slide) { - console.log(`スライドを自動選択: ${slide}`) + // スライド名のバリデーション + const validSlideNames = ['demo', 'other-valid-slides']; // 有効なスライド名のリスト + if (!validSlideNames.includes(slide)) { + // 無効なスライド名の場合はデフォルト値を使用または処理をスキップ + return; + } // スライドモードを有効化 settingsStore.setState({ slideMode: true }) // 強制的に初期状態にリセット slideStore.setState({ isPlaying: false, currentSlide: 0, isAutoplay: false }); // スライドを選択(この時点ではまだロード中) slideStore.setState({ selectedSlideDocs: slide }) // スライドを表示 menuStore.setState({ slideVisible: true }) // 自動再生が指定された場合 if (autoplay === 'true') { - console.log('スライドの自動再生モードを設定します') // イントロダクションを非表示にする homeStore.setState({ showIntroduction: false }) // 自動再生モードを設定 slideStore.setState({ isAutoplay: true }) // 再生自体はslides.tsxのマークダウン変換完了後のタイミングで行う // そのため、ここではisPlayingの設定は行わない } else { // 自動再生ではない場合、明示的にフラグをオフに slideStore.setState({ isAutoplay: false }) } } }, [router.isReady, router.query])さらに、エラーハンドリングのメカニズムを追加することを検討してください。例えば、無効なスライド名が指定された場合にユーザーに通知するなどの方法が考えられます。
src/components/slides.tsx (2)
47-55: obs, obsConnected, isRecordingの型定義を導入することを検討してください
any型のままだと補完や可読性が失われる可能性があります。obs-websocket-jsが提供している型定義があれば活用すると良いでしょう。
367-389: 自動再生開始を1秒遅らせるマジックナンバーは定義化するとより可読性が高くなります
実装としては機能的に問題ありません。docs/obs_recorder.md (1)
1-21: OBS連携機能のドキュメントが追加されました!OBS Studioとの連携機能についての明確なドキュメントが作成されており、ユーザーが機能を利用するために必要な情報が適切に提供されています。
コードブロックに言語指定を追加することで、シンタックスハイライトが有効になり、視認性が向上します:
-``` +```env # .envファイルに追加 NEXT_PUBLIC_OBS_WEBSOCKET_URL=ws://localhost:4455 NEXT_PUBLIC_OBS_WEBSOCKET_PASSWORD=yourpassword-
+url
http://localhost:3000?slide=スライド名&autoplay=true🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
5-5: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
18-18: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (9)
.env.example(2 hunks)docker-compose.obs-url-recorder.override.yml(1 hunks)docs/obs_recorder.md(1 hunks)package.json(1 hunks)src/components/menu.tsx(2 hunks)src/components/slideControls.tsx(3 hunks)src/components/slides.tsx(4 hunks)src/features/stores/slide.ts(2 hunks)src/pages/_app.tsx(2 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
docs/obs_recorder.md
5-5: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
18-18: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
🔇 Additional comments (28)
.env.example (1)
66-66: モデルパスの更新は適切ですデフォルトのVRMモデルパスとLive2Dモデルパスが具体的なモデル(
nikechan_v2.vrmとnike01.model3.json)に更新されています。これにより、より実用的なデフォルト設定になっています。Also applies to: 70-70
src/components/slideControls.tsx (1)
11-12: OBS関連のプロパティ追加は適切です
SlideControlsPropsインターフェースにOBS接続と録画状態を表す2つのオプショナルプロパティが追加されており、機能拡張の設計として適切です。src/components/menu.tsx (2)
53-53: スライドストアからのオートプレイ状態の取得スライドストアから
isAutoplay状態を取得する実装は適切です。これによりURLパラメータを通じて自動再生モードを制御できるようになります。
312-333: オートプレイモード時の追加UIコンポーネント非表示の実装チャットログ、設定、アシスタントテキスト、ウェブカムなどの追加UIコンポーネントもオートプレイモード時に非表示にする実装が追加されています。これによりクリーンな視聴体験が実現されます。
src/pages/_app.tsx (2)
5-11: 新しいインポートの追加Next.jsのルーターとスライド関連のストアのインポートが追加されています。これらはURLパラメータからスライド設定を取得するために必要なインポートであり、適切に実装されています。
17-18: ルーターインスタンスの取得
useRouterフックを使用してNext.jsのルーターインスタンスを取得する実装は適切です。これによりURLパラメータにアクセスできるようになります。src/components/slides.tsx (20)
7-10: OBSモジュールの読み込みパターンが妥当です
CommonJSとESMの兼ね合いによる問題がなければ問題ない実装に見えます。
11-15: OBS WebSocketのパスワード設定が空文字列になるリスクに注意
環境変数の未設定時にパスワードが空文字列となり得るため、本番運用ではパスワードを必須化することを検討してください。
32-45: 自動再生やスライド準備・動画再生を管理するstateとrefが明確で分かりやすいです
それぞれの役割がきちんと分割されており、状態管理の可読性が高いと思います。
57-72: 録画状態をポーリングして確認するロジックが適切に例外処理されており良いです
特に無駄な再レンダリングを抑える工夫がされている点も好印象です。
101-120: 録画開始処理のフローが明確かつガードもあり良好です
録画中チェックを行っているため、ユーザー操作の重複にもしっかり対応できます。
122-141: 録画停止処理も同様にガードされており妥当です
例外時のログ出力もしっかり行われていて安心です。
143-153: 5秒ごとに録画状態をチェックする実装
シンプルで分かりやすいですが、大規模運用時のパフォーマンス影響を一度検証するとより安心です。
155-178: マウント時に接続してアンマウント時に録画停止・切断するフローは適切です
ライフサイクル管理が分かりやすく、大きな問題は見当たりません。
180-190: 全動画の再生終了をチェックする実装が簡潔で読みやすいです
every()を使った条件がとても分かりやすいと思います。
192-215: スクリプト読み込み失敗時のハンドリングが丁寧です
try/catchできちんとログが出るので原因追跡が容易になります。
217-277: 動画要素のイベントリスナーを設定して自動再生を実装する流れは直感的です
同じ動画要素に対して何度もイベントが登録されないよう、DOM更新のたびに再確認することをおすすめします。
281-348: Markdown→HTML変換とmarpit要素の設定が丁寧に実装されています
エラー時の例外処理やスタイル適用も適切に管理されており問題ありません。
391-412: 最後のスライド完了時に自動再生と録画を止めるロジックは適切です
状態遷移が明確で、意図した動きが伝わります。
414-430: 選択スライド変更時やコンポーネント破棄時に自動再生フラグをリセットする実装
自動再生が意図せず続かないよう配慮されている点が良いです。
432-444: nextSlideで音声読み上げを行う流れはUI/UX的に自然です
スライド移動のたびに読み上げる機能が簡潔に書かれていて良いと思います。
446-452: prevSlideでは最小値を0とするバウンダリチェックが実装されており安心です
意図しないスライド番号への移動を防げます。
453-466: toggleIsPlayingの再生/停止切り替えロジックが読みやすいです
再生開始時だけ音声読み上げが走るので混乱がなく実装されています。
467-476: isPlaying変化時に録画開始/停止を連動させる設計
ユーザー操作と録画状態が直結しており、運用イメージがつきやすいです。
478-496: 音声と動画が終了したら500ms後に次のスライドに自動移行する処理
短いディレイでユーザー体験を損なわない配慮が感じられます。
535-556: SlideControlsにobsConnectedやisRecordingが追加されUI上で録画状況が分かりやすいです
ユーザーにリアルタイムで状態を伝えられるのは利便性が高いと思います。package.json (1)
51-51: OBS WebSocketの依存関係が適切に追加されています!OBS Studioとの連携に必要な
obs-websocket-jsパッケージが追加されており、PRの目的に合致しています。バージョン指定も適切です。src/features/stores/slide.ts (1)
8-8: 自動再生機能のためのステート追加が適切です!スライドの自動再生機能を制御するための
isAutoplayプロパティが適切に追加されています。デフォルト値もfalseに設定されており、既存の動作を維持しつつ、新機能を有効にする準備ができています。Also applies to: 17-17
| // OBSに接続する関数 | ||
| const connectToOBS = useCallback(async () => { | ||
| if (!obs) { | ||
| console.error('OBSWebSocketインスタンスが作成されていません'); | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| console.log('OBS Studioに接続を試みています...'); | ||
| await obs.connect(obsConfig.url, obsConfig.password); | ||
| console.log('OBS Studio に接続しました'); | ||
| setObsConnected(true); | ||
|
|
||
| // 接続後すぐに録画状態を確認 | ||
| await checkRecordingStatus(); | ||
|
|
||
| // OBSからのイベント通知を設定 | ||
| obs.on('RecordStateChanged', (event: { outputActive: boolean }) => { | ||
| console.log(`OBSの録画状態が変更されました: ${event.outputActive ? '録画中' : '録画停止'}`); | ||
| setIsRecording(event.outputActive); | ||
| }); | ||
| } catch (error) { | ||
| console.error('OBS Studioへの接続に失敗しました:', error); | ||
| setObsConnected(false); | ||
| } | ||
| }, [obs, checkRecordingStatus]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
connectToOBS内のイベントリスナー重複登録に注意
再接続時に古いイベントリスナーを解除しないと多重登録される可能性があります。オフにする処理を追加してください。
// 例: 新たにイベントを登録する前に既存のリスナーを解除する
+ obs.off('RecordStateChanged');
obs.on('RecordStateChanged', (event: { outputActive: boolean }) => {
// ...
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // OBSに接続する関数 | |
| const connectToOBS = useCallback(async () => { | |
| if (!obs) { | |
| console.error('OBSWebSocketインスタンスが作成されていません'); | |
| return; | |
| } | |
| try { | |
| console.log('OBS Studioに接続を試みています...'); | |
| await obs.connect(obsConfig.url, obsConfig.password); | |
| console.log('OBS Studio に接続しました'); | |
| setObsConnected(true); | |
| // 接続後すぐに録画状態を確認 | |
| await checkRecordingStatus(); | |
| // OBSからのイベント通知を設定 | |
| obs.on('RecordStateChanged', (event: { outputActive: boolean }) => { | |
| console.log(`OBSの録画状態が変更されました: ${event.outputActive ? '録画中' : '録画停止'}`); | |
| setIsRecording(event.outputActive); | |
| }); | |
| } catch (error) { | |
| console.error('OBS Studioへの接続に失敗しました:', error); | |
| setObsConnected(false); | |
| } | |
| }, [obs, checkRecordingStatus]); | |
| // OBSに接続する関数 | |
| const connectToOBS = useCallback(async () => { | |
| if (!obs) { | |
| console.error('OBSWebSocketインスタンスが作成されていません'); | |
| return; | |
| } | |
| try { | |
| console.log('OBS Studioに接続を試みています...'); | |
| await obs.connect(obsConfig.url, obsConfig.password); | |
| console.log('OBS Studio に接続しました'); | |
| setObsConnected(true); | |
| // 接続後すぐに録画状態を確認 | |
| await checkRecordingStatus(); | |
| // OBSからのイベント通知を設定 | |
| obs.off('RecordStateChanged'); | |
| obs.on('RecordStateChanged', (event: { outputActive: boolean }) => { | |
| console.log(`OBSの録画状態が変更されました: ${event.outputActive ? '録画中' : '録画停止'}`); | |
| setIsRecording(event.outputActive); | |
| }); | |
| } catch (error) { | |
| console.error('OBS Studioへの接続に失敗しました:', error); | |
| setObsConnected(false); | |
| } | |
| }, [obs, checkRecordingStatus]); |
|
@stealthinu |
|
了解しました。 |
OBS Studioと連携してスライドの自動録画機能を追加しました。
URL指定によりスライドの指定と自動再生を指示できます。
スライドの自動再生時には操作ボタンやメニューを非表示にします。
スライドに動画が埋め込まれている場合、動画の自動再生を行い、再生が終わってから次のスライドを表示します。
OBS Studioの設定が必要になるため、AITuberKitでの使用を想定したdockerを準備しています。
https://github.com/stealthinu/obs-url-recorder
このdockerを一緒に起動するための docker-compose.obs-url-recorder.override.yml も作成しています。
$ docker compose -f docker-compose.yml -f docker-compose.obs-url-recorder.override.yml up -d
で起動することを想定しています。
この場合、OBS Studio, AivisSpeech-engine を一緒に起動します。
.env.templateには、このobs-url-recorderを使うためのデフォルト設定を追記してあります。
動画の保存先は ~/aituberkit-output/ になっており、パーミッションの関係で先にこのフォルダを作っておく必要があります。
Summary by CodeRabbit
新機能
ドキュメント
その他