はじめに
10月から人生初のフルリモート生活を送っているのですが、オンラインミーティング中に家族(特に子供)が乱入してくることがあります。
また、「何時から会議なの?」とよく聞かれることもあるので、オンラインミーティングの開始/終了を検知し、それを家族に通知したいと考えました。
少し調べてみてた感じ、Google Meet公式にはオンラインミーティングの開始/終了を通知してくれる機能はないみたいなので、今回はChromeの拡張機能を自作し、対応してみたいと思います。
作ったもの
ソースコードは以下で公開してみました。
オンラインミーティングの開始/終了を検知し、任意のWebhookに通知する仕組みです。
以下、少し内容紹介をします。
処理内容
会議の状態
このツールはmeet.google.comを開いている場合のみ動作し、以下の状態の状態遷移を監視します。
| 状態 | 意味 |
|---|---|
| IDLE | 初期状態 |
| PRE_MEETING | 会議開始前 |
| IN_MEETING | 会議中 |
const STATES = {
IDLE: 'IDLE',
PRE_MEETING: 'PRE_MEETING',
IN_MEETING: 'IN_MEETING'
};
DOM要素で状態判定
状態判定は、各状態でのみ存在する、今すぐ参加や通話から退出などのDOM要素の有無で判定します。
const SELECTORS = {
LEAVE_BUTTON: 'button[aria-label*="Leave call"], button[aria-label*="通話から退出"]',
JOIN_BUTTON_TEXT: ['Join now', '今すぐ参加']
};
const detectState = () => {
const leaveButton = document.querySelector(SELECTORS.LEAVE_BUTTON);
if (leaveButton) return STATES.IN_MEETING;
const hasJoinButton = Array.from(document.querySelectorAll('button span'))
.some(span => SELECTORS.JOIN_BUTTON_TEXT.some(text => span.textContent.includes(text)));
return hasJoinButton ? STATES.PRE_MEETING : STATES.IDLE;
};
最初は動画や音声の有無で判定してたのですが、不安定な部分があったので今の方法に落ち着きました。
状態監視
状態監視はMutationObserverでDOM要素の変更を監視することで対応してみました。
const observer = new MutationObserver(throttledCheckState);
observer.observe(document.body, { childList: true, subtree: true });
また、変更検知後の判定は最大で100msの間隔をあけるようにし、負荷軽減をしています。
let throttleTimer = null;
const throttledCheckState = () => {
if (throttleTimer) return;
throttleTimer = setTimeout(() => {
checkState();
throttleTimer = null;
}, 100);
};
状態変更時にWebhook起動
以下のパターンの状態遷移を検知した場合のみ、Webhookを起動しています。
| 状態(旧) | 状態(新) | Webhook |
|---|---|---|
| 初期状態 | 会議中 | 会議開始通知 |
| 会議開始前 | 会議中 | 会議開始通知 |
| 会議中 | 初期状態 | 会議終了通知 |
| 会議中 | 会議開始前 | 会議終了通知 |
// 状態変化ハンドラ
const handleStateChange = (oldState, newState) => {
if (newState === STATES.IN_MEETING && oldState !== STATES.IN_MEETING) {
console.log('✅ 会議開始を検知');
sendWebhook('meeting_started');
} else if (oldState === STATES.IN_MEETING && newState !== STATES.IN_MEETING) {
console.log('❌ 会議終了を検知');
sendWebhook('meeting_ended');
}
};
// 状態チェック
const checkState = () => {
const newState = detectState();
if (newState !== currentState) {
handleStateChange(currentState, newState);
currentState = newState;
}
};
Webhook
Webhookは非同期で実施しています。
const sendWebhook = async (status) => {
try {
const response = await fetch(WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
status: status,
timestamp: new Date().toISOString()
})
});
} catch (error) {
console.error(`[Webhook] ${status} 送信エラー:`, error);
}
};
リクエストパラメタは以下のようになります。
{
"status": "meeting_started or meeting_ended",
"timestamp": "2025-10-28T14:30:45.123Z",
}
残課題
タブ閉じ対応
会議中にタブ閉じで会議を終了した場合の対応ができていません。
beforeunloadやpagehideイベントを監視することで動作確認をしてみましたが上手く発砲しませんでした。
window.addEventListener('beforeunload', () => {
if (currentState === STATES.IN_MEETING) {
const data = new Blob([JSON.stringify({
status: 'meeting_ended',
timestamp: new Date().toISOString()
})], { type: 'application/json' });
navigator.sendBeacon(WEBHOOK_URL, data);
}
});
まとめ
今回はミーティングの開始/終了を検知する仕組みづくりまで作成しました!
次は、実際に通知するところまで作っていきます!
誰かのお役に立てば幸いです〜!