docs(site): strona goon-foss.org do repo + aktualizacja o nowosci

Strona istniala WYLACZNIE na serwerze (wolumen infisical-caddy), a cala
historia to byly kopie index.html.bak-* obok pliku. Wjezdza do repo.

Tresc zaktualizowana o to, czego strona nie mowila:
- filmy (45k) w ogole nie byly wspomniane, mimo osobnej zakladki
- "30+ public tubes" -> 46 realnych zrodel
- pasek liczb w hero (3.8M scen, 108k performerow, 45k filmow, 46 zrodel)
- zakladki: scenes/movies/sites/JAV zamiast samego grida scen
- sekcja "What's new": animacja i 3D, filmy, JAV we wlasnej zakladce

Makiety w sekcji "In the app" zastapione prawdziwymi zrzutami (byl tam
komentarz zeby to zrobic po wgraniu realnych screenow). Miniaturki scen
sa na nich rozmyte. Przy okazji -100 linii martwego CSS-u makiet.
This commit is contained in:
goon-foss 2026-08-13 09:54:25 +02:00
parent 1c1e46130a
commit bb1b502e9a
2 changed files with 424 additions and 0 deletions

35
site/README.md Normal file
View file

@ -0,0 +1,35 @@
# goon-foss.org
Statyczna strona domowa (jeden plik, Tailwind z CDN, bez builda).
**Do 2026-08-13 istniała WYŁĄCZNIE na serwerze**, a jedyną historią były kopie
`index.html.bak-*` leżące obok. Stąd ten katalog: zmiany idą przez repo, kopia
zapasowa na serwerze zostaje jako awaryjne cofnięcie, nie jako historia.
## Deploy
Serwuje ją `infisical-caddy` z wolumenu, NIE z kontenerów Goona:
```
D=/var/lib/docker/volumes/infisical_caddy-data/_data/goon-foss
ssh <vps> "cp $D/index.html $D/index.html.bak-$(date +%Y%m%d-%H%M%S)"
scp site/index.html <vps>:$D/index.html
```
Bez restartu, Caddy czyta plik z dysku przy każdym żądaniu.
## Zawartość katalogu na serwerze
- `index.html` — ta strona
- `goon-v*.apk` — buildy do pobrania (link w hero i w stopce wskazuje najnowszy)
- `logo.png`, `favicon.png`
- `shots/` — zrzuty z apki do sekcji „In the app", kopiowane z
`app/static/marketing/`. Miniaturki scen są na nich rozmyte, bo strona jest publiczna.
## Uwaga przy aktualizacji liczb
Liczby w hero (sceny/performerzy/filmy/źródła) są wpisane na sztywno. Świeże:
```
docker compose exec -T db psql -U goon -d goon -c "SELECT (SELECT count(*) FROM scenes), (SELECT count(*) FROM performers), (SELECT count(*) FROM movies), (SELECT count(DISTINCT origin) FROM playback_sources);"
```

389
site/index.html Normal file
View file

@ -0,0 +1,389 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta name="description" content="Goon: self-hosted adult content metadata aggregator. Mobile-first, FOSS, ad-free." />
<meta name="robots" content="noindex, nofollow" />
<link rel="icon" type="image/png" href="/favicon.png" />
<link rel="apple-touch-icon" href="/logo.png" />
<title>goon · self-hosted adult content aggregator</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
/* Warm dark + oxblood, match z mobile theme (2026-05-29 overhaul).
Wcześniej tu był slop navy+purple, niespójność vs nowy app UI. */
bg: '#15110D',
bgElevated: '#1E1A14',
card: '#26201A',
border: '#3A3128',
accent: '#B23A48',
accentGlow: '#D89B4A',
accentDeep: '#7A1F2A',
good: '#5E8C5A',
},
fontFamily: {
sans: ['-apple-system', 'BlinkMacSystemFont', 'Inter', 'system-ui', 'sans-serif'],
mono: ['ui-monospace', 'SFMono-Regular', 'Menlo', 'monospace'],
},
},
},
};
</script>
<style>
body { background-color: #15110D; color: #F5EDE0; }
/* Subtle warm glow zamiast neonowego purpla. */
.glow { box-shadow: 0 0 50px -12px rgba(178, 58, 72, 0.45); }
.grad { background: radial-gradient(60% 60% at 50% 0%, rgba(178,58,72,0.14) 0%, rgba(21,17,13,0) 70%); }
.card-hover { transition: transform 200ms ease, border-color 200ms ease; }
.card-hover:hover { transform: translateY(-2px); border-color: #B23A48; }
.pulse-dot { animation: pulse 2.5s ease-in-out infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
</style>
</head>
<body class="font-sans antialiased">
<!-- AGE GATE -->
<div id="agegate" class="fixed inset-0 z-50 bg-bg flex items-center justify-center px-6">
<div class="max-w-md text-center">
<div class="inline-block w-3 h-3 rounded-full bg-accent glow pulse-dot mb-6"></div>
<h1 class="text-3xl font-extrabold tracking-tight mb-3">18+ Adults Only</h1>
<p class="text-sm text-gray-400 mb-8 leading-relaxed">
This site discusses software for indexing adult content. You must be of legal
age in your jurisdiction to enter.
</p>
<div class="flex gap-3 justify-center">
<button onclick="document.getElementById('agegate').style.display='none'"
class="px-6 py-3 rounded-xl bg-accent text-white font-bold hover:bg-accentDeep transition">
I'm 18 or older
</button>
<a href="https://www.google.com"
class="px-6 py-3 rounded-xl bg-bgElevated border border-border text-gray-300 font-semibold">
Take me out
</a>
</div>
</div>
</div>
<!-- HERO -->
<header class="grad relative pt-20 pb-24 px-6 overflow-hidden">
<div class="max-w-5xl mx-auto">
<div class="flex items-center gap-3 mb-8">
<img src="/logo.png" alt="goon" width="40" height="40" class="rounded-lg" />
<span class="text-2xl font-extrabold tracking-tight">
<span class="text-gray-100">g</span><span class="text-accent">oo</span><span class="text-gray-100">n</span>
</span>
</div>
<h1 class="text-5xl md:text-7xl font-extrabold tracking-tight leading-[0.95] mb-6">
Self-hosted<br>
<span class="text-accent">scene catalog</span><br>
for grown-ups.
</h1>
<p class="text-lg md:text-xl text-gray-400 max-w-2xl leading-relaxed mb-10">
Goon indexes scene and movie metadata from TPDB &amp; StashDB, deduplicates it
across 46 public sources, and serves a fast mobile client. Zero ads. Zero tracking.
Download, open, browse. No account, no setup.
</p>
<div class="flex flex-wrap gap-3">
<a href="/goon-v0.2.2.apk"
class="px-6 py-4 rounded-xl bg-accent text-white font-bold hover:bg-accentDeep transition glow">
Download APK
</a>
<a href="#donate"
class="px-6 py-4 rounded-xl bg-transparent border border-border text-gray-400 font-semibold hover:text-accent hover:border-accent transition">
♥ Donate
</a>
</div>
<div class="flex flex-wrap gap-x-8 gap-y-3 mt-10 font-mono text-sm">
<div><span class="text-accent font-bold">3.8M</span> <span class="text-gray-500">scenes</span></div>
<div><span class="text-accent font-bold">108k</span> <span class="text-gray-500">performers</span></div>
<div><span class="text-accent font-bold">45k</span> <span class="text-gray-500">movies</span></div>
<div><span class="text-accent font-bold">46</span> <span class="text-gray-500">sources</span></div>
</div>
<p class="text-xs text-gray-500 mt-6 font-mono">
Android 7+ · no setup, no login · 18+
</p>
</div>
</header>
<!-- FEATURES -->
<section class="px-6 py-20 bg-bgElevated/30 border-y border-border">
<div class="max-w-5xl mx-auto">
<h2 class="text-3xl font-extrabold mb-2 tracking-tight">What it does</h2>
<p class="text-gray-500 mb-12 max-w-xl">
Goon is not a tube. It does not host, transcode, or proxy content.
It is a metadata aggregator + mobile UI for finding scenes that are
already publicly available.
</p>
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
<div class="card-hover bg-card border border-border rounded-2xl p-6">
<div class="text-accent text-2xl mb-3">⌬</div>
<h3 class="text-lg font-bold mb-2">Multi-source ingest</h3>
<p class="text-sm text-gray-400 leading-relaxed">
TPDB &amp; StashDB metadata plus 46 public sources, scenes and full movies.
Cross-source deduplication via perceptual-hash thumbnails and title matching,
so the same scene from six tubes stays one entry.
</p>
</div>
<div class="card-hover bg-card border border-border rounded-2xl p-6">
<div class="text-accent text-2xl mb-3">⌖</div>
<h3 class="text-lg font-bold mb-2">Per-performer backfill</h3>
<p class="text-sm text-gray-400 leading-relaxed">
A continuous worker walks performers by staleness and back-fills tube scenes
for the longest-stale first. Completeness over recency.
</p>
</div>
<div class="card-hover bg-card border border-border rounded-2xl p-6">
<div class="text-accent text-2xl mb-3">⌥</div>
<h3 class="text-lg font-bold mb-2">Smart stream resolution</h3>
<p class="text-sm text-gray-400 leading-relaxed">
yt-dlp for mainstream tubes + P.A.C.K.E.R. unpacker for JWPlayer hosters
+ WebView fallback for IP-bound CDNs. Streams direct from source, no transcoding.
</p>
</div>
<div class="card-hover bg-card border border-border rounded-2xl p-6">
<div class="text-accent text-2xl mb-3">⌗</div>
<h3 class="text-lg font-bold mb-2">Mobile-first UI</h3>
<p class="text-sm text-gray-400 leading-relaxed">
React Native + Expo. Separate tabs for scenes, movies, sites and JAV,
plus performer pages, watch history, favorites and hold-to-preview
thumbnails. Built for thumb scrolling.
</p>
</div>
<div class="card-hover bg-card border border-border rounded-2xl p-6">
<div class="text-accent text-2xl mb-3">⌘</div>
<h3 class="text-lg font-bold mb-2">Privacy by default</h3>
<p class="text-sm text-gray-400 leading-relaxed">
App lock (PIN + biometrics), FLAG_SECURE screenshot block, age gate.
No analytics. No telemetry unless YOU configure Sentry with your own DSN.
</p>
</div>
<div class="card-hover bg-card border border-border rounded-2xl p-6">
<div class="text-accent text-2xl mb-3">⌬</div>
<h3 class="text-lg font-bold mb-2">Works out of the box</h3>
<p class="text-sm text-gray-400 leading-relaxed">
Download the APK and it connects automatically, no account, no
config. Power users can point it at their own self-hosted backend.
</p>
</div>
</div>
</div>
</section>
<!-- SCREENSHOTS -->
<section class="px-6 py-20">
<div class="max-w-5xl mx-auto">
<h2 class="text-3xl font-extrabold mb-2 tracking-tight">In the app</h2>
<p class="text-gray-500 mb-12">Screenshots from a real install. Thumbnails are blurred here, not in the app.</p>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<figure class="bg-card border border-border rounded-2xl overflow-hidden">
<img src="/shots/01_scenes_grid.png" alt="Scenes screen" loading="lazy" width="1080" height="2400"
class="w-full h-auto block" />
<figcaption class="p-4">
<div class="text-sm font-bold mb-1">Scenes</div>
<div class="text-xs text-gray-500 leading-relaxed">Grid with search, tag filters and favourites.</div>
</figcaption>
</figure>
<figure class="bg-card border border-border rounded-2xl overflow-hidden">
<img src="/shots/03_scene_detail.png" alt="Scene screen" loading="lazy" width="1080" height="2400"
class="w-full h-auto block" />
<figcaption class="p-4">
<div class="text-sm font-bold mb-1">Scene</div>
<div class="text-xs text-gray-500 leading-relaxed">Cast, studio, tags and every source that has it.</div>
</figcaption>
</figure>
<figure class="bg-card border border-border rounded-2xl overflow-hidden">
<img src="/shots/06_performer_page.png" alt="Performer screen" loading="lazy" width="1080" height="2400"
class="w-full h-auto block" />
<figcaption class="p-4">
<div class="text-sm font-bold mb-1">Performer</div>
<div class="text-xs text-gray-500 leading-relaxed">Everything indexed for one performer.</div>
</figcaption>
</figure>
<figure class="bg-card border border-border rounded-2xl overflow-hidden">
<img src="/shots/02_settings.png" alt="App lock screen" loading="lazy" width="1080" height="2400"
class="w-full h-auto block" />
<figcaption class="p-4">
<div class="text-sm font-bold mb-1">App lock</div>
<div class="text-xs text-gray-500 leading-relaxed">PIN and biometrics, screenshots blocked.</div>
</figcaption>
</figure>
</div>
</div>
</section>
<!-- WHAT'S NEW -->
<section class="px-6 py-20 bg-bgElevated/30 border-y border-border">
<div class="max-w-5xl mx-auto">
<h2 class="text-3xl font-extrabold mb-2 tracking-tight">What's new</h2>
<p class="text-gray-500 mb-12 max-w-xl">
The catalog keeps growing. Recent additions, newest first.
</p>
<div class="space-y-6">
<div class="bg-card border border-border rounded-2xl p-6">
<div class="font-mono text-xs text-accent mb-2">August 2026</div>
<h3 class="text-lg font-bold mb-2">Animation and 3D</h3>
<p class="text-sm text-gray-400 leading-relaxed">
Six new sources covering hentai and 3D animation, each with its own
catalogue rather than reposts of the others. Series, episode numbers and
genres come along with them.
</p>
</div>
<div class="bg-card border border-border rounded-2xl p-6">
<div class="font-mono text-xs text-accent mb-2">August 2026</div>
<h3 class="text-lg font-bold mb-2">45,000 movies</h3>
<p class="text-sm text-gray-400 leading-relaxed">
Full-length movies now sit in their own tab, enriched with cast, studio
and categories, and deduplicated against each other.
</p>
</div>
<div class="bg-card border border-border rounded-2xl p-6">
<div class="font-mono text-xs text-accent mb-2">July 2026</div>
<h3 class="text-lg font-bold mb-2">JAV in its own tab</h3>
<p class="text-sm text-gray-400 leading-relaxed">
JAV is a separate namespace that does not deduplicate against the western
catalogue, so it lives in its own tab instead of mixing into the main feed.
</p>
</div>
</div>
</div>
</section>
<!-- GET STARTED -->
<section class="px-6 py-20 bg-bgElevated/30 border-y border-border">
<div class="max-w-3xl mx-auto">
<h2 class="text-3xl font-extrabold mb-3 tracking-tight">Get started</h2>
<p class="text-gray-500 mb-8">Three steps. No account, no server, no config.</p>
<div class="bg-card border-2 border-accent rounded-2xl p-5 mb-6">
<p class="text-sm font-bold text-accent mb-2">Already have Goon installed? Read this first.</p>
<p class="text-sm text-gray-300 leading-relaxed">
0.2.2 is signed with a new key, so Android will not install it over the old app.
You have to uninstall first, and that wipes what is stored on the phone.
<strong class="text-gray-100">Before you uninstall</strong>, open Goon, go to Settings,
Backup &amp; sync, and copy your sync code. Install this APK, then paste the code into
Restore. Without it your favourites, saved searches, hidden list and watch progress
cannot be found again. A one-off: later updates install themselves as usual.
</p>
</div>
<ol class="space-y-4">
<li class="bg-card border border-border rounded-2xl p-5 flex gap-4">
<span class="text-accent font-extrabold text-xl">1</span>
<span class="text-sm text-gray-300 leading-relaxed">
<a href="/goon-v0.2.2.apk" class="text-accent font-bold hover:underline">Download the APK</a>
and open it. Allow "install from unknown sources" for your browser if Android asks.
</span>
</li>
<li class="bg-card border border-border rounded-2xl p-5 flex gap-4">
<span class="text-accent font-extrabold text-xl">2</span>
<span class="text-sm text-gray-300 leading-relaxed">
Open the app, accept the 18+ gate. It connects automatically, no login.
</span>
</li>
<li class="bg-card border border-border rounded-2xl p-5 flex gap-4">
<span class="text-accent font-extrabold text-xl">3</span>
<span class="text-sm text-gray-300 leading-relaxed">
Browse. That's it.
</span>
</li>
</ol>
</div>
</section>
<!-- DONATE -->
<section id="donate" class="px-6 py-20">
<div class="max-w-3xl mx-auto">
<h2 class="text-3xl font-extrabold mb-3 tracking-tight">Support the project</h2>
<p class="text-gray-400 mb-8 leading-relaxed max-w-xl">
Goon stays free and ad-free because donations cover the VPS, the
TPDB/StashDB tokens, and the time. <strong class="text-gray-200">Crypto
only</strong>. Mainstream processors won't touch adult-adjacent
FOSS projects.
</p>
<div class="grid sm:grid-cols-3 gap-3">
<div class="bg-card border border-border rounded-2xl p-5">
<div class="text-orange-500 text-xs font-mono font-bold mb-1">XMR</div>
<div class="text-sm font-bold mb-3">Monero</div>
<p class="text-xs text-gray-500 leading-relaxed">
Privacy by default. Recommended. Get the address from the app or the project README.
</p>
</div>
<div class="bg-card border border-border rounded-2xl p-5">
<div class="text-yellow-500 text-xs font-mono font-bold mb-1">BTC</div>
<div class="text-sm font-bold mb-3">Bitcoin</div>
<p class="text-xs text-gray-500 leading-relaxed">
Mainstream &amp; easy to send. Use a fresh wallet if you care about on-chain anonymity.
</p>
</div>
<div class="bg-card border border-border rounded-2xl p-5">
<div class="text-blue-400 text-xs font-mono font-bold mb-1">LTC</div>
<div class="text-sm font-bold mb-3">Litecoin</div>
<p class="text-xs text-gray-500 leading-relaxed">
Fast and cheap (~$0.01 fee). Lower adoption than BTC but friendlier for small donations.
</p>
</div>
</div>
<p class="text-xs text-gray-500 mt-6">
Addresses + QR codes are shown in the app under Scenes &raquo; ♥.
</p>
</div>
</section>
<!-- FOOTER -->
<footer class="px-6 py-12 border-t border-border">
<div class="max-w-5xl mx-auto flex flex-col sm:flex-row gap-6 justify-between text-xs text-gray-500">
<div>
<div class="flex items-center gap-2 mb-2">
<div class="w-2 h-2 rounded-full bg-accent"></div>
<span class="font-bold tracking-widest uppercase">goon</span>
</div>
<p>Adult content metadata aggregator. FOSS, ad-free.</p>
<p>MIT license. No warranty. 18+ jurisdictions only.</p>
</div>
<div class="flex flex-col gap-1 text-right">
<a href="/goon-v0.2.2.apk" class="hover:text-accent transition">Download APK</a>
<a href="#donate" class="hover:text-accent transition">Donate</a>
</div>
</div>
<p class="max-w-5xl mx-auto mt-6 text-[10px] text-gray-600 leading-relaxed">
Goon does not host, transcode, store, or distribute any media. It scrapes
publicly-available metadata and links out to the source. Users are
responsible for complying with local law.
</p>
</footer>
<script>
// Persist age-gate acknowledgement so it doesn't reappear every visit.
if (localStorage.getItem('agegate_v1') === 'ok') {
document.getElementById('agegate').style.display = 'none';
}
document.querySelector('#agegate button').addEventListener('click', function () {
localStorage.setItem('agegate_v1', 'ok');
});
</script>
</body>
</html>