Kategorie i studia podszywajace sie pod osoby: "Creampie" (269 scen), "Natural tits" (670), "reverse cowgirl" (315), "69", "Brazzers", "Blacked", "Twistys". Razem 277 rekordow i 33 784 przypisan do scen. Zrodlo: _search_base filtruje wyniki tube-searcha warunkiem "slug zawiera >=1 token z zapytania", a resolve_performer tworzy performera z dowolnej nazwy podanej przez tube. Zadnej bramki po drodze. KRYTERIUM JEST WASKIE CELOWO. To uzywane w app/api/scenes.py do de-rankingu (slug pokrywa sie z tagiem I brak refa tpdb/stashdb) daje 3111 trafien, ale probka pokazala ~60% falszywek dla nazw wielowyrazowych: wpadaja w nie Hatano Yui, Davina Raines, Michelle Ferrari, Clanddi, SolaZola, Kate Kuray. Zalozenie "prawdziwy performer ma ref kanoniczny" nie dziala dla JAV, amatorek i debiutantek. Do de-rankingu wystarcza, do kasowania nie. Rozstrzyga promiskuitycznosc taga: ile ROZNYCH innych performerow pojawia sie na scenach z tym samym slugiem. Zmierzone: prawdziwe osoby maksimum 20 (Julia Reaves), wiekszosc 0-4, Hatano Yui 0. Kategorie: Deepthroat 39541, Creampie 33661, riding 16284. Prog 50 lezy ponad 2x powyzej najwyzszej prawdziwej osoby. Odrzucilem tez sygnal "slug rowny studiu", bo wciagal marki osobiste (Katekuray, Julia Reaves). Tresc nie ginie: te slugi dalej istnieja jako tagi (creampie przy 176 tys. scen), przestaja tylko udawac osoby. 16 968 scen zostalo bez obsady, co dokłada 1,8 procent do istniejacych 943 tys. scen bez obsady. Job co 24h zamiast bramki w resolve_performer: nie dotyka goracej sciezki ingestu, a smieci odrastaja wolno. Ta sama logika co przy blackliscie phashy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|---|---|---|
| .github/workflows | ||
| alembic | ||
| app | ||
| landing | ||
| mobile | ||
| scripts | ||
| tests | ||
| .env.example | ||
| .gitignore | ||
| alembic.ini | ||
| CONTRIBUTING.md | ||
| DISCLAIMER.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
| streamtape_sample.md | ||
| theporndude_coverage.json | ||
| theporndude_dump.json | ||
| theporndude_final_report.md | ||
| theporndude_free_tubes.json | ||
| theporndude_full_audit_report.md | ||
| theporndude_movies.json | ||
| theporndude_movies_scorecard.json | ||
| theporndude_resolved.json | ||
| theporndude_scorecard.json | ||
| theporndude_triage.json | ||
Goon
Self-hosted aggregator for adult-content scene metadata. Indexes scenes from TheporndB, StashDB, and 30+ public adult tube sites; deduplicates across sources; serves an API + mobile (React Native) client for browsing and linking out to playback.
18+ ONLY · Self-hosted only · See DISCLAIMER.md before hosting an instance.
What it does
- Multi-source ingest: pulls canonical scene/performer/studio metadata from TPDB and StashDB on a delta cron, merges duplicates by performer + title + date heuristics (perceptual hash + Levenshtein title distance).
- Tube discovery: per-performer search across 30+ public adult tube sites (mainstream + aggregators). Each tube is scraped directly via HTTP — no proprietary API dependencies.
- Stream resolution on demand: when a user clicks Watch, the API extracts a fresh m3u8/mp4 URL from the tube's page (or falls back to embed link for WebView playback). Mainstream tubes use yt-dlp; aggregator tubes use a generic P.A.C.K.E.R. unpacker for JWPlayer-based hosters (StreamWish/doodporn/mixdrop/...).
- Mobile client (Expo / React Native): scene grid, performer pages, watch history, favorites, hold-to-preview animated thumbnails.
- Performer-driven backfill: a continuous worker walks performers ordered
by
last_searched_at NULLS FIRSTand back-fills tube scenes for the longest-stale performer first.
What it doesn't do
- Host or store any media. Scene metadata + thumbnail URLs only.
- Bypass paywalls, authentication, geo-blocks, or DRM.
- Provide age verification, ToS gating, or moderation for public deployments. See DISCLAIMER.md.
- Phone home. Sentry telemetry is opt-in (env var, empty by default).
Quick start
1. Run the backend (Docker)
git clone <repo-url> goon
cd goon
cp .env.example .env
# Edit .env:
# - TPDB_API_TOKEN (theporndb.net account → API tokens)
# - STASHDB_API_KEY (stashdb.org account → API keys)
# - API_KEYS (generate one: python -c "import secrets; print(secrets.token_urlsafe(32))")
docker compose up -d
Three services come up: db (Postgres 16), api (FastAPI on :8000,
auto-applies migrations on startup), worker (APScheduler running TPDB/StashDB
delta + performer-driven backfill).
Verify: curl localhost:8000/health → {"status":"ok"}.
2. Install the mobile app (Android)
Download the latest debug APK from
GitHub Releases → goon-vX.Y.Z-debug.apk, install on
your Android device (allow "Install from unknown sources" for the browser /
file manager you used to download).
On first launch the app shows the age-gate disclaimer (must be accepted), then a login screen. Enter:
- Backend URL:
http://<your-backend-host>:8000(e.g. your LAN IP, orhttp://localhost:8000if running on the device — uncommon) - API key: one of the values you put in
API_KEYSin.env
That's it.
Local Python (no Docker)
python -m venv .venv && . .venv/bin/activate # or .\.venv\Scripts\activate on Windows
pip install -e .[dev]
cp .env.example .env # edit creds
alembic upgrade head
uvicorn app.main:app --port 8000
Worker (manual one-shot ingest)
# Foreground APScheduler with all jobs
python -m app.scheduler.worker
# One-shot:
python -m app.scheduler.worker --once --source=tpdb --limit=200
python -m app.scheduler.worker --once --strategy=performer-driven --top-n=20
python -m app.scheduler.worker --once --strategy=performer-driven \
--performers="Lola Noir,Mia Malkova"
Building the APK locally
cd mobile
npm install
cd android
./gradlew assembleDebug
# output: mobile/android/app/build/outputs/apk/debug/app-debug.apk
Or just push a v* tag — GitHub Actions builds and attaches the APK to the
Release (.github/workflows/build-apk.yml).
Sentry telemetry (optional)
Default behavior: no telemetry. Sentry only initializes when a DSN is present at runtime/build time.
To enable Sentry for your instance (errors only, no PII, no replay):
- Backend: set
SENTRY_DSN=https://...in.env(gitignored). OptionallySENTRY_ENVIRONMENT=productionandSENTRY_TRACES_SAMPLE_RATE=0.1. - Mobile (local builds): create
mobile/.env(gitignored) withEXPO_PUBLIC_SENTRY_DSN=https://.... Expo SDK 49+ auto-inlinesEXPO_PUBLIC_*vars into the JS bundle at build time. - Mobile (CI builds): add a GitHub repository secret named
SENTRY_DSN. The APK workflow exports it asEXPO_PUBLIC_SENTRY_DSNto gradle. Without the secret, the APK ships with telemetry disabled (forks of this repo don't inherit your DSN).
Sentry init is gated by if (SENTRY_DSN) { Sentry.init(...) } — empty DSN
means the SDK is loaded as dead code but never sends a single request.
Configuration
All runtime config is environment variables (see .env.example for the full list). Highlights:
| Var | Default | Required? | Notes |
|---|---|---|---|
DATABASE_URL |
postgresql+psycopg://goon:goon@localhost:5432/goon |
Yes | Postgres 14+ |
TPDB_API_TOKEN |
empty | For TPDB ingest | Get from theporndb.net account |
STASHDB_API_KEY |
empty | For StashDB ingest | Get from stashdb.org account |
API_KEYS |
empty | Recommended | CSV of allowed API keys; empty = no auth (localhost-only) |
SENTRY_DSN |
empty | No | Empty = no telemetry. Use your own DSN if you want crash reports. |
LOG_LEVEL |
INFO |
No | DEBUG for verbose tube scraping logs |
Scheduler tuning (set to 0 to disable a job):
| Var | Default | Description |
|---|---|---|
GOON_SCHED_TPDB_HOURS |
6 |
TPDB delta interval |
GOON_SCHED_STASHDB_HOURS |
6 |
StashDB delta interval |
GOON_SCHED_PERFORMER_DRIVEN_HOURS |
12 |
Top-N performer ingest |
GOON_SCHED_PERFORMER_CONTINUOUS_SECONDS |
15 |
Continuous backfill tick |
Architecture (high level)
┌──────────┐ delta cron ┌────────────┐
│ TPDB │────────────────▶│ │
└──────────┘ │ │
┌──────────┐ │ ingest │
│ StashDB │────────────────▶│ pipeline │──┐
└──────────┘ │ │ │ cross-source
┌──────────┐ performer- │ │ ▼ dedup +
│ ~25 tube │ driven ┌───▶│ │ ┌─────────┐
│ sites │ search │ └────────────┘ │ Postgres│
└──────────┘────────────┘ └─────────┘
│
┌─────────────────────────────────────────────┤
▼ ▼
┌──────────────┐ ┌──────────────┐
│ FastAPI │ │ Worker │
│ /scenes │◀────── on Watch click ───│ scheduler │
│ /performers │ resolve stream URL │ (APScheduler)│
│ /playback │ (yt-dlp / hoster └──────────────┘
└──────────────┘ packer)
│
▼
┌──────────────┐
│ Expo mobile │
│ (Android) │
└──────────────┘
Key modules:
app/connectors/— TPDB, StashDB, dooplay (movies), paradisehill (movies),direct_scrapers/(25 tube discovery scrapers).app/extractors/— stream URL resolution per tube. yt-dlp wrapper + custom + generic embed-iframe + P.A.C.K.E.R. unpacker.app/resolve/— cross-source scene merging (phash, title similarity, performer overlap, release date window).app/scheduler/— APScheduler jobs +performer_driven.py(the core ingest strategy: completeness > recency).mobile/— Expo / React Native client.
Tube coverage
Discovery + stream resolution registered for ~33 sources:
Mainstream tubes: pornhub, redtube, xhamster, xvideos, xnxx, youporn, eporner, hqporner, sxyprn, porntrex, pornhat.
Aggregators / mirrors: xmoviesforyou, watchporn, siska, porn4days, porndish, xxxfreewatch, latestleaks, latestpornvideo, mypornerleak, porndittcom, hdporn92, sxyland, 0dayxx, perverzija, fpoxxx, porn00, pornxp, hdporngg, fullmovies, freshporno, shyfap.
Movie sites: paradisehill (primary) + dooplay mirrors (mangoporn, streamporn, pandamovies).
If you want to add another tube, see CONTRIBUTING.md.
Support the project
Goon is free, open-source, and ad-free. It stays that way because donations cover the VPS, the TPDB/StashDB tokens, and the time. Crypto only — mainstream processors refuse adult projects, even FOSS tooling.
In-app: Scenes → ♥ opens a screen with QR codes for Monero, Bitcoin, and USDT (TRC-20).
Addresses are hardcoded in
mobile/src/lib/donate.ts so a compromised
server cannot swap them mid-donation. Verify the value on-screen against the
copy in this repo before sending.
Roadmap
Near-term:
- Browse-by-performer + sort-by-studio
- Multi-tag filter (AND / OR)
- Continue-watching rail (position sync across devices)
- Stash local-server bridge — sync favorites/watchlist with a self-hosted Stash
- iOS sideload via TestFlight invite
Mid-term:
- Web companion (read-only browser frontend over the same API)
- BTCPay Server invoicing for one-time / recurring donations
- Performer-alert notifications (server push when a favorited performer drops a new scene)
License
MIT — see LICENSE.