コード例 #1
0
 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);
 }
コード例 #2
0
        internal static void Process(string json)
        {
            // Handle any json parsing errors
            if (json == string.Empty)
            {
                return;
            }

            // Parse the chat info into a json node, making sure it's not null
            JSONNode node = JSON.Parse(json);

            if (node == null || node.IsNull)
            {
                return;
            }

            // If the data has an error node, print out the entire json string for debugging purposes
            if (node.HasKey("error"))
            {
                Plugin.Log(json);
                return;
            }

            // Read in the json data to our data structs
            kind                   = node["kind"].Value;
            etag                   = node["etag"].Value;
            _nextPageToken         = node["nextPageToken"].Value;
            _pollingIntervalMillis = node["pollingIntervalMillis"].AsInt;

            // Iterate through each message, invoking any regstered callbacks along the way
            foreach (JSONObject item in node["items"].AsArray)
            {
                YouTubeMessage newMessage = new YouTubeMessage();
                newMessage.Update(item);

                YouTubeMessageHandlers.InvokeHandler(newMessage, "");
                Thread.Sleep(100);
            }
        }
コード例 #3
0
        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);
        }
コード例 #4
0
        private static void SendMessageLoop()
        {
            while (!Globals.IsApplicationExiting)
            {
                Thread.Sleep(500);
                if (_sendQueue.Count > 0 && _sendQueue.TryPeek(out var messageToSend))
                {
                    try
                    {
                        HttpWebRequest web = (HttpWebRequest)WebRequest.Create($"https://www.googleapis.com/youtube/v3/liveChat/messages?part=snippet");
                        web.Method = "POST";
                        web.Headers.Add("Authorization", $"{YouTubeOAuthToken.tokenType} {YouTubeOAuthToken.accessToken}");
                        web.ContentType = "application/json";

                        JSONObject container = new JSONObject();
                        container["snippet"] = new JSONObject();
                        container["snippet"]["liveChatId"]         = new JSONString(YouTubeLiveBroadcast.currentBroadcast.snippet.liveChatId);
                        container["snippet"]["type"]               = new JSONString("textMessageEvent");
                        container["snippet"]["textMessageDetails"] = new JSONObject();
                        container["snippet"]["textMessageDetails"]["messageText"] = new JSONString(messageToSend.Value);
                        string snippetString = container.ToString();
                        Plugin.Log($"Sending {snippetString}");
                        var postData = Encoding.ASCII.GetBytes(snippetString);
                        web.ContentLength = postData.Length;

                        using (var stream = web.GetRequestStream())
                            stream.Write(postData, 0, postData.Length);

                        using (HttpWebResponse resp = (HttpWebResponse)web.GetResponse())
                        {
                            if (resp.StatusCode != HttpStatusCode.OK)
                            {
                                using (Stream dataStream = resp.GetResponseStream())
                                {
                                    using (StreamReader reader = new StreamReader(dataStream))
                                    {
                                        var response = reader.ReadToEnd();
                                        Plugin.Log($"Status: {resp.StatusCode} ({resp.StatusDescription}), Response: {response}");
                                        continue;
                                    }
                                }
                            }

                            using (Stream dataStream = resp.GetResponseStream())
                            {
                                using (StreamReader reader = new StreamReader(dataStream))
                                {
                                    // Read the response into a JSON objecet
                                    var json = JSON.Parse(reader.ReadToEnd()).AsObject;

                                    // Then create a new YouTubeMessage object from it and send it along to the other StreamCore clients, excluding the assembly that sent the message
                                    var newMessage = new YouTubeMessage();
                                    newMessage.Update(json);

                                    var assemblyHash = messageToSend.Key.ToString();
                                    // Invoke YouTube message received callbacks
                                    YouTubeMessageHandlers.InvokeHandler(newMessage, assemblyHash);

                                    _sendQueue.TryDequeue(out var gone);
                                }
                            }
                        }
                    }
                    catch (ThreadAbortException ex)
                    {
                        return;
                    }
                    catch (Exception ex)
                    {
                        // Failed the send the message for some other reason, it will be retried next iteration
                        Plugin.Log($"Failed to send YouTube message, trying again in a few seconds! {ex.ToString()}");
                        Thread.Sleep(2500);
                    }
                }
            }
        }
コード例 #5
0
        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();
                });
            }
        }
コード例 #6
0
        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());
            }
        }