feat(web+api): FFmpeg profile, filler preset & watermark editors for SPA parity (#143) #166

Merged
timothy merged 5 commits from feat/143-transcoding-editors into main 2026-07-07 15:06:39 +02:00
5 Commits
Author SHA1 Message Date
timothyandClaude Fable 5 66abb24402 test: cover FillerPresetController + WatermarkController in API security test (#166 review)
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 4m15s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 4m36s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 15:01:10 +02:00
timothy 7454411dee Merge remote-tracking branch 'origin/main' into feat/143-transcoding-editors
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 4m10s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 4m30s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
# Conflicts:
#	web/src/App.tsx
#	web/src/screens/SettingsScreen.tsx
2026-07-07 14:55:55 +02:00
timothyandClaude Fable 5 bef33c2950 fix(api): 404 for missing filler preset / watermark on PUT and DELETE (#159)
Live E2E found PUT/DELETE on a missing filler preset or watermark returned 422
instead of 404. Root cause: the must-exist checks fed a NotFoundError through
LanguageExt Validation, whose aggregation to Either flattens the BaseError
subtype, so ApiResults.ToErrorResult never saw a NotFoundError. The precedent
handlers (DeleteProgramSchedule, DeleteFFmpegProfile, UpdateProgramSchedule)
avoid this by resolving must-exist as an Option and returning the NotFoundError
directly as an Either Left via Option.Match — restructured the four
filler/watermark Update/Delete handlers to that pattern (remaining name
validation still 422s). No Blazor behavior change (it only reads error.Value).

Verified live: PUT/DELETE missing → 404, GET missing → 404, empty-name POST →
422; happy-path CRUD unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 14:48:38 +02:00
timothyandClaude Fable 5 e95eed11dd feat(web): FFmpeg profile, filler preset, watermark editors (#143)
Three new SPA list+editor surfaces, closing the Blazor-only gap found in the
#91 phase-(b) recon:

- FFmpeg Profiles (System group): list with resolution/video/audio summary +
  add/copy/delete; full General/Video/Audio editor. Per-hwaccel video-format
  and profile rules ported from FFmpegProfileEditViewModelValidator; video
  preset list ported from FFmpegLibraryHelper.PresetsForFFmpegProfile /
  AvailablePresets.ForAccelAndFormat (cited in code). Resolutions from
  /api/settings/resolutions, hwaccel kinds from the new lookup endpoint.
  Copy = client-side clone into the create form (no server copy endpoint).
- Filler Presets (Media group): list + editor with the Blazor VM interlocks
  (Fallback/Tail force mode None; non-MidRoll clears expression; Fallback
  disables chapters; Playlist collection type forces Count mode; duration/
  count/pad fields gated by mode). Collection pickers use the existing
  /api/library/browse client for all seven collection types incl. Playlist.
- Watermarks (System group): list + editor with mode-driven field enabling,
  ChannelLogo vs Custom image source, upload via /api/artwork/uploads
  (target=watermark) and preview via /artwork/watermarks/{path}.
- App.tsx: ScreenIds/routes (sub-paths /add + /{id}) and nav registration;
  api modules ffmpegProfiles/fillerPresets/watermarks with URL-assert tests;
  SettingsScreen Classic-UI help text updated (these are no longer
  Blazor-only) and the FFmpeg-profiles card now links to the new screen.
- Regenerated web/src/api/generated/v1.d.ts from the #159 OpenAPI changes.

web verification: typecheck clean; vitest 188/188 (14 files); vite build OK;
eslint clean on touched files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 14:33:01 +02:00
timothyandClaude Fable 5 46c8c2e2dc feat(api): filler preset + watermark editor CRUD; ffmpeg profile round-trip (#159)
Backend plumbing for the SPA transcoding editors (#143 blocker):

- FFmpeg profile response DTO round-trip: add NormalizeAudio, NormalizeVideo,
  PadMode, TargetLoudness, NormalizeColors, ResolutionId (keep Resolution name
  for compat); DeinterlaceVideo now bool (was bool?). #nullable enable on the DTO.
- New GET /api/ffmpeg/hardware-acceleration-kinds wrapping
  GetSupportedHardwareAccelerationKinds (returns enum names as strings).
- Filler preset CRUD: GET-by-id/POST/PUT/DELETE on FillerPresetController with
  full request/response DTOs; new FillerPresetFullResponseModel +
  GetFillerPresetByIdForApi. CreateFillerPreset now returns the new id
  (CreateFillerPresetResult) to match sibling Create commands and enable a
  201+Location; updated the one Blazor call site.
- Watermark CRUD: GET-by-id/POST/PUT/DELETE on WatermarkController with full
  DTOs (path+contentType, all 15 fields); new WatermarkFullResponseModel +
  GetWatermarkByIdForApi.
- Startup: register WatermarkLocation/WatermarkSize as OpenAPI string enums
  (they live in ErsatzTV.FFmpeg.State and were documented as ints, mismatching
  the Newtonsoft StringEnumConverter runtime serialization).
- Tests: full CRUD controller tests for filler + watermark; contract-test
  entries (404/401/422) for the new mutating endpoints; regenerated v1.json.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 14:06:26 +02:00