@page "/watermarks/{Id:int}" @page "/watermarks/add" @using ErsatzTV.Application.Artworks @using ErsatzTV.Application.Images @using ErsatzTV.Application.Watermarks @using ErsatzTV.FFmpeg.State @using ErsatzTV.Validators @using FluentValidation.Results @implements IDisposable @inject NavigationManager NavigationManager @inject ILogger Logger @inject ISnackbar Snackbar @inject IMediator Mediator @(IsEdit ? "Save Watermark" : "Add Watermark")
Watermark
Name
Mode
None Permanent Intermittent
Image Source
Custom Channel Logo
Image
Image Preview
@if (!string.IsNullOrWhiteSpace(_model.Image?.Path) && _model.ImageSource == ChannelWatermarkImageSource.Custom) { }
Location
Bottom Right Bottom Middle Bottom Left Left Middle Top Left Top Middle Top Right Right Middle
Place Within Source Content
Size
Scaled Actual Size
Width
Horizontal Margin
Vertical Margin
Frequency
5 minutes 10 minutes 15 minutes 20 minutes 30 minutes 60 minutes
Duration
Opacity
@code { private readonly CancellationTokenSource _cts = new(); [Parameter] public int Id { get; set; } private WatermarkEditViewModel _model = new(); private readonly WatermarkEditViewModelValidator _validator = new(); private MudForm _form; public void Dispose() { _cts.Cancel(); _cts.Dispose(); } protected override async Task OnParametersSetAsync() { if (IsEdit) { Option watermark = await Mediator.Send(new GetWatermarkById(Id), _cts.Token); watermark.Match( watermarkViewModel => _model = new WatermarkEditViewModel(watermarkViewModel), () => NavigationManager.NavigateTo("404")); } else { _model = new WatermarkEditViewModel { Name = string.Empty, Mode = ChannelWatermarkMode.Permanent, Image = ArtworkContentTypeModel.None, Location = WatermarkLocation.BottomRight, Size = WatermarkSize.Scaled, Width = 15, HorizontalMargin = 5, VerticalMargin = 5, FrequencyMinutes = 15, DurationSeconds = 15, Opacity = 100, PlaceWithinSourceContent = false }; } } private bool IsEdit => Id != 0; private async Task HandleSubmitAsync() { await _form.Validate(); ValidationResult result = await _validator.ValidateAsync(_model, _cts.Token); if (result.IsValid) { Seq errorMessage = IsEdit ? (await Mediator.Send(_model.ToUpdate(), _cts.Token)).LeftToSeq() : (await Mediator.Send(_model.ToCreate(), _cts.Token)).LeftToSeq(); errorMessage.HeadOrNone().Match( error => { Snackbar.Add("Unexpected error saving watermark"); Logger.LogError("Unexpected error saving watermark: {Error}", error.Value); }, () => NavigationManager.NavigateTo("watermarks")); } } private async Task UploadWatermark(InputFileChangeEventArgs e) { try { Either maybeCacheFileName = await Mediator.Send( new SaveArtworkToDisk(e.File.OpenReadStream(10 * 1024 * 1024), ArtworkKind.Watermark, e.File.ContentType), _cts.Token); maybeCacheFileName.Match( relativeFileName => { _model.Image = new ArtworkContentTypeModel(relativeFileName, e.File.ContentType); StateHasChanged(); }, error => { Snackbar.Add($"Unexpected error saving watermark: {error.Value}", Severity.Error); Logger.LogError("Unexpected error saving watermark: {Error}", error.Value); }); } catch (IOException) { Snackbar.Add("Watermark exceeds maximum allowed file size of 10 MB", Severity.Error); Logger.LogError("Watermark exceeds maximum allowed file size of 10 MB"); } catch (Exception ex) { Snackbar.Add($"Unexpected error saving watermark: {ex.Message}", Severity.Error); Logger.LogError("Unexpected error saving watermark: {Error}", ex.Message); } } }