**Google Meet リアクション:WebRTCチャネルを逆解析し、絵文字を実装する**

2026/01/21 5:05

**Google Meet リアクション:WebRTCチャネルを逆解析し、絵文字を実装する**

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

Summary

Google Meetの最近の絵文字リアクション拡張により、適切なものを見つけることが難しくなっています。新しいChrome拡張機能 「Google Meet Reactions」 は、最もよく使われる絵文字をすばやくアクセスできる検索可能なリストを追加することでこの問題に対処します。このツールはWebRTCのデータチャネル(

RTCPeerConnection.prototype.createDataChannel
)にフックしてリアクションメッセージをインターセプトし、これらはprotobufでエンコードされたバイナリパケットとして送信されます。受信したリアクションを再構築する際にはデバイス/ユーザーIDを作成し、gzipで圧縮してから
MessageEvent
をディスパッチします。検索機能はBM25ランキングとLevenshtein距離(タイプミス耐性)を用いて1,900以上の絵文字をカバーし、頻繁に選択されるものは自動的に優先表示されます。この拡張機能はページロード時(
document_start
)に実行されるため、Meetがチャネルを確立する前から準備完了です。ピクチャー・イン・ピクチャーモードでも動作しますが、Extended Reactionsが有効なGoogle Workspaceアカウントでのみ機能し、個人のGmailユーザーはデフォルトの9つの絵文字しか表示されません。

Links:

  • Chrome Web Store: Google Meet Reactions
  • Website:
    googlemeetreactions.com
  • Project page for more details.

本文

私は Google Meet に多くの時間を費やしています――1日 3〜4 時間ほど。最近、Google は大量の新しい絵文字リアクションを追加し、私たちはそれらを積極的に使っています。しかし、それらを探す UX が…あまり良いものではありません。仲間が「かっこいい」新絵文字を送ってくる度に、私はちょうどその 1 個を見つけるのに苦労しています。

もちろん、熱心なプログラマーなら UX を即座に改善できます!結果として登場したのが Google Meet Reactions ― Chrome 拡張機能で、Meet のインターフェースに直接絵文字検索を追加します。私にとって最も重要なのは――自分が使った絵文字や仲間が送った絵文字を覚えておき、それらを検索結果の上位に表示してくれる点です。


UI から WebRTC へ

最初に思いついたアイデアは単純でした:DOM 上の絵文字ボタンを見つけて、クリックをシミュレートする。
しかし Google Meet は

.b1bzTb
.VfPpkd-rymPhb
のような難読化されたクラス名で圧倒的に隠蔽されており、ポップアップ内の全絵文字リストを掘り下げるのはあまり良いアプローチではありません。

そこで通話中に

chrome://webrtc-internals
を開いてみたところ、数十もの RTCDataChannel の中に 「reactions」 という名前のチャンネルがあることに気付きました――そして絵文字はこのチャンネルを介して送信されているようです。
もしこのチャネルへの参照を取得し、メッセージフォーマットを解析できれば、プログラムからリアクションを送ることが可能になります。

DataChannel の作成を傍受

WebRTC の DataChannel は

RTCPeerConnection.prototype.createDataChannel()
で生成されます。
Meet が呼び出す前にこのメソッドをパッチし、参照を保存します:

const origCreate = RTCPeerConnection.prototype.createDataChannel;

RTCPeerConnection.prototype.createDataChannel = function (label, options) {
  const channel = origCreate.call(this, label, options);

  if (label === 'reactions') {
    console.log('Gotcha!');
    capturedChannel = channel;
  }

  return channel;
};

アイデアはシンプルですが、コード注入に少し問題があります。

チャネルが使われる前に注入

Chrome 拡張機能では複数の方法でページへコードを注入できます。
Content スクリプトは隔離されたワールドで動作し、ページ上の

RTCPeerConnection
にアクセスできません。そのためスクリプトを直接ページコンテキストに挿入する必要があります。

標準的なアプローチ:

const script = document.createElement('script');
script.src = chrome.runtime.getURL('rtcHook.js');
document.documentElement.appendChild(script);

しかし

script.src = URL
はネットワークリクエストを伴います。
その間に Meet が「reactions」チャンネルを既に作成してしまっていると、フックが失敗します。

解決策は二つの要素の組み合わせです:

  1. マニフェストで
    runAt: 'document_start'
    を指定し、Content スクリプトを DOM がロードされる前に実行
  2. フックスクリプトを Web‑accessible resource として宣言し、できるだけ早く読み込む
// wxt.config.ts
export default defineConfig({
  manifest: {
    web_accessible_resources: [
      {
        resources: ['rtcHook.js'],
        matches: ['https://meet.google.com/*'],
      },
    ],
  },
});

ほとんどの場合、フックは Meet がチャネルを作る前にインストールされます。競合状態が残る可能性はありますが、実際には起きていません。

絵文字の送信

チャンネルが取得できて開いている (

channel.readyState === 'open'
) と確認したら、受信メッセージを監視しつつ、自分で送る内容も観測できます。
メッセージフォーマットはネストされた長さ付きフィールドを持つ比較的単純な protobuf でした。以下のように構築して送信します:

function buildEmojiMessage(emoji) {
  const emojiBytes = [...new TextEncoder().encode(emoji)];

  // 内側から外側へ protobuf を作成 – 監視した手法をコピー
  // 10 = フィールド1、ワイヤタイプ2(長さ付き)
  // 8  = フィールド1、ワイヤタイプ0(varint)、値2
  const i1 = [10, emojiBytes.length, ...emojiBytes];
  const i2 = [10, i1.length, ...i1];
  const i3 = [8, 2, 18, i2.length, ...i2];
  const i4 = [10, i3.length, ...i3];

  return new Uint8Array([10, i4.length, ...i4]);
}

// 送信はワンライナー
capturedChannel.send(buildEmojiMessage('🔥').buffer);

自己注入

絵文字を送る際、自分自身もそのリアクションを見ることが欲しいですよね。
実際の Google Meet は内部コードで処理していますが、フェイクユーザーとフェイク ID を使って受信 WebRTC メッセージハンドラを呼び出すだけでも十分です。

// デバイス 0 は実際に使用されていないので競合しません
const SELF_DEVICE_ID = 'spaces/self/devices/0';
// 英語 UI では「You」で送信したように見えます
const SELF_USER_NAME = 'You';

function buildFullEmojiMessage(emoji) {
  const emojiBytes = [...new TextEncoder().encode(emoji)];
  const deviceIdBytes = [...new TextEncoder().encode(SELF_DEVICE_ID)];
  const userNameBytes = [...new TextEncoder().encode(SELF_USER_NAME)];

  // Emoji ブロック: [0a LL emoji] [10 01]
  const emojiBlock = [0x0a, emojiBytes.length, ...emojiBytes, 0x10, 0x01];

  // フィールド4(デバイス情報): [0a LL deviceId] [10 01]
  const field4Content = [0x0a, deviceIdBytes.length, ...deviceIdBytes, 0x10, 0x01];
  const field4 = [0x22, field4Content.length, ...field4Content];

  // フィールド6(ユーザー情報): [0a LL deviceId] [12 LL userName] [18 01]
  const field6Content = [
    0x0a, deviceIdBytes.length, ...deviceIdBytes,
    0x12, userNameBytes.length, ...userNameBytes,
    0x18, 0x01,
  ];
  const field6 = [0x32, field6Content.length, ...field6Content];

  // ネスト構造を作る
  const emojiContainer = [0x0a, emojiBlock.length, ...emojiBlock];
  const innerContent = [...emojiContainer, ...field4, ...field6];
  const inner = [0x0a, innerContent.length, ...innerContent];
  const outer = [0x0a, inner.length, ...inner];

  return new Uint8Array(outer);
}

async function injectToSelf(emoji) {
  if (!capturedChannel) return false;

  const fullMessage = buildFullEmojiMessage(emoji);

  // gzip 圧縮
  const cs = new CompressionStream('gzip');
  const cw = cs.writable.getWriter();
  cw.write(fullMessage);
  cw.close();

  const cr = cs.readable.getReader();
  const chunks = [];
  while (true) {
    const { done, value } = await cr.read();
    if (done) break;
    chunks.push(value);
  }
  const compressed = new Uint8Array(chunks.flatMap((c) => [...c]));

  // [18, length, gzip_data](フィールド2、長さ付き)でラップ
  const wrapped = new Uint8Array([18, compressed.length, ...compressed]);
  const fakeEvent = new MessageEvent('message', { data: wrapped.buffer });

  // Meet のクライアントはこのイベントを他人から送られたリアクションとして処理します
  capturedChannel.dispatchEvent(fakeEvent);
  return true;
}

タイポ許容検索も実装

数個の必須機能だけに留まるわけにはいきません。
拡張機能は以下を備えています:

  • 1900+ 絵文字を対象としたタイポ補正付き検索(BM25 + Levenshtein 距離)
  • パーソナライズ:自分が使った絵文字や仲間が送ったものを優先表示し、同じリアクションを簡単に共有できるように
  • ピクチャ―イン―ピクチャ モードでも動作

制限事項

拡張機能は Google Workspace アカウントで Extended Reactions が有効なミーティングでのみ機能します。
個人 Gmail アカウントから作成されたミーティングでは標準の 9 絵文字しか利用できず、拡張機能の価値はほとんどありません。


役立ちましたか?

仕事で Google Meet を使っているなら、ぜひ試してみてください。サイドプロジェクト作者として、追加すべき機能や不要なものを削除するべき点について意見をいただけると嬉しいです。何がうまくいき、どこを改善できるでしょうか?

リンク

  • Google Meet Reactions – 拡張機能のインストール
  • googlemeetreactions.com – 拡張機能公式サイト
  • プロジェクトページ – 詳細情報

同じ日のほかのニュース

一覧に戻る →

2026/01/21 3:16

**2019年 「見えないままに隠された26000年前の天文モニュメント」**

## Japanese Translation: **概要:** フーバーダムの西側にあるモニュメント・プラザは、地球の25,772年周期の軸進動をタレーズ床にマッピングした芸術的な敬意表現です。設計の中心には旗竿があり、これは進動円の中心として機能します。その周囲には巨大な翼付きブロンズ像が配置されています。床はダム開業時(1936年)のポラリス、ピラミッド建設中のトゥバン、そして将来の北極星としてプロジェクトされたベガを示しており、技術図面には惑星位置が正確に配置されているため、1日単位での日付計算が可能です。1931年に米国再利用局(U.S. Bureau of Reclamation)から委託され、1936年に完成したモニュメントは後にモニュメント・プラザと名付けられました。アーティストのオスカー J. W. ハンセン氏の意図表明は抽象的であり、歴史家エメー・ウッドワードが提供したアーカイブ写真には「セーフティアイランド」という早期建設名が示されています。デザインはロング・ナウ(Long Now)の10,000年時計コンセプトを反映しており、天体周期の公衆展示に類似するものとしてインスピレーションを与える可能性があります。米国再利用局が計画図をInternet Archiveへ公開したことは、ダム文書へのオープンアクセス化の動向を示しています。訪問者には短い音声解説のみが提供されるため、詳細な科学内容はほぼ隠蔽されており、教育的広報は限定的です。それでもプラザは20世紀初頭の大規模インフラプロジェクトにおける芸術と科学の統合を示す具体例として、歴史家・天文学者・エンジニアに貴重な実証を提供します。

2026/01/21 6:34

**日本のスナックバーの秘密世界へようこそ** 「おかかん」と呼ばれることもある日本のスナックバーは、地元ならではの味と創造性を堪能できる隠れた宝石です。小さな飲食店が揃うこれらのお店では、フライドライスボール(おにぎり)や塩気のあるペストリー、甘いスイーツなど、手軽で美味しい一口料理を提供しつつ、親切なサービスも楽しめます。 - **雰囲気**:街角の居心地の良い隅っこや静かな路地裏が主流です。 - **メニューの見どころ**: - 海苔と醤油をトッピングしたフライドライスボール - 蜂蜜でコーティングされた甘いかぼちゃロール - 豚肉と竹笹の餡が入った塩味の餃子 - **特徴**: - 多くのお店では、新鮮な地元産食材を使用しています。 - 季節ごとにメニューが変わるローテーションもあります。 おかかんへ足を踏み入れることは、単なるスナックの取得以上の体験です。便利さと伝統が交差する日本の食文化を垣間見る瞬間なのです。

## Japanese Translation: スナックバー―第二次世界大戦後に厳しい酒類法を回避するために登場した、女性が経営する小規模カフェ―は、日本独自の社会的ハブとして確立しました。全国には約10万店舗が存在し、コンビニエンスストアの数を2倍以上上回ります。これらは「ママさん」と呼ばれる年配女性によって運営され、家庭的な雰囲気でシンプルなお菓子や飲み物を提供します。主目的は食べ物や飲み物だけでなく、会話と個人的つながりを得られる居心地の良い空間を提供することです。 このコンセプトは日本の戦後経済成長期に急速に広がりました。1960年代後半には全国的にスナックバーが普及し、コミュニティのハブとなり、その後1980年代中頃から1990年代初頭まで存続しました。特徴として「ボトルキープ」システムがあります:常連客は自分のウイスキーや焼酎をラベル付けして保管し、次回訪問時に利用できます。伊良谷真由子(Mayuko Igarashi)氏などの研究者は2021年以降、1200件以上の店舗を巡り、旅行者とこれまで地元住民限定だった場所を結びつけています。 スナックバーはCOVID-19以前から人気低下やホスト人口の高齢化、カラオケバーやチェーン居酒屋との競争など課題に直面していますが、新しいトレンドが存続を支えています。アニメテーマのスナック、SNSプロモーション、LGBTQ+来客へのより包括的な対応などです。著名例として新橋の「Aeru」のウララ氏は14年間でタロットリーディングと現代のマッチメイキング手法を用いて90組以上のカップルを紹介しています。 デジタルライフの圧力にもかかわらず、スナックバーはママさんとの真の人間関係や親密な会話が評価され続けています。旅行者は、豪華ホテルや寿司教室など高価な観光活動よりも、これらの場所での思い出深い体験を重視しており、地元経済と伝統的ホスピタリティ慣行の保存に対する継続的な関連性を示しています。

2026/01/21 1:48

**UNIXパイプ・カードゲーム**

## Japanese Translation: 記事は、子どもに Unix パイプコマンドチェーンの構築方法を教えるカードベースのボードゲームについて説明しています。デッキには、`cat`、`grep`、`tail`、**`head`、`wc`、`sort`、`uniq`** などの主要な Unix コマンドを表すカードと、特定行の表示、出現回数のカウント、非表示コマンドチェーンの作成といったタスクが含まれています。ローカルの Unix システムが利用できない場合は、ブラウザベースの jslinux を使用できます。 ゲームプレイは時計回りに進行します:プレイヤーはカードを引き、最短または最長の有効パイプラインを目指すかどうかを選択し、タスクを完了した最初のプレイヤーがポイントを獲得します。例として、最も頻出する行を見つけるチェーンを示すラウンドがあります: ``` cat 03.txt | sort | uniq -c | sort -n | tail -1 ``` ゲームは €5,00 EUR(現在完売)で販売されており、印刷可能な PDF(`unix-pipe-cards.pdf`、`unix-pipe-box.pdf`)も入手できます。 GitHub 上のソースコードリポジトリ(`github.com/jackdoe`)、共著者 Jackie、連絡メールアドレス (`b0000@fastmail.com`) と CC BY 4.0 ライセンスが製品に付属しています。 「UNIX Pipe Game – Process Substitution」という拡張パックでは、プロセス置換用のコマンド(`paste`、`tr`、`cut`、`bc`)を追加します。 著者は Python の基礎、C ポインタ、機械語、ランレングス符号化、関数合成、RISCV アセンブラなどをカバーする追加のカードゲームも公開しており、子ども向けにプログラミング概念をゲーミフィケーションする広範な取り組みを示しています。