Commit Graph

13 Commits

Author SHA1 Message Date
gramps cb750660c3 fix(ypp): refresh 403'd on every real call — drop the auditDetails part (needs a partner scope)
Creator: 'when I attempt to refresh my YPP page, I get an error about not being
able to reach YouTube. Seriously?' Real log: channels.list failed (403) x3.

Root cause #1 (the 403): channels.list?mine=true&part=statistics,auditDetails,
contentDetails returns 403 insufficientPermissions when the token lacks the
youtubepartner-channel-audit scope — which the auditDetails part ALONE requires,
per the docs ('A request that retrieves the auditDetails part ... must provide an
authorization token that contains the youtubepartner-channel-audit scope'). That
scope is MCN partner tooling with a 2-week token-revocation rule; the app must not
hold it. TASK-39's 'current scopes suffice, no re-consent' slice-1 claim was wrong
for this part; mock-fake tests never touched the real API, so it shipped green and
403'd every refresh since 2026-09-22.
https://developers.google.com/youtube/v3/docs/channels/list

Fix: part=statistics,contentDetails only; standing flags removed from
ChannelStatsService -> YppStatSnapshot surface -> YppTrackerViewModel -> drawer,
replaced by an honest deep-link row ('Channel standing isn't exposed to YouTube
apps — check the Earn page'). YppSnapshot standing columns stay (schema-stable,
always false). channels.list failures now log the response BODY — the bare code
could not name insufficientPermissions, which is what made this undiagnosable.

Root cause #2 (found by the new Good Dog, masked by the 403): statistics come back
as JSON STRINGS ('350'); raw GetInt64() throws. Tolerant ReadInt64 (ValueKind-first;
JsonElement.TryGetInt64 THROWS on strings — type-in, not try-type).

Good Dog: ChannelStatsServiceTests.CaptureCurrent_RequestsNoAuditDetails_AndStillParsesTheSnapshot
(URL asserts no auditDetails + snapshot parses); YppPullOutTests fixture updated.
Recipes for both 403/scope and statistics-strings entered in MyMistakes.md.

Also shipped in the same commit (shared PreviewPane.xaml + ai.md): the audio-sync
status dot removal from the #77 feedback round (creator: 'what is the point of the
status light? Lose it') — IntToSyncBrushConverter deleted with it.

verify.sh gate: 0 warnings, 316/316 pass, scope-check clean.
2026-09-23 16:45:56 -07:00
gramps e8ff4df05f TASK 22: global audio sync offset (positive delay at the mixer out)
Adds AudioSyncOffsetMs (0..500ms, default 0) that delays the whole
interleaved-stereo mix so audio lands on the video when it runs ahead —
OBS's documented lip-sync fix. Positive-only: advancing audio needs a
video-side delay and is out of the audio layer's scope.

- Services/Audio/AudioSyncDelay.cs: pure delay line, flushed on Configure
- AudioMixer: Func<int> syncOffsetMs seam + delay applied post-limiter
- LayoutStore.Settings + MainViewModel.Audio/VM: load/save + binding
- PreviewPane mic bar: SYNC slider + status dot (IntToSyncBrushConverter)
- AudioSyncDelayTests: identity, negative/beyond-500 clamps, 10ms→960 samples

Reference (external scan): https://obs-versions.com/blog/how-to-fix-audio-delay-on-obs
(audio ahead => positive delay). Verified: build 0 warnings; 3/3 delay tests pass.
2026-08-31 18:30:03 -07:00
gramps 7dd140a4c0 Backgrounds: one locked Background per screen + mini rule (TASK 25) 2026-08-23 13:33:33 -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 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 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 3f7f1880c5 Webcam resource validation + first-frame proof + CameraConflictProbe: MediaCaptureFrameSource validates post-init (VideoDeviceId match, stream properties, reader StartAsync status), subscribes Failed/CameraStreamStateChanged → SourceFailed; CameraManager.AcquireAsync requires first-frame proof (4s timeout) — silent empty box impossible; MainViewModel surfaces WebcamError chip + MessageBox with suspect-app names; fallback ladder VideoPreview → VideoRecord; 19041 SDK projection gaps documented; AGENTS.md + schema.md + HANDOFF.md memory-map rules added; 81 tests passing, 0 warnings 2026-08-12 07:21:15 -07:00
gramps e037ba027b Multi-scene webcam (schema v3/v4): singleton Webcam + per-scene WebcamSceneConfig, right-click OBS-style border/context menu, persisted round-to-rect restore + legacy-square 16:9 heal, dark MenuItem template, tests (25 passing) 2026-08-07 08:24:18 -07:00
gramps 4afe11e718 OAuth session persists via DPAPI; sign-in lives in the Start Stream dialog; add xUnit test project (6 passing) 2026-08-06 09:38:35 -07:00
gramps a74162e34e Resolution dropdown, list-focus preservation, unified dark theme, startup logging, and memory map
- Bottom-bar resolution dropdown (1080p60/1080p30/720p60/480p30) with tooltip
  on finding upload bandwidth; disabled while live; no in-app speed test
- FocusPreservingListBox keeps selection/focus coherent when a selected
  scene/source is deleted (skip hidden scenes; leave list when empty)
- Themes/Controls.xaml: single dark-theme dictionary merged once in App.xaml;
  custom ComboBox template fixes SelectionBoxItem rendering; GoLiveWindow and
  ReuseImageDialog consolidated onto shared styles
- AppLog file logger + AppDomain/Dispatcher exception hooks; checkpointed
  MainWindow/VM/dialog constructors (caught MenuItemRole.Separator XAML crash)
- Memory map: schema.md conventions, per-directory index.md, updated ai.md/
  TASKS.md/README.md (OAuth creds real; token persistence still pending)
2026-08-06 08:33:05 -07:00
gramps 7dc8490d96 Scene/source builder with image overlays, reuse dialog, and SQLite layout persistence 2026-08-04 17:12:32 -07:00
gramps 9103ff1fb7 Initial scaffold: ytLive C# WPF project
- MVVM architecture (Models, ViewModels, Views, Services, Helpers)
- Models: Scene, Source, StreamConfig, StreamHealth, YouTubeChannel, ChatMessage
- Services: YouTubeAuthService (OAuth2), YouTubeStreamService (broadcasts/stream health),
  YouTubeChatService (live chat polling)
- ViewModels: MainViewModel with scene management, stream controls, chat
- MainWindow with dark theme: scene/source panel, preview area, chat panel, status bar
- Version roadmap: v0.1 (scenes, RTMP, OAuth2, chat, health) -> 1.0
2026-08-04 09:09:52 -07:00