@page "/blocks/{Id:int}" @using ErsatzTV.Application.MediaCollections @using ErsatzTV.Application.MediaItems @using ErsatzTV.Application.Scheduling @using ErsatzTV.Application.Search @using ErsatzTV.Core.Domain.Scheduling @implements IDisposable @inject NavigationManager NavigationManager @inject ILogger Logger @inject ISnackbar Snackbar @inject IMediator Mediator
Save Block Add Block Item Preview Block Playout
Block
Name
Duration
Stop scheduling block items
Before Duration End After Duration End
Block Items Collection Playback Order Show In EPG Disable Watermarks @context.CollectionName @context.PlaybackOrder
@if (_selectedItem is not null) { Block Item
Collection Type
Collection Television Show Television Season @* Artist *@ @* Multi Collection *@ Smart Collection
@if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.Collection) {
Collection
Only the first 10 items are shown
} @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.MultiCollection) {
Multi Collection
Only the first 10 items are shown
} @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.SmartCollection) {
Smart Collection
Only the first 10 items are shown
} @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.TelevisionShow) {
Television Show
Only the first 10 items are shown
} @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.TelevisionSeason) {
Television Season
Only the first 20 items are shown
}
Playback Order
@switch (_selectedItem.CollectionType) { case ProgramScheduleItemCollectionType.MultiCollection: Shuffle @* Shuffle In Order *@ break; case ProgramScheduleItemCollectionType.Collection: case ProgramScheduleItemCollectionType.SmartCollection: Chronological Shuffle Random Random Rotation @* Shuffle In Order *@ break; case ProgramScheduleItemCollectionType.TelevisionShow: Season, Episode Chronological Shuffle Random @* Multi-Episode Shuffle *@ break; case ProgramScheduleItemCollectionType.TelevisionSeason: case ProgramScheduleItemCollectionType.Artist: case ProgramScheduleItemCollectionType.FakeCollection: default: Chronological Shuffle Random break; }
} else if (_previewItems != null) { Preview Start Finish Media Item Duration @context.Start.ToString(@"hh\:mm\:ss") @context.Finish.ToString(@"hh\:mm\:ss") @context.Title @context.Duration }
@code { private readonly CancellationTokenSource _cts = new(); [Parameter] public int Id { get; set; } private BlockItemsEditViewModel _block = new() { Items = [] }; private BlockItemEditViewModel _selectedItem; private List _previewItems; private int _durationHours; private int _durationMinutes = 15; public void Dispose() { _cts.Cancel(); _cts.Dispose(); } protected override async Task OnParametersSetAsync() => await LoadBlockItems(); private async Task LoadBlockItems() { Option maybeBlock = await Mediator.Send(new GetBlockById(Id), _cts.Token); if (maybeBlock.IsNone) { NavigationManager.NavigateTo("blocks"); return; } foreach (BlockViewModel block in maybeBlock) { _block = new BlockItemsEditViewModel { Name = block.Name, Minutes = block.Minutes, StopScheduling = block.StopScheduling, Items = [] }; _durationHours = _block.Minutes / 60; _durationMinutes = _block.Minutes % 60; } Option> maybeResults = await Mediator.Send(new GetBlockItems(Id), _cts.Token); foreach (IEnumerable items in maybeResults) { _block.Items.AddRange(items.Map(ProjectToEditViewModel)); if (_block.Items.Count == 1) { _selectedItem = _block.Items.Head(); } } } private async Task> SearchCollections(string value, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(value)) { return new List(); } return await Mediator.Send(new SearchCollections(value), _cts.Token); } private async Task> SearchMultiCollections(string value, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(value)) { return new List(); } return await Mediator.Send(new SearchMultiCollections(value), _cts.Token); } private async Task> SearchSmartCollections(string value, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(value)) { return new List(); } return await Mediator.Send(new SearchSmartCollections(value), _cts.Token); } private async Task> SearchTelevisionShows(string value, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(value)) { return new List(); } return await Mediator.Send(new SearchTelevisionShows(value), _cts.Token); } private async Task> SearchTelevisionSeasons(string value, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(value)) { return new List(); } return await Mediator.Send(new SearchTelevisionSeasons(value), _cts.Token); } // private async Task> SearchArtists(string value, CancellationToken cancellationToken) // { // if (string.IsNullOrWhiteSpace(value)) // { // return new List(); // } // // return await Mediator.Send(new SearchArtists(value), _cts.Token); // } private static BlockItemEditViewModel ProjectToEditViewModel(BlockItemViewModel item) => new() { Id = item.Id, Index = item.Index, CollectionType = item.CollectionType, Collection = item.Collection, MultiCollection = item.MultiCollection, SmartCollection = item.SmartCollection, MediaItem = item.MediaItem, PlaybackOrder = item.PlaybackOrder, IncludeInProgramGuide = item.IncludeInProgramGuide, DisableWatermarks = item.DisableWatermarks }; private void AddBlockItem() { var item = new BlockItemEditViewModel { Index = _block.Items.Map(i => i.Index).DefaultIfEmpty().Max() + 1, PlaybackOrder = PlaybackOrder.Chronological, CollectionType = ProgramScheduleItemCollectionType.Collection }; _block.Items.Add(item); _selectedItem = item; } private void CopyItem(BlockItemEditViewModel item) { var newItem = new BlockItemEditViewModel { Index = item.Index + 1, PlaybackOrder = item.PlaybackOrder, CollectionType = item.CollectionType, Collection = item.Collection, MultiCollection = item.MultiCollection, SmartCollection = item.SmartCollection, MediaItem = item.MediaItem, IncludeInProgramGuide = item.IncludeInProgramGuide, DisableWatermarks = item.DisableWatermarks }; foreach (BlockItemEditViewModel i in _block.Items.Filter(bi => bi.Index >= newItem.Index)) { i.Index += 1; } _block.Items.Add(newItem); _selectedItem = newItem; } private void RemoveBlockItem(BlockItemEditViewModel item) { _selectedItem = null; _block.Items.Remove(item); } private void MoveItemUp(BlockItemEditViewModel item) { // swap with lower index BlockItemEditViewModel toSwap = _block.Items.OrderByDescending(x => x.Index).First(x => x.Index < item.Index); (toSwap.Index, item.Index) = (item.Index, toSwap.Index); } private void MoveItemDown(BlockItemEditViewModel item) { // swap with higher index BlockItemEditViewModel toSwap = _block.Items.OrderBy(x => x.Index).First(x => x.Index > item.Index); (toSwap.Index, item.Index) = (item.Index, toSwap.Index); } private async Task SaveChanges() { Seq errorMessages = await Mediator .Send(GenerateReplaceRequest(), _cts.Token) .Map(e => e.LeftToSeq()); errorMessages.HeadOrNone().Match( error => { Snackbar.Add($"Unexpected error saving block: {error.Value}", Severity.Error); Logger.LogError("Unexpected error saving block: {Error}", error.Value); }, () => NavigationManager.NavigateTo("blocks")); } private ReplaceBlockItems GenerateReplaceRequest() { var items = _block.Items.Map(item => new ReplaceBlockItem( item.Index, item.CollectionType, item.Collection?.Id, item.MultiCollection?.Id, item.SmartCollection?.Id, item.MediaItem?.MediaItemId, item.PlaybackOrder, item.IncludeInProgramGuide, item.DisableWatermarks)).ToList(); _block.Minutes = _durationHours * 60 + _durationMinutes; return new ReplaceBlockItems(Id, _block.Name, _block.Minutes, _block.StopScheduling, items); } private async Task PreviewPlayout() { _selectedItem = null; _previewItems = await Mediator.Send(new PreviewBlockPlayout(GenerateReplaceRequest()), _cts.Token); } private static void UpdateEPG(BlockItemEditViewModel context, bool includeInProgramGuide) => context.IncludeInProgramGuide = includeInProgramGuide; private static void UpdateWatermark(BlockItemEditViewModel context, bool disableWatermarks) => context.DisableWatermarks = disableWatermarks; private string SelectedRowClassFunc(BlockItemEditViewModel element, int rowNumber) => _selectedItem != null && _selectedItem == element ? "selected" : string.Empty; }