@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 @using ErsatzTV.Application.Filler @using ErsatzTV.Application.Filler.Queries @using ErsatzTV.Application.Watermarks @using ErsatzTV.Application.Watermarks.Queries @using ErsatzTV.Core.Domain.Filler @inject NavigationManager _navigationManager @inject ILogger _logger @inject ISnackbar _snackbar @inject IMediator _mediator
@(IsEdit ? "Edit Channel" : "Add Channel") MPEG-TS MPEG-TS (Legacy) HLS Direct HLS Segmenter @foreach (FFmpegProfileViewModel profile in _ffmpegProfiles) { @profile.Name } (none) @foreach (CultureInfo culture in _availableCultures) { @culture.EnglishName } Upload Logo (none) @foreach (WatermarkViewModel watermark in _watermarks) { @watermark.Name } (none) @foreach (FillerPresetViewModel fillerPreset in _fillerPresets) { @fillerPreset.Name } @(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; private List _watermarks; private List _fillerPresets; protected override async Task OnParametersSetAsync() { await LoadFFmpegProfiles(); _availableCultures = await _mediator.Send(new GetAllLanguageCodes()); await LoadWatermarks(); await LoadFillerPresets(); 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; _model.WatermarkId = channelViewModel.WatermarkId; _model.FallbackFillerId = channelViewModel.FallbackFillerId; }, () => _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.TransportStreamHybrid; } } protected override void OnInitialized() { _editContext = new EditContext(_model); _messageStore = new ValidationMessageStore(_editContext); } private bool IsEdit => Id.HasValue; private async Task LoadFFmpegProfiles() => _ffmpegProfiles = await _mediator.Send(new GetAllFFmpegProfiles()); private async Task LoadWatermarks() => _watermarks = await _mediator.Send(new GetAllWatermarks()); private async Task LoadFillerPresets() => _fillerPresets = await _mediator.Send(new GetAllFillerPresets()) .Map(list => list.Filter(vm => vm.FillerKind == FillerKind.Fallback).ToList()); 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) { try { Either maybeCacheFileName = await _mediator.Send(new SaveArtworkToDisk(e.File.OpenReadStream(maxAllowedSize: 10 * 1024 * 1024), ArtworkKind.Logo)); maybeCacheFileName.Match( relativeFileName => { _model.Logo = relativeFileName; StateHasChanged(); }, error => { Console.WriteLine($"error saving {error}"); _snackbar.Add($"Unexpected error saving channel logo: {error.Value}", Severity.Error); _logger.LogError("Unexpected error saving channel logo: {Error}", error.Value); }); } catch (IOException ex) { Console.WriteLine(ex); _snackbar.Add("Channel logo exceeds maximum allowed file size of 10 MB", Severity.Error); _logger.LogError("Channel logo exceeds maximum allowed file size of 10 MB"); } catch (Exception ex) { _snackbar.Add($"Unexpected error saving channel logo: {ex.Message}", Severity.Error); _logger.LogError("Unexpected error saving channel logo: {Error}", ex.Message); } } }