Instantly share code, notes, and snippets.

Embed
What would you like to do?
Unity script example for YouTube Live Streaming
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using UnityEngine.Networking;
using SimpleJSON;
namespace YouTubeLive {
public class Chat {
public class Msg {
public string text;
public string name;
public string img;
}
public List<Msg> msgs = new List<Msg>();
public string pageToken;
}
[Serializable]
public class Access {
[Header("YouTube")]
public string id = "_video_uri";
[Header("OAuth")]
public string clientId = "_client_id";
public string clientSecret = "_client_secret";
[Header("Options")]
public string redirectUri = "http://localhost:8080";
public string grantType = "authorization_code";
public string accessType = "offline";
public string scope = "https://www.googleapis.com/auth/youtube.readonly";
public string code = "";
public string token = "";
}
public class YtlClient : MonoBehaviour {
public Access access { set; get; }
public string AuthUrl() {
return "https://accounts.google.com/o/oauth2/v2/auth?response_type=code"
+ "&client_id=" + access.clientId
+ "&redirect_uri=" + access.redirectUri
+ "&scope=" + access.scope
+ "&access_type=" + access.accessType;
}
public void GetToken(Action<string,string> OnSuccess, Action<string> OnFailure) {
var url = "https://www.googleapis.com/oauth2/v4/token";
var content = new Dictionary<string,string> () {
{ "code", access.code },
{ "client_id", access.clientId },
{ "client_secret", access.clientSecret },
{ "redirect_uri", access.redirectUri },
{ "grant_type", access.grantType },
{ "access_type", access.accessType },
};
StartCoroutine (Post (url, content, text => {
var json = JSON.Parse(text);
var accessToken = json["access_token"].RawString();
var refreshToken = json["refresh_token"].RawString();
OnSuccess(accessToken, refreshToken);
}, OnFailure));
}
public void GetLiveChatId(string id, Action<string> OnSuccess, Action<string> OnFailure) {
var url = "https://www.googleapis.com/youtube/v3/liveBroadcasts?part=snippet";
url += "&id=" + id;
StartCoroutine (Get (url, text => {
var json = JSON.Parse(text);
var chatId = json["items"][0]["snippet"]["liveChatId"].RawString();
OnSuccess(chatId);
}, OnFailure));
}
public void GetChatMessages(string chatId, string pageToken, Action<Chat> OnSuccess, Action<string> OnFailure) {
var url = "https://www.googleapis.com/youtube/v3/liveChat/messages?part=snippet,authorDetails";
url += "&liveChatId=" + chatId;
url += pageToken == "" ? "" : "&pageToken=" + pageToken;
StartCoroutine (Get (url, text => {
var chat = new Chat();
var json = JSON.Parse(text);
var items = json["items"];
foreach (var item in items) {
var snip = item.Value["snippet"];
var author = item.Value["authorDetails"];
chat.msgs.Add(new Chat.Msg() {
text = snip["displayMessage"].RawString(),
name = author["displayName"].RawString(),
img = author["profileImageUrl"].RawString()
});
}
var next = json["nextPageToken"];
chat.pageToken = next;
OnSuccess(chat);
}, OnFailure));
}
IEnumerator Get(string uri, Action<string> OnSuccess, Action<string> OnFailure) {
var content = new Dictionary<string,string> () {
{ "Authorization", "Bearer " + access.token }
};
yield return Get (uri, content, OnSuccess, OnFailure);
}
IEnumerator Get(string uri, Dictionary<string,string> content, Action<string> OnSuccess, Action<string> OnFailure) {
UnityWebRequest request = UnityWebRequest.Get (uri);
foreach (var d in content) {
request.SetRequestHeader (d.Key, d.Value);
}
yield return request.SendWebRequest();
if (request.isNetworkError) {
OnFailure("[Network Error]");
} else if (request.isHttpError) {
OnFailure(request.downloadHandler.text);
} else {
OnSuccess(request.downloadHandler.text);
}
}
IEnumerator Post(string uri, Dictionary<string,string> content, Action<string> OnSuccess, Action<string> OnFailure) {
UnityWebRequest request = UnityWebRequest.Post (uri, content);
yield return request.SendWebRequest();
if (request.isNetworkError) {
OnFailure("[Network Error]");
} else if (request.isHttpError) {
OnFailure(request.downloadHandler.text);
} else {
OnSuccess(request.downloadHandler.text);
}
}
}
public static class SimpleJsonUtility {
public static string RawString(this JSONNode node) {
var len = node.ToString ().Length - 2;
return node.ToString ().Substring (1, len);
}
}
}
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
namespace YouTubeLive {
[RequireComponent(typeof(YtlClient))]
[RequireComponent(typeof(YtlServer))]
public class YtlController : MonoBehaviour {
[SerializeField]
Access access;
[SerializeField]
float interval = 3f;
public event Action<Chat.Msg> OnMessage;
IEnumerator Start() {
OnMessage += _ => {};
var client = GetComponent<YtlClient> ();
client.access = access;
yield return null;
if (access.code == "") {
var server = GetComponent<YtlServer>();
server.Listen();
server.OnReceiveCode += code => {
access.code = code;
};
yield return null;
Application.OpenURL (client.AuthUrl());
yield return new WaitUntil (() => access.code != "");
server.Stop ();
}
if (access.token == "") {
client.GetToken((token,_) => {
access.token = token;
}, err => {
Debug.Log("GetToken>" + err);
});
yield return new WaitUntil (() => access.token != "");
}
var chatId = "";
client.GetLiveChatId (access.id, c => {
chatId = c;
}, err => {
Debug.Log("GetLiveChatId>" + err);
});
yield return new WaitUntil (() => chatId != "");
var pageToken = "";
while (true) {
client.GetChatMessages(chatId, pageToken, chat => {
foreach (var msg in chat.msgs) {
OnMessage(msg);
}
pageToken = chat.pageToken;
}, err => Debug.Log("GetChatMessages>" + err));
yield return new WaitForSeconds (interval);
}
}
}
}
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System;
using UnityEngine;
namespace YouTubeLive {
public class YtlServer : MonoBehaviour {
HttpListener listener;
bool isRunning;
Queue<string> queue = new Queue<string>();
public event Action<string> OnReceiveCode;
public void Listen() {
ThreadStart start = () => {
try {
listener = new HttpListener();
listener.Prefixes.Add("http://*:8080/");
listener.Start();
isRunning = true;
while (isRunning) {
var context = listener.GetContext();
var req = context.Request;
var res = context.Response;
var code = ExtractCode(req.RawUrl);
if (code != "") {
queue.Enqueue(code);
}
var content = Encoding.UTF8.GetBytes(req.RawUrl);
res.StatusCode = 200;
res.OutputStream.Write(content, 0, content.Length);
res.Close();
}
} catch (Exception e) {
Debug.LogError(e);
}
};
var thread = new Thread (start);
thread.Start ();
}
public void Stop() {
if (isRunning) {
listener.Close ();
isRunning = false;
}
}
void Update() {
if (queue.Count > 0) {
var item = queue.Dequeue ();
if (OnReceiveCode != null) {
OnReceiveCode(item);
}
}
}
void OnDestory() {
Stop ();
}
public static string ExtractCode(string rawUrl) {
var re = new System.Text.RegularExpressions.Regex (@"/\?code=(?<c>.*)");
return re.Match (rawUrl).Groups ["c"].ToString();
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YouTubeLive {
[RequireComponent(typeof(YtlController))]
public class YtlTest : MonoBehaviour {
void Start () {
var ctrl = GetComponent<YtlController> ();
ctrl.OnMessage += msg => {
Debug.Log(msg.name + ": " + msg.text);
};
}
}
}
@n0mimono

This comment has been minimized.

Show comment
Hide comment
@n0mimono

n0mimono Feb 12, 2018

使用例

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);
  }

}
Owner

n0mimono commented Feb 12, 2018

使用例

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);
  }

}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment