mirror of https://github.com/ErsatzTV/ErsatzTV.git
8 changed files with 269 additions and 2 deletions
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
using ErsatzTV.Core.Domain; |
||||
|
||||
namespace ErsatzTV.Application.MediaItems; |
||||
|
||||
public record MediaItemInfo( |
||||
int Id, |
||||
string Kind, |
||||
string LibraryKind, |
||||
string ServerName, |
||||
string LibraryName, |
||||
MediaItemState State, |
||||
TimeSpan Duration, |
||||
string SampleAspectRatio, |
||||
string DisplayAspectRatio, |
||||
string RFrameRate, |
||||
VideoScanKind VideoScanKind, |
||||
int Width, |
||||
int Height, |
||||
List<MediaItemInfoStream> Streams); |
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
using ErsatzTV.Core.Domain; |
||||
|
||||
namespace ErsatzTV.Application.MediaItems; |
||||
|
||||
public record MediaItemInfoStream( |
||||
int Index, |
||||
MediaStreamKind Kind, |
||||
string Title, |
||||
string Codec, |
||||
string Profile, |
||||
string Language, |
||||
int? Channels, |
||||
bool Default, |
||||
bool Forced, |
||||
bool AttachedPic, |
||||
string PixelFormat, |
||||
string ColorRange, |
||||
string ColorSpace, |
||||
string ColorTransfer, |
||||
string ColorPrimaries, |
||||
int BitsPerRawSample, |
||||
string FileName, |
||||
string MimeType); |
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
using ErsatzTV.Core; |
||||
|
||||
namespace ErsatzTV.Application.MediaItems; |
||||
|
||||
public record GetMediaItemInfo(int Id) : IRequest<Either<BaseError, MediaItemInfo>>; |
@ -0,0 +1,97 @@
@@ -0,0 +1,97 @@
|
||||
using ErsatzTV.Core; |
||||
using ErsatzTV.Core.Domain; |
||||
using ErsatzTV.Core.Extensions; |
||||
using ErsatzTV.Infrastructure.Data; |
||||
using ErsatzTV.Infrastructure.Extensions; |
||||
using Microsoft.EntityFrameworkCore; |
||||
|
||||
namespace ErsatzTV.Application.MediaItems; |
||||
|
||||
public class GetMediaItemInfoHandler : IRequestHandler<GetMediaItemInfo, Either<BaseError, MediaItemInfo>> |
||||
{ |
||||
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||
|
||||
public GetMediaItemInfoHandler(IDbContextFactory<TvContext> dbContextFactory) |
||||
{ |
||||
_dbContextFactory = dbContextFactory; |
||||
} |
||||
|
||||
public async Task<Either<BaseError, MediaItemInfo>> Handle( |
||||
GetMediaItemInfo request, |
||||
CancellationToken cancellationToken) |
||||
{ |
||||
try |
||||
{ |
||||
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); |
||||
|
||||
Option<MediaItemInfo> mediaItem = await dbContext.MediaItems |
||||
.AsNoTracking() |
||||
.Include(i => i.LibraryPath) |
||||
.ThenInclude(lp => lp.Library) |
||||
.ThenInclude(l => l.MediaSource) |
||||
// TODO: support all media types here
|
||||
.Include(i => (i as Movie).MediaVersions) |
||||
.ThenInclude(mv => mv.Streams) |
||||
.Include(i => (i as Episode).MediaVersions) |
||||
.ThenInclude(mv => mv.Streams) |
||||
.SelectOneAsync(i => i.Id, i => i.Id == request.Id) |
||||
.MapT(Project); |
||||
|
||||
return mediaItem.ToEither(BaseError.New("Unable to locate media item")); |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
return BaseError.New(ex.ToString()); |
||||
} |
||||
} |
||||
|
||||
private static MediaItemInfo Project(MediaItem mediaItem) |
||||
{ |
||||
MediaVersion version = mediaItem.GetHeadVersion(); |
||||
|
||||
string serverName = mediaItem.LibraryPath.Library.MediaSource switch |
||||
{ |
||||
PlexMediaSource plexMediaSource => plexMediaSource.ServerName, |
||||
EmbyMediaSource embyMediaSource => embyMediaSource.ServerName, |
||||
JellyfinMediaSource jellyfinMediaSource => jellyfinMediaSource.ServerName, |
||||
_ => null |
||||
}; |
||||
|
||||
return new MediaItemInfo( |
||||
mediaItem.Id, |
||||
mediaItem.GetType().Name, |
||||
mediaItem.LibraryPath.Library.GetType().Name, |
||||
serverName, |
||||
mediaItem.LibraryPath.Library.Name, |
||||
mediaItem.State, |
||||
version.Duration, |
||||
version.SampleAspectRatio, |
||||
version.DisplayAspectRatio, |
||||
version.RFrameRate, |
||||
version.VideoScanKind, |
||||
version.Width, |
||||
version.Height, |
||||
version.Streams.OrderBy(s => s.Index).Map(Project).ToList()); |
||||
} |
||||
|
||||
private static MediaItemInfoStream Project(MediaStream mediaStream) => |
||||
new( |
||||
mediaStream.Index, |
||||
mediaStream.MediaStreamKind, |
||||
mediaStream.Title, |
||||
mediaStream.Codec, |
||||
mediaStream.Profile, |
||||
mediaStream.Language, |
||||
mediaStream.Channels > 0 ? mediaStream.Channels : null, |
||||
mediaStream.Default, |
||||
mediaStream.Forced, |
||||
mediaStream.AttachedPic, |
||||
mediaStream.PixelFormat, |
||||
mediaStream.ColorRange, |
||||
mediaStream.ColorSpace, |
||||
mediaStream.ColorTransfer, |
||||
mediaStream.ColorPrimaries, |
||||
mediaStream.BitsPerRawSample, |
||||
mediaStream.FileName, |
||||
mediaStream.MimeType); |
||||
} |
@ -0,0 +1,62 @@
@@ -0,0 +1,62 @@
|
||||
@using ErsatzTV.Application.MediaItems |
||||
@using System.Text.Json |
||||
@using System.Text.Json.Serialization |
||||
@inject IJSRuntime JsRuntime |
||||
|
||||
<div> |
||||
<MudDialog> |
||||
<DialogContent> |
||||
<div class="overflow-y-scroll" style="max-height: 500px"> |
||||
<pre> |
||||
<code @ref="_infoView">@_info</code> |
||||
</pre> |
||||
</div> |
||||
</DialogContent> |
||||
<DialogActions> |
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="(() => CopyToClipboard(_infoView))"> |
||||
Copy |
||||
</MudButton> |
||||
<MudButton Color="Color.Primary" OnClick="Close">Close</MudButton> |
||||
</DialogActions> |
||||
</MudDialog> |
||||
</div> |
||||
|
||||
@code { |
||||
|
||||
[CascadingParameter] |
||||
MudDialogInstance MudDialog { get; set; } |
||||
|
||||
[Parameter] |
||||
public MediaItemInfo MediaItemInfo { get; set; } |
||||
|
||||
private string _info; |
||||
private ElementReference _infoView; |
||||
|
||||
protected override Task OnParametersSetAsync() |
||||
{ |
||||
try |
||||
{ |
||||
_info = JsonSerializer.Serialize( |
||||
MediaItemInfo, |
||||
new JsonSerializerOptions |
||||
{ |
||||
Converters = { new JsonStringEnumConverter() }, |
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, |
||||
WriteIndented = true |
||||
}); |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
_info = ex.ToString(); |
||||
} |
||||
|
||||
return Task.CompletedTask; |
||||
} |
||||
|
||||
private async Task CopyToClipboard(ElementReference view) |
||||
{ |
||||
await JsRuntime.InvokeVoidAsync("clipboardCopy.copyText", view); |
||||
} |
||||
|
||||
private void Close() => MudDialog.Close(DialogResult.Ok(true)); |
||||
} |
Loading…
Reference in new issue