3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

VRChatのフレンドがいるワールドをGASを使ってカレンダーに記録

Posted at

VRChatのフレンドがいるワールドをGASを使ってカレンダーに記録する

最近、VRChatのAPIを叩き始め、何か面白いことできないかと思って作ってみた。

GAS(Google Apps Script)には指定したURLにリクエストを出す機能(UrlFetchApp.fetch())がある。
これを用いればVRCのAPIが叩ける。

今回作ったのは、あるフレンドの現在いるワールドをGoogleのスプレッドシートとカレンダーに記録して行くスクリプト。
(本当は自分のいるワールドの記録をとりたかったのだけど、自分のフレンドしか現在いるワールドを取得できないため、自分のワールドを取得できない。)
使う場合は、フレンドの了承が得られてから。

VRChatのAPI

VRChatのAPIで取得できる情報はいろいろある。結構使えなくなってるのも多いけど。
ドキュメントはここ
今回はフレンドの名前から情報を得る、"Get By Name"を使う。
エンドポイントは以下のURL
https://api.vrchat.cloud/api/1/users/[USERNAME]/name

また、ワールドの名前をIDから得るために、"Get World"を用いる
エンドポイントは以下のURL
https://api.vrchat.cloud/api/1/worlds/[ID]

非公式のものなので急に使えなくなる可能性がある。
また、負荷をかけないためにもリクエストは1分間に1度まで。

GAS

Google Apps ScriptはGoogleの各種サービスをスクリプトで制御するもの。
JavaScriptベースなのでWeb業界の人なら新しく覚えることも少ない。
GASは時間ベースのトリガーを使って*分ごとに自動実行というのが行える。

準備

必要なもの

  • Googleアカウント
    以上

ドライブ上でGASとスプレッドシートを1個ずつ作る。
右クリックすれば作れる。
(GASは最初ないので、"その他->アプリを追加"から追加しておく)
適当にGASとスプレッドシートは名前を付けておく。
876df5a9-525e-4b25-b0bd-d2aa32a0b014.jpg

スプレッドシートからIDを記録しておく。
(スプレッドシートの編集画面でURLの/d/と/editに囲まれた文字列がID)
スプレッドシートの一行目に以下の画像のように適当にヘッダーを書いておく
d09e7dbe-a74e-4282-951c-df07ea51a0eb.jpg

Googleカレンダーでワールド記録用にカレンダーを一個作っておく。
そのカレンダーのIDを記録しておく。

実装

以下のスクリプトをGASに書き込む。
自分の環境に合わせてVRChatのID、パスワード、フレンド名、スプレッドシートとカレンダーのIDを埋めておく。

function GetWorldID() {
  // アクセス先の情報
  var url = "https://api.vrchat.cloud/api/1/users/";
  var friendName = "";//追跡するフレンドの名前
  url = url + friendName + "/name"
  var userid = "";//VRCのユーザ名
  var password = "";  //VRCのパスワード
  var queryString = "?apiKey=JlE5Jldo5Jibnk5O5hTx6XVqsJu4WJ26";
  
  
  //スプレッドシートを得るための情報
  var SheetId = "";//スプレッドシートのID
  var SheetName = "シート1";
  var ss = SpreadsheetApp.openById(SheetId);
  var Sheet = ss.getSheetByName(SheetName);
  var dat = Sheet.getDataRange().getValues(); //シートデータを取得
  
  url = url + queryString;
  Logger.log(url);

  // GETメソッドのオプション
  var options = {
    "contentType": "application/json",
    "headers" : {"Authorization" : "Basic " + Utilities.base64Encode(userid + ':' + password, Utilities.Charset.UTF_8)},
    "muteHttpExceptions" : true
  }

  try{
    var response = UrlFetchApp.fetch(url, options);
    var content = response.getContentText("UTF-8");
    Logger.log(content);
    var json=JSON.parse(response);
 
    Logger.log("WorldIDは" + json["worldId"]);
    
    var WorldID = json["worldId"];

    //VRCHATをやっていないときは記録しない
    if(WorldID == "offline"){
      Logger.log("User id offline");
      return 0;
   }

    var now = new Date();
    
    Sheet.getRange(dat.length+1,2).setValue(WorldID);
    Sheet.getRange(dat.length+1,1).setValue(now);
    
   //set Trigger 2分後に起動
    var triggerDay = new Date();
    triggerDay.setMinutes(triggerDay.getMinutes() +2);
    ScriptApp.newTrigger("GetWorldName").timeBased().at(triggerDay).create();
   
    
    
  }catch(e){
    Logger.log(e.message);
  }
}


function GetWorldName() {
  deleteTrigger();
  var url = "https://api.vrchat.cloud/api/1/worlds/";
  var userid = "";//VRCのユーザ名
  var password = "";//VRCのパスワード
  var queryString = "?apiKey=JlE5Jldo5Jibnk5O5hTx6XVqsJu4WJ26";
  
  var SheetId = "";//スプレッドシートのID
  var SheetName = "シート1";
  var ss = SpreadsheetApp.openById(SheetId);
  var Sheet = ss.getSheetByName(SheetName);
  var dat = Sheet.getDataRange().getValues(); 
  
  var WorldID = Sheet.getRange(dat.length, 2).getValue();
  var TheTime = Sheet.getRange(dat.length, 1).getValue();
  var TheTime10 = Sheet.getRange(dat.length, 1).getValue();

  var options = {
    "contentType": "application/json",
    "headers" : {"Authorization" : "Basic " + Utilities.base64Encode(userid + ':' + password, Utilities.Charset.UTF_8)},
    "muteHttpExceptions" : true
  }

  try{
    url = url + WorldID + queryString;
    var response = UrlFetchApp.fetch(url, options);
    var content = response.getContentText("UTF-8");
    Logger.log(content);
    
    var json=JSON.parse(response); 
    Logger.log("WorldNameは" + json["name"]);
    var WorldName = json["name"];
        
    Sheet.getRange(dat.length,3).setValue(WorldName);
    
    RecordCalender(WorldName, TheTime, TheTime10);
    
  }catch(e){
    Logger.log(e.message);
  }
}

function RecordCalender(WorldName, TheTime, TheTime10){
  var calID =  "";//カレンダーのID
  var cal = CalendarApp.getCalendarById(calID);
  var now = TheTime;
  var now10 = TheTime10;
  now10.setMinutes(now10.getMinutes() + 10);
  cal.createEvent(WorldName, now, now10);  
}

function deleteTrigger() {
  var triggers = ScriptApp.getProjectTriggers();
  for(var i=0; i < triggers.length; i++) {
    if (triggers[i].getHandlerFunction() == "GetWorldName") {
      ScriptApp.deleteTrigger(triggers[i]);
    }
  }
}

スクリプトの処理の流れとしては、

  1. VRCAPIを使ってフレンドの現在いるワールドのIDを取得しスプレッドシートに追加。2分後に2.を起動するトリガーを設定。
    2.1 この処理を起動したトリガーを削除。ワールドIDからワールドの名前をVRCのAPIを使って取得し、スプレッドシートに追加。
    2.2. カレンダーに記録する。

トリガー設定

トリガー設定前に、必ずGASエディタ画面で1回は実行しておくこと(エディタ画面でctrl + r)。
ワールドIDを取得する関数を10分ごとに呼び出すようにトリガーを追加設定しておく。
トリガーはGASエディタ画面の編集->現在のプロジェクトのトリガーから行える。
dc9da21a-1ea1-4c2b-8686-91540dfb3872.jpg

結果

記録されたデータは、ワールド名をタイトルにイベントとしてGoogleカレンダーに記録される。(見づらい…)。
Googleカレンダーなので全世界に公開も可能。
4802e6e7-2a57-4289-8d4a-723ba9ff571e.jpg

はまったとこ

ユーザ名に日本語名が入っていると、リクエストの際にBASIC認証で、UTF-8を指定しておかないといけない。
自分は自分のフレンドにはなれない。
VRCAPIが1分間に1回の制限、GASの実行時間が1日に1時間までの制限があるのであつかいづらい。

今後やりたいこと

今回のスクリプトの改善

カレンダーで見やすいイベント(ワールド名)追加。

  • 同じワールドなら表示をまとめる。
    10分感覚で情報を取得ているが、もっと狭い感覚で情報を取得する。
    WorldIDから名前を取得するときにVRCのAPIを叩かずにスプレッドシートから取得するキャッシュ機能
  • どのワールドに長くいたとかの分析機能

APIを用いた別のこと

フレンド登録日をカレンダーに記録するGASの作成。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?