@@ -338,3 +338,40 @@ NEXT SESSION (session 11) candidates:
338338 playlist/collection tags after rescan (verify tag:"name" queries + smart collections)
339339- late-scheduled force-cut; audio-only error process (anullsrc, x5); icecast endpoint (x5)
340340- ui: announcer + tts endpoints config page, interrupt queue page, books tiles/list toggle
341+
342+
343+ ### Session 11 (2026-07-07): ui + cleanup (branch feature/ui-cleanup)
344+ COMPILE-VERIFIED (app + scanner, 0 errors). Session 10 fully validated live first: wyoming tts
345+ against real piper WORKED FIRST TRY (announcer end-to-end with voice), navidrome playlist tags
346+ (61 playlists/6513 songs), abs collection/series tags (after hotfix 0013: season GetOrAdd missing
347+ .ThenInclude(sm => sm.Tags) -> null Tags crash in the new sync), {artist} template confirmed.
348+
349+ UI:
350+ - /settings/announcer (nav: Settings > Announcer): tts endpoints table (add/delete, wyoming:// or
351+ http(s):// validation) + per-channel announcer form (audio-only channel select; enabled/template/
352+ style/duckPercent/ttsEndpoint select/voice override). Direct IConfigElementRepository access,
353+ deliberately duplicating the small controller read/write logic for leanness.
354+ - /system/interrupts (nav: Support > Interrupts): audio-only channel selector, sessionActive chip,
355+ queue table (title/priority/style/duration/airAt/expires) with per-row remove + clear all, 5s
356+ auto-refresh (System.Timers + InvokeAsync).
357+ - books tiles/list toggle: ?view=tiles query param (linkable, author filter preserved);
358+ AudiobookBookViewModel gained Poster (season poster artwork projected in the EF query, abs://
359+ rewritten to relative proxy url via AudiobookshelfUrl.RelativeProxyForArtwork + width=440 in the
360+ handler - same transform the card mapper uses); tiles render shared MediaCard components,
361+ Href=media/tv/seasons/{id}.
362+
363+ Docs:
364+ - README-ERSATZRADIO.md: fork overview, feature list, quickstart, api cheatsheet, limits
365+ - docs/UPSTREAM-SYNC.md: new-vs-modified file inventory; the four conflict-zone files
366+ (HlsSessionWorker, GetPlayoutItemProcessByChannelNumberHandler, FFmpegLibraryProcessService,
367+ GetPlayoutItemProcessByChannelNumber) with the NextState incomplete-realtime INVARIANT called out;
368+ merge procedure + smoke tests + etag bump guidance.
369+
370+ PENDING dakota validations: per-channel voice on an italian channel (it_IT via piper-mkii or voice
371+ override); duckPercent taste tuning (10-15 suggested for loud program material).
372+
373+ NEXT SESSION (session 12) candidates:
374+ - live-test the three ui pages + books tiles
375+ - late-scheduled force-cut refinement; audio-only error process (anullsrc, x5)
376+ - icecast/direct MP3 endpoint (PARKED per dakota: flexibility, not priority)
377+ - possible: announcer preview button (synthesize test phrase), interrupt upload from the ui page
0 commit comments