introbotics’s blog

人工知能、機械の心について思いついたことを並べてます

スポンサーリンク

youtubeAPIを使ってyoutubeのライブ配信のチャットを取得(Visual Studio C++)④ ソースコード

youtubeAPIを使ってyoutubeのライブ配信のチャットを取得(Visual Studio C++)④
ソースコード

概要

①②③でメモしたことを組み合わせ、
VisualStdio C++からライブ配信のコメントを取得します。

前提条件

下記実施済みである事
①のcurl導入
②のyoutubeのAPIキーを取得
③のpicojson導入

ソースコード
using namespace std;
#include <curl/curl.h>
#include <picojson.h>
#include <codecvt>
size_t callbackWrite(char *ptr, size_t size, size_t nmemb, string *stream)
{
	int dataLength = size * nmemb;
	stream->append(ptr, dataLength);
	return dataLength;
}

string GetactiveLiveChatId(string LiveID){
	CURL *curl;
	CURLcode ret;
	string url = "https://www.googleapis.com/youtube/v3/videos?part=liveStreamingDetails";

	string key = "AAAAAAAAAAAAAAAAAAAAAAAAAA";//APIキー
	string chunk;

	printf("youtube初期設定\n");

	curl = curl_easy_init();

	if (curl == NULL) {
		cerr << "curl_easy_init() failed" << endl;
		getchar();
	}

	url = url + "&id=" + LiveID + "&key=" + key;
		cout << "activeLiveChatId取得用URL= " << std::endl;
		cout << url << endl;

	// レスポンスのコールバック            
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callbackWrite);
	// 書き込みバッファを指定
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &chunk);//取得行が多すぎるとエラーになる
	ret = curl_easy_perform(curl);
	curl_easy_cleanup(curl);

	if (ret != CURLE_OK) {
		cerr << "curl_easy_perform() failed." << endl;
		getchar();
	}

	picojson::value v;
	string err;
	err = picojson::parse(v, chunk);
	if (err.empty() == false) {
		std::cerr << err << std::endl;
		getchar();
	}

	std::cout << "取得jsonすべてを出力" << std::endl;
	std::cout << v << std::endl;
	std::cout << std::endl;

	//jsonを参照
	picojson::object& obj = v.get<picojson::object>();
	//std::cout << "item配列をarrayで参照 " << std::endl;
	picojson::array& obj2 = obj["items"].get<picojson::array>();

	//ここでエラーが出るときは配信が公開・限定公開になっているか確認
	string ACLiveID = obj2[0].get< picojson::object >().at("liveStreamingDetails")
		.get< picojson::object >().at("activeLiveChatId")
		.get< std::string>();

	std::cout << "activeLiveChatId" << ACLiveID << std::endl;
	printf("youtube初期設定終了\n");
	return ACLiveID;
}

//youtubeチャット取得
//引数にkey
void Getlivechat(string ACLiveID,int* totalResults, string* nextPageToken) {
	CURL *curl;
	CURLcode ret;
	string url = "https://www.googleapis.com/youtube/v3/liveChat/messages?";
	string key = "AAAAAAAAAAAAAAAAAAAAAAAAAA";//APIキー
	string chunk = "";
	int pollingIntervalMillis = 0;

	picojson::value v2;
	string err2;

	printf("youtubeチャット取得\n");

	url = url + "key=" + key + "&part=snippet,authorDetails" + "&liveChatId=" + ACLiveID + "&pageToken=" + *nextPageToken;

	std::cout << "チャット確認用URL" << std::endl;
	cout << url << endl;

	curl = curl_easy_init();
	curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callbackWrite);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &chunk);
	ret = curl_easy_perform(curl);//取得行が多すぎるとエラーになる
	curl_easy_cleanup(curl);

	if (ret != CURLE_OK) {
		cerr << "curl_easy_perform() failed." << endl;
		getchar();
	}

	err2 = picojson::parse(v2, chunk);
	if (err2.empty() == false) {
		std::cerr << err2 << std::endl;
		getchar();
	}

	//jsonを参照
	picojson::object& obj = v2.get<picojson::object>();
	std::cout << "チャット用jsonすべてを出力" << v2 << std::endl;;

	//nextPageToken/polling時間を取得
	*nextPageToken = obj["nextPageToken"].get<std::string>();
	pollingIntervalMillis = (int)obj["pollingIntervalMillis"].get < double >();
	std::cout << "polling時間 " << obj["pollingIntervalMillis"].get<double>() << std::endl;;

	//メッセージ数を取得
	*totalResults = (int)obj["pageInfo"].get< picojson::object >().at("totalResults").get < double >();
	std::cout << "メッセージ数 " << *totalResults << std::endl;;

	string displayMessage;
	//std::cout << "item配列をarrayで参照 " << std::endl;

	picojson::array& obj12 = obj["items"].get<picojson::array>();
	//item配列0番を参照

	for (int i = 0;i < *totalResults;i++) {
		//youtubeのjsonはitemsが配列だが
		//item配列0番を直接参照する方法がわからなかったので、obj2からactiveLiveChatIdを直接参照
		displayMessage = obj12[i].get< picojson::object >().at("snippet")
			.get< picojson::object >().at("displayMessage")
			.get< std::string>();

		//日本語はUTF-8で入手してしまう
		//出力時はSJISでないといけない
		//string(UTF-8):displayMessageとwstringの文字コード変換:wdisplayMessage 
		std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
		std::wstring wdisplayMessage = converter.from_bytes(displayMessage);

		//wstring(wdisplayMessage)からstring(Shift_JIS):SdisplayMessageとの文字コード変換
		std::size_t converted{};
		std::vector<char> dest(wdisplayMessage.size() * sizeof(wchar_t) + 1, '\0');
		if (::_wcstombs_s_l(&converted, dest.data(), dest.size(), wdisplayMessage.data(), _TRUNCATE, ::_create_locale(LC_ALL, "jpn")) != 0) {
			//throw std::system_error{ errno, std::system_category() };
			std::cout << "絵文字またはエラー" << endl;;
		}
		dest.resize(std::char_traits<char>::length(dest.data()));
		dest.shrink_to_fit();
		std::string SdisplayMessage = std::string(dest.begin(), dest.end());
		std::cout << "メッセージ " << SdisplayMessage << endl;;
	}
	Sleep(pollingIntervalMillis);
	//return totalResults;
}
関数使い方
	int totalResults = 0;//新規チャット数
	string nextPageToken = "";//最新チャットのみ取得のためのトークン
	string ACLiveID = "";;
	//ライブ配信毎に設定
	//idはhttps://www.youtube.com/watch?v=xxxxxxxxxxxのxxxxxxxxxxxの部分を入れます
	//自分の配信の場合、右上の共有可能なリンクを取得 から可能
	string LiveID = "xxxxxxxxxxxx";

	ACLiveID = GetactiveLiveChatId(LiveID);

	//youtubeチャット取得 実行の度に最新チャットを取得し新規チャット数を取得
	Getlivechat(ACLiveID, &totalResults, &nextPageToken);