尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗A serverless bot that runs my family's weekly Quiniela (the Spanish football pools) end to end: it detects each new LaLiga matchday from the official lottery data, collects everyone's predictions through a small web app, posts progress and results to a Telegram group, works out who pays the next ticket and reports any prize won. It runs entirely on free tiers, with no server to maintain.
📄 Full guide (functional and technical, for any reader): English · Español
The code, documentation and database are in English. Everything the players see (Telegram messages, ticket images and the web app) is in Spanish, their language.
diagnose command. Loterías y Apuestas ─┐ ┌─> Telegram group
(fixtures, results, ├─> Bot (Python, GitHub Actions) ─┤ (announcements, images,
prize breakdown) │ │ │ reminders, results, prizes)
ESPN (LaLiga teams, ─┘ ▼ │
live scores) Supabase (PostgreSQL) <───────┴── Web app (GitHub Pages)
players submit their picks
| Component | Technology | Role |
|---|---|---|
| Bot | Python 3.12 on GitHub Actions (bot/) | Reads the official data, computes hits, posts to Telegram |
| Web app | Static HTML + JS on GitHub Pages (web/) | Each player picks their name, enters a PIN and fills in their column |
| Database | Supabase / PostgreSQL (supabase/) | Matchdays, fixtures, picks, reports sent, payments |
| Messaging | Telegram Bot API | Ticket images, reminders, who pays, prizes |
| Data | Loterías y Apuestas del Estado (LAE) | Official fixtures, kickoff times, results, prize breakdown |
| Teams and live scores | ESPN public API | Current LaLiga top-flight teams (league filter) and final scores as soon as each match ends |
| Backup | GitHub Actions (backups/) | Weekly encrypted database backup |
The bot runs every 10 minutes (see Reliable schedule).
Who pays
Pleno al 15 (the 15th match, where each team's goals are predicted: 0, 1, 2 or M = 3+)
Which Quinielas are played
When a new matchday is announced
Overlapping matchdays
Postponements and rescheduling
Prizes
supabase/schema.sql → Run.select set_pin(1::smallint, '....'); (ids 1–5).
Never commit real PINs.select set_family_key(); and copy the value it returns
(it is shown only once; only its hash is stored)./newbot → note the token./setprivacy → your bot → Disable (before adding it to the group), so it can see
who writes and mention people.SUPABASE_URL, SUPABASE_SERVICE_KEY, TELEGRAM_TOKEN, TELEGRAM_CHAT_ID,
FAMILY_KEY (the value from step 1.4), BACKUP_KEY (a long made-up password that encrypts backups; store it elsewhere
too, it cannot be recovered from GitHub)WEB_URL (the GitHub Pages address from step 4). The family key is added
to the link by the bot; keep it a secret, because Actions logs are public.update players set telegram_user_id = 123456789 where name = 'Rosana';web/config.js with the Supabase URL and anon key (public by design).https://<user>.github.io/<repo>/.#k=…, a URL fragment that is never sent to any server); the device then
remembers it. Opened without the key it only shows «Quiniela privada».?demo to the URL. Preselect a player: ?p=5.Actions → Bot → Run workflow → diagnose prints the ESPN team list, the upcoming
matchdays with their 15 fixtures (whether they qualify as LaLiga, and each result marked
LAE or ESPN), the number of finished games ESPN reports and recent prize breakdowns. If something comes back empty, LAE changed its website and bot/lae.py
needs adjusting.
GitHub runs scheduled workflows late when it is busy (hours, in practice), so the bot is started every 10 minutes by cron-job.org (free) through the GitHub API; the workflow's own schedule remains as a fallback.
https://api.github.com/repos/<user>/<repo>/actions/workflows/quiniela.yml/dispatchesAuthorization: Bearer <token>,
Accept: application/vnd.github+json, X-GitHub-Api-Version: 2022-11-28,
body {"ref":"main","inputs":{"command":"tick"}}Supabase's free tier keeps no backups, so every Tuesday the Backup workflow exports
all tables, encrypts them with BACKUP_KEY and commits backups/quiniela.json.enc; git
history keeps every previous version. To restore:
openssl enc -d -aes-256-cbc -pbkdf2 -iter 200000 -in backups/quiniela.json.enc -out backup.json
python -m bot.backup restore backup.json # needs SUPABASE_URL and SUPABASE_SERVICE_KEY
Then, in the SQL Editor: select setval('matchdays_id_seq', (select coalesce(max(id), 1) from matchdays));
Because the bot commits a backup every week, run
git pullbefore pushing your own changes.
-100); update TELEGRAM_CHAT_ID.select set_family_key();, update the
FAMILY_KEY secret and re-send the announcement (below) so the button carries the new key.update matchdays set announced = false where number = 16; then Run workflow → tick.actions/checkout@v5, actions/setup-python@v6
and actions/upload-pages-artifact@v4, and force Node.js 24.supabase/migrations/ holds one-off scripts already applied to the production
database. Fresh installs only need schema.sql..github/workflows/quiniela.yml Bot: schedule and secrets
.github/workflows/web.yml Deploys web/ to GitHub Pages
.github/workflows/backup.yml Weekly encrypted database backup
.github/workflows/tests.yml Runs the simulation on every push
bot/main.py Orchestration: one idempotent run (tick) and the CLI
bot/rules.py Game rules: hits, who pays, Pleno, daily reports, league filter, prizes
bot/lae.py Client for the official lottery data (fixtures, results, prizes)
bot/teams.py LaLiga team list from ESPN and fuzzy name matching
bot/espn.py Live scores from ESPN while the lottery has no results yet
bot/messages.py Every user-facing text (Spanish)
bot/ticket.py Renders the ticket images (Pillow)
bot/db.py Supabase (PostgREST) access
bot/telegram.py Telegram Bot API client
bot/backup.py Database export and restore
web/index.html · web/config.js Betting web app
supabase/schema.sql Database schema, security and functions
supabase/migrations/ One-off scripts applied to the production database
tests/test_simulation.py Offline simulation of whole matchdays
docs/ Full guide (English and Spanish) and README images
backups/ Encrypted database backups
pip install -r requirements.txt
python -m tests.test_simulation output/ # full offline simulation; images and messages land in output/
python -m bot.main tick --dry-run output/ # real Supabase and LAE data, but nothing is sent to Telegram