loadUserVideos rendered only the live relay fetch, and the render REPLACES the
grid container. So when a relay holding a creator's video transiently failed or
EOSE'd late, that video disappeared from the wall even though it was already
known in memory/cache — the "channel doesn't pull in all of a creator's videos"
bug (#20, symptom 1).
Union the live events with the already-known author events
(mergeChannelVideoSources, live wins on id collision) before building the
renderable list, so the rendered set is a superset and can't shrink on a
transient relay gap. Existing dedupe-by-root + access/delete filtering still
decide precedence downstream, so newer versions and deletions still win.
Helper + tests live in channelProfileVideos.js (channelProfile.js is at its
size cap); the call site stays net-zero. Streaming/first-relay-wins render is
still the separate 17d UX follow-up.
Regression: tests/channel-video-merge.test.mjs.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
A cold hard-refresh on a profile previously sat on "Loading videos…" for
~5s — the optimistic in-memory cache is empty on cold start (ingest hasn't
injected yet) and the grid waited on relay connection.
Now channelProfileVideos.js persists the last-rendered wall per author
(localStorage bitvid:channel-videos:v1) and loadUserVideos paints it
immediately on cold load, before relays connect; the live fetch then
replaces it. Bounded (60 videos/channel, 20 channels LRU-evicted) and
strips the heavy raw `tags` array. Same proven pattern as the main feed's
optimistic cache.
Closes TODO 17d per-channel cache. Tests + mutation-verified (round-trip,
tag-strip, per-channel + channel-count caps). 1267/1268 unit (known flake).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
The channel-profile grid fetched only kind-30078, so a creator's NIP-71
videos (incl. their Nostube cross-posts) appeared in the main feed via
ingest but were absent from their profile wall.
New js/channelProfileVideos.js:
- buildChannelVideoFilters(pubkey): native (kind 30078, #t=video) + NIP-71
(kinds 21/22/34235/34236) filters for the author.
- convertChannelEvent(entry): routes NIP-71 kinds through
buildVideoFromNip71Event (which rejects bitvid's own outbound mirrors so
they don't duplicate the canonical note); kind-30078 uses the standard
converter.
channelProfile.js now uses these (net fewer lines, stays under size cap).
Existing buildRenderableChannelVideos dedupe-by-root + canAccess handle
precedence and whitelist/blacklist gating, so foreign videos inherit the
same gating as native ones.
Closes pre-launch TODO 17b. Tests + mutation-verified (NIP-71 routing,
mirror skip, dual-filter build). 1253/1254 unit (known UploadModal flake).
Co-Authored-By: Claude Opus 4.8 <[email protected]>