A project to filter content visually from stashdb.org, using multiple tags and performers.
  • TypeScript 66.1%
  • Go 21.8%
  • CSS 8.4%
  • Shell 1.7%
  • HTML 1%
  • Other 1%
Find a file
2026-04-01 14:27:23 -07:00
backend Initial commit 2026-03-31 16:59:56 -07:00
docs/screenshots Added screenshots 2026-04-01 14:27:23 -07:00
frontend Initial commit 2026-03-31 16:59:56 -07:00
stashbrowse Initial commit 2026-03-31 16:59:56 -07:00
.gitignore Initial commit 2026-03-31 16:59:56 -07:00
build.sh Initial commit 2026-03-31 16:59:56 -07:00
deploy.sh Initial commit 2026-03-31 16:59:56 -07:00
LICENSE Add GPL v3 license 2026-04-01 14:25:10 -07:00
README.md Add GPL v3 license 2026-04-01 14:25:10 -07:00
stashbrowse.service Initial commit 2026-03-31 16:59:56 -07:00

stashbrowse

Browse StashDB by combining tags, performers, and studios to discover scenes and send them to Whisparr in one click.

License

This project is licensed under the GNU General Public License v3.0.

You are free to use, modify, and distribute this software, but any derivative works must also be released under the GPL v3. See the LICENSE file for full details.

Screenshots

Home view Browse view

Due to the NSFW nature of this project, these two screenshots are all I will publicly display.

Disclaimer

This project was primarily coded using Claude. I don't really know how to code, especially in go. However, I used Claude to bring my idea to life so others can audit and build off of it.

Features

  • Search and combine include / exclude filters for tags, performers, and studios
  • Paginated scene grid with thumbnails, duration, studio, and performer badges
  • Add to Whisparr directly from the browse or scene detail view
  • Favorites list persisted to disk
  • In-memory caching — repeated queries are instant
  • Single self-contained binary (frontend embedded at build time)

Prerequisites

  • A StashDB account and API key (Settings → API Key)
  • A running Whisparr instance with an API key

Installation

Option A — download a release binary

Download the latest binary for your platform from the Releases page, make it executable, and place it somewhere on your PATH:

install -m 755 stashbrowse ~/.local/bin/stashbrowse

Option B — build from source

Requirements: Go 1.22+, Node.js 18+

git clone <repo-url>
cd stashbrowse

# Build frontend
cd stashbrowse
npm install
npm run build
cd ..

# Embed frontend and build binary
cd backend
cp -r ../stashbrowse/build/client/. ui/
go build -o stashbrowse .
install -m 755 stashbrowse ~/.local/bin/stashbrowse
cd ..

Configuration

Run the interactive setup wizard to create your config file:

stashbrowse init

This prompts for:

Field Description
Config file path Defaults to ~/.config/stashbrowse/config.toml
Server port Defaults to 8585
StashDB API key From stashdb.org user settings
Whisparr URL e.g. http://localhost:6969
Whisparr API key From Whisparr → Settings → General
Quality profile ID Numeric ID of the quality profile to use
Root folder Where Whisparr stores media, e.g. /data/media/xxx

The resulting config looks like:

[server]
port = 8585

[stashdb]
api_key = "your-stashdb-key"
endpoint = "https://stashdb.org/graphql"

[whisparr]
url = "http://localhost:6969"
api_key = "your-whisparr-key"
quality_profile_id = 8
root_folder = "/data/media/xxx"

To use a non-default config path:

stashbrowse init --config /path/to/config.toml
stashbrowse --config /path/to/config.toml

Running

stashbrowse          # reads ~/.config/stashbrowse/config.toml
stashbrowse serve    # same, explicit subcommand
stashbrowse version  # print version
stashbrowse --help   # show usage

Open http://localhost:8585 in your browser.


Process supervisors

stashbrowse runs in the foreground and exits cleanly on SIGTERM / SIGINT, making it compatible with any process supervisor.

systemd (user service)

A unit file is included in the repo as stashbrowse.service.

# Install
cp stashbrowse.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now stashbrowse

# Manage
systemctl --user status stashbrowse
systemctl --user restart stashbrowse
journalctl --user -u stashbrowse -f

The unit uses %h (home directory) and expects the binary at ~/.local/bin/stashbrowse and the config at ~/.config/stashbrowse/config.toml.

dinit (user service)

Create ~/.config/dinit.d/stashbrowse:

type = process
command = /home/<user>/.local/bin/stashbrowse
restart = true
logfile = /home/<user>/.local/share/stashbrowse/stashbrowse.log
dinitctl start stashbrowse

s6-overlay / s6

Create a service directory, e.g. ~/.config/s6/sv/stashbrowse/:

mkdir -p ~/.config/s6/sv/stashbrowse
cat > ~/.config/s6/sv/stashbrowse/run <<'EOF'
#!/bin/sh
exec ~/.local/bin/stashbrowse
EOF
chmod +x ~/.config/s6/sv/stashbrowse/run

Deploying to a remote host

deploy.sh builds the frontend, embeds it into the Go binary, and rsyncs the single binary to a remote host named thor (override with env vars):

./deploy.sh

# Overrides
THOR_USER=myuser THOR_HOST=myserver THOR_DEST=/opt/stashbrowse ./deploy.sh

On first deploy, SSH into the server and run stashbrowse init to create the config, then start the service.


Development

# Terminal 1 — backend API server
cd backend
go run . --config ../config.dev.toml   # create this with `go run . init`

# Terminal 2 — frontend dev server with HMR
cd stashbrowse
npm run dev                             # http://localhost:5173 (proxies /api → :8585)

Frontend changes hot-reload instantly. Backend changes require restarting go run ..