Find the release for a StashDB scene without ever leaving the page.
A Firefox extension that turns any StashDB scene page into a one-click Prowlarr search — resolving the scene's studio, cast and date, hunting your indexers in three escalating passes, scoring what comes back, and sending your pick straight to your download client.
This software is vibecoded. It was written end to end by an AI (Claude) from natural-language prompts. No human wrote or reviewed the code by hand. It ships with automated tests but no warranty.
It works, it's commented, and it's been thought through — but it has never seen a human code review. Read it before you run it. That's the deal.
(This notice is a licensing requirement, not just a disclaimer — see License.)
You're on a StashDB scene page. You want the file. Normally that means copy-pasting the studio, the performers and the date into Prowlarr, guessing at naming conventions, and trying again with different terms when nothing hits.
This does that for you, and then some:
| One-click search | A floating ⬇ Search Prowlarr button on every stashdb.org/scenes/<id> page. |
| Three escalating passes | Starts narrow and precise, widens on demand — 5 parallel queries, then 3 more, then a last-ditch performer-only sweep. |
| Scored results | Every release is checked against 5 known facts about the scene and ranked, so a prolific performer's entire back catalogue doesn't drown the one file you want. |
| Grouped by quality | 2160p → 1080p → 720p → everything else, with seeders/size/indexer on every row. |
| One-click grab | Download hands the release to Prowlarr, which passes it to your download client. |
| "Already have it" | If you run StashApp, scenes already in your library get a badge with their resolution and a link — before you search anything. |
| ✓ in every list | Scene cards on performer, studio, tag and search pages carry a ✓ 1080p (or whatever you have) when that scene is already in your Stash — one request per page, and a click on it opens the scene in Stash. Needs Stash 0.31 or newer. |
| Her other scenes | With StashApp set up, the scene's first two performers each get a sidebar — right edge, then left — with up to 4 of their other scenes in your library, thumbnails included, and a link to the performer in Stash when there are more. |
| Reverse lookup | Select any text anywhere in the browser → right-click → Search StashDB to find the scene that text belongs to. |
| Full transparency | A Details pane shows every query fired, live, with each one's own raw unfiltered results. No black box. |
Everything runs locally in your browser. There is no server, no telemetry, no third party — just your Firefox talking to your Prowlarr, your Stash, and StashDB.
┌──────────────────────── Firefox ────────────────────────┐
│ │
stashdb.org │ content.js ──── GraphQL (your session) ──► StashDB │
scene page │ │ studio · cast · aliases · parent · date │
│ │ │
│ ▼ │
│ 3-stage search ──► background.js ──────────► Prowlarr │
│ ▲ (all cross-origin (search │
│ │ requests proxied + grab) │
│ results panel through here) │
│ scored · grouped · deduped ◄─────────────────► StashApp │
│ (library │
any page ────┤ right-click selection ──► background.js ──► StashDB │
(reverse) │ picker.js ◄── matching scenes search) │
│ │
└──────────────────────────────────────────────────────────┘
Each stage fires its queries in parallel, merges the responses, de-duplicates them by release GUID, and merges them into everything found so far. Results never get thrown away when you move up a stage — the list only ever grows.
| Stage | Trigger | Queries | Filtering |
|---|---|---|---|
| 1 — Automatic | Clicking the button |
|
Must match ≥ 2 of 5 criteria |
| 2 — 🍆 Try Harder | Click 1 |
|
Same ≥ 2 of 5 filter |
| 3 — 🍑 Last Chance... | Click 2 |
|
No filter. Sorted by publish-date proximity, capped at 50. |
Queries that would repeat something already tried — or that have nothing to fill in, like a studio with no parent brand — are skipped rather than re-sent. After stage 3 there is nothing left to fall back to, so the button retires itself and leaves a parting word in its place.
Every release title is normalised (lowercased, punctuation stripped) and checked against five fixed facts about the scene:
Studio · Parent studio · Performer · Title · Date
- Performer matches on any cast member's name, the name she's credited as in this scene, or any of her aliases. Short single-word aliases are skipped for scoring, because something like "Mia" would match half the index.
- Title matches on the whole title, or on at least 60 % of its significant words. Release names often cut long titles short.
Stages 1 and 2 only show releases matching at least 2 of 5 — that's what keeps the broad
queries usable. Every row shows its own score inline (3/5 hits (Studio, Performer 2/3, Date)),
so you can see exactly why something is in the list. With more than one performer, the
2/3 tells you how much of the cast the release names. Within a resolution group, higher
scores rank first, then releases naming more of the cast, then seeders/grabs.
Every row also shows how far its Prowlarr publish date sits from the scene's release date
(4d from scene date). That's informational only — it never feeds the score or the sort,
except in stage 3, where it is the sort.
Found a filename in a forum post, a release tracker, or a chat log and want to know which scene it actually is? Select it, right-click, Search StashDB for "…".
The selection gets normalised into a plain search phrase — file extensions, quality and codec tags
(1080p, x264, WEB-DL, …) and separators (dots, underscores, brackets, hyphens) all stripped —
without assuming which format it is. All of these work:
Studio.Performer.Name.26.09.10.XXX.1080p.mp4 → Studio Performer Name 26 09 10
[Studio] Performer - Scene Title → Studio Performer Scene Title
Performer - Scene Title → Performer Scene Title
just a half-remembered title → just a half remembered title
A floating panel then shows the matching StashDB scenes with their thumbnails, studio, date and cast. Click one to open it on StashDB — where the normal search button takes over. This step only finds and confirms the scene; it never touches Prowlarr on its own.
Grab the signed stasharr-<version>.xpi from Releases
and drag it into Firefox. That's it — from 1.3.0 on it updates itself: Firefox periodically
checks updates.json in this repo and pulls newer releases like any other
add-on. To check right away: about:addons → gear icon → Check for Updates.
Temporary — for trying out a branch (gone on restart)
- Clone or download this repo.
- Open
about:debugging#/runtime/this-firefox. - Load Temporary Add-on… → pick
manifest.json.
Signing your own build (for forks)
Firefox refuses to permanently install unsigned extensions on Release and Beta. An add-on ID can
only ever be signed by the AMO account that owns it, so a fork first needs its own gecko.id in
manifest.json — and its own update_url, or it'll keep polling this repo. Then sign it as an
unlisted add-on, which never goes on the public store or through Mozilla's review:
npm install --global web-ext
web-ext sign --channel=unlisted \
--api-key="$AMO_JWT_ISSUER" \
--api-secret="$AMO_JWT_SECRET"Get the credentials at addons.mozilla.org → Developer Hub → API Keys.
The signed .xpi lands in web-ext-artifacts/.
Firefox Developer Edition, Nightly and ESR can skip signing entirely by setting
xpinstall.signatures.requiredtofalseinabout:config.
Open the add-on's preferences (about:addons → stasharr → Preferences) and fill in:
| Setting | Default | Required | What it's for |
|---|---|---|---|
| Prowlarr URL | — | yes | Base URL, no trailing slash. e.g. http://localhost:9696 |
| Prowlarr API key | — | yes | Prowlarr → Settings → General → Security |
| Search categories | 6000 |
no | Newznab/Torznab category IDs, comma-separated. 6000 = XXX. Empty = all. |
| Result limit | 200 |
no | Max releases Prowlarr returns per query. Raise it if stage 3 seems to be missing hits for a prolific performer. |
| Request timeout | 25 |
no | Seconds to wait for Prowlarr, Stash or StashDB before giving up. Raise it if slow indexers keep timing out. |
| Stash URL | — | no | Your own StashApp, e.g. http://localhost:9999. Enables the "already in your library" badge, the performer sidebars and the ✓ on scene cards. |
| Stash API key | — | no | Only if your Stash requires one. |
Test Prowlarr and Test Stash verify each connection before you save.
A couple of knobs are deliberately not in the UI, but are one-line edits if you want them:
MIN_SCORE in common.js (the 2-of-5 threshold) and LAST_CHANCE_LIMIT in content.js (the
50-result cap on stage 3).
- Open a scene on
stashdb.org. If it's already in your Stash library, the badge tells you now, and the sidebars show what else you have of its performers. On narrower windows they start folded to their header; + opens one. - Hit ⬇ Search Prowlarr (bottom right).
- Pick a release, hit Download. It turns into ✓ Sent and stays that way — across stages, new searches, other tabs and reloads, for 90 days — so you can't accidentally grab the same thing twice.
- Nothing good? 🍆 Try Harder, then 🍑 Last Chance....
- Curious what it actually searched for? Expand Details — every query, every raw result.
- Come back to a scene within 30 minutes and the panel picks up where you left off, without querying your indexers again. ↻ in the panel header searches fresh.
| Symptom | Cause |
|---|---|
| Panel says "Could not read scene" | Not logged into StashDB. It falls back to scraping the rendered page, which has no aliases or parent studio — log in for the good data. |
| Every query fails instantly | Prowlarr URL or API key wrong. Hit Test Prowlarr in preferences. |
| Search hangs, then errors | Requests time out after 25s by default. Usually a dead indexer in Prowlarr, or an unreachable instance — raise Request timeout if your indexers are just slow. |
| Results look stale | Reopening a scene within 30 minutes restores the last search instead of re-querying. Hit ↻ in the panel header. |
| Some queries fail, others don't | You'll get a warning banner above the results; expand Details to see which indexer choked. Partial results still show. |
| Stage 3 feels like it's missing things | Raise Result limit. Prowlarr caps at 200 by default, and a prolific performer blows through that easily. |
| No "already in Stash" badge | Stash URL not set, or the scene was never scraped from StashDB (matching is done on the stash-box ID StashApp records). |
| No ✓ on scene cards | Stash URL not set, Stash older than 0.31 (it lacks the stash_ids_endpoint filter — the console says so), or the scenes were never matched to StashDB in Stash. |
| No performer sidebars | Stash URL not set, the performer isn't linked to StashDB in Stash (matching is done on her StashDB ID, never by name), or you have no other scene of hers. Male performers don't get one. |
| Right-click search does nothing | Restricted page (about:, addons.mozilla.org) — Firefox forbids injection there. Also needs a StashDB login. |
No build step, no bundler, no dependencies. Clone it and it runs.
manifest.json MV2, <all_urls> + storage + contextMenus
common.js pure text/matching/scoring helpers, loaded ahead of both scripts below
background.js every cross-origin request (Prowlarr, StashApp, StashDB search),
configurable timeouts, context-menu registration
content.js injected on stashdb.org — scene resolution, query building,
the 3-stage state machine, results panel, performer sidebars,
✓ on scene cards
picker.js injected on demand into any page for the reverse lookup panel
content.css shared styling for both panels
options.html/js preferences
tests/ node:test suite — run with `node --test` (Node 20+, nothing to install)
Content scripts can't reach cross-origin hosts, so everything network-facing lives in
background.js and is reached by message passing. Credentials never leave browser.storage.local
and are only ever sent to the hosts you configured yourself.
- Bump
versioninmanifest.json, add aCHANGELOG.mdentry, and add an entry toupdates.jsonpointing atreleases/download/v<version>/stasharr-<version>.xpi.node --testfails until all three agree. - Push a tag
v<version>on that commit. The Release workflow runs the tests, has Mozilla sign the build as an unlisted add-on and publishes a GitHub release withstasharr-<version>.xpiattached and the CHANGELOG entry as notes. It needs the repo secretsAMO_JWT_ISSUERandAMO_JWT_SECRETfrom AMO → API Keys. - Merge to
mainonce the release is up. Installs readupdates.jsonfrommain, so publishing the release first means they never go looking for a file that isn't there yet.
Mozilla signs each version number only once, so re-running a release that already got signed
fails. If a run breaks after signing, take the signed .xpi from the run's artifacts and attach
it to the release by hand. A release you pull after publishing needs a new version.
PolyForm Noncommercial License 1.0.0 — source available, not open source.
You can: use it, fork it, modify it, redistribute it, run it at home or in any nonprofit, school or public institution. Go wild.
You must: keep both Required Notices with it — the copyright line and the vibecoded statement — and keep them visible in any version you publish: in the README, and on the extension's preferences page. Reformat them however you like; just don't bury them or make them less prominent than your own credits. Nothing requires you to call your changes vibecoded.
You can't: charge money for it, or use it commercially in any form.
Required Notice: Copyright 2026 brewing8309 — https://github.com/brewing8309/stasharr
Required Notice: This software is vibecoded. It was written end to end by an AI (Claude) from natural-language prompts. No human wrote or reviewed the code by hand. It ships with automated tests but no warranty.
This tool searches your own Prowlarr instance across your own indexers, and talks to your own Stash. It hosts nothing, indexes nothing, distributes nothing, and ships with no indexers, trackers or sources of any kind. What you point it at, and whether you're entitled to what you find, is entirely on you.
Not affiliated with StashDB, Stash, or Prowlarr.