diff --git a/Clients/CirrusCiClient/CirrusCi.cs b/Clients/CirrusCiClient/CirrusCi.cs index ee209978..5db19d60 100644 --- a/Clients/CirrusCiClient/CirrusCi.cs +++ b/Clients/CirrusCiClient/CirrusCi.cs @@ -23,8 +23,7 @@ public static class CirrusCi static CirrusCi() { var collection = new ServiceCollection(); - collection.AddClient(ExecutionStrategy.CacheAndNetwork) - .ConfigureHttpClient(c => c.BaseAddress = new("https://api.cirrus-ci.com/graphql")); + collection.AddClient(ExecutionStrategy.CacheAndNetwork).ConfigureHttpClient(c => c.BaseAddress = new("https://api.cirrus-ci.com/graphql")); ServiceProvider = collection.BuildServiceProvider(); } diff --git a/Clients/CompatApiClient/ApiConfig.cs b/Clients/CompatApiClient/ApiConfig.cs index 8634ed6f..ae1465e6 100644 --- a/Clients/CompatApiClient/ApiConfig.cs +++ b/Clients/CompatApiClient/ApiConfig.cs @@ -90,8 +90,8 @@ public static class ApiConfig catch (Exception e) { Log.Fatal(e); - ReverseDirections = new Dictionary(); - ReverseReleaseTypes = new Dictionary(); + ReverseDirections = new(); + ReverseReleaseTypes = new(); } } } \ No newline at end of file diff --git a/Clients/CompatApiClient/Compression/CompressionMessageHandler.cs b/Clients/CompatApiClient/Compression/CompressionMessageHandler.cs index 8d0ca624..674474ea 100644 --- a/Clients/CompatApiClient/Compression/CompressionMessageHandler.cs +++ b/Clients/CompatApiClient/Compression/CompressionMessageHandler.cs @@ -31,8 +31,7 @@ public class CompressionMessageHandler : DelegatingHandler protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { if (isServer - && request.Content?.Headers.ContentEncoding != null - && request.Content.Headers.ContentEncoding.FirstOrDefault() is string serverEncoding + && request.Content?.Headers.ContentEncoding.FirstOrDefault() is string serverEncoding && Compressors.FirstOrDefault(c => c.EncodingType.Equals(serverEncoding, StringComparison.OrdinalIgnoreCase)) is ICompressor serverDecompressor) { request.Content = new DecompressedContent(request.Content, serverDecompressor); diff --git a/Clients/CompatApiClient/Formatters/CompatApiCommitHashConverter.cs b/Clients/CompatApiClient/Formatters/CompatApiCommitHashConverter.cs index a35ad42e..7663499e 100644 --- a/Clients/CompatApiClient/Formatters/CompatApiCommitHashConverter.cs +++ b/Clients/CompatApiClient/Formatters/CompatApiCommitHashConverter.cs @@ -8,16 +8,11 @@ public sealed class CompatApiCommitHashConverter : JsonConverter { public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonTokenType.Number - && !reader.HasValueSequence - && reader.ValueSpan.Length == 1 - && reader.ValueSpan[0] == (byte)'0') - { - _ = reader.GetInt32(); - return null; - } - - return reader.GetString(); + if (reader is not { TokenType: JsonTokenType.Number, HasValueSequence: false, ValueSpan: [(byte)'0'] }) + return reader.GetString(); + + _ = reader.GetInt32(); + return null; } public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) diff --git a/Clients/CompatApiClient/Formatters/NamingStyles.cs b/Clients/CompatApiClient/Formatters/NamingStyles.cs index 1af2110a..97d29da9 100644 --- a/Clients/CompatApiClient/Formatters/NamingStyles.cs +++ b/Clients/CompatApiClient/Formatters/NamingStyles.cs @@ -18,15 +18,8 @@ public static class NamingStyles return value; } - public static string Dashed(string value) - { - return Delimitied(value, '-'); - } - - public static string Underscore(string value) - { - return Delimitied(value, '_'); - } + public static string Dashed(string value) => Delimitied(value, '-'); + public static string Underscore(string value) => Delimitied(value, '_'); private static string Delimitied(string value, char separator) { diff --git a/Clients/CompatApiClient/Utils/Statistics.cs b/Clients/CompatApiClient/Utils/Statistics.cs index c9977138..75a7b771 100644 --- a/Clients/CompatApiClient/Utils/Statistics.cs +++ b/Clients/CompatApiClient/Utils/Statistics.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Numerics; namespace CompatApiClient.Utils; @@ -7,7 +8,7 @@ public static class Statistics { public static long Mean(this IEnumerable data) { - System.Numerics.BigInteger sum = 0; + BigInteger sum = 0; var itemCount = 0; foreach (var value in data) { @@ -22,12 +23,12 @@ public static class Statistics public static double StdDev(this IEnumerable data) { - System.Numerics.BigInteger σx = 0, σx2 = 0; + BigInteger σx = 0, σx2 = 0; var n = 0; foreach (var value in data) { σx += value; - σx2 += (System.Numerics.BigInteger)value * value; + σx2 += (BigInteger)value * value; n++; } if (n == 0) diff --git a/Clients/CompatApiClient/Utils/UriExtensions.cs b/Clients/CompatApiClient/Utils/UriExtensions.cs index bc54efde..54be0020 100644 --- a/Clients/CompatApiClient/Utils/UriExtensions.cs +++ b/Clients/CompatApiClient/Utils/UriExtensions.cs @@ -14,21 +14,15 @@ public static class UriExtensions public static NameValueCollection ParseQueryString(Uri uri) { if (!uri.IsAbsoluteUri) - uri = new Uri(FakeHost, uri); + uri = new(FakeHost, uri); return uri.ParseQueryString(); } public static string? GetQueryParameter(this Uri uri, string name) - { - var parameters = ParseQueryString(uri); - return parameters[name]; - } + => ParseQueryString(uri)[name]; public static Uri AddQueryParameter(this Uri uri, string name, string value) - { - var queryValue = WebUtility.UrlEncode(name) + "=" + WebUtility.UrlEncode(value); - return AddQueryValue(uri, queryValue); - } + => AddQueryValue(uri, WebUtility.UrlEncode(name) + "=" + WebUtility.UrlEncode(value)); public static Uri AddQueryParameters(Uri uri, IEnumerable> parameters) { @@ -105,16 +99,16 @@ public static class UriExtensions if (isAbsolute) { var builder = new UriBuilder(uri) { Query = value }; - return new Uri(builder.ToString()); + return new(builder.ToString()); } else { var startWithSlash = uri.OriginalString.StartsWith("/"); - uri = new Uri(FakeHost, uri); + uri = new(FakeHost, uri); var builder = new UriBuilder(uri) { Query = value }; var additionalStrip = startWithSlash ? 0 : 1; var newUri = builder.ToString()[(FakeHost.OriginalString.Length + additionalStrip)..]; - return new Uri(newUri, UriKind.Relative); + return new(newUri, UriKind.Relative); } } } \ No newline at end of file diff --git a/Clients/CompatApiClient/Utils/Utils.cs b/Clients/CompatApiClient/Utils/Utils.cs index 8d17f9a0..21dd1336 100644 --- a/Clients/CompatApiClient/Utils/Utils.cs +++ b/Clients/CompatApiClient/Utils/Utils.cs @@ -50,13 +50,11 @@ public static class Utils => AsStorageUnit((long)bytes); public static string AsStorageUnit(this long bytes) - { - if (bytes < UnderKB) - return $"{bytes} byte{(bytes == 1 ? "" : "s")}"; - if (bytes < UnderMB) - return $"{bytes / 1024.0:0.##} KB"; - if (bytes < UnderGB) - return $"{bytes / 1024.0 / 1024:0.##} MB"; - return $"{bytes / 1024.0 / 1024 / 1024:0.##} GB"; - } + => bytes switch + { + < UnderKB => $"{bytes} byte{(bytes == 1 ? "" : "s")}", + < UnderMB => $"{bytes / 1024.0:0.##} KB", + < UnderGB => $"{bytes / (1024.0 * 1024):0.##} MB", + _ => $"{bytes / (1024.0 * 1024 * 1024):0.##} GB" + }; } \ No newline at end of file diff --git a/Clients/GithubClient/Client.cs b/Clients/GithubClient/Client.cs index c39b5207..6aa80ab4 100644 --- a/Clients/GithubClient/Client.cs +++ b/Clients/GithubClient/Client.cs @@ -4,12 +4,13 @@ using System.Threading; using System.Threading.Tasks; using CompatApiClient; using Microsoft.Extensions.Caching.Memory; +using Octokit; namespace GithubClient; public class Client { - private readonly Octokit.GitHubClient client; + private readonly GitHubClient client; private static readonly TimeSpan PrStatusCacheTime = TimeSpan.FromMinutes(3); private static readonly TimeSpan IssueStatusCacheTime = TimeSpan.FromMinutes(30); @@ -22,26 +23,22 @@ public class Client public Client(string? githubToken) { - client = new Octokit.GitHubClient(new Octokit.ProductHeaderValue(ApiConfig.ProductName, ApiConfig.ProductVersion)); - if (!string.IsNullOrEmpty(githubToken)) - { - client.Credentials = new Octokit.Credentials(githubToken); - } + client = new(new ProductHeaderValue(ApiConfig.ProductName, ApiConfig.ProductVersion)); + if (githubToken is {Length: >0}) + client.Credentials = new(githubToken); } - public async Task GetPrInfoAsync(int pr, CancellationToken cancellationToken) + public async Task GetPrInfoAsync(int pr, CancellationToken cancellationToken) { - if (StatusesCache.TryGetValue(pr, out Octokit.PullRequest? result)) + if (StatusesCache.TryGetValue(pr, out PullRequest? result)) { - ApiConfig.Log.Debug($"Returned {nameof(Octokit.PullRequest)} for {pr} from cache"); + ApiConfig.Log.Debug($"Returned {nameof(PullRequest)} for {pr} from cache"); return result; } try { - var request = client.PullRequest.Get("RPCS3", "rpcs3", pr); - request.Wait(cancellationToken); - result = (await request.ConfigureAwait(false)); + result = await client.PullRequest.Get("RPCS3", "rpcs3", pr).WaitAsync(cancellationToken).ConfigureAwait(false); UpdateRateLimitStats(); } catch (Exception e) @@ -50,61 +47,53 @@ public class Client } if (result == null) { - ApiConfig.Log.Debug($"Failed to get {nameof(Octokit.PullRequest)}, returning empty result"); + ApiConfig.Log.Debug($"Failed to get {nameof(PullRequest)}, returning empty result"); return new(pr); } StatusesCache.Set(pr, result, PrStatusCacheTime); - ApiConfig.Log.Debug($"Cached {nameof(Octokit.PullRequest)} for {pr} for {PrStatusCacheTime}"); + ApiConfig.Log.Debug($"Cached {nameof(PullRequest)} for {pr} for {PrStatusCacheTime}"); return result; } - public async Task GetIssueInfoAsync(int issue, CancellationToken cancellationToken) + public async Task GetIssueInfoAsync(int issue, CancellationToken cancellationToken) { - if (IssuesCache.TryGetValue(issue, out Octokit.Issue? result)) + if (IssuesCache.TryGetValue(issue, out Issue? result)) { - ApiConfig.Log.Debug($"Returned {nameof(Octokit.Issue)} for {issue} from cache"); + ApiConfig.Log.Debug($"Returned {nameof(Issue)} for {issue} from cache"); return result; } try { - var request = client.Issue.Get("RPCS3", "rpcs3", issue); - request.Wait(cancellationToken); - result = (await request.ConfigureAwait(false)); + result = await client.Issue.Get("RPCS3", "rpcs3", issue).WaitAsync(cancellationToken).ConfigureAwait(false); UpdateRateLimitStats(); + IssuesCache.Set(issue, result, IssueStatusCacheTime); + ApiConfig.Log.Debug($"Cached {nameof(Issue)} for {issue} for {IssueStatusCacheTime}"); + return result; } catch (Exception e) { ApiConfig.Log.Error(e); } - if (result == null) - { - ApiConfig.Log.Debug($"Failed to get {nameof(Octokit.Issue)}, returning empty result"); - return new() { }; - } - - IssuesCache.Set(issue, result, IssueStatusCacheTime); - ApiConfig.Log.Debug($"Cached {nameof(Octokit.Issue)} for {issue} for {IssueStatusCacheTime}"); - return result; + ApiConfig.Log.Debug($"Failed to get {nameof(Issue)}, returning empty result"); + return new(); } - public Task?> GetOpenPrsAsync(CancellationToken cancellationToken) => GetPrsWithStatusAsync(new Octokit.PullRequestRequest + public Task?> GetOpenPrsAsync(CancellationToken cancellationToken) + => GetPrsWithStatusAsync(new() { State = ItemStateFilter.Open }, cancellationToken); + + public Task?> GetClosedPrsAsync(CancellationToken cancellationToken) => GetPrsWithStatusAsync(new() { - State = Octokit.ItemStateFilter.Open + State = ItemStateFilter.Closed, + SortProperty = PullRequestSort.Updated, + SortDirection = SortDirection.Descending }, cancellationToken); - public Task?> GetClosedPrsAsync(CancellationToken cancellationToken) => GetPrsWithStatusAsync(new Octokit.PullRequestRequest + private async Task?> GetPrsWithStatusAsync(PullRequestRequest filter, CancellationToken cancellationToken) { - State = Octokit.ItemStateFilter.Closed, - SortProperty = Octokit.PullRequestSort.Updated, - SortDirection = Octokit.SortDirection.Descending - }, cancellationToken); - - private async Task?> GetPrsWithStatusAsync(Octokit.PullRequestRequest filter, CancellationToken cancellationToken) - { - var statusURI = "https://api.github.com/repos/RPCS3/rpcs3/pulls?state=" + filter.ToString(); - if (StatusesCache.TryGetValue(statusURI, out IReadOnlyList? result)) + var statusUri = "https://api.github.com/repos/RPCS3/rpcs3/pulls?state=" + filter; + if (StatusesCache.TryGetValue(statusUri, out IReadOnlyList? result)) { ApiConfig.Log.Debug("Returned list of opened PRs from cache"); return result; @@ -112,23 +101,17 @@ public class Client try { - var request = client.PullRequest.GetAllForRepository("RPCS3", "rpcs3", filter); - request.Wait(cancellationToken); - - result = (await request.ConfigureAwait(false)); + result = await client.PullRequest.GetAllForRepository("RPCS3", "rpcs3", filter).WaitAsync(cancellationToken).ConfigureAwait(false); UpdateRateLimitStats(); + StatusesCache.Set(statusUri, result, PrStatusCacheTime); + foreach (var prInfo in result) + StatusesCache.Set(prInfo.Number, prInfo, PrStatusCacheTime); + ApiConfig.Log.Debug($"Cached list of open PRs for {PrStatusCacheTime}"); } catch (Exception e) { ApiConfig.Log.Error(e); } - if (result != null) - { - StatusesCache.Set(statusURI, result, PrStatusCacheTime); - foreach (var prInfo in result) - StatusesCache.Set(prInfo.Number, prInfo, PrStatusCacheTime); - ApiConfig.Log.Debug($"Cached list of open PRs for {PrStatusCacheTime}"); - } return result; } @@ -136,16 +119,12 @@ public class Client { var apiInfo = client.GetLastApiInfo(); if (apiInfo == null) - { return; - } RateLimit = apiInfo.RateLimit.Limit; RateLimitRemaining = apiInfo.RateLimit.Remaining; RateLimitResetTime = DateTimeOffset.FromUnixTimeSeconds(apiInfo.RateLimit.ResetAsUtcEpochSeconds).UtcDateTime; - if (RateLimitRemaining < 10) ApiConfig.Log.Warn($"Github rate limit is low: {RateLimitRemaining} out of {RateLimit}, will be reset on {RateLimitResetTime:u}"); } - } \ No newline at end of file diff --git a/Clients/IrdLibraryClient/IrdClient.cs b/Clients/IrdLibraryClient/IrdClient.cs index 09d3a7a9..01377f9f 100644 --- a/Clients/IrdLibraryClient/IrdClient.cs +++ b/Clients/IrdLibraryClient/IrdClient.cs @@ -29,7 +29,7 @@ public class IrdClient public IrdClient() { client = HttpClientFactory.Create(new CompressionMessageHandler()); - jsonOptions = new JsonSerializerOptions + jsonOptions = new() { PropertyNamingPolicy = SpecialJsonNamingPolicy.SnakeCase, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, @@ -209,9 +209,8 @@ public class IrdClient var idx = html.LastIndexOf("", StringComparison.Ordinal); var result = html[(idx + 7)..].Trim(); - if (string.IsNullOrEmpty(result)) - return null; - - return result; + if (result is {Length: >0}) + return result; + return null; } } \ No newline at end of file diff --git a/Clients/PsnClient/PsnClient.cs b/Clients/PsnClient/PsnClient.cs index 0bad2f16..1b77c717 100644 --- a/Clients/PsnClient/PsnClient.cs +++ b/Clients/PsnClient/PsnClient.cs @@ -38,8 +38,10 @@ public class Client "pl-PL", "pt-BR", "pt-PT", "ru-RU", "ru-UA", "sv-SE", "tr-TR", "zh-Hans-CN", "zh-Hans-HK", "zh-Hant-HK", "zh-Hant-TW", }; // Dest=87;ImageVersion=0001091d;SystemSoftwareVersion=4.8500;CDN=http://duk01.ps3.update.playstation.net/update/ps3/image/uk/2019_0828_c975768e5d70e105a72656f498cc9be9/PS3UPDAT.PUP;CDN_Timeout=30; - private static readonly Regex FwVersionInfo = new(@"Dest=(?\d+);ImageVersion=(?[0-9a-f]+);SystemSoftwareVersion=(?\d+\.\d+);CDN=(?http[^;]+);CDN_Timeout=(?\d+)", - RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.Singleline | RegexOptions.IgnoreCase); + private static readonly Regex FwVersionInfo = new( + @"Dest=(?\d+);ImageVersion=(?[0-9a-f]+);SystemSoftwareVersion=(?\d+\.\d+);CDN=(?http[^;]+);CDN_Timeout=(?\d+)", + RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.Singleline | RegexOptions.IgnoreCase + ); // directly from vsh.self private static readonly string[] KnownFwLocales = { "jp", "us", "eu", "kr", "uk", "mx", "au", "sa", "tw", "ru", "cn", "br", }; @@ -47,19 +49,19 @@ public class Client public Client() { client = HttpClientFactory.Create(new CustomTlsCertificatesHandler(), new CompressionMessageHandler()); - dashedJson = new JsonSerializerOptions + dashedJson = new() { PropertyNamingPolicy = SpecialJsonNamingPolicy.Dashed, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, IncludeFields = true, }; - snakeJson = new JsonSerializerOptions + snakeJson = new() { PropertyNamingPolicy = SpecialJsonNamingPolicy.SnakeCase, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, IncludeFields = true, }; - xmlFormatters = new MediaTypeFormatterCollection(new[] {new XmlMediaTypeFormatter {UseXmlSerializer = true}}); + xmlFormatters = new(new[] {new XmlMediaTypeFormatter {UseXmlSerializer = true}}); } public static string[] GetLocales() => KnownStoreLocales; // Sony removed the ability to get the full store list, now relying on geolocation service instead @@ -101,7 +103,6 @@ public class Client { message.Headers.Add("Cookie", sessionCookies); response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false); - await response.Content.LoadIntoBufferAsync().ConfigureAwait(false); var tries = 0; while (response.StatusCode == HttpStatusCode.Redirect && tries < 10 && !cancellationToken.IsCancellationRequested) @@ -116,7 +117,7 @@ public class Client tries++; } if (response.StatusCode == HttpStatusCode.Redirect) - return new List(0); + return new(0); } using (response) @@ -127,7 +128,7 @@ public class Client var matches = ContainerIdLink.Matches(html); var result = new List(); foreach (Match m in matches) - if (m.Groups["id"].Value is string id && !string.IsNullOrEmpty(id)) + if (m.Groups["id"].Value is {Length: >0} id) result.Add(id); return result; } @@ -344,7 +345,7 @@ public class Client allVersions = allVersions.OrderByDescending(fwi => fwi.Version).ToList(); if (allVersions.Count == 0) - return new List(0); + return new(0); var maxFw = allVersions.First(); var result = allVersions.Where(fwi => fwi.Version == maxFw.Version).ToList(); @@ -372,7 +373,7 @@ public class Client { ["country_code"] = country, ["language_code"] = language, - }!) + }) }; using (authMessage) using (response = await client.SendAsync(authMessage, cancellationToken).ConfigureAwait(false)) @@ -418,7 +419,7 @@ public class Client if (string.IsNullOrEmpty(data)) return null; - if (FwVersionInfo.Match(data) is not Match m || !m.Success) + if (FwVersionInfo.Match(data) is not { Success: true } m) return null; var ver = m.Groups["version"].Value; @@ -429,7 +430,7 @@ public class Client else ver = ver[..4] + "." + ver[4..].TrimEnd('0'); //4.851 -> 4.85.1 } - return new FirmwareInfo { Version = ver, DownloadUrl = m.Groups["url"].Value, Locale = fwLocale}; + return new() { Version = ver, DownloadUrl = m.Groups["url"].Value, Locale = fwLocale}; } catch (Exception e) diff --git a/Clients/YandexDiskClient/Client.cs b/Clients/YandexDiskClient/Client.cs index a5277841..c2bcbfd8 100644 --- a/Clients/YandexDiskClient/Client.cs +++ b/Clients/YandexDiskClient/Client.cs @@ -21,7 +21,7 @@ public sealed class Client public Client() { client = HttpClientFactory.Create(new CompressionMessageHandler()); - jsonOptions = new JsonSerializerOptions + jsonOptions = new() { PropertyNamingPolicy = SpecialJsonNamingPolicy.SnakeCase, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, @@ -36,7 +36,7 @@ public sealed class Client { try { - var uri = new Uri($"https://cloud-api.yandex.net/v1/disk/public/resources").SetQueryParameters( + var uri = new Uri("https://cloud-api.yandex.net/v1/disk/public/resources").SetQueryParameters( ("public_key", publicUri.ToString()), ("fields", "size,name,file") ); diff --git a/CompatBot/Commands/Attributes/LimitedToSpamChannel.cs b/CompatBot/Commands/Attributes/LimitedToSpamChannel.cs index ef9ae947..b181830c 100644 --- a/CompatBot/Commands/Attributes/LimitedToSpamChannel.cs +++ b/CompatBot/Commands/Attributes/LimitedToSpamChannel.cs @@ -23,8 +23,7 @@ internal class LimitedToSpamChannel: CheckBaseAttribute try { var msgList = await ctx.Channel.GetMessagesCachedAsync(10).ConfigureAwait(false); - if (msgList.Any(m => m.Author.IsCurrent - && m.Content is string s + if (msgList.Any(m => m is {Author.IsCurrent: true, Content: {Length: >0} s } && s.Contains(ctx.Command.QualifiedName, StringComparison.OrdinalIgnoreCase))) { await ctx.ReactWithAsync(Config.Reactions.Failure).ConfigureAwait(false); diff --git a/CompatBot/Commands/Attributes/RequiresBotModRole.cs b/CompatBot/Commands/Attributes/RequiresBotModRole.cs index d51ba4ba..4504aff3 100644 --- a/CompatBot/Commands/Attributes/RequiresBotModRole.cs +++ b/CompatBot/Commands/Attributes/RequiresBotModRole.cs @@ -11,7 +11,5 @@ internal class RequiresBotModRole: CheckBaseAttributeWithReactions public RequiresBotModRole() : base(reactOnFailure: Config.Reactions.Denied) { } protected override Task IsAllowed(CommandContext ctx, bool help) - { - return Task.FromResult(ModProvider.IsMod(ctx.User.Id)); - } + => Task.FromResult(ModProvider.IsMod(ctx.User.Id)); } \ No newline at end of file diff --git a/CompatBot/Commands/Attributes/RequiresNotMedia.cs b/CompatBot/Commands/Attributes/RequiresNotMedia.cs index 150f7232..cfd3819f 100644 --- a/CompatBot/Commands/Attributes/RequiresNotMedia.cs +++ b/CompatBot/Commands/Attributes/RequiresNotMedia.cs @@ -9,7 +9,5 @@ namespace CompatBot.Commands.Attributes; internal class RequiresNotMedia: CheckBaseAttribute { public override Task ExecuteCheckAsync(CommandContext ctx, bool help) - { - return Task.FromResult(ctx.Channel.Name != "media"); - } + => Task.FromResult(ctx.Channel.Name != "media"); } \ No newline at end of file diff --git a/CompatBot/Commands/Attributes/RequiresSupporterRole.cs b/CompatBot/Commands/Attributes/RequiresSupporterRole.cs index 51c5e054..a23e474d 100644 --- a/CompatBot/Commands/Attributes/RequiresSupporterRole.cs +++ b/CompatBot/Commands/Attributes/RequiresSupporterRole.cs @@ -11,7 +11,5 @@ internal class RequiresSupporterRole: CheckBaseAttributeWithReactions public RequiresSupporterRole() : base(reactOnFailure: Config.Reactions.Denied) { } protected override Task IsAllowed(CommandContext ctx, bool help) - { - return Task.FromResult(ctx.User.IsWhitelisted(ctx.Client, ctx.Guild) || ctx.User.IsSupporter(ctx.Client, ctx.Guild)); - } + => Task.FromResult(ctx.User.IsWhitelisted(ctx.Client, ctx.Guild) || ctx.User.IsSupporter(ctx.Client, ctx.Guild)); } \ No newline at end of file diff --git a/CompatBot/Commands/Attributes/RequiresWhitelistedRole.cs b/CompatBot/Commands/Attributes/RequiresWhitelistedRole.cs index c9e81aa9..da30710c 100644 --- a/CompatBot/Commands/Attributes/RequiresWhitelistedRole.cs +++ b/CompatBot/Commands/Attributes/RequiresWhitelistedRole.cs @@ -11,7 +11,5 @@ internal class RequiresWhitelistedRole: CheckBaseAttributeWithReactions public RequiresWhitelistedRole() : base(reactOnFailure: Config.Reactions.Denied) { } protected override Task IsAllowed(CommandContext ctx, bool help) - { - return Task.FromResult(ctx.User.IsWhitelisted(ctx.Client, ctx.Guild)); - } + => Task.FromResult(ctx.User.IsWhitelisted(ctx.Client, ctx.Guild)); } \ No newline at end of file diff --git a/CompatBot/Commands/Attributes/TriggersTyping.cs b/CompatBot/Commands/Attributes/TriggersTyping.cs index a6cf3cbb..18953609 100644 --- a/CompatBot/Commands/Attributes/TriggersTyping.cs +++ b/CompatBot/Commands/Attributes/TriggersTyping.cs @@ -9,7 +9,5 @@ internal class TriggersTyping: Attribute public bool InDmOnly { get; set; } public bool ExecuteCheck(CommandContext ctx) - { - return !InDmOnly || ctx.Channel.IsPrivate; - } + => !InDmOnly || ctx.Channel.IsPrivate; } \ No newline at end of file diff --git a/CompatBot/Commands/BaseApplicationCommandModuleCustom.cs b/CompatBot/Commands/BaseApplicationCommandModuleCustom.cs index b902ab66..836efb5b 100644 --- a/CompatBot/Commands/BaseApplicationCommandModuleCustom.cs +++ b/CompatBot/Commands/BaseApplicationCommandModuleCustom.cs @@ -15,8 +15,7 @@ internal class BaseApplicationCommandModuleCustom : ApplicationCommandModule public override async Task BeforeSlashExecutionAsync(InteractionContext ctx) { executionStart = DateTimeOffset.UtcNow; - - if (ctx.Channel.Name == "media" && ctx.Interaction is { Type: InteractionType.ApplicationCommand, Data.Name: not ("warn" or "report") }) + if (ctx is {Channel.Name: "media", Interaction: { Type: InteractionType.ApplicationCommand, Data.Name: not ("warn" or "report") } }) { //todo: look what's available in data Config.Log.Info($"Ignoring slash command from {ctx.User.Username} (<@{ctx.User.Id}>) in #media: {ctx.Interaction.Data}"); diff --git a/CompatBot/Commands/BotMath.cs b/CompatBot/Commands/BotMath.cs index d38dbd2e..cb77d0da 100644 --- a/CompatBot/Commands/BotMath.cs +++ b/CompatBot/Commands/BotMath.cs @@ -29,7 +29,10 @@ internal sealed class BotMath : BaseCommandModuleCustom return; } - var result = @"Something went wrong ¯\\_(ツ)\_/¯" + "\nMath is hard, yo"; + var result = """ + Something went wrong ¯\\\_(ツ)\_/¯ + Math is hard, yo + """; try { var expr = new Expression(expression); @@ -45,5 +48,5 @@ internal sealed class BotMath : BaseCommandModuleCustom [Command("help"), LimitedToSpamChannel, Cooldown(1, 5, CooldownBucketType.Channel)] [Description("General math expression help, or description of specific math word")] public Task Help(CommandContext ctx) - => ctx.Channel.SendMessageAsync("Help for all the features and built-in constants and functions could be found at "); + => ctx.Channel.SendMessageAsync("Help for all the features and built-in constants and functions could be found at [mXparser website]()"); } \ No newline at end of file diff --git a/CompatBot/Commands/BotStats.cs b/CompatBot/Commands/BotStats.cs index 30be1731..12322d07 100644 --- a/CompatBot/Commands/BotStats.cs +++ b/CompatBot/Commands/BotStats.cs @@ -37,19 +37,33 @@ internal sealed class BotStats: BaseCommandModuleCustom var osInfo = RuntimeInformation.OSDescription; if (Environment.OSVersion.Platform is PlatformID.Unix or PlatformID.MacOSX) osInfo = RuntimeInformation.RuntimeIdentifier; + var gcMemInfo = GC.GetGCMemoryInfo(); + var apiMsm = ApiConfig.MemoryStreamManager; + var botMsm = Config.MemoryStreamManager; + var apiLpsTotal = apiMsm.LargePoolInUseSize + apiMsm.LargePoolFreeSize; + var apiSpsTotal = apiMsm.SmallPoolInUseSize + apiMsm.SmallPoolFreeSize; + var botLpsTotal = botMsm.LargePoolInUseSize + botMsm.LargePoolFreeSize; + var botSpsTotal = botMsm.SmallPoolInUseSize + botMsm.SmallPoolFreeSize; embed.AddField("API Tokens", GetConfiguredApiStats(), true) - .AddField("Memory Usage", $"GC: {GC.GetGCMemoryInfo().HeapSizeBytes.AsStorageUnit()}/{GC.GetGCMemoryInfo().TotalAvailableMemoryBytes.AsStorageUnit()}\n" + - $"API pools: L: {ApiConfig.MemoryStreamManager.LargePoolInUseSize.AsStorageUnit()}/{(ApiConfig.MemoryStreamManager.LargePoolInUseSize + ApiConfig.MemoryStreamManager.LargePoolFreeSize).AsStorageUnit()}" + - $" S: {ApiConfig.MemoryStreamManager.SmallPoolInUseSize.AsStorageUnit()}/{(ApiConfig.MemoryStreamManager.SmallPoolInUseSize + ApiConfig.MemoryStreamManager.SmallPoolFreeSize).AsStorageUnit()}\n" + - $"Bot pools: L: {Config.MemoryStreamManager.LargePoolInUseSize.AsStorageUnit()}/{(Config.MemoryStreamManager.LargePoolInUseSize + Config.MemoryStreamManager.LargePoolFreeSize).AsStorageUnit()}" + - $" S: {Config.MemoryStreamManager.SmallPoolInUseSize.AsStorageUnit()}/{(Config.MemoryStreamManager.SmallPoolInUseSize + Config.MemoryStreamManager.SmallPoolFreeSize).AsStorageUnit()}", true) - .AddField("GitHub Rate Limit", $"{GithubClient.Client.RateLimitRemaining} out of {GithubClient.Client.RateLimit} calls available\nReset in {(GithubClient.Client.RateLimitResetTime - DateTime.UtcNow).AsShortTimespan()}", true) - .AddField(".NET Info", $"{RuntimeInformation.FrameworkDescription}\n" + - $"{(System.Runtime.GCSettings.IsServerGC ? "Server" : "Workstation")} GC Mode", true) - .AddField("Runtime Info", $"Confinement: {SandboxDetector.Detect()}\n" + - $"OS: {osInfo}\n" + - $"CPUs: {Environment.ProcessorCount}\n" + - $"Time zones: {TimeParser.TimeZoneMap.Count} out of {TimeParser.TimeZoneAcronyms.Count} resolved, {TimeZoneInfo.GetSystemTimeZones().Count} total", true); + .AddField("Memory Usage", $""" + GC: {gcMemInfo.HeapSizeBytes.AsStorageUnit()}/{gcMemInfo.TotalAvailableMemoryBytes.AsStorageUnit()} + API pools: L: {apiMsm.LargePoolInUseSize.AsStorageUnit()}/{apiLpsTotal.AsStorageUnit()} S: {apiMsm.SmallPoolInUseSize.AsStorageUnit()}/{apiSpsTotal.AsStorageUnit()} + Bot pools: L: {botMsm.LargePoolInUseSize.AsStorageUnit()}/{botLpsTotal.AsStorageUnit()} S: {botMsm.SmallPoolInUseSize.AsStorageUnit()}/{botSpsTotal.AsStorageUnit()} + """, true) + .AddField("GitHub Rate Limit", $""" + {GithubClient.Client.RateLimitRemaining} out of {GithubClient.Client.RateLimit} calls available + Reset in {(GithubClient.Client.RateLimitResetTime - DateTime.UtcNow).AsShortTimespan()} + """, true) + .AddField(".NET Info", $""" + {RuntimeInformation.FrameworkDescription} + {(System.Runtime.GCSettings.IsServerGC ? "Server" : "Workstation")} GC Mode + """, true) + .AddField("Runtime Info", $""" + Confinement: {SandboxDetector.Detect()} + OS: {osInfo} + CPUs: {Environment.ProcessorCount} + Time zones: {TimeParser.TimeZoneMap.Count} out of {TimeParser.TimeZoneAcronyms.Count} resolved, {TimeZoneInfo.GetSystemTimeZones().Count} total + """, true); AppendPiracyStats(embed); AppendCmdStats(embed); AppendExplainStats(embed); @@ -70,16 +84,13 @@ internal sealed class BotStats: BaseCommandModuleCustom public Task Hardware(CommandContext ctx, [Description("Desired period in days, default is 30")] int period = 30) => Commands.Hardware.ShowStats(ctx, period); private static string GetConfiguredApiStats() - { - return new StringBuilder() - .Append(GoogleDriveHandler.ValidateCredentials() ? "✅" : "❌").AppendLine(" Google Drive") - .Append(string.IsNullOrEmpty(Config.AzureDevOpsToken) ? "❌" : "✅").AppendLine(" Azure DevOps") - .Append(string.IsNullOrEmpty(Config.AzureComputerVisionKey) ? "❌" : "✅").AppendLine(" Computer Vision") - .Append(string.IsNullOrEmpty(Config.AzureAppInsightsConnectionString) ? "❌" : "✅").AppendLine(" AppInsights") - .Append(string.IsNullOrEmpty(Config.GithubToken) ? "❌" : "✅").AppendLine(" Github") - .ToString() - .Trim(); - } + => $""" + {(GoogleDriveHandler.ValidateCredentials() ? "✅" : "❌")} Google Drive + {(string.IsNullOrEmpty(Config.AzureDevOpsToken) ? "❌" : "✅")} Azure DevOps + {(string.IsNullOrEmpty(Config.AzureComputerVisionKey) ? "❌" : "✅")} Computer Vision + {(string.IsNullOrEmpty(Config.AzureAppInsightsConnectionString) ? "❌" : "✅")} AppInsights + {(string.IsNullOrEmpty(Config.GithubToken) ? "❌" : "✅")} GitHub + """; private static void AppendPiracyStats(DiscordEmbedBuilder embed) { @@ -228,11 +239,11 @@ internal sealed class BotStats: BaseCommandModuleCustom var totalFuncCount = db.SyscallInfo.AsNoTracking().Select(sci => sci.Function).Distinct().Count(); var fwCallCount = totalFuncCount - syscallCount; var gameCount = db.SyscallToProductMap.AsNoTracking().Select(m => m.ProductId).Distinct().Count(); - embed.AddField("SceCall Stats", - $"Tracked game IDs: {gameCount}\n" + - $"Tracked syscalls: {syscallCount} function{(syscallCount == 1 ? "" : "s")}\n" + - $"Tracked fw calls: {fwCallCount} function{(fwCallCount == 1 ? "" : "s")}\n", - true); + embed.AddField("SceCall Stats", $""" + Tracked game IDs: {gameCount} + Tracked syscalls: {syscallCount} function{(syscallCount == 1 ? "" : "s")} + Tracked fw calls: {fwCallCount} function{(fwCallCount == 1 ? "" : "s")} + """, true); } catch (Exception e) { @@ -258,15 +269,12 @@ internal sealed class BotStats: BaseCommandModuleCustom .OrderByDescending(s => s.count) .FirstOrDefault(); - var cpuInfo = ""; - if (cpu is not null) - cpuInfo = $"\nPopular CPU: {cpu.maker} {cpu.name} ({cpu.count*100.0/monthCount:0.##}%)"; - embed.AddField("Hardware Stats", - $"Total: {totalCount} system{(totalCount == 1 ? "" : "s")}\n" + - $"Last 30 days: {monthCount} system{(monthCount == 1 ? "" : "s")}" + - cpuInfo, - true); - + var cpuInfo = cpu is null ? "" : $"Popular CPU: {cpu.maker} {cpu.name} ({cpu.count * 100.0 / monthCount:0.##}%)"; + embed.AddField("Hardware Stats", $""" + Total: {totalCount} system{(totalCount == 1 ? "" : "s")} + Last 30 days: {monthCount} system{(monthCount == 1 ? "" : "s")} + {cpuInfo} + """.TrimEnd(), true); } catch (Exception e) { diff --git a/CompatBot/Commands/CommandsManagement.cs b/CompatBot/Commands/CommandsManagement.cs index c79fb168..133c9183 100644 --- a/CompatBot/Commands/CommandsManagement.cs +++ b/CompatBot/Commands/CommandsManagement.cs @@ -22,7 +22,10 @@ public sealed class CommandsManagement : BaseCommandModule var list = DisabledCommandsProvider.Get(); if (list.Count > 0) { - var result = new StringBuilder("Currently disabled commands:").AppendLine().AppendLine("```"); + var result = new StringBuilder(""" + Currently disabled commands: + ``` + """); foreach (var cmd in list) result.AppendLine(cmd); await ctx.SendAutosplitMessageAsync(result.Append("```")).ConfigureAwait(false); diff --git a/CompatBot/Commands/CompatList.cs b/CompatBot/Commands/CompatList.cs index f17d2a2a..70eefaeb 100644 --- a/CompatBot/Commands/CompatList.cs +++ b/CompatBot/Commands/CompatList.cs @@ -41,7 +41,10 @@ internal sealed class CompatList : BaseCommandModuleCustom private const string Rpcs3UpdateStateKey = "Rpcs3UpdateState"; private const string Rpcs3UpdateBuildKey = "Rpcs3UpdateBuild"; private static UpdateInfo? cachedUpdateInfo; - private static readonly Regex UpdateVersionRegex = new(@"v(?\d+\.\d+\.\d+)-(?\d+)-(?[0-9a-f]+)\b", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture); + private static readonly Regex UpdateVersionRegex = new( + @"v(?\d+\.\d+\.\d+)-(?\d+)-(?[0-9a-f]+)\b", + RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture + ); static CompatList() { @@ -153,7 +156,7 @@ internal sealed class CompatList : BaseCommandModuleCustom if (exactStatus) result.Append(" only"); result.Append(" games"); - if (scoreType == "critic" || scoreType == "user") + if (scoreType is "critic" or "user") result.Append($" according to {scoreType}s"); result.AppendLine(":"); foreach (var (title, score, _) in resultList) @@ -170,17 +173,12 @@ internal sealed class CompatList : BaseCommandModuleCustom public sealed class UpdatesCheck: BaseCommandModuleCustom { [GroupCommand] - public Task Latest(CommandContext ctx) - { - return CheckForRpcs3Updates(ctx.Client, ctx.Channel); - } + public Task Latest(CommandContext ctx) => CheckForRpcs3Updates(ctx.Client, ctx.Channel); [Command("since")] [Description("Show additional info about changes since specified update")] public Task Since(CommandContext ctx, [Description("Commit hash of the update, such as `46abe0f31`")] string commit) - { - return CheckForRpcs3Updates(ctx.Client, ctx.Channel, commit); - } + => CheckForRpcs3Updates(ctx.Client, ctx.Channel, commit); [Command("clear"), RequiresBotModRole] [Description("Clears update info cache that is used to post new build announcements")] @@ -345,7 +343,7 @@ internal sealed class CompatList : BaseCommandModuleCustom { var updateInfo = await Client.GetUpdateAsync(cancellationToken, mergedPr.MergeCommitSha).ConfigureAwait(false) ?? new UpdateInfo {ReturnCode = -1}; - if (updateInfo.ReturnCode == 0 || updateInfo.ReturnCode == 1) // latest or known build + if (updateInfo.ReturnCode is 0 or 1) // latest or known build { updateInfo.LatestBuild = updateInfo.CurrentBuild; updateInfo.CurrentBuild = null; @@ -503,7 +501,7 @@ internal sealed class CompatList : BaseCommandModuleCustom if (trimmedList.Count > 0) sortedList = trimmedList; - var searchTerm = request.Search ?? @"¯\_(ツ)_/¯"; + var searchTerm = request.Search ?? @"¯\\\_(ツ)\_/¯"; var searchHits = sortedList.Where(t => t.score > 0.5 || (t.info.Title?.StartsWith(searchTerm, StringComparison.InvariantCultureIgnoreCase) ?? false) || (t.info.AlternativeTitle?.StartsWith(searchTerm, StringComparison.InvariantCultureIgnoreCase) ?? false)); @@ -684,8 +682,6 @@ internal sealed class CompatList : BaseCommandModuleCustom ProductCode = productCode, Name = titleInfo.Title, }).ConfigureAwait(false)).Entity; - if (dbItem is null) - continue; dbItem.Name = titleInfo.Title; if (Enum.TryParse(titleInfo.Status, out CompatStatus status)) diff --git a/CompatBot/Commands/ContentFilters.cs b/CompatBot/Commands/ContentFilters.cs index e370b708..9e23b69d 100644 --- a/CompatBot/Commands/ContentFilters.cs +++ b/CompatBot/Commands/ContentFilters.cs @@ -406,10 +406,10 @@ internal sealed class ContentFilters: BaseCommandModuleCustom step1: // step 1: define trigger string var embed = FormatFilter(filter, errorMsg, 1) - .WithDescription( - "Any simple string that is used to flag potential content for a check using Validation regex.\n" + - "**Must** be sufficiently long to reduce the number of checks." - ); + .WithDescription(""" + Any simple string that is used to flag potential content for a check using Validation regex. + **Must** be sufficiently long to reduce the number of checks. + """); saveEdit.SetEnabled(filter.IsComplete()); var messageBuilder = new DiscordMessageBuilder() .WithContent("Please specify a new **trigger**") @@ -453,12 +453,12 @@ internal sealed class ContentFilters: BaseCommandModuleCustom step2: // step 2: context of the filter where it is applicable embed = FormatFilter(filter, errorMsg, 2) - .WithDescription( - "Context of the filter indicates where it is applicable.\n" + - $"**`C`** = **`{FilterContext.Chat}`** will apply it in filtering discord messages.\n" + - $"**`L`** = **`{FilterContext.Log}`** will apply it during log parsing.\n" + - "Reactions will toggle the context, text message will set the specified flags." - ); + .WithDescription($""" + Context of the filter indicates where it is applicable. + **`C`** = **`{FilterContext.Chat}`** will apply it in filtering discord messages. + **`L`** = **`{FilterContext.Log}`** will apply it during log parsing. + Reactions will toggle the context, text message will set the specified flags. + """); saveEdit.SetEnabled(filter.IsComplete()); contextChat.SetEmoji(filter.Context.HasFlag(FilterContext.Chat) ? minus : plus); contextLog.SetEmoji(filter.Context.HasFlag(FilterContext.Log) ? minus : plus); @@ -529,16 +529,16 @@ internal sealed class ContentFilters: BaseCommandModuleCustom step3: // step 3: actions that should be performed on match embed = FormatFilter(filter, errorMsg, 3) - .WithDescription( - "Actions that will be executed on positive match.\n" + - $"**`R`** = **`{FilterAction.RemoveContent}`** will remove the message / log.\n" + - $"**`W`** = **`{FilterAction.IssueWarning}`** will issue a warning to the user.\n" + - $"**`M`** = **`{FilterAction.SendMessage}`** send _a_ message with an explanation of why it was removed.\n" + - $"**`E`** = **`{FilterAction.ShowExplain}`** show `explain` for the specified term (**not implemented**).\n" + - $"**`U`** = **`{FilterAction.MuteModQueue}`** mute mod queue reporting for this action.\n" + - $"**`K`** = **`{FilterAction.Kick}`** kick user from server.\n" + - "Buttons will toggle the action, text message will set the specified flags." - ); + .WithDescription($""" + Actions that will be executed on positive match. + **`R`** = **`{FilterAction.RemoveContent}`** will remove the message / log. + **`W`** = **`{FilterAction.IssueWarning}`** will issue a warning to the user. + **`M`** = **`{FilterAction.SendMessage}`** send _a_ message with an explanation of why it was removed. + **`E`** = **`{FilterAction.ShowExplain}`** show `explain` for the specified term (**not implemented**). + **`U`** = **`{FilterAction.MuteModQueue}`** mute mod queue reporting for this action. + **`K`** = **`{FilterAction.Kick}`** kick user from server. + Buttons will toggle the action, text message will set the specified flags. + """); actionR.SetEmoji(filter.Actions.HasFlag(FilterAction.RemoveContent) ? minus : plus); actionW.SetEmoji(filter.Actions.HasFlag(FilterAction.IssueWarning) ? minus : plus); actionM.SetEmoji(filter.Actions.HasFlag(FilterAction.SendMessage) ? minus : plus); @@ -666,11 +666,11 @@ internal sealed class ContentFilters: BaseCommandModuleCustom step4: // step 4: validation regex to filter out false positives of the plaintext triggers embed = FormatFilter(filter, errorMsg, 4) - .WithDescription( - "Validation [regex](https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference) to optionally perform more strict trigger check.\n" + - "**Please [test](https://regex101.com/) your regex**. Following flags are enabled: Multiline, IgnoreCase.\n" + - "Additional validation can help reduce false positives of a plaintext trigger match." - ); + .WithDescription(""" + Validation [regex](https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference) to optionally perform more strict trigger check. + **Please [test](https://regex101.com/) your regex**. Following flags are enabled: Multiline, IgnoreCase. + Additional validation can help reduce false positives of a plaintext trigger match. + """); var next = (filter.Actions & (FilterAction.SendMessage | FilterAction.ShowExplain)) == 0 ? firstPage : nextPage; trash.SetDisabled(string.IsNullOrEmpty(filter.ValidatingRegex)); saveEdit.SetEnabled(filter.IsComplete()); @@ -775,10 +775,10 @@ internal sealed class ContentFilters: BaseCommandModuleCustom step6: // step 6: show explanation for the term embed = FormatFilter(filter, errorMsg, 6) - .WithDescription( - "Explanation term that is used to show an explanation.\n" + - "**__Currently not implemented__**." - ); + .WithDescription(""" + Explanation term that is used to show an explanation. + **__Currently not implemented__**. + """); saveEdit.SetEnabled(filter.IsComplete()); messageBuilder = new DiscordMessageBuilder() .WithContent("Please specify filter **explanation term**") diff --git a/CompatBot/Commands/DevOnly.cs b/CompatBot/Commands/DevOnly.cs index 0b04a5c5..e630e73c 100644 --- a/CompatBot/Commands/DevOnly.cs +++ b/CompatBot/Commands/DevOnly.cs @@ -25,12 +25,12 @@ internal sealed class DevOnly : BaseCommandModuleCustom #pragma warning disable 8321 static void addRandomStuff(DiscordEmbedBuilder emb) { - var txt = "😾 lasjdf wqoieyr osdf `Vreoh Sdab` wohe `270`\n" + - "🤔 salfhiosfhsero hskfh shufwei oufhwehw e wkihrwe h\n" + - "ℹ️ sakfjas f hs `ASfhewighehw safds` asfw\n" + - "🔮 ¯\\\\\\_(ツ)\\_/¯"; - - emb.AddField("Random section", txt, false); + emb.AddField("Random section", """ + 😾 lasjdf wqoieyr osdf `Vreoh Sdab` wohe `270` + 🤔 salfhiosfhsero hskfh shufwei oufhwehw e wkihrwe h + ℹ️ sakfjas f hs `ASfhewighehw safds` asfw + 🔮 ¯\\\_(ツ)\_/¯ + """, false); } #pragma warning restore 8321 var embed = new DiscordEmbedBuilder() diff --git a/CompatBot/Commands/EventsBaseCommand.cs b/CompatBot/Commands/EventsBaseCommand.cs index 0bd1e989..0b71b50e 100644 --- a/CompatBot/Commands/EventsBaseCommand.cs +++ b/CompatBot/Commands/EventsBaseCommand.cs @@ -81,7 +81,7 @@ internal class EventsBaseCommand: BaseCommandModuleCustom var noEventMsg = $"No information about the upcoming {eventName?.Sanitize(replaceBackTicks: true)} at the moment"; if (eventName?.Length > 10) noEventMsg = "No information about such event at the moment"; - else if (ctx.User.Id == 259997001880436737ul || ctx.User.Id == 377190919327318018ul) + else if (ctx.User.Id is 259997001880436737ul or 377190919327318018ul) { noEventMsg = $"Haha, very funny, {ctx.User.Mention}. So original. Never saw this joke before."; promo = null; @@ -114,7 +114,7 @@ internal class EventsBaseCommand: BaseCommandModuleCustom var noEventMsg = $"No information about the upcoming {eventName?.Sanitize(replaceBackTicks: true)} at the moment"; if (eventName?.Length > 10) noEventMsg = "No information about such event at the moment"; - else if (ctx.User.Id == 259997001880436737ul || ctx.User.Id == 377190919327318018ul) + else if (ctx.User.Id is 259997001880436737ul or 377190919327318018ul) { noEventMsg = $"Haha, very funny, {ctx.User.Mention}. So original. Never saw this joke before."; promo = null; @@ -301,7 +301,10 @@ internal class EventsBaseCommand: BaseCommandModuleCustom saveEdit.SetEnabled(evt.IsComplete()); messageBuilder = new DiscordMessageBuilder() .WithContent("Please specify a new **start date and time**") - .WithEmbed(FormatEvent(evt, errorMsg, 1).WithDescription($"Example: `{DateTime.UtcNow:yyyy-MM-dd HH:mm}`\nBy default all times use UTC, only limited number of time zones supported")) + .WithEmbed(FormatEvent(evt, errorMsg, 1).WithDescription($""" + Example: `{DateTime.UtcNow:yyyy-MM-dd HH:mm}` + By default all times use UTC, only limited number of time zones supported + """)) .AddComponents(lastPage, nextPage) .AddComponents(saveEdit, abort); errorMsg = null; diff --git a/CompatBot/Commands/Explain.cs b/CompatBot/Commands/Explain.cs index 8b230721..f8529910 100644 --- a/CompatBot/Commands/Explain.cs +++ b/CompatBot/Commands/Explain.cs @@ -67,7 +67,7 @@ internal sealed class Explain: BaseCommandModuleCustom var hasMention = false; term = term.ToLowerInvariant(); var result = await LookupTerm(term).ConfigureAwait(false); - if (result.explanation == null || !string.IsNullOrEmpty(result.fuzzyMatch)) + if (result is {explanation: null} or {fuzzyMatch.Length: >0}) { term = term.StripQuotes(); var idx = term.LastIndexOf(" to ", StringComparison.Ordinal); @@ -116,7 +116,7 @@ internal sealed class Explain: BaseCommandModuleCustom term = term.ToLowerInvariant().StripQuotes(); byte[]? attachment = null; string? attachmentFilename = null; - if (ctx.Message.Attachments.FirstOrDefault() is DiscordAttachment att) + if (ctx.Message.Attachments is [DiscordAttachment att, ..]) { attachmentFilename = att.FileName; try @@ -165,7 +165,7 @@ internal sealed class Explain: BaseCommandModuleCustom term = term.ToLowerInvariant().StripQuotes(); byte[]? attachment = null; string? attachmentFilename = null; - if (ctx.Message.Attachments.FirstOrDefault() is DiscordAttachment att) + if (ctx.Message.Attachments is [DiscordAttachment att, ..]) { attachmentFilename = att.FileName; try @@ -346,12 +346,12 @@ internal sealed class Explain: BaseCommandModuleCustom } else { - if (!string.IsNullOrEmpty(item.Text)) + if (item is { Text.Length: > 0 }) { await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(item.Text)); await ctx.Channel.SendMessageAsync(new DiscordMessageBuilder().AddFile($"{termOrLink}.txt", stream)).ConfigureAwait(false); } - if (!string.IsNullOrEmpty(item.AttachmentFilename) && item.Attachment?.Length > 0) + if (item is { AttachmentFilename.Length: > 0, Attachment.Length: > 0 }) { await using var stream = new MemoryStream(item.Attachment); await ctx.Channel.SendMessageAsync(new DiscordMessageBuilder().AddFile(item.AttachmentFilename, stream)).ConfigureAwait(false); diff --git a/CompatBot/Commands/ForcedNicknames.cs b/CompatBot/Commands/ForcedNicknames.cs index b2b4bc1a..3712806d 100644 --- a/CompatBot/Commands/ForcedNicknames.cs +++ b/CompatBot/Commands/ForcedNicknames.cs @@ -71,9 +71,8 @@ internal sealed class ForcedNicknames : BaseCommandModuleCustom else { if (enforceRules.Nickname == expectedNickname) - { continue; - } + enforceRules.Nickname = expectedNickname; } } @@ -187,7 +186,7 @@ internal sealed class ForcedNicknames : BaseCommandModuleCustom var hex = BitConverter.ToString(nameBytes).Replace('-', ' '); var result = $"User ID: {discordUser.Id}\nUsername: {hex}"; var member = ctx.Client.GetMember(ctx.Guild, discordUser); - if (member?.Nickname is string {Length: >0} nickname) + if (member is { Nickname: { Length: > 0 } nickname }) { nameBytes = StringUtils.Utf8.GetBytes(nickname); hex = BitConverter.ToString(nameBytes).Replace('-', ' '); diff --git a/CompatBot/Commands/Fortune.cs b/CompatBot/Commands/Fortune.cs index 600202d1..f1bb6b99 100644 --- a/CompatBot/Commands/Fortune.cs +++ b/CompatBot/Commands/Fortune.cs @@ -46,20 +46,20 @@ internal sealed class Fortune : BaseCommandModuleCustom fortune = await db.Fortune.AsNoTracking().Skip(selectedId).FirstOrDefaultAsync().ConfigureAwait(false); } while (fortune is null); - var msg = fortune.Content.FixTypography(); - var msgParts = msg.Split('\n'); var tmp = new StringBuilder(); var quote = true; - foreach (var l in msgParts) + foreach (var l in fortune.Content.FixTypography().Split('\n')) { quote &= !l.StartsWith(" "); if (quote) tmp.Append("> "); tmp.Append(l).Append('\n'); } - msg = tmp.ToString().TrimEnd().FixSpaces(); var msgBuilder = new DiscordMessageBuilder() - .WithContent($"{user.Mention}, your fortune for today:\n{msg}") + .WithContent($""" + {user.Mention}, your fortune for today: + {tmp.ToString().TrimEnd().FixSpaces()} + """) .WithReply(message.Id); await message.Channel.SendMessageAsync(msgBuilder).ConfigureAwait(false); } @@ -136,7 +136,7 @@ internal sealed class Fortune : BaseCommandModuleCustom || buf.Length > 0) && !Config.Cts.IsCancellationRequested) { - if (line == "%" || line is null) + if (line is "%" or null) { var content = buf.ToString().Replace("\r\n", "\n").Trim(); if (content.Length > 1900) @@ -187,7 +187,7 @@ internal sealed class Fortune : BaseCommandModuleCustom var progressMsg = $"Imported {count} fortune{(count == 1 ? "" : "s")}"; if (skipped > 0) progressMsg += $", skipped {skipped}"; - if (response.Content.Headers.ContentLength is long len && len > 0) + if (response.Content.Headers.ContentLength is long len and > 0) progressMsg += $" ({stream.Position * 100.0 / len:0.##}%)"; await msg.UpdateOrCreateMessageAsync(ctx.Channel, progressMsg).ConfigureAwait(false); stopwatch.Restart(); @@ -246,7 +246,7 @@ internal sealed class Fortune : BaseCommandModuleCustom [Description("Clears fortune database. Use with caution")] public async Task Clear(CommandContext ctx, [RemainingText, Description("Must be `with my blessing, I swear I exported the backup`")] string confirmation) { - if (confirmation != "with my blessing, I swear I exported the backup") + if (confirmation is not "with my blessing, I swear I exported the backup") { await ctx.ReactWithAsync(Config.Reactions.Failure).ConfigureAwait(false); return; diff --git a/CompatBot/Commands/Hardware.cs b/CompatBot/Commands/Hardware.cs index a758a702..81a1906d 100644 --- a/CompatBot/Commands/Hardware.cs +++ b/CompatBot/Commands/Hardware.cs @@ -130,13 +130,17 @@ internal sealed class Hardware: BaseCommandModuleCustom var lowRam = mem.Where(i => i.Mem < 4 * 1024 - margin).Sum(i => i.Count); var ram4to6 = mem.Where(i => i.Mem is >= 4 * 1024 - margin and < 6 * 1024 - margin).Sum(i => i.Count); var ram6to8 = mem.Where(i => i.Mem is >= 6 * 1024 - margin and < 8 * 1024 - margin).Sum(i => i.Count); - var highRam = mem.Where(i => i.Mem >= 8 * 1024 - margin).Sum(i => i.Count); + var ram8to16 = mem.Where(i => i.Mem is >= 8 * 1024 - margin and < 16 * 1024 - margin).Sum(i => i.Count); + var ram16to32 = mem.Where(i => i.Mem is >= 16 * 1024 - margin and < 32 * 1024 - margin).Sum(i => i.Count); + var highRam = mem.Where(i => i.Mem >= 32 * 1024 - margin).Sum(i => i.Count); var ramStats = new (int Count, string Mem)[] { (lowRam, "less than 4 GB"), (ram4to6, "4 to 6 GB"), (ram6to8, "6 to 8 GB"), - (highRam, "8 GB or more"), + (ram8to16, "8 to 16 GB"), + (ram16to32, "16 to 32 GB"), + (highRam, "32 GB or more"), } .Where(i => i.Count > 0) .Take(top) diff --git a/CompatBot/Commands/Misc.cs b/CompatBot/Commands/Misc.cs index 6aad8f68..f171253c 100644 --- a/CompatBot/Commands/Misc.cs +++ b/CompatBot/Commands/Misc.cs @@ -164,8 +164,8 @@ internal sealed class Misc: BaseCommandModuleCustom if (!int.TryParse(m.Groups["num"].Value, out var num)) num = 1; if (int.TryParse(m.Groups["face"].Value, out var face) - && 0 < num && num < 101 - && 1 < face && face < 1001) + && num is > 0 and < 101 + && face is > 1 and < 1001) { List rolls; lock (rng) rolls = Enumerable.Range(0, num).Select(_ => rng.Next(face) + 1).ToList(); @@ -312,7 +312,7 @@ internal sealed class Misc: BaseCommandModuleCustom { try { - var funMult = DateTime.UtcNow.Month == 4 && DateTime.UtcNow.Day == 1 ? 100 : Config.FunMultiplier; + var funMult = DateTime.UtcNow is {Month: 4, Day: 1} ? 100 : Config.FunMultiplier; var choices = RateAnswers; var choiceFlags = new HashSet(); whatever = whatever.ToLowerInvariant().StripInvisibleAndDiacritics(); diff --git a/CompatBot/Commands/Moderation.Audit.cs b/CompatBot/Commands/Moderation.Audit.cs index 224eeb73..c5693dde 100644 --- a/CompatBot/Commands/Moderation.Audit.cs +++ b/CompatBot/Commands/Moderation.Audit.cs @@ -51,7 +51,7 @@ internal sealed partial class Moderation await using var memoryStream = Config.MemoryStreamManager.GetStream(); await using var writer = new StreamWriter(memoryStream, new UTF8Encoding(false), 4096, true); foreach (var member in members) - await writer.WriteLineAsync($"{member.Username}\t{member.Nickname}\t{member.JoinedAt:O}\t{(string.Join(',', member.Roles.Select(r => r.Name)))}").ConfigureAwait(false); + await writer.WriteLineAsync($"{member.Username}\t{member.Nickname}\t{member.JoinedAt:O}\t{string.Join(',', member.Roles.Select(r => r.Name))}").ConfigureAwait(false); await writer.FlushAsync().ConfigureAwait(false); memoryStream.Seek(0, SeekOrigin.Begin); if (memoryStream.Length <= ctx.GetAttachmentSizeLimit()) @@ -192,11 +192,13 @@ internal sealed partial class Moderation } } - /* +#if DEBUG [Command("locales"), Aliases("locale", "languages", "language", "lang", "loc")] public async Task UserLocales(CommandContext ctx) { +#pragma warning disable VSTHRD103 if (!CheckLock.Wait(0)) +#pragma warning restore VSTHRD103 { await ctx.Channel.SendMessageAsync("Another check is already in progress").ConfigureAwait(false); return; @@ -236,7 +238,7 @@ internal sealed partial class Moderation await ctx.RemoveReactionAsync(Config.Reactions.PleaseWait).ConfigureAwait(false); } } - */ +#endif private static List GetMembers(DiscordClient client) { diff --git a/CompatBot/Commands/Pr.cs b/CompatBot/Commands/Pr.cs index f1a34404..bccc122b 100644 --- a/CompatBot/Commands/Pr.cs +++ b/CompatBot/Commands/Pr.cs @@ -284,7 +284,10 @@ internal sealed class Pr: BaseCommandModuleCustom var avgBuildTime = (await azureClient.GetPipelineDurationAsync(Config.Cts.Token).ConfigureAwait(false)).Mean; if (now < mergeTime + avgBuildTime) waitTime = mergeTime + avgBuildTime - now; - embed.AddField("Latest master build", $"This pull request has been merged, and will be part of `master` very soon.\nPlease check again in {waitTime.AsTimeDeltaDescription()}."); + embed.AddField("Latest master build", $""" + This pull request has been merged, and will be part of `master` very soon. + Please check again in {waitTime.AsTimeDeltaDescription()}. + """); } } } diff --git a/CompatBot/Commands/SlashMisc.cs b/CompatBot/Commands/SlashMisc.cs index 039767d3..1d9068f1 100644 --- a/CompatBot/Commands/SlashMisc.cs +++ b/CompatBot/Commands/SlashMisc.cs @@ -18,23 +18,19 @@ internal sealed class SlashMisc: BaseApplicationCommandModuleCustom Title = "RPCS3 Compatibility Bot", Url = "https://github.com/RPCS3/discord-bot", Color = DiscordColor.Purple, - }.AddField("Made by", - $""" + }.AddField("Made by", $""" 💮 13xforever 🇭🇷 Roberto Anić Banić aka nicba1010 {clienthax} clienthax """ - ) - .AddField("People who ~~broke~~ helped test the bot", - $""" + ).AddField("People who ~~broke~~ helped test the bot", $""" 🐱 Juhn {hcorion} hcorion 🙃 TGE 🍒 Maru ♋ Tourghool """ - ) - .WithFooter($"Running {Config.GitRevision}"); + ).WithFooter($"Running {Config.GitRevision}"); await ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder().AddEmbed(embed.Build()).AsEphemeral()); } } \ No newline at end of file diff --git a/CompatBot/Commands/Sudo.Bot.Configuration.cs b/CompatBot/Commands/Sudo.Bot.Configuration.cs index 8a56c1f8..237b4051 100644 --- a/CompatBot/Commands/Sudo.Bot.Configuration.cs +++ b/CompatBot/Commands/Sudo.Bot.Configuration.cs @@ -31,9 +31,9 @@ internal partial class Sudo foreach (var v in setVars) { #if DEBUG - result.Append(v.Key![SqlConfiguration.ConfigVarPrefix.Length ..]).Append(" = ").AppendLine(v.Value); + result.Append(v.Key[SqlConfiguration.ConfigVarPrefix.Length ..]).Append(" = ").AppendLine(v.Value); #else - result.AppendLine(v.Key![(SqlConfiguration.ConfigVarPrefix.Length)..]); + result.AppendLine(v.Key[(SqlConfiguration.ConfigVarPrefix.Length)..]); #endif } await ctx.Channel.SendMessageAsync(result.ToString()).ConfigureAwait(false); @@ -53,7 +53,7 @@ internal partial class Sudo var stateValue = await db.BotState.FirstOrDefaultAsync(v => v.Key == key).ConfigureAwait(false); if (stateValue == null) { - stateValue = new BotState {Key = key, Value = value}; + stateValue = new() {Key = key, Value = value}; await db.BotState.AddAsync(stateValue).ConfigureAwait(false); } else diff --git a/CompatBot/Commands/Sudo.Dotnet.cs b/CompatBot/Commands/Sudo.Dotnet.cs index 8e19e487..91e4bb53 100644 --- a/CompatBot/Commands/Sudo.Dotnet.cs +++ b/CompatBot/Commands/Sudo.Dotnet.cs @@ -30,7 +30,7 @@ internal partial class Sudo msg = await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Checking for dotnet updates...").ConfigureAwait(false); var (updated, stdout) = await UpdateAsync(version).ConfigureAwait(false); if (!string.IsNullOrEmpty(stdout)) - await ctx.SendAutosplitMessageAsync("```" + stdout + "```").ConfigureAwait(false); + await ctx.SendAutosplitMessageAsync($"```{stdout}```").ConfigureAwait(false); if (!updated) return; diff --git a/CompatBot/Commands/Sudo.Mod.cs b/CompatBot/Commands/Sudo.Mod.cs index 9832b3b5..93489d4a 100644 --- a/CompatBot/Commands/Sudo.Mod.cs +++ b/CompatBot/Commands/Sudo.Mod.cs @@ -21,8 +21,10 @@ internal partial class Sudo if (await ModProvider.AddAsync(user.Id).ConfigureAwait(false)) { await ctx.ReactWithAsync(Config.Reactions.Success, - $"{user.Mention} was successfully added as moderator!\n" + - $"Try using `{ctx.Prefix}help` to see new commands available to you" + $""" + {user.Mention} was successfully added as moderator! + Try using `{ctx.Prefix}help` to see new commands available to you + """ ).ConfigureAwait(false); } else @@ -36,7 +38,7 @@ internal partial class Sudo if (ctx.Client.CurrentApplication.Owners.Any(u => u.Id == user.Id)) { var dm = await user.CreateDmChannelAsync().ConfigureAwait(false); - await dm.SendMessageAsync($@"Just letting you know that {ctx.Message.Author.Mention} just tried to strip you off of your mod role ¯\\_(ツ)_/¯").ConfigureAwait(false); + await dm.SendMessageAsync($@"Just letting you know that {ctx.Message.Author.Mention} just tried to strip you off of your mod role ¯\\\_(ツ)\_/¯").ConfigureAwait(false); await ctx.ReactWithAsync(Config.Reactions.Denied, $"{ctx.Message.Author.Mention} why would you even try this?! Alerting {user.Mention}", true).ConfigureAwait(false); } else if (await ModProvider.RemoveAsync(user.Id).ConfigureAwait(false)) diff --git a/CompatBot/Commands/Sudo.cs b/CompatBot/Commands/Sudo.cs index 84d80cf2..2f0effa9 100644 --- a/CompatBot/Commands/Sudo.cs +++ b/CompatBot/Commands/Sudo.cs @@ -33,7 +33,6 @@ internal sealed partial class Sudo : BaseCommandModuleCustom public async Task Say(CommandContext ctx, [RemainingText, Description("Message text to send")] string message) { var msgParts = message.Split(' ', 2, StringSplitOptions.TrimEntries); - var channel = ctx.Channel; DiscordMessage? ogMsg = null; if (msgParts.Length > 1) diff --git a/CompatBot/Commands/Vision.cs b/CompatBot/Commands/Vision.cs index a14ee52a..b4a8933f 100644 --- a/CompatBot/Commands/Vision.cs +++ b/CompatBot/Commands/Vision.cs @@ -117,7 +117,7 @@ internal sealed class Vision: BaseCommandModuleCustom //resize and shrink file size to get under azure limits var quality = 90; var resized = false; - if (img.Width > 4000 || img.Height > 4000) + if (img is {Width: >4000} or {Height: >4000}) { img.Mutate(i => i.Resize(new ResizeOptions {Size = new(3840, 2160), Mode = ResizeMode.Min,})); resized = true; diff --git a/CompatBot/Commands/Warnings.cs b/CompatBot/Commands/Warnings.cs index 205bb47f..588be643 100644 --- a/CompatBot/Commands/Warnings.cs +++ b/CompatBot/Commands/Warnings.cs @@ -52,7 +52,6 @@ internal sealed partial class Warnings: BaseCommandModuleCustom var interact = ctx.Client.GetInteractivity(); await using var db = new BotDb(); var warnings = await db.Warning.Where(w => id.Equals(w.Id)).ToListAsync().ConfigureAwait(false); - if (warnings.Count == 0) { await ctx.ReactWithAsync(Config.Reactions.Denied, $"{ctx.Message.Author.Mention} Warn not found", true); @@ -60,7 +59,6 @@ internal sealed partial class Warnings: BaseCommandModuleCustom } var warningToEdit = warnings.First(); - if (warningToEdit.IssuerId != ctx.User.Id) { await ctx.ReactWithAsync(Config.Reactions.Denied, $"{ctx.Message.Author.Mention} This warn wasn't issued by you :(", true); @@ -83,7 +81,6 @@ internal sealed partial class Warnings: BaseCommandModuleCustom } warningToEdit.Reason = response.Result.Content; - await db.SaveChangesAsync().ConfigureAwait(false); await ctx.Channel.SendMessageAsync($"Warning successfully edited!").ConfigureAwait(false); } @@ -166,7 +163,7 @@ internal sealed partial class Warnings: BaseCommandModuleCustom { await using var db = new BotDb(); var warn = await db.Warning.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false); - if (warn?.Retracted is true) + if (warn is { Retracted: true }) { warn.Retracted = false; warn.RetractedBy = null; diff --git a/CompatBot/Database/BotDb.cs b/CompatBot/Database/BotDb.cs index 907e2488..9e6a382c 100644 --- a/CompatBot/Database/BotDb.cs +++ b/CompatBot/Database/BotDb.cs @@ -27,7 +27,7 @@ internal class BotDb: DbContext #if DEBUG optionsBuilder.UseLoggerFactory(Config.LoggerFactory); #endif - optionsBuilder.UseSqlite($"Data Source=\"{dbPath}\""); + optionsBuilder.UseSqlite($""" Data Source="{dbPath}" """); } protected override void OnModelCreating(ModelBuilder modelBuilder) diff --git a/CompatBot/Database/DbImporter.cs b/CompatBot/Database/DbImporter.cs index 0eaa8719..260cf61c 100644 --- a/CompatBot/Database/DbImporter.cs +++ b/CompatBot/Database/DbImporter.cs @@ -18,20 +18,20 @@ public static class DbImporter public static async Task UpgradeAsync(CancellationToken cancellationToken) { await using (var db = new BotDb()) - if (!await UpgradeAsync(db, Config.Cts.Token)) + if (!await UpgradeAsync(db, cancellationToken).ConfigureAwait(false)) return false; await using (var db = new ThumbnailDb()) { - if (!await UpgradeAsync(db, Config.Cts.Token)) + if (!await UpgradeAsync(db,cancellationToken).ConfigureAwait(false)) return false; - if (!await ImportNamesPool(db, Config.Cts.Token)) + if (!await ImportNamesPool(db, cancellationToken).ConfigureAwait(false)) return false; } await using (var db = new HardwareDb()) - if (!await UpgradeAsync(db, Config.Cts.Token)) + if (!await UpgradeAsync(db, cancellationToken).ConfigureAwait(false)) return false; return true; diff --git a/CompatBot/Database/HardwareDb.cs b/CompatBot/Database/HardwareDb.cs index 8e383e66..5ad9a63e 100644 --- a/CompatBot/Database/HardwareDb.cs +++ b/CompatBot/Database/HardwareDb.cs @@ -15,7 +15,7 @@ internal class HardwareDb : DbContext #if DEBUG optionsBuilder.UseLoggerFactory(Config.LoggerFactory); #endif - optionsBuilder.UseSqlite($"Data Source=\"{dbPath}\""); + optionsBuilder.UseSqlite($""" Data Source="{dbPath}" """); } protected override void OnModelCreating(ModelBuilder modelBuilder) diff --git a/CompatBot/Database/Providers/ContentFilter.cs b/CompatBot/Database/Providers/ContentFilter.cs index 7d79b509..5c05555d 100644 --- a/CompatBot/Database/Providers/ContentFilter.cs +++ b/CompatBot/Database/Providers/ContentFilter.cs @@ -276,8 +276,7 @@ internal static class ContentFilter public static string? GetMatchedScope(Piracystring trigger, string? context) => context is { Length: >0 } && trigger.ValidatingRegex is { Length: >0 } pattern - && Regex.Match(context, pattern, RegexOptions.IgnoreCase | RegexOptions.Multiline) is { Success: true } m - && m.Groups.Count > 0 + && Regex.Match(context, pattern, RegexOptions.IgnoreCase | RegexOptions.Multiline) is { Success: true, Groups.Count: > 0 } m ? m.Groups[0].Value.Trim(256) : null; } \ No newline at end of file diff --git a/CompatBot/Database/Providers/DisabledCommandsProvider.cs b/CompatBot/Database/Providers/DisabledCommandsProvider.cs index ff44262f..44fa237a 100644 --- a/CompatBot/Database/Providers/DisabledCommandsProvider.cs +++ b/CompatBot/Database/Providers/DisabledCommandsProvider.cs @@ -26,7 +26,7 @@ internal static class DisabledCommandsProvider if (DisabledCommands.Add(command)) { using var db = new BotDb(); - db.DisabledCommands.Add(new DisabledCommand {Command = command}); + db.DisabledCommands.Add(new() {Command = command}); db.SaveChanges(); } } diff --git a/CompatBot/Database/Providers/ModProvider.cs b/CompatBot/Database/Providers/ModProvider.cs index baaa8f6b..5999e4b2 100644 --- a/CompatBot/Database/Providers/ModProvider.cs +++ b/CompatBot/Database/Providers/ModProvider.cs @@ -19,7 +19,6 @@ internal static class ModProvider } public static bool IsMod(ulong userId) => Moderators.ContainsKey(userId); - public static bool IsSudoer(ulong userId) => Moderators.TryGetValue(userId, out var mod) && mod.Sudoer; public static async Task AddAsync(ulong userId) @@ -34,6 +33,7 @@ internal static class ModProvider { if (IsMod(userId)) return false; + Moderators[userId] = newMod; } return true; diff --git a/CompatBot/Database/Providers/ScrapeStateProvider.cs b/CompatBot/Database/Providers/ScrapeStateProvider.cs index cf166868..7d7d1b98 100644 --- a/CompatBot/Database/Providers/ScrapeStateProvider.cs +++ b/CompatBot/Database/Providers/ScrapeStateProvider.cs @@ -20,7 +20,7 @@ internal static class ScrapeStateProvider var id = GetId(locale, containerId); using var db = new ThumbnailDb(); var timestamp = string.IsNullOrEmpty(id) ? db.State.OrderBy(s => s.Timestamp).FirstOrDefault() : db.State.FirstOrDefault(s => s.Locale == id); - if (timestamp?.Timestamp is long checkDate && checkDate > 0) + if (timestamp is { Timestamp: long checkDate and > 0 }) return IsFresh(new DateTime(checkDate, DateTimeKind.Utc)); return false; } @@ -29,7 +29,7 @@ internal static class ScrapeStateProvider { using var db = new ThumbnailDb(); var timestamp = string.IsNullOrEmpty(locale) ? db.State.OrderBy(s => s.Timestamp).FirstOrDefault() : db.State.FirstOrDefault(s => s.Locale == locale); - if (timestamp?.Timestamp is long checkDate && checkDate > 0) + if (timestamp is { Timestamp: long checkDate and > 0 }) return new DateTime(checkDate, DateTimeKind.Utc) > dataTimestamp; return false; } diff --git a/CompatBot/Database/Providers/ThumbnailProvider.cs b/CompatBot/Database/Providers/ThumbnailProvider.cs index d24b0106..2384fb47 100644 --- a/CompatBot/Database/Providers/ThumbnailProvider.cs +++ b/CompatBot/Database/Providers/ThumbnailProvider.cs @@ -25,13 +25,13 @@ internal static class ThumbnailProvider productCode = productCode.ToUpperInvariant(); var tmdbInfo = await PsnClient.GetTitleMetaAsync(productCode, Config.Cts.Token).ConfigureAwait(false); - if (tmdbInfo?.Icon.Url is string tmdbIconUrl) + if (tmdbInfo is { Icon.Url: string tmdbIconUrl }) return tmdbIconUrl; await using var db = new ThumbnailDb(); var thumb = await db.Thumbnail.FirstOrDefaultAsync(t => t.ProductCode == productCode).ConfigureAwait(false); //todo: add search task if not found - if (thumb?.EmbeddableUrl is string embeddableUrl && !string.IsNullOrEmpty(embeddableUrl)) + if (thumb?.EmbeddableUrl is {Length: >0} embeddableUrl) return embeddableUrl; if (string.IsNullOrEmpty(thumb?.Url) || !ScrapeStateProvider.IsFresh(thumb.Timestamp)) @@ -40,7 +40,7 @@ internal static class ThumbnailProvider if (!string.IsNullOrEmpty(gameTdbCoverUrl)) { if (thumb is null) - thumb = (await db.Thumbnail.AddAsync(new Thumbnail {ProductCode = productCode, Url = gameTdbCoverUrl}).ConfigureAwait(false)).Entity; + thumb = (await db.Thumbnail.AddAsync(new() {ProductCode = productCode, Url = gameTdbCoverUrl}).ConfigureAwait(false)).Entity; else thumb.Url = gameTdbCoverUrl; thumb.Timestamp = DateTime.UtcNow.Ticks; @@ -81,7 +81,7 @@ internal static class ThumbnailProvider if (!string.IsNullOrEmpty(title)) { if (thumb == null) - await db.Thumbnail.AddAsync(new Thumbnail + await db.Thumbnail.AddAsync(new() { ProductCode = productCode, Name = title, @@ -107,7 +107,7 @@ internal static class ThumbnailProvider contentId = contentId.ToUpperInvariant(); await using var db = new ThumbnailDb(); var info = await db.Thumbnail.FirstOrDefaultAsync(ti => ti.ContentId == contentId, Config.Cts.Token).ConfigureAwait(false); - info ??= new Thumbnail{Url = url}; + info ??= new() {Url = url}; if (info.Url is null) return (null, defaultColor); @@ -139,7 +139,7 @@ internal static class ThumbnailProvider await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false); } } - var color = info.EmbedColor.HasValue ? new DiscordColor(info.EmbedColor.Value) : defaultColor; + var color = info.EmbedColor.HasValue ? new(info.EmbedColor.Value) : defaultColor; return (info.EmbeddableUrl, color); } diff --git a/CompatBot/Database/Providers/TitleUpdateInfoProvider.cs b/CompatBot/Database/Providers/TitleUpdateInfoProvider.cs index 68ec582c..4362127e 100644 --- a/CompatBot/Database/Providers/TitleUpdateInfoProvider.cs +++ b/CompatBot/Database/Providers/TitleUpdateInfoProvider.cs @@ -21,7 +21,7 @@ public static class TitleUpdateInfoProvider productId = productId.ToUpper(); var (update, xml) = await Client.GetTitleUpdatesAsync(productId, cancellationToken).ConfigureAwait(false); - if (xml is string {Length: > 10}) + if (xml is {Length: > 10}) { var xmlChecksum = xml.GetStableHash(); await using var db = new ThumbnailDb(); @@ -38,7 +38,7 @@ public static class TitleUpdateInfoProvider updateInfo.Timestamp = DateTime.UtcNow.Ticks; await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false); } - if ((update?.Tag?.Packages?.Length ?? 0) == 0) + if (update?.Tag?.Packages?.Length is null or 0) { await using var db = new ThumbnailDb(); var updateInfo = db.GameUpdateInfo.FirstOrDefault(ui => ui.ProductCode == productId); @@ -50,8 +50,9 @@ public static class TitleUpdateInfoProvider update = (TitlePatch?)xmlSerializer.Deserialize(memStream); if (update is not null) update.OfflineCacheTimestamp = updateInfo.Timestamp.AsUtc(); + + return update; } - return update; } @@ -65,7 +66,7 @@ public static class TitleUpdateInfoProvider { var updateInfo = db.GameUpdateInfo.AsNoTracking().FirstOrDefault(ui => ui.ProductCode == titleId); if (!cancellationToken.IsCancellationRequested - && ((updateInfo?.Timestamp ?? 0) == 0 || updateInfo!.Timestamp.AsUtc() < DateTime.UtcNow.AddMonths(-1))) + && (updateInfo?.Timestamp is null or 0L || updateInfo.Timestamp.AsUtc() < DateTime.UtcNow.AddMonths(-1))) { await GetAsync(titleId, cancellationToken).ConfigureAwait(false); await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); diff --git a/CompatBot/Database/ThumbnailDb.cs b/CompatBot/Database/ThumbnailDb.cs index b0b3ea8b..cbd5a5ec 100644 --- a/CompatBot/Database/ThumbnailDb.cs +++ b/CompatBot/Database/ThumbnailDb.cs @@ -23,7 +23,7 @@ internal class ThumbnailDb : DbContext #if DEBUG optionsBuilder.UseLoggerFactory(Config.LoggerFactory); #endif - optionsBuilder.UseSqlite($"Data Source=\"{dbPath}\""); + optionsBuilder.UseSqlite($""" Data Source="{dbPath}" """); } protected override void OnModelCreating(ModelBuilder modelBuilder) diff --git a/CompatBot/EventHandlers/BotReactionsHandler.cs b/CompatBot/EventHandlers/BotReactionsHandler.cs index 55de9fd3..e8a99517 100644 --- a/CompatBot/EventHandlers/BotReactionsHandler.cs +++ b/CompatBot/EventHandlers/BotReactionsHandler.cs @@ -132,7 +132,7 @@ namespace CompatBot.EventHandlers await using var db = new BotDb(); var matchedGroups = (from m in mc from Group g in m.Groups - where g.Success && !string.IsNullOrEmpty(g.Value) + where g is { Success: true, Value.Length: > 0 } select g.Name ).Distinct() .ToArray(); @@ -193,7 +193,7 @@ namespace CompatBot.EventHandlers await msg.DeleteAsync("asked to shut up").ConfigureAwait(false); } else - await args.Message.ReactWithAsync(DiscordEmoji.FromUnicode("🙅"), @"No can do, boss ¯\\_(ツ)\_/¯").ConfigureAwait(false); + await args.Message.ReactWithAsync(DiscordEmoji.FromUnicode("🙅"), @"No can do, boss ¯\\\_(ツ)\_/¯").ConfigureAwait(false); } } } diff --git a/CompatBot/EventHandlers/DeletedMessagesMonitor.cs b/CompatBot/EventHandlers/DeletedMessagesMonitor.cs index 104c76a0..b45c255c 100644 --- a/CompatBot/EventHandlers/DeletedMessagesMonitor.cs +++ b/CompatBot/EventHandlers/DeletedMessagesMonitor.cs @@ -74,9 +74,7 @@ internal static class DeletedMessagesMonitor { if (attachmentContent?.Count > 0) foreach (var f in attachmentContent.Values) -#pragma warning disable VSTHRD103 - f.Dispose(); -#pragma warning restore VSTHRD103 + await f.DisposeAsync(); } } } \ No newline at end of file diff --git a/CompatBot/EventHandlers/DiscordInviteFilter.cs b/CompatBot/EventHandlers/DiscordInviteFilter.cs index 381c6650..fecf1a3a 100644 --- a/CompatBot/EventHandlers/DiscordInviteFilter.cs +++ b/CompatBot/EventHandlers/DiscordInviteFilter.cs @@ -187,7 +187,7 @@ internal static class DiscordInviteFilter public static async Task<(bool hasInvalidInvite, bool attemptToWorkaround, List invites)> GetInvitesAsync(this DiscordClient client, string message, DiscordUser? author = null, bool tryMessageAsACode = false) { if (string.IsNullOrEmpty(message)) - return (false, false, new List(0)); + return (false, false, new(0)); var inviteCodes = new HashSet(InviteLink.Matches(message).Select(m => m.Groups["invite_id"].Value).Where(s => !string.IsNullOrEmpty(s))); var discordMeLinks = InviteLink.Matches(message).Select(m => m.Groups["me_id"].Value).Distinct().Where(s => !string.IsNullOrEmpty(s)).ToList(); @@ -202,7 +202,7 @@ internal static class DiscordInviteFilter } } if (inviteCodes.Count == 0 && discordMeLinks.Count == 0 && !tryMessageAsACode) - return (false, attemptedWorkaround, new List(0)); + return (false, attemptedWorkaround, new(0)); var hasInvalidInvites = false; foreach (var meLink in discordMeLinks) @@ -221,9 +221,9 @@ internal static class DiscordInviteFilter using var handler = new HttpClientHandler {AllowAutoRedirect = false}; // needed to store cloudflare session cookies using var httpClient = HttpClientFactory.Create(handler, new CompressionMessageHandler()); using var request = new HttpRequestMessage(HttpMethod.Get, "https://discord.me/" + meLink); - request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/html")); + request.Headers.Accept.Add(new("text/html")); request.Headers.CacheControl = CacheControlHeaderValue.Parse("no-cache"); - request.Headers.UserAgent.Add(new ProductInfoHeaderValue("RPCS3CompatibilityBot", "2.0")); + request.Headers.UserAgent.Add(new("RPCS3CompatibilityBot", "2.0")); using var response = await httpClient.SendAsync(request).ConfigureAwait(false); var html = await response.Content.ReadAsStringAsync().ConfigureAwait(false); if (response.IsSuccessStatusCode) @@ -244,8 +244,8 @@ internal static class DiscordInviteFilter ["serverEid"] = serverEidMatch.Groups["server_eid"].Value, }!), }; - postRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/html")); - postRequest.Headers.UserAgent.Add(new ProductInfoHeaderValue("RPCS3CompatibilityBot", "2.0")); + postRequest.Headers.Accept.Add(new("text/html")); + postRequest.Headers.UserAgent.Add(new("RPCS3CompatibilityBot", "2.0")); using var postResponse = await httpClient.SendAsync(postRequest).ConfigureAwait(false); if (postResponse.StatusCode == HttpStatusCode.Redirect) { @@ -254,7 +254,7 @@ internal static class DiscordInviteFilter { using var getDiscordRequest = new HttpRequestMessage(HttpMethod.Get, "https://discord.me/server/join/redirect/" + redirectId); getDiscordRequest.Headers.CacheControl = CacheControlHeaderValue.Parse("no-cache"); - getDiscordRequest.Headers.UserAgent.Add(new ProductInfoHeaderValue("RPCS3CompatibilityBot", "2.0")); + getDiscordRequest.Headers.UserAgent.Add(new("RPCS3CompatibilityBot", "2.0")); using var discordRedirect = await httpClient.SendAsync(getDiscordRequest).ConfigureAwait(false); if (discordRedirect.StatusCode == HttpStatusCode.Redirect) { diff --git a/CompatBot/EventHandlers/IsTheGamePlayableHandler.cs b/CompatBot/EventHandlers/IsTheGamePlayableHandler.cs index 9d45e0bb..1eeeeab4 100644 --- a/CompatBot/EventHandlers/IsTheGamePlayableHandler.cs +++ b/CompatBot/EventHandlers/IsTheGamePlayableHandler.cs @@ -58,7 +58,7 @@ internal static class IsTheGamePlayableHandler .Concat(matches.Select(m => m.Groups["game_title_2"].Value)) .Concat(matches.Select(m => m.Groups["game_title_3"].Value)) .FirstOrDefault(t => !string.IsNullOrEmpty(t)); - if (string.IsNullOrEmpty(gameTitle) || gameTitle.Length < 2) + if (gameTitle is null or { Length: < 2 }) return; gameTitle = CompatList.FixGameTitleSearch(gameTitle); @@ -89,7 +89,7 @@ internal static class IsTheGamePlayableHandler if (!string.IsNullOrEmpty(info.Date)) msg += $" since {info.ToUpdated()}"; } - msg += $"\nfor more results please use compatibility list () or `{Config.CommandPrefix}c` command in {botSpamChannel.Mention} (`!c {gameTitle.Sanitize()}`)"; + msg += $"\nfor more results please use [compatibility list]() or `{Config.CommandPrefix}c` command in {botSpamChannel.Mention} (`!c {gameTitle.Sanitize()}`)"; await args.Channel.SendMessageAsync(msg).ConfigureAwait(false); CooldownBuckets[args.Channel.Id] = DateTime.UtcNow; } diff --git a/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/GzipHandler.cs b/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/GzipHandler.cs index 8d0fcef5..1f941bf9 100644 --- a/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/GzipHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/GzipHandler.cs @@ -19,7 +19,7 @@ internal sealed class GzipHandler: IArchiveHandler { if (header.Length >= Header.Length) { - if (header.Slice(0, Header.Length).SequenceEqual(Header)) + if (header[..Header.Length].SequenceEqual(Header)) return (true, null); } else if (fileName.EndsWith(".log.gz", StringComparison.InvariantCultureIgnoreCase) diff --git a/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/PlainText.cs b/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/PlainText.cs index a8d44323..666a34ac 100644 --- a/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/PlainText.cs +++ b/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/PlainText.cs @@ -18,7 +18,7 @@ internal sealed class PlainTextHandler: IArchiveHandler if (fileName.Contains("tty.log", StringComparison.InvariantCultureIgnoreCase)) return (false, null); - if (header.Length > 10 && Encoding.UTF8.GetString(header.Slice(0, 30)).Contains("RPCS3 v")) + if (header.Length > 10 && Encoding.UTF8.GetString(header[..30]).Contains("RPCS3 v")) return (true, null); return (false, null); diff --git a/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/RarHandler.cs b/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/RarHandler.cs index 299f4938..ef95e249 100644 --- a/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/RarHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/RarHandler.cs @@ -18,7 +18,7 @@ internal sealed class RarHandler: IArchiveHandler public (bool result, string? reason) CanHandle(string fileName, int fileSize, ReadOnlySpan header) { - if (header.Length >= Header.Length && header.Slice(0, Header.Length).SequenceEqual(Header) + if (header.Length >= Header.Length && header[..Header.Length].SequenceEqual(Header) || header.Length == 0 && fileName.EndsWith(".rar", StringComparison.InvariantCultureIgnoreCase)) { var firstEntry = Encoding.ASCII.GetString(header); diff --git a/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/SevenZipHandler.cs b/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/SevenZipHandler.cs index 0686d18c..56dbcea6 100644 --- a/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/SevenZipHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/SevenZipHandler.cs @@ -17,7 +17,7 @@ internal sealed class SevenZipHandler: IArchiveHandler public (bool result, string? reason) CanHandle(string fileName, int fileSize, ReadOnlySpan header) { - if (header.Length >= Header.Length && header.Slice(0, Header.Length).SequenceEqual(Header) + if (header.Length >= Header.Length && header[..Header.Length].SequenceEqual(Header) || header.Length == 0 && fileName.EndsWith(".7z", StringComparison.InvariantCultureIgnoreCase)) { if (fileSize > Config.AttachmentSizeLimit) diff --git a/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/ZipHandler.cs b/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/ZipHandler.cs index e936a74d..6cbca236 100644 --- a/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/ZipHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/ArchiveHandlers/ZipHandler.cs @@ -19,7 +19,7 @@ internal sealed class ZipHandler: IArchiveHandler public (bool result, string? reason) CanHandle(string fileName, int fileSize, ReadOnlySpan header) { - if (header.Length >= Header.Length && header.Slice(0, Header.Length).SequenceEqual(Header) + if (header.Length >= Header.Length && header[..Header.Length].SequenceEqual(Header) || header.Length == 0 && fileName.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase)) { var firstEntry = Encoding.ASCII.GetString(header); diff --git a/CompatBot/EventHandlers/LogParsing/LogParser.PipeReader.cs b/CompatBot/EventHandlers/LogParsing/LogParser.PipeReader.cs index 93b9f9b5..becbf76f 100644 --- a/CompatBot/EventHandlers/LogParsing/LogParser.PipeReader.cs +++ b/CompatBot/EventHandlers/LogParsing/LogParser.PipeReader.cs @@ -13,7 +13,6 @@ namespace CompatBot.EventHandlers.LogParsing; internal static partial class LogParser { private static readonly byte[] Bom = {0xEF, 0xBB, 0xBF}; - private static readonly PoorMansTaskScheduler TaskScheduler = new(); public static async Task ReadPipeAsync(PipeReader reader, CancellationToken cancellationToken) diff --git a/CompatBot/EventHandlers/LogParsing/LogParser.StateMachineGenerator.cs b/CompatBot/EventHandlers/LogParsing/LogParser.StateMachineGenerator.cs index 7ea901f8..a98107d4 100644 --- a/CompatBot/EventHandlers/LogParsing/LogParser.StateMachineGenerator.cs +++ b/CompatBot/EventHandlers/LogParsing/LogParser.StateMachineGenerator.cs @@ -60,8 +60,7 @@ internal partial class LogParser if (trigger == "{PPU[" || trigger == "⁂") { if (state.WipCollection["serial"] is string serial - && extractor.Match(buffer) is Match match - && match.Success + && extractor.Match(buffer) is { Success: true } match && match.Groups["syscall_name"].Value is string syscallName) { lock (state) @@ -81,8 +80,7 @@ internal partial class LogParser foreach (Match match in matches) foreach (Group group in match.Groups) { - if (string.IsNullOrEmpty(group.Name) - || group.Name == "0" + if (group.Name is null or "" or "0" || string.IsNullOrWhiteSpace(group.Value)) continue; diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/DropboxHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/DropboxHandler.cs index ae3feeae..ced7e58d 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/DropboxHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/DropboxHandler.cs @@ -30,51 +30,50 @@ internal sealed class DropboxHandler : BaseSourceHandler using var client = HttpClientFactory.Create(); foreach (Match m in matches) { - if (m.Groups["dropbox_link"].Value is string lnk - && !string.IsNullOrEmpty(lnk) - && Uri.TryCreate(lnk, UriKind.Absolute, out var uri)) + if (m.Groups["dropbox_link"].Value is not { Length: > 0 } lnk + || !Uri.TryCreate(lnk, UriKind.Absolute, out var uri)) + continue; + + try { + uri = uri.SetQueryParameter("dl", "1"); + var filename = Path.GetFileName(lnk); + var filesize = -1; + + using (var request = new HttpRequestMessage(HttpMethod.Head, uri)) + { + using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Config.Cts.Token); + if (response.Content.Headers.ContentLength > 0) + filesize = (int)response.Content.Headers.ContentLength.Value; + if (response.Content.Headers.ContentDisposition?.FileNameStar is {Length: >0} fname) + filename = fname; + uri = response.RequestMessage?.RequestUri; + } + + await using var stream = await client.GetStreamAsync(uri).ConfigureAwait(false); + var buf = BufferPool.Rent(SnoopBufferSize); try { - uri = uri.SetQueryParameter("dl", "1"); - var filename = Path.GetFileName(lnk); - var filesize = -1; - - using (var request = new HttpRequestMessage(HttpMethod.Head, uri)) + var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false); + foreach (var handler in handlers) { - using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Config.Cts.Token); - if (response.Content.Headers.ContentLength > 0) - filesize = (int)response.Content.Headers.ContentLength.Value; - if (response.Content.Headers.ContentDisposition?.FileNameStar is string fname && !string.IsNullOrEmpty(fname)) - filename = fname; - uri = response.RequestMessage?.RequestUri; - } - - await using var stream = await client.GetStreamAsync(uri).ConfigureAwait(false); - var buf = BufferPool.Rent(SnoopBufferSize); - try - { - var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false); - foreach (var handler in handlers) - { - var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read)); - if (canHandle) - return (new DropboxSource(uri, handler, filename, filesize), null); - else if (!string.IsNullOrEmpty(reason)) - return (null, reason); - } - } - finally - { - BufferPool.Return(buf); + var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read)); + if (canHandle) + return (new DropboxSource(uri, handler, filename, filesize), null); + else if (!string.IsNullOrEmpty(reason)) + return (null, reason); } } - - catch (Exception e) + finally { - Config.Log.Warn(e, $"Error sniffing {m.Groups["dropbox_link"].Value}"); + BufferPool.Return(buf); } } + + catch (Exception e) + { + Config.Log.Warn(e, $"Error sniffing {m.Groups["dropbox_link"].Value}"); + } } return (null, null); } diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/GenericLinkHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/GenericLinkHandler.cs index 53c06089..fb9b4b1c 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/GenericLinkHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/GenericLinkHandler.cs @@ -28,51 +28,50 @@ internal sealed class GenericLinkHandler : BaseSourceHandler using var client = HttpClientFactory.Create(); foreach (Match m in matches) { - if (m.Groups["link"].Value is string lnk - && !string.IsNullOrEmpty(lnk) - && Uri.TryCreate(lnk, UriKind.Absolute, out var uri) - && !"tty.log".Equals(m.Groups["filename"].Value, StringComparison.InvariantCultureIgnoreCase)) + if (m.Groups["link"].Value is not { Length: > 0 } lnk + || !Uri.TryCreate(lnk, UriKind.Absolute, out var uri) + || "tty.log".Equals(m.Groups["filename"].Value, StringComparison.InvariantCultureIgnoreCase)) + continue; + + try { + var host = uri.Host; + var filename = Path.GetFileName(lnk); + var filesize = -1; + + using (var request = new HttpRequestMessage(HttpMethod.Head, uri)) + { + using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Config.Cts.Token); + if (response.Content.Headers.ContentLength > 0) + filesize = (int)response.Content.Headers.ContentLength.Value; + if (response.Content.Headers.ContentDisposition?.FileNameStar is {Length: >0} fname) + filename = fname; + uri = response.RequestMessage?.RequestUri; + } + + await using var stream = await client.GetStreamAsync(uri).ConfigureAwait(false); + var buf = BufferPool.Rent(SnoopBufferSize); try { - var host = uri.Host; - var filename = Path.GetFileName(lnk); - var filesize = -1; - - using (var request = new HttpRequestMessage(HttpMethod.Head, uri)) + var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false); + foreach (var handler in handlers) { - using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Config.Cts.Token); - if (response.Content.Headers.ContentLength > 0) - filesize = (int)response.Content.Headers.ContentLength.Value; - if (response.Content.Headers.ContentDisposition?.FileNameStar is string fname && !string.IsNullOrEmpty(fname)) - filename = fname; - uri = response.RequestMessage?.RequestUri; - } - - await using var stream = await client.GetStreamAsync(uri).ConfigureAwait(false); - var buf = BufferPool.Rent(SnoopBufferSize); - try - { - var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false); - foreach (var handler in handlers) - { - var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read)); - if (canHandle) - return (new GenericSource(uri, handler, host, filename, filesize), null); - else if (!string.IsNullOrEmpty(reason)) - return (null, reason); - } - } - finally - { - BufferPool.Return(buf); + var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read)); + if (canHandle) + return (new GenericSource(uri, handler, host, filename, filesize), null); + else if (!string.IsNullOrEmpty(reason)) + return (null, reason); } } - catch (Exception e) + finally { - Config.Log.Warn(e, $"Error sniffing {m.Groups["link"].Value}"); + BufferPool.Return(buf); } } + catch (Exception e) + { + Config.Log.Warn(e, $"Error sniffing {m.Groups["link"].Value}"); + } } return (null, null); } diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/GoogleDriveHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/GoogleDriveHandler.cs index d6caa1dc..05577458 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/GoogleDriveHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/GoogleDriveHandler.cs @@ -39,42 +39,38 @@ internal sealed class GoogleDriveHandler: BaseSourceHandler { try { - if (m.Groups["gdrive_id"].Value is string fid - && !string.IsNullOrEmpty(fid)) + if (m.Groups["gdrive_id"].Value is not { Length: > 0 } fid) + continue; + + var fileInfoRequest = client.Files.Get(fid); + fileInfoRequest.Fields = "name, size, kind"; + var fileMeta = await fileInfoRequest.ExecuteAsync(Config.Cts.Token).ConfigureAwait(false); + if (fileMeta is not { Kind: "drive#file", Size: > 0 }) + continue; + + var buf = BufferPool.Rent(SnoopBufferSize); + try { - var fileInfoRequest = client.Files.Get(fid); - fileInfoRequest.Fields = "name, size, kind"; - var fileMeta = await fileInfoRequest.ExecuteAsync(Config.Cts.Token).ConfigureAwait(false); - if (fileMeta.Kind == "drive#file" && fileMeta.Size > 0) - { - var buf = BufferPool.Rent(SnoopBufferSize); - try - { - int read; - await using (var stream = new MemoryStream(buf, true)) - { - var limit = Math.Min(SnoopBufferSize, fileMeta.Size.Value) - 1; - var progress = await fileInfoRequest.DownloadRangeAsync(stream, new RangeHeaderValue(0, limit), Config.Cts.Token).ConfigureAwait(false); - if (progress.Status != DownloadStatus.Completed) - continue; + await using var stream = new MemoryStream(buf, true); + var limit = Math.Min(SnoopBufferSize, fileMeta.Size.Value) - 1; + var progress = await fileInfoRequest.DownloadRangeAsync(stream, new RangeHeaderValue(0, limit), Config.Cts.Token).ConfigureAwait(false); + if (progress.Status != DownloadStatus.Completed) + continue; - read = (int)progress.BytesDownloaded; - } - foreach (var handler in handlers) - { - var (canHandle, reason) = handler.CanHandle(fileMeta.Name, (int)fileMeta.Size, buf.AsSpan(0, read)); - if (canHandle) - return (new GoogleDriveSource(client, fileInfoRequest, fileMeta, handler), null); - else if (!string.IsNullOrEmpty(reason)) - return(null, reason); - } - } - finally - { - BufferPool.Return(buf); - } + var read = (int)progress.BytesDownloaded; + foreach (var handler in handlers) + { + var (canHandle, reason) = handler.CanHandle(fileMeta.Name, (int)fileMeta.Size, buf.AsSpan(0, read)); + if (canHandle) + return (new GoogleDriveSource(client, fileInfoRequest, fileMeta, handler), null); + else if (!string.IsNullOrEmpty(reason)) + return(null, reason); } } + finally + { + BufferPool.Return(buf); + } } catch (Exception e) { diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/MediafireHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/MediafireHandler.cs index caaf07fd..834f936f 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/MediafireHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/MediafireHandler.cs @@ -31,56 +31,55 @@ internal sealed class MediafireHandler : BaseSourceHandler using var client = HttpClientFactory.Create(); foreach (Match m in matches) { - if (m.Groups["mediafire_link"].Value is string lnk - && !string.IsNullOrEmpty(lnk) - && Uri.TryCreate(lnk, UriKind.Absolute, out var webLink)) + if (m.Groups["mediafire_link"].Value is not { Length: > 0 } lnk + || !Uri.TryCreate(lnk, UriKind.Absolute, out var webLink)) + continue; + + try { + var filename = m.Groups["filename"].Value; + var filesize = -1; + + Config.Log.Debug($"Trying to get download link for {webLink}..."); + var directLink = await Client.GetDirectDownloadLinkAsync(webLink, Config.Cts.Token).ConfigureAwait(false); + if (directLink is null) + return (null, null); + + Config.Log.Debug($"Trying to get content size for {directLink}..."); + using (var request = new HttpRequestMessage(HttpMethod.Head, directLink)) + { + using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Config.Cts.Token); + if (response.Content.Headers.ContentLength > 0) + filesize = (int)response.Content.Headers.ContentLength.Value; + if (response.Content.Headers.ContentDisposition?.FileName is {Length: >0} fname) + filename = fname; + } + + Config.Log.Debug($"Trying to get content stream for {directLink}..."); + await using var stream = await client.GetStreamAsync(directLink).ConfigureAwait(false); + var buf = BufferPool.Rent(SnoopBufferSize); try { - var filename = m.Groups["filename"].Value; - var filesize = -1; - - Config.Log.Debug($"Trying to get download link for {webLink}..."); - var directLink = await Client.GetDirectDownloadLinkAsync(webLink, Config.Cts.Token).ConfigureAwait(false); - if (directLink is null) - return (null, null); - - Config.Log.Debug($"Trying to get content size for {directLink}..."); - using (var request = new HttpRequestMessage(HttpMethod.Head, directLink)) + var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false); + foreach (var handler in handlers) { - using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Config.Cts.Token); - if (response.Content.Headers.ContentLength > 0) - filesize = (int)response.Content.Headers.ContentLength.Value; - if (response.Content.Headers.ContentDisposition?.FileName is string fname && !string.IsNullOrEmpty(fname)) - filename = fname; - } - - Config.Log.Debug($"Trying to get content stream for {directLink}..."); - await using var stream = await client.GetStreamAsync(directLink).ConfigureAwait(false); - var buf = BufferPool.Rent(SnoopBufferSize); - try - { - var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false); - foreach (var handler in handlers) - { - var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read)); - if (canHandle) - return (new MediafireSource(directLink, handler, filename, filesize), null); - else if (!string.IsNullOrEmpty(reason)) - return (null, reason); - } - Config.Log.Debug("MediaFire Response:\n" + Encoding.UTF8.GetString(buf, 0, read)); - } - finally - { - BufferPool.Return(buf); + var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read)); + if (canHandle) + return (new MediafireSource(directLink, handler, filename, filesize), null); + else if (!string.IsNullOrEmpty(reason)) + return (null, reason); } + Config.Log.Debug("MediaFire Response:\n" + Encoding.UTF8.GetString(buf, 0, read)); } - catch (Exception e) + finally { - Config.Log.Warn(e, $"Error sniffing {m.Groups["mediafire_link"].Value}"); + BufferPool.Return(buf); } } + catch (Exception e) + { + Config.Log.Warn(e, $"Error sniffing {m.Groups["mediafire_link"].Value}"); + } } return (null, null); } diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/MegaHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/MegaHandler.cs index 4a1d3838..bd769b46 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/MegaHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/MegaHandler.cs @@ -33,34 +33,32 @@ internal sealed class MegaHandler : BaseSourceHandler { try { - if (m.Groups["mega_link"].Value is string lnk - && !string.IsNullOrEmpty(lnk) - && Uri.TryCreate(lnk, UriKind.Absolute, out var uri)) + if (m.Groups["mega_link"].Value is not { Length: > 0 } lnk + || !Uri.TryCreate(lnk, UriKind.Absolute, out var uri)) + continue; + + var node = await client.GetNodeFromLinkAsync(uri).ConfigureAwait(false); + if (node.Type is not NodeType.File) + continue; + + var buf = BufferPool.Rent(SnoopBufferSize); + try { - var node = await client.GetNodeFromLinkAsync(uri).ConfigureAwait(false); - if (node.Type == NodeType.File) + await using var stream = await client.DownloadAsync(uri, Doodad, Config.Cts.Token).ConfigureAwait(false); + var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false); + foreach (var handler in handlers) { - var buf = BufferPool.Rent(SnoopBufferSize); - try - { - int read; - await using (var stream = await client.DownloadAsync(uri, Doodad, Config.Cts.Token).ConfigureAwait(false)) - read = await stream.ReadBytesAsync(buf).ConfigureAwait(false); - foreach (var handler in handlers) - { - var (canHandle, reason) = handler.CanHandle(node.Name, (int)node.Size, buf.AsSpan(0, read)); - if (canHandle) - return (new MegaSource(client, uri, node, handler), null); - else if (!string.IsNullOrEmpty(reason)) - return (null, reason); - } - } - finally - { - BufferPool.Return(buf); - } + var (canHandle, reason) = handler.CanHandle(node.Name, (int)node.Size, buf.AsSpan(0, read)); + if (canHandle) + return (new MegaSource(client, uri, node, handler), null); + else if (!string.IsNullOrEmpty(reason)) + return (null, reason); } } + finally + { + BufferPool.Return(buf); + } } catch (Exception e) { diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/OneDriveSourceHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/OneDriveSourceHandler.cs index f1dbbdc5..6bcd2a5a 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/OneDriveSourceHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/OneDriveSourceHandler.cs @@ -32,42 +32,39 @@ internal sealed class OneDriveSourceHandler : BaseSourceHandler { try { - if (m.Groups["onedrive_link"].Value is string lnk - && !string.IsNullOrEmpty(lnk) - && Uri.TryCreate(lnk, UriKind.Absolute, out var uri) - && await Client.ResolveContentLinkAsync(uri, Config.Cts.Token).ConfigureAwait(false) is DriveItemMeta itemMeta - && itemMeta.ContentDownloadUrl is string downloadUrl) + if (m.Groups["onedrive_link"].Value is not { Length: > 0 } lnk + || !Uri.TryCreate(lnk, UriKind.Absolute, out var uri) + || await Client.ResolveContentLinkAsync(uri, Config.Cts.Token).ConfigureAwait(false) is not { ContentDownloadUrl: { Length: > 0 } downloadUrl } itemMeta) + continue; + try { + var filename = itemMeta.Name ?? ""; + var filesize = itemMeta.Size; + uri = new(downloadUrl); + + await using var stream = await httpClient.GetStreamAsync(uri).ConfigureAwait(false); + var buf = BufferPool.Rent(SnoopBufferSize); try { - var filename = itemMeta.Name ?? ""; - var filesize = itemMeta.Size; - uri = new Uri(downloadUrl); - - await using var stream = await httpClient.GetStreamAsync(uri).ConfigureAwait(false); - var buf = BufferPool.Rent(SnoopBufferSize); - try + var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false); + foreach (var handler in handlers) { - var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false); - foreach (var handler in handlers) - { - var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read)); - if (canHandle) - return (new OneDriveSource(uri, handler, filename, filesize), null); - else if (!string.IsNullOrEmpty(reason)) - return (null, reason); - } - } - finally - { - BufferPool.Return(buf); + var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read)); + if (canHandle) + return (new OneDriveSource(uri, handler, filename, filesize), null); + else if (!string.IsNullOrEmpty(reason)) + return (null, reason); } } - catch (Exception e) + finally { - Config.Log.Warn(e, $"Error sniffing {m.Groups["link"].Value}"); + BufferPool.Return(buf); } } + catch (Exception e) + { + Config.Log.Warn(e, $"Error sniffing {m.Groups["link"].Value}"); + } } catch (Exception e) { diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/PastebinHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/PastebinHandler.cs index 7ed588f5..0a27278f 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/PastebinHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/PastebinHandler.cs @@ -29,31 +29,30 @@ internal sealed class PastebinHandler : BaseSourceHandler { try { - if (m.Groups["pastebin_id"].Value is string pid - && !string.IsNullOrEmpty(pid)) + if (m.Groups["pastebin_id"].Value is not { Length: > 0 } pid) + continue; + + var uri = new Uri("https://pastebin.com/raw/" + pid); + await using var stream = await client.GetStreamAsync(uri).ConfigureAwait(false); + var buf = BufferPool.Rent(SnoopBufferSize); + try { - var uri = new Uri("https://pastebin.com/raw/" + pid); - await using var stream = await client.GetStreamAsync(uri).ConfigureAwait(false); - var buf = BufferPool.Rent(SnoopBufferSize); - try + var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false); + var filename = pid + ".log"; + var filesize = stream.CanSeek ? (int)stream.Length : 0; + foreach (var handler in handlers) { - var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false); - var filename = pid + ".log"; - var filesize = stream.CanSeek ? (int)stream.Length : 0; - foreach (var handler in handlers) - { - var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read)); - if (canHandle) - return (new PastebinSource(uri, filename, filesize, handler), null); - else if (!string.IsNullOrEmpty(reason)) - return (null, reason); - } - } - finally - { - BufferPool.Return(buf); + var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read)); + if (canHandle) + return (new PastebinSource(uri, filename, filesize, handler), null); + else if (!string.IsNullOrEmpty(reason)) + return (null, reason); } } + finally + { + BufferPool.Return(buf); + } } catch (Exception e) { diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/YandexDiskHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/YandexDiskHandler.cs index d8363e86..1f9eb823 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/YandexDiskHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/YandexDiskHandler.cs @@ -29,49 +29,48 @@ internal sealed class YandexDiskHandler: BaseSourceHandler using var client = HttpClientFactory.Create(); foreach (Match m in matches) { - if (m.Groups["yadisk_link"].Value is string lnk - && !string.IsNullOrEmpty(lnk) - && Uri.TryCreate(lnk, UriKind.Absolute, out var webLink)) + if (m.Groups["yadisk_link"].Value is not { Length: > 0 } lnk + || !Uri.TryCreate(lnk, UriKind.Absolute, out var webLink)) + continue; + + try { + var filename = ""; + var filesize = -1; + + var resourceInfo = await Client.GetResourceInfoAsync(webLink, Config.Cts.Token).ConfigureAwait(false); + if (string.IsNullOrEmpty(resourceInfo?.File)) + return (null, null); + + if (resourceInfo.Size.HasValue) + filesize = resourceInfo.Size.Value; + if (!string.IsNullOrEmpty(resourceInfo.Name)) + filename = resourceInfo.Name; + + await using var stream = await client.GetStreamAsync(resourceInfo.File).ConfigureAwait(false); + var buf = BufferPool.Rent(SnoopBufferSize); try { - var filename = ""; - var filesize = -1; - - var resourceInfo = await Client.GetResourceInfoAsync(webLink, Config.Cts.Token).ConfigureAwait(false); - if (string.IsNullOrEmpty(resourceInfo?.File)) - return (null, null); - - if (resourceInfo.Size.HasValue) - filesize = resourceInfo.Size.Value; - if (!string.IsNullOrEmpty(resourceInfo.Name)) - filename = resourceInfo.Name; - - await using var stream = await client.GetStreamAsync(resourceInfo.File).ConfigureAwait(false); - var buf = BufferPool.Rent(SnoopBufferSize); - try + var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false); + foreach (var handler in handlers) { - var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false); - foreach (var handler in handlers) - { - var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read)); - if (canHandle) - return (new YaDiskSource(resourceInfo.File, handler, filename, filesize), null); - else if (!string.IsNullOrEmpty(reason)) - return (null, reason); - } - } - finally - { - BufferPool.Return(buf); + var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read)); + if (canHandle) + return (new YaDiskSource(resourceInfo.File, handler, filename, filesize), null); + else if (!string.IsNullOrEmpty(reason)) + return (null, reason); } } - - catch (Exception e) + finally { - Config.Log.Warn(e, $"Error sniffing {m.Groups["yadisk_link"].Value}"); + BufferPool.Return(buf); } } + + catch (Exception e) + { + Config.Log.Warn(e, $"Error sniffing {m.Groups["yadisk_link"].Value}"); + } } return (null, null); } diff --git a/CompatBot/EventHandlers/LogParsingHandler.cs b/CompatBot/EventHandlers/LogParsingHandler.cs index 4e34275b..a81162f3 100644 --- a/CompatBot/EventHandlers/LogParsingHandler.cs +++ b/CompatBot/EventHandlers/LogParsingHandler.cs @@ -136,8 +136,10 @@ public static class LogParsingHandler { botMsg = await botMsg.UpdateOrCreateMessageAsync(channel, embed: new DiscordEmbedBuilder { - Description = "Log analysis failed, most likely cause is a truncated/invalid log.\n" + - "Please run the game again and re-upload a new copy.", + Description = """ + Log analysis failed, most likely cause is a truncated/invalid log. + Please run the game again and re-upload a new copy. + """, Color = Config.Colors.LogResultFailed, } .AddAuthor(client, message, source) @@ -154,8 +156,8 @@ public static class LogParsingHandler { if (result.SelectedFilter is null) { - Config.Log.Error("Piracy was detectedin log, but no trigger provided"); - result.SelectedFilter = new Piracystring + Config.Log.Error("Piracy was detected in log, but no trigger provided"); + result.SelectedFilter = new() { String = "Unknown trigger, plz kick 13xforever", Actions = FilterAction.IssueWarning | FilterAction.RemoveContent, @@ -188,13 +190,14 @@ public static class LogParsingHandler try { botMsg = await botMsg.UpdateOrCreateMessageAsync(channel, - $"{message.Author.Mention}, please read carefully:\n" + - "🏴‍☠️ **Pirated content detected** 🏴‍☠️\n" + - "__You are being denied further support until you legally dump the game__.\n" + - "Please note that the RPCS3 community and its developers do not support piracy.\n" + - "Most of the issues with pirated dumps occur due to them being modified in some way " + - "that prevent them from working on RPCS3.\n" + - "If you need help obtaining valid working dump of the game you own, please read the quickstart guide at " + $""" + # 🏴‍☠️ **Pirated content detected** 🏴‍☠️ + {message.Author.Mention}, please read carefully: + __You are being denied further support until you legally dump the game__. + Please note that the RPCS3 community and its developers do not support piracy. + Most of the issues with pirated dumps occur due to them being modified in some way that prevent them from working on RPCS3. + If you need help obtaining valid working dump of the game you own, please read [the quickstart guide](). + """ ).ConfigureAwait(false); } catch (Exception e) @@ -233,8 +236,7 @@ public static class LogParsingHandler if (isHelpChannel) await botMsg.UpdateOrCreateMessageAsync( channel, - $"{message.Author.Mention} please describe the issue if you require help, " + - $"or upload log in {botSpamChannel.Mention} if you only need to check your logs automatically" + $"{message.Author.Mention} please describe the issue if you require help, or upload log in {botSpamChannel.Mention} if you only need to check your logs automatically" ).ConfigureAwait(false); else { @@ -278,7 +280,11 @@ public static class LogParsingHandler { case "TXT": { - await channel.SendMessageAsync($"{message.Author.Mention} Please upload the full RPCS3.log.gz (or RPCS3.log with a zip/rar icon) file after closing the emulator instead of copying the logs from RPCS3's interface, as it doesn't contain all the required information.").ConfigureAwait(false); + await channel.SendMessageAsync( + $"{message.Author.Mention}, please upload the full RPCS3.log.gz (or RPCS3.log with a zip/rar icon) file " + + "after closing the emulator instead of copying the logs from RPCS3's interface, " + + "as it doesn't contain all the required information." + ).ConfigureAwait(false); Config.TelemetryClient?.TrackRequest(nameof(LogParsingHandler), start, DateTimeOffset.UtcNow - start, HttpStatusCode.BadRequest.ToString(), true); return; } @@ -398,7 +404,7 @@ public static class LogParsingHandler private static DiscordEmbedBuilder GetAnalyzingMsgEmbed(DiscordClient client) { var indicator = client.GetEmoji(":kannamag:", Config.Reactions.PleaseWait); - return new DiscordEmbedBuilder + return new() { Description = $"{indicator} Looking at the log, please wait... {indicator}", Color = Config.Colors.LogUnknown, diff --git a/CompatBot/EventHandlers/NewBuildsMonitor.cs b/CompatBot/EventHandlers/NewBuildsMonitor.cs index 79a3fdf4..287b8da2 100644 --- a/CompatBot/EventHandlers/NewBuildsMonitor.cs +++ b/CompatBot/EventHandlers/NewBuildsMonitor.cs @@ -24,9 +24,8 @@ internal static class NewBuildsMonitor if (args.Author.IsBotSafeCheck() && !args.Author.IsCurrent && "github".Equals(args.Channel.Name, StringComparison.InvariantCultureIgnoreCase) - && args.Message.Embeds.FirstOrDefault() is DiscordEmbed embed - && !string.IsNullOrEmpty(embed.Title) - && BuildResult.IsMatch(embed.Title) + && args.Message?.Embeds is [{ Title: { Length: > 0 } title }, ..] + && BuildResult.IsMatch(title) ) { Config.Log.Info("Found new PR merge message"); diff --git a/CompatBot/EventHandlers/PostLogHelpHandler.cs b/CompatBot/EventHandlers/PostLogHelpHandler.cs index 5bc188c7..fccbc6d8 100644 --- a/CompatBot/EventHandlers/PostLogHelpHandler.cs +++ b/CompatBot/EventHandlers/PostLogHelpHandler.cs @@ -20,8 +20,8 @@ internal static class PostLogHelpHandler private static readonly TimeSpan ThrottlingThreshold = TimeSpan.FromSeconds(5); private static readonly Dictionary DefaultExplanation = new() { - ["log"] = new Explanation { Text = "To upload log, run the game, then completely close RPCS3, then drag and drop rpcs3.log.gz from the RPCS3 folder into Discord. The file may have a zip or rar icon." }, - ["vulkan-1"] = new Explanation { Text = "Please remove all the traces of video drivers using DDU, and then reinstall the latest driver version for your GPU." }, + ["log"] = new() { Text = "To upload log, run the game, then completely close RPCS3, then drag and drop rpcs3.log.gz from the RPCS3 folder into Discord. The file may have a zip or rar icon." }, + ["vulkan-1"] = new() { Text = "Please remove all the traces of video drivers using DDU, and then reinstall the latest driver version for your GPU." }, }; private static DateTime lastMention = DateTime.UtcNow.AddHours(-1); diff --git a/CompatBot/EventHandlers/ThumbnailCacheMonitor.cs b/CompatBot/EventHandlers/ThumbnailCacheMonitor.cs index e24648f2..56def344 100644 --- a/CompatBot/EventHandlers/ThumbnailCacheMonitor.cs +++ b/CompatBot/EventHandlers/ThumbnailCacheMonitor.cs @@ -21,7 +21,7 @@ internal static class ThumbnailCacheMonitor await using var db = new ThumbnailDb(); var thumb = db.Thumbnail.FirstOrDefault(i => i.ContentId == args.Message.Content); - if (thumb?.EmbeddableUrl is string url && !string.IsNullOrEmpty(url) && args.Message.Attachments.Any(a => a.Url == url)) + if (thumb is { EmbeddableUrl: { Length: > 0 } url } && args.Message.Attachments.Any(a => a.Url == url)) { thumb.EmbeddableUrl = null; await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false); diff --git a/CompatBot/EventHandlers/UnknownCommandHandler.cs b/CompatBot/EventHandlers/UnknownCommandHandler.cs index 7da1e85b..25535d6a 100644 --- a/CompatBot/EventHandlers/UnknownCommandHandler.cs +++ b/CompatBot/EventHandlers/UnknownCommandHandler.cs @@ -15,8 +15,10 @@ namespace CompatBot.EventHandlers; internal static class UnknownCommandHandler { - private static readonly Regex BinaryQuestion = new(@"^\s*(am I|(are|is|do(es)|did|can(?!\s+of\s+)|should|must|have)(n't)?|shall|shan't|may|will|won't)\b", - RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase); + private static readonly Regex BinaryQuestion = new( + @"^\s*(am I|(are|is|do(es)|did|can(?!\s+of\s+)|should|must|have)(n't)?|shall|shan't|may|will|won't)\b", + RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase + ); public static Task OnError(CommandsNextExtension cne, CommandErrorEventArgs e) { diff --git a/CompatBot/EventHandlers/UsernameZalgoMonitor.cs b/CompatBot/EventHandlers/UsernameZalgoMonitor.cs index d076b9b5..952cc776 100644 --- a/CompatBot/EventHandlers/UsernameZalgoMonitor.cs +++ b/CompatBot/EventHandlers/UsernameZalgoMonitor.cs @@ -29,7 +29,10 @@ public static class UsernameZalgoMonitor { var suggestedName = StripZalgo(m.DisplayName, m.Username, m.Id).Sanitize(); await c.ReportAsync("🔣 Potential display name issue", - $"User {m.GetMentionWithNickname()} has changed their __username__ and is now shown as **{m.DisplayName.Sanitize()}**\nAutomatically renamed to: **{suggestedName}**", + $""" + User {m.GetMentionWithNickname()} has changed their __username__ and is now shown as **{m.DisplayName.Sanitize()}** + Automatically renamed to: **{suggestedName}** + """, null, ReportSeverity.Low); await DmAndRenameUserAsync(c, m, suggestedName).ConfigureAwait(false); @@ -60,7 +63,10 @@ public static class UsernameZalgoMonitor { var suggestedName = StripZalgo(name, fallback, args.Member.Id).Sanitize(); await c.ReportAsync("🔣 Potential display name issue", - $"Member {member.GetMentionWithNickname()} has changed their __display name__ and is now shown as **{name.Sanitize()}**\nAutomatically renamed to: **{suggestedName}**", + $""" + Member {member.GetMentionWithNickname()} has changed their __display name__ and is now shown as **{name.Sanitize()}** + Automatically renamed to: **{suggestedName}** + """, null, ReportSeverity.Low); await DmAndRenameUserAsync(c, member, suggestedName).ConfigureAwait(false); @@ -81,7 +87,10 @@ public static class UsernameZalgoMonitor { var suggestedName = StripZalgo(name, args.Member.Username, args.Member.Id).Sanitize(); await c.ReportAsync("🔣 Potential display name issue", - $"New member joined the server: {args.Member.GetMentionWithNickname()} and is shown as **{name.Sanitize()}**\nAutomatically renamed to: **{suggestedName}**", + $""" + New member joined the server: {args.Member.GetMentionWithNickname()} and is shown as **{name.Sanitize()}** + Automatically renamed to: **{suggestedName}** + """, null, ReportSeverity.Low); await DmAndRenameUserAsync(c, args.Member, suggestedName).ConfigureAwait(false); @@ -106,9 +115,11 @@ public static class UsernameZalgoMonitor var renameTask = member.ModifyAsync(m => m.Nickname = suggestedName); Config.Log.Info($"Renamed {member.Username}#{member.Discriminator} ({member.Id}) to {suggestedName}"); var rulesChannel = await client.GetChannelAsync(Config.BotRulesChannelId).ConfigureAwait(false); - var msg = $"Hello, your current _display name_ is breaking {rulesChannel.Mention} #7, so you have been renamed to `{suggestedName}`.\n" + - "I'm not perfect and can't clean all the junk in names in some cases, so change your nickname at your discretion.\n" + - "You can change your _display name_ by clicking on the server name at the top left and selecting **Change Nickname**."; + var msg = $""" + Hello, your current _display name_ is breaking {rulesChannel.Mention} #7, so you have been renamed to `{suggestedName}`. + I'm not perfect and can't clean all the junk in names in some cases, so change your nickname at your discretion. + You can change your _display name_ by clicking on the server name at the top left and selecting **Change Nickname**. + """; var dm = await member.CreateDmChannelAsync().ConfigureAwait(false); await dm.SendMessageAsync(msg).ConfigureAwait(false); await renameTask.ConfigureAwait(false); diff --git a/CompatBot/ThumbScrapper/GameTdbScraper.cs b/CompatBot/ThumbScrapper/GameTdbScraper.cs index 0aeb3236..e9188ef3 100644 --- a/CompatBot/ThumbScrapper/GameTdbScraper.cs +++ b/CompatBot/ThumbScrapper/GameTdbScraper.cs @@ -20,7 +20,10 @@ internal static class GameTdbScraper { private static readonly HttpClient HttpClient = HttpClientFactory.Create(new CompressionMessageHandler()); private static readonly Uri TitleDownloadLink = new("https://www.gametdb.com/ps3tdb.zip?LANG=EN"); - private static readonly Regex CoverArtLink = new(@"(?https?://art\.gametdb\.com/ps3/cover(?!full)[/\w\d]+\.jpg(\?\d+)?)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.ExplicitCapture); + private static readonly Regex CoverArtLink = new( + @"(?https?://art\.gametdb\.com/ps3/cover(?!full)[/\w\d]+\.jpg(\?\d+)?)", + RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.ExplicitCapture + ); //private static readonly List PreferredOrder = new List{"coverHQ", "coverM", "cover"}; public static async Task RunAsync(CancellationToken cancellationToken) @@ -47,10 +50,14 @@ internal static class GameTdbScraper try { var html = await HttpClient.GetStringAsync("https://www.gametdb.com/PS3/" + productCode).ConfigureAwait(false); - var coverLinks = CoverArtLink.Matches(html).Select(m => m.Groups["cover_link"].Value).Distinct().Where(l => l.Contains(productCode, StringComparison.InvariantCultureIgnoreCase)).ToList(); - return coverLinks.FirstOrDefault(l => l.Contains("coverHQ", StringComparison.InvariantCultureIgnoreCase)) ?? - coverLinks.FirstOrDefault(l => l.Contains("coverM", StringComparison.InvariantCultureIgnoreCase)) ?? - coverLinks.FirstOrDefault(); + var coverLinks = CoverArtLink.Matches(html) + .Select(m => m.Groups["cover_link"].Value) + .Distinct() + .Where(l => l.Contains(productCode, StringComparison.InvariantCultureIgnoreCase)) + .ToList(); + return coverLinks.FirstOrDefault(l => l.Contains("coverHQ", StringComparison.InvariantCultureIgnoreCase)) + ?? coverLinks.FirstOrDefault(l => l.Contains("coverM", StringComparison.InvariantCultureIgnoreCase)) + ?? coverLinks.FirstOrDefault(); } catch (Exception e) { diff --git a/CompatBot/ThumbScrapper/PsnScraper.cs b/CompatBot/ThumbScrapper/PsnScraper.cs index 2521f2f1..7e469f99 100644 --- a/CompatBot/ThumbScrapper/PsnScraper.cs +++ b/CompatBot/ThumbScrapper/PsnScraper.cs @@ -17,7 +17,10 @@ namespace CompatBot.ThumbScrapper; internal sealed class PsnScraper { private static readonly PsnClient.Client Client = new(); - public static readonly Regex ContentIdMatcher = new(@"(?(?(?\w\w)(?\d{4}))-(?(?\w{4})(?\d{5}))_(?\d\d)-(?