13
10

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 3 years have passed since last update.

UnityAdvent Calendar 2020

Day 22

YouTube Data API Client Library for .NETをUnityで利用してYoutubeライブのコメント、スパチャを取得する

Posted at

概要

Youtube公式に提供されているAPIを利用して、Youtubeライブのコメント、スパチャを取得します。
下記は作りかけの機能ですが、APIを利用するとこんなの作れます。

Youtube APIを利用出来るようにする

下記URLを参考に以下の3つを作成します。

YouTube Data API Client Library for .NETのインストール

YouTube Data API Client Library for .NETはNugetにありますが、UnityでNugetを利用するにはNuget for Unityをインストールします。
そして、Nuget for Unityで「Google.Apis.Youtube.v3」を検索してインストールします。

Oauthの実装

下記コードをGameObjectにアタッチして実行するとOAuthできます。_cliendIdと_clientSecretは↑で手に入れたものを入力します(下記コードの実行にはUniTaskのインストールが別途必要です)

YoutubeAuthorize.cs
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using UnityEngine;
using System.Threading;
using Cysharp.Threading.Tasks;
using Google.Apis.Auth.OAuth2;
using Google.Apis.YouTube.v3;

public class YoutubeAuthorizeSample : MonoBehaviour
{

	[SerializeField] private string _cliendId;
	[SerializeField] private string _clientSecret;
	[SerializeField] private string _user = "SampleGame";

	private void Start()
	{
		Authorize().Forget();
	}

	

	async UniTask Authorize()
	{
		YoutubeAuthorize.AuthorizeAsync(_cliendId, _clientSecret, _user).Forget();
	}

	private NameValueCollection ParseQueryString(string s)
	{
		NameValueCollection nvc = new NameValueCollection();

		// remove anything other than query string from url
		if (s.Contains("?"))
		{
			s = s.Substring(s.IndexOf('?') + 1);
		}

		foreach (string vp in Regex.Split(s, "&"))
		{
			string[] singlePair = Regex.Split(vp, "=");
			if (singlePair.Length == 2)
			{
				nvc.Add(singlePair[0], singlePair[1]);
			}
			else
			{
				// only one key with no value specified in query string
				nvc.Add(singlePair[0], string.Empty);
			}
		}

		return nvc;
	}

	async UniTask<UserCredential> AuthorizeAsync(string cliendId, string clientSecret, string user)
	{
		var secrets = new ClientSecrets
		{
			ClientId = cliendId,
			ClientSecret = clientSecret
		};

		var scopes = new string[]
		{
			YouTubeService.Scope.YoutubeReadonly
		};

		return await GoogleWebAuthorizationBroker.AuthorizeAsync(secrets, scopes, user, CancellationToken.None);
	}
}

コメント、スーパーチャットの取得

下記コードをGameObjectにアタッチし、_apiKeyに↑のAPIキー、_liveChatURLにはコメントを取得したいYoutubeライブのURLを入力して実行すると、OnReceiveLiveChatMessageにコメントとスパチャの情報が渡ります。コメント取得はポーリング式で、APIから取得できるLiveChatMessageのPollingIntervalMillis間隔で取得できます。PollingIntervalMillisはサーバーの状況によって変動するらしいですが、大体が5秒程度です。

YoutubeChatProvider.cs
using System;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using UnityEngine;
using System.Threading;
using Cysharp.Threading.Tasks;
using Google.Apis.Services;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using UniRx;
using UnityEngine.UI;
public class YoutubeChatSample : MonoBehaviour
{
	public System.Action<LiveChatMessage> OnReceiveLiveChatMessage;

	[SerializeField] private string _apiKey;
	[SerializeField] private string _liveChatURL;


	void Start()
	{
		var cancel = this.GetCancellationTokenOnDestroy();
		ConnectAsync(cancel).Forget();
	}

	async UniTask ConnectAsync(CancellationToken cancel)
	{
		var youtubeService = new YouTubeService(new BaseClientService.Initializer
		{
			ApiKey = _apiKey
		});


		var response = await GetVideoListResponse(_liveChatURL, youtubeService);

		if (response.Items.Count > 0)
		{
			var item = response.Items[0];

			var chatId = item.LiveStreamingDetails.ActiveLiveChatId;

			var livechatRequest = youtubeService.LiveChatMessages.List(chatId, new string[] { "snippet", "authorDetails" });

			livechatRequest.PageToken = null;

			var livechatResponse = await livechatRequest.ExecuteAsync();

			foreach (var liveChatItem in livechatResponse.Items)
			{
				OnReceiveLiveChatMessage?.Invoke(liveChatItem);
			}

			await UniTask.Delay((int)livechatResponse.PollingIntervalMillis);

			var nextPageToken = livechatResponse.NextPageToken;

			while (true)
			{
				if (cancel.IsCancellationRequested)
				{
					youtubeService.Dispose();
					break;
				}

				try
				{
					livechatRequest.PageToken = nextPageToken;
					livechatResponse = await livechatRequest.ExecuteAsync();


					foreach (LiveChatMessage liveChatItem in livechatResponse.Items)
					{
						OnReceiveLiveChatMessage?.Invoke(liveChatItem);
					}

				}
				catch (Exception e)
				{
					Debug.Log(e.Message);
				}
				nextPageToken = livechatResponse.NextPageToken;
				Debug.Log((int)livechatResponse.PollingIntervalMillis);
				await UniTask.Delay((int)livechatResponse.PollingIntervalMillis, false, PlayerLoopTiming.Update, cancel);
			}

		}

	}


	async UniTask<VideoListResponse> GetVideoListResponse(string liveChatURL, YouTubeService youtubeService)
	{
		var uri = new Uri(_liveChatURL);
		var qscoll = ParseQueryString(uri.Query);
		var videoId = qscoll["v"];
		var videosList = youtubeService.Videos.List("LiveStreamingDetails");
		videosList.Id = videoId;

		try
		{
			return await videosList.ExecuteAsync();

		}
		catch (Exception e)
		{
			throw e;
		}
	}

	private NameValueCollection ParseQueryString(string s)
	{
		NameValueCollection nvc = new NameValueCollection();

		// remove anything other than query string from url
		if (s.Contains("?"))
		{
			s = s.Substring(s.IndexOf('?') + 1);
		}

		foreach (string vp in Regex.Split(s, "&"))
		{
			string[] singlePair = Regex.Split(vp, "=");
			if (singlePair.Length == 2)
			{
				nvc.Add(singlePair[0], singlePair[1]);
			}
			else
			{
				// only one key with no value specified in query string
				nvc.Add(singlePair[0], string.Empty);
			}
		}

		return nvc;
	}
}

13
10
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
13
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?