Commit Graph
21 Commits
Author SHA1 Message Date
timothyandClaude Opus 4.8 f869dfe87a feat(api): GET /api/collections/{id}/items (paged) + confirm POST-items 422 guard (#155)
Adds a paged collection-items endpoint reusing LibraryBrowseItemResponseModel
so the SPA lists a manual collection's full contents (all media kinds), replacing
the lossy Lucene name-based preview. Confirms POST /items already returns 422 for
bogus ids (guarded by ValidateMediaItems, fb3f2856); adds endpoint-level coverage.

fixes #155

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 18:26:52 +02:00
timothy 7083301ce6 Merge remote-tracking branch 'origin/main' into feat/141-media-browse
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 4m37s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 5m5s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
# Conflicts:
#	ErsatzTV.Tests/Controllers/OpenApiErrorResponseContractTests.cs
#	web/src/App.tsx
#	web/src/screens/SettingsScreen.tsx
2026-07-07 15:50:03 +02:00
timothyandClaude Fable 5 6c68c291a0 feat(api): browse all media kinds, grouped search, delete media-items (#141, #161)
- Extend /api/library/browse to episodes, music videos, songs, other videos,
  images and remote streams (new LibraryBrowseMediaType values + hydrators);
  add optional Subtitle to LibraryBrowseItemResponseModel for leaf-item context
- Add GET /api/search: grouped per-kind results reusing the browse query/shape;
  empty query -> 422
- Add DELETE /api/media-items: body { ids }, empty -> 422, success -> 204
- Tests: SearchController, MediaItemsController, security + OpenAPI contract entries
- Regenerate openapi v1.json + web v1.d.ts

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 15:23:07 +02:00
timothy 1b9d85896c Merge remote-tracking branch 'origin/main' into feat/142-trakt-lists
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 4m28s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 4m40s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
# Conflicts:
#	ErsatzTV.Tests/Controllers/ApiControllerSecurityTests.cs
#	web/src/App.tsx
#	web/src/screens/SettingsScreen.tsx
2026-07-07 15:13:22 +02:00
timothy 4306b39ef8 feat(api): Trakt lists REST endpoints (#160)
Adds TraktController (GET/POST /api/trakt/lists, GET/PUT/DELETE by id,
POST .../match, GET /api/trakt/status) covering the API gap for SPA
parity issue #142. Add/match/delete dispatch to the same
ChannelWriter<IBackgroundServiceRequest> the classic Blazor "Trakt
Lists" page uses, gated by the existing IEntityLocker (LockTrakt/
IsTraktLocked) singleton; GET /api/trakt/status wraps IsTraktLocked as
the HTTP-observable substitute for the Blazor page's OnTraktChanged
event. URL validation mirrors AddTraktListHandler.ValidateUrl's regexes
(replicated, since that method is private to the handler and returns a
handler-private record) so an obviously-invalid URL gets a synchronous
422 before dispatch.

Adds TraktListResponseModel/PagedTraktListsResponseModel/
TraktStatusResponseModel DTOs, AddTraktListRequest/UpdateTraktListRequest,
controller tests, ApiControllerSecurityTests + OpenApiErrorResponseContractTests
coverage, and regenerates the checked-in OpenAPI document.
2026-07-07 15:09:12 +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
timothyandClaude Fable 5 540def7f17 fix: address #93 adversarial review findings
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 4m51s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 5m21s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Backend: 401 documented on all mutating settings/resolution routes;
resolution delete distinguishes 404 (unknown) from 422 (not custom);
XMLTV enum bridging via exhaustive switch instead of int casts;
field-level Arg.Is assertions incl. non-null watermark/filler flow.

Frontend: resolution add/delete failures surfaced inline (were
silent); partial saves merge succeeded groups via allSettled; empty
numeric fields invalid + tunerCount min 1; HLS Direct select shows
out-of-list wire values; media-source rows show derived last-scan.

ErsatzTV.Tests 495; web suite 145.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 09:22:51 +02:00
timothyandClaude Fable 5 57905bc0f4 feat(api): settings read/write endpoints (#93)
GET/PUT /api/settings/{ffmpeg,playout,xmltv,scanner,logging,ui,hdhr}
wrapping the existing MediatR settings handlers, plus custom resolution
list/create/delete under /api/settings/resolutions. String-enum OpenAPI
schemas extended to OutputFormatKind + LogEventLevel.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 09:22:50 +02:00
timothy 6857a0d191 feat(api): composite create-channel endpoint (#63)
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 4m58s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 5m42s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
2026-07-06 20:27:02 +02:00
timothy 7858ac002a feat(api): add channel templates
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 5m34s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 5m58s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
2026-07-06 18:43:39 +02:00
timothy 06355b7590 Merge main into feat/59-spa-foundation (post-#119 backend API sync)
# Conflicts:
#	ErsatzTV.Tests/Controllers/ChannelControllerTests.cs
#	ErsatzTV/Controllers/Api/ChannelController.cs
#	ErsatzTV/wwwroot/openapi/v1.json
2026-07-04 07:51:56 +02:00
timothyandClaude Fable 5 3d086aabc1 feat(api): artwork upload endpoint (#104)
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 4m4s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 5m1s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
POST /api/artwork/uploads (multipart/form-data) accepting logo and
watermark images. Validates content type (png/jpeg/gif/webp) and size
(SystemEnvironment.MaximumUploadMb, default 10MB) mirroring the Blazor
upload path; stores via IImageCache.SaveArtworkToCache; returns
{ path, contentType } consumable by channel create/update.

Includes handler + controller tests, OpenAPI 422 contract-test entry,
and regenerated v1.json.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 23:32:22 +02:00
timothyandClaude Fable 5 20ca71b388 feat(api): playout read endpoints + reset-all (#100 #101 #107 #110)
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 2m59s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 4m2s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
- GET /api/playouts — paged list over GetPagedPlayouts (query/pageNum/pageSize), list DTO with buildStatus (#100, #107)
- GET /api/playouts/{id}/items — paged future items + UNSCHEDULED gaps over GetFuturePlayoutItemsById; 404 ProblemDetails for unknown playout (matches /api/schedules/{id}/items precedent) (#101)
- buildStatus {lastBuild, success, message} on GET /api/playouts/{id} (BuildStatus now included by GetPlayoutByIdHandler) (#107)
- GET /api/playouts/warnings/count — failed-build count for the warnings badge (#107)
- POST /api/playouts/reset-all — 202 Accepted, wraps ResetAllPlayouts (#110)
- POST /api/channels/{channelNumber}/playout/reset — optional ?mode= override; default branches by ScheduleKind (Classic→Refresh, others→Reset) to match Blazor semantics (#110)
- Option<FillerKind>→FillerKind? projection uses MatchUnsafe (Match throws on null-returning branch; idiom per Health/Mapper.cs)
- Tests: controller unit tests (routes, projections, 404s, reset-mode defaults), OpenAPI ProblemDetails contract entry for /api/playouts/{id}/items get 404
- Regenerated wwwroot/openapi/v1.json

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 22:28:09 +02:00
timothy f01ffc6254 test(api): enforce nullable channel now playing schema 2026-07-02 19:50:19 +02:00
timothy 6057bcea7d docs(api): document channel state endpoint 2026-07-02 19:45:53 +02:00
timothy 6b3a698283 feat(api): add bulk channel operations
fixes #98
2026-07-02 19:07:35 +02:00
timothy 32c0d6a6d3 feat(api): enrich channel list response 2026-07-02 18:56:05 +02:00
timothy 861827dcbc feat(api): standardize ffmpeg profile endpoints
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 5m12s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 6m13s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
refs #38
2026-06-30 07:29:47 +02:00
timothy b53b06c615 feat(api): add playout REST endpoints
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 3m34s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 4m48s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
fixes #37
2026-06-29 20:31:18 +02:00
timothy b552905799 feat(api): add schedule REST endpoints
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 3m40s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 4m52s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Refs #36
2026-06-29 08:13:14 +02:00
timothy c113142a3d fix(api): standardize error response contract
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 3m34s
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
refs #46
2026-06-28 14:58:48 +02:00