Goon — self-hosted aggregator for adult-content scene metadata. Indexes scenes from TPDB, StashDB, and 30+ public adult tube sites. Cross-source deduplication via perceptual hash + Levenshtein distance. FastAPI backend + APScheduler worker + React Native (Expo) mobile client. FOSS, ad-free, donation-funded. See README for details.
120 lines
4 KiB
Markdown
120 lines
4 KiB
Markdown
# Contributing to Goon
|
|
|
|
## Development setup
|
|
|
|
Goon backend is Python 3.12+, FastAPI + SQLAlchemy + APScheduler + Postgres.
|
|
Mobile client is React Native + Expo.
|
|
|
|
### Backend
|
|
|
|
```bash
|
|
# Create virtualenv
|
|
python -m venv .venv
|
|
. .venv/bin/activate # or .venv\Scripts\activate on Windows
|
|
|
|
# Install with dev extras
|
|
pip install -e .[dev]
|
|
|
|
# Bring up postgres (or use docker-compose; see README)
|
|
# Adjust DATABASE_URL in .env if needed
|
|
cp .env.example .env
|
|
|
|
# Run migrations
|
|
alembic upgrade head
|
|
|
|
# Run API
|
|
uvicorn app.main:app --reload --port 8000
|
|
|
|
# Run worker (separate terminal)
|
|
python -m app.scheduler.worker # full scheduler
|
|
python -m app.scheduler.worker --once --source=tpdb --limit=50 # one-shot ingest
|
|
```
|
|
|
|
### Mobile
|
|
|
|
```bash
|
|
cd mobile
|
|
npm install
|
|
npm start # opens Expo dev server
|
|
```
|
|
|
|
## Tests
|
|
|
|
```bash
|
|
pytest # full suite (~70 tests, <5s)
|
|
pytest tests/test_resolve_*.py -v
|
|
ruff check app/
|
|
mypy app/ # optional, CI-only
|
|
```
|
|
|
|
PRs must pass `pytest` + `ruff check`. Run them locally before pushing.
|
|
|
|
## Code style
|
|
|
|
- **Formatting**: ruff (config in `pyproject.toml`). Line length 100.
|
|
- **Type hints**: required on public functions. `from __future__ import annotations`
|
|
in every module.
|
|
- **Docstrings**: write the **why**, not the **what**. Reference real bugs/incidents
|
|
when explaining non-obvious code paths.
|
|
- **Comments**: only when the code can't speak for itself. Prefer renaming a
|
|
variable over adding a comment that explains it.
|
|
- **No dead code, no commented-out code, no TODO without an issue link.**
|
|
- **Polish or English in comments**: existing code is mostly Polish in
|
|
comments and English in code (function/class/var names). New code can be
|
|
either, but be consistent within a file.
|
|
|
|
## Adding a new tube extractor / scraper
|
|
|
|
If you want Goon to support an additional adult tube site:
|
|
|
|
1. **Stream extractor** (`app/extractors/tubes/`): given a scene page URL,
|
|
return a list of `StreamSource` (m3u8/mp4 URLs with quality labels).
|
|
- Mainstream tubes: try `_ytdlp.extract` (yt-dlp covers ~30 tubes out of
|
|
the box — just register the sitetag in `app/extractors/__init__.py`).
|
|
- WordPress-like tubes with embed iframe: register `_embed_iframe.extract`.
|
|
- Custom player / signed URLs / token rotation: write your own per-tube
|
|
module (see `hqporner.py`, `eporner.py`, `sxyprn.py` as references).
|
|
|
|
2. **Discovery scraper** (`app/connectors/direct_scrapers/`): subclass
|
|
`BaseSearchScraper`, set `sitetag`, `_search_url_template`, `_scene_url_re`.
|
|
Most aggregator tubes can fit in 10-20 lines (see `xmoviesforyou.py`).
|
|
|
|
3. **Register** the scraper class in `ALL_DIRECT_SCRAPERS` in
|
|
`app/connectors/direct_scrapers/__init__.py`.
|
|
|
|
4. **Test** with one performer name that you know has scenes on that tube:
|
|
```bash
|
|
python -m app.scheduler.worker --once --strategy=performer-driven \
|
|
--performers="Some Performer" --sitetags=<your-sitetag>
|
|
```
|
|
|
|
## Database migrations
|
|
|
|
Use Alembic:
|
|
|
|
```bash
|
|
alembic revision -m "describe change" # new migration
|
|
alembic upgrade head # apply
|
|
alembic downgrade -1 # roll back one
|
|
```
|
|
|
|
Every migration must have a working `downgrade()`. We don't ship squashed
|
|
migrations — full history is the source of truth.
|
|
|
|
## What we won't merge
|
|
|
|
- **Adult-content moderation features** (auto-tagging by detected acts,
|
|
content filtering by performer attributes, etc.) — out of scope.
|
|
- **Hardcoded credentials, API keys, or device IDs** in source — must be
|
|
env-driven.
|
|
- **Bypassing tube paywalls / DRM / auth** — Goon only scrapes publicly
|
|
accessible search pages.
|
|
- **Telemetry or analytics that report user activity to third parties**.
|
|
Sentry is opt-in (`SENTRY_DSN` empty by default).
|
|
- **Public deployment recipes** (e.g. nginx config for an open instance).
|
|
Goon is self-hosted only — see [DISCLAIMER.md](./DISCLAIMER.md).
|
|
|
|
## License
|
|
|
|
By contributing, you agree your contributions are licensed under the MIT
|
|
License (see [LICENSE](./LICENSE)).
|