169 lines
7.8 KiB
C#

using System.Text.RegularExpressions;
using CompatBot.Database;
using CompatBot.Database.Providers;
using DSharpPlus.Commands.Processors.TextCommands;
namespace CompatBot.Commands;
internal static partial class Sudo
{
// '2018-06-09 08:20:44.968000 - '
// '2018-07-19T12:19:06.7888609Z - '
[GeneratedRegex(@"^(?<cutout>(?<date>\d{4}-\d\d-\d\d[ T][0-9:\.]+Z?) - )", RegexOptions.ExplicitCapture | RegexOptions.Singleline)]
private static partial Regex Timestamp();
[GeneratedRegex(@"(?<id><#\d+>)", RegexOptions.ExplicitCapture | RegexOptions.Singleline)]
private static partial Regex Channel();
[Command("fix"), RequiresDm]
[Description("Commands to fix various stuff")]
internal static class Fix
{
[Command("timestamps")]
[Description("Fix `timestamp` column in the `warning` table")]
public static async ValueTask Timestamps(TextCommandContext ctx)
{
try
{
var @fixed = 0;
await using var wdb = await BotDb.OpenWriteAsync().ConfigureAwait(false);
foreach (var warning in wdb.Warning)
if (!string.IsNullOrEmpty(warning.FullReason))
{
var match = Timestamp().Match(warning.FullReason);
if (match.Success && DateTime.TryParse(match.Groups["date"].Value, out var timestamp))
{
warning.Timestamp = timestamp.Ticks;
warning.FullReason = warning.FullReason[(match.Groups["cutout"].Value.Length)..];
@fixed++;
}
}
await wdb.SaveChangesAsync().ConfigureAwait(false);
await ctx.Channel.SendMessageAsync($"Fixed {@fixed} records").ConfigureAwait(false);
}
catch (Exception e)
{
Config.Log.Warn(e, "Couldn't fix warning timestamps");
await ctx.Channel.SendMessageAsync("Failed to fix warning timestamps").ConfigureAwait(false);
}
}
[Command("channels")]
[Description("Fixes channel mentions in `warning` table")]
public static async ValueTask Channels(TextCommandContext ctx)
{
try
{
var @fixed = 0;
await using var wdb = await BotDb.OpenWriteAsync().ConfigureAwait(false);
foreach (var warning in wdb.Warning)
{
var newReason = await FixChannelMentionAsync(ctx, warning.Reason).ConfigureAwait(false);
if (newReason != warning.Reason && newReason != null)
{
warning.Reason = newReason;
@fixed++;
}
}
await wdb.SaveChangesAsync().ConfigureAwait(false);
await ctx.Channel.SendMessageAsync($"Fixed {@fixed} records").ConfigureAwait(false);
}
catch (Exception e)
{
Config.Log.Warn(e, "Couldn't fix channel mentions");
await ctx.Channel.SendMessageAsync("Failed to fix warning timestamps").ConfigureAwait(false);
}
}
[Command("syscalls")]
[Description("Fixes invalid function names in `syscall-info` table and associated data")]
public static async ValueTask Syscalls(TextCommandContext ctx)
{
try
{
await ctx.Channel.SendMessageAsync("Fixing invalid function names…").ConfigureAwait(false);
var result = await SyscallInfoProvider.FixInvalidFunctionNamesAsync().ConfigureAwait(false);
if (result.funcs > 0)
await ctx.Channel.SendMessageAsync($"Successfully fixed {result.funcs} function name{(result.funcs == 1 ? "" : "s")} and {result.links} game link{(result.links == 1 ? "" : "s")}").ConfigureAwait(false);
else
await ctx.Channel.SendMessageAsync("No invalid syscall functions detected").ConfigureAwait(false);
await ctx.Channel.SendMessageAsync("Fixing duplicates…").ConfigureAwait(false);
result = await SyscallInfoProvider.FixDuplicatesAsync().ConfigureAwait(false);
if (result.funcs > 0)
await ctx.Channel.SendMessageAsync($"Successfully merged {result.funcs} function{(result.funcs == 1 ? "" : "s")} and {result.links} game link{(result.links == 1 ? "" : "s")}").ConfigureAwait(false);
else
await ctx.Channel.SendMessageAsync("No duplicate function entries found").ConfigureAwait(false);
}
catch (Exception e)
{
Config.Log.Warn(e, "Failed to fix syscall info");
await ctx.ReactWithAsync(Config.Reactions.Failure, "Failed to fix syscall information", true).ConfigureAwait(false);
}
}
[Command("title_marks"), TextAlias("trademarks", "tms")]
[Description("Strips trade marks and similar cruft from game titles in local database")]
public static async ValueTask TitleMarks(TextCommandContext ctx)
{
var changed = 0;
await using var wdb = await ThumbnailDb.OpenWriteAsync().ConfigureAwait(false);
foreach (var thumb in wdb.Thumbnail)
{
if (string.IsNullOrEmpty(thumb.Name))
continue;
var newTitle = thumb.Name.StripMarks();
if (newTitle.EndsWith("full game", StringComparison.OrdinalIgnoreCase))
newTitle = newTitle[..^10];
if (newTitle.EndsWith("full game unlock", StringComparison.OrdinalIgnoreCase))
newTitle = newTitle[..^17];
if (newTitle.EndsWith("downloadable game", StringComparison.OrdinalIgnoreCase))
newTitle = newTitle[..^18];
newTitle = newTitle.TrimEnd();
if (newTitle == thumb.Name)
continue;
changed++;
thumb.Name = newTitle;
}
await wdb.SaveChangesAsync();
await ctx.Channel.SendMessageAsync($"Fixed {changed} title{(changed == 1 ? "" : "s")}").ConfigureAwait(false);
}
[Command("metacritic_links"), TextAlias("mcl")]
[Description("Cleans up Metacritic links")]
public static async ValueTask MetacriticLinks(TextCommandContext ctx, [Description("Remove links for trial and demo versions only")] bool demosOnly = true)
{
var changed = 0;
await using var wdb = await ThumbnailDb.OpenWriteAsync().ConfigureAwait(false);
foreach (var thumb in wdb.Thumbnail.Where(t => t.MetacriticId != null))
{
if (demosOnly
&& thumb.Name != null
&& !CompatList.TrialNamePattern().IsMatch(thumb.Name))
continue;
thumb.MetacriticId = null;
changed++;
}
await wdb.SaveChangesAsync();
await ctx.Channel.SendMessageAsync($"Fixed {changed} title{(changed == 1 ? "" : "s")}").ConfigureAwait(false);
}
private static async ValueTask<string?> FixChannelMentionAsync(TextCommandContext ctx, string? msg)
{
if (msg is not {Length: >0})
return msg;
var entries = Channel().Matches(msg).Select(m => m.Groups["id"].Value).Distinct().ToList();
if (entries.Count is 0)
return msg;
foreach (var channel in entries)
if (await ctx.ParseChannelNameAsync(channel).ConfigureAwait(false) is {} ch)
msg = msg.Replace(channel, "#" + ch.Name);
return msg;
}
}
}