Skip to content

Instantly share code, notes, and snippets.

@noaione
Last active August 11, 2021 16:34
Show Gist options
  • Save noaione/738ce5ba570b4d27e00f8e69679b0bff to your computer and use it in GitHub Desktop.
Save noaione/738ce5ba570b4d27e00f8e69679b0bff to your computer and use it in GitHub Desktop.
A monkey-patch of a monkey-patch for discord-py-interactions [discord.py commit: 58ca9e9]
"""
A monkeypatch to patch some of the discord-interactions *patched* methods.
Refer: https://github.com/discord-py-interactions/discord-py-interactions/issues/287
This was created using this commit as the original reference:
https://github.com/Rapptz/discord.py/commit/58ca9e99325ac2678a51cd63afd7ae917f14bc8d
---
MIT License
Copyright (c) 2021 noaione
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.
"""
from typing import List, Optional, Sequence
from discord import File, InvalidArgument, components, embeds, message, sticker
from discord.ext import commands
from discord.http import HTTPClient, Route
from discord.mentions import AllowedMentions
__all__ = ["dpy_dslash_send_override", "dpy_send_files", "dpy_send_message"]
def dpy_send_files(
self: HTTPClient,
channel_id,
*,
files: Sequence[File],
content: Optional[str] = None,
tts: bool = False,
embed: Optional[embeds.Embed] = None,
embeds: Optional[List[embeds.Embed]] = None,
nonce: Optional[str] = None,
allowed_mentions: Optional[AllowedMentions] = None,
message_reference: Optional[message.MessageReference] = None,
stickers: Optional[List[sticker.StickerItem]],
components: Optional[List[components.Component]] = None,
):
r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id)
return self.send_multipart_helper(
r,
files=files,
content=content,
tts=tts,
embed=embed,
embeds=embeds,
nonce=nonce,
allowed_mentions=allowed_mentions,
message_reference=message_reference,
stickers=stickers,
components=components,
)
def dpy_send_message(
self: HTTPClient,
channel_id,
content: str,
*,
tts: bool = False,
embed: Optional[embeds.Embed] = None,
embeds: Optional[List[embeds.Embed]] = None,
nonce: Optional[str] = None,
allowed_mentions: Optional[AllowedMentions] = None,
message_reference: Optional[message.MessageReference] = None,
stickers: Optional[List[sticker.StickerItem]] = None,
components: Optional[List[components.Component]] = None,
):
r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id)
payload = {}
if content:
payload["content"] = content
if tts:
payload["tts"] = True
if embed:
payload["embeds"] = [embed]
if embeds:
payload["embeds"] = embeds
if nonce:
payload["nonce"] = nonce
if allowed_mentions:
payload["allowed_mentions"] = allowed_mentions
if message_reference:
payload["message_reference"] = message_reference
if components:
payload["components"] = components
if stickers:
payload["sticker_ids"] = stickers
return self.request(r, json=payload)
async def dpy_dslash_send(
self,
content: str = None,
*,
tts=False,
embed=None,
embeds=None,
file=None,
files=None,
components=None,
stickers=None,
delete_after=None,
nonce=None,
allowed_mentions=None,
reference=None,
mention_author=None,
view=None,
):
"""|coro|
Sends a message to the destination with the content given.
The content must be a type that can convert to a string through ``str(content)``.
If the content is set to ``None`` (the default), then the ``embed`` parameter must
be provided.
To upload a single file, the ``file`` parameter should be used with a
single :class:`~discord.File` object. To upload multiple files, the ``files``
parameter should be used with a :class:`list` of :class:`~discord.File` objects.
**Specifying both parameters will lead to an exception**.
To upload a single embed, the ``embed`` parameter should be used with a
single :class:`~discord.Embed` object. To upload multiple embeds, the ``embeds``
parameter should be used with a :class:`list` of :class:`~discord.Embed` objects.
**Specifying both parameters will lead to an exception**.
Parameters
------------
content: Optional[:class:`str`]
The content of the message to send.
tts: :class:`bool`
Indicates if the message should be sent using text-to-speech.
embed: :class:`~discord.Embed`
The rich embed for the content.
file: :class:`~discord.File`
The file to upload.
files: List[:class:`~discord.File`]
A list of files to upload. Must be a maximum of 10.
nonce: :class:`int`
The nonce to use for sending this message. If the message was successfully sent,
then the message will have a nonce with this value.
delete_after: :class:`float`
If provided, the number of seconds to wait in the background
before deleting the message we just sent. If the deletion fails,
then it is silently ignored.
allowed_mentions: :class:`~discord.AllowedMentions`
Controls the mentions being processed in this message. If this is
passed, then the object is merged with :attr:`~discord.Client.allowed_mentions`.
The merging behaviour only overrides attributes that have been explicitly passed
to the object, otherwise it uses the attributes set in :attr:`~discord.Client.allowed_mentions`.
If no object is passed at all then the defaults given by :attr:`~discord.Client.allowed_mentions`
are used instead.
.. versionadded:: 1.4
reference: Union[:class:`~discord.Message`, :class:`~discord.MessageReference`, :class:`~discord.PartialMessage`]
A reference to the :class:`~discord.Message` to which you are replying, this can be created using
:meth:`~discord.Message.to_reference` or passed directly as a :class:`~discord.Message`. You can control
whether this mentions the author of the referenced message using the :attr:`~discord.AllowedMentions.replied_user`
attribute of ``allowed_mentions`` or by setting ``mention_author``.
.. versionadded:: 1.6
mention_author: Optional[:class:`bool`]
If set, overrides the :attr:`~discord.AllowedMentions.replied_user` attribute of ``allowed_mentions``.
.. versionadded:: 1.6
view: :class:`discord.ui.View`
A Discord UI View to add to the message.
embeds: List[:class:`~discord.Embed`]
A list of embeds to upload. Must be a maximum of 10.
.. versionadded:: 2.0
stickers: Sequence[Union[:class:`~discord.GuildSticker`, :class:`~discord.StickerItem`]]
A list of stickers to upload. Must be a maximum of 3.
.. versionadded:: 2.0
Raises
--------
~discord.HTTPException
Sending the message failed.
~discord.Forbidden
You do not have the proper permissions to send the message.
~discord.InvalidArgument
The ``files`` list is not of the appropriate size,
you specified both ``file`` and ``files``,
or you specified both ``embed`` and ``embeds``,
or the ``reference`` object is not a :class:`~discord.Message`,
:class:`~discord.MessageReference` or :class:`~discord.PartialMessage`.
Returns
---------
:class:`~discord.Message`
The message that was sent.
""" # noqa: E501
channel = await self._get_channel()
state = self._state
content = str(content) if content is not None else None
if embed is not None and embeds is not None:
raise InvalidArgument("cannot pass both embed and embeds parameter to send()")
if embed is not None:
embed = embed.to_dict()
elif embeds is not None:
if len(embeds) > 10:
raise InvalidArgument("embeds parameter must be a list of up to 10 elements")
embeds = [embed.to_dict() for embed in embeds]
if stickers is not None:
stickers = [sticker.id for sticker in stickers]
if allowed_mentions is not None:
if state.allowed_mentions is not None:
allowed_mentions = state.allowed_mentions.merge(allowed_mentions).to_dict()
else:
allowed_mentions = allowed_mentions.to_dict()
else:
allowed_mentions = state.allowed_mentions and state.allowed_mentions.to_dict()
if mention_author is not None:
allowed_mentions = allowed_mentions or AllowedMentions().to_dict()
allowed_mentions["replied_user"] = bool(mention_author)
if reference is not None:
try:
reference = reference.to_message_reference_dict()
except AttributeError:
raise InvalidArgument(
"reference parameter must be Message, MessageReference, or PartialMessage"
) from None
extended_components = []
if components is not None:
extended_components.extend(components)
if view:
if not hasattr(view, "__discord_ui_view__"):
raise InvalidArgument(f"view parameter must be View not {view.__class__!r}")
view_component = view.to_components()
extended_components.extend(view_component)
# else:
# components = None
if len(extended_components) < 1:
extended_components = None
if file is not None and files is not None:
raise InvalidArgument("cannot pass both file and files parameter to send()")
if file is not None:
if not isinstance(file, File):
raise InvalidArgument("file parameter must be File")
try:
data = await state.http.send_files(
channel.id,
files=[file],
allowed_mentions=allowed_mentions,
content=content,
tts=tts,
embed=embed,
embeds=embeds,
nonce=nonce,
message_reference=reference,
stickers=stickers,
components=extended_components,
)
finally:
file.close()
elif files is not None:
if len(files) > 10:
raise InvalidArgument("files parameter must be a list of up to 10 elements")
elif not all(isinstance(file, File) for file in files):
raise InvalidArgument("files parameter must be a list of File")
try:
data = await state.http.send_files(
channel.id,
files=files,
content=content,
tts=tts,
embed=embed,
embeds=embeds,
nonce=nonce,
allowed_mentions=allowed_mentions,
message_reference=reference,
stickers=stickers,
components=extended_components,
)
finally:
for f in files:
f.close()
else:
data = await state.http.send_message(
channel.id,
content,
tts=tts,
embed=embed,
embeds=embeds,
nonce=nonce,
allowed_mentions=allowed_mentions,
message_reference=reference,
stickers=stickers,
components=extended_components,
)
ret = state.create_message(channel=channel, data=data)
if view:
state.store_view(view, ret.id)
if delete_after is not None:
await ret.delete(delay=delete_after)
return ret
async def dpy_dslash_send_override(context_or_channel, *args, **kwargs):
if isinstance(context_or_channel, commands.Context):
channel = context_or_channel.channel
else:
channel = context_or_channel
return await dpy_dslash_send(channel, *args, **kwargs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment