LANCommander/LANCommander.Server/UI/Pages/Games/Components/MediaEditor.razor

275 lines
9.7 KiB
Text

@using LANCommander.SDK.Enums
@using System.Net.Mime
@inject DatabaseServiceFactory DatabaseServiceFactory
@inject ModalService ModalService
@inject IMessageService MessageService
@inject NavigationManager NavigationManager
@inject ILogger<MediaEditor> Logger
<Space Direction="DirectionVHType.Vertical" Size="@("large")" Style="width: 100%" Class="media-editor">
<SpaceItem>
<Table TItem="Media" DataSource="@Values" HidePagination="true" Responsive>
<PropertyColumn Property="p => p.Id" Title="Preview" Width="100px" Align="ColumnAlign.Center">
@if (MediaService.FileExists(context))
{
if (context.Thumbnail != null && context.Type == MediaType.Manual)
{
<Image Width="100px" Src="@($"/api/Media/{context.Thumbnail.Id}/Download?fileId={context.Thumbnail.FileId}")" PreviewVisible="false" OnClick="() => OpenManual(context)" />
}
else if (context.Thumbnail != null)
{
<Image Width="100px" Src="@($"/api/Media/{context.Thumbnail.Id}/Download?fileId={context.Thumbnail.FileId}")" />
}
else if (context.Type != MediaType.Manual)
{
<Image Width="100px" Src="@($"/api/Media/{context.Id}/Download?fileId={context.FileId}")" />
}
}
</PropertyColumn>
<PropertyColumn Property="p => p.Type">
<Select @bind-Value="context.Type" TItem="MediaType" TItemValue="MediaType" DataSource="AllowedMediaTypes" />
</PropertyColumn>
<PropertyColumn Property="p => p.Name">
@if (context.Type == MediaType.Manual)
{
<Input @bind-Value="context.Name" OnBlur="() => Update(context)" />
}
</PropertyColumn>
<ActionColumn>
<Space Style="display: flex; justify-content: end">
<SpaceItem>
@{
var fileInputId = Guid.NewGuid();
}
<InputFile id="@fileInputId" OnChange="(e) => UploadMedia(e, context)" hidden accept=".jpg,.jpeg,.png,.gif,.pdf,.ico" />
<label class="ant-btn ant-btn-text ant-btn-icon-only" for="@fileInputId">
<Icon Type="@IconType.Outline.Upload" />
</label>
</SpaceItem>
<SpaceItem>
@if (String.IsNullOrWhiteSpace(Settings.Media.SteamGridDbApiKey))
{
<Popconfirm OnConfirm="() => NavigateToSettings()" Title="Invalid SteamGridDB credentials. Setup now?">
<Button Type="@ButtonType.Text" Icon="@IconType.Outline.Search" />
</Popconfirm>
}
else
{
<Button OnClick="() => SearchMedia(context)" Type="@ButtonType.Text" Icon="@IconType.Outline.Search" />
}
</SpaceItem>
<SpaceItem>
<Popconfirm OnConfirm="() => RemoveMedia(context)" Title="Are you sure you want to delete this media?">
<Button Type="@ButtonType.Text" Danger Icon="@IconType.Outline.Close" />
</Popconfirm>
</SpaceItem>
</Space>
</ActionColumn>
</Table>
</SpaceItem>
<SpaceItem>
<GridRow Justify="end">
<GridCol>
<Button OnClick="AddMedia" Type="@ButtonType.Primary">Add Media</Button>
</GridCol>
</GridRow>
</SpaceItem>
</Space>
@code {
[Parameter] public ICollection<Media> Values { get; set; } = new List<Media>();
[Parameter] public EventCallback<ICollection<Media>> ValuesChanged { get; set; }
[Parameter] public Guid GameId { get; set; }
[Parameter] public string GameTitle { get; set; }
Settings Settings = SettingService.GetSettings();
MediaType[] AllowedMediaTypes = new MediaType[]
{
MediaType.Icon,
MediaType.Cover,
MediaType.Background,
MediaType.Logo,
MediaType.Manual
};
MediaType[] SearchableMediaTypes = new MediaType[]
{
MediaType.Icon,
MediaType.Cover,
MediaType.Background,
MediaType.Logo,
MediaType.Manual
};
string[] ValidMimeTypes = new string[]
{
MediaTypeNames.Image.Png,
MediaTypeNames.Image.Jpeg,
MediaTypeNames.Image.Gif,
MediaTypeNames.Application.Pdf,
MediaTypeNames.Image.Icon
};
private async Task Update(Media media)
{
try
{
if (media.Id != Guid.Empty)
{
using (var mediaService = DatabaseServiceFactory.Create<MediaService>())
{
await mediaService.UpdateAsync(media);
}
MessageService.Success($"{media.Type} updated!");
}
}
catch (Exception ex)
{
MessageService.Error($"{media.Type} could not be updated.");
Logger.LogError(ex, $"{media.Type} could not be updated.");
}
}
private async Task AddMedia()
{
if (Values == null)
Values = new List<Media>();
var types = Enum.GetValues<MediaType>();
var nextType = types.FirstOrDefault(t => !Values.Any(v => v.Type == t) && AllowedMediaTypes.Contains(t));
Values.Add(new Media()
{
GameId = GameId,
Type = nextType == MediaType.Icon && Values.Any(v => v.Type == MediaType.Icon) ? MediaType.Manual : nextType
});
}
private async Task SearchMedia(Media media)
{
var modalOptions = new ModalOptions()
{
Title = $"Download {media.Type}",
Maximizable = false,
DefaultMaximized = true,
Closable = true,
OkText = "Select",
};
var grabberOptions = new MediaGrabberOptions()
{
Type = media.Type,
Search = GameTitle
};
var modalRef = await ModalService.CreateModalAsync<MediaGrabberDialog, MediaGrabberOptions, MediaGrabberResult>(modalOptions, grabberOptions);
modalRef.OnOk = async (result) =>
{
modalRef.Config.ConfirmLoading = true;
media.SourceUrl = result.SourceUrl;
media.MimeType = result.MimeType;
using (var mediaService = DatabaseServiceFactory.Create<MediaService>())
{
if (media.Id == Guid.Empty)
{
media = await mediaService.DownloadMediaAsync(result.SourceUrl, media);
await mediaService.AddAsync(media);
}
else
{
mediaService.DeleteLocalMediaFile(media);
media = await mediaService.DownloadMediaAsync(result.SourceUrl, media);
await mediaService.UpdateAsync(media);
}
Values = await mediaService.GetAsync(m => m.GameId == media.GameId);
if (ValuesChanged.HasDelegate)
await ValuesChanged.InvokeAsync(Values);
}
};
}
private async Task UploadMedia(InputFileChangeEventArgs e, Media media)
{
if (!ValidMimeTypes.Contains(e.File.ContentType))
{
MessageService.Error("Unsupported file type");
Logger.LogError($"Unsupported file type {e.File.ContentType}");
return;
}
if ((e.File.Size / 1024 / 1024) > Settings.Media.MaxSize)
{
MessageService.Error($"File size must be smaller than {Settings.Media.MaxSize}MB");
return;
}
media.SourceUrl = "";
media.MimeType = e.File.ContentType;
using (var mediaService = DatabaseServiceFactory.Create<MediaService>())
{
if (media.Id == Guid.Empty)
{
media = await mediaService.UploadMediaAsync(e.File.OpenReadStream(maxAllowedSize: Settings.Media.MaxSize * 1024 * 1024), media);
await mediaService.AddAsync(media);
}
else
{
mediaService.DeleteLocalMediaFile(media);
media = await mediaService.UploadMediaAsync(e.File.OpenReadStream(maxAllowedSize: Settings.Media.MaxSize * 1024 * 1024), media);
await mediaService.UpdateAsync(media);
}
Values = await mediaService.GetAsync(m => m.GameId == media.GameId);
if (ValuesChanged.HasDelegate)
await ValuesChanged.InvokeAsync(Values);
}
}
private async Task RemoveMedia(Media media)
{
Values.Remove(media);
using (var mediaService = DatabaseServiceFactory.Create<MediaService>())
{
if (media.Id != Guid.Empty)
await mediaService.DeleteAsync(media);
}
}
private async Task OpenManual(Media media)
{
var modalOptions = new ModalOptions()
{
Title = media.Name,
Maximizable = true,
DefaultMaximized = true,
Closable = true,
Footer = null,
Draggable = true,
Resizable = true,
WrapClassName = "pdf-reader-dialog",
};
var modalRef = await ModalService.CreateModalAsync<PdfReaderDialog, Media>(modalOptions, media);
}
private void NavigateToSettings()
{
NavigationManager.NavigateTo("/Settings/Media", true);
}
}