Skip to content

Latest commit

Β 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

idstickbot β€” Sticker & Custom Emoji ID Bot

Telegram bot that instantly replies with file_id for stickers and custom_emoji_id for Premium emoji.
Tap-to-copy, no fluff β€” built for developers, sticker makers, and bot builders.

Python aiogram License Platform Telegram


✨ Features

Feature What you get
Sticker IDs file_id, file_unique_id, set_name, emoji, custom_emoji_id (if type custom_emoji)
Premium Emoji IDs custom_emoji_id + default emoji for any message / caption containing Premium emoji
Copy-friendly Every ID in its own <code> block β€” one tap to copy on mobile/desktop
Smart parsing Correct UTF-16 handling for surrogate pairs, deduplication, per-field entity resolution
Reply Keyboard Persistent keyboard β€” 🎨 Sticker Guide, ✨ Emoji Guide, ℹ️ About, 🌐 Language, ❌ Hide
Multilingual πŸ‡¬πŸ‡§ English Β· πŸ‡·πŸ‡Ί Русский Β· πŸ‡ΊπŸ‡Ώ OΚ»zbekcha β€” per-user, /lang or 🌐 button
Silent by design No spam β€” custom emoji handler silent, plain text gently guided only in PM
Production ready Rotating logs, graceful shutdown, HTML escaping, /help + BotFather menu

Supported sticker kinds: Static Β· Animated (.tgs) Β· Video (.webm) Β· Custom Emoji


πŸš€ Quick Start

# 1. Clone
git clone https://github.com/algorithco/idstickbot.git
cd idstickbot

# 2. Environment
python -m venv .venv
# Windows
.venv\Scripts\activate
# Linux / macOS
source .venv/bin/activate

pip install -r requirements.txt

# 3. Configure
cp .env.example .env
# then edit .env and set your token from @BotFather

# 4. Run
python bot.py

Open Telegram β†’ talk to your bot β†’ send a sticker or a Premium emoji.


βš™οΈ Configuration

.env

# Get a token from @BotFather β†’ /newbot
BOT_TOKEN=123456789:AAA-your-botfather-token-here

# Optional β€” drop queued updates on restart (default: false)
DROP_PENDING_UPDATES=false
Variable Required Default Description
BOT_TOKEN βœ… β€” Bot token from @BotFather
DROP_PENDING_UPDATES β€” false true = discard updates received while offline

Token is read with (os.getenv("BOT_TOKEN") or "").strip() β€” whitespace is ignored and missing token exits with a clear message.


πŸ’¬ Usage

Reply Keyboard

After /start a persistent keyboard appears:

Button Action
🎨 Sticker Guide Step-by-step how to get file_id / file_unique_id / set_name
✨ Emoji Guide How Telegram Premium emoji works + how to send one to get custom_emoji_id
ℹ️ About About + inline buttons β†’ GitHub / Share bot
🌐 Language Inline selector β€” πŸ‡¬πŸ‡§ / πŸ‡·πŸ‡Ί / πŸ‡ΊπŸ‡Ώ (also /lang)

The keyboard is resize_keyboard + is_persistent with placeholder Send a sticker or Premium emoji….

Commands

Command Description
/start Show help + reply keyboard (auto-detects Telegram language)
/help Alias for /start
/lang Choose language β€” πŸ‡¬πŸ‡§ English / πŸ‡·πŸ‡Ί Русский / πŸ‡ΊπŸ‡Ώ OΚ»zbekcha

Sticker

Send any sticker β€” the bot replies threaded (new design):

🎬 Video sticker
file_id:
<code>CAACAgIAAxkBAAEf...</code>

file_unique_id:
<code>AgADr...</code>

Set: <code>MySetByBot</code>
Emoji: πŸ˜€
Tap any code block to copy πŸ“‹
  • Includes file_unique_id (stable across bots) and set_name to fetch the whole set via getStickerSet.
  • Works with forwarded stickers and all types.

Premium Custom Emoji

Send any message or caption containing Premium emoji (including photo captions):

✨ Custom emoji IDs β€” tap to copy:
πŸ˜€ <code>5368324170671202286</code>
❀️ <code>5431449001532594346</code>
  • Deduplicates same custom_emoji_id in one message (first-seen order).
  • Correctly resolves text vs. caption offsets β€” even with emoji like πŸ³οΈβ€πŸŒˆ or πŸ˜€ that use surrogate pairs.

Plain Text

In private chats, other text gets a gentle hint with the keyboard; groups stay silent to avoid spam. Buttons are handled before the fallback.

🌐 Languages

Bot speaks English, Русский, OΚ»zbekcha β€” per-user stored in user_langs.json:

  • Auto-detect from Telegram language_code on first /start
  • Change anytime via 🌐 Language button or /lang β†’ inline selector
  • Keyboard, help, guides, sticker headers and footers all localize
  • BotFather menu is localized too (set_my_commands with language_code)

πŸ“ Project Structure

idstickbot/
β”œβ”€β”€ bot.py              # Main bot β€” i18n, keyboards, handlers, UTF-16 parsing
β”œβ”€β”€ requirements.txt    # aiogram, python-dotenv
β”œβ”€β”€ .env.example        # Template for BOT_TOKEN
β”œβ”€β”€ .env                # Your real token (gitignored)
β”œβ”€β”€ run.bat             # Windows auto-restart loop
β”œβ”€β”€ bot.log             # Rotating log (5 MB Γ— 5, gitignored)
β”œβ”€β”€ restart.log         # Restart history (gitignored)
└── user_langs.json     # Per-user language prefs (gitignored)

🧠 How It Works

UTF-16 entity handling

Telegram sends offset/length in UTF-16 code units, not Python characters. A naive text[offset:offset+length] breaks on πŸ˜€ (2 units) or ZWJ sequences.

raw = text.encode("utf-16-le")
units = len(raw) // 2
chunk = raw[offset*2 : (offset+length)*2]
char = chunk.decode("utf-16-le")

Bounds are checked before slicing, and text vs. caption entities are resolved against their own field to avoid offset mismatch.

Why <code> blocks?

Telegram clients make <code>...</code> tappable. One ID per block = one tap copies exactly that ID β€” no selection dance.

f"<code>{html.escape(file_id)}</code>"

All user-visible strings are html.escaped for ParseMode.HTML safety.


☁️ Deploy for Free β€” Render + Supabase (Recommended for 24/7)

You asked for free hosting β€” this uses Render (web service, free) + Supabase (Postgres, free). I don’t read your .env; you set the keys yourself on Render/Supabase dashboards.

Service What it does Free tier
Render Hosts bot.py 24/7 (polling + /health keep-alive) 750 h/mo, sleeps after 15 min idle β€” we add health endpoint + optional pinger
Supabase Stores user_langs (user_id β†’ en/ru/uz) so language survives Render restarts 500 MB DB, 2 projects, pauses after 7 days idle β€” one click resume

1. Supabase β€” create project & table (2 min)

  1. Go to supabase.com β†’ New Project (no credit card), pick region (e.g. Frankfurtclosest to Render) β†’ wait ~2 min
  2. In Supabase: SQL Editor β†’ New query β†’ paste supabase_setup.sql (in repo) β†’ Run
    create table public.user_langs (user_id bigint primary key, lang text check (lang in ('en','ru','uz')), updated_at timestamptz default now());
    alter table public.user_langs enable row level security;
    -- then policies & grants (see file)
  3. Project Settings β†’ API β†’ Copy: Project URL (SUPABASE_URL) and anon public or publishable key (SUPABASE_KEY)
    • Keep the service_role key secret β€” not needed for bot

2. Render β€” deploy bot (3 min)

  1. Push this repo to GitHub (already algorithco/idstickbot)
  2. dashboard.render.com β†’ New β†’ Web Service β†’ Connect algorithco/idstickbot
  3. Settings:
    • Name: idstickbot Β· Region: Frankfurt Β· Branch: main Β· Runtime: Python Β· Plan: Free
    • Build Command: pip install -r requirements.txt
    • Start Command: python bot.py
    • Health Check Path: /health (bot exposes / and /health via aiohttp when PORT is set)
  4. Environment β†’ Add:
    BOT_TOKEN=… (from @BotFather, you already have)
    SUPABASE_URL=https://YOUR_PROJECT.supabase.co
    SUPABASE_KEY=YOUR_ANON_OR_PUBLISHABLE_KEY
    # optional: DROP_PENDING_UPDATES=false
    
    Render injects PORT automatically (e.g. 10000). Locally you can leave it empty β€” bot just polls.
  5. Create Web Service β†’ Deploy. Watch logs: Health server listening on 0.0.0.0:10000 + Run polling for bot @idstickrobot

Why health server? Render free web services sleep after 15 min without inbound HTTP. A polling bot makes no inbound requests, so it would sleep. This bot starts a tiny aiohttp server on PORT (/ and /health) so Render sees it as healthy. For 100% no-sleep on free, also add a pinger (e.g. cron-job.org β†’ https://YOUR_RENDER_URL/health every 14 min) or use render.yaml (included) which sets healthCheckPath: /health.

3. render.yaml β€” Infrastructure as Code

Repo includes render.yaml so Render can auto-create the service from code:

services:
  - type: web
    name: idstickbot
    env: python
    region: frankfurt
    plan: free
    buildCommand: pip install -r requirements.txt
    startCommand: python bot.py
    healthCheckPath: /health
    envVars:
      - key: BOT_TOKEN
        sync: false
      - key: SUPABASE_URL
        sync: false
      - key: SUPABASE_KEY
        sync: false

In Render: New β†’ Blueprint β†’ Connect repo β†’ Apply β€” then set the 3 env vars.

4. How language storage works

  • If SUPABASE_URL + SUPABASE_KEY are set β†’ bot.py uses Supabase user_langs table (upsert on user_id). Works on Render’s ephemeral filesystem.
  • If not set β†’ falls back to local user_langs.json (fine for Windows/Linux). You can run locally without Supabase.

Test locally without Supabase:

pip install -r requirements.txt
python bot.py  # uses user_langs.json

Test with Supabase locally:

# .env
SUPABASE_URL=https://xxx.supabase.co
SUPABASE_KEY=eyJ...
python bot.py

No credentials are read by the assistant β€” you paste them only in Render dashboard and your local .env (gitignored).


πŸ–₯️ Local Deployment (Windows / Linux)

Windows β€” run.bat (recommended)

run.bat loops forever and logs restarts:

@echo off
cd /d "%~dp0"
:loop
echo [%date% %time%] Starting bot...>> restart.log
".venv\Scripts\python.exe" bot.py
echo [%date% %time%] Bot exited code %errorlevel% >> restart.log
timeout /t 5 /nobreak >nul
goto loop

Manual start (hidden):

Start-Process -FilePath ".\run.bat" -WindowStyle Hidden
Get-Content bot.log -Tail 20

Auto-start at logon (no admin needed):

Already configured via:

  • Registry: HKCU\Software\Microsoft\Windows\CurrentVersion\Run β†’ IDStickBot
  • Startup shortcut: %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\IDStickBot.lnk

Scheduled Task (admin, survives reboot before logon):

# Run as Administrator
$A = New-ScheduledTaskAction -Execute "C:\path\to\idstickbot\run.bat" -WorkingDirectory "C:\path\to\idstickbot"
$T = @((New-ScheduledTaskTrigger -AtStartup),(New-ScheduledTaskTrigger -AtLogOn))
$S = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -ExecutionTimeLimit 0 -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)
$P = New-ScheduledTaskPrincipal -UserId "$env:USERDOMAIN\$env:USERNAME" -LogonType S4U -RunLevel Highest
Register-ScheduledTask -TaskName IDStickBot -Description "idstickbot polling" -Action $A -Trigger $T -Settings $S -Principal $P -Force

Linux / macOS β€” systemd

# /etc/systemd/system/idstickbot.service
[Unit]
Description=idstickbot
After=network.target

[Service]
WorkingDirectory=/opt/idstickbot
ExecStart=/opt/idstickbot/.venv/bin/python bot.py
Restart=always
RestartSec=5
EnvironmentFile=/opt/idstickbot/.env

[Install]
WantedBy=multi-user.target
sudo systemctl enable --now idstickbot
journalctl -u idstickbot -f

Docker (optional)

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY bot.py .env.example ./
CMD ["python", "bot.py"]

πŸ“ Logs

  • File: bot.log via RotatingFileHandler β€” 5 MB Γ— 5 (bot.log, bot.log.1 …), UTF-8, also mirrored to console.
  • Format: %(asctime)s %(levelname)-8s %(name)s - %(message)s
  • Restart history: restart.log (only when using run.bat)
  • Both are .gitignored.
  • Log level INFO β€” every handled update is logged by aiogram.dispatcher.

Tail logs:

Get-Content bot.log -Tail 50 -Wait
Get-Content restart.log -Tail 20

πŸ› οΈ Development

# Lint / type check (optional)
pip install ruff mypy
ruff check bot.py
mypy bot.py

# Quick smoke test
python -m py_compile bot.py
python -c "import bot; print(bot.extract_custom_emojis)"

Environment: Python 3.12, aiogram 3.30, python-dotenv 1.2.3
Pin exact versions for reproducibility: pip freeze > requirements.lock


πŸ”’ Security Notes

  • Never commit .env β€” .gitignore covers .env, .env.*, *.env (.env.example is the only exception).
  • OneDrive / cloud sync: If the project lives under OneDrive\Desktop, .env is synced to the cloud. Consider moving to C:\Projects\... or excluding .env from sync, and rotate the token via @BotFather β†’ /mybots β†’ API Token β†’ Revoke if exposed.
  • All IDs are escaped before sending with ParseMode.HTML.

🀝 Contributing

PRs welcome β€” keep the scope tight (sticker / emoji IDs). For larger features open an issue first.

  1. Fork & create a branch
  2. python -m py_compile bot.py must pass
  3. Commit with a clear message and push

πŸ“„ License

MIT β€” do what you want, just keep the notice.


Made with ❀️ for Telegram bot developers
@idstickrobot Β· algorithco/idstickbot

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages