Exemple #1
0
        public async Task Subscribe(WebSubHandler webSubHandler)
        {
            string externalAddress = await webAccessConfig.GetExternalWebSubAddress();

            externalURL = $"{externalAddress}/TASagentBotAPI/WebSub/Stream";
            subURL      = $"https://api.twitch.tv/helix/streams?user_id={botConfig.BroadcasterId}";

            bool success = await helixHelper.WebhookSubscribe(
                callback : externalURL,
                mode : "subscribe",
                topic : subURL,
                lease : 48 * 60 * 60,
                secret : webSubHandler.CreateSecretForRoute("/TASagentBotAPI/WebSub/Stream"));

            if (!success)
            {
                communication.SendErrorMessage("Failed to subscribe to Stream Changes. Aborting.");

                externalURL = null;
                subURL      = null;

                return;
            }

            TwitchStreams streamData = await helixHelper.GetStreams(userIDs : new List <string>()
            {
                botConfig.BroadcasterId
            });

            if (streamData.Data is null || streamData.Data.Count == 0)
            {
                currentStreamData = null;
            }
Exemple #2
0
        public IActionResult Stream(
            [FromServices] WebSub.IStreamChangeSubscriber streamChangeSubscriber,
            TwitchStreams _)
        {
            //I am unclear on why, but I have to deserialize the follow from the body manually
            Request.Body.Position     = 0;
            using StreamReader reader = new StreamReader(
                      Request.Body,
                      encoding: Encoding.UTF8,
                      detectEncodingFromByteOrderMarks: false,
                      bufferSize: -1,
                      leaveOpen: true);

            string body = reader.ReadToEnd();

            TwitchStreams channelData = JsonSerializer.Deserialize <TwitchStreams>(body);

            if (channelData.Data is not null && channelData.Data.Count > 0)
            {
                streamChangeSubscriber.NotifyUpdate(channelData.Data[0]);
            }
Exemple #3
0
        public void JoinOrPartChannels()
        {
            // Channel Status:
            //    -2 = Queued Part
            //    -1 = Queued Join
            //    0+ = Joined (Value represents strike count)
            List <String>       forcedChannels = new List <String>(Properties.Settings.Default.ChannelList.Split(','));
            List <TwitchStream> streams        =
                TwitchStreams.GetStreamsByMinViewers(Convert.ToInt32(Properties.Settings.Default.AutojoinViewerMinimum * 0.8));

            if (streams.Count == 0)
            {
                Logger.Warn("No Twitch.tv streams found meeting viewer minimums. Skipping Join/Part process.");
            }
            else
            {
                // Join channels which meet the minimum viewer requirement
                foreach (TwitchStream curStream in streams)
                {
                    if (curStream.Viewers >= Properties.Settings.Default.AutojoinViewerMinimum)
                    {
                        // We're above the Viewer Minimum so join
                        if (_channelStatus.ContainsKey(curStream.Name.ToLower()))
                        {
                            // We have some sort of status for this channel
                            Int32 status;
                            _channelStatus.TryGetValue(curStream.Name.ToLower(), out status);
                            if (status == -2)
                            {
                                // We're already set to part this channel
                                // We're above the Viewer Minimum so queue a join even though we're already set to part
                                Logger.Info($"Stream {curStream.Name} has {curStream.Viewers} viewers. Joining...");
                                QueueSend(IrcFunctions.Join('#' + curStream.Name.ToLower()));
                                _channelStatus.AddOrUpdate(curStream.Name.ToLower(), -1, (name, count) => - 1);
                            }
                            else if (status > 0)
                            {
                                // We're in the channel, so reset it's strike counter since it it's in the "OK" list
                                _channelStatus.AddOrUpdate(curStream.Name.ToLower(), 0, (name, count) => 0);
                            }
                        }
                        else
                        {
                            // We've never done anything with this channel before so queue a join.
                            Logger.Info($"Stream {curStream.Name} has {curStream.Viewers} viewers. Joining...");
                            QueueSend(IrcFunctions.Join('#' + curStream.Name.ToLower()));
                            _channelStatus.AddOrUpdate(curStream.Name.ToLower(), -1, (name, count) => - 1);
                        }
                    }
                }
                foreach (String curChannel in forcedChannels)
                {
                    // This channel is a forced channel
                    if (_channelStatus.ContainsKey(curChannel.ToLower()))
                    {
                        // We have some sort of status for this channel
                        Int32 status;
                        _channelStatus.TryGetValue(curChannel.ToLower(), out status);
                        if (status == -2)
                        {
                            // We're already set to part this channel (this should only happen if we're kicked since we don't volunteer to part forced channels)
                            // We're above the Viewer Minimum so join even though we're already set to part
                            Logger.Info($"Stream {curChannel} is in the forced list. Joining...");
                            QueueSend(IrcFunctions.Join('#' + curChannel.ToLower()));
                            _channelStatus.AddOrUpdate(curChannel.ToLower(), -1, (name, count) => - 1);
                        }
                    }
                    else
                    {
                        // We've never done anything with this channel before
                        Logger.Info($"Stream {curChannel} is in the forced list. Joining...");
                        QueueSend(IrcFunctions.Join('#' + curChannel.ToLower()));
                        _channelStatus.AddOrUpdate(curChannel.ToLower(), -1, (name, count) => - 1);
                    }
                }
                // Leave channels which don't meet 80% of the minimum viewer requirement
                foreach (KeyValuePair <String, Int32> curChanKVP in _channelStatus)
                {
                    if (!forcedChannels.Contains(curChanKVP.Key.ToLower()))
                    {
                        // If this is not a forced channel
                        Int32 findIndex =
                            streams.FindIndex(f => String.Equals(f.Name, curChanKVP.Key, StringComparison.CurrentCultureIgnoreCase));
                        if (findIndex == -1)
                        {
                            // Channel didn't come back in our twitch query (meaning it is offline or below min viewer count)
                            if (_channelStatus.ContainsKey(curChanKVP.Key.ToLower()))
                            {
                                // We have some sort of status for this channel
                                Int32 status;
                                _channelStatus.TryGetValue(curChanKVP.Key.ToLower(), out status);
                                if (status >= 0)
                                {
                                    // We're already in the channel (don't give strikes until we're in the channel)
                                    // Increment the number of strikes
                                    _channelStatus[curChanKVP.Key.ToLower()]++;
                                    Logger.Info(
                                        $"Stream {curChanKVP.Key} has less than {Properties.Settings.Default.AutojoinViewerMinimum * 0.8} viewers. Strike {_channelStatus[curChanKVP.Key.ToLower()]}/{Properties.Settings.Default.AutojoinStrikeLimit}...");
                                    if (_channelStatus[curChanKVP.Key.ToLower()] >= Properties.Settings.Default.AutojoinStrikeLimit)
                                    {
                                        // We're at max strikes, queue a leave
                                        Logger.Info(
                                            $"Strike {_channelStatus[curChanKVP.Key.ToLower()]}/{Properties.Settings.Default.AutojoinStrikeLimit} for {curChanKVP.Key}... Leaving...");
                                        QueueSend(IrcFunctions.Part('#' + curChanKVP.Key.ToLower()));
                                        _channelStatus.AddOrUpdate(curChanKVP.Key.ToLower(), -2, (name, count) => - 2);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (_joinTimer == null)
            {
                Logger.Info($"Starting Channel Maintainer ({Properties.Settings.Default.AutojoinCheckFrequencyMS}ms)");
                _joinTimer = new Timer(_ => JoinOrPartChannels(), null, Properties.Settings.Default.AutojoinCheckFrequencyMS,
                                       Timeout.Infinite);
            }
            else
            {
                _joinTimer.Change(Properties.Settings.Default.AutojoinCheckFrequencyMS, Timeout.Infinite);
            }
        }