Make a bunch of image url getters and memory optimize the image hashes
This commit is contained in:
parent
fadf533066
commit
0764147bed
|
@ -22,7 +22,7 @@ proc getIdentifyPacket(shard: Shard): JsonNode
|
|||
proc handleGatewayDisconnect(shard: Shard, error: string) {.async.}
|
||||
proc handleHeartbeat(shard: Shard) {.async.}
|
||||
proc handleWebsocketPacket(shard: Shard) {.async.}
|
||||
proc newDiscordClient*(tkn: string): DiscordClient
|
||||
proc newDiscordClient*(tkn: string, commandPrefix: string): DiscordClient
|
||||
proc newShard(shardID: int, client: DiscordClient): Shard
|
||||
proc reconnectShard(shard: Shard) {.async.}
|
||||
proc sendGatewayRequest*(shard: Shard, request: JsonNode, msg: string = "") {.async.}
|
||||
|
|
|
@ -96,3 +96,21 @@ proc deleteEmoji*(emoji: Emoji) {.async.} =
|
|||
## Delete the given emoji. Requires the `MANAGE_EMOJIS` permission.
|
||||
discard sendRequest(endpoint(fmt("/guilds/{emoji.guildID}/emojis/{emoji.id}")), HttpDelete,
|
||||
defaultHeaders(), emoji.guildID, RateLimitBucketType.guild)
|
||||
|
||||
proc getEmojiURL*(emoji: Emoji, imageType: ImageType = ImageType.imgTypeAuto): string =
|
||||
## Get the URL for the emoji's.
|
||||
result = "https://cdn.discordapp.com/emojis/" & $emoji.id
|
||||
|
||||
# Choose the type of image automaticly.
|
||||
var tmp = imageType
|
||||
if emoji.animated:
|
||||
tmp = ImageType.imgTypeGif
|
||||
else:
|
||||
tmp = ImageType.imgTypePng
|
||||
|
||||
case tmp:
|
||||
of ImageType.imgTypeGif:
|
||||
result &= ".gif"
|
||||
discard
|
||||
else: # The only other possible image type is png
|
||||
result &= ".png"
|
|
@ -1,6 +1,6 @@
|
|||
import json, discordobject, channel, member, options, nimcordutils, emoji
|
||||
import role, permission, httpcore, strformat, image, asyncdispatch, user
|
||||
import permission, presence, tables
|
||||
import permission, presence, tables, strutils
|
||||
|
||||
type
|
||||
VerificationLevel* = enum
|
||||
|
@ -68,9 +68,10 @@ type
|
|||
Guild* = ref object of DiscordObject
|
||||
## Discord Guild object
|
||||
name*: string ## The name of the current guild
|
||||
icon*: string ## The hash of the current guild's icon
|
||||
splash*: string ## The hash of the current guild's splash
|
||||
discoverySplash*: string
|
||||
iconRaw: array[2, uint64] ## The split hash for the 128bit hexadeximal icon.
|
||||
isIconGif: bool ## Wether the avatar is a gif.
|
||||
splashRaw: array[2, uint64] ## The split hash for the 128bit hexadeximal splash.
|
||||
discoverySplashRaw: array[2, uint64] ## The split hash for the 128bit hexadeximal discovery splash.
|
||||
owner*: bool ## Whether or not the current user is the owner of the current guild
|
||||
ownerID: Snowflake ## The snowflake id of the current guild's owner
|
||||
permissions*: Permissions
|
||||
|
@ -102,7 +103,7 @@ type
|
|||
maxMembers*: int ## The maximum amount of members in the current guild?
|
||||
vanityUrlCode*: string ## The vanity invite for the current guild (ex: https://discord.gg/discord-api)
|
||||
description*: string
|
||||
banner*: string ## The hash code of the current guild
|
||||
bannerRaw: array[2, uint64] ## The split hash for the 128bit hexadeximal banner.
|
||||
premiumTier*: PremiumTier
|
||||
premiumSubscriptionCount*: int
|
||||
preferredLocale*: string
|
||||
|
@ -175,9 +176,8 @@ proc newGuild*(json: JsonNode): Guild {.inline.} =
|
|||
var g = Guild(
|
||||
id: getIDFromJson(json["id"].getStr()),
|
||||
name: json["name"].getStr(),
|
||||
icon: json["icon"].getStr(),
|
||||
splash: json["splash"].getStr(),
|
||||
discoverySplash: json["discovery_splash"].getStr(),
|
||||
splashRaw: splitAvatarHash(json["splash"].getStr()), # No need to remove prefixed "a_", can't be animated.
|
||||
discoverySplashRaw: splitAvatarHash(json["discovery_splash"].getStr()), # No need to remove prefixed "a_", can't be animated.
|
||||
ownerID: getIDFromJson(json["owner_id"].getStr()),
|
||||
region: json["region"].getStr(),
|
||||
afkChannelID: getIDFromJson(json["afk_channel_id"].getStr()),
|
||||
|
@ -192,13 +192,23 @@ proc newGuild*(json: JsonNode): Guild {.inline.} =
|
|||
rulesChannelID: getIDFromJson(json["rules_channel_id"].getStr()),
|
||||
vanityUrlCode: json["vanity_url_code"].getStr(),
|
||||
description: json["description"].getStr(),
|
||||
banner: json["banner"].getStr(),
|
||||
bannerRaw: splitAvatarHash(json["banner"].getStr()), # No need to remove prefixed "a_", can't be animated.
|
||||
premiumTier: PremiumTier(json["premium_tier"].getInt()),
|
||||
preferredLocale: json["preferred_locale"].getStr(),
|
||||
publicUpdatesChannelID: getIDFromJson(json["public_updates_channel_id"].getStr())
|
||||
)
|
||||
|
||||
# Parse all non guaranteed fields
|
||||
if json.contains("icon"):
|
||||
let iconStr = json["icon"].getStr()
|
||||
|
||||
# If the icon is animated we need to remove the prefixed "a_"
|
||||
if iconStr.startsWith("a_"):
|
||||
g.isIconGif = true
|
||||
g.iconRaw = splitAvatarHash(iconStr.substr(2))
|
||||
else:
|
||||
g.isIconGif = false
|
||||
g.iconRaw = splitAvatarHash(iconStr)
|
||||
if json.contains("owner"):
|
||||
g.owner = json["owner"].getBool()
|
||||
if json.contains("permissions"):
|
||||
|
@ -916,3 +926,96 @@ proc getGuildMemberRoles*(guild: Guild, member: GuildMember): seq[Role] =
|
|||
for role in guild.roles:
|
||||
if member.roles.contains(role.id):
|
||||
result.add(role)
|
||||
|
||||
proc getGuildIconURL*(guild: Guild, imageType: ImageType = ImageType.imgTypeAuto): string =
|
||||
## Get the URL for the guild's icon.
|
||||
result = "https://cdn.discordapp.com/icons/" & $guild.id & "/" & $combineAvatarHash(guild.iconRaw)
|
||||
|
||||
# If we're finding the image type automaticly, then we need to
|
||||
# check if the avatar is a gif.
|
||||
var tmp = imageType
|
||||
if (imageType == ImageType.imgTypeAuto):
|
||||
if guild.isIconGif:
|
||||
tmp = ImageType.imgTypeGif
|
||||
else:
|
||||
tmp = ImageType.imgTypePng
|
||||
|
||||
case tmp:
|
||||
of ImageType.imgTypeGif:
|
||||
result &= ".gif"
|
||||
discard
|
||||
of ImageType.imgTypeJpeg:
|
||||
result &= ".jpeg"
|
||||
discard
|
||||
of ImageType.imgTypePng:
|
||||
result &= ".png"
|
||||
discard
|
||||
of ImageType.imgTypeWebp:
|
||||
result &= ".webp"
|
||||
discard
|
||||
of ImageType.imgTypeAuto:
|
||||
result &= ".png" # Just incase
|
||||
discard
|
||||
|
||||
proc getGuildSplashURL*(guild: Guild, imageType: ImageType = ImageType.imgTypePng): string =
|
||||
## Get the URL for the guild's splash.
|
||||
result = "https://cdn.discordapp.com/splashes/" & $guild.id & "/" & $combineAvatarHash(guild.splashRaw)
|
||||
|
||||
case imageType:
|
||||
of ImageType.imgTypeGif:
|
||||
result &= ".png" # The guild's splash can't be a gif.
|
||||
discard
|
||||
of ImageType.imgTypeJpeg:
|
||||
result &= ".jpeg"
|
||||
discard
|
||||
of ImageType.imgTypePng:
|
||||
result &= ".png"
|
||||
discard
|
||||
of ImageType.imgTypeWebp:
|
||||
result &= ".webp"
|
||||
discard
|
||||
of ImageType.imgTypeAuto:
|
||||
result &= ".png"
|
||||
discard
|
||||
|
||||
proc getGuildDiscoverySplashURL*(guild: Guild, imageType: ImageType = ImageType.imgTypePng): string =
|
||||
## Get the URL for the guild's discovery splash.
|
||||
result = "https://cdn.discordapp.com/discovery-splashes/" & $guild.id & "/" & $combineAvatarHash(guild.discoverySplashRaw)
|
||||
|
||||
case imageType:
|
||||
of ImageType.imgTypeGif:
|
||||
result &= ".png" # The guild's discovery splash can't be a gif.
|
||||
discard
|
||||
of ImageType.imgTypeJpeg:
|
||||
result &= ".jpeg"
|
||||
discard
|
||||
of ImageType.imgTypePng:
|
||||
result &= ".png"
|
||||
discard
|
||||
of ImageType.imgTypeWebp:
|
||||
result &= ".webp"
|
||||
discard
|
||||
of ImageType.imgTypeAuto:
|
||||
result &= ".png" # Just incase
|
||||
discard
|
||||
|
||||
proc getGuildBannerURL*(guild: Guild, imageType: ImageType = ImageType.imgTypePng): string =
|
||||
## Get the URL for the guild's banner.
|
||||
result = "https://cdn.discordapp.com/banners/" & $guild.id & "/" & $combineAvatarHash(guild.bannerRaw)
|
||||
|
||||
case imageType:
|
||||
of ImageType.imgTypeGif:
|
||||
result &= ".png" # The guild's banner can't be a gif.
|
||||
discard
|
||||
of ImageType.imgTypeJpeg:
|
||||
result &= ".jpeg"
|
||||
discard
|
||||
of ImageType.imgTypePng:
|
||||
result &= ".png"
|
||||
discard
|
||||
of ImageType.imgTypeWebp:
|
||||
result &= ".webp"
|
||||
discard
|
||||
of ImageType.imgTypeAuto:
|
||||
result &= ".png" # Just incase
|
||||
discard
|
|
@ -1,6 +1,13 @@
|
|||
import parseutils, json, httpClient, strformat, tables, times, asyncdispatch
|
||||
import parseutils, json, httpClient, strformat, tables, times, asyncdispatch, strutils
|
||||
from discordobject import Snowflake
|
||||
|
||||
type ImageType* = enum
|
||||
imgTypeAuto = 0,
|
||||
imgTypeWebp = 1,
|
||||
imgTypePng = 2,
|
||||
imgTypeJpeg = 3,
|
||||
imgTypeGif = 4
|
||||
|
||||
proc getIDFromJson*(str: string): uint64 =
|
||||
var num: uint64
|
||||
discard parseBiggestUInt(str, num)
|
||||
|
@ -17,12 +24,22 @@ proc endpoint*(url: string): string =
|
|||
var globalToken*: string
|
||||
|
||||
proc defaultHeaders*(added: HttpHeaders = newHttpHeaders()): HttpHeaders =
|
||||
# added.add("Authorization", fmt("Bot {globalToken}"))
|
||||
added.add("Authorization", fmt("{globalToken}"))
|
||||
added.add("Authorization", fmt("Bot {globalToken}"))
|
||||
added.add("User-Agent", "NimCord (https://github.com/SeanOMik/nimcord, v0.0.0)")
|
||||
added.add("X-RateLimit-Precision", "millisecond")
|
||||
return added
|
||||
|
||||
proc splitAvatarHash*(hash: string): array[2, uint64] =
|
||||
var first: uint64
|
||||
discard parseBiggestUInt(hash.substr(0, 16), first)
|
||||
var second: uint64
|
||||
discard parseBiggestUInt(hash.substr(0, 16), first)
|
||||
|
||||
return [first, second]
|
||||
|
||||
proc combineAvatarHash*(hash: array[2, uint64]): string =
|
||||
return (BiggestInt hash[0]).toHex(16) & (BiggestInt hash[1]).toHex(16)
|
||||
|
||||
type
|
||||
RateLimitBucketType* = enum
|
||||
channel,
|
||||
|
@ -125,4 +142,4 @@ proc sendRequest*(endpoint: string, httpMethod: HttpMethod, headers: HttpHeaders
|
|||
|
||||
waitForRateLimits(objectID, bucketType)
|
||||
let response = client.request(endpoint, httpMethod, strPayload)
|
||||
return handleResponse(response, objectId, bucketType)
|
||||
return handleResponse(response, objectId, bucketType)
|
|
@ -1,4 +1,4 @@
|
|||
import json, discordobject, nimcordutils
|
||||
import json, discordobject, nimcordutils, strutils
|
||||
|
||||
type
|
||||
NitroSubscription* = enum
|
||||
|
@ -7,41 +7,52 @@ type
|
|||
nitro = 2
|
||||
|
||||
User* = ref object of DiscordObject
|
||||
## This type is a discord user.
|
||||
## This type is any discord user.
|
||||
username*: string ## The user's username, not unique across the platform.
|
||||
discriminator*: cushort ## The user's 4-digit discord-tag.
|
||||
avatar*: string ## The user's avatar hash.
|
||||
bot*: bool ## Whether the user belongs to an OAuth2 application.
|
||||
system*: bool ## Whether the user is an Official Discord System user (part of the urgent message system).
|
||||
flags*: int ## The flags on a user's account.
|
||||
premiumType*: NitroSubscription ## The type of Nitro subscription on a user's account.
|
||||
publicFlags*: int ## The public flags on a user's account.
|
||||
publicFlags*: int ## The public [flags](https://discord.com/developers/docs/resources/user#user-object-user-flags) on a user's account. (User Badges)
|
||||
avatarRaw: array[2, uint64] ## The split hash for the 128bit hexadeximal avatar.
|
||||
isAvatarGif: bool ## Wether the avatar is a gif.
|
||||
|
||||
|
||||
ClientUser* = ref object of User
|
||||
## This type is the clients discord user.
|
||||
mfaEnabled*: bool ## Whether the user has two factor authentication enabled on their account.
|
||||
locale*: string ## The user's chosen language option.
|
||||
verified*: bool ## Whether or not the current user has a verified email.
|
||||
email*: string ## The current user's email
|
||||
premiumType*: NitroSubscription ## The type of Nitro subscription on a user's account.
|
||||
flags*: int ## The [flags](https://discord.com/developers/docs/resources/user#user-object-user-flags) on a user's account.
|
||||
|
||||
proc newUser*(user: JsonNode): User {.inline.} =
|
||||
return User(
|
||||
result = User(
|
||||
id: getIDFromJson(user["id"].getStr()),
|
||||
username: user["username"].getStr(),
|
||||
discriminator: cushort(parseIntEasy(user["discriminator"].getStr())),
|
||||
avatar: user["avatar"].getStr(),
|
||||
bot: user{"bot"}.getBool(),
|
||||
system: user{"system"}.getBool(),
|
||||
flags: user{"flags"}.getInt(),
|
||||
premiumType: NitroSubscription(user{"premium_type"}.getInt()),
|
||||
publicFlags: user{"public_flags"}.getInt()
|
||||
)
|
||||
|
||||
if user.contains("avatar"):
|
||||
let avatarStr = user["avatar"].getStr()
|
||||
|
||||
# If the avatar is animated we need to remove the prefixed "a_"
|
||||
if avatarStr.startsWith("a_"):
|
||||
result.isAvatarGif = true
|
||||
result.avatarRaw = splitAvatarHash(avatarStr.substr(2))
|
||||
else:
|
||||
result.isAvatarGif = false
|
||||
result.avatarRaw = splitAvatarHash(avatarStr)
|
||||
|
||||
|
||||
proc newClientUser*(clientUser: JsonNode): ClientUser {.inline.} =
|
||||
return ClientUser(
|
||||
result = ClientUser(
|
||||
id: getIDFromJson(clientUser["id"].getStr()),
|
||||
username: clientUser["username"].getStr(),
|
||||
discriminator: cushort(parseIntEasy(clientUser["discriminator"].getStr())),
|
||||
avatar: clientUser["avatar"].getStr(),
|
||||
bot: clientUser{"bot"}.getBool(),
|
||||
system: clientUser{"system"}.getBool(),
|
||||
mfaEnabled: clientUser{"mfa_enabled"}.getBool(),
|
||||
|
@ -51,4 +62,48 @@ proc newClientUser*(clientUser: JsonNode): ClientUser {.inline.} =
|
|||
flags: clientUser{"flags"}.getInt(),
|
||||
premiumType: NitroSubscription(clientUser{"premium_type"}.getInt()),
|
||||
publicFlags: clientUser{"public_flags"}.getInt()
|
||||
)
|
||||
)
|
||||
|
||||
if clientUser.contains("avatar"):
|
||||
let avatarStr = clientUser["avatar"].getStr()
|
||||
|
||||
# If the avatar is animated we need to remove the prefixed "a_"
|
||||
if avatarStr.startsWith("a_"):
|
||||
result.isAvatarGif = true
|
||||
result.avatarRaw = splitAvatarHash(avatarStr.substr(2))
|
||||
else:
|
||||
result.isAvatarGif = false
|
||||
result.avatarRaw = splitAvatarHash(avatarStr)
|
||||
|
||||
proc getUserAvatarURL*(user: User, imageType: ImageType = ImageType.imgTypeAuto): string =
|
||||
# If the user doesn't have an avatar, then return a default avatar url.
|
||||
if user.avatarRaw.len == 0:
|
||||
return "https://cdn.discordapp.com/embed/avatars/" & $(user.discriminator mod 5) & ".png"
|
||||
|
||||
result = "https://cdn.discordapp.com/avatars/" & $user.id & "/" & $combineAvatarHash(user.avatarRaw)
|
||||
|
||||
# If we're finding the image type automaticly, then we need to
|
||||
# check if the avatar is a gif.
|
||||
var tmp = imageType
|
||||
if (imageType == ImageType.imgTypeAuto):
|
||||
if user.isAvatarGif:
|
||||
tmp = ImageType.imgTypeGif
|
||||
else:
|
||||
tmp = ImageType.imgTypePng
|
||||
|
||||
case tmp:
|
||||
of ImageType.imgTypeGif:
|
||||
result &= ".gif"
|
||||
discard
|
||||
of ImageType.imgTypeJpeg:
|
||||
result &= ".jpeg"
|
||||
discard
|
||||
of ImageType.imgTypePng:
|
||||
result &= ".png"
|
||||
discard
|
||||
of ImageType.imgTypeWebp:
|
||||
result &= ".webp"
|
||||
discard
|
||||
of ImageType.imgTypeAuto:
|
||||
result &= ".png" # Just incase
|
||||
discard
|
Reference in New Issue