Discord.py | Pillow ImageFilter

Задача кода: При использовании команды бот берет фотографию пользователя или того, кого пользователь отметил, и добавляет эффект размытия.

Проблема кода: Просмотрев довольно много источников, чтобы выполнить свою задачу, я не смог найти подробного ответа. На мой взгляд, мой код выглядит нормально, но он не работает, но, несмотря на то, ошибка не выводится.

Код:

from PIL import Image, ImageFilter

@Bot.command()
async def blur(ctx, user: discord.Member = None):
    async with ctx.channel.typing():
        await ctx.message.delete()
        url = user.avatar_url
        image = Image.open(url)
        blurred_url = image.filter(ImageFilter.BLUR)
        blurred_url.save("sas.png")
        file = discord.File("sas.png", filename="sas.png")
        await ctx.send(file=file)

Ответы (1 шт):

Автор решения: denisnumb

Возможно ошибка у вас не выводится потому что вы даже не запустили бота)

По крайней мере в конце вашего кода я не вижу строчки Bot.run('TOKEN') или чего-то такого.

Далее к проблемам кода


Первая проблема в том, что у вас по умолчанию, если не указан аргумент user, он принимает значение None. На этот случай нужно добавить условие проверки:

if user is None:
    # значит нужно размыть аватарку автора
else:
    # нужно размыть аватарку указанного пользователя

В противном случае бот будет пытаться размыть аватарку только объекта user, а объект None является пустым и не имеет атрибута avatar_url, соответственно, строка url = user.avatar_url работать не будет.

Об этом и сообщает discord-py:

discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'NoneType' object has no attribute 'avatar_url'

Данная проблема решается одной строкой:

if user is None: user = ctx.author

Если user пустой, то он принимает значение автора сообщения


Следующая проблема заключается в том, что вы пытаетесь считать картинку по ссылке, в то время как библиотеке требуется локальная картинка на вашем компьютере. То есть, bytes-like object, объект, который можно считать по отдельным битам.

discord.ext.commands.errors.CommandInvokeError: Command raised an exception: TypeError: a bytes-like object is required, not 'coroutine'

Для решения этой проблемы достаточно просто скачать указанную картинку - прямая ссылка у вас уже есть:

from urllib.request import Request, urlopen

url = user.avatar_url                                      # ссылка на аватарку пользователя
req = Request(url, headers={'User-Agent': 'Mozilla/5.0'})  # эти параметры нужно передать дискорду, чтобы он думал, что заходит реальный человек - в противном случае не будет доступа
resource = urlopen(req)                                    # открываем картинку
avatar = open("avatar", 'wb')                              # записываем картинку в файл
avatar.write(resource.read())
avatar.close()                                             # закрываем файл

Затем все тоже самое, но открываем уже конкретный файл:

image = Image.open('avatar.png')

Готово! Результат:

введите сюда описание изображения введите сюда описание изображения


Полный код:

import discord
from discord.ext import commands
from PIL import Image, ImageFilter
from urllib.request import Request, urlopen

Bot = commands.Bot(command_prefix='!', intents = discord.Intents.all())

@Bot.command()
async def blur(ctx, user: discord.Member = None):
    if user is None: user = ctx.author
    async with ctx.channel.typing():
        await ctx.message.delete()
        url = user.avatar_url
        req = Request(url, headers={'User-Agent': 'Mozilla/5.0'})
        resource = urlopen(req)
        avatar = open("avatar.png", 'wb')
        avatar.write(resource.read())
        avatar.close()
        image = Image.open('avatar.png')
        blurred_url = image.filter(ImageFilter.BLUR)
        blurred_url.save("sas.png")
        file = discord.File("sas.png", filename="sas.png")
        await ctx.send(file=file)

Bot.run('TOKEN')

Не забудьте указать токен!

→ Ссылка