Files
linker/README.md
T
paulandClaude Opus 4.8 c2618ce0ea feat: cue-phrase candidate extraction + testable extract.js (task/smarter-candidate-extraction)
Catch artist names written in lowercase right after a cue phrase ("check out devourment",
"by cattle decapitation", "fan of ...") — the Title-Case/ALL-CAPS pass missed those.

- extension/extract.js (new): pure extraction (matchesIn + new cueMatchesIn + allMatchesIn),
  UMD so it loads as a content script AND require()s in node for tests. The cue pass uses the
  regex `d` flag to map matches back to positions for in-place wrapping; a small cue-stoplist
  drops "the/this/new/..." right after the cue.
- extension/content.js: extraction now comes from globalThis.RSLExtract.allMatchesIn
  (Title-Case + cue union), keeping the existing position-based wrapping.
- extension/manifest.json: load extract.js before content.js.
- extension/extract.test.cjs (new) + scripts/check.sh: 6 node:test cases for the extraction
  logic; check.sh now runs the extension tests too (16 total, green).
- README: updated the detection limitation note.

Deferred (design item 2): merging names split across inline formatting (cross-node) — more
involved; left as a follow-up.

Verified: scripts/check.sh green (16 tests). In-browser behavior is logic-verified only (no
headless Firefox); additive to the pending background-fix re-test — the [rsl] logs distinguish
"candidates found" from "resolve failed".

Source: task/smarter-candidate-extraction (objective/linker-improvements).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 06:36:28 +00:00

5.8 KiB

Reddit → Spotify / Bandcamp linker

A Firefox extension that, while you browse a Reddit thread, finds artist / band names in the comments (and the post body) and turns them into inline links to Spotify and Bandcamp — so a recommendation thread like this one becomes a list of clickable artists instead of names you have to copy-paste into search.

The hard part is "which words are artists and which aren't?". Rather than guess with client-side rules, the extension hands candidate names to a tiny local resolver service that checks each one against a real music database and only links the names that actually match an artist.

 reddit page                 content script                 resolver service
 ───────────                 ──────────────                 ────────────────
 comment text  ──extract──>  candidate names  ──POST /resolve──>  Spotify API  (direct links)
                                                                     or
 <a> links     <──rewrite──  confirmed links  <─────────────────  MusicBrainz  (zero-setup)

Layout

service/      tiny Node.js resolver (one file, zero npm deps)
  resolver.js
  package.json
  .env.example
extension/    Firefox MV2 extension
  manifest.json
  background.js   (does the resolver fetch; talks to the content script)
  content.js
  styles.css
  icon.svg

1. Run the resolver service

Requirements: Node 18+ (uses the built-in fetch). No npm install needed — there are no dependencies.

cd service
node resolver.js
# resolver listening on http://localhost:8787  (provider: musicbrainz)

That's it. With no configuration the resolver validates names against MusicBrainz (no account required). When MusicBrainz knows an artist's official links (its url-relations), you get direct Spotify and Bandcamp artist pages; otherwise it falls back to Spotify/Bandcamp search URLs.

For direct artist links (instead of Spotify search), give the service Spotify API credentials:

  1. Create a free app at https://developer.spotify.com/dashboard and copy its Client ID and Client Secret.

  2. cp .env.example .env and fill them in (the .env file is gitignored):

    SPOTIFY_CLIENT_ID=your_id
    SPOTIFY_CLIENT_SECRET=your_secret
    
  3. Restart the service. It will report provider: spotify on startup.

(Bandcamp has no public API; direct Bandcamp links come from MusicBrainz url-relations when present, else a Bandcamp search URL.)

Quick check that it works:

curl -s localhost:8787/resolve \
  -H 'content-type: application/json' \
  -d '{"candidates":["Cerebral Bore","Devourment","Notarealband Xyzzy"]}'
# {"Cerebral Bore":{...},"Devourment":{...},"Notarealband Xyzzy":null}

2. Install the extension in Firefox

The extension is unpacked / unsigned, so load it as a temporary add-on:

  1. Open about:debugging#/runtime/this-firefox.
  2. Load Temporary Add-on…
  3. Select extension/manifest.json.

It's now active until you restart Firefox. (To keep it permanently you'd sign it via AMO or use Firefox Developer/ESR with xpinstall.signatures.required = false.)

3. Use it

  1. Make sure the resolver service is running.
  2. Open any Reddit comments thread (a URL with /comments/ in it).
  3. Artist names become a single link — to Spotify if the artist is on Spotify, otherwise to Bandcamp — colour-coded (green = Spotify, teal = Bandcamp). New comments loaded as you scroll are linked automatically.
  4. The toolbar icon shows the extension is active; its badge shows how many links were added on the current page.

Troubleshooting

If nothing gets linked:

  1. Confirm the resolver is running — curl localhost:8787/health should return {"ok":true,...}.
  2. On the reddit thread, open the browser console (F12) and look for [rsl] logs: they report the root element, candidate count, and resolver responses on each scan. A resolve failed line means the background script can't reach the resolver (is it on :8787?); candidates found: 0 means the comment text wasn't matched (please report the thread).
  3. The content script reaches the resolver through the extension's background script — a page-context fetch to http://localhost is blocked by reddit's CSP — so make sure the add-on loaded without errors in about:debugging.

Configuration

The resolver URL is the constant RESOLVER_URL at the top of extension/content.js (default http://localhost:8787). If you change the host or port, update both that constant and the matching entry in extension/manifest.jsonpermissions (Firefox needs the host listed there to let the content script reach it).

Limitations (MVP)

  • Detection is mostly capitalization-based, with a cue-phrase pass that also catches lowercase names right after "check out / by / fan of / recommend …". Names split across inline formatting (e.g. bold mid-name) can still be missed. The resolver's exact-name match keeps false positives low; the trade-off is some false negatives.
  • Links are direct when MusicBrainz has the artist's url-relations (official Bandcamp / Spotify pages); otherwise they fall back to a search URL. (Each confirmed artist costs one extra throttled MusicBrainz lookup, cached after.)
  • The resolver caches results in memory; it resets when you restart it.
  • Without Spotify credentials the MusicBrainz path is rate-limited to ~1 lookup/ second, so the first scan of a large thread fills in gradually (cached after).
  • Built and tested as a Firefox MV2 extension.

License

Personal project — do as you like.