Files
ersatztv/ErsatzTV/Pages/ScheduleItemsEditor.razor
T

671 lines
33 KiB
Plaintext

@page "/schedules/{Id:int}/items"
@using ErsatzTV.Application.Filler
@using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaItems
@using ErsatzTV.Application.ProgramSchedules
@using ErsatzTV.Application.Search
@using ErsatzTV.Application.Watermarks
@using ErsatzTV.Core.Domain.Filler
@using ErsatzTV.Core.Scheduling
@implements IDisposable
@inject NavigationManager NavigationManager
@inject ILogger<ScheduleItemsEditor> Logger
@inject ISnackbar Snackbar
@inject IMediator Mediator
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
<MudTable T="ProgramScheduleItemEditViewModel"
Hover="true"
Items="_schedule?.Items?.OrderBy(i => i.Index)"
Dense="true"
SelectedItemChanged="@(vm => SelectedItemChanged(vm))">
<ToolBarContent>
<MudText Typo="Typo.h6">@_schedule.Name Items</MudText>
</ToolBarContent>
<ColGroup>
<col/>
<col/>
<col/>
<col style="width: 60px;"/>
<col style="width: 60px;"/>
<col style="width: 60px;"/>
</ColGroup>
<HeaderContent>
<MudTh>Start Time</MudTh>
<MudTh>Collection</MudTh>
<MudTh>Playout Mode</MudTh>
<MudTh/>
<MudTh/>
<MudTh/>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Start Time">
<MudText Typo="@(context == _selectedItem ? Typo.subtitle2 : Typo.body2)">
@(context.StartType == StartType.Fixed ? context.StartTime == null ? string.Empty : DateTime.Today.Add(context.StartTime.Value).ToShortTimeString() : "Dynamic")
</MudText>
</MudTd>
<MudTd DataLabel="Collection">
<MudText Typo="@(context == _selectedItem ? Typo.subtitle2 : Typo.body2)">
@context.CollectionName
</MudText>
</MudTd>
<MudTd DataLabel="Playout Mode">
<MudText Typo="@(context == _selectedItem ? Typo.subtitle2 : Typo.body2)">
@context.PlayoutMode
@if (context.PlayoutMode == PlayoutMode.Multiple && context.MultipleCount.HasValue)
{
@($" ({context.MultipleCount})")
}
</MudText>
</MudTd>
<MudTd>
@if (!_schedule.ShuffleScheduleItems)
{
<MudIconButton Icon="@Icons.Material.Filled.ArrowUpward"
OnClick="@(_ => MoveItemUp(context))"
Disabled="@(_schedule.ShuffleScheduleItems || _schedule.Items.All(x => x.Index >= context.Index))">
</MudIconButton>
}
</MudTd>
<MudTd>
@if (!_schedule.ShuffleScheduleItems)
{
<MudIconButton Icon="@Icons.Material.Filled.ArrowDownward"
OnClick="@(_ => MoveItemDown(context))"
Disabled="@(_schedule.ShuffleScheduleItems || _schedule.Items.All(x => x.Index <= context.Index))">
</MudIconButton>
}
</MudTd>
<MudTd>
<MudIconButton Icon="@Icons.Material.Filled.Delete"
OnClick="@(_ => RemoveScheduleItem(context))">
</MudIconButton>
</MudTd>
</RowTemplate>
</MudTable>
<MudButton Variant="Variant.Filled" Color="Color.Default" OnClick="@(_ => AddScheduleItem())" Class="mt-4">
Add Schedule Item
</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => SaveChanges())" Class="mt-4 ml-4">
Save Changes
</MudButton>
@if (_selectedItem is not null)
{
<EditForm Model="_selectedItem">
<FluentValidationValidator/>
<div style="display: flex; flex-direction: row;" class="mt-6">
<div style="flex-grow: 1; max-width: 400px;" class="mr-6">
<MudCard>
<MudCardContent>
<MudSelect Label="Start Type" @bind-Value="_selectedItem.StartType" For="@(() => _selectedItem.StartType)">
<MudSelectItem Value="StartType.Dynamic">Dynamic</MudSelectItem>
@if (!_schedule.ShuffleScheduleItems)
{
<MudSelectItem Value="StartType.Fixed">Fixed</MudSelectItem>
}
</MudSelect>
<MudTimePicker Class="mt-3" Label="Start Time" @bind-Time="@_selectedItem.StartTime" For="@(() => _selectedItem.StartTime)" Disabled="@(_selectedItem.StartType == StartType.Dynamic)" Editable="true"/>
@if (_selectedItem.StartType == StartType.Fixed)
{
<MudSelect Class="mt-3" Label="Fixed Start Time Behavior" @bind-Value="_selectedItem.FixedStartTimeBehavior" For="@(() => _selectedItem.FixedStartTimeBehavior)">
<MudSelectItem Value="@((FixedStartTimeBehavior?)null)">Inherit</MudSelectItem>
<MudSelectItem T="FixedStartTimeBehavior?" Value="FixedStartTimeBehavior.Strict">Strict - Always Wait For Exact Start Time</MudSelectItem>
<MudSelectItem T="FixedStartTimeBehavior?" Value="FixedStartTimeBehavior.Flexible">Flexible - Start As Soon As Possible After Start Time</MudSelectItem>
</MudSelect>
}
<MudSelect Class="mt-3" Label="Collection Type" @bind-Value="_selectedItem.CollectionType" For="@(() => _selectedItem.CollectionType)">
<MudSelectItem Value="ProgramScheduleItemCollectionType.Collection">Collection</MudSelectItem>
<MudSelectItem Value="ProgramScheduleItemCollectionType.TelevisionShow">Television Show</MudSelectItem>
<MudSelectItem Value="ProgramScheduleItemCollectionType.TelevisionSeason">Television Season</MudSelectItem>
<MudSelectItem Value="ProgramScheduleItemCollectionType.Artist">Artist</MudSelectItem>
<MudSelectItem Value="ProgramScheduleItemCollectionType.MultiCollection">Multi Collection</MudSelectItem>
<MudSelectItem Value="ProgramScheduleItemCollectionType.SmartCollection">Smart Collection</MudSelectItem>
<MudSelectItem Value="ProgramScheduleItemCollectionType.Playlist">Playlist</MudSelectItem>
</MudSelect>
@if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.Collection)
{
<MudAutocomplete Class="mt-3" T="MediaCollectionViewModel" Label="Collection"
@bind-Value="_selectedItem.Collection" SearchFunc="@SearchCollections"
ToStringFunc="@(c => c?.Name)" Placeholder="Type to search...">
<MoreItemsTemplate>
<MudText Align="Align.Center" Class="px-4 py-1">
Only the first 10 items are shown
</MudText>
</MoreItemsTemplate>
</MudAutocomplete>
}
@if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.MultiCollection)
{
<MudAutocomplete Class="mt-3" T="MultiCollectionViewModel" Label="Multi Collection"
@bind-Value="_selectedItem.MultiCollection" SearchFunc="@SearchMultiCollections"
ToStringFunc="@(c => c?.Name)" Placeholder="Type to search...">
<MoreItemsTemplate>
<MudText Align="Align.Center" Class="px-4 py-1">
Only the first 10 items are shown
</MudText>
</MoreItemsTemplate>
</MudAutocomplete>
}
@if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.SmartCollection)
{
<MudAutocomplete Class="mt-3" T="SmartCollectionViewModel" Label="Smart Collection"
@bind-Value="_selectedItem.SmartCollection" SearchFunc="@SearchSmartCollections"
ToStringFunc="@(c => c?.Name)" Placeholder="Type to search...">
<MoreItemsTemplate>
<MudText Align="Align.Center" Class="px-4 py-1">
Only the first 10 items are shown
</MudText>
</MoreItemsTemplate>
</MudAutocomplete>
}
@if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.TelevisionShow)
{
<MudAutocomplete Class="mt-3" T="NamedMediaItemViewModel" Label="Television Show"
@bind-Value="_selectedItem.MediaItem" SearchFunc="@SearchTelevisionShows"
ToStringFunc="@(c => c?.Name)" Placeholder="Type to search...">
<MoreItemsTemplate>
<MudText Align="Align.Center" Class="px-4 py-1">
Only the first 10 items are shown
</MudText>
</MoreItemsTemplate>
</MudAutocomplete>
}
@if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.TelevisionSeason)
{
<MudAutocomplete Class="mt-3" T="NamedMediaItemViewModel" Label="Television Season"
@bind-Value="_selectedItem.MediaItem" SearchFunc="@SearchTelevisionSeasons"
ToStringFunc="@(c => c?.Name)" Placeholder="Type to search..."
MaxItems="20">
<MoreItemsTemplate>
<MudText Align="Align.Center" Class="px-4 py-1">
Only the first 20 items are shown
</MudText>
</MoreItemsTemplate>
</MudAutocomplete>
}
@if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.Artist)
{
<MudAutocomplete Class="mt-3" T="NamedMediaItemViewModel" Label="Artist"
@bind-Value="_selectedItem.MediaItem" SearchFunc="@SearchArtists"
ToStringFunc="@(c => c?.Name)" Placeholder="Type to search..."
MaxItems="10">
<MoreItemsTemplate>
<MudText Align="Align.Center" Class="px-4 py-1">
Only the first 10 items are shown
</MudText>
</MoreItemsTemplate>
</MudAutocomplete>
}
@if (_selectedItem.CollectionType == ProgramScheduleItemCollectionType.Playlist)
{
<MudSelect Class="mt-3"
T="PlaylistGroupViewModel"
Value="@_selectedPlaylistGroup"
Label="Playlist Group"
ValueChanged="@(vm => UpdatePlaylistGroupItems(vm))">
@foreach (PlaylistGroupViewModel playlistGroup in _playlistGroups)
{
<MudSelectItem Value="@playlistGroup">@playlistGroup.Name</MudSelectItem>
}
</MudSelect>
<MudSelect Class="mt-3"
T="PlaylistViewModel"
Label="Playlist"
@bind-value="_selectedItem.Playlist">
@foreach (PlaylistViewModel playlist in _playlists)
{
<MudSelectItem Value="@playlist">@playlist.Name</MudSelectItem>
}
</MudSelect>
}
<MudSelect Class="mt-3"
Label="Playback Order"
@bind-Value="@_selectedItem.PlaybackOrder"
For="@(() => _selectedItem.PlaybackOrder)"
Disabled="@(_selectedItem.CollectionType is ProgramScheduleItemCollectionType.Playlist)">
@switch (_selectedItem.CollectionType)
{
case ProgramScheduleItemCollectionType.MultiCollection:
<MudSelectItem Value="PlaybackOrder.Shuffle">Shuffle</MudSelectItem>
<MudSelectItem Value="PlaybackOrder.ShuffleInOrder">Shuffle In Order</MudSelectItem>
break;
case ProgramScheduleItemCollectionType.Collection:
case ProgramScheduleItemCollectionType.SmartCollection:
<MudSelectItem Value="PlaybackOrder.Chronological">Chronological</MudSelectItem>
<MudSelectItem Value="PlaybackOrder.Random">Random</MudSelectItem>
<MudSelectItem Value="PlaybackOrder.Shuffle">Shuffle</MudSelectItem>
<MudSelectItem Value="PlaybackOrder.ShuffleInOrder">Shuffle In Order</MudSelectItem>
break;
case ProgramScheduleItemCollectionType.TelevisionShow:
<MudSelectItem Value="PlaybackOrder.Chronological">Chronological</MudSelectItem>
<MudSelectItem Value="PlaybackOrder.SeasonEpisode">Season, Episode</MudSelectItem>
<MudSelectItem Value="PlaybackOrder.Random">Random</MudSelectItem>
<MudSelectItem Value="PlaybackOrder.Shuffle">Shuffle</MudSelectItem>
<MudSelectItem Value="PlaybackOrder.MultiEpisodeShuffle">Multi-Episode Shuffle</MudSelectItem>
break;
case ProgramScheduleItemCollectionType.Playlist:
break;
default:
<MudSelectItem Value="PlaybackOrder.Chronological">Chronological</MudSelectItem>
<MudSelectItem Value="PlaybackOrder.Random">Random</MudSelectItem>
<MudSelectItem Value="PlaybackOrder.Shuffle">Shuffle</MudSelectItem>
break;
}
</MudSelect>
<MudSelect Class="mt-3" Label="Playout Mode" @bind-Value="@_selectedItem.PlayoutMode" For="@(() => _selectedItem.PlayoutMode)">
@if (!_schedule.ShuffleScheduleItems)
{
<MudSelectItem Value="PlayoutMode.Flood">Flood</MudSelectItem>
}
<MudSelectItem Value="PlayoutMode.One">One</MudSelectItem>
<MudSelectItem Value="PlayoutMode.Multiple">Multiple</MudSelectItem>
<MudSelectItem Value="PlayoutMode.Duration">Duration</MudSelectItem>
</MudSelect>
<MudTextField Class="mt-3" Label="Multiple Count" @bind-Value="@_selectedItem.MultipleCount" For="@(() => _selectedItem.MultipleCount)" Disabled="@(_selectedItem.PlayoutMode != PlayoutMode.Multiple)"/>
<MudGrid Class="mt-3" Style="align-items: center" Justify="Justify.Center">
<MudItem xs="6">
<MudTextField T="int"
Label="Playout Duration"
@bind-Value="_selectedItem.PlayoutDurationHours"
Adornment="Adornment.End"
AdornmentText="hours"
Disabled="@(_selectedItem.PlayoutMode != PlayoutMode.Duration)"/>
</MudItem>
<MudItem xs="6">
<MudTextField T="int"
@bind-Value="_selectedItem.PlayoutDurationMinutes"
Adornment="Adornment.End"
AdornmentText="minutes"
Disabled="@(_selectedItem.PlayoutMode != PlayoutMode.Duration)"/>
</MudItem>
</MudGrid>
<MudSelect Class="mt-3" Label="Fill With Group Mode (Show or Artist)" @bind-Value="@_selectedItem.FillWithGroupMode" For="@(() => _selectedItem.FillWithGroupMode)" Disabled="@(_selectedItem.CanFillWithGroups == false)">
<MudSelectItem Value="FillWithGroupMode.None">(none)</MudSelectItem>
<MudSelectItem Value="FillWithGroupMode.FillWithOrderedGroups">Ordered Groups</MudSelectItem>
<MudSelectItem Value="FillWithGroupMode.FillWithShuffledGroups">Shuffled Groups</MudSelectItem>
</MudSelect>
<MudSelect Class="mt-3" Label="Tail Mode" @bind-Value="@_selectedItem.TailMode" For="@(() => _selectedItem.TailMode)" Disabled="@(_selectedItem.PlayoutMode != PlayoutMode.Duration)">
<MudSelectItem Value="@TailMode.None">(none)</MudSelectItem>
<MudSelectItem Value="@TailMode.Offline">Offline</MudSelectItem>
<MudSelectItem Value="@TailMode.Filler">Filler</MudSelectItem>
</MudSelect>
<MudTextField Class="mt-3" Label="Discard To Fill Attempts" @bind-Value="@_selectedItem.DiscardToFillAttempts" For="@(() => _selectedItem.DiscardToFillAttempts)" Disabled="@(_selectedItem.PlayoutMode != PlayoutMode.Duration)"/>
<MudTextField Class="mt-3" Label="Custom Title" @bind-Value="@_selectedItem.CustomTitle" For="@(() => _selectedItem.CustomTitle)"/>
<MudSelect Class="mt-3" Label="Guide Mode" @bind-Value="@_selectedItem.GuideMode" For="@(() => _selectedItem.GuideMode)">
<MudSelectItem Value="@GuideMode.Normal">Normal</MudSelectItem>
<MudSelectItem Value="@GuideMode.Filler">Filler</MudSelectItem>
</MudSelect>
</MudCardContent>
</MudCard>
</div>
<div style="flex-grow: 1; max-width: 400px;">
<MudCard>
<MudCardContent>
<MudSelect T="FillerPresetViewModel"
Label="Pre-Roll Filler"
@bind-value="_selectedItem.PreRollFiller"
Clearable="true">
@foreach (FillerPresetViewModel filler in _fillerPresets.Where(f => f.FillerKind == FillerKind.PreRoll))
{
<MudSelectItem Value="@filler">@filler.Name</MudSelectItem>
}
</MudSelect>
<MudSelect Class="mt-3"
T="FillerPresetViewModel"
Label="Mid-Roll Filler"
@bind-value="_selectedItem.MidRollFiller"
Clearable="true">
@foreach (FillerPresetViewModel filler in _fillerPresets.Where(f => f.FillerKind == FillerKind.MidRoll))
{
<MudSelectItem Value="@filler">@filler.Name</MudSelectItem>
}
</MudSelect>
<MudSelect Class="mt-3"
T="FillerPresetViewModel"
Label="Post-Roll Filler"
@bind-value="_selectedItem.PostRollFiller"
Clearable="true">
@foreach (FillerPresetViewModel filler in _fillerPresets.Where(f => f.FillerKind == FillerKind.PostRoll))
{
<MudSelectItem Value="@filler">@filler.Name</MudSelectItem>
}
</MudSelect>
<MudSelect Class="mt-3"
T="FillerPresetViewModel"
Label="Tail Filler"
@bind-value="_selectedItem.TailFiller"
Clearable="true">
@foreach (FillerPresetViewModel filler in _fillerPresets.Where(f => f.FillerKind == FillerKind.Tail))
{
<MudSelectItem Value="@filler">@filler.Name</MudSelectItem>
}
</MudSelect>
<MudSelect Class="mt-3"
T="FillerPresetViewModel"
Label="Fallback Filler"
@bind-value="_selectedItem.FallbackFiller"
Clearable="true">
@foreach (FillerPresetViewModel filler in _fillerPresets.Where(f => f.FillerKind == FillerKind.Fallback))
{
<MudSelectItem Value="@filler">@filler.Name</MudSelectItem>
}
</MudSelect>
</MudCardContent>
</MudCard>
<MudCard Class="mt-4">
<MudCardContent>
<MudSelect Label="Watermark" @bind-Value="@_selectedItem.Watermark" For="@(() => _selectedItem.Watermark)" Clearable="true">
@foreach (WatermarkViewModel watermark in _watermarks)
{
<MudSelectItem Value="@watermark">@watermark.Name</MudSelectItem>
}
</MudSelect>
<MudSelect Class="mt-3"
Label="Preferred Audio Language"
@bind-Value="_selectedItem.PreferredAudioLanguageCode"
For="@(() => _selectedItem.PreferredAudioLanguageCode)"
Clearable="true">
<MudSelectItem Value="@((string)null)">(none)</MudSelectItem>
@foreach (LanguageCodeViewModel culture in _availableCultures)
{
<MudSelectItem Value="@culture.ThreeLetterISOLanguageName">@culture.EnglishName</MudSelectItem>
}
</MudSelect>
<MudTextField Class="mt-3" Label="Preferred Audio Title" @bind-Value="@_selectedItem.PreferredAudioTitle" For="@(() => _selectedItem.PreferredAudioTitle)"/>
<MudSelect Class="mt-3"
Label="Preferred Subtitle Language"
@bind-Value="_selectedItem.PreferredSubtitleLanguageCode"
For="@(() => _selectedItem.PreferredSubtitleLanguageCode)"
Clearable="true">
<MudSelectItem Value="@((string)null)">(none)</MudSelectItem>
@foreach (LanguageCodeViewModel culture in _availableCultures)
{
<MudSelectItem Value="@culture.ThreeLetterISOLanguageName">@culture.EnglishName</MudSelectItem>
}
</MudSelect>
<MudSelect T="ChannelSubtitleMode?" Class="mt-3" Label="Subtitle Mode" @bind-Value="_selectedItem.SubtitleMode" For="@(() => _selectedItem.SubtitleMode)" Clearable="true">
<MudSelectItem T="ChannelSubtitleMode?" Value="@(ChannelSubtitleMode.None)">None</MudSelectItem>
<MudSelectItem T="ChannelSubtitleMode?" Value="@(ChannelSubtitleMode.Forced)">Forced</MudSelectItem>
<MudSelectItem T="ChannelSubtitleMode?" Value="@(ChannelSubtitleMode.Default)">Default</MudSelectItem>
<MudSelectItem T="ChannelSubtitleMode?" Value="@(ChannelSubtitleMode.Any)">Any</MudSelectItem>
</MudSelect>
</MudCardContent>
</MudCard>
</div>
</div>
</EditForm>
}
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
private ProgramScheduleItemsEditViewModel _schedule = new();
private List<FillerPresetViewModel> _fillerPresets = new();
private List<WatermarkViewModel> _watermarks = new();
private List<LanguageCodeViewModel> _availableCultures = new();
private readonly List<PlaylistGroupViewModel> _playlistGroups = [];
private readonly List<PlaylistViewModel> _playlists = [];
private PlaylistGroupViewModel _selectedPlaylistGroup;
private ProgramScheduleItemEditViewModel _selectedItem;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync() => await LoadScheduleItems();
private async Task LoadScheduleItems()
{
// TODO: fix performance
_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);
_playlistGroups.AddRange(await Mediator.Send(new GetAllPlaylistGroups(), _cts.Token));
string name = string.Empty;
var shuffleScheduleItems = false;
Option<ProgramScheduleViewModel> maybeSchedule = await Mediator.Send(new GetProgramScheduleById(Id), _cts.Token);
foreach (ProgramScheduleViewModel schedule in maybeSchedule)
{
name = schedule.Name;
shuffleScheduleItems = schedule.ShuffleScheduleItems;
}
Option<IEnumerable<ProgramScheduleItemViewModel>> maybeResults =
await Mediator.Send(new GetProgramScheduleItems(Id), _cts.Token);
foreach (IEnumerable<ProgramScheduleItemViewModel> items in maybeResults)
{
_schedule = new ProgramScheduleItemsEditViewModel
{
Name = name,
ShuffleScheduleItems = shuffleScheduleItems,
Items = items.Map(ProjectToEditViewModel).ToList()
};
if (_schedule.Items.Count == 1)
{
await SelectedItemChanged(_schedule.Items.Head());
}
}
}
private async Task<IEnumerable<MediaCollectionViewModel>> SearchCollections(string value, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(value))
{
return new List<MediaCollectionViewModel>();
}
return await Mediator.Send(new SearchCollections(value), _cts.Token);
}
private async Task<IEnumerable<MultiCollectionViewModel>> SearchMultiCollections(string value, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(value))
{
return new List<MultiCollectionViewModel>();
}
return await Mediator.Send(new SearchMultiCollections(value), _cts.Token);
}
private async Task<IEnumerable<SmartCollectionViewModel>> SearchSmartCollections(string value, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(value))
{
return new List<SmartCollectionViewModel>();
}
return await Mediator.Send(new SearchSmartCollections(value), _cts.Token);
}
private async Task<IEnumerable<NamedMediaItemViewModel>> SearchTelevisionShows(string value, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(value))
{
return new List<NamedMediaItemViewModel>();
}
return await Mediator.Send(new SearchTelevisionShows(value), _cts.Token);
}
private async Task<IEnumerable<NamedMediaItemViewModel>> SearchTelevisionSeasons(string value, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(value))
{
return new List<NamedMediaItemViewModel>();
}
return await Mediator.Send(new SearchTelevisionSeasons(value), _cts.Token);
}
private async Task<IEnumerable<NamedMediaItemViewModel>> SearchArtists(string value, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(value))
{
return new List<NamedMediaItemViewModel>();
}
return await Mediator.Send(new SearchArtists(value), _cts.Token);
}
private async Task UpdatePlaylistGroupItems(PlaylistGroupViewModel playlistGroup)
{
_selectedPlaylistGroup = playlistGroup;
_playlists.Clear();
_playlists.AddRange(await Mediator.Send(new GetPlaylistsByPlaylistGroupId(playlistGroup.Id), _cts.Token));
}
private ProgramScheduleItemEditViewModel ProjectToEditViewModel(ProgramScheduleItemViewModel item)
{
var result = new ProgramScheduleItemEditViewModel
{
Id = item.Id,
Index = item.Index,
StartType = item.StartType,
StartTime = item.StartTime,
FixedStartTimeBehavior = item.FixedStartTimeBehavior,
PlayoutMode = item.PlayoutMode,
CollectionType = item.CollectionType,
Collection = item.Collection,
MultiCollection = item.MultiCollection,
SmartCollection = item.SmartCollection,
Playlist = item.Playlist,
MediaItem = item.MediaItem,
PlaybackOrder = item.PlaybackOrder,
FillWithGroupMode = item.FillWithGroupMode,
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,
PreferredAudioTitle = item.PreferredAudioTitle,
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;
result.DiscardToFillAttempts = duration.DiscardToFillAttempts;
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.FixedStartTimeBehavior,
item.PlayoutMode,
item.CollectionType,
item.Collection?.Id,
item.MultiCollection?.Id,
item.SmartCollection?.Id,
item.MediaItem?.MediaItemId,
item.Playlist?.Id,
item.PlaybackOrder,
item.FillWithGroupMode,
item.MultipleCount,
item.PlayoutDuration,
item.TailMode,
item.DiscardToFillAttempts,
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.PreferredAudioTitle,
item.PreferredSubtitleLanguageCode,
item.SubtitleMode)).ToList();
Seq<BaseError> 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"));
}
private async Task SelectedItemChanged(ProgramScheduleItemEditViewModel vm)
{
_selectedItem = vm;
foreach (int playlistGroupId in Optional(_selectedItem.Playlist?.PlaylistGroupId))
{
foreach (PlaylistGroupViewModel group in Optional(_playlistGroups.Find(g => g.Id == playlistGroupId)))
{
_selectedPlaylistGroup = group;
await UpdatePlaylistGroupItems(group);
}
}
}
}