Capture Compare (Advanced)
Capture Compare (Advanced)
This project includes a Capture Compare modal that opens from the Advanced UI.
It lets users visually compare two capture files (File A vs File B).
Source: assets/js/modals/capture-compare/index.js.
What it is
A full-screen-ish modal built for debugging and verification of capture/snapshot output:
Shows a diff summary between two capture files (added/removed/updated/unchanged).
Lets you browse the items in each file side-by-side.
Lets you inspect a single item with field-level changes and the full raw JSON for both sides.
Provides quick copy-to-clipboard actions for keys, IDs, and records.
It’s basically: “tell me exactly what changed between these two capture runs, and show me the raw proof.”
What it does (user-facing)
1) Loads an extended diff from the backend
On open (and on Refresh) it fetches an extended diff for the selected files:
Endpoint:
GET /api/snapshots/diff/extendedParameters:
a=<path>(File A capture path)b=<path>(File B capture path)kind=alloffset=0limit=20000max_changes=250max_depth=6
The modal then does all searching/filtering/sorting locally on the returned dataset.
The API path still uses snapshots. The UI calls them captures.
2) Shows a header with context + summary
The top bar displays:
Provider + feature (lowercased)
Counts summary:
+added -removed ~updated =unchangedButtons:
Refresh: re-fetch diff from the API
Close: calls
window.cxCloseModal?.()
3) Provides filters and controls
Toolbar includes:
Search: matches title, key, ids, show_ids, and small derived labels.
Status chips:
Added (on by default)
Deleted (on by default)
Updated (on by default)
Unchanged (off by default)
Type filter: All / Movies / Shows / Seasons / Episodes
Sort: status (default) / title / key
Changed only toggle:
When enabled: shows only added/removed/updated
When disabled: also includes unchanged
4) Two-pane list view (File A vs File B)
The upper section is split into:
Left pane (A): items that have a record in File A
Right pane (B): items that have a record in File B
Each row shows:
Status pill (Added/Deleted/Updated/Unchanged)
Title + short “sub” line (type/year/season-episode, watched hint when present)
For Updated items: a
Δ<change_count>badge
Clicking a row selects the item and syncs the selection across panes.
5) Detail inspector for the selected item
The bottom section shows:
Title + status + (for updated items)
Δ<change_count>The item key (monospace)
Action buttons:
Copy key
Copy JSON A
Copy JSON B
If the item is Updated, it also shows a field-level change list:
Each change shows:
JSON path
value in A
value in B
(Capped to 200 displayed changes per item in the UI.)
Then it shows two record cards, side-by-side:
File A card: key fields + ID chips + Raw JSON collapsible block
File B card: same
Missing-side behavior:
If status is Added: File A record is missing.
If status is Deleted: File B record is missing.
6) Copy helpers (quality-of-life)
Clicking an ID chip copies its value (e.g.,
imdb,tmdb, etc.).Copy uses
navigator.clipboardwith a fallback for older/locked-down browsers.Buttons briefly flash Copied or Copy blocked for feedback.
7) Splitters + synced scrolling
The layout is resizable with drag handles:
Vertical splitter between A and B lists (top)
Horizontal splitter between list area and detail area
Vertical splitter between A and B record cards (detail)
Detail panes also keep scroll position synced, so comparing JSON blocks is less painful.
Status semantics
The modal treats diff rows as:
Added: present in B, missing in A
Deleted: present in A, missing in B
Updated: exists on both sides but differs (has a
changes[]list)Unchanged: exists on both sides and is effectively the same
Internally:
For Added:
recA = null,recB = new/itemFor Deleted:
recA = old/item,recB = nullFor others: A comes from
old, B comes fromnew(withbriefused for display)
What it’s for
Verifying capture/snapshot correctness after code changes.
Explaining “why did sync plan change?” by comparing two state dumps.
Debugging tricky cases: missing IDs, season/episode mismatches, timestamp differences, etc.
Giving users a clear view of “what CrossWatch thinks changed” without digging through raw files.
Notes / constraints
The modal pulls up to 20k diff items in one request and filters locally.
This is intentional for fast UI interactions after the initial load.
“Unchanged” is hidden by default to reduce noise.
The modal injects its own CSS once (
<style id="cc-css">…</style>), so it’s self-contained.
Integration requirements
To open the modal, the caller must pass:
aPath(ora)bPath(orb)
And the global close helper must exist:
window.cxCloseModal(used by the Close button)
Last updated
Was this helpful?