Skip to content

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
Hold "Alt" / "Option" to enable pan & zoom

On each scheduled run:

  1. Authenticates to the Transparent Classroom API with stored credentials
  2. Fetches all posts for the configured child and school
  3. Skips posts already recorded in the local cache (incremental — no re-downloads)
  4. Downloads new photos and embeds EXIF/IPTC metadata: GPS coordinates, timestamp, and observation description
  5. 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:

✅ Photo Sync Complete

📸 New photos downloaded: 3
📋 Total posts scanned: 42

Sending 3 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 jpegjpg and tifftif 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