From 6560fe011d18367725b942cef6a1a1d19ffe0499 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 20 Jun 2025 02:57:45 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B0=D1=80=D1=83=20=D0=BF=D0=BB=D1=8E?= =?UTF-8?q?=D1=88=D0=B5=D0=BA=20+=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=80=D0=B8=D0=B4=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE | 21 +++++++++ README.md | 97 ++++++++++++++++++++++++++++++--------- example/example.py | 10 +++- example/simple_example.py | 31 +++++++++++++ maxapi/dispatcher.py | 8 +++- maxapi/methods/get_me.py | 2 +- maxapi/types/__init__.py | 2 +- requirements.txt | 5 -- setup.py | 4 ++ 9 files changed, 150 insertions(+), 30 deletions(-) create mode 100644 LICENSE create mode 100644 example/simple_example.py delete mode 100644 requirements.txt diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ea001b6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Твоё Имя + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index f932b16..a944ee2 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,84 @@ -# maxapi +# Асинхронный MAX API -#### Библиотека (like aiogram) для взаимодействия с мессенджером MAX +[![PyPI version](https://img.shields.io/pypi/v/maxapi.svg)](https://pypi.org/project/maxapi/) +[![Python Version](https://img.shields.io/pypi/pyversions/maxapi.svg)](https://pypi.org/project/maxapi/) +[![License](https://img.shields.io/github/license/love-apples/maxapi.svg)](https://love-apples/maxapi/blob/main/LICENSE) -Информация на данный момент: -* Проект тестируется и активно дорабатывается -* На данный момент имеется: - - * Роутеры - * Билдер инлайн клавиатур - * Этакая машина состояний и контекст к нему - * Поллинг и вебхук методы запуска - * Логгирование +--- +## 📦 Установка ```bash -Пример бота описан в example.py -Перед запуском примера установите зависимости: - -pip install maxapi==0.1 - -Запуск бота из папки https://github.com/love-apples/maxapi/tree/main/example: - -python example.py +pip install maxapi ``` +--- -### Контакты -[Группа MAX](https://max.ru/join/IPAok63C3vFqbWTFdutMUtjmrAkGqO56YeAN7iyDfc8) \ No newline at end of file +## 🚀 Быстрый старт + +```python +import asyncio +import logging + +from maxapi import Bot, Dispatcher +from maxapi.types import BotStarted, Command, MessageCreated + +logging.basicConfig(level=logging.INFO) + +bot = Bot('f9LHodD0cOL5NY7All_9xJRh5ZhPw6bRvq_0Adm8-1bZZEHdRy6_ZHDMNVPejUYNZg7Zhty-wKHNv2X2WJBQ') +dp = Dispatcher() + + +@dp.bot_started() +async def bot_started(event: BotStarted): + await event.bot.send_message( + chat_id=event.chat_id, + text='Привет! Отправь мне /start' + ) + + +@dp.message_created(Command('start')) +async def hello(event: MessageCreated): + await event.message.answer(f"Пример чат-бота для MAX 💙") + + +async def main(): + await dp.start_polling(bot) + + +if __name__ == '__main__': + asyncio.run(main()) +``` + +--- + +## 📚 Документация + +В разработке... + +--- + +## 🧩 Возможности + +- ✅ Роутеры +- ✅ Билдер инлайн клавиатур +- ✅ Простая загрузка медиафайлов +- ✅ MagicFilter +- ✅ Внутренние функции моделей +- ✅ Контекстный менеджер +- ✅ Поллинг +- ✅ Вебхук +- ✅ Логгирование + +--- + + +## 💬 Обратная связь и поддержка + +- MAX: [Чат](https://max.ru/join/IPAok63C3vFqbWTFdutMUtjmrAkGqO56YeAN7iyDfc8) +- Telegram: [@loveappless](https://t.me/loveappless) +--- + +## 📄 Лицензия + +Этот проект распространяется под лицензией MIT. См. файл [LICENSE](LICENSE) для подробностей. diff --git a/example/example.py b/example/example.py index 4e46bd7..d7200e7 100644 --- a/example/example.py +++ b/example/example.py @@ -3,7 +3,7 @@ import logging from maxapi import Bot, Dispatcher, F from maxapi.context import MemoryContext, State, StatesGroup -from maxapi.types import Command, MessageCreated, CallbackButton, MessageCallback, BotCommand +from maxapi.types import BotStarted, Command, MessageCreated, CallbackButton, MessageCallback, BotCommand from maxapi.types.input_media import InputMedia from maxapi.utils.inline_keyboard import InlineKeyboardBuilder @@ -36,6 +36,14 @@ async def _(): logging.info('Бот стартовал!') +@dp.bot_started() +async def bot_started(event: BotStarted): + await event.bot.send_message( + chat_id=event.chat_id, + text='Привет! Отправь мне /start' + ) + + @dp.message_created(Command('clear')) async def hello(event: MessageCreated, context: MemoryContext): await context.clear() diff --git a/example/simple_example.py b/example/simple_example.py new file mode 100644 index 0000000..6bfad13 --- /dev/null +++ b/example/simple_example.py @@ -0,0 +1,31 @@ +import asyncio +import logging + +from maxapi import Bot, Dispatcher +from maxapi.types import BotStarted, Command, MessageCreated + +logging.basicConfig(level=logging.INFO) + +bot = Bot('f9LHodD0cOL5NY7All_9xJRh5ZhPw6bRvq_0Adm8-1bZZEHdRy6_ZHDMNVPejUYNZg7Zhty-wKHNv2X2WJBQ') +dp = Dispatcher() + + +@dp.bot_started() +async def bot_started(event: BotStarted): + await event.bot.send_message( + chat_id=event.chat_id, + text='Привет! Отправь мне /start' + ) + + +@dp.message_created(Command('start')) +async def hello(event: MessageCreated): + await event.message.answer(f"Пример чат-бота для MAX 💙") + + +async def main(): + await dp.start_polling(bot) + + +if __name__ == '__main__': + asyncio.run(main()) \ No newline at end of file diff --git a/maxapi/dispatcher.py b/maxapi/dispatcher.py index 0e5dcc4..65246e2 100644 --- a/maxapi/dispatcher.py +++ b/maxapi/dispatcher.py @@ -42,6 +42,10 @@ class Dispatcher: self.user_added = Event(update_type=UpdateType.USER_ADDED, router=self) self.user_removed = Event(update_type=UpdateType.USER_REMOVED, router=self) self.on_started = Event(update_type=UpdateType.ON_STARTED, router=self) + + async def check_me(self): + me = await self.bot.get_me() + logger_dp.info(f'Бот: @{me.username} id={me.user_id}') def include_routers(self, *routers: 'Router'): for router in routers: @@ -97,8 +101,9 @@ class Dispatcher: async def start_polling(self, bot: Bot): self.bot = bot + await self.check_me() - logger_dp.info(f'{len(self.event_handlers)} event handlers started') + logger_dp.info(f'{len(self.event_handlers)} событий на обработку') if self.on_started_func: await self.on_started_func() @@ -130,6 +135,7 @@ class Dispatcher: async def handle_webhook(self, bot: Bot, host: str = 'localhost', port: int = 8080): self.bot = bot + await self.check_me() if self.on_started_func: await self.on_started_func() diff --git a/maxapi/methods/get_me.py b/maxapi/methods/get_me.py index 833e4d5..cf44ccd 100644 --- a/maxapi/methods/get_me.py +++ b/maxapi/methods/get_me.py @@ -20,7 +20,7 @@ class GetMe(BaseConnection): def __init__(self, bot: 'Bot'): self.bot = bot - async def request(self) -> Chats: + async def request(self) -> User: return await super().request( method=HTTPMethod.GET, path=ApiPath.ME, diff --git a/maxapi/types/__init__.py b/maxapi/types/__init__.py index dc0703f..8feacfe 100644 --- a/maxapi/types/__init__.py +++ b/maxapi/types/__init__.py @@ -23,7 +23,7 @@ from ..types.attachments.buttons.request_geo_location_button import RequestGeoLo from ..types.command import Command, BotCommand -from input_media import InputMedia +from .input_media import InputMedia __all__ = [ InputMedia, diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index bfee7d7..0000000 --- a/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -aiohttp==3.11.16 -fastapi==0.115.13 -magic_filter==1.0.12 -pydantic==2.11.7 -uvicorn==0.34.3 diff --git a/setup.py b/setup.py index be8ef83..987b529 100644 --- a/setup.py +++ b/setup.py @@ -16,5 +16,9 @@ setup( 'pydantic==2.11.7', 'uvicorn==0.34.3' ], + license='MIT', + classifiers=[ + 'License :: OSI Approved :: MIT License', + ], python_requires=">=3.10", ) \ No newline at end of file