Merge branch 'vnext'

This commit is contained in:
13xforever
2026-01-30 19:23:26 +05:00

View File

@@ -1,18 +1,17 @@
using CompatApiClient.Utils; using System.Threading.Channels;
using CompatApiClient.Utils;
using CompatBot.Commands; using CompatBot.Commands;
using CompatBot.Database; using CompatBot.Database;
using CompatBot.Database.Providers; using CompatBot.Database.Providers;
using CompatBot.Ocr; using CompatBot.Ocr;
using CompatBot.Utils.Extensions; using CompatBot.Utils.Extensions;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using System.Collections.Concurrent;
namespace CompatBot.EventHandlers; namespace CompatBot.EventHandlers;
internal sealed class MediaScreenshotMonitor internal sealed class MediaScreenshotMonitor
{ {
private static readonly SemaphoreSlim WorkSemaphore = new(0); private static readonly Channel<(DiscordMessage msg, string imgUrl)> WorkQueue = Channel.CreateUnbounded<(DiscordMessage msg, string imgUrl)>();
private static readonly ConcurrentQueue<(DiscordMessage msg, string imgUrl)> WorkQueue = new();
private static readonly MemoryCache RemovedMessages = new(new MemoryCacheOptions() { ExpirationScanFrequency = TimeSpan.FromMinutes(10) }); private static readonly MemoryCache RemovedMessages = new(new MemoryCacheOptions() { ExpirationScanFrequency = TimeSpan.FromMinutes(10) });
private static readonly TimeSpan CachedTime = TimeSpan.FromMinutes(5); private static readonly TimeSpan CachedTime = TimeSpan.FromMinutes(5);
public DiscordClient Client { get; internal set; } = null!; public DiscordClient Client { get; internal set; } = null!;
@@ -50,15 +49,8 @@ internal sealed class MediaScreenshotMonitor
.ToList(); .ToList();
foreach (var url in images) foreach (var url in images)
{ {
try if (!WorkQueue.Writer.TryWrite((message, url)))
{ Config.Log.Warn($"Failed to create a new text recognition task for message {message.JumpLink} / {url}");
WorkQueue.Enqueue((message, url));
WorkSemaphore.Release();
}
catch (Exception ex)
{
Config.Log.Warn(ex, "Failed to create a new text recognition task");
}
} }
} }
@@ -69,33 +61,30 @@ internal sealed class MediaScreenshotMonitor
do do
{ {
await WorkSemaphore.WaitAsync(Config.Cts.Token).ConfigureAwait(false); MaxQueueLength = Math.Max(MaxQueueLength, WorkQueue.Reader.Count);
var (msg, imgUrl) = await WorkQueue.Reader.ReadAsync(Config.Cts.Token).ConfigureAwait(false);
if (Config.Cts.IsCancellationRequested) if (Config.Cts.IsCancellationRequested)
return; return;
MaxQueueLength = Math.Max(MaxQueueLength, WorkQueue.Count); if (RemovedMessages.TryGetValue(msg.Id, out bool removed) && removed)
if (!WorkQueue.TryDequeue(out var item))
continue;
if (RemovedMessages.TryGetValue(item.msg.Id, out bool removed) && removed)
continue; continue;
try try
{ {
var signature = GetSignature(item.msg); var signature = GetSignature(msg);
var prefix = $"[{item.msg.Id % 100:00}]"; var prefix = $"[{msg.Id % 100:00}]";
if (RemovedMessages.TryGetValue(signature, out (Piracystring hit, DiscordMessage msg) previousItem)) if (RemovedMessages.TryGetValue(signature, out (Piracystring hit, DiscordMessage msg) previousItem))
{ {
Config.Log.Debug($"{prefix} OCR result of message {item.msg.JumpLink} from user {item.msg.Author?.Username} ({item.msg.Author?.Id}):"); Config.Log.Debug($"{prefix} OCR result of message {msg.JumpLink} from user {msg.Author?.Username} ({msg.Author?.Id}):");
var ocrTextBuf = new StringBuilder($"OCR result of message <{item.msg.JumpLink}>:").AppendLine(); var ocrTextBuf = new StringBuilder($"OCR result of message <{msg.JumpLink}>:").AppendLine();
FilterAction suppressFlags = 0; FilterAction suppressFlags = 0;
if ("media".Equals(item.msg.Channel?.Name)) if ("media".Equals(msg.Channel?.Name))
{ {
suppressFlags = FilterAction.SendMessage | FilterAction.ShowExplain; suppressFlags = FilterAction.SendMessage | FilterAction.ShowExplain;
} }
await ContentFilter.PerformFilterActions( await ContentFilter.PerformFilterActions(
Client, Client,
item.msg, msg,
previousItem.hit, previousItem.hit,
suppressFlags, suppressFlags,
$"Matched to previously removed message from {previousItem.msg.Author?.Mention}: {previousItem.msg.JumpLink}", $"Matched to previously removed message from {previousItem.msg.Author?.Mention}: {previousItem.msg.JumpLink}",
@@ -103,18 +92,18 @@ internal sealed class MediaScreenshotMonitor
"Screenshot of an undesirable content" "Screenshot of an undesirable content"
).ConfigureAwait(false); ).ConfigureAwait(false);
if (previousItem.hit.Actions.HasFlag(FilterAction.RemoveContent)) if (previousItem.hit.Actions.HasFlag(FilterAction.RemoveContent))
RemovedMessages.Set(item.msg.Id, true, CachedTime); RemovedMessages.Set(msg.Id, true, CachedTime);
} }
else if (await OcrProvider.GetTextAsync(item.imgUrl, Config.Cts.Token).ConfigureAwait(false) is ({ Length: > 0 } result, var confidence)) else if (await OcrProvider.GetTextAsync(imgUrl, Config.Cts.Token).ConfigureAwait(false) is ({ Length: > 0 } result, var confidence))
{ {
var cnt = true; var cnt = true;
var duplicates = new HashSet<string>(); var duplicates = new HashSet<string>();
Config.Log.Debug($""" Config.Log.Debug($"""
{prefix} OCR result of message {item.msg.JumpLink} from user {item.msg.Author?.Username} ({item.msg.Author?.Id}) ({confidence * 100:0.00}%): {prefix} OCR result of message {msg.JumpLink} from user {msg.Author?.Username} ({msg.Author?.Id}) ({confidence * 100:0.00}%):
{result} {result}
""" """
); );
var ocrTextBuf = new StringBuilder($"OCR result of message <{item.msg.JumpLink}> ({confidence * 100:0.00}%):").AppendLine() var ocrTextBuf = new StringBuilder($"OCR result of message <{msg.JumpLink}> ({confidence * 100:0.00}%):").AppendLine()
.AppendLine(result.Sanitize()); .AppendLine(result.Sanitize());
if (cnt if (cnt
&& confidence > 0.65 && confidence > 0.65
@@ -122,13 +111,13 @@ internal sealed class MediaScreenshotMonitor
&& duplicates.Add(hit.String)) && duplicates.Add(hit.String))
{ {
FilterAction suppressFlags = 0; FilterAction suppressFlags = 0;
if ("media".Equals(item.msg.Channel?.Name)) if ("media".Equals(msg.Channel?.Name))
{ {
suppressFlags = FilterAction.SendMessage | FilterAction.ShowExplain; suppressFlags = FilterAction.SendMessage | FilterAction.ShowExplain;
} }
await ContentFilter.PerformFilterActions( await ContentFilter.PerformFilterActions(
Client, Client,
item.msg, msg,
hit, hit,
suppressFlags, suppressFlags,
result, result,
@@ -137,9 +126,9 @@ internal sealed class MediaScreenshotMonitor
).ConfigureAwait(false); ).ConfigureAwait(false);
if (hit.Actions.HasFlag(FilterAction.RemoveContent)) if (hit.Actions.HasFlag(FilterAction.RemoveContent))
{ {
RemovedMessages.Set(item.msg.Id, true, CachedTime); RemovedMessages.Set(msg.Id, true, CachedTime);
if (signature is { Length: >0}) if (signature is { Length: >0})
RemovedMessages.Set(signature, (hit, item.msg), CachedTime); RemovedMessages.Set(signature, (hit, msg), CachedTime);
} }
cnt &= !hit.Actions.HasFlag(FilterAction.RemoveContent) && !hit.Actions.HasFlag(FilterAction.IssueWarning); cnt &= !hit.Actions.HasFlag(FilterAction.RemoveContent) && !hit.Actions.HasFlag(FilterAction.IssueWarning);
} }