Skip to main content

A lightweight aiogram-based library for broadcasting Telegram messages.

Project description

aiogram_broadcaster

GitHub License GitHub Actions Workflow Status GitHub last commit Static Badge Static Badge PyPI - Downloads PyPI - Version

aiogram_broadcaster is lightweight aiogram-based library for broadcasting Telegram messages.

Features

Installation

$ pip install aiogram-broadcaster

Creating a mailer and running broadcasting

How to create a mailer and initiate broadcasting.

Usage:

import logging
import sys
from typing import Any

from aiogram import Bot, Dispatcher, Router
from aiogram.types import Message

from aiogram_broadcaster import Broadcaster
from aiogram_broadcaster.contents import MessageSendContent
from aiogram_broadcaster.storage.file import FileMailerStorage

TOKEN = "1234:Abc"
USER_IDS = {78238238, 78378343, 98765431, 12345678}

router = Router(name=__name__)


@router.message()
async def process_any_message(message: Message, broadcaster: Broadcaster) -> Any:
    # Creating content based on the Message
    content = MessageSendContent(message=message)

    mailer = await broadcaster.create_mailer(
        content=content,
        chats=USER_IDS,
        interval=1,
        preserve=True,
        destroy_on_complete=True,
    )

    # The mailer launch method starts mailing to chats as an asyncio task.
    mailer.start()

    await message.reply(text="Run broadcasting...")


def main() -> None:
    logging.basicConfig(level=logging.INFO, stream=sys.stdout)

    bot = Bot(token=TOKEN)
    dispatcher = Dispatcher()
    dispatcher.include_router(router)

    storage = FileMailerStorage()
    broadcaster = Broadcaster(bot, storage=storage)
    broadcaster.setup(dispatcher=dispatcher)

    dispatcher.run_polling(bot)


if __name__ == "__main__":
    main()

Mailer

The Mailer class facilitates the broadcasting of messages to multiple chats in Telegram. It manages the lifecycle of the broadcast process, including starting, stopping, and destroying the broadcast.

Properties

  • id: Unique identifier for the mailer.

  • status: Current mailer status of the mailer (e.g., STARTED, STOPPED, COMPLETED).

  • settings: Configuration settings for the mailer.

  • statistic: Statistic instance containing statistics about the mailer's performance.

  • content: Content to be broadcast.

  • context: Additional context data used during the broadcasting process.

  • bot: aiogram Bot instance used for interacting with the Telegram API.

Methods

  • send(chat_id: int) -> Any: Sends the content to a specific chat identified by chat_id.

  • add_chats(chats: Iterable[int]) -> Set[int]: Adds new chats to the mailer's registry.

  • reset_chats() -> bool: Resets the state of all chats.

  • destroy() -> None: Destroys the mailer instance and cleans up resources.

  • stop() -> None: Stops the broadcasting process.

  • run() -> bool: Initiates the broadcasting process.

  • start() -> None: Starts the broadcasting process in background.

  • wait() -> None: Waits for the broadcasting process to complete.

Usage:

mailer = await broadcaster.create_mailer(content=..., chats=...)
try:
    logging.info("Mailer starting...")
    await mailer.run()
finally:
    logging.info("Mailer shutdown...")
    await mailer.destroy()

Multibot

When using a multibot, it may be necessary to launch many mailings in several bots. For this case, there is a MailerGroup object that stores several mailers and can manage them.

Usage:

from aiogram import Bot

from aiogram_broadcaster import Broadcaster

# List of bots
bots = [Bot(token="1234:Abc"), Bot(token="5678:Vbn")]

broadcaster = Broadcaster()

# Creating a group of mailers based on several bots
mailer_group = await broadcaster.create_mailers(
    *bots,
    content=...,
    chats=...,
)

# Run all mailers in the mailer group
await mailer_group.run()

Event system

The event system empowers you to effectively manage events throughout the broadcast process.

NOTE: EventRouter supports chained nesting, similar to aiogram Router.

Usage:

from aigoram_broadcaster import EventRouter

event = EventRouter(name=__name__)


# Define event handlers


@event.started()
async def mailer_started() -> None:
    """Triggered when the mailer begins its operations."""


@event.stopped()
async def mailer_stopped() -> None:
    """Triggered when the mailer stops its operations."""


@event.completed()
async def mailer_completed() -> None:
    """Triggered when the mailer successfully completes its operations."""


@event.before_sent()
async def mail_before_sent() -> None:
    """
    Triggered before sending content.

    Exclusive parameters for this type of event.
        chat_id (int): ID of the chat.
    """


@event.failed_sent()
async def mail_failed_sent() -> None:
    """
    Triggered when a content fails to send.

    Exclusive parameters for this type of event.
        chat_id (int): ID of the chat.
        error (Exception): Exception raised during sending.
    """


@event.success_sent()
async def mail_successful_sent() -> None:
    """
    Triggered when a mail is successfully sent.

    Exclusive parameters for this type of event:
        chat_id (int): ID of the chat.
        response (Any): Response from the sent mail.
    """


# Include the event instance in the broadcaster
broadcaster.event.include(event)

Placeholders

Placeholders facilitate the insertion of dynamic content within texts, this feature allows for personalized messaging.

NOTE: PlaceholderRouter supports chained nesting, similar to aiogram Router.

Usage:

  • Function-based

from aiogram_broadcaster import PlaceholderRouter

placeholder = PlaceholderRouter(name=__name__)


@placeholder(key="name")
async def get_username(chat_id: int, bot: Bot) -> str:
    """Retrieves the username using the Telegram Bot API."""
    member = await bot.get_chat_member(chat_id=chat_id, user_id=chat_id)
    return member.user.first_name


broadcaster.placeholder.include(placeholder)
  • Class-based

from aiogram_broadcaster import PlaceholderItem


class NamePlaceholder(PlaceholderItem, key="name"):
    async def __call__(self, chat_id: int, bot: Bot) -> str:
        member = await bot.get_chat_member(chat_id=chat_id, user_id=chat_id)
        return member.user.first_name


broadcaster.placeholder.register(NamePlaceholder())
  • Other registration methods

placeholder["name"] = function
placeholder.add(key="key", value="value")
placeholder.attach({"key": "value"}, key="value")

And then

text_content = TextContent(text="Hello, $name!")
photo_content = PhotoContent(photo=..., caption="Photo especially for $name!")

Key-based content

This module provides utilities to create personalized content targeted to specific users or groups based on their language preferences or geographical location, etc.

NOTE: If the default key is not specified, an error will be given if the key is not found.

Usage:

from aiogram.exceptions import TelegramBadRequest

from aiogram_broadcaster.contents import KeyBasedContent, TextContent


class LanguageBasedContent(KeyBasedContent):
    """Content based on the user's language."""

    async def __call__(self, chat_id: int, bot: Bot) -> Optional[str]:
        try:
            member = await bot.get_chat_member(chat_id=chat_id, user_id=chat_id)
        except TelegramBadRequest:
            return None
        else:
            return member.user.language_code


content = LanguageBasedContent(
    # default=TextContent(text="Hello!"),
    uk=TextContent(text="Привіт!"),
    ru=TextContent(text="Привет!"),
)

Lazy content

Allows content to be generated dynamically at the time the message is sent.

Usage:

from secrets import choice
from typing import List

from pydantic import SerializeAsAny

from aiogram_broadcaster.contents import BaseContent, LazyContent, TextContent


class RandomizedContent(LazyContent):
    contents: List[SerializeAsAny[BaseContent]]

    async def __call__(self) -> BaseContent:
        return choice(self.contents)


content = RandomizedContent(
    contents=[
        TextContent(text="Hello!"),
        TextContent(text="Hi!"),
    ],
)
await broadcaster.create_mailer(content=content, chats=...)

Dependency injection

It is used for comprehensive dependency management, used in event system, key-based/lazy content, placeholders and so on.

Usage:

  • Main contextual data

from aiogram_broadcaster import Broadcaster

broadcaster = Broadcaster(key="value")
  • Fetching the dispatcher contextual data

from aiogram import Dispatcher

from aiogram_broadcaster import Broadcaster

dispatcher = Dispatcher()
dispatcher["key"] = "value"

broadcaster = Broadcaster()
broadcaster.setup(dispatcher, fetch_dispatcher_context=True)
  • Contextual data only for mailer

await broadcaster.create_mailer(content=..., chats=..., key=value)
  • Stored contextual data only for mailer

await broadcaster.create_mailer(content=..., chats=..., stored_context={"key": "value"})
  • Event-to-event

@event.completed()
async def transfer_content(mailer: Mailer) -> Dict[str, Any]:
    return {"mailer_content": mailer.content}


@event.completed()
async def mailer_completed(mailer_content: BaseContent) -> None:
    print(mailer_content)

Storages

Storage allow you to save mailer states to external storage.

Usage:

from aiogram_broadcaster import Broadcaster
from aiogram_broadcaster.storage.redis import RedisMailerStorage

# from aiogram_broadcaster.storage.file import FileMailerStorage
# from aiogram_broadcaster.storage.mongodb import MongoDBMailerStorage
# from aiogram_broadcaster.storage.sqlalchemy import SQLAlchemyMailerStorage

# storage = FileMailerStorage()
# storage = MongoDBMailerStorage.from_url(url="mongodb://localhost:27017")
# storage = SQLAlchemyMailerStorage.from_url(url="sqlite+aiosqlite:///database.db")

storage = RedisMailerStorage.from_url(url="redis://localhost:6379")
broadcaster = Broadcaster(storage=storage)

Default mailer settings

The DefaultMailerSettings class defines the default properties for mailers created within the broadcaster. It allows setting various parameters like interval, dynamic_interval, run_on_startup, handle_retry_after, destroy_on_complete, and preserve. These properties provide flexibility and control over the behavior of mailers.

Parameters:

  • interval: The interval (in seconds) between successive message broadcasts. It defaults to 0, indicating immediate broadcasting.

  • dynamic_interval: A boolean flag indicating whether the interval should be adjusted dynamically based on the number of chats. If set to True, the interval will be divided equally among the chats.

  • run_on_startup: A boolean flag indicating whether the mailer should start broadcasting messages automatically on bot startup.

  • handle_retry_after: A boolean flag indicating whether the mailer should handle the TelegramAPIError error automatically.

  • destroy_on_complete: A boolean flag indicating whether the mailer should be destroyed automatically upon completing its operations.

  • preserve: A boolean flag indicating whether the mailer's state should be preserved even after completion. If set to True, the mailer's state will be stored in the specified storage.

Usage:

from aiogram_broadcaster import Broadcaster
from aiogram_broadcaster.mailer import DefaultMailerSettings

default = DefaultMailerSettings(
    interval=60_000,
    dynamic_interval=True,
    run_on_startup=True,
    handle_retry_after=True,
    destroy_on_complete=True,
    preserve=True,
)
broadcaster = Broadcaster(default=default)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aiogram_broadcaster-0.4.6.tar.gz (27.2 kB view details)

Uploaded Source

Built Distribution

aiogram_broadcaster-0.4.6-py3-none-any.whl (46.8 kB view details)

Uploaded Python 3

File details

Details for the file aiogram_broadcaster-0.4.6.tar.gz.

File metadata

  • Download URL: aiogram_broadcaster-0.4.6.tar.gz
  • Upload date:
  • Size: 27.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.12.3

File hashes

Hashes for aiogram_broadcaster-0.4.6.tar.gz
Algorithm Hash digest
SHA256 269ba2ff326dd62db322f30a63ab24297bb4f1a08234d1dd1d2e34008081b35e
MD5 117146a6a7bde8d8a8a73035df550e5e
BLAKE2b-256 d1160f758d3889c387d3a7b98a469209052399c5fdcc7d98d8b151ac84925b0e

See more details on using hashes here.

File details

Details for the file aiogram_broadcaster-0.4.6-py3-none-any.whl.

File metadata

File hashes

Hashes for aiogram_broadcaster-0.4.6-py3-none-any.whl
Algorithm Hash digest
SHA256 ec1e2c257fb402a54f37ece0efdc7dbcd4f1ffd6877fb30e900c07db0e491051
MD5 3372e075220673a8050569a3bd1300fc
BLAKE2b-256 2a5855fb014722034278d100b8b11d5953b19ad71fb95606c17c8449ace1cf7a

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page