internal static void Start() { YouTubeMessageHandlers.InvokeHandler(new YouTubeMessage("youtube#onInitialize"), ""); TaskHelper.ScheduleUniqueActionAtTime("YouTubeOAuthRefresh", () => YouTubeOAuthToken.Refresh(), YouTubeOAuthToken.expireTime.Subtract(new TimeSpan(0, 1, 0))); TaskHelper.ScheduleUniqueRepeatingAction("YouTubeChannelRefresh", () => YouTubeLiveBroadcast.Refresh(), 60000 * 3); // Refresh our list of broadcasts 3 minutes (this task will automatically cancel it's self once it latches onto a broadcast) TaskHelper.ScheduleUniqueRepeatingAction("YouTubeLiveChatRefresh", () => YouTubeLiveChat.Refresh(), 0); }
private static void HttpServer_OnGet(HttpRequestEventArgs e) { var request = e.Request; var response = e.Response; byte[] data = null; switch (request.Url.LocalPath) { case "/callback": // If we successfully exchange our code for an auth token, request a listing of live broadcast info if (YouTubeOAuthToken.Exchange(request.QueryString["code"])) { response.StatusCode = 307; response.Redirect($"http://localhost:{port}/success"); // Start the YouTubeConnection YouTubeConnection.Start(); } else { response.StatusCode = 401; response.Redirect($"http://localhost:{port}/failure"); } // Close the response then stop the server response.Close(); break; case "/success": data = Encoding.UTF8.GetBytes("Success linking YouTube account! You may now close this page and return to the game."); response.WriteContent(data); response.StatusCode = 200; response.Close(); StopServer(); break; case "/failure": data = Encoding.UTF8.GetBytes("Failed to link YouTube account."); response.WriteContent(data); response.StatusCode = 200; response.Close(); StopServer(); break; default: response.StatusCode = 404; StopServer(); break; } }
internal static void Refresh() { try { // Wait a few seconds then return if the current broadcast is null if (YouTubeLiveBroadcast.currentBroadcast == null) { Thread.Sleep(5000); return; } //Plugin.Log($"Requesting chat messages for live chat with id {YouTubeChannel.liveOrDefaultChatId}..."); HttpWebRequest web = (HttpWebRequest)WebRequest.Create($"https://www.googleapis.com/youtube/v3/liveChat/messages?liveChatId={YouTubeLiveBroadcast.currentBroadcast.snippet.liveChatId}&part=id%2Csnippet%2CauthorDetails{(_nextPageToken!=""? $"&pageToken={_nextPageToken}" : "")}"); web.Method = "GET"; web.Headers.Add("Authorization", $"{YouTubeOAuthToken.tokenType} {YouTubeOAuthToken.accessToken}"); web.Accept = "application/json"; using (HttpWebResponse resp = (HttpWebResponse)web.GetResponse()) { if (resp.StatusCode == HttpStatusCode.OK) { using (Stream dataStream = resp.GetResponseStream()) { using (StreamReader reader = new StreamReader(dataStream)) { string ret = reader.ReadToEnd(); Process(ret); //Plugin.Log($"Chat: {ret}"); } } } else { Plugin.Log($"Error: {resp.StatusCode.ToString()}"); } } } catch (WebException ex) { // Read the response and log it using (Stream dataStream = ex.Response.GetResponseStream()) { using (StreamReader reader = new StreamReader(dataStream)) { var response = reader.ReadToEnd(); Plugin.Log($"Status: {ex.Status}, Response: {response}"); switch (((HttpWebResponse)ex.Response).StatusCode) { // If we hit an unauthorized exception, the users auth token has expired case HttpStatusCode.Unauthorized: // Try to refresh the users auth token, forcing it through even if our local timestamp says it's not expired if (!YouTubeOAuthToken.Refresh(true)) { YouTubeOAuthToken.Invalidate(); YouTubeOAuthToken.Generate(); } break; case HttpStatusCode.Forbidden: var json = JSON.Parse(response); List <string> errorList = new List <string>(); foreach (var error in json["error"]["errors"].AsArray) { errorList.Add(error.Value["reason"].Value); } YouTubeConnection.lastError = "Unable to retrieve YouTube live chat messages. Have you reached your quota? Error(s): " + string.Join(", ", errorList); YouTubeMessageHandlers.InvokeHandler(new YouTubeMessage("youtube#onError"), ""); YouTubeLiveBroadcast.currentBroadcast = null; YouTubeConnection.Stop(); break; } } } _pollingIntervalMillis = 3000; } catch (Exception ex) { Plugin.Log(ex.ToString()); _pollingIntervalMillis = 3000; } Thread.Sleep(_pollingIntervalMillis); }
internal static void Initialize_Internal() { if (!initialized) { YouTubeMessageHandlers.Initialize(); initialized = true; Task.Run(() => { Plugin.Log("Initializing!"); string ClientIDPath = Path.Combine(Globals.DataPath, "YouTubeClientId.json"); if (!File.Exists(ClientIDPath)) { Plugin.Log("YouTubeClientId.json does not exist!"); // Client id/secret don't exist, abort return; } // Initialize our client id/secret if (!YouTubeOAuthToken.Initialize(ClientIDPath)) { Plugin.Log("Something went wrong when trying to read YouTubeClientId.json."); // Something went wrong when trying to read client id/secret return; } string tokenPath = Path.Combine(Globals.DataPath, "YouTubeOAuthToken.json"); if (!File.Exists(tokenPath)) { Plugin.Log("YouTubeOAuthToken.json does not exist, generating new auth token!"); // If we haven't already retrieved an oauth token, generate a new one YouTubeOAuthToken.Generate(); return; } Plugin.Log("Auth token file exists!"); // Read our oauth token in from file if (!YouTubeOAuthToken.Update(File.ReadAllText(tokenPath), false)) { Plugin.Log("Failed to parse oauth token file, generating new auth token!"); // If we fail to parse the file, generate a new oauth token YouTubeOAuthToken.Generate(); return; } Plugin.Log("Success parsing oauth token file!"); // Check if our auth key is expired, and if so refresh it if (!YouTubeOAuthToken.Refresh()) { Plugin.Log("Failed to refresh access token, generating new auth token!"); // If we fail to refresh our access token, generate a new one YouTubeOAuthToken.Generate(); return; } // Sleep for a second before connecting, to allow for other plugins to register their callbacks Thread.Sleep(1000); // Finally, request our live broadcast info if everything went well Start(); }); } }
internal static void Refresh() { try { Plugin.Log($"Requesting live broadcast info..."); HttpWebRequest web = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/youtube/v3/liveBroadcasts?part=id%2Csnippet%2Cstatus&broadcastStatus=all&broadcastType=all&maxResults=50"); web.Method = "GET"; web.Headers.Add("Authorization", $"{YouTubeOAuthToken.tokenType} {YouTubeOAuthToken.accessToken}"); web.Accept = "application/json"; web.UserAgent = "StreamCoreClient"; using (HttpWebResponse resp = (HttpWebResponse)web.GetResponse()) { if (resp.StatusCode == HttpStatusCode.OK) { using (Stream dataStream = resp.GetResponseStream()) { using (StreamReader reader = new StreamReader(dataStream)) { string ret = reader.ReadToEnd(); if (Update(ret)) { channelName = GetChannelName(currentBroadcast.snippet.channelId); Plugin.Log("YouTube channel name: " + channelName); YouTubeMessageHandlers.InvokeHandler(new YouTubeMessage("youtube#onConnectedToLiveChat"), ""); TaskHelper.CancelTask("YouTubeChannelRefresh"); Plugin.Log($"There are currently {broadcasts.Count} broadcasts being tracked.");// Ret: {ret}"); } //Plugin.Log($"Broadcast \"{broadcast.Value.snippet.title}\" (ID: {broadcast.Value.id}, ChannelID: {broadcast.Value.snippet.channelId}) with description \"{broadcast.Value.snippet.description}\" status is \"{broadcast.Value.status.recordingStatus}\""); } } } else { Plugin.Log($"Error: {resp.StatusCode}"); } } } catch (WebException ex) { // Read the response and log it using (Stream dataStream = ex.Response.GetResponseStream()) { using (StreamReader reader = new StreamReader(dataStream)) { var response = reader.ReadToEnd(); Plugin.Log($"Status: {ex.Status}, Response: {response}"); switch (((HttpWebResponse)ex.Response).StatusCode) { // If we hit an unauthorized exception, the users auth token has expired case HttpStatusCode.Unauthorized: // Try to refresh the users auth token, forcing it through even if our local timestamp says it's not expired if (!YouTubeOAuthToken.Refresh(true)) { YouTubeOAuthToken.Invalidate(); YouTubeOAuthToken.Generate(); } break; case HttpStatusCode.Forbidden: var json = JSON.Parse(response); List <string> errorList = new List <string>(); foreach (var error in json["error"]["errors"].AsArray) { errorList.Add(error.Value["reason"].Value); } YouTubeConnection.lastError = "Unable to retrieve live broadcast data! Ensure you have configured the YouTube data API correctly, then try again. Error(s): " + string.Join(", ", errorList); YouTubeMessageHandlers.InvokeHandler(new YouTubeMessage("youtube#onError"), ""); currentBroadcast = null; YouTubeConnection.Stop(); break; } } } } catch (Exception ex) { Plugin.Log(ex.ToString()); } }