@page "/schedules/{Id:int}/items" @using ErsatzTV.Application.MediaCollections @using ErsatzTV.Application.MediaItems @using ErsatzTV.Application.ProgramSchedules @using ErsatzTV.Application.Television @using ErsatzTV.Application.Watermarks @using ErsatzTV.Application.Filler @using System.Globalization @using ErsatzTV.Core.Domain.Filler @using ErsatzTV.Application.Artists @implements IDisposable @inject NavigationManager _navigationManager @inject ILogger _logger @inject ISnackbar _snackbar @inject IMediator _mediator @_schedule.Name Items Start Time Collection Playout Mode @(context.StartType == StartType.Fixed ? context.StartTime == null ? string.Empty : DateTime.Today.Add(context.StartTime.Value).ToShortTimeString() : "Dynamic") @context.CollectionName @context.PlayoutMode @if (context.PlayoutMode == PlayoutMode.Multiple && context.MultipleCount.HasValue) { @($" ({context.MultipleCount})") } @if (!_schedule.ShuffleScheduleItems) { } @if (!_schedule.ShuffleScheduleItems) { } Add Schedule Item Save Changes @if (_selectedItem is not null) {
Dynamic @if (!_schedule.ShuffleScheduleItems) { Fixed } @foreach (ProgramScheduleItemCollectionType collectionType in Enum.GetValues()) { @collectionType } @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.Collection) { @foreach (MediaCollectionViewModel collection in _mediaCollections) { @collection.Name } } @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.MultiCollection) { @foreach (MultiCollectionViewModel collection in _multiCollections) { @collection.Name } } @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.SmartCollection) { @foreach (SmartCollectionViewModel collection in _smartCollections) { @collection.Name } } @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.TelevisionShow) { @foreach (NamedMediaItemViewModel show in _televisionShows) { @show.Name } } @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.TelevisionSeason) { @foreach (NamedMediaItemViewModel season in _televisionSeasons) { @season.Name } } @if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.Artist) { @foreach (NamedMediaItemViewModel artist in _artists) { @artist.Name } } @switch (_selectedItem.CollectionType) { case ProgramScheduleItemCollectionType.MultiCollection: Shuffle Shuffle In Order break; case ProgramScheduleItemCollectionType.Collection: case ProgramScheduleItemCollectionType.SmartCollection: Chronological Random Shuffle Shuffle In Order break; default: Chronological Random Shuffle break; } @if (!_schedule.ShuffleScheduleItems) { Flood } One Multiple Duration (none) Offline Filler Normal Filler
@foreach (FillerPresetViewModel filler in _fillerPresets.Where(f => f.FillerKind == FillerKind.PreRoll)) { @filler.Name } @foreach (FillerPresetViewModel filler in _fillerPresets.Where(f => f.FillerKind == FillerKind.MidRoll)) { @filler.Name } @foreach (FillerPresetViewModel filler in _fillerPresets.Where(f => f.FillerKind == FillerKind.PostRoll)) { @filler.Name } @foreach (FillerPresetViewModel filler in _fillerPresets.Where(f => f.FillerKind == FillerKind.Tail)) { @filler.Name } @foreach (FillerPresetViewModel filler in _fillerPresets.Where(f => f.FillerKind == FillerKind.Fallback)) { @filler.Name } @foreach (WatermarkViewModel watermark in _watermarks) { @watermark.Name } (none) @foreach (CultureInfo culture in _availableCultures) { @culture.EnglishName } (none) @foreach (CultureInfo culture in _availableCultures) { @culture.EnglishName } None Forced Default Any
}
@code { private readonly CancellationTokenSource _cts = new(); [Parameter] public int Id { get; set; } private ProgramScheduleItemsEditViewModel _schedule; private List _mediaCollections; private List _multiCollections; private List _smartCollections; private List _televisionShows; private List _televisionSeasons; private List _artists; private List _fillerPresets; private List _watermarks; private List _availableCultures; private ProgramScheduleItemEditViewModel _selectedItem; public void Dispose() { _cts.Cancel(); _cts.Dispose(); } protected override async Task OnParametersSetAsync() => await LoadScheduleItems(); private async Task LoadScheduleItems() { // TODO: fix performance _mediaCollections = await _mediator.Send(new GetAllCollections(), _cts.Token) .Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList()); _multiCollections = await _mediator.Send(new GetAllMultiCollections(), _cts.Token) .Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList()); _smartCollections = await _mediator.Send(new GetAllSmartCollections(), _cts.Token) .Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList()); _televisionShows = await _mediator.Send(new GetAllTelevisionShows(), _cts.Token) .Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList()); _televisionSeasons = await _mediator.Send(new GetAllTelevisionSeasons(), _cts.Token) .Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList()); _artists = await _mediator.Send(new GetAllArtists(), _cts.Token) .Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList()); _fillerPresets = await _mediator.Send(new GetAllFillerPresets(), _cts.Token) .Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList()); _watermarks = await _mediator.Send(new GetAllWatermarks(), _cts.Token) .Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList()); _availableCultures = await _mediator.Send(new GetAllLanguageCodes(), _cts.Token); string name = string.Empty; var shuffleScheduleItems = false; Option maybeSchedule = await _mediator.Send(new GetProgramScheduleById(Id), _cts.Token); foreach (ProgramScheduleViewModel schedule in maybeSchedule) { name = schedule.Name; shuffleScheduleItems = schedule.ShuffleScheduleItems; } Option> maybeResults = await _mediator.Send(new GetProgramScheduleItems(Id), _cts.Token); foreach (IEnumerable items in maybeResults) { _schedule = new ProgramScheduleItemsEditViewModel { Name = name, ShuffleScheduleItems = shuffleScheduleItems, Items = items.Map(ProjectToEditViewModel).ToList() }; if (_schedule.Items.Count == 1) { _selectedItem = _schedule.Items.Head(); } } } private ProgramScheduleItemEditViewModel ProjectToEditViewModel(ProgramScheduleItemViewModel item) { var result = new ProgramScheduleItemEditViewModel { Id = item.Id, Index = item.Index, StartType = item.StartType, StartTime = item.StartTime, PlayoutMode = item.PlayoutMode, CollectionType = item.CollectionType, Collection = item.Collection, MultiCollection = item.MultiCollection, SmartCollection = item.SmartCollection, MediaItem = item.MediaItem, PlaybackOrder = item.PlaybackOrder, CustomTitle = item.CustomTitle, GuideMode = item.GuideMode, PreRollFiller = item.PreRollFiller, MidRollFiller = item.MidRollFiller, PostRollFiller = item.PostRollFiller, TailFiller = item.TailFiller, FallbackFiller = item.FallbackFiller, Watermark = item.Watermark, PreferredAudioLanguageCode = item.PreferredAudioLanguageCode, PreferredSubtitleLanguageCode = item.PreferredSubtitleLanguageCode, SubtitleMode = item.SubtitleMode }; switch (item) { case ProgramScheduleItemMultipleViewModel multiple: result.MultipleCount = multiple.Count; break; case ProgramScheduleItemDurationViewModel duration: result.PlayoutDuration = duration.PlayoutDuration; result.TailMode = duration.TailMode; break; } return result; } private void AddScheduleItem() { var item = new ProgramScheduleItemEditViewModel { Index = _schedule.Items.Map(i => i.Index).DefaultIfEmpty().Max() + 1, StartType = StartType.Dynamic, PlayoutMode = PlayoutMode.One, PlaybackOrder = PlaybackOrder.Shuffle, CollectionType = ProgramScheduleItemCollectionType.Collection }; _schedule.Items.Add(item); _selectedItem = item; } private void RemoveScheduleItem(ProgramScheduleItemEditViewModel item) { _selectedItem = null; _schedule.Items.Remove(item); } private void MoveItemUp(ProgramScheduleItemEditViewModel item) { // swap with lower index ProgramScheduleItemEditViewModel toSwap = _schedule.Items.OrderByDescending(x => x.Index).First(x => x.Index < item.Index); (toSwap.Index, item.Index) = (item.Index, toSwap.Index); } private void MoveItemDown(ProgramScheduleItemEditViewModel item) { // swap with higher index ProgramScheduleItemEditViewModel toSwap = _schedule.Items.OrderBy(x => x.Index).First(x => x.Index > item.Index); (toSwap.Index, item.Index) = (item.Index, toSwap.Index); } private async Task SaveChanges() { var items = _schedule.Items.Map(item => new ReplaceProgramScheduleItem( item.Index, item.StartType, item.StartTime, item.PlayoutMode, item.CollectionType, item.Collection?.Id, item.MultiCollection?.Id, item.SmartCollection?.Id, item.MediaItem?.MediaItemId, item.PlaybackOrder, item.MultipleCount, item.PlayoutDuration, item.TailMode, item.CustomTitle, item.GuideMode, item.PreRollFiller?.Id, item.MidRollFiller?.Id, item.PostRollFiller?.Id, item.TailFiller?.Id, item.FallbackFiller?.Id, item.Watermark?.Id, item.PreferredAudioLanguageCode, item.PreferredSubtitleLanguageCode, item.SubtitleMode)).ToList(); Seq errorMessages = await _mediator.Send(new ReplaceProgramScheduleItems(Id, items), _cts.Token).Map(e => e.LeftToSeq()); errorMessages.HeadOrNone().Match( error => { _snackbar.Add($"Unexpected error saving schedule: {error.Value}", Severity.Error); _logger.LogError("Unexpected error saving schedule: {Error}", error.Value); }, () => _navigationManager.NavigateTo("/schedules")); } }