使用aiogram处理媒体组中的文件



我需要一个可持续的方法来处理媒体组中包装的文件。

我的函数handle_files正在等待媒体文件。当用户上传媒体文件时,它会经过一系列不同的检查。如果它通过了所有测试(大小限制、格式限制(,则下载并处理媒体文件。

它看起来像这样:

async def handle_files(message: types.Message, state: FSMContext):
user_data = await state.get_data()
locale = user_data['locale']
list_of_files = user_data['list_of_files']
try:
file = message.document
file_name = file['file_name']
except Exception as e:
await message.answer('Error while downloading file')
return None
file_name = unidecode(file_name)
file_size = file['file_size']
if file_size >= 20971520:
await message.answer('File is too big')
return None
invalid_format, formats = check_invalid_format(file_name, function)
if invalid_format:
await message.answer(file_name + 'has unsupported format. Supported formats: ' + ', '.join(formats))
return None
output_folder = os.path.join('temp', str(message.from_user.id))
if not os.path.exists(output_folder):
os.makedirs(output_folder, exist_ok=True)
file_path = os.path.join(output_folder, file_name)
await file.download(destination_file=file_path)
list_of_files.append(file_path)
await state.update_data(list_of_files=list_of_files)
await message.answer('Added files: '.format('n'.join(list_of_files)))

使用单独的文件看起来不错。下载文件后,用户会得到一个列表添加的文件一个接一个。

但问题是,当用户上传媒体组中的文件时,一个文件会覆盖另一个文件。看起来是那样的。

因此,只有一个文件附加到列表list_of_files中,这使我无法处理这两个文件。

我试图通过再次初始化user_data字典来解决问题:

...
await file.download(destination_file=file_path)
user_data = await state.get_data()
list_of_files = user_data['list_of_files']
list_of_files.append(file_path)
await state.update_data(list_of_files=list_of_files)
...

它解决了我问题的一部分,但这种解决方案并不优雅,据说也不太可持续。消息重复。

我需要在上传媒体组后,用户会收到一条包含该媒体组中所有文件列表的消息

我想这里的问题与异步有关。但我已经花了很多时间,但还没有找到解决方案。正在寻求您的帮助。

检查此链接。在这里您可以找到中间件,它将返回来自媒体组的消息列表,然后您可以使用for loop来处理它们。

import asyncio
from typing import List, Union
from aiogram import Bot, Dispatcher, executor, types
from aiogram.dispatcher.handler import CancelHandler
from aiogram.dispatcher.middlewares import BaseMiddleware
bot = Bot(token="TOKEN_HERE")  # Place your token here
dp = Dispatcher(bot)

class AlbumMiddleware(BaseMiddleware):
"""This middleware is for capturing media groups."""
album_data: dict = {}
def __init__(self, latency: Union[int, float] = 0.01):
"""
You can provide custom latency to make sure
albums are handled properly in highload.
"""
self.latency = latency
super().__init__()
async def on_process_message(self, message: types.Message, data: dict):
if not message.media_group_id:
return
try:
self.album_data[message.media_group_id].append(message)
raise CancelHandler()  # Tell aiogram to cancel handler for this group element
except KeyError:
self.album_data[message.media_group_id] = [message]
await asyncio.sleep(self.latency)
message.conf["is_last"] = True
data["album"] = self.album_data[message.media_group_id]
async def on_post_process_message(self, message: types.Message, result: dict, data: dict):
"""Clean up after handling our album."""
if message.media_group_id and message.conf.get("is_last"):
del self.album_data[message.media_group_id]

@dp.message_handler(is_media_group=True, content_types=types.ContentType.ANY)
async def handle_albums(message: types.Message, album: List[types.Message]):
"""This handler will receive a complete album of any type."""
media_group = types.MediaGroup()
for obj in album:
if obj.photo:
file_id = obj.photo[-1].file_id
else:
file_id = obj[obj.content_type].file_id
try:
# We can also add a caption to each file by specifying `"caption": "text"`
media_group.attach({"media": file_id, "type": obj.content_type})
except ValueError:
return await message.answer("This type of album is not supported by aiogram.")
await message.answer_media_group(media_group)

if __name__ == "__main__":
dp.middleware.setup(AlbumMiddleware())
executor.start_polling(dp, skip_updates=True)

最新更新