Browse Source

Add support for guild banners

Document banner attribute of Guild and Invite

Update discord/utils.py

Co-Authored-By: SnowyLuma <[email protected]>
pull/1967/head
SnowyLuma 6 years ago
committed by Rapptz
parent
commit
42a7c4f7e5
  1. 65
      discord/guild.py
  2. 2
      discord/http.py
  3. 26
      discord/invite.py
  4. 4
      discord/utils.py

65
discord/guild.py

@ -95,6 +95,8 @@ class Guild(Hashable):
all be None. It is best to not do anything with the guild if it is unavailable.
Check the :func:`on_guild_unavailable` and :func:`on_guild_available` events.
banner: Optional[:class:`str`]
The guild's banner.
mfa_level: :class:`int`
Indicates the guild's two factor authorisation level. If this value is 0 then
the guild does not require 2FA for their administrative members. If the value is
@ -119,7 +121,7 @@ class Guild(Hashable):
"""
__slots__ = ('afk_timeout', 'afk_channel', '_members', '_channels', 'icon',
'name', 'id', 'unavailable', 'name', 'region', '_state',
'name', 'id', 'unavailable', 'banner', 'region', '_state',
'_default_role', '_roles', '_member_count', '_large',
'owner_id', 'mfa_level', 'emojis', 'features',
'verification_level', 'explicit_content_filter', 'splash',
@ -211,6 +213,7 @@ class Guild(Hashable):
self.explicit_content_filter = try_enum(ContentFilter, guild.get('explicit_content_filter', 0))
self.afk_timeout = guild.get('afk_timeout')
self.icon = guild.get('icon')
self.banner = guild.get('banner')
self.unavailable = guild.get('unavailable', False)
self.id = int(guild['id'])
self._roles = {}
@ -409,7 +412,7 @@ class Guild(Hashable):
"""Returns a friendly URL version of the guild's icon. Returns an empty string if it has no icon.
The format must be one of 'webp', 'jpeg', 'jpg', or 'png'. The
size must be a power of 2 between 16 and 2048.
size must be a power of 2 between 16 and 4096.
Parameters
-----------
@ -429,7 +432,7 @@ class Guild(Hashable):
Bad image format passed to ``format`` or invalid ``size``.
"""
if not valid_icon_size(size):
raise InvalidArgument("size must be a power of 2 between 16 and 2048")
raise InvalidArgument("size must be a power of 2 between 16 and 4096")
if format not in VALID_ICON_FORMATS:
raise InvalidArgument("format must be one of {}".format(VALID_ICON_FORMATS))
@ -438,6 +441,44 @@ class Guild(Hashable):
return 'https://cdn.discordapp.com/icons/{0.id}/{0.icon}.{1}?size={2}'.format(self, format, size)
@property
def banner_url(self):
"""Returns the URL version of the guild's banner. Returns an empty string if it has no banner."""
return self.banner_url_as()
def banner_url_as(self, *, format='webp', size=2048):
"""Returns a friendly URL version of the guild's banner. Returns an empty string if it has no banner.
The format must be one of 'webp', 'jpeg', or 'png'. The
size must be a power of 2 between 16 and 4096.
Parameters
-----------
format: str
The format to attempt to convert the banner to.
size: int
The size of the image to display.
Returns
--------
str
The resulting CDN URL.
Raises
------
InvalidArgument
Bad image format passed to ``format`` or invalid ``size``.
"""
if not valid_icon_size(size):
raise InvalidArgument("size must be a power of 2 between 16 and 4096")
if format not in VALID_ICON_FORMATS:
raise InvalidArgument("format must be one of {}".format(VALID_ICON_FORMATS))
if self.banner is None:
return ''
return 'https://cdn.discordapp.com/banners/{0.id}/{0.banner}.{1}?size={2}'.format(self, format, size)
@property
def splash_url(self):
"""Returns the URL version of the guild's invite splash. Returns an empty string if it has no splash."""
@ -447,7 +488,7 @@ class Guild(Hashable):
"""Returns a friendly URL version of the guild's invite splash. Returns an empty string if it has no splash.
The format must be one of 'webp', 'jpeg', 'jpg', or 'png'. The
size must be a power of 2 between 16 and 2048.
size must be a power of 2 between 16 and 4096.
Parameters
-----------
@ -467,7 +508,7 @@ class Guild(Hashable):
Bad image format passed to ``format`` or invalid ``size``.
"""
if not valid_icon_size(size):
raise InvalidArgument("size must be a power of 2 between 16 and 2048")
raise InvalidArgument("size must be a power of 2 between 16 and 4096")
if format not in VALID_ICON_FORMATS:
raise InvalidArgument("format must be one of {}".format(VALID_ICON_FORMATS))
@ -764,6 +805,9 @@ class Guild(Hashable):
icon: bytes
A :term:`py:bytes-like object` representing the icon. Only PNG/JPEG supported.
Could be ``None`` to denote removal of the icon.
banner: bytes
A :term:`py:bytes-like object` representing the banner.
Could be ``None`` to denote removal of the banner.
splash: bytes
A :term:`py:bytes-like object` representing the invite splash.
Only PNG/JPEG supported. Could be ``None`` to denote removing the
@ -814,6 +858,16 @@ class Guild(Hashable):
else:
icon = None
try:
banner_bytes = fields['banner']
except KeyError:
banner = self.banner
else:
if banner_bytes is not None:
banner = utils._bytes_to_base64_data(banner_bytes)
else:
banner = None
try:
vanity_code = fields['vanity_code']
except KeyError:
@ -832,6 +886,7 @@ class Guild(Hashable):
splash = None
fields['icon'] = icon
fields['banner'] = banner
fields['splash'] = splash
try:

2
discord/http.py

@ -568,7 +568,7 @@ class HTTPClient:
valid_keys = ('name', 'region', 'icon', 'afk_timeout', 'owner_id',
'afk_channel_id', 'splash', 'verification_level',
'system_channel_id', 'default_message_notifications',
'description', 'explicit_content_filter')
'description', 'explicit_content_filter', 'banner')
payload = {
k: v for k, v in fields.items() if k in valid_keys

26
discord/invite.py

@ -81,7 +81,7 @@ class PartialInviteChannel(namedtuple('PartialInviteChannel', 'id name type')):
"""Returns the channel's creation time in UTC."""
return utils.snowflake_time(self.id)
class PartialInviteGuild(namedtuple('PartialInviteGuild', 'features icon id name splash verification_level')):
class PartialInviteGuild(namedtuple('PartialInviteGuild', 'features icon banner id name splash verification_level')):
"""Represents a "partial" invite guild.
This model will be given when the user is not part of the
@ -117,6 +117,8 @@ class PartialInviteGuild(namedtuple('PartialInviteGuild', 'features icon id name
A list of features the guild has. See :attr:`Guild.features` for more information.
icon: Optional[:class:`str`]
The partial guild's icon.
banner: Optional[:class:`str`]
The partial guild's banner.
splash: Optional[:class:`str`]
The partial guild's invite splash.
"""
@ -139,7 +141,7 @@ class PartialInviteGuild(namedtuple('PartialInviteGuild', 'features icon id name
def icon_url_as(self, *, format='webp', size=1024):
""":class:`str`: The same operation as :meth:`Guild.icon_url_as`."""
if not valid_icon_size(size):
raise InvalidArgument("size must be a power of 2 between 16 and 2048")
raise InvalidArgument("size must be a power of 2 between 16 and 4096")
if format not in VALID_ICON_FORMATS:
raise InvalidArgument("format must be one of {}".format(VALID_ICON_FORMATS))
@ -148,6 +150,23 @@ class PartialInviteGuild(namedtuple('PartialInviteGuild', 'features icon id name
return 'https://cdn.discordapp.com/icons/{0.id}/{0.icon}.{1}?size={2}'.format(self, format, size)
@property
def banner_url(self):
"""Returns the URL version of the guild's banner. Returns an empty string if it has no banner."""
return self.banner_url_as()
def banner_url_as(self, *, format='webp', size=2048):
""":class:`str`: The same operation as :meth:`Guild.banner_url_as`."""
if not valid_icon_size(size):
raise InvalidArgument("size must be a power of 2 between 16 and 4096")
if format not in VALID_ICON_FORMATS:
raise InvalidArgument("format must be one of {}".format(VALID_ICON_FORMATS))
if self.banner is None:
return ''
return 'https://cdn.discordapp.com/banners/{0.id}/{0.banner}.{1}?size={2}'.format(self, format, size)
@property
def splash_url(self):
"""Returns the URL version of the guild's invite splash. Returns an empty string if it has no splash."""
@ -156,7 +175,7 @@ class PartialInviteGuild(namedtuple('PartialInviteGuild', 'features icon id name
def splash_url_as(self, *, format='webp', size=2048):
""":class:`str`: The same operation as :meth:`Guild.splash_url_as`."""
if not valid_icon_size(size):
raise InvalidArgument("size must be a power of 2 between 16 and 2048")
raise InvalidArgument("size must be a power of 2 between 16 and 4096")
if format not in VALID_ICON_FORMATS:
raise InvalidArgument("format must be one of {}".format(VALID_ICON_FORMATS))
@ -257,6 +276,7 @@ class Invite(Hashable):
name=guild_data['name'],
features=guild_data.get('features', []),
icon=guild_data.get('icon'),
banner=guild_data.get('banner'),
splash=guild_data.get('splash'),
verification_level=try_enum(VerificationLevel, guild_data.get('verification_level')))
data['guild'] = guild

4
discord/utils.py

@ -294,8 +294,8 @@ async def sane_wait_for(futures, *, timeout, loop):
raise asyncio.TimeoutError()
def valid_icon_size(size):
"""Icons must be power of 2 within [16, 2048]."""
return not size & (size - 1) and size in range(16, 2049)
"""Icons must be power of 2 within [16, 4096]."""
return not size & (size - 1) and size in range(16, 4097)
class SnowflakeList(array.array):
"""Internal data storage class to efficiently store a list of snowflakes.

Loading…
Cancel
Save