見出し画像

[VRChat OSC]寝落ち時にフレンドが自分を遠隔ミュートしてくれるシステムの作り方[GAS]

これは何

マイクを付けっぱなしにして寝落ち、いびきを垂れ流してしまう……そんなことありますよね。私はあります。
そこで今回はGAS(Google Apps Script)とPythonを使って、特定のリンクを知っている人なら誰でもVRChatの中のあなたのマイクをトグルできるようになるシステムを構築します。
展望
このシステムを応用すればVRChat OSCの操作全般ができるので何かと捗るかもしれません。

必要なもの

  • Google アカウント

  • Python実行環境

    • python-osc モジュール

    • requests モジュール

システムの概要

今回の主役はGoogleスプレッドシートとそれにくっついたGAS(Google Apps Script)です。

システムの構成図

スプレッドシートのA1のセルに「true」または「false」と書かれています。これに対してブラウザやPythonからGAS経由でアクセスし、読み書きを行います。
A1セルは基本的には常にfalseで、「何者か」がアクセスした時(GASに対してGETリクエストを送った時)に初めてtrueになります。
Pythonは無限ループを回しており、絶え間なくA1セルを読み取っています。falseのときは何もしませんが、trueに変更されたことを検知すると(1) OSCサーバー(ローカルホスト9000番)の`input/Voice`にアクションを起こしマイクをトグルします。(2)スプレッドシートのA1セルをfalseに戻します。

VRChat側の下準備

これを参考にOSCを有効化してください。

GAS(スプレッドシート)側の実装

あなたのGoogleドライブの任意の場所に任意の名前のスプレッドシートを作成し、A1セルに「false」と入力します。(この時勝手に大文字中央揃えになります。)

拡張機能 > App Script からGASの編集画面に飛びます。

コード.gsに以下のコードを貼り付けます。

function doGet(e) {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getActiveSheet();

  if (e.parameter.a == "true") {
    sheet.getRange(1,1).setValue(e.parameter.a);
    return ContentService.createTextOutput("入力を承りました");
  }else if (e.parameter.a == "false") {
    sheet.getRange(1,1).setValue(e.parameter.a);
    return ContentService.createTextOutput("入力待ちです");
  }else if (e.parameter.a == "read") {
    var v = sheet.getRange(1,1).getValue();
    return ContentService.createTextOutput(v);
  }else{
    return ContentService.createTextOutput("無効なパラメータです");
  }
}

doGet(e)はGASでGETリクエストを受け付けるための関数です。`https://xxxyyyzzz?a=true`というGETリクエストがあった時、`e.parameter.a`の値は"true"になります。このGETパラメータを条件にしてA1セルを書き換えたり読み込んだりしています。

※ "https://xxxyyyzzz"は次の工程で得られるURLのことです。以下説明のためにこの仮URLを使用します。

GASの公開

このGASをWebアプリとして外部に公開します。

デプロイ > 新しいデプロイ へ進み、

  1. 種類の選択 からウェブアプリを選択

  2. 適当な説明文を入力

  3. 「自分」として実行

  4. 「全員」にアクセスを許可

  5. デプロイを実行

  6. 得られたURLをコピーしてどこかに書き留める

これでGAS製のWebアプリの完成です!コングラッチュレーションズ!

Pythonプログラム

PC上の任意の場所にいかの.pyコードを作成してください。

import argparse
import time

from pythonosc import udp_client
import requests

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--ip", default="127.0.0.1",
        help="The ip of the OSC server")
    parser.add_argument("--port", type=int, default=9000,
        help="The port the OSC server is listening on")
    args = parser.parse_args()

    client = udp_client.SimpleUDPClient(args.ip, args.port)

    n_exception = 0
    # GASのリンクをここに書く
    url = "https://xxxyyyzzz"
    while(True):
        try:
            time.sleep(0.1)
            r = requests.get(url, params={"a":"read"}, timeout=2)
            print(r.text, time.time(), "n_exception:", n_exception)
            if r.text == "true":
                print("toggle!")
                client.send_message("/input/Voice", 1) 
                time.sleep(0.1)
                client.send_message("/input/Voice", 0) 

                while True:
                    time.sleep(0.1)
                    try:
                        r = requests.get(url, params={"a":"false"}, timeout=2)
                        if r.text == "入力待ちです":
                            break
                    except:
                        print("a=falseは失敗")
                        n_exception += 1
        except KeyboardInterrupt:
            print("キーボインタラ")
            exit()
        except:
            print("exception occured.(hanya)")
            n_exception += 1

当該箇所にさっきのURLを入れるだけで動作します。


参考


Webページの作成(任意)

レンタルサーバーやgithub.ioに以下のようなHTMLファイルを置いてユーザーに見てもらうと体験がマシになるかもしれません。

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

    <title>Mute Me</title>
  </head>
  <body>
    <div class="container">
        <h1>Mute Me!</h1>
        <a type="button" class="btn btn-primary" id="toggle">Toggle his mic!</a>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
  
    <script>
        let toggle_btn = document.getElementById("toggle");
        // GASのリンクをここに書く
        const url = "http://xxxyyyzzz";
        toggle_btn.addEventListener("click", async() => {
            const res = await fetch(url + "?a=true");
            //alert(Promise.resolve(res.text()));
            alert("Request sent!");
        });
    </script>
  </body>
</html>

システムの使い方

  1. 上記の.pyを実行します。

  2. ブラウザでhttp://xxxyyyzzz?a=trueにアクセスする、または上記のHTMLのボタンを押す ※末尾の"?a=true"が重要です。

  3. pythonくんが反応してVRChat OSCサーバーにデータを送信

  4. 見事マイクがミュート/アンミュートされます!!やったね

おわりに

免責

このシステムを構築、使用したことによる不利益に関して、当方は一切責任を負いかねます。

お金くれ~~

この記事が有用だと思ったら、「気に入ったらサポート」ボタンを押してみてください!ありがたい気持ちになります。

この記事が気に入ったらサポートをしてみませんか?