Files
tony eabab39210 Initial commit: AutoTrader Marker Firefox extension
Mark AutoTrader listings as 'not wanted' on both search results and detail
pages. Includes the unlisted signing / auto-update pipeline (web-ext +
dist/updates.json polled by Firefox).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 12:33:45 +00:00

5.2 KiB

AutoTrader Marker

Firefox extension to mark AutoTrader (autotrader.co.uk) listings as "not wanted" so the ones you haven't reviewed yet stand out.

What it does

  • Search results: adds a ✗ Not wanted button to the top-left of every listing card. Click and the card fades to ~30 % opacity with a red dashed outline.
  • Detail page (/car-details/{id}): adds a floating ✗ Not wanted button in the bottom-right corner. If you land on a page you've already dismissed, a red banner appears at the top with an Undo action.
  • Browser-action popup shows the count, lets you toggle Hide dismissed listings (fully collapse them on search results instead of fade), export/import the list as JSON, or clear everything.
  • State persists in browser.storage.local and syncs across open tabs via storage.onChanged.

Temporary install (for development)

  1. about:debugging#/runtime/this-firefoxLoad Temporary Add-on…
  2. Select manifest.json. Changes require clicking Reload on that page.
  3. Temporary add-ons vanish on Firefox restart.

Persistent install via unlisted signing (auto-updates)

Once signed and installed this way, Firefox auto-updates installed copies by polling dist/updates.json in the Gitea repo roughly once a day.

One-time setup

  1. Create the Gitea repo at https://git.nocker.cloud/tony/autotrader-marker (must be pullable over HTTPS without auth so Firefox can fetch dist/updates.json and the XPIs).
  2. Initial commit and push:
    cd autotrader-marker
    git init && git branch -m main
    git remote add origin https://git.nocker.cloud/tony/autotrader-marker.git
    npm install
    git add .
    git commit -m "Initial commit"
    git push -u origin main
    
  3. Get AMO JWT credentials at https://addons.mozilla.org/en-US/developers/addon/api/key/. Save them somewhere safe (macOS Keychain or Infisical /autotrader-marker).
  4. Export the creds before running any release:
    export WEB_EXT_API_KEY='user:12345:67'
    export WEB_EXT_API_SECRET='abcdef0123456789...'
    
  5. Cut the first signed release (from the repo root, on your Mac):
    bin/release.sh 0.1.0     # or: bin/release.sh patch
    git add manifest.json package.json dist/
    git commit -m "Release v0.1.0"
    git push origin main
    
  6. Install the signed XPI once on your host Firefox:
    • Open about:addons → ⚙ (gear) → Install Add-on From File…
    • Select dist/autotrader-marker-0.1.0.xpi
    • Firefox keeps it installed and checks for updates automatically.

Subsequent releases

# Edit code, then:
bin/release.sh patch          # 0.1.0 → 0.1.1
# (or 'minor' / 'major' / an explicit version like '1.2.3')

git add manifest.json package.json dist/
git commit -m "Release v$(node -p "require('./manifest.json').version")"
git push origin main

Firefox polls for updates on its own schedule (~daily). To trigger immediately: about:addons → ⚙ → Check for Updates.

What bin/release.sh does

  1. Bumps the version in manifest.json and package.json.
  2. Runs web-ext sign --channel=unlisted against AMO. Mozilla validates and signs the XPI (usually seconds for an unlisted submission).
  3. Copies the signed XPI to dist/autotrader-marker-<version>.xpi.
  4. Appends the new version to dist/updates.json so Firefox can discover it.
  5. Prints next-step git commands — it does not push automatically.

If web-ext sign prints a lint ERROR about MANIFEST_UPDATE_URL, that's expected and doesn't block signing: the rule only applies to AMO-listed add-ons, and --channel=unlisted proceeds past it.

Package a static zip (for about:debugging without signing)

python3 -c "
import zipfile
with zipfile.ZipFile('../autotrader-marker.zip', 'w', zipfile.ZIP_DEFLATED) as z:
    for f in ['manifest.json','content.js','content.css','popup.html','popup.css','popup.js','icon.svg']:
        z.write(f)
"

DOM contract (verified 2026-04)

The content script relies on these AutoTrader selectors. If they change, update content.js:

What Selector
Listing card li[data-testid^="id-"] (id is id-{listingId})
Search result title [data-testid="search-listing-title"]
Detail page id URL path /car-details/{digits}
Detail page title h1 (falls back to document.title)

The primary id sources are the data-testid on the <li> for search results and the URL path for detail pages — no href parsing needed in the happy path. The detail-page UI uses a fixed-position FAB, so it doesn't depend on the page's layout at all.

Files

File Purpose
manifest.json MV3 manifest, Firefox-specific settings, update_url → Gitea
content.js Injects buttons, manages dismissal state, MutationObserver for infinite scroll, SPA-nav aware
content.css Button styling + dismissed-card fade/hide rules
popup.html / popup.css / popup.js Toolbar popup UI
icon.svg Single SVG used for toolbar + addon listing
bin/release.sh Version bump + sign + updates.json refresh
dist/updates.json Served to Firefox for update polling
dist/*.xpi Signed extension bundles referenced by updates.json