arg
у вас не имеет стандартного значения. Аргументы без стандартного значения считаются обязательными аргументами.@bot.command() # pass_context НЕ существует в текущей версии discord.py: https://discordpy.readthedocs.io/en/v1.4.1/migrating.html#context-changes
async def help(ctx, arg = None):
emb = discord.Embed(title = 'Помощь', colour = 0x2e2d2d)
if arg == 'poll':
emb.add_field(name = f"{ctx.prefix}poll", value = f"Использовать:\nder poll (название голосования), (первый параметр), (второй параметр), (и так до 9 раз)\nПример создания голосования:\npoll test, 1, 2")
await ctx.send(embed = emb)
else:
emb.add_field(name = f"{ctx.prefix}poll", value = f"Создание голосовния.")
await ctx.send(embed = emb)
from typing import Optional
@commands.command()
async def cmd(ctx, arg: Optional[str]): ...
guild
не определена. В данном случае Вы, скорее всего, хотите получить её из контекста - ctx.guildGuild.voice_channels
и Guild.text_channels
- "списки" (list) с каналами соответствующего типа. Списки не имеют атрибута set_permissions
. Данный атрибут есть у каналов в списке. Для установки прав для каждого канала нужно данный список итерировать. @client.command()
async def set_permissions(сtx, role: discord.Role):
for textchannel in ctx.guild.text_channels:
await alltext.set_permissions(
role,
read_messages=True,
send_messages=True,
manage_channels=True,
manage_roles=True,
)
for voicechannel in ctx.guild.voice_channels:
await allvoice.set_permissions(
role, connect=True, manage_channels=True, manage_roles=True
)
await ctx.send(
f"{ctx.author.mention}, вы успешно установили {role.mention} права доступа во всех текстовых/голосовых каналах"
)
Замена стандартного `on_message` предотвращает выполнение любых дополнительных команд. Для исправления этого добавьте добавьте строку `bot.process_commands(message)` в конце вашего `on_message`, например:
@bot.event
async def on_message(message):
# делаем что-нибудь тут
await bot.process_commands(message)
if message.guild.id != 282480459897027773:
return
Message.reactions
. discord.Reaction
- тип возвращаемых объектов в reactions.@bot.command()
async def start(ctx):
mess = await channel.send('Набор в игру')
await asyncio.sleep(10)
mess = await ctx.channel.fetch_message(mess.id)
if yes_react := discord.utils.get(mess.reactions, emoji=ctx.guild.get_emoji(471483388532742130)):
async for user in yes_react.users:
print(str(user)) # выведет всех пользователей поставивших реакцию в консоль
bot.event
используется только для событий.@bot.command()
или @commands.command()
в модулях.from datetime import date
import discord
from datetime import date
@bot.command()
async def bdays4(ctx):
cur_year = date.today().year
bdays = {
"Kenshi": date(day=12, month=8, year=1997),
"Broody": date(day=11, month=11, year=1009),
"Melanie": date(day=22, month=1, year=1941),
"Blueface Baby": date(day=18, month=8, year=2020),
}
for bday_name, date in bdays.items():
bday = date.update(year=cur_year)
if bday == date.today():
await ctx.send(
embed=discord.Embed(
description=f"Happy birthday {bday_name}",
colour=discord.Color.green(),
)
)
on_error_command(context, error)
: https://discordpy.readthedocs.io/en/v1.4.1/ext/com...from discord.ext import commands
from contextlib import suppress
class MyBot(commands.Bot):
async def on_command_error(self, ctx, error):
if isinstance(error, commands.BadArgument):
await ctx.send(f"Неверный аргумент: {error.message}")
else:
await super().on_command_error(ctx, error) # вызывает изначальное поведение on_error_message
bot = MyBot(command_prefix="!")
from discord.ext import commands
from contextlib import suppress
bot = commands.Bot(command_prefix="!")
@bot.event
async def on_command_error(ctx, error):
if isinstance(error, commands.BadArgument):
await ctx.send(f"Неверный аргумент: {error.message}")
.post
, рискну предположить что Disc
- экземпляр объекта типа aiohttp.ClientSession
. Он не знает что такое дискорд.import discord
import aiohttp
session = aiohttp.ClientSession()
# Discord поддерживает только markdown для форматирования. html-теги (<i> и прочие) будут отображаться напрямую
embed_obj = discord.Embed(
title="*Заголовок*", colour=0x21D3CD, url="https://example.com"
) # Цвет в HEX более читаемый
embed_obj.set_image(url="https://via.placeholder.com/140x100")
embed_obj.set_thumbnail(url="https://via.placeholder.com/140x100")
embed_obj.set_footer(text="*Текст*", icon_url="https://via.placeholder.com/140x100")
embed_obj.set_author(
name="*Текст*",
url="https://example.com",
icon_url="https://via.placeholder.com/140x100",
)
embed_obj.add_field(
name="*Текст*", value="\N{Zero Width Space}"
) # Значение поля не может быть пустым, такой embed дискорд отклонит. Используем визуально пустой символ для этого.
await session.post(
"https://discord.com/api/webhooks/%WEBHOOK_ID%/%WEBHOOK_TOKEN",
json={"embeds": [embed_obj.to_dict()]},
)
import aiohttp
import discord
session = aiohttp.ClientSession()
webhook = discord.Webhook.from_url(
"https://discord.com/api/webhooks/%WEBHOOK_ID%/%WEBHOOK_TOKEN",
adapter=discord.AsyncWebhookAdapter(session),
)
embed_obj = ...
await webhook.send(embed=embed_obj)
on_guild_join
передаётся аргумент guild
, который и является сервером, к которому присоединился бот.import logging
@listener # client.event / commands.Cog.listener / etc...
async def on_guild_join(guild):
logging.info(f"Joined guild {guild.name} ({guild.id})"
def func(a, b: int = 0, c)
- не работает, так как a
, b
и c
являются порядковым аргументом.def func(a, b: int = 0, c = 0)
- работаетfrom typing import Optional
...
@commands.command()
async def cmd(ctx, member: Optional[discord.Member], count: int): ...
delete_after
функции send
.@client.command(aliases = ['очистить', 'клеар', 'clr' ,'клр'])
@commands.has_permissions(administrator = True)
async def clear( ctx, amount : int):
await ctx.message.delete()
await ctx.channel.purge(limit = amount)
await ctx.send(embed = discord.Embed(description = f':white_check_mark: удалено {amount} сообщений(я)'), delete_after=5)
discord.utils.get
вы получаете канал того сервера, в котором было написано сообщение.GLOBAL_CHAT = 'глобальный-чат' # PEP8: Названия констант пишутся капсом
@client.event
async def on_message(message):
channel = discord.utils.get(message.guild.text_channels, name=GLOBAL_CHAT)
if message.author.id == client.user.id:
return # return предотвратит выполнение следующего кода
if message.channel.id != channel.id:
return
await message.delete() # удаляем сообщение один раз
for guild in client.guilds:
if channel := discord.utils.get(guild.text_channels, name=GLOBAL_CHAT):
# py3.8: walrus operator ("моржовый" оператор)
# равносильно следующему:
# channel = discord.utils.get(guild.text_channels, name=GLOBAL_CHAT)
# if channel: ...
try:
await channel.send('**{0.author}:** {0.content}'.format(message))
except discord.Forbidden:
print(f"Невозможно отправить сообщение на сервер {guild.name}: Недостаточно прав")
except discord.HTTPException as e:
print(f"Невозможно отправить сообщение на сервер {guild.name}: {e}")
bot.remove_command("help")
@bot.group(invoke_without_command=True)
async def help(ctx, ...):
... # вручную построенная/собирающая команда help.
@help.command()
async def islam(ctx, ...):
... # подкоманда help
@bot.command()
async def islam(ctx):
"""Описание команды"""
...
@bot.command(
help="Данный текст будет использоваться в полноразмерной помощи (help islam)",
brief="Данный текст будет отображаться в help рядом с командой",
usage="Данный текст будет отображаться вместо автоматического построенного текста для аргументов (таких как <arg> [arg] и т.д.)"
)
async def islam(ctx):
...
@bot.command()
async def report(ctx, user: discord.Membmer, *, reason: str): # первый kwarg используется как "собирающий" аргумент
# https://discordpy.readthedocs.io/en/v1.3.4/ext/commands/commands.html#keyword-only-arguments
...
[p]report User#0000 Нарушение правила 42
from asyncio import TimeoutError as AsyncTimeoutError
@bot.command()
async def report(ctx):
...
try:
member = await bot.wait_for("message", check=lambda m: m.author == ctx.author, timeout = 60) # Базовая проверка - будет ловить сообщения от пользователя запустившего команду везде.
except AsyncTimeoutError:
await ctx.send("Вы уснули, я ушёл")
return
# На данный момент переменная "member" является лишь строкой, и не факт что это реальный пользователь
# Используем конвертер для перевода из строки в пользователя
# https://discordpy.readthedocs.io/en/v1.3.4/ext/commands/api.html#discord.ext.commands.MemberConverter
try:
member = commands.MemberConverter().convert(ctx, member)
except commands.BadArgument:
await ctx.send("Это не пользователь, кого вы пытаетесь ~~на...~~ обмануть")
return
# и тоже самое для причины
import this
:Simple is better than complex.
sync_to_async
и прочих.database_sync_to_async
вовсе не используется в данном коде.Errors should never pass silently.
Unless explicitly silenced.
import asyncio
import os
from functools import partial
import discord
from discord.ext import commands
from allauth.socialaccount.models import SocialAccount
from main.models import Game, Purchase, Key
bot = commands.Bot()
@bot.event
async def on_ready():
print('We have logged in as {0.user}'.format(bot))
@commands.command()
async def hello(ctx):
game = (await bot.loop.run_in_executor(None, Game.objects.all))[0]
await ctx.send(game.name)
@bot.event
async def on_member_join(member):
allAccounts = await bot.loop.run_in_executor(None, SocialAccount.objects.all)
for acc in allAccounts:
if acc.extra_data['id'] == str(member.id):
account_id = acc.extra_data['id']
purchases = await bot.loop.run_in_executor(None, partial(Key.objects.filter, user__id=account_id))
keys = [await bot.loop.run_in_executor(None, partial(Key.objects.filter, purchase__id=purchase.id)) for purchase in purchases]
for key in keys:
role = discord.utils.get(member.guild.roles, id=key.cheat.ds_role_id)
print(str(key.cheat.ds_role_id))
await member.add_roles(role)
break
bot.run(os.environ.get('DS_BOT_TOKEN'))
Counter
из стандартной библиотеки collections
: https://docs.python.org/3/library/collections.html...from collections import Counter
...
msg_count = Counter()
@client.event
async def on_message(msg):
if msg.author == client.user:
return
global msg_count
msg_count[msg.author.id] += 1
print(f"Message by {msg.author}: {msg.content}")
...
self
у событий есть только в модулях (cogs). И представляет собой сам модуль if Y > N: ...
выполняется только один раз - при запуске файла. Необходимо сделать чтобы оно либо менялось при обновлении (получении/удалении реакции), либо непосредственно перед выводом результата pass_context
не существует в текущей версии discord.py. Контекст передаётся в функцию команды первым аргументом всегда (за исключением момента с нахождением команды в вышеупомянутом "модуле") voting_message = None
@Bot.command()
@commands.has_permissions(administrator=True)
async def startvote(ctx):
embed = discord.Embed(...) # embed goes here
voting_message = await ctx.send(embed=embed)
@Bot.command()
@commands.has_permissions(administrator=True)
async def endvote(ctx):
msg = await bot.get_channel(voting_message.channel.id).fetch_message(voting_message.id)
y = discord.utils.get(msg.reactions, emoji="\N{WHITE HEAVY CHECK MARK}").count
n = discord.utils.get(msg.reactions, emoji="\N{CROSS MARK}").count
if y>n:
result = "Принято"
elif y==n:
result = "Отказано (да = нет)"
else:
result = "Отказано"
emb = discord.Embed(title=f'Окончено голосование.', description = 'Результат: ' + result, colour=discord.Color.purple())
return await ctx.send(embed=emb) # **Возвращаем** сообщение после отправки.
y, n = 0, 0