@page "/media/tv/seasons/{SeasonId:int}" @using ErsatzTV.Application.MediaCards @using ErsatzTV.Application.MediaCollections @using ErsatzTV.Application.MediaItems @using ErsatzTV.Application.ProgramSchedules @using ErsatzTV.Application.Television @using ErsatzTV.Extensions @implements IDisposable @inject IMediator Mediator @inject ILogger Logger @inject ISnackbar Snackbar @inject IDialogService Dialog @inject NavigationManager NavigationManager @inject IJSRuntime JsRuntime
@if (!string.IsNullOrWhiteSpace(_season?.FanArt)) { if (_season.FanArt.StartsWith("http://") || _season.FanArt.StartsWith("https://")) { fan art } else { fan art } }
@if (!string.IsNullOrWhiteSpace(_season?.Poster)) { } @_season?.Title @_season?.Title @_season?.Name Add To Collection Add To Playlist Add To Schedule @foreach (TelevisionEpisodeCardViewModel episode in _data.Cards) { @if (!string.IsNullOrWhiteSpace(episode.Poster)) {
@if (episode.State == MediaItemState.FileNotFound) {
} else if (episode.State == MediaItemState.Unavailable) {
}
}
@episode.Episode. @episode.Title @episode.Plot Add To Collection Add To Playlist Show Media Info Troubleshoot Playback
@if (episode.State == MediaItemState.FileNotFound) {
File Not Found:  @episode.Path
} else if (episode.State == MediaItemState.Unavailable) {
Unavailable:  @episode.LocalPath
}
Released: @episode.Aired.ToShortDateString()
@if (episode.Directors.Any()) { var sorted = episode.Directors.OrderBy(w => w).ToList();
Directors:  @sorted.Head() @foreach (string director in sorted.Skip(1)) { @director }
} @if (episode.Writers.Any()) { var sorted = episode.Writers.OrderBy(w => w).ToList();
Writers:  @sorted.Head() @foreach (string writer in sorted.Skip(1)) { @writer }
}
}
@code { private CancellationTokenSource _cts; [Parameter] public int SeasonId { get; set; } private TelevisionSeasonViewModel _season; private static int PageSize => 100; private const int PageNumber = 1; private TelevisionEpisodeCardResultsViewModel _data = new(0, new List(), null); public void Dispose() { _cts?.Cancel(); _cts?.Dispose(); } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { try { await NavigationManager.NavigateToFragmentAsync(JsRuntime); } catch (Exception) { // ignored } } } protected override async Task OnParametersSetAsync() { _cts?.Cancel(); _cts?.Dispose(); _cts = new CancellationTokenSource(); var token = _cts.Token; try { await Mediator.Send(new GetTelevisionSeasonById(SeasonId), token).IfSomeAsync(vm => _season = vm); _data = await Mediator.Send(new GetTelevisionEpisodeCards(SeasonId, PageNumber, PageSize), token); } catch (OperationCanceledException) { // do nothing } } private async Task AddToCollection() { var parameters = new DialogParameters { { "EntityType", "season" }, { "EntityName", $"{_season.Title} - {_season.Name}" } }; var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall }; IDialogReference dialog = await Dialog.ShowAsync("Add To Collection", parameters, options); DialogResult result = await dialog.Result; if (result is { Canceled: false, Data: MediaCollectionViewModel collection }) { await Mediator.Send(new AddSeasonToCollection(collection.Id, SeasonId), _cts.Token); NavigationManager.NavigateTo($"media/collections/{collection.Id}"); } } private async Task AddToPlaylist() { var parameters = new DialogParameters { { "EntityType", "season" }, { "EntityName", $"{_season.Title} - {_season.Name}" } }; var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall }; IDialogReference dialog = await Dialog.ShowAsync("Add To Playlist", parameters, options); DialogResult result = await dialog.Result; if (result is { Canceled: false, Data: PlaylistViewModel playlist }) { await Mediator.Send(new AddSeasonToPlaylist(playlist.Id, SeasonId), _cts.Token); NavigationManager.NavigateTo($"media/playlists/{playlist.Id}"); } } private async Task AddToSchedule() { var parameters = new DialogParameters { { "EntityType", "season" }, { "EntityName", $"{_season.Title} - {_season.Name}" } }; var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall }; IDialogReference dialog = await Dialog.ShowAsync("Add To Schedule", parameters, options); DialogResult result = await dialog.Result; if (result is { Canceled: false, Data: ProgramScheduleViewModel schedule }) { await Mediator.Send(AddProgramScheduleItem.ForMediaItem(schedule.Id, CollectionType.TelevisionSeason, SeasonId), _cts.Token); NavigationManager.NavigateTo($"schedules/{schedule.Id}/items"); } } private async Task AddEpisodeToCollection(TelevisionEpisodeCardViewModel episode) { var parameters = new DialogParameters { { "EntityType", "episode" }, { "EntityName", episode.Title } }; var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall }; IDialogReference dialog = await Dialog.ShowAsync("Add To Collection", parameters, options); DialogResult result = await dialog.Result; if (result is { Canceled: false, Data: MediaCollectionViewModel collection }) { var request = new AddEpisodeToCollection(collection.Id, episode.EpisodeId); Either addResult = await Mediator.Send(request, _cts.Token); addResult.Match( Left: error => { Snackbar.Add($"Unexpected error adding episode to collection: {error.Value}"); Logger.LogError("Unexpected error adding episode to collection: {Error}", error.Value); }, Right: _ => Snackbar.Add($"Added {episode.Title} to collection {collection.Name}", Severity.Success)); } } private async Task AddEpisodeToPlaylist(TelevisionEpisodeCardViewModel episode) { var parameters = new DialogParameters { { "EntityType", "episode" }, { "EntityName", episode.Title } }; var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall }; IDialogReference dialog = await Dialog.ShowAsync("Add To Playlist", parameters, options); DialogResult result = await dialog.Result; if (result is { Canceled: false, Data: PlaylistViewModel playlist }) { var request = new AddEpisodeToPlaylist(playlist.Id, episode.EpisodeId); Either addResult = await Mediator.Send(request, _cts.Token); addResult.Match( Left: error => { Snackbar.Add($"Unexpected error adding episode to playlist: {error.Value}"); Logger.LogError("Unexpected error adding episode to playlist: {Error}", error.Value); }, Right: _ => Snackbar.Add($"Added {episode.Title} to playlist {playlist.Name}", Severity.Success)); } } private async Task ShowInfo(TelevisionEpisodeCardViewModel episode) { Either maybeInfo = await Mediator.Send(new GetMediaItemInfo(episode.EpisodeId)); foreach (BaseError error in maybeInfo.LeftToSeq()) { Snackbar.Add("Unexpected error loading media info"); Logger.LogError("Unexpected error loading media info: {Error}", error.Value); } foreach (MediaItemInfo info in maybeInfo.RightToSeq()) { var parameters = new DialogParameters { { "MediaItemInfo", info } }; var options = new DialogOptions { CloseButton = true, CloseOnEscapeKey = true, MaxWidth = MaxWidth.Medium, FullWidth = true }; IDialogReference dialog = await Dialog.ShowAsync( $"{episode.ShowTitle} - s{episode.Season:00}e{episode.Episode:00} - {episode.Title}", parameters, options); DialogResult _ = await dialog.Result; } } private static string GetPosterUrl(string poster) => poster.StartsWith("http://") || poster.StartsWith("https://") ? poster : $"artwork/posters/{poster}"; private static string GetThumbnailUrl(string poster) => poster.StartsWith("http://") || poster.StartsWith("https://") ? poster : $"artwork/thumbnails/{poster}"; }