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(),
)
)
from asyncio import sleep
@commands.command()
async def test(self, ctx):
embed = discord.Embed(title="No")
msg = await ctx.send(embed=embed)
embed.description = "Well, actually, yes"
await sleep(5)
await msg.edit(embed=embed)
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})"
on_member_join(member)
<@Bot.event
async def on_member_join(member):
if role := member.guild.get_role(418187634689139935):
await member.add_roles(role)
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): ...
bot.wait_for("reaction_add")
: https://discordpy.readthedocs.io/en/v1.3.4/api.htm...@bot.command(ctx):
async def test(ctx):
accept_decline = await ctx.send('Test')
await accept_decline.add_reaction('one')
try:
reaction = await bot.wait_for("reaction_add", timeout=60, check = lambda r, u: r=='one' )
except asyncio.TimeoutError:
await channel.send("\N{THUMBS DOWN SIGN}")
else:
await channel.send("\N{THUMBS UP SIGN}")
bot.get_channel
в качестве аргумента принимает ID в типе int. По умолчанию все аргументы передаваемые в команду парсером, передаются туда как str, если не указан иной тип. В вашем случае эта функция никогда не вернёт канал.@bot.command()
async def news(ctx, channel: discord.TextChannel, *, text): # используем kwargs для отсутствия необходимости написания ковычек: https://discordpy.readthedocs.io/en/stable/ext/commands/commands.html#keyword-only-arguments
emb= discord.Embed(title='Новость!!!',description=f'{text}', timestamp=ctx.message.created_at)
await channel.send(embed=emb)
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}")
id
.@bot.event
async def on_voice_state_update(member, before, after):
clients = [969338428647912064, 424184503818564866, 424184503818564866]
role = bot.get_role(240688302893711904)
if not before.channel and after.channel:
if member.id in clients:
await member.add_roles(role)
elif before.channel and not after.channel:
await member.remove_roles(role)
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
# и тоже самое для причины
@client.event
async def on_member_update(before, after):
if before.roles != after.roles:
channel = client.get_channel(729733881129074768)
emb = discord.Embed(description = f'**Обновление ролей пользователя - {before.mention}**', colour = discord.Color.red())
emb.add_field(name = '**Роли до**', value = ", ".join([r.mention for r in before.roles]))
emb.add_field(name = '**Роли после**', value = ", ".join([r.mention for r in after.roles]))
async for event in before.guild.audit_logs(limit=1, action=discord.AuditLogAction.member_role_update): # https://discordpy.readthedocs.io/en/v1.3.4/api.html#discord.AuditLogAction.member_role_update
# event: AuditLogEntry — https://discordpy.readthedocs.io/en/v1.3.4/api.html#discord.AuditLogEntry
if getattr(event.target, "id", None) != before.id:
# изменение ролей пользователя прошло без записи в логах аудита, или в лог аудита попала другая запись перед выполнением текущего участка кода
continue
emb.add_field(name="Изменённые роли", value = ", ".join([getattr(r, "mention", r.id) for r in event.before.roles or event.after.roles])) # event.before, event.after: AuditLogDiff — https://discordpy.readthedocs.io/en/v1.3.4/api.html#discord.AuditLogDiff
emb.add_field(name="Модератор", value = event.user)
break
await channel.send(embed = emb)
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'))