Commit Graph

87 Commits

Author SHA1 Message Date
gramps 5eecf4536f refactor: split Account out of MainViewModel — Commit 1/12 (tag refactor-commit-1)
Pure member movement into MainViewModel.Account.cs (zero behavior change):
session restore (LoadSavedSessionAsync), sign-in/out/change (SignInAsync,
SignOutYouTubeAsync, ChangeAccountAsync), IsConnected + account avatar/name +
AccountStatusLightToolTip. Partial carries its own usings (ytLive.Services for
the INotificationService default interface methods). docs in same commit:
ViewModels/index.md split table + tagging convention.
2026-08-30 07:13:17 -07:00
gramps abc78cd071 MainViewModel is now a partial class — scaffold for the per-area split (Commit 0)
Zero behavior change: \`public class\` -> \`public partial class\`. Each functional area
(Scenes, Background, Webcam, Audio, Trax, Socials, Streaming, Chat, Overlays,
Account, License) will move to its own file next, one commit per partial — each
a roll-back point. Docs updated in the same commit: ViewModels/index.md (split
map), ai.md (architecture table), HANDOFF.md (state). verify.sh: build 0 warnings,
only the 2 known pre-existing test failures.
2026-08-30 07:07:35 -07:00
gramps 6031a5682d Gear cleanup + Default Location for Recordings + single Start + socials hover glow
KISS: removed Gear-menu Save/SaveAs/Open Layout (redundant with auto-save; multi-layout = OBS).
App Settings: first real setting — Default Location for Recordings (Browse + Use Downloads reset,
fallback: configured → Downloads → MyVideos). Single Start button (pills = intent, button = trigger).
Socials button moved to preview bottom row, left of TRAX; hover pulses the SocialBarElement
DropShadowEffect (sine wave BlurRadius 24→48, Opacity 0.7→1.0 at 30ms). TextBox OneWay binding
fix for get-only RecordFolderDisplay. ONE fallback test. Build 0 warnings, 247 tests (2 known).
2026-08-29 10:30:40 -07:00
gramps 46f4696db6 TASK 18: manual rename modal for finished recordings
RenameRecordingDialog (themed, mirrors GoLiveWindow chrome): pre-fills the auto stem,
Enter/OK saves, Esc/Cancel keeps the auto name, strips stray .mp4, rejects invalid
filename chars. FinalizeRecordingAsync shows it before UniquePath rename. Naming logic
still covered by RecordingFileTests; UI shell is pure. verify.sh gate: 0 warnings,
244/246 (2 known).
2026-08-29 09:24:13 -07:00
gramps a9eb360288 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-<yyyymmdd>-<start hhmm>-0000.mp4, rename-on-stop to
ty-...-<len hhmmss>.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).
2026-08-29 09:02:55 -07:00
gramps 9b56e88800 Revert ab29ec8: container==content auto-fit made it worse — back to alpha-crop with the container at element size
The container tracks the element's own Width/Height again; the crop stays in the bitmap.
2026-08-28 12:09:13 -07:00
gramps ab29ec801d Web source: container == content — element grid + selection box sized to the cropped frame's canvas extent
- FindContentBounds already trimmed the bitmap; the grid/box still rendered at the uncropped user
  size, so Fill stretched the tight widget into a bigger frame = dead-between-content-and-border.
- ContentCanvasSize maps the crop rect to canvas units (1920/pixW per axis, DPI-correct) and the
  preview event now carries (bitmap, canvasW, canvasH).
- OnWebView2PreviewBitmapChanged sets the element Width/Height to that size; the grid and the
  SelectionOverlay (both bound to the element's Width/Height) now equal the widget exactly.
- IsPreviewDragging (set in MainWindow drag/resize) suppresses auto-fit mid-gesture.
- Tests 10/10 (alpha bounds, canvas-size mapping incl. DPI, control size); 0 warnings.
2026-08-28 12:08:04 -07:00
gramps e917c41a48 Web source: fix rendering — fixed 1920×1080 viewport (OBS pattern), Stretch=Uniform, startup registration 2026-08-28 10:23:59 -07:00
gramps fd6e02b687 Web source: off-screen WebView2 capture + layout persistence + transparent bg
Bundle exception (2026-08-27): this lands prior-session work plus today's
transparency fix as one commit per creator instruction.

WebView2Manager (new): off-screen WebView2 control parked at -5000/-5000 in
the window's visual tree, captures via CapturePreviewAsync every 100 ms into
a BGRA8 VideoFrame. Source Width/Height sync to the control via
PropertyChanged. JS transparent-background injection runs on every
NavigationStarting/NavigationCompleted so the page's own CSS does not paint
white over the capture.

Transparency fix: DefaultBackgroundColor = System.Drawing.Color.Transparent
set on the WPF control before EnsureCoreWebView2Async. The WPF SDK doc says
the value is forwarded to the controller on init; the IDL (ICoreWebView2-
Controller2) confirms alpha=0 makes the capture alpha-preserving. The
prior-session 'CoreWebView2.BackgroundColor' path was the wrong property
name and has been replaced.

LayoutStore: WebUri column added (idempotent ALTER TABLE) and round-tripped
on save/load (schema v11).

MainViewModel: WebView2Manager constructed on Loaded; loaded web sources
re-registered; Source.WebUri PropertyChanged forwards to manager.

MainWindow: off-screen host Canvas added to visual tree.

Tests: 3 scale-sync + WebView2_DefaultBackgroundColor_Is_Transparent +
LayoutStorePersistenceTests.WebSource_WebUri_Persists. 234/236 pass
(2 pre-existing failures unchanged).

Scale bug (DPI/physical-pixel mismatch) still open.
2026-08-27 08:52:39 -07:00
gramps 67baac6fdd Rename pull-out tab to 'Stream Settings'; right-click Start Stream → Change Account / Logout 2026-08-26 09:35:07 -07:00
gramps d4aa5e1003 Thumbnail strip: show hotkey label next to each scene name 2026-08-26 08:28:48 -07:00
gramps 3a1484b3c5 TASK 20 step 2: hotkey config UI + modifier chord persistence + conflict detection 2026-08-26 06:48:14 -07:00
gramps 89ab83be2e Update Broadcast button: diff before push, offline=local only, live=API; Go Live empty-field prompt 2026-08-25 17:25:25 -07:00
gramps e6baa55867 Fix logo-click crash (Run is not a Visual); Text tab always visible; avatar initial fallback 2026-08-24 14:44:16 -07:00
gramps b988e6d72e Broadcast Text pull-out (Live screen) + launch geometry 1920x1040/1366x768 with restore 2026-08-24 11:04:41 -07:00
gramps 7357836f9b ON-AIR sign right of REC: gray offline, red public, green private 2026-08-24 10:22:18 -07:00
gramps b0bace7432 TASK 20 step 1: global hotkeys F1-F9 (scenes, stream, mutes, TRAX) 2026-08-24 09:32:54 -07:00
gramps 708b336da7 YouTube Chat layer: one-per-layout gate + legacy label heal (TASK 27) 2026-08-24 09:08:03 -07:00
gramps ef710c5537 Webcam menu gates on the app-wide identity (TASK 26) 2026-08-24 08:56:17 -07:00
gramps 7dd140a4c0 Backgrounds: one locked Background per screen + mini rule (TASK 25) 2026-08-23 13:33:33 -07:00
gramps b400ab59c5 Toasts: non-blocking notifications replace MessageBoxes + log-only failures (TASK 24) 2026-08-23 12:25:04 -07:00
gramps d2114c7e1c the ai is an overthinking fucking moron who needs it's plug pulled until such time it can repeat a similar action with its head and ass 2026-08-23 06:25:38 -07:00
gramps 4b9a8e515f Control Surface UX: pill toggle, background rename, per-scene properties
- Sliding pill toggle (green ON / red OFF) replaces checkbox
- Geometry mismatch error for custom backgrounds
- Backdrop -> Background: C# rename, SQL column rename with migration
- Source.IsBackground: new -> override (fixes WPF binding)
- Legacy 'Backdrop' display name migrated to 'Background'
- Per-scene UseDefaultBackground + CustomBackgroundPath
- Asset files renamed backdrop -> background
- StagedScene/LiveScene split, thumbnail strip, edit gating
- TransitionService (Cut/Fade/Move)
- Context menu: Capture Desktop, Refresh Desktop
- Resolution badge removed, ON-AIR status light added
2026-08-22 18:10:59 -07:00
gramps e06bfa42a8 Fix: TRAX meter reflection — remove double attenuation from slider+loopback 2026-08-21 08:32:20 -07:00
gramps 8951141c65 TASK 10: Polar billing + Velopack auto-updates (steps 1-7) 2026-08-21 08:18:52 -07:00
gramps 0bd17ab428 feat(ui): Show Desktop toggle, avatar login, chat preview, backdrop seeding, border animations
- Source.ShowDesktop bool persisted in DB (schema migration + LayoutStore)
- ClearBackdropCaptureAsync clears CaptureKey + VideoImageSource for static fallback
- Top bar: red/green/pulsing status light, avatar via BitmapImage, Log In button
- ShowStartStream now requires IsConnected
- RunMockChatPreviewAsync: simple async loop, ChatPreviewEnabled property on Source
- EnsureDefaultBackdrop called on every scene switch, seeds all 5 scenes
- SeedEndingBackdrop replaces existing, SeedChatBackdrop added
- SceneCatalog: Chat scene display name corrected (layer = 'YouTube Chat')
- Left panel spacing consistency, context menu reordered
- Border animation rendering via code-behind Storyboard approach
- 3 new backdrop assets (ending-backdrop.jpg, chat-backdrop.jpg, live-backdrop.jpg)
- Build 0 warnings, 178 tests passing
2026-08-20 18:02:41 -07:00
gramps a76a3d2acd fix: BRB backdrop seed replaces existing instead of skipping
SeedBrbBackdrop() now updates the AssetId on an existing Background
source instead of bailing when one already exists. This ensures the
new brb-backdrop.jpg replaces any old image already in the DB.
2026-08-19 15:02:47 -07:00
gramps f40ec83e69 feat: BRB backdrop seed + docs refresh + Polar org ID
- Add brb-backdrop.jpg asset, SeedBrbBackdrop() mirrors Starting pattern
- Update HANDOFF.md (was stale), TASKS.md (TASK 10 ready, TASK 15 2/5), ai.md (org ID)
- Polar org ID c05fb364 obtained via OAT, recorded in CREDENTIALS.md
2026-08-19 15:01:23 -07:00
gramps 26828ccdd7 feat(ui): rename panels Screens → Layers → Properties
Renames all user-facing UI text to distinguish from OBS terminology:
- SCENES → SCREENS (section header, tooltips, hints)
- SOURCES → LAYERS (section header, tooltips, context menu, empty hints, onboarding text)
- ELEMENTS → PROPERTIES (section header, tooltips, empty hint)
- Fallback display name 'Source' → 'Layer'

Code identifiers unchanged (IsElementsPanelEmpty, ShowSourcesEmptyHint, etc.)
16 UI text locations across MainWindow.xaml + MainViewModel.cs
2026-08-19 13:52:42 -07:00
gramps e292f0e037 fix: seed starting backdrop on every load, not just first launch
SeedStartingBackdrop() moved outside the Scenes.Count==0 guard so it
fires on every startup. Existing layouts with a Background source are
skipped (idempotent check).
2026-08-19 13:13:00 -07:00
gramps 6a74147611 feat(chat-overlay): selection highlight + default size + starting backdrop
- Source.IsDraggable now includes ChatBox and WebSource (was Image-only)
- ChatBox default: 400×1080, top-right corner (1520, 0) on first add
- SeedStartingBackdrop: embeds starting-backdrop.jpg as Background source
  in the Starting scene on first launch (pack:// resource)
2026-08-19 13:01:35 -07:00
gramps 65641d84e5 feat(chat-overlay): add ChatBox config UI + schema persistence
- Elements panel config UI for ChatBox source (font size slider,
  font/member/super-chat/background color inputs, max messages slider,
  timestamp/badge toggles)
- Schema migration: 8 new ChatBox columns on Source table (ChatFontSize,
  ChatFontColor, ChatBackgroundColor, ChatMaxMessages, ChatShowTimestamps,
  ChatShowBadges, ChatMemberColor, ChatSuperChatColor)
- Load/save: Source SELECT and INSERT now include all ChatBox fields
- IsElementsPanelEmpty excludes ChatBox so hint doesn't cover config
- ChatBoxRenderer.cs created: WPF FormattedText + RenderTargetBitmap
  renderer for on-stream chat overlay
- Slider bindings set to TwoWay for live propagation
2026-08-19 12:42:32 -07:00
gramps 1613acadc3 TASK 9.4: live chat wiring — right panel with Super Chat + membership badges
- YouTubeStreamService: added GetBroadcastLiveChatIdAsync to fetch liveChatId from broadcast contentDetails
- YouTubeChatService.Poll(): parse snippet.type to handle textMessageEvent, superChatEvent, newSponsorEvent
- MainViewModel: wire _youtubeChat.Start(liveChatId) in PrepareAndStartLiveAsync after broadcast creation
- MainViewModel: wire _youtubeChat.Stop() in StopStream before encoder stop
- MainViewModel: wire _youtubeChat.Dispose() in Shutdown
- MainWindow.xaml: updated chat DataTemplate with member badge (⭐), Super Chat highlight (💰 + gold border), timestamps (HH:mm)
- MainWindow.xaml.cs: auto-scroll ChatListBox on new messages via CollectionChanged
- Chat lifecycle is non-fatal: failures log and the stream continues without on-panel chat
2026-08-19 11:59:29 -07:00
gramps e97406d649 v1 task queue: add TASK 19-23 (transitions, hotkeys, media source, audio sync, studio mode)
- TASKS.md: added 5 new tasks for v1 feature completeness, execution order, updated backlog
- MONETIZATION.md: added v1 feature completeness section (competitive gap analysis)
- ai.md: added v1 task queue note in Current limitations/TODOs
- HANDOFF.md: updated session state and next steps
- ViewModels/SocialsDialogViewModel.cs: removed isPremium parameter (social slot locks)
- ViewModels/MainViewModel.cs: removed isPremium argument from SocialsDialogViewModel constructor
- ytLive.Tests/SocialsDialogViewModelTests.cs: updated 5 tests for unlocked slots
2026-08-19 11:51:32 -07:00
gramps 5ad58542fb Monetization: Polar chosen as billing provider
- Updated ai.md billing decision to reference Polar (polar.sh)
- Updated code comments (PremiumUrl, IsPremium) to reference Polar
- MONETIZATION.md updated locally (gitignored — confidential)

207 tests, 0 warnings.
2026-08-18 10:13:53 -07:00
gramps 30a193b2c9 TRAX: error display, retain track on failure, gray idle dot
1. Error text shows in red inside the desktop audio meter bar (scrollable)
   when TRAX load or playback fails — user gets feedback, not just a
   silent red dot.
2. LoadTrax no longer nulls _music on error — the track path is retained
   so the user sees what failed and can retry.
3. OnTraxPlaybackEnded now receives the NAudio exception and surfaces it.
4. TRAX dot is green (playing) or gray (idle/no track) — no more yellow
   or red states.

207 tests, 0 warnings.
2026-08-18 08:44:21 -07:00
gramps 02cb4bc219 Fix: desktop audio slider now controls system volume (WYSIWYG audio)
Push GameAudioVolume to MMDevice.AudioEndpointVolume.MasterVolumeLevelScalar
on every change. The slider now controls what Windows sends to the
headphones, so the creator hears exactly what the stream carries (minus
mic — monitored via meters only, no feedback).

207 tests, 0 warnings.
2026-08-18 08:27:31 -07:00
gramps 28765a0dbf creator feedback batch: 9 fixes from initial review
1. About box bg → #0A0C1A (matches icon bg)
2. Elements panel collapses when no element selected / scene changes
3. OpacityChip moved from preview overlay into Elements panel
4. Color picker fix: cast to SceneElement not Source (WebcamSceneConfig was silently blocked)
5. Red left accent bar on selected items in Scene/Source lists
6. ✓ character replaced with Path checkmark icon in Elements panel
7. Removed ToolTip='Applied' from green check buttons
8. Created bugs.md with first entry (iTunes audio on mic meter)
9. Full logo in README + About box uses ytLlive-logo.png
2026-08-17 10:16:55 -07:00
gramps 16f905c8d7 feat: Elements panel, Countdown/Web sources, webcam border config (TASK 14 Branch 2)
- New SourceType.Countdown (Starting/BRB only, timer 1-60 min) and SourceType.WebSource (all scenes, URI)
- Elements panel beneath Sources: per-element config with live preview, ✕ revert / ✓ applied indicator
- Webcam border: hex color input + swatch picker, thickness 0-10 slider
- Countdown: timer minutes slider (1-60, default 15), Web: URI text input
- SourceTypeToVisibilityConverter for conditional panel visibility
- Snapshot/revert mechanism in code-behind for live-preview cancel
2026-08-17 07:53:03 -07:00
gramps a3dd0791db fix: creator feedback batch Branch 1 — TRAX volume, tooltip, meter boost, slider click, backdrop
- TRAX: LocalGain now applies 0.2× factor so music is quieter relative to desktop audio slider
- TRAX tooltip: switched to ToolTipService with Placement=Top to fix z-order in Viewbox overlay
- Mic meter: MeterLevel multiplied by 1.2× before clamping for ~20% higher visual readout
- Volume sliders: click anywhere on track to jump thumb to that position before dragging
- Backdrop: Image Visibility now binds to BackdropVisible; compositor checks IsVisible before blit
- Renamed 'Backdrop' to 'Game Capture' in EnsureBackdrop + test assertions
2026-08-17 07:45:29 -07:00
gramps 13ce867bf3 docs: renumber tasks sequentially 1-13, close gaps, fix all cross-references 2026-08-16 19:28:41 -07:00
gramps 3904b626b9 dokunfuk 2026-08-16 18:16:10 -07:00
gramps 0fac1e6a5a TASK 5 items 1-3: reusable stream, health banner, docs refresh
- Reusable stream: GetOrCreateReusableStreamAsync, cached via LayoutStore, bound at broadcast insert
- Health monitoring: GetStreamHealthAsync polls liveStreams.status, report-by-exception banner
- Go-live order: ensure stream → create broadcast → then start pump (URL must exist first)
- Full broadcast form scoped (TASK 5 items 6-7) in TASKS.md + ai.md
- TASK 23 trimmed to technical scope, TASK 26 added (marcom/launch kit)
- Confidential files: MONETIZATION.md + MARCOM.md (gitignored, not committed)
- .gitignore updated for confidential business files
- HANDOFF.md updated with session state and next steps
2026-08-16 17:48:37 -07:00
gramps 24f16b2cd9 Game audio bar is now ALWAYS visible (TASK 4 gating removed, 2026-08-15): the show/hide machinery kept hiding the desktop/game meter whenever no full-screen game with sound was up or no TRAX music played, which the creator read as the meter being lost. Deleted IGameAudioDetector/GameAudioDetector/GameAudioHysteresis (Services/), the VM's 250ms DispatcherTimer poll + OnGameAudioActiveChanged/OnGameAudioPollTick + IsGameAudioBarVisible + _gameAudioBarActive/_gameAudioTimer/_gameAudioDetector, and the two detector test files (GameAudioDetectorTests, GameAudioHysteresisTests); MainWindow.xaml drops the Visibility binding so the bar renders unconditionally. Desktop audio is just automatic WASAPI loopback now. Docs in the same commit: ai.md (audio section + Services inventory), Services/index.md, ViewModels/index.md, TASKS.md TASK 9 item 7 follow-up, HANDOFF.md shipped state + stale poll-timer landmine removed. Build 0 warnings, 189 tests passing (8 detector tests removed) 2026-08-15 15:53:51 -07:00
gramps cc71ed5066 TASK 24 follow-up: TRAX button moved into the game audio bar, left of the 'Desktop Audio' label in the preview overlay (the creator's follow-up pick — the music control sits with the desktop audio controls it rides); removed from the footer's left cluster next to Socials. TraxToolTip now teaches the clicks ('left-click plays/pauses, right-click chooses a track'). Docs in the same commit: TASKS.md TASK 24 item 6, ai.md audio section, ViewModels/index.md. Build 0 warnings, 197 tests passing (no test changes — UI relocation only) 2026-08-15 15:42:24 -07:00
gramps a0a8331569 TASK 24 post-pause polish batch (creator's 8 review issues, 2026-08-15): (1) desktop/game audio volume slider + (2) mute were no-ops — the AudioMixer's gain Func seams defaulted to unity because the VM never passed them; new AudioGainProvider (Services/Audio/) wires MicMuted/MicVolume/GameMuted/GameAudioVolume into the mixer at construction, read live each mix tick, so sliders and mutes are stream-honest; the game bar also scales TRAX locally via new MusicPlayer.LocalGain (UpdateTraxLocalGain on every game volume/mute change + on load) so the creator HEARS the controls work on the music in the headphones. (3) TRAX played once then stopped — OnPlaybackStopped only looped on Position>=Length (unreliable for MediaFoundationReader); now any clean stop rewinds + replays, errors/explicit stops surface via PlaybackEnded; unused using dropped. (4+6) TRAX moved right of Socials in the footer's left cluster (centered under scenes/sources); the mic cluster is now MIC + meter + mute + volume. (5) mic source persists — LayoutStore gains a Settings key/value table (SaveMicSourceName/LoadMicSourceName); the VM saves on pick and restores before the mixer's first Start, so a restart reconnects the same vetted device (green) or reports it missing (yellow). (7) Backdrop's missing trashcan shifted the edit/eye icons right — new HiddenBoolToVisibilityConverter keeps the trash column reserved (Hidden, not Collapsed) so every source row's icons stay in fixed columns. (8) a 1px hairline with top/bottom padding separates scenes from sources in the left panel. Docs in the same commit: ai.md (gains honest + drive TRAX locally, TRAX loops, mic persistence, footer layout), TASKS.md TASK 24, HANDOFF.md shipped state, ViewModels/index.md. ONE integration test: AudioPipelineTests.Mix_HonorsProviderGains_AndGameMute_KillsTheLoopback (real mixer + provider gains through the pipe harness: scaled loopback audible, silence after mute). Build 0 warnings, 197 tests passing 2026-08-15 10:23:49 -07:00
gramps 86fcd868a8 Monetization policy locked + dev pause recorded (docs changeset, 2026-08-14): the one paid line becomes an annual subscription — early access $49.99/yr → $99/yr list at GA, grandfather-while-subscribed with lapse → list on renewal (no escalation matrix); free tier unchanged (branding flash is the free tier's billboard + no Alerts, which is the one paid feature); billing NOT locked to itch.io (hunted fact: itch.io has no native subscription billing — candidates Gumroad, whose native affiliate program is the tiebreaker, and Lemon Squeezy); support = in-app bug-report → git issues with a when-I-get-around-to-it cadence + emergency patches. ai.md Monetization section rewritten + stale paid-unlock seams fixed (L115 subscription-entitlement wording, the About hub's tabled billing PremiumUrl seam); TASKS.md gains TASK 23 (Monetization — billing provider decision, unlock mechanism with lapse→flash-returns enforcement, in-app bug-report loop, Unlock Premium seam lighting, Alerts gating, and line-item pointers for the early-access strategy, affiliate/ads phase 2, and the channel revival); HANDOFF.md records the decisions + the development pause (resume streaming = pair-programming dev streams via OBS + The Division 2 under the gramps/GOAT persona, 67 and gaming since 1981, 3D-printing content retired; dogfood switch to ytLlive once TASK 5 lands; resume point = TASK 5). Stale itch.io assertions corrected across comments and indexes (MainViewModel.cs PremiumUrl/IsPremium seams, MainWindow.xaml tooltip, AboutHubTests comment, ViewModels/index.md, TASK 9 out-of-scope note). Build 0 warnings, 196 tests passing 2026-08-14 18:48:42 -07:00
gramps 6d71acef8c 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
gramps 3d92bd0225 TASK 21: real logo + creator-hub About overlay — the About overlay is now the in-app creator hub: real logo (the creator's 'llama fortnite superman logo' copied to Assets/llama-logo.png, creator-owned art), hub links — llama chile shop on YouTube (MainViewModel.ChannelUrl, now public), Mastodon (https://mastodon.llamachile.tube/@gramps), Buy me a coffee (https://buymeacoffee.com/llamachiley, live), Unlock Premium (greyed 'coming soon'; IsPremiumAvailable flips on once the tabled itch.io PremiumUrl lands); a Licenses & legal sub-panel loads the full shipped THIRD-PARTY-NOTICES.txt in-app (ShowLicenses reads from the executable dir on first open, 'not found' fallback — never the OS viewer) with '← Back to About' (BackToAbout_Click) — the AboutHubTests integration test drives the real window + VM asserting the hub opens, link URLs are real, licensing loads the shipped notices text, and back returns to the hub — 174 tests passing, 0 warnings 2026-08-14 12:39:05 -07:00
gramps 801219ec46 TASK 4 ship step 7: one-click go live + private-only enforcement (req 8) — the Go Live dialog is locked to Private (GoLiveViewModel.Visibility is a get-only string, no dropdown; settings' dead Default Visibility dropdown + Visibilities/DefaultStreamVisibility removed); YouTubeStreamService.CreateBroadcast always sends privacyStatus='private' and gained an injectable HttpClient? http = null seam; BeginGoLive fires CreateBroadcastAsync which stashes _currentBroadcastId for TASK 5's bind/transition (failure → StreamStatus.Error via AppLog, never a crash) alongside the frame pump, and StopStream clears it; the REC sign shows a dark-red PRIVATE badge next to REC whenever the live stream is private (IsLivePrivate) — the broadcast-insert integration test asserts the request body carries privacyStatus private (RecordingHandler seam) + a no-session guard test — 173 tests passing, 0 warnings 2026-08-14 09:20:03 -07:00