david-spacil c0272f4f70
testy / pytest (3.11) (push) Successful in 1s
testy / pytest (3.12) (push) Successful in 1s
testy / pytest (3.13) (push) Successful in 1s
testy / pytest (3.14) (push) Successful in 1s
binárka / linux (push) Successful in 10s
Merge pull request 'Zaříznout stará jména kostky' (#20) from agents/claude/zariznout-stara-jmena into main
Reviewed-on: #20
2026-08-23 23:14:58 +02:00
2026-08-23 23:09:15 +02:00
2026-08-22 18:26:32 +02:00
2026-08-23 23:09:15 +02:00
2026-08-22 18:26:32 +02:00
2026-08-23 23:09:15 +02:00
2026-08-22 18:22:35 +02:00
2026-08-22 18:22:35 +02:00
2026-08-22 18:22:35 +02:00
2026-08-22 18:22:35 +02:00
2026-08-22 18:22:35 +02:00
2026-08-22 18:22:35 +02:00
2026-08-23 23:09:15 +02:00

Dice Counter

Doprovod k fyzickým kostkám: telefon zapisuje skóre, notebook ukazuje zápisník a hry se pamatují mezi večery.

Hráči se napříč hrami poznávají podle jména — Adam ze středečního večera je ten samý Adam jako z minulého měsíce. Žádné účty, žádná hesla.

Spuštění

Stáhni binárku pro svůj systém z releases:

Systém Soubor
Linux (x86-64) dice-counter-linux-x86_64
Linux (ARM64) dice-counter-linux-arm64
macOS (Apple Silicon) dice-counter-macos-arm64
macOS (Intel) dice-counter-macos-x86_64
Windows (x86-64) dice-counter-windows-x86_64.exe

Nic se neinstaluje — Python, Flask i šablony jsou uvnitř.

Na Linuxu a macOS:

chmod +x dice-counter-*
./dice-counter-linux-x86_64

Na Windows stačí na .exe poklepat.

Linuxová binárka je postavená proti glibc 2.17, takže jede prakticky všude.

Než to poprvé pustíš

Binárky nejsou podepsané — podpisové certifikáty stojí tisíce ročně a na počitadlo kostek by to byl nesmysl. Systémy si toho všimnou:

  • macOS stažený soubor označí za karanténní a odmítne ho spustit. Buď značku sundej (xattr -dr com.apple.quarantine dice-counter-macos-arm64), nebo soubor stáhni rovnou z terminálu přes curl -LO — tudy se karanténa nenastavuje.
  • Windows ukáže modré okno SmartScreenu. Další informace → Přesto spustit. Občas si postěžuje i antivirus; u zabalených Python programů je to běžný falešný poplach. Při prvním spuštění se ještě zeptá brána firewall — bez povolení do místní sítě se telefon nepřipojí.

Kdo tomu nechce věřit, ověří si stažený soubor podle přiloženého součtu (níž) nebo si ho postaví sám — ./build.sh, zdrojáky jsou tady celé.

Ze zdrojáků to je stejně krátké:

uv run web.py

Závislosti si skript nese v hlavičce (PEP 723) a uv je obstará sám.

Server vypíše všechny adresy, na kterých je dostupný:

dice-counter v1.2.2

Počitadlo je dostupné na:
 → http://10.186.234.182:8000     místní síť
   http://100.91.0.24:8000        přes Tailscale
   http://172.17.0.1:8000         virtuální síť

Kterou verzi máš, řekne i dice-counter --version; visí taky v patičce každé stránky. Když něco nefunguje, je to první věc, na kterou se zeptám.

Na notebooku otevři /board, naskenuj QR kód telefonem a hraj. Tabule nabízí i zbylé adresy — když jedna nefunguje, klikni na jinou a QR kód se přepne na ni. Zastavuje se Ctrl+C.

Proměnná K čemu je Výchozí
DICE_DB soubor s databází podle způsobu spuštění, viz níž
DICE_PORT port 8000
DICE_HOST pevná adresa; vypne hledání hledá se za běhu

Kde jsou data

Jeden soubor SQLite. Založí se sám při prvním načtení stránky, cestu k němu server vypíše při startu.

Spuštěno Databáze
binárkou na Linuxu ~/.local/share/dice-counter/dice.db
binárkou na macOS ~/Library/Application Support/dice-counter/dice.db
binárkou na Windows %LOCALAPPDATA%\dice-counter\dice.db
ze zdrojáků dice.db v pracovním adresáři

Binárka se při každém spuštění rozbaluje do dočasného adresáře a pouští se odkudkoli, takže relativní cesta by databázi rozsypala po disku — proto napevno domovský adresář. Ze zdrojáků zůstává relativní, ať se dá mít víc sad vedle sebe.

Zálohovat i stěhovat jde prostým zkopírováním souboru; DICE_DB si ho najde kdekoli. Kdo ho hledat nechce — a z binárky na Windows je zalezlý — si ho stáhne ze síně slávy odkazem Stáhnout databázi (/export). Kopie se dělá přes VACUUM INTO, takže je použitelná i uprostřed rozehrané hry.

Schéma má verzi uloženou v PRAGMA user_version a storage.migrate() si databázi při každém připojení dorovná. Starší soubory z verzí, kdy se verze schématu ještě nepsala, se poznají podle nuly a orazítkují se. Databázi založenou novější verzí počitadla appka odmítne otevřít, místo aby ji tiše rozbila.

Obsluhuje to waitress — čistě pythonní WSGI server, který se zabalí do binárky stejně snadno jako zbytek. Vestavěný server Flasku by pod úvodní hlášku vysypal varování, že takhle se to nemá, a měl by pravdu.

Počítá se s domácí sítí — appka nemá přihlašování a kdokoli na stejné WiFi může zapisovat.

Nasazení na server

Kdo nechce každý večer spouštět binárku na notebooku, může to nechat běžet pořád. Obojí níž počítá jen s domácí sítí — appka nemá přihlašování a ani jedno nasazení ji nijak nezabezpečuje. Do internetu to nepatří.

Proxmox (LXC)

Jeden příkaz v terminálu uzlu Proxmoxu, jako root. Založí kontejner, nastaví ho, stáhne poslední vydanou binárku, ověří kontrolní součet a zapne službu:

bash -c "$(curl -fsSL https://gitea.spacilovi.eu/david-spacil/dice-counter/raw/branch/main/deploy/pve-dice-counter.sh)"

Na konci vypíše adresu, na které počitadlo poslouchá. Výchozí nastavení je 1 jádro, 512 MB, 4 GB disku a Debian 13; úložiště si najde samo. Přebíjí se proměnnými před příkazem:

MEMORY=1024 STORAGE=local-zfs PORT=8080 bash -c "$(curl -fsSL ...)"
Proměnná Výchozí
CTID první volné číslo
CT_HOSTNAME dice-counter
CORES, MEMORY, DISK 1, 512, 4
STORAGE první aktivní úložiště pro kontejnery
TEMPLATE_STORAGE, BRIDGE local, vmbr0
PORT 8000
UNPRIVILEGED, OSVERSION 1, 13
NESTING 1 — systemd v Debianu 13 ho potřebuje
AUTOLOGIN 1 — konzole ve webu Proxmoxu bez hesla
VERSION poslední vydání

Aktualizace na novější vydání se dá spustit dvěma způsoby. Buď zevnitř kontejneru, kde na to stačí jedno slovo:

update

Nebo z uzlu Proxmoxu tím samým příkazem s číslem kontejneru:

CTID=123 MODE=update bash -c "$(curl -fsSL ...)"

Obojí vymění binárku za poslední vydání a službu restartuje; databáze zůstává. Příkaz update si přitom obnoví i sám sebe — instalátor bere z větve main, takže jede na nejnovější verzi skriptu, ne na té, se kterou se instalovalo.

Do konzole kontejneru se dostaneš přímo z webu Proxmoxu, žádné jméno ani heslo se nezadává — kontejner root heslo nemá a konzole se přihlašuje sama. Nová práva to nikomu nedává: kdo se dostane do webu Proxmoxu, má root na uzlu tak jako tak. Komu se to nezdá, vypne to přes AUTOLOGIN=0 a do kontejneru pak leze přes pct enter <ctid>.

Podoba je odkoukaná od community-scripts.org, ale nic z jejich frameworku se nestahuje — jejich build.func si instalační skript hledá natvrdo ve vlastním repozitáři, takže mimo něj nefunguje.

Instalátor, který běží uvnitř kontejneru, je ve skriptu vložený jako text — přes rouru z curlu na disku hostitele žádný druhý soubor není. O Proxmoxu nic neví, takže se dá použít i v kontejneru, který sis založil sám:

bash pve-dice-counter.sh instalator > install.sh

Je idempotentní; druhé spuštění jen vymění binárku za nejnovější.

Docker

Stačí jeden soubor, repozitář k tomu potřeba není:

curl -fsSLO https://gitea.spacilovi.eu/david-spacil/dice-counter/raw/branch/main/deploy/docker-compose.yaml
docker compose up -d

Image se stáhne hotový z registru Gitey, pro amd64 i arm64 — Docker si vybere svoji variantu sám. Databáze leží v pojmenovaném svazku, appka běží pod nerootovým uživatelem.

Aktualizace na novější vydání:

docker compose pull && docker compose up -d

Kdo si ho radši postaví ze zdrojáků, přebije ten stažený stejnou značkou:

docker build -f deploy/Dockerfile -t gitea.spacilovi.eu/david-spacil/dice-counter:latest .

Pozor na síť. Compose schválně používá network_mode: host. V bridge režimu kontejner uvnitř vidí adresu jako 172.17.0.2, tabule ji poctivě nabídne a vygeneruje na ni QR kód — jenže z telefonu je nedosažitelná. Kdo bridge potřebuje, musí nastavit DICE_HOST na adresu hostitele v LAN.

LXC Docker
Odkud vydaná binárka z releasu image z registru
Databáze /var/lib/dice-counter/dice.db svazek dice-counter-data
Aktualizace update uvnitř kontejneru docker compose pull
Adresa a QR funguje samo potřeba síť hostitele

Když se telefon nepřipojí

Adresy se hledají při každém načtení tabule, takže přechod z domácí WiFi na hotspot a zpátky si tabule pohlídá sama a načte se znovu.

Zbývají tři důvody, proč se telefon nedostane na notebook:

  • Telefon je na mobilních datech, notebook na WiFi. Různé sítě, nepotkají se. Připoj telefon na stejnou WiFi, nebo notebook na hotspot telefonu — to funguje taky.
  • Zapnutý hotspot na telefonu shodil jeho WiFi. Většina Androidů to dělá. Pak je řešením připojit na ten hotspot i notebook.
  • VPN nebo Tailscale exit node na telefonu posílá veškerý provoz mimo místní síť. V Tailscale to řeší přepínač „Allow local network access"; případně použij tailnet adresu notebooku, ta funguje odkudkoli.

Pravidla

Skóre se zadává ručně po tazích, hází se doopravdy. Tři nulové tahy za sebou vynulují hráči skóre; indikátor x / xx ukazuje, jak blízko k tomu je. Vítěz se vyhlašuje až po dokončeném kole, aby měli všichni stejný počet tahů — při remíze na prvním místě se hraje dál.

Co kde je

Soubor Role
core.py pravidla hry, žádný vstup ani výstup
net.py hledání adres, na kterých je počitadlo dostupné
storage.py SQLite: hráči, hry, tahy
stats.py síň slávy a kariérní statistiky
web.py Flask aplikace
dice.py totéž v terminálu, bez ukládání
console.py aby čeština prošla i windowsovou konzolí
version.py která verze to je — z gitu, nebo z binárky
build.sh, dice-counter.spec stavba binárky
.gitea/workflows/ testy, linuxová binárka a zkouška image doma
.github/workflows/ binárky pro Windows a macOS
deploy/ nasazení na server: Proxmox LXC a Docker

Terminálová verze zůstává funkční jako záloha:

uv run dice.py

Bez uv

Když uv po ruce není, jde to postaru:

python -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python web.py

Na Fedoře stačí i systémové balíčky, pak se nemusí řešit vůbec nic:

sudo dnf install python3-flask python3-qrcode python3-tabulate python3-waitress
python3 web.py

Závislosti

Verze jsou zamčené, aby binárka postavená dnes a za půl roku obsahovala totéž. Volné seznamy jsou v .in, zamčené v .txt:

Soubor K čemu
requirements.in → .txt běh aplikace
requirements-dev.in → .txt + pytest, pro testy
requirements-build.in → .txt + PyInstaller, pro stavbu binárky

Aktualizace je vědomý krok, ne vedlejší efekt toho, že něco vyšlo na PyPI:

for f in requirements requirements-dev requirements-build; do
    uv pip compile "$f.in" -o "$f.txt"
done

Verze se píšou ještě jednou v hlavičce PEP 723 na začátku web.py a dice.py, aby fungovalo uv run web.py. Že se ty dva zápisy shodují, hlídá tests/test_zavislosti.py — po každém přegenerování je potřeba hlavičky srovnat.

Vlastní binárka

./build.sh

Verzi si build.sh vezme z git describe, nebo se dá vnutit přes VERSION=v1.2.3 ./build.sh. Zapíše ji do verze.txt, dice-counter.spec ji přibalí a binárka ji pak umí ohlásit i na cizím počítači, kde žádný git není. Verzi Pythonu, proti kterému se staví, přebíjí PYTHON_VERSION.

Staví se proti samostatnému CPythonu od uv, ne proti systémovému. Ten je slinkovaný s glibc 2.17; postavené proti Pythonu z Fedory 44 by to chtělo glibc 2.43 a nešlo by spustit skoro nikde — glibc drží zpětnou kompatibilitu, ne dopřednou. Nic z hostitele se do binárky nedostane, takže kontejner k tomu potřeba není. Výsledek je v dist/.

Stejný build.sh staví i na macOS a na Windows (v Git Bash) — jen tam bez té starosti o glibc. Křížem to nejde: PyInstaller balí do výsledku interpret a knihovny toho systému, na kterém běží, takže binárku pro každý systém musí postavit ten systém.

Terminálová verze součástí binárky není; ta se pouští ze zdrojáků.

Jak vznikají releasy

Otagovaný commit spustí stavbu na obou stranách:

Kde Co staví Workflow
vlastní runner u Gitey Linux x86-64 .gitea/workflows/binarka.yml
GitHub Actions Windows, macOS ×2, Linux ARM64 .github/workflows/binarky.yml
GitHub Actions image amd64 + arm64 .github/workflows/image.yml
git tag v1.0.0 && git push origin v1.0.0

GitHub je tu jen půjčená dílna. Repozitář se tam z Gitey zrcadlí (mirror), postavené soubory se posílají zpátky na zdejší release přes Gitea API a projekt má pořád jednu stránku s releasy — tuhle. Linux na x86-64 se na GitHubu schválně nestaví; doma to jde proti staré glibc, a když GitHub vypadne, release má aspoň tu platformu, na které to reálně poběží. ARM64 je výjimka — doma na něm není na čem stavět, a hodí se pro Raspberry Pi nebo jinou malou pořád zapnutou krabičku.

Každá stavba nejdřív projede testy a zkusí hotovou binárku nastartovat, než ji kamkoli pověsí. Vedle každé visí i .sha256, takže se stažený soubor dá ověřit:

sha256sum -c dice-counter-linux-x86_64.sha256   # na macOS: shasum -a 256 -c

Nad pull requesty se Linux staví taky, jen se nikam nevěší. Totéž platí pro kontejnerový image — doma se nad každým PR postaví a zkusí nastartovat (.gitea/workflows/image.yml), publikuje se ale až z tagu na GitHubu.

Image se schválně nevydává doma: tamní runner běží v LXC, kde nejde zaregistrovat emulaci pro arm64 — je to vlastnost jádra hostitele a ten je produkční stroj. Běhouni GitHubu jsou plnohodnotné virtuály, kde to funguje bez zásahu do čehokoli.

Testy

uv run --with-requirements requirements.txt --no-project pytest

Nebo z připraveného prostředí prostě pytest.

Nad každým pull requestem a nad main běží .gitea/workflows/testy.yml — 118 testů na Pythonu 3.11, 3.12, 3.13 i 3.14, a k tomu skriptovaná partie v terminálové verzi, na kterou pytest nesahá.

S
Description
No description provided
Readme
515 KiB
0 Stars 1 Watchers 0 Forks
2026-08-23 23:15:56 +02:00
Languages
Python 65.1%
HTML 12.4%
Shell 12.3%
CSS 8.4%
Dockerfile 1.8%