Underground 2 Revived
Play Need for Speed: Underground 2 (2004) in Chrome and Firefox with WebGPU graphics, Web Audio, up to 120 fps widescreen, controller support, free roam and Online races with friends. Fan project, not
翻译准备中
Telegram bot that finds Dead by Daylight promo codes with LLM web search, lets admins moderate them and broadcasts approved codes to subscribers. ⭐
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗Telegram bot that collects Dead by Daylight promo codes via LLM web search (OpenAI or OpenRouter), lets an admin approve them, and sends each approved code once to everyone who pressed /start.
Try it: @fogwatch_bot.
Needs a bot token from @BotFather and an OpenAI or
OpenRouter API key. Put the variables from Configuration
into .env (template: .env.example) next to compose.yaml:
services:
fogwatch:
image: ghcr.io/evlmaistrenko/fogwatch:latest
env_file: .env
volumes:
- ./data:/data
restart: unless-stopped
The container runs as uid 65532 (distroless nonroot), so create data/
with that owner first, or Docker creates it as root and the bot can't write:
mkdir -p data && sudo chown 65532:65532 data
docker compose up -d # start
docker compose pull && docker compose up -d # update
The image is also on Docker Hub as evlmaistrenko/fogwatch (linux/amd64,
linux/arm64). latest is the last release; pin X.Y or X.Y.Z to control
updates; main follows every push to main. The version is logged at start.
Admins get their extended command menu after pressing /start in the bot; no restart needed.
Environment variables (see .env.example):
| Variable | Default | |
|---|---|---|
TELEGRAM_TOKEN | — | bot token, required |
ADMIN_IDS | — | admin Telegram user ids, comma-separated (@userinfobot) |
OPENAI_API_KEY | — | required |
OPENAI_BASE_URL | https://api.openai.com/v1 | any Responses API, e.g. https://openrouter.ai/api/v1 |
OPENAI_MODEL | gpt-5-mini | openai/gpt-5-mini on OpenRouter |
TZ | UTC | "today" for code expiry, search schedule, log timestamps |
/start help + recent codes, one message each (without an expiry
date: added within the last 7 days)
/codes all active codes, one message with pages and copy buttons:
expiring soonest, then recent, then older without a date;
admins see the whole database with status filter buttons
(🎁 active, ⏳ pending, 🚫 rejected, ⌛ expired, 🗑 removed)
/lang ru / en / same as Telegram (default)
Admin (shown in the admin's menu):
/pending resend moderation cards
/add CODE [YYYY-MM-DD] [reward] publish + broadcast now;
"ru text | en text" sets both languages
/del CODE tombstone: search won't re-add it
/fetch search now
/stats users (new in 7 days, language),
codes by status and source
TZ), never on start.
A check is skipped if a search (scheduled or /fetch) succeeded less than
3 hours ago, so normally the bot searches every 6 hours and retries 3 hours
after a failure. The time of the last success survives restarts. The
prompt lists the 200 most recent known codes (any status) so the model looks
for new ones only.OPENAI_BASE_URL. Web search uses OpenAI's
web_search tool, or openrouter:web_search when the URL is OpenRouter
(any model; Exa fallback for models without native search, billed extra).[A-Z0-9-]{4,30}, have a source
URL, and not be past its expiry. Codes without a known expiry stay active
until an admin removes them, but /start only sends the ones added within
the last 7 days; /codes lists them all.Users and codes live in SQLite at data/db.sqlite (relative to the working
dir; ./data in the Compose example). The schema is created and extended
automatically at start. WAL mode: back up all db.sqlite* files with the bot
stopped, or use sqlite3 data/db.sqlite ".backup backup.sqlite".
Setup, commands, project rules, CI and releases: CONTRIBUTING.md.