Files
ersatztv/ErsatzTV/Shared/MediaCard.razor
T
Jason DoveandGitHub 4d86250630 add jellyfin media source (#185)
* wip

* start to add jellyfin tables to db

* code cleanup

* finish adding jellyfin media source

* sync jellyfin libraries

* display list of jellyfin libraries

* toggle jellyfin library sync

* edit jellyfin path replacements

* noop jellyfin scanners

* get jellyfin admin user id on startup

* implement jellyfin disconnect

* add jellyfin libraries to list; start to query jellyfin library items

* code cleanup

* start to project jellyfin movies

* save new jellyfin movies to db

* basic jellyfin movie update

* load jellyfin actor artwork

* load jellyfin movie poster and fan art

* more jellyfin artwork fixes, sync audio streams

* jellyfin playback sort of works

* skip jellyfin movies that are inaccessible

* use ffprobe for jellyfin movie statistics

* code cleanup

* store jellyfin operating system

* more jellyfin movie updates

* update jellyfin movie poster and fan art

* add jellyfin tv types

* sync jellyfin shows

* sync jellyfin seasons

* sync jellyfin episodes

* remove missing jellyfin television items

* delete empty jellyfin seasons and shows

* fix jellyfin updates

* fix indexing jellyfin movie and show languages
2021-05-15 13:14:17 -05:00

154 lines
5.7 KiB
Plaintext

@using static LanguageExt.Prelude
@using ErsatzTV.Application.MediaCards
@using Unit = LanguageExt.Unit
@inject IMediator Mediator
<div class="@((ContainerClass ?? "media-card-container mr-6") + " pb-3")" id="@($"item_{Data.MediaItemId}")">
@if (SelectClicked.HasDelegate || !string.IsNullOrWhiteSpace(Link))
{
<div class="@(IsSelected ? DeleteClicked.HasDelegate ? "media-card-selected-delete" : "media-card-selected" : "")"
style="border-radius: 4px; position: relative;">
<MudPaper Class="@($"media-card {CardClass}")" Style="@ArtworkForItem()">
@if (string.IsNullOrWhiteSpace(Data.Poster))
{
<MudText Align="Align.Center" Typo="Typo.h1" Class="media-card-poster-placeholder mud-text-primary">
@GetPlaceholder(Data.SortTitle)
</MudText>
}
</MudPaper>
@if (IsSelected)
{
<div style="display: flex; height: 48px; left: 0; position: absolute; top: 0; width: 48px;">
<MudIcon Color="@SelectColor"
Icon="@Icons.Material.Filled.CheckBox"
Style="margin: auto"/>
</div>
}
<div class="media-card-overlay" style="">
<MudButton Link="@(IsSelectMode ? null : Link)"
Style="height: 100%; width: 100%"
OnClick="@(e => IsSelectMode || string.IsNullOrWhiteSpace(Link) ? SelectClicked.InvokeAsync(e) : Task.CompletedTask)">
</MudButton>
@if (SelectClicked.HasDelegate)
{
<MudIconButton Color="@SelectColor"
Icon="@(IsSelected ? Icons.Material.Filled.CheckBox : Icons.Material.Filled.CheckBoxOutlineBlank)"
Style="left: 0; position: absolute; top: 0;"
OnClick="@(e => SelectClicked.InvokeAsync(e))"/>
}
@if (AddToCollectionClicked.HasDelegate && !IsSelectMode)
{
<MudIconButton Color="Color.Tertiary"
Icon="@Icons.Material.Filled.PlaylistAdd"
Style="bottom: 0; left: 0; position: absolute;"
OnClick="@(() => AddToCollectionClicked.InvokeAsync(Data))"/>
}
@if (DeleteClicked.HasDelegate && !IsSelectMode)
{
<MudIconButton Color="Color.Error"
Icon="@Icons.Material.Filled.Delete"
Style="bottom: 0; position: absolute; right: 0;"
OnClick="@(() => DeleteClicked.InvokeAsync(Data))"/>
}
</div>
</div>
}
else
{
<MudPaper Class="@($"media-card {CardClass}")" Style="@ArtworkForItem()">
@if (string.IsNullOrWhiteSpace(Data.Poster))
{
<MudText Align="Align.Center" Typo="Typo.h1" Class="media-card-poster-placeholder mud-text-primary">
@GetPlaceholder(Data.SortTitle)
</MudText>
}
</MudPaper>
}
<MudText Align="Align.Center" Class="media-card-title" UserAttributes="@(new Dictionary<string, object> { { "title", Data.Title } })">
@(Title ?? Data.Title)
</MudText>
<MudText Typo="Typo.body2" Align="Align.Center" Class="mud-text-secondary">
@(Subtitle ?? Data.Subtitle)
</MudText>
</div>
@code {
[Parameter]
public MediaCardViewModel Data { get; set; }
[Parameter]
public string Link { get; set; }
[Parameter]
public EventCallback<Unit> DataRefreshed { get; set; }
[Parameter]
public string Placeholder { get; set; }
[Parameter]
public string Title { get; set; }
[Parameter]
public string Subtitle { get; set; }
[Parameter]
public string ContainerClass { get; set; }
[Parameter]
public string CardClass { get; set; }
[Parameter]
public ArtworkKind ArtworkKind { get; set; }
[Parameter]
public EventCallback<MediaCardViewModel> DeleteClicked { get; set; }
[Parameter]
public EventCallback<MediaCardViewModel> AddToCollectionClicked { get; set; }
[Parameter]
public EventCallback<MouseEventArgs> SelectClicked { get; set; }
[Parameter]
public bool IsSelectMode { get; set; }
[Parameter]
public bool IsSelected { get; set; }
[Parameter]
public Color SelectColor { get; set; } = Color.Tertiary;
[Parameter]
public bool IsRemoteArtwork { get; set; }
private string GetPlaceholder(string sortTitle)
{
if (Placeholder != null)
{
return Placeholder;
}
char first = Optional(sortTitle).Map(t => t.ToUpperInvariant().HeadOrNone()).Flatten().Match(head => head, () => ' ');
return char.IsDigit(first) || !char.IsLetter(first) ? "#" : first.ToString();
}
private string ArtworkForItem()
{
if (IsRemoteArtwork || Data.Poster?.StartsWith("http://") == true || Data.Poster?.StartsWith("https://") == true)
{
return $"position: relative; background-image: url({Data.Poster}); background-size: cover; background-position: center";
}
return string.IsNullOrWhiteSpace(Data.Poster)
? "position: relative"
: $"position: relative; background-image: url(/artwork/{PathForArtwork()}/{Data.Poster}); background-size: cover; background-position: center";
}
private string PathForArtwork() => ArtworkKind switch
{
ArtworkKind.Thumbnail => "thumbnails",
_ => "posters"
};
}