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_id
とclient_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);
}
id
はhttps://www.youtube.com/watch?v=xxxxxxxxxxx
のxxxxxxxxxxx
の部分を入れます。
対象にしている動画がライブ中でない(かそもそもライブでない)場合は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);
}
}
結果
チャットに書き込むとキャラが加速します。