<feed xmlns='http://www.w3.org/2005/Atom'>
<title>coinosv3.git/tools/feed-media-cache-test.js, branch master</title>
<subtitle>coinos v3 — bitcoin, Ark, Lightning and nostr wallet (web + Android)</subtitle>
<id>https://git.coinos.io/coinosv3.git/atom?h=master</id>
<link rel='self' href='https://git.coinos.io/coinosv3.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/'/>
<updated>2026-10-07T23:33:09Z</updated>
<entry>
<title>Feed videos before they play: the picture fills the box with only the play button and size (no seek bar or sound button until playing); hovering the cover no longer paints it over with the app's button grey; upright phone clips (stored sideways with a quarter-turn matrix) paint upright, v1 size caches dropped; a clip the probe found HEVC switches to the copy before fetching the original</title>
<updated>2026-10-07T23:33:09Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-07T23:33:09Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=6dfb59316865093eda01307ee3c95f87511cdf56'/>
<id>urn:sha1:6dfb59316865093eda01307ee3c95f87511cdf56</id>
<content type='text'>
Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Browser tests: public relays answered in the page, never reached</title>
<updated>2026-10-07T19:02:51Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-07T19:02:51Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=86d9818abfc160dac031bb292abe28d6f28fc624'/>
<id>urn:sha1:86d9818abfc160dac031bb292abe28d6f28fc624</id>
<content type='text'>
A suite run let ~90 throwaway test wallets subscribe and publish on public
relays from one home address, and nos.lol and relay.damus.io banned it.
tools/puppeteer.js wraps puppeteer-core: every socket to a non-local host
gets an in-page stand-in relay (EVENT -&gt; OK, REQ -&gt; EOSE). Tests that read
real content launch with { relays: 'read' } (real reads, publishes answered
in place); feed-live, chat-layout and cordn-ui launch with { relays: 'live' }.
LIVE_RELAYS=read|1|host,... overrides per run.

profile-key-qr: measure the QR again if a repaint swapped it out.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Feed tests: catch up with Articles, Popular as the default feed, timed feed defs and the tint that fades on sight</title>
<updated>2026-10-07T15:12:38Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-07T15:12:38Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=faad243486666eb4cbefcd7ff813329e707106dd'/>
<id>urn:sha1:faad243486666eb4cbefcd7ff813329e707106dd</id>
<content type='text'>
- feed-media-views: the mode switch has an Articles button now
- feed-media-cache: the live watch's since-only subscription isn't part of the crawl
- feed-switch-seed: seeded feeds carry their edit time (the feeds sync merge drops one without)
- feed-editor-relays: nos.lol is a local stand-in relay, so the test doesn't depend on reaching it
- feed-streaming: the stub wallet opens on Following (no remembered feed = Popular); the held picture
  answers repeat fetches once released; the new-post tint is recorded as it paints (it fades on sight)

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Rebuildable caches move from localStorage to IndexedDB (cache-store.js)</title>
<updated>2026-10-07T14:24:33Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-07T14:24:33Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=78cf670939133fc4f656f0f42b21a59431a53842'/>
<id>urn:sha1:78cf670939133fc4f656f0f42b21a59431a53842</id>
<content type='text'>
localStorage is ~5M characters per site whatever the device, and a phone
had filled it. Profiles, faceless list, reports, follow packs, profile
pages, relay lists, the moderation baseline, community directory, link
previews, video sizes/probes and search profiles (~3M on that phone) now
live in IndexedDB, which shares the site's disk allowance (GBs).

cacheStorage keeps localStorage's string API: reads from memory,
coalesced write-behind, flushed on hide. Copies migrate on open and are
removed once written. Boot waits for it (max 3s) beside the Ark store;
caches read at construction re-merge on ready; an early write can't
replace the stored copy. A copy an older build writes to localStorage
later moves in on first ask. Wallet wipes reach it; private mode stays on
localStorage. Read markers, drafts, follows, note threads and sync
outboxes stay in localStorage on purpose (cross-tab consistency, early
server-rendered seeding). Also asks navigator.storage.persist().

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Video frames from bytes, not from a CORS player; pager clips load plainly again</title>
<updated>2026-10-03T22:52:38Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-03T22:52:38Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=141779ab97efad6abefaec0545bba5330fd1e12d'/>
<id>urn:sha1:141779ab97efad6abefaec0545bba5330fd1e12d</id>
<content type='text'>
Regression from 6488806: pager clips were loaded crossorigin so their
frame could be kept, and on a phone the large clip's slide went black.
Some hosts (Primal's R2 bucket) send CORS headers only to a request with
an Origin and don't Vary on it, so a copy the browser cached from a plain
player load answers a later CORS load without them, and it fails. The
same thing made the size probe fail for any clip that had played in the
feed.

- Pager clips load plainly again; the still under a tap-to-play cover is
  restored on every return.
- The probe (and its HEAD) go past the browser cache (no-store).
- A clip's frame is now made from bytes: the opening of the file (index
  plus about 1 MB, no-store) decoded from a blob and kept as a JPEG —
  for tiles and as the pager's poster. No CORS player anywhere. Files
  whose index trails, or hosts whose bytes can't be read, keep the plain
  player still (shown, not kept).
- Kept frames are 480 px wide (were 270) and capped at 600.
- Probe failures are stored as failedAt, so earlier failures are asked
  again at once.
- Test: an R2-style host, its clip cached by a plain load first, is
  still measured and its frame kept (failed before this change).

Co-Authored-By: Claude Fable 5.1 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01ULQZS9MQa6iAsXnrJUD9Du
</content>
</entry>
<entry>
<title>Video tiles: a frame even when the size check fails; retry it later</title>
<updated>2026-10-03T22:32:41Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-03T22:32:41Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=d39a1b87358965bb0118cb88e4c8a86c89992a4c'/>
<id>urn:sha1:d39a1b87358965bb0118cb88e4c8a86c89992a4c</id>
<content type='text'>
Efrat's clip (blossom.primal.net → r2a.primal.net) showed a blank tile on
a phone: the 64 KB probe failed there (slow connection), the failure was
kept for good, and a tile with a failed probe never tried for a frame.

- A failed probe is dated and asked again after an hour (it was kept
  forever; old 'failed: true' entries are retried). The probe waits 10 s.
- A tile whose probe failed still tries for a first frame, giving up and
  letting go of the file after 8 s.
- Primal's CDN lets scripts read the bytes but not Content-Range, so the
  size was unknown: a HEAD's Content-Length (readable by any page) fills
  it in.
- No size in imeta but a bitrate and duration (Primal posts those): the
  size is estimated from them. 'dim 1080.0x1920.0' is understood.
- A tile with nothing to show is dark, like a video, not a pale gap.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01ULQZS9MQa6iAsXnrJUD9Du
</content>
</entry>
<entry>
<title>Media views keep their own cache and crawl for media directly</title>
<updated>2026-10-03T22:05:52Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-03T22:05:52Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=8edbd7b7544d829f44d36b430c4fcbbc521224a8'/>
<id>urn:sha1:8edbd7b7544d829f44d36b430c4fcbbc521224a8</id>
<content type='text'>
Videos was slow because the grid read from the feed's page of posts:
the feed cache holds 30, so after every reload the grid re-crawled the
relays, ten posts a step, each post first waiting (up to 8 s) for its
avatar, pictures and link cards — none of which the grid shows.

- Each feed now keeps a media index (IndexedDB, src/media-cache.js): the
  posts carrying pictures and those carrying clips, 400 of each, and how
  far back it has looked. The grid and pager read from it; a reload
  paints them at once.
- The crawl reads older posts straight into the index, 100 at a time,
  without the readiness wait and without touching the feed's own page;
  it resumes from where it stopped. The bottom of a feed is looked for
  again after a day. Curated feeds still page the usual way.
- A tile's first frame is kept (a small JPEG in the Cache API, when the
  host lets its pixels be read) and painted as a picture from then on: in
  the grid, as the pager's poster and the feed's.
- Probe results kept for 2000 clips (was 600).
- Forgetting a wallet wipes the index and the frames.

tools/feed-media-cache-test.js

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01ULQZS9MQa6iAsXnrJUD9Du
</content>
</entry>
</feed>
