1- using System . Collections . Immutable ;
2- using System . Diagnostics ;
3- using System . Text ;
4-
5- using Newtonsoft . Json ;
6-
7- using Nullinside . Api . Common . Twitch ;
8- using Nullinside . Api . Model ;
9- using Nullinside . Api . Model . Ddl ;
10- using Nullinside . Api . TwitchBot . Model ;
11-
12- using TwitchLib . Api . Helix . Models . Chat . GetChatters ;
13-
14- using TwitchUserConfig = Nullinside . Api . Model . Ddl . TwitchUserConfig ;
15-
16- namespace Nullinside . Api . TwitchBot . Bots ;
17-
18- /// <summary>
19- /// Searches for and bans known bots when they enter the chat.
20- /// </summary>
21- public class BanKnownBots : ABotRule {
22- /// <summary>
23- /// Handles refreshing the <see cref="KnownBotListUsername" /> collection.
24- /// </summary>
25- private static Task _ = Task . Run ( async ( ) => {
26- while ( true ) {
27- Task < ImmutableHashSet < string > ? > twitchInsights = GetTwitchInsightsBots ( ) ;
28- Task < ImmutableHashSet < string > ? > commanderRoot = GetCommanderRootBots ( ) ;
29- await Task . WhenAll ( twitchInsights , commanderRoot ) ;
30- if ( null != twitchInsights . Result ) {
31- KnownBotListUsername = twitchInsights . Result ;
32- }
33-
34- if ( null != commanderRoot . Result ) {
35- KnownBotListUserId = commanderRoot . Result ;
36- }
37-
38- // The list is enormous, force garbage collection.
39- GC . Collect ( ) ;
40- GC . WaitForPendingFinalizers ( ) ;
41- await Task . Delay ( TimeSpan . FromMinutes ( 10 ) ) ;
42- }
43- } ) ;
44-
45- /// <summary>
46- /// The cache of known bots.
47- /// </summary>
48- public static ImmutableHashSet < string > ? KnownBotListUsername { get ; set ; }
49-
50- /// <summary>
51- /// The cache of known bots.
52- /// </summary>
53- public static ImmutableHashSet < string > ? KnownBotListUserId { get ; set ; }
54-
55- /// <summary>
56- /// Determine if the rule is enabled in the configuration.
57- /// </summary>
58- /// <param name="config">The user's configuration.</param>
59- /// <returns>True if it should run, false otherwise.</returns>
60- public override bool ShouldRun ( TwitchUserConfig config ) {
61- return config is { Enabled : true , BanKnownBots : true } ;
62- }
63-
64- /// <summary>
65- /// Searches for and bans known bots when they enter the chat.
66- /// </summary>
67- /// <param name="user">The user.</param>
68- /// <param name="config">The user's configuration.</param>
69- /// <param name="botProxy">The twitch api authenticated as the bot user.</param>
70- /// <param name="db">The database.</param>
71- /// <param name="stoppingToken">The cancellation token.</param>
72- public override async Task Handle ( User user , TwitchUserConfig config , ITwitchApiProxy botProxy ,
73- INullinsideContext db , CancellationToken stoppingToken = new ( ) ) {
74- if ( null == user . TwitchId ) {
75- return ;
76- }
77-
78- // TODO: SKIP MODS AND VIPS
79-
80- // Get the list of people in the chat.
81- List < Chatter > ? chatters =
82- ( await botProxy . GetChannelUsers ( user . TwitchId , Constants . BotId , stoppingToken ) ) ? . ToList ( ) ;
83- if ( null == chatters || chatters . Count == 0 ) {
84- return ;
85- }
86-
87- // Perform the comparison in the lock to prevent multithreading issues.
88- // The collection is extremely large so we do not want to make a copy of it.
89- var botsInChatInsights = new List < Chatter > ( ) ;
90- var botsInChatCommanderRoot = new List < Chatter > ( ) ;
91- ImmutableHashSet < string > ? knownBotUsernames = KnownBotListUsername ;
92- ImmutableHashSet < string > ? knownBotUserIds = KnownBotListUserId ;
93-
94- if ( null != knownBotUsernames ) {
95- botsInChatInsights . AddRange ( chatters . Where ( k =>
96- knownBotUsernames . Contains ( k . UserLogin . ToLowerInvariant ( ) ) ) ) ;
97- }
98-
99- if ( null != knownBotUserIds ) {
100- botsInChatCommanderRoot . AddRange ( chatters . Where ( k =>
101- knownBotUserIds . Contains ( k . UserId . ToLowerInvariant ( ) ) ) ) ;
102- }
103-
104- // Remove the whitelisted bots
105- botsInChatInsights = botsInChatInsights
106- . Where ( b => ! Constants . WhitelistedBots . Contains ( b . UserLogin . ToLowerInvariant ( ) ) ) . ToList ( ) ;
107- botsInChatCommanderRoot = botsInChatCommanderRoot
108- . Where ( b => ! Constants . WhitelistedBots . Contains ( b . UserLogin . ToLowerInvariant ( ) ) ) . ToList ( ) ;
109-
110- // Ban them.
111- if ( botsInChatInsights . Count != 0 ) {
112- await BanOnce ( botProxy , db , user . TwitchId , botsInChatInsights . Select ( b => ( Id : b . UserId , Username : b . UserLogin ) ) ,
113- "[Bot] Username on Known Bot List" , stoppingToken ) ;
114- }
115-
116- if ( botsInChatCommanderRoot . Count != 0 ) {
117- await BanOnce ( botProxy , db , user . TwitchId ,
118- botsInChatCommanderRoot . Select ( b => ( Id : b . UserId , Username : b . UserLogin ) ) ,
119- "[Bot] Username on Known Bot List" , stoppingToken ) ;
120- }
121- }
122-
123- /// <summary>
124- /// Gets the list of all known bots.
125- /// </summary>
126- /// <returns>The list of bots if successful, null otherwise.</returns>
127- private static async Task < ImmutableHashSet < string > ? > GetTwitchInsightsBots ( ) {
128- var stopwatch = new Stopwatch ( ) ;
129- stopwatch . Start ( ) ;
130- // Reach out to the api and find out what bots are online.
131- using var http = new HttpClient ( ) ;
132- HttpResponseMessage response = await http . GetAsync ( "https://api.twitchinsights.net/v1/bots/all" ) ;
133- if ( ! response . IsSuccessStatusCode ) {
134- return null ;
135- }
136-
137- byte [ ] ? content = await response . Content . ReadAsByteArrayAsync ( ) ;
138- string ? jsonString = Encoding . UTF8 . GetString ( content ) ;
139- var liveBotsResponse = JsonConvert . DeserializeObject < TwitchInsightsLiveBotsResponse > ( jsonString ) ;
140- if ( null == liveBotsResponse ) {
141- return null ;
142- }
143-
144- ImmutableHashSet < string > allBots = liveBotsResponse . bots
145- . Where ( s => ! string . IsNullOrWhiteSpace ( s [ 0 ] . ToString ( ) ) )
146- #pragma warning disable 8602
147- . Select ( s => s [ 0 ] . ToString ( ) . ToLowerInvariant ( ) )
148- #pragma warning restore 8602
149- . ToImmutableHashSet ( ) ;
150-
151- foreach ( List < object > ? list in liveBotsResponse . bots ) {
152- list . Clear ( ) ;
153- }
154-
155- liveBotsResponse . bots . Clear ( ) ;
156- liveBotsResponse . bots = null ;
157- liveBotsResponse = null ;
158- content = null ;
159- jsonString = null ;
160- return allBots ;
161- }
162-
163- /// <summary>
164- /// Gets the list of all known bots.
165- /// </summary>
166- /// <returns>The list of bots if successful, null otherwise.</returns>
167- private static async Task < ImmutableHashSet < string > ? > GetCommanderRootBots ( ) {
168- var stopwatch = new Stopwatch ( ) ;
169- stopwatch . Start ( ) ;
170- // Reach out to the api and find out what bots are online.
171- using var http = new HttpClient ( ) ;
172- using HttpResponseMessage response =
173- await http . GetAsync ( "https://twitch-tools.rootonline.de/blocklist_manager.php?preset=known_bot_users" ) ;
174- if ( ! response . IsSuccessStatusCode ) {
175- return null ;
176- }
177-
178- byte [ ] ? content = await response . Content . ReadAsByteArrayAsync ( ) ;
179- string ? jsonString = Encoding . UTF8 . GetString ( content ) ;
180- var liveBotsResponse = JsonConvert . DeserializeObject < List < string > > ( jsonString ) ;
181- if ( null == liveBotsResponse ) {
182- return null ;
183- }
184-
185- ImmutableHashSet < string > allBots = liveBotsResponse
186- #pragma warning disable 8602
187- . Select ( s => s . ToLowerInvariant ( ) )
188- #pragma warning restore 8602
189- . ToImmutableHashSet ( ) ;
190-
191- liveBotsResponse . Clear ( ) ;
192- liveBotsResponse = null ;
193- liveBotsResponse = null ;
194- content = null ;
195- jsonString = null ;
196- return allBots ;
197- }
198- }
1+ // using System.Collections.Immutable;
2+ // using System.Diagnostics;
3+ // using System.Text;
4+ //
5+ // using Newtonsoft.Json;
6+ //
7+ // using Nullinside.Api.Common.Twitch;
8+ // using Nullinside.Api.Model;
9+ // using Nullinside.Api.Model.Ddl;
10+ // using Nullinside.Api.TwitchBot.Model;
11+ //
12+ // using TwitchLib.Api.Helix.Models.Chat.GetChatters;
13+ //
14+ // using TwitchUserConfig = Nullinside.Api.Model.Ddl.TwitchUserConfig;
15+ //
16+ // namespace Nullinside.Api.TwitchBot.Bots;
17+ //
18+ // // / <summary>
19+ // // / Searches for and bans known bots when they enter the chat.
20+ // // / </summary>
21+ // public class BanKnownBots : ABotRule {
22+ // /// <summary>
23+ // /// Handles refreshing the <see cref="KnownBotListUsername" /> collection.
24+ // /// </summary>
25+ // private static Task _ = Task.Run(async () => {
26+ // while (true) {
27+ // Task<ImmutableHashSet<string>?> twitchInsights = GetTwitchInsightsBots();
28+ // Task<ImmutableHashSet<string>?> commanderRoot = GetCommanderRootBots();
29+ // await Task.WhenAll(twitchInsights, commanderRoot);
30+ // if (null != twitchInsights.Result) {
31+ // KnownBotListUsername = twitchInsights.Result;
32+ // }
33+ //
34+ // if (null != commanderRoot.Result) {
35+ // KnownBotListUserId = commanderRoot.Result;
36+ // }
37+ //
38+ // // The list is enormous, force garbage collection.
39+ // GC.Collect();
40+ // GC.WaitForPendingFinalizers();
41+ // await Task.Delay(TimeSpan.FromMinutes(10));
42+ // }
43+ // });
44+ //
45+ // /// <summary>
46+ // /// The cache of known bots.
47+ // /// </summary>
48+ // public static ImmutableHashSet<string>? KnownBotListUsername { get; set; }
49+ //
50+ // /// <summary>
51+ // /// The cache of known bots.
52+ // /// </summary>
53+ // public static ImmutableHashSet<string>? KnownBotListUserId { get; set; }
54+ //
55+ // /// <summary>
56+ // /// Determine if the rule is enabled in the configuration.
57+ // /// </summary>
58+ // /// <param name="config">The user's configuration.</param>
59+ // /// <returns>True if it should run, false otherwise.</returns>
60+ // public override bool ShouldRun(TwitchUserConfig config) {
61+ // return config is { Enabled: true, BanKnownBots: true };
62+ // }
63+ //
64+ // /// <summary>
65+ // /// Searches for and bans known bots when they enter the chat.
66+ // /// </summary>
67+ // /// <param name="user">The user.</param>
68+ // /// <param name="config">The user's configuration.</param>
69+ // /// <param name="botProxy">The twitch api authenticated as the bot user.</param>
70+ // /// <param name="db">The database.</param>
71+ // /// <param name="stoppingToken">The cancellation token.</param>
72+ // public override async Task Handle(User user, TwitchUserConfig config, ITwitchApiProxy botProxy,
73+ // INullinsideContext db, CancellationToken stoppingToken = new()) {
74+ // if (null == user.TwitchId) {
75+ // return;
76+ // }
77+ //
78+ // // TODO: SKIP MODS AND VIPS
79+ //
80+ // // Get the list of people in the chat.
81+ // List<Chatter>? chatters =
82+ // (await botProxy.GetChannelUsers(user.TwitchId, Constants.BotId, stoppingToken))?.ToList();
83+ // if (null == chatters || chatters.Count == 0) {
84+ // return;
85+ // }
86+ //
87+ // // Perform the comparison in the lock to prevent multithreading issues.
88+ // // The collection is extremely large so we do not want to make a copy of it.
89+ // var botsInChatInsights = new List<Chatter>();
90+ // var botsInChatCommanderRoot = new List<Chatter>();
91+ // ImmutableHashSet<string>? knownBotUsernames = KnownBotListUsername;
92+ // ImmutableHashSet<string>? knownBotUserIds = KnownBotListUserId;
93+ //
94+ // if (null != knownBotUsernames) {
95+ // botsInChatInsights.AddRange(chatters.Where(k =>
96+ // knownBotUsernames.Contains(k.UserLogin.ToLowerInvariant())));
97+ // }
98+ //
99+ // if (null != knownBotUserIds) {
100+ // botsInChatCommanderRoot.AddRange(chatters.Where(k =>
101+ // knownBotUserIds.Contains(k.UserId.ToLowerInvariant())));
102+ // }
103+ //
104+ // // Remove the whitelisted bots
105+ // botsInChatInsights = botsInChatInsights
106+ // .Where(b => !Constants.WhitelistedBots.Contains(b.UserLogin.ToLowerInvariant())).ToList();
107+ // botsInChatCommanderRoot = botsInChatCommanderRoot
108+ // .Where(b => !Constants.WhitelistedBots.Contains(b.UserLogin.ToLowerInvariant())).ToList();
109+ //
110+ // // Ban them.
111+ // if (botsInChatInsights.Count != 0) {
112+ // await BanOnce(botProxy, db, user.TwitchId, botsInChatInsights.Select(b => (Id: b.UserId, Username: b.UserLogin)),
113+ // "[Bot] Username on Known Bot List", stoppingToken);
114+ // }
115+ //
116+ // if (botsInChatCommanderRoot.Count != 0) {
117+ // await BanOnce(botProxy, db, user.TwitchId,
118+ // botsInChatCommanderRoot.Select(b => (Id: b.UserId, Username: b.UserLogin)),
119+ // "[Bot] Username on Known Bot List", stoppingToken);
120+ // }
121+ // }
122+ //
123+ // /// <summary>
124+ // /// Gets the list of all known bots.
125+ // /// </summary>
126+ // /// <returns>The list of bots if successful, null otherwise.</returns>
127+ // private static async Task<ImmutableHashSet<string>?> GetTwitchInsightsBots() {
128+ // var stopwatch = new Stopwatch();
129+ // stopwatch.Start();
130+ // // Reach out to the api and find out what bots are online.
131+ // using var http = new HttpClient();
132+ // HttpResponseMessage response = await http.GetAsync("https://api.twitchinsights.net/v1/bots/all");
133+ // if (!response.IsSuccessStatusCode) {
134+ // return null;
135+ // }
136+ //
137+ // byte[]? content = await response.Content.ReadAsByteArrayAsync();
138+ // string? jsonString = Encoding.UTF8.GetString(content);
139+ // var liveBotsResponse = JsonConvert.DeserializeObject<TwitchInsightsLiveBotsResponse>(jsonString);
140+ // if (null == liveBotsResponse) {
141+ // return null;
142+ // }
143+ //
144+ // ImmutableHashSet<string> allBots = liveBotsResponse.bots
145+ // .Where(s => !string.IsNullOrWhiteSpace(s[0].ToString()))
146+ // #pragma warning disable 8602
147+ // .Select(s => s[0].ToString().ToLowerInvariant())
148+ // #pragma warning restore 8602
149+ // .ToImmutableHashSet();
150+ //
151+ // foreach (List<object>? list in liveBotsResponse.bots) {
152+ // list.Clear();
153+ // }
154+ //
155+ // liveBotsResponse.bots.Clear();
156+ // liveBotsResponse.bots = null;
157+ // liveBotsResponse = null;
158+ // content = null;
159+ // jsonString = null;
160+ // return allBots;
161+ // }
162+ //
163+ // /// <summary>
164+ // /// Gets the list of all known bots.
165+ // /// </summary>
166+ // /// <returns>The list of bots if successful, null otherwise.</returns>
167+ // private static async Task<ImmutableHashSet<string>?> GetCommanderRootBots() {
168+ // var stopwatch = new Stopwatch();
169+ // stopwatch.Start();
170+ // // Reach out to the api and find out what bots are online.
171+ // using var http = new HttpClient();
172+ // using HttpResponseMessage response =
173+ // await http.GetAsync("https://twitch-tools.rootonline.de/blocklist_manager.php?preset=known_bot_users");
174+ // if (!response.IsSuccessStatusCode) {
175+ // return null;
176+ // }
177+ //
178+ // byte[]? content = await response.Content.ReadAsByteArrayAsync();
179+ // string? jsonString = Encoding.UTF8.GetString(content);
180+ // var liveBotsResponse = JsonConvert.DeserializeObject<List<string>>(jsonString);
181+ // if (null == liveBotsResponse) {
182+ // return null;
183+ // }
184+ //
185+ // ImmutableHashSet<string> allBots = liveBotsResponse
186+ // #pragma warning disable 8602
187+ // .Select(s => s.ToLowerInvariant())
188+ // #pragma warning restore 8602
189+ // .ToImmutableHashSet();
190+ //
191+ // liveBotsResponse.Clear();
192+ // liveBotsResponse = null;
193+ // liveBotsResponse = null;
194+ // content = null;
195+ // jsonString = null;
196+ // return allBots;
197+ // }
198+ // }
0 commit comments