diff options
| author | salmonik <salmonik@tuta.io> | 2026-10-30 00:07:24 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-10-30 00:07:24 +0100 |
| commit | 2f92026ec648d47c25fea6fc8f354fbc04f4d714 (patch) | |
| tree | a432320c6630eb9e5f44a2499a40da63fffbc37a | |
| parent | make the download page dynamic: scan builds, show versions and SHA-256 (diff) | |
| download | zagan-bet-2f92026ec648d47c25fea6fc8f354fbc04f4d714.tar.gz zagan-bet-2f92026ec648d47c25fea6fc8f354fbc04f4d714.zip | |
strip the download page to plain HTML: no CSS, sha256sum-format checksums
| -rw-r--r-- | web/README.md | 5 | ||||
| -rw-r--r-- | web/index.php | 309 |
2 files changed, 53 insertions, 261 deletions
diff --git a/web/README.md b/web/README.md index 3c6ee08..5434e28 100644 --- a/web/README.md +++ b/web/README.md | |||
| @@ -2,7 +2,8 @@ | |||
| 2 | 2 | ||
| 3 | `index.php` scans `bin/client` and `bin/server` on every request and renders | 3 | `index.php` scans `bin/client` and `bin/server` on every request and renders |
| 4 | whatever builds it finds, with version, size and SHA-256. No database, no | 4 | whatever builds it finds, with version, size and SHA-256. No database, no |
| 5 | JavaScript, no dependencies. PHP 8.0+. | 5 | JavaScript, no CSS, no dependencies. The page is plain browser defaults: |
| 6 | black text, blue links, monospace checksums. PHP 8.0+. | ||
| 6 | 7 | ||
| 7 | ## Layout | 8 | ## Layout |
| 8 | 9 | ||
| @@ -62,3 +63,5 @@ Then open <http://127.0.0.1:8899/>. | |||
| 62 | handful of builds; add an mtime-keyed cache if the directory grows. | 63 | handful of builds; add an mtime-keyed cache if the directory grows. |
| 63 | - The page lists every build it finds, newest version first, so old releases | 64 | - The page lists every build it finds, newest version first, so old releases |
| 64 | stay downloadable until you remove them from `bin/`. | 65 | stay downloadable until you remove them from `bin/`. |
| 66 | - The checksum block is in `sha256sum` format, so visitors can save it as | ||
| 67 | `SHA256SUMS` and run `sha256sum -c SHA256SUMS`. | ||
diff --git a/web/index.php b/web/index.php index cd77dad..361fdcf 100644 --- a/web/index.php +++ b/web/index.php | |||
| @@ -164,274 +164,63 @@ foreach (KINDS as $kind => $meta) { | |||
| 164 | <meta name="viewport" content="width=device-width, initial-scale=1"> | 164 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 165 | <title>Download · zagan.bet</title> | 165 | <title>Download · zagan.bet</title> |
| 166 | <meta name="description" content="Official zagan.bet client and server downloads."> | 166 | <meta name="description" content="Official zagan.bet client and server downloads."> |
| 167 | <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:"> | 167 | <meta http-equiv="Content-Security-Policy" content="default-src 'none'"> |
| 168 | <link rel="icon" href="data:,"> | ||
| 169 | <style> | ||
| 170 | :root { | ||
| 171 | --bg: #0b0e11; | ||
| 172 | --panel: #11171d; | ||
| 173 | --line: #222c35; | ||
| 174 | --text: #dde6ec; | ||
| 175 | --muted: #8b9aa6; | ||
| 176 | --accent: #5fd0e0; | ||
| 177 | --win: #6ee7a0; | ||
| 178 | --radius: 10px; | ||
| 179 | } | ||
| 180 | |||
| 181 | * { box-sizing: border-box; } | ||
| 182 | |||
| 183 | body { | ||
| 184 | margin: 0; | ||
| 185 | background: var(--bg); | ||
| 186 | color: var(--text); | ||
| 187 | font: 16px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; | ||
| 188 | } | ||
| 189 | |||
| 190 | code, pre, .mono { | ||
| 191 | font-family: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace; | ||
| 192 | } | ||
| 193 | |||
| 194 | .wrap { | ||
| 195 | max-width: 880px; | ||
| 196 | margin: 0 auto; | ||
| 197 | padding: 3rem 1.25rem 4rem; | ||
| 198 | } | ||
| 199 | |||
| 200 | header { margin-bottom: 2.5rem; } | ||
| 201 | |||
| 202 | h1 { | ||
| 203 | margin: 0 0 .35rem; | ||
| 204 | font: 700 2rem/1.1 ui-monospace, "SF Mono", Menlo, Consolas, monospace; | ||
| 205 | letter-spacing: -.02em; | ||
| 206 | } | ||
| 207 | |||
| 208 | h1 span { color: var(--accent); } | ||
| 209 | |||
| 210 | .tagline { margin: 0; color: var(--muted); } | ||
| 211 | |||
| 212 | .stamp { margin: .6rem 0 0; color: var(--muted); font-size: .8rem; } | ||
| 213 | |||
| 214 | section { margin-top: 2.5rem; } | ||
| 215 | |||
| 216 | h2 { | ||
| 217 | margin: 0 0 .9rem; | ||
| 218 | font-size: .8rem; | ||
| 219 | font-weight: 600; | ||
| 220 | letter-spacing: .12em; | ||
| 221 | text-transform: uppercase; | ||
| 222 | color: var(--muted); | ||
| 223 | border-bottom: 1px solid var(--line); | ||
| 224 | padding-bottom: .6rem; | ||
| 225 | } | ||
| 226 | |||
| 227 | .hint { margin: -.3rem 0 1rem; color: var(--muted); font-size: .9rem; } | ||
| 228 | |||
| 229 | .empty { color: var(--muted); font-size: .9rem; } | ||
| 230 | |||
| 231 | .grid { | ||
| 232 | list-style: none; | ||
| 233 | margin: 0; | ||
| 234 | padding: 0; | ||
| 235 | display: grid; | ||
| 236 | grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); | ||
| 237 | gap: .9rem; | ||
| 238 | } | ||
| 239 | |||
| 240 | .card { | ||
| 241 | background: var(--panel); | ||
| 242 | border: 1px solid var(--line); | ||
| 243 | border-radius: var(--radius); | ||
| 244 | padding: 1rem; | ||
| 245 | display: flex; | ||
| 246 | flex-direction: column; | ||
| 247 | gap: .3rem; | ||
| 248 | } | ||
| 249 | |||
| 250 | .card-head { | ||
| 251 | display: flex; | ||
| 252 | align-items: baseline; | ||
| 253 | justify-content: space-between; | ||
| 254 | gap: .5rem; | ||
| 255 | } | ||
| 256 | |||
| 257 | .card h3 { margin: 0; font-size: 1rem; } | ||
| 258 | |||
| 259 | .ver { | ||
| 260 | font-size: .75rem; | ||
| 261 | color: var(--accent); | ||
| 262 | border: 1px solid var(--line); | ||
| 263 | border-radius: 999px; | ||
| 264 | padding: .1rem .5rem; | ||
| 265 | white-space: nowrap; | ||
| 266 | } | ||
| 267 | |||
| 268 | .card .arch { margin: 0; color: var(--muted); font-size: .85rem; } | ||
| 269 | |||
| 270 | .card .meta { margin: 0; color: var(--muted); font-size: .8rem; } | ||
| 271 | |||
| 272 | .card .btn { margin-top: .7rem; } | ||
| 273 | |||
| 274 | .btn { | ||
| 275 | display: block; | ||
| 276 | text-align: center; | ||
| 277 | text-decoration: none; | ||
| 278 | padding: .55rem .8rem; | ||
| 279 | border-radius: 7px; | ||
| 280 | background: var(--accent); | ||
| 281 | color: #06222a; | ||
| 282 | font-weight: 600; | ||
| 283 | font-size: .92rem; | ||
| 284 | } | ||
| 285 | |||
| 286 | .btn:hover { background: #86e2ee; } | ||
| 287 | |||
| 288 | .btn:focus-visible, | ||
| 289 | summary:focus-visible { | ||
| 290 | outline: 2px solid var(--win); | ||
| 291 | outline-offset: 2px; | ||
| 292 | } | ||
| 293 | |||
| 294 | pre { | ||
| 295 | margin: 0 0 1rem; | ||
| 296 | padding: .85rem 1rem; | ||
| 297 | overflow-x: auto; | ||
| 298 | background: var(--panel); | ||
| 299 | border: 1px solid var(--line); | ||
| 300 | border-radius: var(--radius); | ||
| 301 | font-size: .88rem; | ||
| 302 | line-height: 1.6; | ||
| 303 | } | ||
| 304 | |||
| 305 | pre .c { color: var(--muted); } | ||
| 306 | |||
| 307 | .table-wrap { overflow-x: auto; } | ||
| 308 | |||
| 309 | table { | ||
| 310 | width: 100%; | ||
| 311 | border-collapse: collapse; | ||
| 312 | font-size: .82rem; | ||
| 313 | } | ||
| 314 | |||
| 315 | th, td { | ||
| 316 | text-align: left; | ||
| 317 | padding: .55rem .7rem; | ||
| 318 | border-bottom: 1px solid var(--line); | ||
| 319 | vertical-align: top; | ||
| 320 | } | ||
| 321 | |||
| 322 | th { | ||
| 323 | color: var(--muted); | ||
| 324 | font-weight: 600; | ||
| 325 | font-size: .75rem; | ||
| 326 | letter-spacing: .06em; | ||
| 327 | text-transform: uppercase; | ||
| 328 | white-space: nowrap; | ||
| 329 | } | ||
| 330 | |||
| 331 | td.file { word-break: break-all; } | ||
| 332 | td.sum { word-break: break-all; color: var(--muted); } | ||
| 333 | td.size { white-space: nowrap; color: var(--muted); } | ||
| 334 | |||
| 335 | footer { | ||
| 336 | margin-top: 3rem; | ||
| 337 | padding-top: 1.5rem; | ||
| 338 | border-top: 1px solid var(--line); | ||
| 339 | color: var(--muted); | ||
| 340 | font-size: .88rem; | ||
| 341 | } | ||
| 342 | |||
| 343 | footer p { margin: .6rem 0 0; } | ||
| 344 | |||
| 345 | a { color: var(--accent); } | ||
| 346 | </style> | ||
| 347 | </head> | 168 | </head> |
| 348 | <body> | 169 | <body> |
| 349 | <div class="wrap"> | ||
| 350 | |||
| 351 | <header> | ||
| 352 | <h1>zagan<span>.bet</span></h1> | ||
| 353 | <p class="tagline">Terminal betting. Slots, roulette, blackjack and crash.</p> | ||
| 354 | <?php if ($newest > 0): ?> | ||
| 355 | <p class="stamp">Builds published <?= e(gmdate('j M Y H:i', $newest)) ?> UTC</p> | ||
| 356 | <?php endif; ?> | ||
| 357 | </header> | ||
| 358 | 170 | ||
| 359 | <main> | 171 | <h1>zagan.bet</h1> |
| 360 | <?php foreach (KINDS as $kind => $meta): ?> | 172 | <p>Official client and server builds.</p> |
| 361 | <section> | 173 | <?php if ($newest > 0): ?> |
| 362 | <h2><?= e($meta['title']) ?></h2> | 174 | <p>Builds published <?= e(gmdate('j M Y H:i', $newest)) ?> UTC.</p> |
| 363 | <p class="hint"><?= e($meta['hint']) ?></p> | 175 | <?php endif; ?> |
| 364 | 176 | ||
| 365 | <?php if ($releases[$kind] === []): ?> | 177 | <h2>Client</h2> |
| 366 | <p class="empty">Nothing published yet.</p> | 178 | <p>Needs a terminal of at least 80×24 cells.</p> |
| 367 | <?php else: ?> | 179 | <?php if ($releases['client'] === []): ?> |
| 368 | <ul class="grid"> | 180 | <p>Nothing published yet.</p> |
| 369 | <?php foreach ($releases[$kind] as $release): ?> | 181 | <?php else: ?> |
| 370 | <li class="card"> | 182 | <ul> |
| 371 | <div class="card-head"> | 183 | <?php foreach ($releases['client'] as $release): ?> |
| 372 | <h3><?= e(PLATFORMS[$release['platform']] ?? ucfirst($release['platform'])) ?></h3> | 184 | <li><a href="<?= e($release['href']) ?>" download><?= e(PLATFORMS[$release['platform']] ?? ucfirst($release['platform'])) ?> <?= e($release['arch']) ?><?php if (isset(ARCHES[$release['arch']])): ?> (<?= e(ARCHES[$release['arch']]) ?>)<?php endif; ?> — version <?= e($release['version']) ?> — <?= e(human_size($release['size'])) ?></a></li> |
| 373 | <span class="ver">v<?= e($release['version']) ?></span> | 185 | <?php endforeach; ?> |
| 374 | </div> | 186 | </ul> |
| 375 | <p class="arch"> | 187 | <?php endif; ?> |
| 376 | <?= e($release['arch']) ?><?php if (isset(ARCHES[$release['arch']])): ?> | 188 | |
| 377 | · <?= e(ARCHES[$release['arch']]) ?> | 189 | <h2>Server</h2> |
| 378 | <?php endif; ?> | 190 | <p>Generates its own TLS identity on first run.</p> |
| 379 | </p> | 191 | <?php if ($releases['server'] === []): ?> |
| 380 | <p class="meta"><?= e(human_size($release['size'])) ?></p> | 192 | <p>Nothing published yet.</p> |
| 381 | <a class="btn" href="<?= e($release['href']) ?>" download>Download</a> | 193 | <?php else: ?> |
| 382 | </li> | 194 | <ul> |
| 383 | <?php endforeach; ?> | 195 | <?php foreach ($releases['server'] as $release): ?> |
| 384 | </ul> | 196 | <li><a href="<?= e($release['href']) ?>" download><?= e(PLATFORMS[$release['platform']] ?? ucfirst($release['platform'])) ?> <?= e($release['arch']) ?><?php if (isset(ARCHES[$release['arch']])): ?> (<?= e(ARCHES[$release['arch']]) ?>)<?php endif; ?> — version <?= e($release['version']) ?> — <?= e(human_size($release['size'])) ?></a></li> |
| 385 | <?php endif; ?> | 197 | <?php endforeach; ?> |
| 386 | </section> | 198 | </ul> |
| 387 | <?php endforeach; ?> | 199 | <?php endif; ?> |
| 388 | 200 | ||
| 389 | <?php $all = array_merge($releases['client'], $releases['server']); ?> | 201 | <?php $all = array_merge($releases['client'], $releases['server']); ?> |
| 390 | <?php if ($all !== []): ?> | 202 | <?php if ($all !== []): ?> |
| 391 | <section> | 203 | <h2>SHA-256</h2> |
| 392 | <h2>Checksums</h2> | 204 | <p>Save this block as <code>SHA256SUMS</code> and run <code>sha256sum -c SHA256SUMS</code>. On Windows use <code>Get-FileHash <file></code>.</p> |
| 393 | <p class="hint">SHA-256 of every published file.</p> | 205 | <pre><?php |
| 394 | <div class="table-wrap"> | 206 | $sums = ''; |
| 395 | <table> | 207 | foreach ($all as $release) { |
| 396 | <thead> | 208 | $sums .= $release['sha256'] . ' ' . $release['file'] . "\n"; |
| 397 | <tr> | 209 | } |
| 398 | <th>File</th> | 210 | echo e($sums); |
| 399 | <th>Version</th> | 211 | ?></pre> |
| 400 | <th>Size</th> | 212 | <?php endif; ?> |
| 401 | <th>SHA-256</th> | ||
| 402 | </tr> | ||
| 403 | </thead> | ||
| 404 | <tbody> | ||
| 405 | <?php foreach ($all as $release): ?> | ||
| 406 | <tr> | ||
| 407 | <td class="file mono"><?= e($release['file']) ?></td> | ||
| 408 | <td><?= e($release['version']) ?></td> | ||
| 409 | <td class="size"><?= e(human_size($release['size'])) ?></td> | ||
| 410 | <td class="sum mono"><?= e($release['sha256']) ?></td> | ||
| 411 | </tr> | ||
| 412 | <?php endforeach; ?> | ||
| 413 | </tbody> | ||
| 414 | </table> | ||
| 415 | </div> | ||
| 416 | </section> | ||
| 417 | <?php endif; ?> | ||
| 418 | </main> | ||
| 419 | 213 | ||
| 420 | <footer> | 214 | <h2>Running it</h2> |
| 421 | <h2>Running it</h2> | 215 | <p>Client:</p> |
| 422 | <pre><code><span class="c"># client (use the file you downloaded)</span> | 216 | <pre><code>chmod +x <downloaded-client> |
| 423 | chmod +x <downloaded-client> | ||
| 424 | ./<downloaded-client></code></pre> | 217 | ./<downloaded-client></code></pre> |
| 425 | 218 | <p>Server, first run creates <code>identity.p12</code>, <code>key.pem</code> and <code>cert.pem</code>:</p> | |
| 426 | <pre><code><span class="c"># server: first run creates identity.p12, key.pem and cert.pem</span> | 219 | <pre><code>chmod +x <downloaded-server> |
| 427 | chmod +x <downloaded-server> | ||
| 428 | ./<downloaded-server> --init | 220 | ./<downloaded-server> --init |
| 429 | ./<downloaded-server> -i 0.0.0.0 -p 11525</code></pre> | 221 | ./<downloaded-server> -i 0.0.0.0 -p 11525</code></pre> |
| 430 | 222 | ||
| 431 | <p>Windows: run the <code>.exe</code> from Windows Terminal or another real terminal.</p> | 223 | <p>Windows: run the <code>.exe</code> from Windows Terminal or another real terminal.</p> |
| 432 | <p>Verify a download before running it: <code>sha256sum <file></code> (Linux) or <code>Get-FileHash <file></code> (Windows).</p> | ||
| 433 | </footer> | ||
| 434 | 224 | ||
| 435 | </div> | ||
| 436 | </body> | 225 | </body> |
| 437 | </html> | 226 | </html> |
