From a9eb3602880d1525594225883a3e13ce2cad11ff Mon Sep 17 00:00:00 2001 From: gramps Date: Sat, 29 Aug 2026 09:02:55 -0700 Subject: [PATCH] TASK 18: local (record-only) recording pipeline + top-bar pills/light/Start-End button UX Encoder dual-output: StreamEnabled/RecordEnabled/RecordPath options; per-output ffmpeg block (stream ->flv, record ->mp4); throw unless at least one output. RecordingFile: auto-name ty---0000.mp4, rename-on-stop to ty-...-.mp4 with numeric-suffix on collision. LayoutStore persists record folder. MainViewModel: REC/ON-AIR pills, status light, single Start<->End button (replaces Start/Stop variants), StopStream no longer signs out, explicit session timer. About overlay widened. Sign In label + spacing before Start. Tests: 244 passed / 246 (2 pre-existing: AudioPipeline gains-mute, RoundClip). Build 0 warnings. Scope check clean. Memory-map correction (derived-solution rule, 2026-08-29): image-shrink recipe was never recorded when first done, so it was re-derived. Added Derived-solution/recipes rule to AGENTS.md; MyMistakes.md now a permanent recipes registry (records the verified WPF-imaging shrink recipe); schema.md rows MyMistakes as registry; ai.md points to the rule. README hero image replaced: 3.2MB screenshot -> 1400x794 -> 188KB docs/ytLlive-preview.jpg (JPEG q82). --- AGENTS.md | 9 + HANDOFF.md | 106 +++++----- MainWindow.xaml | 48 +++-- MyMistakes.md | 47 ++++- README.md | 2 +- Services/Encoder/EncoderOptions.cs | 13 ++ Services/Encoder/FfmpegArgs.cs | 68 +++--- Services/Encoder/FfmpegEncoder.cs | 8 +- Services/Encoder/FramePump.cs | 2 +- Services/LayoutStore.cs | 24 +++ Services/RecordingFile.cs | 27 +++ TASKS.md | 21 +- ViewModels/MainViewModel.cs | 328 ++++++++++++++++++++++++++--- ai.md | 54 ++++- docs/ytLlive-preview.jpg | Bin 0 -> 192946 bytes docs/ytLlive-preview.png | Bin 330093 -> 0 bytes schema.md | 1 + ytLive.Tests/FfmpegEncoderTests.cs | 50 +++++ ytLive.Tests/FramePumpTests.cs | 2 +- ytLive.Tests/RecordingFileTests.cs | 49 +++++ 20 files changed, 708 insertions(+), 151 deletions(-) create mode 100644 Services/RecordingFile.cs create mode 100644 docs/ytLlive-preview.jpg delete mode 100644 docs/ytLlive-preview.png create mode 100644 ytLive.Tests/RecordingFileTests.cs diff --git a/AGENTS.md b/AGENTS.md index b99617f..b13a37a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -53,6 +53,15 @@ at a problem. - **The first time a fact costs a hunt (secrets path, DB path, port, recovery source), record it** in `ai.md`/indexes/`HANDOFF.md` so the next session never re-hunts it. +- **Derived-solution rule (record once, then grep):** the moment you work out a + reusable solution — a recipe, workaround, or how-to (e.g. how to shrink and + re-encode an image for the README) — write it into `MyMistakes.md` **in the same + session**, before you finish the task. And always **grep `MyMistakes.md` first** + when you hit a "I've done this before but have to figure it out again" wall. A + solution recorded once ends the re-derivation loop; an un-recorded solution is a + guarantee you will re-derive it and make the user sit through it again. This is + the fix for the image-shrink incident (2026-08-29): the recipe was never written + down, so it had to be worked out from scratch a second time. - **Follow existing conventions** — MVVM, `RelayCommand` for actions, `ViewModelBase.SetProperty()`, all styles in `Themes/Controls.xaml` (merged once in `App.xaml`; never duplicate per-window). diff --git a/HANDOFF.md b/HANDOFF.md index 9ba7ce4..06b123a 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -2,66 +2,74 @@ ## Branch / Commit State -**`main`**, working tree clean. Web-source bounding work is **DONE, verified, committed, and -PUSHED (2026-08-28)** — the first push in a while; the web feature is complete and on origin. -No feature branches pre-1.0: all work lands on `main` per work unit. +**`main`**, working tree has an **uncommitted TASK 18 work unit** (record-only pipeline + top-bar +pills/light/button UX + About resize + now button-label Start/End simplification) **plus a docs/image +memory-map fix** (derived-solution rule + README hero image). `origin/main` and head are both at +**`1e633f9`** (spin-guard rule), already pushed. This session's changes are **NOT committed** yet — see +"Next steps". -## The web-source rendering work (2026-08-28) — DONE: canvas-size viewport + ALPHA-BBOX crop +No feature branches pre-1.0: all work lands on `main` per work unit (pending the creator's go-ahead to +commit + push). -**VERDICT (creator, 2026-08-28):** bounding is PERFECT. Verified with a second widget resource that -has no glow effect. The earlier "remaining defect / dead-space gap" was the WIDGET'S OWN GLOW -effect pushing out its perceived borders — NOT a code bug. The alpha-bbox was already hugging the -glow halo; with a plain widget the dashed selection border sits exactly on the widget edge. +## Memory-map corrections (2026-08-29 — "don't re-derive" fix) -**History of failures (log wiped from MyMistakes.md per task-complete rule; see git history):** -box-size rendering clipped full-bleed widgets to their upper-left chunk; `JSON.stringify` return -double-encoded under `ExecuteScriptAsync` (crop silently disabled); `scrollWidth/scrollHeight` at -canvas size = whole viewport for full-canvas wrappers (no trim); DOM-element-union measured an -unsettled layout on NavigationCompleted (BROKE the image); sizing the container to the crop -(`ab29ec8`) made things worse (reverted). +- **Incident:** the image-shrink recipe (for `docs/ytLlive-preview.jpg`) was never recorded when first + done, so it was re-derived from scratch. Fixed by: +- **`AGENTS.md`** → Working rules: new **🔬 Derived-solution rule** (record a one-off solution in + `MyMistakes.md` the same session; grep it first on any "did this before?" wall). +- **`MyMistakes.md`** → contract expanded: per-task failure log **+ RECIPES REGISTRY** (permanent, NOT + truncated); recorded the verified image-shrink recipe. +- **`schema.md`** → file inventory now rows `MyMistakes.md` as the recipes registry. +- **`ai.md`** → Derivative-work section notes the derived-solution rule (registry reachable from map home). +- **`README.md`** + `docs/ytLlive-preview.jpg` → README hero image replaced (screenshot downscaled to + 1400×794, 188KB JPEG). -**The model that shipped:** -- `Services/WebView2Manager.cs` — page renders at 1920×1080 (stable, never tracked); `overflow:hidden` - + transparent-bg injection. `FindContentBounds` scans the Bgra32 capture per frame and crops to the - bounding box of NON-TRANSPARENT pixels — the widget's true rendered extent, measured from the frame - itself. No DOM query, no layout timing: it can never truncate visible content (worst case = full - frame = the confirmed-good image). `Stretch="Fill"` maps the cropped frame flush under the selection - box → the box hugs the widget on all four sides. `QueryContentBoundsAsync` + the JS script are - DELETED. -- `MainWindow.xaml` — web `` Stretch set to Fill via the IsWebSource DataTrigger (unchanged). -- Invariant: **render at canvas size; crop to the alpha extent; Fill to the box.** -- Unit tests: 7/7 (3 `FindContentBounds`, 4 control-size.) -**Property panel / sliders (2026-08-28):** web URI ✕ clears the textbox; web ✓/✕ icon buttons -`IsTabStop="False"` so Tab walks X→Y→W→H→URI; Slider style `IsMoveToPointEnabled="True"` -restores click-anywhere-on-bar. All three confirmed fixed by the creator. +## TASK 18 — Local recording (in progress, 2026-08-29) -Build: 0 warnings; tests 7/7 (WebView2Manager). Rejected for the record: box-sized viewport (upper-left -truncation), fixed 1920×1080 + `Uniform` (letterbox dead space), CSS margin/100% reset (enlarged gap), -viewport==box (reflow/truncation/scrollbars), DOM-union crop (broke the image), container==content -auto-fit sized to the crop (`ab29ec8`, reverted). +**Shipped in this (uncommitted) change:** +- `EncoderOptions` + `FfmpegArgs` + `FfmpegEncoder`: independent `StreamEnabled`/`RecordEnabled`/ + `RecordPath`; per-output blocks (`-f flv` stream, `-f mp4` record); encoder throws unless ≥1 output. +- `MainViewModel`: REC + ON-AIR pill toggles, status lights, dynamic `PrimaryButtonText` + (Start Streaming / Start Recording), `ShowPrimaryStartButton`/`ShowLogInButton`/`ShowEndStreamButton`, + `CanStartSession`, `AccountStatusLightToolTip`; `IsEditMode` += `!IsRecording`. +- `StartSession()` routes: ON-AIR → GoLive dialog then stream (± record); only-REC → `BeginRecordOnly()` + (no YouTube dialog). `StopStream()` no longer signs the creator out (explicit logout only) and runs + **rename-on-stop** to `ty---.mp4`. +- `Services/RecordingFile` (pure): auto-name `ty-…-0000.mp4` → rename-on-stop with hh2mm2 length. +- `LayoutStore.Load/SaveRecordFolder` + `ChooseRecordFolderCommand` (`OpenFolderDialog`), default + `%APPDATA%\ytLlive\recordings\`. +- `MainWindow.xaml`: REC/ON-AIR pill `ToggleButton`s + status lights, dynamic button, status-light tooltip, + About overlay border 520→650 / MaxHeight 560→700 / padding 24→28, About grid background `#171928`. +- Tests: `FfmpegEncoderTests` record-only + dual-output arg tests; `RecordingFileTests` (naming rules). + +**Not done / parked:** manual rename dialog for the user (planned as a modal, needs a trigger since the +toast service has no actions) — parked; running-app verification of rename + dual output. ## Key facts / landmines -- **Why the web-box saga spun (2026-08):** nine commits of in-head theorizing for a problem - OBS already solved (browser source = fixed canvas, box = user-sized, content clips at the - edge). The apparent gap was the widget's CSS glow, not a bug. → AGENTS.md now mandates - external research on the second failed fix and proactive scans for new features. - -- **App running locks `ytLive.exe`** → build fails MSB3027 until creator exits the app. -- **Startup diagnostics:** unhandled exceptions + checkpoints go to `%APPDATA%\ytLlive\startup.log` - (`Helpers/AppLog.cs`). On a silent startup crash, read that. -- **Pre-existing test failures (unrelated to web source, do not chase):** - `AudioPipelineTests.Mix_HonorsProviderGains_AndGameMute_KillsTheLoopback` + - `RoundClipInteractionTests.Round_Clip_Corner_Is_Grabbable_And_Shape_Is_Circle`. +- **Pre-existing test failures (do not chase):** `AudioPipelineTests.Mix_HonorsProviderGains…` + + `RoundClipInteractionTests.Round_Clip_Corner_Is_Grabbable…` — fail on `main` with this change unapplied. + All other tests pass (incl. the 7 new recording tests). +- **App running locks `ytLive.exe`** → build fails MSB3027 until the creator exits the app. +- **Startup diagnostics:** `%APPDATA%\ytLlive\startup.log` (`Helpers/AppLog.cs`). - **Real-MainWindow tests MUST set `LayoutPathOverride`** — DB pollution wiped real data once. -- **Good Dog Rule:** ONE integration test per change; no new feature branches pre-1.0. -- **Scope Lock:** declare the file list, run `scripts/scope-check.sh` before every commit. +- **Good Dog Rule:** ONE integration test per change; no feature branches pre-1.0. +- **Scope Lock:** declared list below; run `scripts/scope-check.sh` before committing. - **Every feature change ships memory updates in the SAME commit** — `TASKS.md` status + this file. - No `CODING.md`; conventions live in `AGENTS.md` + `ai.md`. +## Commit scope (declared) + +`Services/Encoder/EncoderOptions.cs Services/Encoder/FfmpegArgs.cs Services/Encoder/FfmpegEncoder.cs +Services/Encoder/FramePump.cs Services/RecordingFile.cs Services/LayoutStore.cs +ViewModels/MainViewModel.cs MainWindow.xaml ytLive.Tests/FfmpegEncoderTests.cs +ytLive.Tests/FramePumpTests.cs ytLive.Tests/RecordingFileTests.cs +AGENTS.md TASKS.md ai.md HANDOFF.md MyMistakes.md schema.md README.md +docs/ytLlive-preview.jpg docs/ytLlive-preview.png(deleted)` + ## Next steps -1. Done (2026-08-28): web-source bounding verified PERFECT and pushed. If an animated widget causes - visible crop jitter later, add hysteresis as a follow-up — not queued. -2. Graceful handling of navigation errors / invalid URIs (TASK 17 ×9) — only if the creator asks. -3. Continue queue: TASK 18 local recording, TASK 21 media source, TASK 22 audio sync offset. \ No newline at end of file + +1. Creator to decide: commit + push this TASK 18 work unit (scope list above), or refine first + (verify the rename + dual output in the running app before committing). +2. Continue queue: TASK 21 media source, TASK 22 audio sync offset. diff --git a/MainWindow.xaml b/MainWindow.xaml index 8a46848..2a5f9a1 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -111,10 +111,23 @@ - + - + + + + + + + @@ -134,7 +147,9 @@ - +