From ded5a3e5ebb4bec7d64943c519c3319027d2b1cc Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Wed, 10 Jun 2026 14:14:35 -0400 Subject: [PATCH] feat(manager): add optional cover art upload to Add Track form --- .../Components/Pages/Tracks/TrackNew.razor | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/DeepDrftManager/Components/Pages/Tracks/TrackNew.razor b/DeepDrftManager/Components/Pages/Tracks/TrackNew.razor index ed95ec1..e94d2b8 100644 --- a/DeepDrftManager/Components/Pages/Tracks/TrackNew.razor +++ b/DeepDrftManager/Components/Pages/Tracks/TrackNew.razor @@ -29,6 +29,34 @@ + + + + @if (_selectedImageFile is { } selectedImage) + { + + Selected: @selectedImage.Name + + + } + else + { + No cover art — optional. + } + + + @if (_selectedImageFile is not null) + { + Will upload on save. + } + + + @if (!string.IsNullOrEmpty(_errorMessage)) @@ -67,6 +95,8 @@ private const long MaxUploadBytes = 1_073_741_824L; private IBrowserFile? _selectedFile; + private IBrowserFile? _selectedImageFile; + private string? _imagePath; private string _trackName = string.Empty; private string _artist = string.Empty; private string _album = string.Empty; @@ -81,6 +111,18 @@ _errorMessage = null; } + private void HandleImageFileSelected(InputFileChangeEventArgs e) + { + _selectedImageFile = e.File; + _imagePath = null; + } + + private void ClearImage() + { + _selectedImageFile = null; + _imagePath = null; + } + private async Task SubmitAsync() { _errorMessage = null; @@ -130,6 +172,21 @@ _isUploading = true; try { + // Upload any selected cover art first; abort the submit if it fails so we never + // create a track expecting an image that was never stored in the vault. + if (_selectedImageFile is { } imgFile) + { + await using var imgStream = imgFile.OpenReadStream(maxAllowedSize: 50_000_000); + var imgResult = await CmsTrackService.UploadImageAsync(imgStream, imgFile.Name, imgFile.ContentType); + if (!imgResult.Success) + { + var imgError = imgResult.Messages.FirstOrDefault()?.Message ?? "Unknown error"; + _errorMessage = $"Image upload failed: {imgError}"; + return; + } + _imagePath = imgResult.Value; + } + // OpenReadStream streams chunks from the browser via the SignalR circuit; the // service wraps it in StreamContent so the whole file is never materialised in // memory before DeepDrftAPI receives it. @@ -149,6 +206,26 @@ if (result.Success) { + // The upload endpoint does not accept an imagePath, so link the cover art with a + // follow-up metadata update — same two-step pattern TrackEdit uses. + if (_imagePath is { } imgPath && result.Value is { } created) + { + var linkResult = await CmsTrackService.UpdateAsync( + created.Id, + _trackName, + _artist, + string.IsNullOrWhiteSpace(_album) ? null : _album, + string.IsNullOrWhiteSpace(_genre) ? null : _genre, + string.IsNullOrWhiteSpace(_releaseDate) ? null : (DateOnly?)DateOnly.ParseExact(_releaseDate, "yyyy-MM-dd"), + imgPath); + if (!linkResult.Success) + { + // Track was created; image is in the vault but unlinked. Non-blocking — + // the user can attach it via Edit. + Snackbar.Add("Track uploaded, but cover art could not be linked. You can add it via Edit.", Severity.Warning); + } + } + Snackbar.Add($"Uploaded '{_trackName}'.", Severity.Success); Navigation.NavigateTo("/tracks"); return;