Skip to content

feat: forward albums as a single grouped batch#12

Merged
awdr74100 merged 1 commit into
mainfrom
feat/album-forwarding
Jul 10, 2026
Merged

feat: forward albums as a single grouped batch#12
awdr74100 merged 1 commit into
mainfrom
feat/album-forwarding

Conversation

@awdr74100

Copy link
Copy Markdown
Owner

Summary

Telegram delivers an album (media group) as separate messages sharing a groupedId, so each part was forwarded individually and reached the target as loose messages. This PR enables mtcute's messageGroupingInterval so a whole album arrives as one message_group update, and forwards the unit in a single forwardMessages call that keeps the grouped layout at the target.

Changes

  • src/client.ts — enable updates.messageGroupingInterval: 250 (upstream-recommended value). Singles are unaffected; an album waits at most 250 ms before forwarding.
  • src/forwarder.ts — route onNewMessage and onMessageGroup through one handler. With grouping enabled, album messages are dispatched only as message_group, so both subscriptions are required to see every message. Matching is wrapped so an unexpected error is logged with message ids instead of silently dropping the unit.
  • src/filter.tsmatchesKeywords now evaluates a whole unit: an album's caption lives on one message but speaks for the entire post (include satisfied by any part; exclude on any part drops the unit).
  • Content types stay per-message — the matching subset is still batched and reaches the target as one (smaller) album.
  • Deletion-race salvage — when an album member is deleted between matching and sending, the batched forward fails with MESSAGE_ID_INVALID for the whole album; the forwarder now re-fetches the batch and retries with the surviving parts instead of losing them. isDeletedMessageError is exported from queue.ts so both layers share one classification.

Performance / behavior notes

  • A 5-part album previously took 5 rate-limited sends (~500 ms+ of spacing, 5 API calls); it is now 1 call — faster overall and lower FloodWait exposure.
  • If an album's parts arrive slower than the buffer window, it splits into two smaller albums at the target — cosmetic, never a lost message.
  • catchUp was deliberately not enabled: mtcute documents it can replay duplicate updates after an unclean shutdown, i.e. double-forwards.

Testing

  • 13 new tests: batched album forwarding, content-type subset, unit-level keyword semantics, deletion-race salvage (partial and total), single-message behavior unchanged, dry-run, and a guard that both dispatcher handlers are registered.
  • pnpm typecheck / pnpm lint / pnpm test (75 passed) / pnpm build / pnpm knip / pnpm format:check all green.
  • Verified live: albums from a monitored channel arrive at the target as a single grouped album.

Telegram delivers an album (media group) as separate messages sharing a
groupedId, so each part was forwarded individually and reached the
target as loose messages. Enable mtcute's messageGroupingInterval so a
whole album arrives as one message_group update, and forward the unit
in a single forwardMessages call that keeps the grouped layout.

- route onNewMessage and onMessageGroup through one handler; with
  grouping enabled album messages are dispatched ONLY as message_group,
  so both subscriptions are required to see every message
- match keywords per unit: an album's caption lives on one message but
  speaks for the whole post (exclude on any part drops the unit)
- keep content-type filtering per message; the matching subset is still
  batched and stays an album at the target
- salvage the surviving parts when an album member is deleted between
  matching and sending, instead of losing the whole batch to
  MESSAGE_ID_INVALID
- singles are unaffected; an album waits at most 250 ms (upstream
  recommendation) and now needs one API call instead of N rate-limited
  sends, finishing sooner than before
@awdr74100 awdr74100 merged commit 5d46365 into main Jul 10, 2026
2 checks passed
@awdr74100 awdr74100 deleted the feat/album-forwarding branch July 10, 2026 17:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant