4.4 KiB
Watch history logging (v2 pipeline)
BitVid's watch history sync is orchestrated by the
WatchHistoryService. The service collects
per-video pointer data during playback, batches it in session storage, and emits
encrypted snapshots to relays only when a publish is triggered. Relay payloads
stick to pointer identifiers so title, thumbnail, and profile context remain on
the client unless an operator opts into local metadata caching.
Snapshot composition
Snapshots publish two event types to the shared WATCH_HISTORY_KIND stream:
- Chunk events — Each chunk carries a deterministic identifier in its
dtag, advertises itssnapshotandchunkposition, and is tagged with['encrypted','nip04']. The first chunk is additionally marked as['head','1']and may append"a"tags that reference previous chunk addresses, allowing readers to reconstruct the full set even when relays deduplicate aggressively.【F:js/nostrEventSchemas.js†L175-L189】【F:js/nostr.js†L2329-L2369】 - Pointer event — After chunks are accepted, BitVid emits a compact index
event containing the canonical list identifier (
['d', WATCH_HISTORY_LIST_IDENTIFIER]), thesnapshotlabel, the total chunk count, and anatag for each chunk address.【F:js/nostrEventSchemas.js†L157-L170】【F:js/nostr.js†L2425-L2441】
Chunk content is a NIP-04 encrypted JSON envelope of { version: 2, snapshot, chunkIndex, totalChunks, items[] }. Items are pointer descriptors (e or a
references plus optional relay hints) so that relays never learn which titles
were played—only which events or addresses the client can dereference later.【F:js/nostr.js†L2337-L2364】
Batching configuration
Operators can toggle grouped resolution with WATCH_HISTORY_BATCH_RESOLVE and
optionally cap each response by defining WATCH_HISTORY_BATCH_PAGE_SIZE in
config/instance-config.js. Leaving the page size unset returns the full
WATCH_HISTORY_MAX_ITEMS window while still letting the UI paginate locally,
but setting a positive integer keeps API payloads in lockstep with batched
renderers like historyView.【F:config/instance-config.js†L101-L123】【F:js/nostr.js†L2987-L2998】【F:js/historyView.js†L1-L38】
Snapshot cadence
WatchHistoryService.publishView queues pointer entries while the feature flag
is enabled, merging repeats with a one-minute throttle and persisting the queue
in sessionStorage. Snapshots run when watchHistoryService.snapshot() is
invoked (e.g., on beforeunload, visibilitychange, or manual sync actions in
the history UI) and clear the queue on success.【F:js/watchHistoryService.js†L872-L917】【F:js/app.js†L6041-L6081】【F:js/app.js†L7467-L7484】
If no items are pending, the snapshot resolves with an empty result so UI calls
remain idempotent.【F:js/watchHistoryService.js†L932-L944】
Republish and backoff
When a snapshot publish fails but the response is retryable, the service stores
the returned snapshotId, records the originating reason, and delegates to the
Nostr client to retry with exponential backoff. Retries start after two seconds,
double per attempt with 25% jitter, cap at five minutes, and stop after eight
attempts unless a publish succeeds sooner.【F:js/watchHistoryService.js†L948-L985】【F:js/watchHistoryService.js†L723-L777】【F:js/nostr.js†L1988-L2087】
Legacy payload handling
Readers hydrate history by combining the pointer event, any encrypted chunks,
and fallback metadata embedded in legacy watch-history lists. The resolver still
accepts the watch-history:v2:index identifier, merges pointer tags from the
index event, and falls back to plaintext content when decryption fails so older
relays remain compatible.【F:config/instance-config.js†L60-L78】【F:js/nostr.js†L2704-L2779】【F:js/nostr.js†L5216-L5264】
Local metadata toggles
By default the service only persists pointer data to relays; richer metadata is stored locally (and opt-in). Users can toggle the "store watch history metadata" preference, which flips a localStorage flag, clears cached entries when disabled, and never pushes the sanitized video/profile cache over the network.【F:js/watchHistoryService.js†L82-L140】【F:js/watchHistoryService.js†L232-L313】【F:js/watchHistoryService.js†L331-L376】
See the WatchHistoryService API for
event hooks, queue inspection helpers, and manual snapshot controls.