Diagnosis (live, verified): the zap-totals pipeline is correct end to end —
a seeded receipt queries and sums to the right sats — but of 310 kind-9735
receipts reachable on the relays, ZERO reference any bitvid video, so every
badge was legitimately hidden. That reads as "broken" and profile zaps to a
Lightning address never attach to a video, so hidden-when-zero left the
feature invisible in practice.
Show the counter always, like the view counter it sits beside: "0 sats"
until a receipt lands, then the summed total. Card binder and modal render
no longer gate on sats>0; the badge is revealed on bind/open and re-hidden
on modal close (no video open). Live-checked: 158/158 cards render the
badge. Tests spec-corrected with integrity notes.
Co-Authored-By: Claude Fable 5 <[email protected]>
Video cards show the total sats from the shared zapTotals cache: new
--color-zap token (bitcoin orange, both themes), badge pushed to the
engagement row's end so views/comments stay left-aligned, hidden until a
nonzero total is known. The list view's zap binder fills [data-zap-total]
on bind (also scheduling the batched receipt fetch) and one shared change
listener updates every bound card as receipt batches land.
Co-Authored-By: Claude Fable 5 <[email protected]>
Replaces the per-card view-count transport (each card: list + NIP-45 COUNT +
live sub, × relays — the ~880 REQ/s storm) with ONE shared batched kind-30079
subscription + ONE backfill list() over all visible cards, bucketed back to
per-pointer state by #a. Re-enables the VideoListView circuit-breaker.
Grid counts are convergent/approximate (cheap, persists via the existing view
cache); the watch page opts into an exact NIP-45 COUNT for its single pointer
(modalCoordinator passes { exact: true }) — accurate where it matters, one
request, no storm. Legacy per-pointer path retained for SubscriptionManager-less
environments (tests/mocks).
Verified: nip07-heat steady-idle with views on; flaky multi-relay harness still
all-PASS; new cheat-resistant batching+bucketing test. (Pre-existing
view-counter publish-session-tag failure is unrelated — fails at baseline.)
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Real-environment console logs revealed nip-07 login pegging the CPU and
starving encrypted-list decryption via relay REQ storms (~1000 REQ/s):
- moderationService.rebuildTrustedContacts emitted "contacts"
unconditionally, forming an emit->fetch->emit loop (~1600 kind-3 REQ/s).
Now emits only on actual change. Regression test added.
- Per-video live report (kind 1984) and view-count (kind 30079)
subscriptions fan out O(videos x relays) and re-fire on every flaky-relay
reconnect. Circuit-broken behind flags until batched (see refactor plan).
- onVideosShouldRefresh now coalesces forced reloads (2s leading-edge
throttle) so list-change signals can't drive a reload loop.
- nip-07 queue reserves one foreground slot; DM decryption demoted to LOW
so background DM backfill can't starve feed-driving lists. Test added.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
- Implemented `hydrateVideoHistoryBatch` in `NostrClient` to fetch missing root events and sparse histories in a single `pool.list` request.
- Refactored `hydrateVideoHistory` to use shared helper methods `getLocalVideoHistory` and `_processAndCacheEvent`.
- Added `resolveVideoPostedAtBatch` to `PlaybackCoordinator` which delegates to the batched client method.
- Updated `VideoListView` to collect videos needing timestamp resolution and call the batch method, falling back to individual calls if necessary.
- Added regression test `tests/performance/resolvePostedAt.test.mjs` to verify reduced network calls.
Co-authored-by: PR0M3TH3AN <[email protected]>
This commit addresses an issue where thumbnail images would "drop" (disappear/flicker) upon login or re-initialization of the video list.
Changes:
- Modified `js/ui/views/VideoListView.js` to add a guard clause in `cleanupThumbnailCache`.
- The function now returns early if the provided `videos` list is empty, preserving the existing `loadedThumbnails` cache during transient loading states.
Verification:
- Created a reproduction script (`reproduce_issue.mjs`) that confirmed the cache was being cleared on empty input.
- Verified the fix with the same script, ensuring the cache is preserved.
- Verified no regression in `npm run lint:hex` and `npm run lint:inline-styles`.