300 lines
10 KiB
Text
300 lines
10 KiB
Text
@using System.Net.Mime
|
|
@inject MediaService MediaService
|
|
@inject ModalService ModalService
|
|
@inject IMessageService MessageService
|
|
@inject NavigationManager NavigationManager
|
|
@inject ILogger<MediaEditor> Logger
|
|
|
|
<Flex Direction="FlexDirection.Vertical" Gap="FlexGap.Large" Style="width: 100%" Class="media-editor">
|
|
<Table @ref="ResultsTable" TItem="Media" DataSource="@Values" RowKey="c => c.Id" @bind-SelectedRows="Selected" HidePagination="true" Responsive>
|
|
<TitleTemplate>
|
|
<Flex Justify="FlexJustify.End" Align="FlexAlign.Center" Gap="@("10")">
|
|
@if (Selected.Any())
|
|
{
|
|
<span>@Selected.Count() selected</span>
|
|
}
|
|
<Popconfirm Disabled="!Selected.Any()" OnConfirm="DeleteAll" Title="Are you sure you want to delete all selected media?">
|
|
<Button Disabled="!Selected.Any()" Danger>Delete</Button>
|
|
</Popconfirm>
|
|
</Flex>
|
|
</TitleTemplate>
|
|
<ColumnDefinitions Context="row">
|
|
<Selection Type="SelectionType.Checkbox" />
|
|
<PropertyColumn Property="p => p.Id" Title="Preview" Width="100px" Align="ColumnAlign.Center">
|
|
@if (MediaService.FileExists(row))
|
|
{
|
|
string originalPath = $"/api/Media/{row.Id}/Download?fileId={row.FileId}";
|
|
string thumbnailPath = row.Thumbnail != null
|
|
? $"/api/Media/{row.Thumbnail?.Id}/Download?fileId={row.Thumbnail?.FileId}"
|
|
: $"/api/Media/{row.Id}/Thumbnail?fileId={row.FileId}";
|
|
|
|
if (row.Type == MediaType.Manual)
|
|
{
|
|
<Image Width="100px" Src="@thumbnailPath" PreviewVisible="false" OnClick="() => OpenManual(row)" />
|
|
}
|
|
else
|
|
{
|
|
<Image Width="100px" Src="@thumbnailPath" PreviewSrc="@originalPath" />
|
|
}
|
|
}
|
|
</PropertyColumn>
|
|
<PropertyColumn Property="p => p.Type">
|
|
<Select @key="row.Id" @bind-Value="row.Type" TItem="MediaType" TItemValue="MediaType" DataSource="AllowedMediaTypes" />
|
|
</PropertyColumn>
|
|
<PropertyColumn Property="p => p.Name">
|
|
@if (row.Type == MediaType.Manual)
|
|
{
|
|
<Input @bind-Value="row.Name" OnBlur="() => Update(row)" />
|
|
}
|
|
</PropertyColumn>
|
|
<ActionColumn>
|
|
<Flex Gap="FlexGap.Small" Justify="FlexJustify.End">
|
|
@{
|
|
var fileInputId = Guid.NewGuid();
|
|
}
|
|
<InputFile id="@fileInputId" OnChange="(e) => UploadMedia(e, row)" 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>
|
|
|
|
@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(row)" Type="ButtonType.Text" Icon="@IconType.Outline.Search"/>
|
|
}
|
|
|
|
<Popconfirm OnConfirm="() => RemoveMedia(row)" Title="Are you sure you want to delete this media?">
|
|
<Button Type="ButtonType.Text" Danger Icon="@IconType.Outline.Close"/>
|
|
</Popconfirm>
|
|
</Flex>
|
|
</ActionColumn>
|
|
</ColumnDefinitions>
|
|
</Table>
|
|
|
|
<GridRow Justify="RowJustify.End">
|
|
<GridCol>
|
|
<Button OnClick="AddMedia" Type="@ButtonType.Primary">Add Media</Button>
|
|
</GridCol>
|
|
</GridRow>
|
|
</Flex>
|
|
|
|
@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; }
|
|
|
|
IEnumerable<Media> Selected = new List<Media>();
|
|
ITable? ResultsTable;
|
|
|
|
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)
|
|
{
|
|
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>();
|
|
|
|
try
|
|
{
|
|
var types = Enum.GetValues<MediaType>();
|
|
var nextType = types.FirstOrDefault(t => !Values.Any(v => v.Type == t) && AllowedMediaTypes.Contains(t));
|
|
|
|
var defaultStorageLocation = await MediaService.GetDefaultStorageLocationAsync();
|
|
|
|
var media = new Media
|
|
{
|
|
GameId = GameId,
|
|
Type = nextType == MediaType.Icon && Values.Any(v => v.Type == MediaType.Icon) ? MediaType.Manual : nextType,
|
|
StorageLocationId = defaultStorageLocation.Id,
|
|
Crc32 = String.Empty
|
|
};
|
|
|
|
media = await MediaService.AddAsync(media);
|
|
|
|
Values.Add(await MediaService.GetAsync(media.Id));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageService.Error("Could not add new media!");
|
|
Logger.LogError(ex, "Could not add new media!");
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
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);
|
|
}
|
|
|
|
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;
|
|
|
|
if (media.Id == Guid.Empty)
|
|
{
|
|
media = await MediaService.WriteToFileAsync(media, e.File.OpenReadStream(maxAllowedSize: Settings.Media.MaxSize * 1024 * 1024));
|
|
|
|
await MediaService.AddAsync(media);
|
|
}
|
|
else
|
|
{
|
|
MediaService.DeleteLocalMediaFile(media);
|
|
|
|
media = await MediaService.WriteToFileAsync(media, e.File.OpenReadStream(maxAllowedSize: Settings.Media.MaxSize * 1024 * 1024));
|
|
|
|
await MediaService.UpdateAsync(media);
|
|
}
|
|
|
|
Values = await MediaService.GetAsync(m => m.GameId == media.GameId);
|
|
|
|
if (ValuesChanged.HasDelegate)
|
|
await ValuesChanged.InvokeAsync(Values);
|
|
}
|
|
|
|
private async Task DeleteAll()
|
|
{
|
|
if (!Selected.Any())
|
|
return;
|
|
|
|
Values = Values.Except(Selected).ToList();
|
|
await MediaService.DeleteRangeAsync(Selected);
|
|
|
|
Selected = [];
|
|
ResultsTable.ReloadData();
|
|
}
|
|
|
|
private async Task RemoveMedia(Media media)
|
|
{
|
|
Values.Remove(media);
|
|
|
|
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);
|
|
}
|
|
}
|