tc-photo-grabber¶
tc-photo-grabber is a Telegram bot that automatically downloads photos from Transparent Classroom and delivers them to a Telegram chat. It runs on a cron schedule during school hours and sends each new photo directly to Telegram with its classroom observation description embedded as a caption.
Without this bot, photos from Transparent Classroom accumulate on the platform and require manual login to view or download. tc-photo-grabber checks for new photos throughout the school day and pushes them directly to Telegram as files (preserving original resolution) or compressed images, configurable per-chat.
How It Works¶
graph LR
TC[Transparent Classroom] -->|1. poll for new posts| Bot[tc-photo-grabber]
Bot -->|2. download new photos + embed metadata| Disk[(PVC)]
Bot -->|3. send summary + photos| Telegram[Telegram Chat]
Telegram -->|4. commands| Bot
On each scheduled run:
- Authenticates to the Transparent Classroom API with stored credentials
- Fetches all posts for the configured child and school
- Skips posts already recorded in the local cache (incremental — no re-downloads)
- Downloads new photos and embeds EXIF/IPTC metadata: GPS coordinates, timestamp, and observation description
- Sends a summary message to Telegram followed by the new photos (up to 10 per run; remaining count is noted)
Cache
A JSON cache in the mounted PVC records which posts have already been downloaded. If the cache is empty or the page is empty, the bot re-fetches from Transparent Classroom before concluding there's nothing new — preventing a stale empty cache from permanently hiding photos.
Notifications¶
Download Summary¶
Sent after each run that finds new photos:
Followed by each photo as a file or compressed image with the observation description as caption. If more than 10 photos are downloaded in a single run, only the first 10 are sent and a message notes how many were skipped.
No notification is sent when there are no new photos.
Error Notifications¶
Errors during a scheduled run are sent to Telegram with exponential backoff to avoid spam:
| Consecutive errors | Notification sent |
|---|---|
| 1st | Always |
| Same error, 2nd+ | After 1h, 2h, 4h, 8h, … (max 24h) |
| Different error | Always (resets backoff) |
| Success | Resets counter, no message |
Telegram Commands¶
| Command | Description |
|---|---|
/sendfile |
Send new photos as files (original quality) |
/sendphoto |
Send new photos as compressed images |
/status |
Show current send mode and scheduler state |
/pause |
Pause the scheduler — runs are skipped until resumed |
/resume |
Resume the scheduler |
/photos |
Open a calendar picker to view locally stored photos for any date |
/resync |
Open a calendar picker to delete and re-download photos for a date |
Settings (/sendfile / /sendphoto) persist across restarts in cache/telegram_settings.json.
The bot only responds to commands from the configured TELEGRAM_CHAT_ID — messages from other chats are silently ignored.
Calendar Picker¶
Both /photos and /resync open an inline calendar. Days that have locally stored photos are marked with 📷.
/photos sends all stored photos for the selected date to the chat.
/resync deletes local photos for the selected date and triggers a fresh download from Transparent Classroom. Useful when a photo was corrupted or metadata needs to be re-embedded.
Deployment¶
-
Namespace
bots -
Source
gitea.hdhomelab.com/cicd/tc-photo-grabber -
Config
flux/apps/noah/bots/tc-photo-grabber/ -
Schedule
*/10 8-18 * * 1-5— every 10 min, Mon–Fri, 8am–6pm ET
The bot has no ingress or port — it makes outbound requests only (to Transparent Classroom and the Telegram API). Two PVCs are mounted: one for the photo archive and one for the cache.
Implementation Notes¶
File Extension Mismatch¶
Transparent Classroom serves photos from a CDN where the URL extension does not always match the actual file format. A URL ending in .jpg may return PNG bytes, for example.
After downloading, the bot uses filetype to detect the real format from the file's magic bytes and compares it against the URL extension (normalizing jpeg↔jpg and tiff↔tif as equivalent). If they differ, the correct extension is used for the saved filename instead.
Duplicate download guard
If the corrected filename already exists on disk, the photo is skipped rather than overwritten. This means a photo downloaded once with the wrong extension will not be re-downloaded after the fix — use /resync to force a clean re-download for a specific date.
Stale Empty Cache¶
The Transparent Classroom API returns an empty list when a page has no posts. If such a response is cached, subsequent runs would read the empty cache and conclude there is nothing to download — permanently hiding any photos added later.
When the bot reads a cached page and finds an empty list, it treats it as a cache miss: the file is deleted and the API is queried fresh before deciding there is nothing new.
Configuration¶
Environment Variables¶
| Env Var | Source | Value |
|---|---|---|
TC_EMAIL |
Vault secret | Transparent Classroom account email |
TC_PASSWORD |
Vault secret | Transparent Classroom account password |
SCHOOL |
Vault secret | Transparent Classroom school ID |
CHILD |
Vault secret | Transparent Classroom child ID |
SCHOOL_LAT |
Vault secret | School latitude (embedded in photo GPS metadata) |
SCHOOL_LNG |
Vault secret | School longitude (embedded in photo GPS metadata) |
SCHOOL_KEYWORDS |
ConfigMap | Keywords embedded in photo IPTC metadata |
TELEGRAM_BOT_TOKEN |
Vault secret | Telegram bot token from @BotFather |
TELEGRAM_CHAT_ID |
Vault secret | Chat ID to send photos and notifications to |
CRON_EXPRESSION |
ConfigMap | */10 8-18 * * 1-5 |
TZ |
ConfigMap | America/New_York |
RUN_IMMEDIATELY |
ConfigMap | true — runs once at startup before waiting for the first cron tick |
OUTPUT_DIR |
ConfigMap | /photo |
CACHE_DIR |
ConfigMap | /cache |
Vault Secrets¶
Create at path tc-photo-grabber in Vault:
| Key | Description |
|---|---|
email |
Transparent Classroom account email |
password |
Transparent Classroom account password |
school |
School ID — visible in the Transparent Classroom URL |
child |
Child ID — visible in the Transparent Classroom URL |
school-lat |
School latitude |
school-lng |
School longitude |
telegram-token |
Telegram bot token — @BotFather /newbot |
telegram-chat-id |
Chat ID of the family Telegram group |