Files
bitvid/docs/watch-history-logging.md
2025-10-02 15:59:06 -04:00

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:

  1. Chunk events — Each chunk carries a deterministic identifier in its d tag, advertises its snapshot and chunk position, 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】
  2. Pointer event — After chunks are accepted, BitVid emits a compact index event containing the canonical list identifier (['d', WATCH_HISTORY_LIST_IDENTIFIER]), the snapshot label, the total chunk count, and an a tag 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.