@page "/channels/{Id:int?}" @page "/channels/add" @using static LanguageExt.Prelude @using ErsatzTV.Application.FFmpegProfiles @using ErsatzTV.Application.FFmpegProfiles.Queries @using ErsatzTV.Application.Images.Commands @using ErsatzTV.Application.MediaItems.Queries @using System.Globalization @using ErsatzTV.Application.Channels @using ErsatzTV.Application.Channels.Queries @inject NavigationManager _navigationManager @inject ILogger _logger @inject ISnackbar _snackbar @inject IMediator _mediator
@(IsEdit ? "Edit Channel" : "Add Channel") MPEG-TS HLS Direct @foreach (FFmpegProfileViewModel profile in _ffmpegProfiles) { @profile.Name } (none) @foreach (CultureInfo culture in _availableCultures) { @culture.EnglishName } Upload Logo @(IsEdit ? "Save Changes" : "Add Channel")
@code { [Parameter] public int? Id { get; set; } private readonly ChannelEditViewModel _model = new(); private EditContext _editContext; private ValidationMessageStore _messageStore; private List _ffmpegProfiles; private List _availableCultures; protected override async Task OnParametersSetAsync() { await LoadFFmpegProfilesAsync(); _availableCultures = await _mediator.Send(new GetAllLanguageCodes()); if (Id.HasValue) { Option maybeChannel = await _mediator.Send(new GetChannelById(Id.Value)); maybeChannel.Match( channelViewModel => { _model.Id = channelViewModel.Id; _model.Name = channelViewModel.Name; _model.Number = channelViewModel.Number; _model.FFmpegProfileId = channelViewModel.FFmpegProfileId; _model.Logo = channelViewModel.Logo; _model.StreamingMode = channelViewModel.StreamingMode; _model.PreferredLanguageCode = channelViewModel.PreferredLanguageCode; }, () => _navigationManager.NavigateTo("404")); } else { FFmpegSettingsViewModel ffmpegSettings = await _mediator.Send(new GetFFmpegSettings()); // TODO: command for new channel IEnumerable channelNumbers = await _mediator.Send(new GetAllChannels()) .Map(list => list.Map(c => int.TryParse(c.Number.Split(".").Head(), out int result) ? result : 0)); int maxNumber = Optional(channelNumbers).Flatten().DefaultIfEmpty(0).Max(); _model.Number = (maxNumber + 1).ToString(); _model.Name = "New Channel"; _model.FFmpegProfileId = ffmpegSettings.DefaultFFmpegProfileId; _model.StreamingMode = StreamingMode.TransportStream; } } protected override void OnInitialized() { _editContext = new EditContext(_model); _messageStore = new ValidationMessageStore(_editContext); } private bool IsEdit => Id.HasValue; private async Task LoadFFmpegProfilesAsync() => _ffmpegProfiles = await _mediator.Send(new GetAllFFmpegProfiles()); private async Task HandleSubmitAsync() { _messageStore.Clear(); if (_editContext.Validate()) { Seq errorMessage = IsEdit ? (await _mediator.Send(_model.ToUpdate())).LeftToSeq() : (await _mediator.Send(_model.ToCreate())).LeftToSeq(); errorMessage.HeadOrNone().Match( error => { _snackbar.Add(error.Value, Severity.Error); _logger.LogError("Unexpected error saving channel: {Error}", error.Value); }, () => _navigationManager.NavigateTo("/channels")); } } private async Task UploadLogo(InputFileChangeEventArgs e) { var buffer = new byte[e.File.Size]; await e.File.OpenReadStream().ReadAsync(buffer); Either maybeCacheFileName = await _mediator.Send(new SaveArtworkToDisk(buffer, ArtworkKind.Logo)); maybeCacheFileName.Match( relativeFileName => { _model.Logo = relativeFileName; StateHasChanged(); }, error => { _snackbar.Add($"Unexpected error saving channel logo: {error.Value}", Severity.Error); _logger.LogError("Unexpected error saving channel logo: {Error}", error.Value); }); } }