@yaebal/media-group

collect telegram album updates into a single handler call. telegram delivers each photo or video in an album as a separate update sharing a media_group_id; this plugin debounces them and fires your handler once with all parts.

install

shell
pnpm add @yaebal/media-group

registration

pass the handler and optional options directly to mediaGroup(), then install the result with bot.install().

bot.ts
import { Bot } from "@yaebal/core";
import { mediaGroup } from "@yaebal/media-group";

const bot = new Bot(token);

bot.install(
  mediaGroup(
    (ctx, messages) => {
      console.log("album received:", messages.length, "parts");
      // messages[0] is the first update that arrived for this album
    },
    { delayMs: 200 }, // optional — defaults to 200 ms
  ),
);

api

exportkinddescription
mediaGroupfunction(handler: MediaGroupHandler, options?: MediaGroupOptions) => Plugin
MediaGroupHandlertype alias(ctx: Context, messages: Message[]) => unknown | Promise<unknown>
MediaGroupOptionsinterfacesee options table.

MediaGroupOptions

fieldtypedefaultdescription
delayMsnumber200how long to wait after the last album part arrives before firing the handler. each new part resets the debounce timer.

example — save an album

save-album.ts
bot.install(
  mediaGroup(async (ctx, messages) => {
    for (const msg of messages) {
      const photo = msg.photo?.[msg.photo.length - 1];
      if (photo) {
        const url = await ctx.files.fileLink(photo.file_id);
        await db.savePhoto(url);
      }
    }
    await ctx.reply(`saved ${messages.length} photos`);
  }),
);
album messages are consumed. updates with a media_group_id never reach other handlers — the plugin intercepts them entirely. messages without a media_group_id are passed through normally. multiple concurrent albums are tracked independently by their media_group_id. the ctx passed to the handler is the context of the first part that arrived.