Allow media grabber dialog to show results from multiple groups. Show media type in media grabber dialog. Allow modification of search for media grabber dialog.

media
Pat Hartl 2023-11-02 19:27:50 -05:00
parent 499b0c910a
commit d51eab151a
7 changed files with 92 additions and 34 deletions

View File

@ -2,7 +2,7 @@
<div class="image-picker-images">
@foreach (var image in Images)
{
<div class="image-picker-image" style="width: @(Size)px; height: @(Size)px">
<div class="image-picker-image" style="width: @(Size)px; max-height: @(Size)px">
<input type="radio" id="image-picker-image-@image.Key" checked="@(Value == image.Key)" name="SelectedResult" @onchange="@(() => SelectionChanged(image.Key))" />
<label for="image-picker-image-@image.Key"></label>
<img src="@image.Value" />

View File

@ -3,9 +3,24 @@
@using LANCommander.Models;
@inject IMediaGrabberService MediaGrabberService
<Slider TValue="double" @bind-Value="Size" DefaultValue="200" Min="50" Max="400" />
<GridRow Justify="space-between">
<GridCol Span="6">
<Search @bind-Value="Search" OnSearch="(x) => GetResults(Type, x)" DefaultValue="@Search" />
</GridCol>
<GridCol Span="12"></GridCol>
<GridCol Span="6">
<Slider TValue="double" @bind-Value="Size" DefaultValue="200" Min="50" Max="400" />
</GridCol>
</GridRow>
<ImagePicker Size="Size" Images="Images" ValueChanged="OnImageSelected" />
@foreach (var group in Results)
{
<div class="media-grabber-group">
<h2>@group.First().Group</h2>
<ImagePicker Size="Size" Images="@group.ToDictionary(r => r.Id, r => r.ThumbnailUrl)" ValueChanged="OnImageSelected" />
</div>
}
@code {
[Parameter] public string Search { get; set; }
@ -15,16 +30,22 @@
double Size { get; set; } = 200;
IEnumerable<MediaGrabberResult> Results = new List<MediaGrabberResult>();
IEnumerable<IEnumerable<MediaGrabberResult>> Results = new List<List<MediaGrabberResult>>();
Dictionary<string, string> Images { get; set; } = new Dictionary<string, string>();
protected override async Task OnAfterRenderAsync(bool firstRender)
protected override async Task OnFirstAfterRenderAsync()
{
if (firstRender)
{
Results = await MediaGrabberService.SearchAsync(Options.Type, Options.Search);
Type = Options.Type;
Search = Options.Search;
Images = Results.ToDictionary(r => r.Id, r => r.ThumbnailUrl);
await GetResults(Type, Search);
}
private async Task GetResults(MediaType type, string search)
{
if (!String.IsNullOrWhiteSpace(search))
{
Results = (await MediaGrabberService.SearchAsync(type, search)).GroupBy(r => r.Group);
StateHasChanged();
}
@ -32,7 +53,7 @@
private void OnImageSelected(string key)
{
Media = Results.FirstOrDefault(r => r.Id == key);
Media = Results.SelectMany(g => g).FirstOrDefault(r => r.Id == key);
}
public override async Task OnFeedbackOkAsync(ModalClosingEventArgs args)

View File

@ -8,5 +8,6 @@ namespace LANCommander.Models
public MediaType Type { get; set; }
public string SourceUrl { get; set; }
public string ThumbnailUrl { get; set; }
public string Group { get; set; }
}
}

View File

@ -9,7 +9,7 @@
<PropertyColumn Property="p => p.Id" Title="Preview" Width="100px" Align="ColumnAlign.Center">
@if (MediaService.FileExists(context))
{
<Image Width="100px" Src="@($"/api/Media/{context.Id}/Download")" />
<Image Width="100px" Src="@($"/api/Media/{context.Id}/Download?fileId={context.FileId}")" />
}
</PropertyColumn>
<PropertyColumn Property="p => p.Type">
@ -53,7 +53,8 @@
Values.Add(new Media()
{
GameId = GameId
GameId = GameId,
Type = Enum.GetValues<MediaType>().ToList().FirstOrDefault(t => !Values.Any(v => v.Type == t))
});
}
@ -61,7 +62,7 @@
{
var modalOptions = new ModalOptions()
{
Title = "Search Media",
Title = $"Download {media.Type}",
Maximizable = false,
DefaultMaximized = true,
Closable = true,
@ -81,9 +82,19 @@
modalRef.Config.ConfirmLoading = true;
media.SourceUrl = result.SourceUrl;
media.FileId = await MediaService.DownloadMediaAsync(result.SourceUrl);
await MediaService.Add(media);
if (media.Id == Guid.Empty)
{
media.FileId = await MediaService.DownloadMediaAsync(result.SourceUrl);
await MediaService.Add(media);
}
else
{
MediaService.DeleteLocalMediaFile(media.FileId);
media.FileId = await MediaService.DownloadMediaAsync(result.SourceUrl);
await MediaService.Update(media);
}
Values = MediaService.Get(m => m.GameId == media.GameId).ToList();

View File

@ -18,63 +18,68 @@ namespace LANCommander.Services.MediaGrabbers
public async Task<IEnumerable<MediaGrabberResult>> SearchAsync(MediaType type, string keywords)
{
var games = await SteamGridDb.SearchForGamesAsync(keywords);
var results = new List<MediaGrabberResult>();
if (games.Length > 0)
foreach (var game in games)
{
var game = games.FirstOrDefault();
switch (type)
{
case MediaType.Icon:
return await GetIconsAsync(game.Id);
results.AddRange(await GetIconsAsync(game));
break;
case MediaType.Cover:
return await GetCoversAsync(game.Id);
results.AddRange(await GetCoversAsync(game));
break;
case MediaType.Background:
return await GetBackgroundsAsync(game.Id);
results.AddRange(await GetBackgroundsAsync(game));
break;
}
}
return new List<MediaGrabberResult>();
return results;
}
private async Task<IEnumerable<MediaGrabberResult>> GetIconsAsync(int gameId)
private async Task<IEnumerable<MediaGrabberResult>> GetIconsAsync(SteamGridDbGame game)
{
var icons = await SteamGridDb.GetIconsByGameIdAsync(gameId);
var icons = await SteamGridDb.GetIconsByGameIdAsync(game.Id);
return icons.Select(i => new MediaGrabberResult()
{
Id = i.Id.ToString(),
Type = MediaType.Icon,
SourceUrl = i.FullImageUrl,
ThumbnailUrl = i.ThumbnailImageUrl
ThumbnailUrl = i.ThumbnailImageUrl,
Group = game.Name
});
}
private async Task<IEnumerable<MediaGrabberResult>> GetCoversAsync(int gameId)
private async Task<IEnumerable<MediaGrabberResult>> GetCoversAsync(SteamGridDbGame game)
{
var covers = await SteamGridDb.GetGridsByGameIdAsync(gameId);
var covers = await SteamGridDb.GetGridsByGameIdAsync(game.Id);
return covers.Select(c => new MediaGrabberResult()
{
Id = c.Id.ToString(),
Type = MediaType.Cover,
SourceUrl = c.FullImageUrl,
ThumbnailUrl = c.ThumbnailImageUrl
ThumbnailUrl = c.ThumbnailImageUrl,
Group = game.Name
});
}
private async Task<IEnumerable<MediaGrabberResult>> GetBackgroundsAsync(int gameId)
private async Task<IEnumerable<MediaGrabberResult>> GetBackgroundsAsync(SteamGridDbGame game)
{
var backgrounds = await SteamGridDb.GetHeroesByGameIdAsync(gameId);
var backgrounds = await SteamGridDb.GetHeroesByGameIdAsync(game.Id);
return backgrounds.Select(b => new MediaGrabberResult()
{
Id = b.Id.ToString(),
Type = MediaType.Background,
SourceUrl = b.FullImageUrl,
ThumbnailUrl = b.ThumbnailImageUrl
ThumbnailUrl = b.ThumbnailImageUrl,
Group = game.Name
});
}
}

View File

@ -47,9 +47,18 @@ namespace LANCommander.Services
return Path.Combine(Settings.Media.StoragePath, entity.FileId.ToString());
}
public void DeleteLocalMediaFile(Guid fileId)
{
var path = Path.Combine(Settings.Media.StoragePath, fileId.ToString());
if (File.Exists(path))
File.Delete(path);
}
public async Task<Guid> DownloadMediaAsync(string sourceUrl)
{
var fileId = Guid.NewGuid();
var path = Path.Combine(Settings.Media.StoragePath, fileId.ToString());
using (var http = new HttpClient())

View File

@ -176,13 +176,11 @@
.image-picker-images {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
gap: 16px;
}
.image-picker-image {
position: relative;
aspect-ratio: 1/1;
display: flex;
align-items: center;
justify-content: center;
@ -218,6 +216,19 @@
max-height: 100px;
}
.media-grabber-group {
margin-top: 18px;
}
.media-grabber-group + .media-grabber-group {
padding-top: 16px;
border-top: 1px solid rgba(0, 0, 0, 0.85);
}
[data-theme="Dark"] .media-grabber-group + .media-grabber-group {
border-top: 1px solid rgba(255, 255, 255, 0.12);
}
@media screen and (min-width: 768px) {
.mobile-menu {
display: none;