Files
LlamaCasty/Models
gramps 0fade9702b feat(ypp): session report derived from YouTube — no ledger, money off by default (TASK 3·20)
The task asked for a `RewardEvents` table plus a backfill. That would have contradicted the published
promise that no viewer, member or donor information is retained after the session ends, and it would
have meant owning a ledger that YouTube already keeps.

So the report is DERIVED on demand instead:

- `Services/SuperChatEventService.cs` — `superChatEvents.list`, parsed for both event types (a sticker
  must not be dropped), authorised by the existing `auth/youtube` scope, so no re-consent.
- `Models/SessionRewardSummary.cs` — rolls events up for the session window with **per-currency totals
  that are never summed together** (a $5 and a €5 are not $10). Nothing is written down.
- The YPP drawer gains a **THIS SESSION** section: counts are neutral and always shown when there were
  events; money appears only when the creator asks for it. `Show monetary metrics` is a drawer toggle,
  persisted, **off by default** — a creator who never monetized is never shown a $0.00.

Also: money is labelled as estimates (removed/refunded events are excluded and totals can be restated
for weeks, not days).

Tests: `SessionRewardReportTests` — both reward types parse, the window makes it a session rather than
a channel report, currencies stay separate, an empty session shows nothing, a sticker-only session
still counts. `BackOnAirTests` moves into the serialised `MainViewModelLayoutPath` collection: it builds
a MainViewModel directly and was flaking against parallel tests that swap the static layout path.

FAST gate: 557 passed, 0 failed, 0 warnings.
2026-11-05 15:38:32 -08:00
..
TASK 9 audio milestone: real stream audio + voice filters + auto-duck + free TRAX music — the mixer now feeds the encoder real audio (ffmpeg reads a Windows named pipe, -f f32le -ar 48000 -ac 2 -i \.\pipe\ytllive_audio, replacing anullsrc silence; explicit -map 0:v -map 1:a via EncoderOptions.AudioPipeName), with honest gains reaching the stream (MicVolume scales mic, GameAudioVolume + mute scale loopback, Func<double> seams on AudioMixer), an always-on pure-C# voice chain on the mic BEFORE the meter and mix (LowShelfFilter 120Hz +4dB → HighShelfFilter 8kHz +3dB → NoiseGate 0.005/hysteresis 0.5 → Compressor 0.5 4:1, all TDF2), AutoDucker (mic RMS>0.02 → loopback ×0.25, attack 0.05/release 0.005), and TRAX free background music (MusicPlayer = MediaFoundationReader → VolumeWaveProvider16 at fixed 0.20 → WaveOutEvent via the new sibling NAudio.WinMM 2.2.1 package; plays to the default device so the existing loopback carries it, ducked with game; footer TRAX button with red/yellow/green status dot, left-click toggles/picks, right-click opens the OpenFileDialog picker, tooltip shows the track name; persisted via schema v9 single-row Music). Build-time deviations from the plan (recorded in ai.md + TASKS.md): WasapiCapture in NAudio 2.2.1 exposes no overridable GetDefaultMixFormat so sources run device mix format and the mixer's TinyResampler normalizes any rate to 48kHz (resampler IS the design); FfmpegEncoder.cs untouched — MainViewModel.StopStream calls _audioMixer.StopLive() (pipe EOF) before the frame pump stops; sound-bar relabelled 'Desktop Audio', IsGameAudioBarVisible = game sound OR music playing. Tests: new AudioPipelineTests (DSP/ring-buffer/ducker/resampler units + the ONE integration test Mix_WithFiltersDuckAndGain_Lands_On_AudioPipe reading real pipe bytes; ring-buffer overwrite bug found + fixed), FfmpegEncoderTests/LayoutStorePersistenceTests updated — 196 tests passing, 0 warnings
2026-08-14 18:09:26 -07:00
Scene strip tile artwork + on-air indicator (creator ruling 2026-10-10). Top-bar tiles now carry their own art: each canonical scene's tile is a per-scene CRT-styled image stored in the internal DB (Scene.ThumbnailAssetId - additive migration, seeded at heal from the creator's five Downloads JPGs via SceneThumbnailSeedPaths), and the preview pane keeps rendering the scene's ORIGINAL background - never the tiles. One shared on-air image (Gemini 4zajyl...jpg) replaces the staged scene's tile and follows the scene swap ('the on-air screen jumps around the top bar as the user swaps scenes'): stored as an Asset BLOB tracked by the OnAirImageAssetId Setting (EnsureOnAirImage, same contract as the alert clip) with MainViewModel.OnAirSeedPath override; RefreshSnapshotsAsync shows it for the staged scene, otherwise thumbnail-or-background art, and a staged Live with no on-air art still falls back to the green placeholder (minis never render live captures). Removed the 6px #22c55e rectangle in PreviewPane's backdrop ('green outline around the preview screen' that surfaced when a scene had no background) - the outer PreviewGlow red border is the real live signal. Doubled the scene-tile labels (FontSize 10 -> 20). Fixed a real bug this surfaced: Save()'s Asset pruner only kept Source/alert-clip rows, so the first save would have DELETED the seeded tile + on-air assets - the keep-set now includes Scene.ThumbnailAssetId and the OnAirImageAssetId Setting. New Settings/Load/Save migrations + SceneThumbnailTests (4 tests: seeded tile in strip, preview keeps original bg, Live-staged tile, no-seed fallback, on-air swap + persistence). 427 pass, 0 build warnings. (Unit: strip tiles + on-air)
2026-10-10 13:27:26 -07:00