Iceshrimp.NET/Iceshrimp.Backend/Components/PublicPreview/Renderers/UserRenderer.cs
Laura Hausmann 9ff79c92e0
[backend/libmfm] Improve performance of AngleSharp calls for MFM-HTML conversion, improve UrlNode HTML representation
This makes sure the AngleSharp owner document is only created once per application lifecycle, and replaces all async calls with their synchronous counterparts (since the input is already loaded in memory, using async for this just creates overhead)
2025-03-24 18:05:21 +01:00

69 lines
No EOL
2.3 KiB
C#

using Iceshrimp.Backend.Components.PublicPreview.Schemas;
using Iceshrimp.Backend.Core.Configuration;
using Iceshrimp.Backend.Core.Database;
using Iceshrimp.Backend.Core.Database.Tables;
using Iceshrimp.Backend.Core.Extensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace Iceshrimp.Backend.Components.PublicPreview.Renderers;
public class UserRenderer(
DatabaseContext db,
MfmRenderer mfm,
IOptions<Config.InstanceSection> instance,
IOptionsSnapshot<Config.SecuritySection> security
) : IScopedService
{
public async Task<PreviewUser?> RenderOne(User? user)
{
if (user == null) return null;
var emoji = await GetEmojiAsync([user]);
return Render(user, emoji);
}
private PreviewUser Render(User user, Dictionary<string, List<Emoji>> emoji)
{
var mentions = user.UserProfile?.Mentions ?? [];
// @formatter:off
var res = new PreviewUser
{
Id = user.Id,
Username = user.Username,
Host = user.Host ?? instance.Value.AccountDomain,
Uri = user.GetUriOrPublicUri(instance.Value),
Url = user.UserProfile?.Url ?? user.Uri ?? user.PublicUrlPath,
AvatarUrl = user.GetAvatarUrl(instance.Value),
BannerUrl = user.GetBannerUrl(instance.Value),
RawDisplayName = user.DisplayName,
DisplayName = mfm.RenderSimple(user.DisplayName, user.Host, mentions, emoji[user.Id], "span"),
Bio = mfm.RenderSimple(user.UserProfile?.Description, user.Host, mentions, emoji[user.Id], "span"),
MovedToUri = user.MovedToUri
};
// @formatter:on
if (security.Value.PublicPreview is Enums.PublicPreview.RestrictedNoMedia)
{
res.AvatarUrl = user.IdenticonUrlPath;
res.BannerUrl = null;
}
return res;
}
private async Task<Dictionary<string, List<Emoji>>> GetEmojiAsync(List<User> users)
{
var ids = users.SelectMany(n => n.Emojis).Distinct().ToList();
if (ids.Count == 0) return users.ToDictionary<User, string, List<Emoji>>(p => p.Id, _ => []);
var emoji = await db.Emojis.Where(p => ids.Contains(p.Id)).ToListAsync();
return users.ToDictionary(p => p.Id, p => emoji.Where(e => p.Emojis.Contains(e.Id)).ToList());
}
public async Task<List<PreviewUser>> RenderManyAsync(List<User> users)
{
var emoji = await GetEmojiAsync(users);
return users.Select(p => Render(p, emoji)).ToList();
}
}