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.
parent
499b0c910a
commit
d51eab151a
|
@ -2,7 +2,7 @@
|
||||||
<div class="image-picker-images">
|
<div class="image-picker-images">
|
||||||
@foreach (var image in 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))" />
|
<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>
|
<label for="image-picker-image-@image.Key"></label>
|
||||||
<img src="@image.Value" />
|
<img src="@image.Value" />
|
||||||
|
|
|
@ -3,9 +3,24 @@
|
||||||
@using LANCommander.Models;
|
@using LANCommander.Models;
|
||||||
@inject IMediaGrabberService MediaGrabberService
|
@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 {
|
@code {
|
||||||
[Parameter] public string Search { get; set; }
|
[Parameter] public string Search { get; set; }
|
||||||
|
@ -15,16 +30,22 @@
|
||||||
|
|
||||||
double Size { get; set; } = 200;
|
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>();
|
Dictionary<string, string> Images { get; set; } = new Dictionary<string, string>();
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnFirstAfterRenderAsync()
|
||||||
{
|
{
|
||||||
if (firstRender)
|
Type = Options.Type;
|
||||||
{
|
Search = Options.Search;
|
||||||
Results = await MediaGrabberService.SearchAsync(Options.Type, 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();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
@ -32,7 +53,7 @@
|
||||||
|
|
||||||
private void OnImageSelected(string key)
|
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)
|
public override async Task OnFeedbackOkAsync(ModalClosingEventArgs args)
|
||||||
|
|
|
@ -8,5 +8,6 @@ namespace LANCommander.Models
|
||||||
public MediaType Type { get; set; }
|
public MediaType Type { get; set; }
|
||||||
public string SourceUrl { get; set; }
|
public string SourceUrl { get; set; }
|
||||||
public string ThumbnailUrl { get; set; }
|
public string ThumbnailUrl { get; set; }
|
||||||
|
public string Group { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<PropertyColumn Property="p => p.Id" Title="Preview" Width="100px" Align="ColumnAlign.Center">
|
<PropertyColumn Property="p => p.Id" Title="Preview" Width="100px" Align="ColumnAlign.Center">
|
||||||
@if (MediaService.FileExists(context))
|
@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>
|
||||||
<PropertyColumn Property="p => p.Type">
|
<PropertyColumn Property="p => p.Type">
|
||||||
|
@ -53,7 +53,8 @@
|
||||||
|
|
||||||
Values.Add(new Media()
|
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()
|
var modalOptions = new ModalOptions()
|
||||||
{
|
{
|
||||||
Title = "Search Media",
|
Title = $"Download {media.Type}",
|
||||||
Maximizable = false,
|
Maximizable = false,
|
||||||
DefaultMaximized = true,
|
DefaultMaximized = true,
|
||||||
Closable = true,
|
Closable = true,
|
||||||
|
@ -81,9 +82,19 @@
|
||||||
modalRef.Config.ConfirmLoading = true;
|
modalRef.Config.ConfirmLoading = true;
|
||||||
|
|
||||||
media.SourceUrl = result.SourceUrl;
|
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();
|
Values = MediaService.Get(m => m.GameId == media.GameId).ToList();
|
||||||
|
|
||||||
|
|
|
@ -18,63 +18,68 @@ namespace LANCommander.Services.MediaGrabbers
|
||||||
public async Task<IEnumerable<MediaGrabberResult>> SearchAsync(MediaType type, string keywords)
|
public async Task<IEnumerable<MediaGrabberResult>> SearchAsync(MediaType type, string keywords)
|
||||||
{
|
{
|
||||||
var games = await SteamGridDb.SearchForGamesAsync(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)
|
switch (type)
|
||||||
{
|
{
|
||||||
case MediaType.Icon:
|
case MediaType.Icon:
|
||||||
return await GetIconsAsync(game.Id);
|
results.AddRange(await GetIconsAsync(game));
|
||||||
|
break;
|
||||||
|
|
||||||
case MediaType.Cover:
|
case MediaType.Cover:
|
||||||
return await GetCoversAsync(game.Id);
|
results.AddRange(await GetCoversAsync(game));
|
||||||
|
break;
|
||||||
|
|
||||||
case MediaType.Background:
|
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()
|
return icons.Select(i => new MediaGrabberResult()
|
||||||
{
|
{
|
||||||
Id = i.Id.ToString(),
|
Id = i.Id.ToString(),
|
||||||
Type = MediaType.Icon,
|
Type = MediaType.Icon,
|
||||||
SourceUrl = i.FullImageUrl,
|
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()
|
return covers.Select(c => new MediaGrabberResult()
|
||||||
{
|
{
|
||||||
Id = c.Id.ToString(),
|
Id = c.Id.ToString(),
|
||||||
Type = MediaType.Cover,
|
Type = MediaType.Cover,
|
||||||
SourceUrl = c.FullImageUrl,
|
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()
|
return backgrounds.Select(b => new MediaGrabberResult()
|
||||||
{
|
{
|
||||||
Id = b.Id.ToString(),
|
Id = b.Id.ToString(),
|
||||||
Type = MediaType.Background,
|
Type = MediaType.Background,
|
||||||
SourceUrl = b.FullImageUrl,
|
SourceUrl = b.FullImageUrl,
|
||||||
ThumbnailUrl = b.ThumbnailImageUrl
|
ThumbnailUrl = b.ThumbnailImageUrl,
|
||||||
|
Group = game.Name
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,9 +47,18 @@ namespace LANCommander.Services
|
||||||
return Path.Combine(Settings.Media.StoragePath, entity.FileId.ToString());
|
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)
|
public async Task<Guid> DownloadMediaAsync(string sourceUrl)
|
||||||
{
|
{
|
||||||
var fileId = Guid.NewGuid();
|
var fileId = Guid.NewGuid();
|
||||||
|
|
||||||
var path = Path.Combine(Settings.Media.StoragePath, fileId.ToString());
|
var path = Path.Combine(Settings.Media.StoragePath, fileId.ToString());
|
||||||
|
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
|
|
|
@ -176,13 +176,11 @@
|
||||||
.image-picker-images {
|
.image-picker-images {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: space-evenly;
|
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-picker-image {
|
.image-picker-image {
|
||||||
position: relative;
|
position: relative;
|
||||||
aspect-ratio: 1/1;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -218,6 +216,19 @@
|
||||||
max-height: 100px;
|
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) {
|
@media screen and (min-width: 768px) {
|
||||||
.mobile-menu {
|
.mobile-menu {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
Loading…
Reference in New Issue