mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 09:48:26 -04:00
231 lines
6.9 KiB
C#
231 lines
6.9 KiB
C#
using System.Collections.Concurrent;
|
|
using System.Net;
|
|
using System.Threading.Tasks;
|
|
using Discord;
|
|
using Discord.Net;
|
|
using LinqToDB;
|
|
using LinqToDB.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using NadekoBot.Common.ModuleBehaviors;
|
|
using NadekoBot.Extensions;
|
|
using NadekoBot.Services;
|
|
|
|
namespace NadekoBot.Modules.Searches;
|
|
|
|
public sealed class TranslateService : ITranslateService, ILateExecutor, IReadyExecutor, INService
|
|
{
|
|
private readonly IGoogleApiService _google;
|
|
private readonly DbService _db;
|
|
private readonly IEmbedBuilderService _eb;
|
|
private readonly Bot _bot;
|
|
|
|
private readonly ConcurrentDictionary<ulong, bool> _atcs = new();
|
|
private readonly ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, (string From, string To)>> _users = new();
|
|
|
|
public TranslateService(IGoogleApiService google,
|
|
DbService db,
|
|
IEmbedBuilderService eb,
|
|
Bot bot)
|
|
{
|
|
_google = google;
|
|
_db = db;
|
|
_eb = eb;
|
|
_bot = bot;
|
|
}
|
|
|
|
public async Task OnReadyAsync()
|
|
{
|
|
var ctx = _db.GetDbContext();
|
|
|
|
var guilds = _bot.AllGuildConfigs.Select(x => x.GuildId).ToList();
|
|
var cs = await ctx.AutoTranslateChannels
|
|
.Include(x => x.Users)
|
|
.Where(x => guilds.Contains(x.GuildId))
|
|
.ToListAsyncEF();
|
|
|
|
foreach (var c in cs)
|
|
{
|
|
_atcs[c.ChannelId] = c.AutoDelete;
|
|
_users[c.ChannelId] = new(c.Users.ToDictionary(x => x.UserId, x => (x.Source.ToLower(), x.Target.ToLower())));
|
|
}
|
|
}
|
|
|
|
|
|
public async Task LateExecute(IGuild guild, IUserMessage msg)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(msg.Content))
|
|
return;
|
|
|
|
if (msg is { Channel: ITextChannel tch } um)
|
|
{
|
|
if (!_atcs.TryGetValue(tch.Id, out var autoDelete))
|
|
return;
|
|
|
|
if (!_users.TryGetValue(tch.Id, out var users)
|
|
|| !users.TryGetValue(um.Author.Id, out var langs))
|
|
return;
|
|
|
|
var output = await _google.Translate(msg.Content, langs.From, langs.To);
|
|
|
|
if (string.IsNullOrWhiteSpace(output)
|
|
|| msg.Content.Equals(output, StringComparison.InvariantCultureIgnoreCase))
|
|
return;
|
|
|
|
var embed = _eb.Create()
|
|
.WithOkColor();
|
|
|
|
if (autoDelete)
|
|
{
|
|
embed
|
|
.WithAuthor(um.Author.ToString(), um.Author.GetAvatarUrl())
|
|
.AddField(langs.From, um.Content)
|
|
.AddField(langs.To, output);
|
|
|
|
await tch.EmbedAsync(embed);
|
|
|
|
try
|
|
{
|
|
await um.DeleteAsync();
|
|
}
|
|
catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.Forbidden)
|
|
{
|
|
_atcs.TryUpdate(tch.Id, false, true);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
await um.ReplyAsync(embed: embed
|
|
.AddField(langs.To, output)
|
|
.Build(),
|
|
allowedMentions: AllowedMentions.None);
|
|
}
|
|
}
|
|
|
|
public async Task<string> Translate(string source, string target, string text = null)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(text))
|
|
throw new ArgumentException("Text is empty or null", nameof(text));
|
|
|
|
var res = await _google.Translate(text, source, target).ConfigureAwait(false);
|
|
return res.SanitizeMentions(true);
|
|
}
|
|
|
|
public async Task<bool> ToggleAtl(ulong guildId, ulong channelId, bool autoDelete)
|
|
{
|
|
var ctx = _db.GetDbContext();
|
|
|
|
var old = await ctx.AutoTranslateChannels
|
|
.ToLinqToDBTable()
|
|
.FirstOrDefaultAsyncLinqToDB(x => x.ChannelId == channelId);
|
|
|
|
if (old is null)
|
|
{
|
|
ctx.AutoTranslateChannels
|
|
.Add(new()
|
|
{
|
|
GuildId = guildId,
|
|
ChannelId = channelId,
|
|
AutoDelete = autoDelete,
|
|
});
|
|
|
|
await ctx.SaveChangesAsync();
|
|
|
|
_atcs[channelId] = autoDelete;
|
|
_users[channelId] = new();
|
|
|
|
return true;
|
|
}
|
|
|
|
// if autodelete value is different, update the autodelete value
|
|
// instead of disabling
|
|
if (old.AutoDelete != autoDelete)
|
|
{
|
|
old.AutoDelete = autoDelete;
|
|
await ctx.SaveChangesAsync();
|
|
_atcs[channelId] = autoDelete;
|
|
return true;
|
|
}
|
|
|
|
await ctx.AutoTranslateChannels
|
|
.ToLinqToDBTable()
|
|
.DeleteAsync(x => x.ChannelId == channelId);
|
|
|
|
await ctx.SaveChangesAsync();
|
|
_atcs.TryRemove(channelId, out _);
|
|
_users.TryRemove(channelId, out _);
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
private void UpdateUser(ulong channelId, ulong userId, string from, string to)
|
|
{
|
|
var dict = _users.GetOrAdd(channelId, new ConcurrentDictionary<ulong, (string, string)>());
|
|
dict[userId] = (from, to);
|
|
}
|
|
|
|
public async Task<bool?> RegisterUserAsync(ulong userId, ulong channelId, string from, string to)
|
|
{
|
|
if (!_google.Languages.ContainsKey(from) || !_google.Languages.ContainsKey(to))
|
|
return null;
|
|
|
|
var ctx = _db.GetDbContext();
|
|
var ch = await ctx.AutoTranslateChannels
|
|
.GetByChannelId(channelId);
|
|
|
|
if (ch is null)
|
|
return null;
|
|
|
|
var user = ch.Users
|
|
.FirstOrDefault(x => x.UserId == userId);
|
|
|
|
if (user is null)
|
|
{
|
|
ch.Users.Add(user = new()
|
|
{
|
|
Source = from,
|
|
Target = to,
|
|
UserId = userId,
|
|
});
|
|
|
|
await ctx.SaveChangesAsync();
|
|
|
|
UpdateUser(channelId, userId, from, to);
|
|
|
|
return true;
|
|
}
|
|
|
|
// if it's different from old settings, update
|
|
if (user.Source != from || user.Target != to)
|
|
{
|
|
user.Source = from;
|
|
user.Target = to;
|
|
|
|
await ctx.SaveChangesAsync();
|
|
|
|
UpdateUser(channelId, userId, from, to);
|
|
|
|
return true;
|
|
}
|
|
|
|
return await UnregisterUser(channelId, userId);
|
|
}
|
|
|
|
public async Task<bool> UnregisterUser(ulong channelId, ulong userId)
|
|
{
|
|
var ctx = _db.GetDbContext();
|
|
var rows = await ctx.AutoTranslateUsers
|
|
.ToLinqToDBTable()
|
|
.DeleteAsync(x => x.UserId == userId &&
|
|
x.Channel.ChannelId == channelId);
|
|
|
|
if (_users.TryGetValue(channelId, out var inner))
|
|
inner.TryRemove(userId, out _);
|
|
|
|
await ctx.SaveChangesAsync();
|
|
return rows > 0;
|
|
}
|
|
|
|
public IEnumerable<string> GetLanguages() => _google.Languages.Select(x => x.Key);
|
|
} |