60
47

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.

YouTubeLiveの配信コメントをUnityで利用する

Last updated at Posted at 2018-02-12

スクリーンショット 2018-02-12 13.21.12.png

YouTube Liveのチャットコメントを使って遊んでみます。

チャンネルIDから辿る方法をとらずに、Unity上でOAuth認証を行います。

こちらのほぼUnity実装版に相当
https://blog.sky-net.pw/article/86

APIキーの用意

Google APIsに行き

  • プロジェクトを作成しYouTube Data API v3を有効化

次にOAuthクライアントを作成します。

  • 認証情報>「OAuth 同意画面」 に適当なサービス名を入力
  • 認証情報>「認証情報を作成」>「OAuth クライアント ID」から作成(アプリケーションの種類はその他、名前は適当)

これでclient_idclient_secertが得られます。

認可コードの取得

ここからUnity。

コード全体はこちら

public class YouTubeLiveController : MonoBehaviour { 
  
  IEnumerator Start() {
    var clientId = "client_id";
    var clientSecret = "client_secret";

    var code = "";
    LocalServer (c => code = c);

    var authUrl = "https://accounts.google.com/o/oauth2/v2/auth?response_type=code"
      + "&client_id=" + clientId
      + "&redirect_uri=" + "http://localhost:8080"
      + "&scope=" + "https://www.googleapis.com/auth/youtube.readonly"
      + "&access_type=" + "offline";
    Application.OpenURL (authUrl);
    yield return new WaitUntil (() => code != "");

    Debug.Log (code);
  }

  void LocalServer(Action<string> onReceive) {
    ThreadStart start = () => {
      try {
        var listener = new HttpListener();
        listener.Prefixes.Add("http://*:8080/");
        listener.Start();

        var context = listener.GetContext();
        var req = context.Request;
        var res = context.Response;

        var re = new Regex (@"/\?code=(?<c>.*)");
        var code = re.Match (req.RawUrl).Groups ["c"].ToString();
        onReceive(code);

        res.StatusCode = 200;
        res.Close();
      } catch (Exception e) {
        Debug.LogError(e);
      }
    };
    new Thread (start).Start ();
  }

}

client_idからコード取得用のURLを構築してApplication.OpenURLでブラウザを開きます。

ブラウザで認証後にUnity側で認証結果を受け取る手段がないため、ローカルサーバを立ててこちらにリダイレクトさせて無理やりcodeを取得します。

アクセストークンの取得

取得したcodeを使用してaccess_tokenを取得します。

  IEnumerator Start() {
    // snip

    var tokenUrl = "https://www.googleapis.com/oauth2/v4/token";
    var content = new Dictionary<string,string> () {
      { "code", code },
      { "client_id", clientId },
      { "client_secret", clientSecret },
      { "redirect_uri",  "http://localhost:8080" },
      { "grant_type", "authorization_code" },
      { "access_type", "offline" },
    };
    var request = UnityWebRequest.Post (tokenUrl, content);
    yield return request.SendWebRequest();

    var json = JSON.Parse (request.downloadHandler.text);
    var token = json["access_token"].RawString();

    Debug.Log (token);
  }

実際のレスポンスは次のようになっています。リフレッシュトークンも取得できますがここではとりあえず使用しません。

{
 "access_token": "ya29.GltgB...",
 "token_type": "Bearer",
 "expires_in": 3600,
 "refresh_token": "1/hsjPU..."
}

JSONパーサーとしてSimpleJsonを利用します。。RawString()の中身は

public static class SimpleJsonUtility {
  public static string RawString(this JSONNode node) {
    var len = node.ToString ().Length - 2;
    return node.ToString ().Substring (1, len);
  }
}

パース結果をjson["access_token"].ToString()すると""abcdef""のようにダブルクオーテーションまで文字列に含まれてしまうのでその対応をしています。

チャットIDの取得

YouTube Live Streaming APIを使っていきます。

はじめにliveChatIdを取得します。

  IEnumerator Start() {
    // snip

    var url = "https://www.googleapis.com/youtube/v3/liveBroadcasts?part=snippet";
    url += "&id=" + "xxxxxxxxxxx";

    var req = UnityWebRequest.Get (url);
    req.SetRequestHeader ("Authorization", "Bearer " + token);
    yield return req.SendWebRequest();

    json = JSON.Parse (req.downloadHandler.text);
    var chatId = json["items"][0]["snippet"]["liveChatId"].RawString();

    Debug.Log (chatId);
  }

idhttps://www.youtube.com/watch?v=xxxxxxxxxxxxxxxxxxxxxxの部分を入れます。

対象にしている動画がライブ中でない(かそもそもライブでない)場合はliveChatIdがレスポンスの中に含まれません。

また、トークンを指定せずにアクセスすると

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "required",
    "message": "Login Required",
    "locationType": "header",
    "location": "Authorization"
   }
  ],
  "code": 401,
  "message": "Login Required"
 }
}

このように怒られます。

コメントの取得

対象のチャットからコメントを取得します。

  IEnumerator Start() {
    // snip

    url = "https://www.googleapis.com/youtube/v3/liveChat/messages?part=snippet,authorDetails";
    url += "&liveChatId=" + chatId;

    req = UnityWebRequest.Get (url);
    req.SetRequestHeader ("Authorization", "Bearer " + token);
    yield return req.SendWebRequest();

    json = JSON.Parse (req.downloadHandler.text);
    var items = json["items"];

    foreach (var item in items) {
      var snip = item.Value ["snippet"];
      var author = item.Value["authorDetails"];
      Debug.Log (author ["displayName"].RawString () + ": "
        + snip ["displayMessage"].RawString());
    }
    Debug.Log (json["nextPageToken"]);
  }

コメントだけでなくコメント投稿者の名前やアイコンを取得することもできます。

何度もコメントを取得するような場合、page_tokenを指定することで前回取得分からの差分のみを取得できます。

コメントの利用

使いやすく書き直したもの
https://gist.github.com/n0mimono/00f8e68a8fa5e2f9b36a4fab30adcd22

コメントを取得してキャラを走らせてみます。

public class Rotater : MonoBehaviour {
  [SerializeField]
  Transform character;

  [SerializeField]
  YouTubeLive.YtlController ctrl;

  float tgt;
  float speed;

  void Start() {
    Application.runInBackground = true;

    ctrl.OnMessage += msg => {
      tgt += msg.text.Length * 5f;
    };
  }

  void Update() {
    speed = Mathf.Lerp (tgt, speed, Time.deltaTime);

    transform.Rotate (Vector3.up, speed * Time.deltaTime);

    var animator = character.GetComponent<Animator> ();
    animator.SetFloat ("Speed", speed);
  }
}

結果

wak2.gif

チャットに書き込むとキャラが加速します。

60
47
1

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
60
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?