Rustico is a lightning-fast, asynchronous bot written in Rust that automatically monitors Anime News Network (ANN) and AniList for the latest anime news and episodes, pushing beautiful and formatted updates directly to your Discord server via Webhooks.
- AniList Integration: Automatically fetches newly aired episodes within the last 24 hours
- Anime News Network (ANN) Integration: Parses multiple RSS feeds for the latest breaking anime news
- Multiple Discord Webhooks: Send to multiple Discord servers simultaneously
- Persistent State: Automatically saves seen articles/episodes in YAML format to prevent duplicates
- Advanced HTML Parsing: Intelligent HTML entity decoding and tag stripping
- Discord Components V2: Beautiful formatted messages with colors, thumbnails, and rich components
- Fully Asynchronous: Built on
tokioandreqwestwith non-blocking I/O and connection pooling - Cron Scheduler: Runs automatically at a configured interval (default: every 15 minutes)
- Health Check API: REST API for monitoring bot status (
/health,/metrics,/stats) with concurrency limiting - Configurable Message Templates: Customize formatting via YAML configuration files
- Demo Mode: On first run, sends sample items to verify Discord webhook is working
- Graceful Shutdown: Clean shutdown of all components (scheduler, API server, state persistence)
- Auto-Pruning State: Automatically limits stored seen items to prevent unbounded memory growth
- Rust 1.80+ (uses
std::sync::LazyLock) - (Optional)
lldfor faster builds:sudo apt install lld
git clone https://github.com/gonzyui/rustico.git
cd rusticoCreate a .env file in the root of the project. Use example.env as a template:
cp example.env .envEdit .env with your settings:
# Required
DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/WEBHOOK"
# Multiple webhooks (comma-separated)
# DISCORD_WEBHOOK_URL="https://..., https://..."
# Optional - RSS Feeds (comma-separated)
ANN_RSS_URLS="https://www.animenewsnetwork.com/all/rss.xml"
# Optional - AniList
ANILIST_ENABLED=true
# Optional - Scheduling
CHECK_INTERVAL_MINUTES=15
DEMO_MODE_ITEM_LIMIT=3
DELAY_BETWEEN_MESSAGES_MS=800
# Optional - Health API
API_ENABLED=true
API_HOST=127.0.0.1
API_PORT=3000
# Optional - Logging
RUST_LOG=info
# Optional - Message templates
MESSAGES_CONFIG_FILE=messages.yamlEdit config/messages.yaml to customize Discord message formatting:
colors:
ann: 0x1E90FF # Dodger Blue for ANN
anilist: 0x8A2BE2 # Blue Violet for AniList
formatting:
ann:
title_prefix: "π°"
truncate_description: 400
anilist:
title_prefix: "π¬"
truncate_description: 300
show_score: true# Debug build
cargo run
# Release build (optimized)
cargo run --releaseπ‘ Tip: Rustico ships with a
.cargo/config.tomlthat useslldas the linker for ~30-50% faster link times. Install it withsudo apt install lld.
# Build the image
docker build -t rustico .
# Run the container
docker run -d \
--name rustico-bot \
-e DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/your_id/your_token" \
-e ANILIST_ENABLED=true \
-e CHECK_INTERVAL_MINUTES=15 \
-v rustico-data:/app/data \
rustico
# View logs
docker logs -f rustico-botThe Docker image includes a built-in HEALTHCHECK that automatically monitors the bot via the /health endpoint.
Rustico exposes a REST API for monitoring (default: http://127.0.0.1:3000).
Endpoints are protected by a concurrency limiter (max 50 simultaneous requests).
curl http://127.0.0.1:3000/health | jqResponse:
{
"status": "π’ healthy",
"version": "0.4.0",
"uptime_seconds": 3600,
"stats": {
"articles_sent": 5,
"episodes_sent": 3,
"errors": 0,
"seen_articles": 50,
"seen_episodes": 15,
"last_check": "2026-05-29T10:30:00Z"
}
}curl http://127.0.0.1:3000/metrics | jq
curl http://127.0.0.1:3000/stats | jqRustico automatically saves and loads state from data/rustico_state.yaml:
seen_ann:
- "guid1"
- "guid2"
seen_anilist:
- 12345
- 67890
initialized: true
stats:
total_articles_sent: 15
total_episodes_sent: 8
total_errors: 0
last_check: "2026-05-29T10:30:00Z"This file is:
- Automatically created on first run
- Updated after each check cycle using async I/O (non-blocking)
- Preserved on restart to avoid re-sending old content
- Auto-pruned: ANN entries are capped at 1000, AniList at 500 to prevent unbounded growth
- Human-readable YAML format
Rustico validates all configuration at startup:
β
Discord webhook URLs must be valid
β
At least one data source (ANN or AniList) must be enabled
β
Check interval must be >= 1 minute
β
Port numbers must be valid
Invalid configurations will show clear error messages.
First run - Demo Mode:
π Starting Rustico v0.4.0
π Configuration:
Webhooks: 1 webhook(s) configured
ANN RSS: 1 feed(s)
AniList: enabled
API: enabled
Interval: 15 min
Delay between messages: 800 ms
β±οΈ Executing initial pass...
β
Webhook avatar configured from assets/logo.png
π First run β sending up to 3 articles as demo
π€ [ANN] Sending: "New Attack on Titan Season 5 Announced"
π€ [AniList] Sending: "Jujutsu Kaisen Season 2 EP20"
β
Initial pass completed β state initialized
β° Cron configured: '0 */15 * * * *'
π Health API listening on http://127.0.0.1:3000
β
Scheduler started β press Ctrl+C to stop
Subsequent runs:
- Checks every 15 minutes
- Only sends new articles/episodes
- State is automatically saved
- Graceful shutdown on Ctrl+C (scheduler, API, and state are all cleanly stopped)
- Tokio β Async runtime
- Reqwest β HTTP client with connection pooling
- Serde β Serialization/Deserialization
- Serde YML β YAML parsing
- RSS β RSS parsing
- Tokio-cron-scheduler β Task scheduling
- Scraper β HTML parsing
- Axum β Web framework for health API
- Tower β Middleware (concurrency limiting)
- Chrono β Date/time handling
- Anyhow β Error handling
cargo testcargo clippy -- -D warningscargo fmtRustico includes a .cargo/config.toml that configures lld as the linker. To benefit from it:
# Install lld (Debian/Ubuntu)
sudo apt install lld
# Or use mold (even faster)
# Edit .cargo/config.toml and replace lld with moldYou can also profile build times with:
cargo build --release --timings- Check
.envfile β ensureDISCORD_WEBHOOK_URLis valid - Check logs β run with
RUST_LOG=debug - Test health API:
curl http://127.0.0.1:3000/health
- Verify webhook hasn't expired (Discord webhooks can expire after 7 days of inactivity)
- Check webhook permissions in Discord server settings
- Check firewall/network β make sure bot can reach Discord API
- Delete
data/rustico_state.yamlto reset and start fresh in demo mode - File is created automatically on first run in the
data/directory
- Ensure
API_ENABLED=true(default) - Check that port 3000 is not blocked inside the container
- Inspect with
docker inspect --format='{{json .State.Health}}' rustico-bot
This project is licensed under the MIT License β see the LICENSE file for details.
Contributions are welcome! Please ensure your code passes all checks before submitting:
cargo fmt --check && cargo clippy -- -D warnings && cargo testFeel free to open issues and pull requests on GitHub.
