# 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-firefox` → **Load 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 (must be pullable over HTTPS without auth so Firefox can fetch `dist/updates.json` and the XPIs). 2. **Initial commit and push**: ```bash 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 . Save them somewhere safe (macOS Keychain or Infisical `/autotrader-marker`). 4. **Export** the creds before running any release: ```bash 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): ```bash 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 ```bash # 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-.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) ```bash 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 `
  • ` 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` |