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/extended

  • Parameters:

    • a=<path> (File A capture path)

    • b=<path> (File B capture path)

    • kind=all

    • offset=0

    • limit=20000

    • max_changes=250

    • max_depth=6

The modal then does all searching/filtering/sorting locally on the returned dataset.

circle-info

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 =unchanged

  • Buttons:

    • 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.clipboard with 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/item

  • For Deleted: recA = old/item, recB = null

  • For others: A comes from old, B comes from new (with brief used 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 (or a)

  • bPath (or b)

And the global close helper must exist:

  • window.cxCloseModal (used by the Close button)

Last updated

Was this helpful?