Because not all beers are created equal.
SCLU converts any alcoholic beverage to a universal unit — how many Coors Lights is this thing?
SCLU = (volume_ml × ABV_percent) / (355 × 4.2)
| Reference | Volume | ABV | SCLU |
|---|---|---|---|
| Coors Light (standard) | 355ml (12oz) | 4.2% | 1.00 |
| Coors Light Banquet | 355ml (12oz) | 5.0% | 1.19 |
The bot outputs two values:
SCLU₄.₂— relative to standard Coors Light (4.2%)SCLU₅.₀— relative to Coors Light Banquet (5.0%)
| Drink | Volume | ABV | SCLU₄.₂ | SCLU₅.₀ |
|---|---|---|---|---|
| Coors Light | 355ml | 4.2% | 1.00 | 0.84 |
| Bud Light 16oz | 473ml | 4.2% | 1.33 | 1.12 |
| IPA 12oz | 355ml | 7.0% | 1.67 | 1.40 |
| Wine 750ml | 750ml | 13.0% | 7.37 | 6.19 |
| Handle of vodka 1.75L | 1750ml | 40.0% | 94.08 | 78.99 |
- 📸 Barcode scanning — upload a photo of the barcode, bot looks it up automatically
- 🔍 Product lookup — searches Open Food Facts and UPC Item DB
- 🔤 OCR fallback — if barcode scan fails, reads the label text
- ✏️ Manual mode —
!sclu 16oz 5.5%when photo isn't available - ⚡ Auto-scan channels — configure channels where any image gets scanned automatically
git clone https://github.com/christmas-island/sclu
cd sclu
pip install -r requirements.txtNote:
pyzbarrequires the ZBar system library.
- macOS:
brew install zbar- Ubuntu/Debian:
apt install libzbar0- Windows: included in the wheel
Note:
pytesseractrequires Tesseract OCR (optional, for label fallback):
- macOS:
brew install tesseract- Ubuntu/Debian:
apt install tesseract-ocr
cp .env.example .env
# Edit .env and set DISCORD_TOKEN- Go to discord.com/developers/applications
- Click New Application → give it a name (e.g. "SCLU Bot") → Create
- Go to Bot in the left sidebar
- Click Reset Token → copy it → paste into
DISCORD_TOKENin your.env - Under Privileged Gateway Intents, enable:
- ✅ Message Content Intent (required to read image attachments)
- ✅ Server Members Intent (optional, for future features)
- Click Save Changes
Go to OAuth2 → URL Generator in the left sidebar and configure:
Scopes:
- ✅
bot - ✅
applications.commands
Bot Permissions:
- ✅ Read Messages / View Channels
- ✅ Send Messages
- ✅ Embed Links
- ✅ Attach Files
- ✅ Read Message History
- ✅ Use Slash Commands
Copy the generated URL and open it in your browser to add the bot to any server where you have Manage Server permissions.
Quick invite URL template (replace YOUR_CLIENT_ID with your app's Client ID from the OAuth2 page):
https://discord.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&scope=bot+applications.commands&permissions=274877975552
Finding your Client ID: Go to your application → General Information → copy the Application ID.
Permissions integer
274877975552encodes: Read Messages, Send Messages, Embed Links, Attach Files, Read Message History, Use Slash Commands. Generate your own at discordapi.com/permissions.html if you need to customize.
To have the bot automatically SCLU any image dropped in specific channels (no !sclu command needed), add channel IDs to your .env:
# Comma-separated Discord channel IDs
AUTOSCAN_CHANNELS=123456789012345678,987654321098765432To find a channel ID: right-click the channel in Discord → Copy Channel ID (requires Developer Mode — enable it under User Settings → Advanced).
python bot.py- Upload a photo of the barcode or label in Discord
- Type
!scluin the same message
Or configure an auto-scan channel and just drop the photo — no command needed.
!sclu 12oz 4.2%
!sclu 16oz 5.5%
!sclu 473ml 7.0%
/sclu image:<attach photo>
/sclu volume:16oz abv:5.5
!sclu help
All deployment methods require
DISCORD_TOKENto be set. If you use auto-scan channels,AUTOSCAN_CHANNELSmust also be set. See.env.examplefor the full list of env vars.
The easiest way to run SCLU:
cp .env.example .env
# Edit .env and set DISCORD_TOKEN (and optionally AUTOSCAN_CHANNELS)
docker compose up -dThis builds the image and starts the bot with automatic restarts. To rebuild after pulling updates:
docker compose up -d --buildOr run without Compose:
docker build -t sclu .
docker run -d --env-file .env --restart unless-stopped scluflyctl launch # creates fly.toml — pick a region, say No to databases
flyctl secrets set DISCORD_TOKEN=your-token-here
flyctl secrets set AUTOSCAN_CHANNELS=channel-id-1,channel-id-2 # optional
flyctl deployScale to one machine (bots don't need redundancy):
flyctl scale count 1- Click Deploy on Railway (or connect your fork)
- Set environment variables in the Railway dashboard:
DISCORD_TOKEN(required)AUTOSCAN_CHANNELS(optional)
- Railway auto-deploys on push
After cloning, installing deps, and creating your .env:
# /etc/systemd/system/sclu-bot.service
[Unit]
Description=SCLU Discord Bot
After=network.target
[Service]
Type=simple
User=sclu
WorkingDirectory=/opt/sclu
EnvironmentFile=/opt/sclu/.env
ExecStart=/opt/sclu/venv/bin/python bot.py
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now sclu-botSee DESIGN.md for the full design document including:
- Data flow diagrams
- Barcode lookup strategy
- OCR fallback approach
- ABV mode handling
Issues and PRs welcome. See open issues for planned features.
MIT