Files
nyeki-api/nyekiapi/lib/integrations/discord.py
T
2026-07-16 02:12:29 -03:00

70 lines
2.0 KiB
Python

from typing import TypedDict, NotRequired
from nyekiapi.lib import settings, cache
from nyekiapi.lib.requests import httpx
from nyekiapi.lib.integrations import Profile
CACHE_BY_ID_KEY = "discord:profile:id:%s"
class DiscordProfile(TypedDict):
id: str
username: str
global_name: str | None
discriminator: str
avatar: str | None
banner: NotRequired[str | None]
def _get_username(user: DiscordProfile) -> str:
if user["discriminator"] == "0":
return user["username"]
return f"{user['username']}#{user['discriminator']}"
def _get_avatar_url(user: DiscordProfile) -> str:
if user["avatar"] is None:
if user["discriminator"] == "0":
return f"https://cdn.discordapp.com/embed/avatars/{(int(user['id']) >> 22) % 6}.png?size=256"
else:
return f"https://cdn.discordapp.com/embed/avatars/{int(user['discriminator']) % 6}.png?size=256"
else:
return f"https://cdn.discordapp.com/avatars/{user['id']}/{user['avatar']}.png?size=256"
def _get_banner_url(user: DiscordProfile) -> str | None:
if "banner" not in user or user["banner"] is None:
return None
return f"https://cdn.discordapp.com/banners/{user['id']}/{user['banner']}.png?size=2048"
async def get_profile_by_id(id: str) -> Profile:
profile = await cache.get(CACHE_BY_ID_KEY % id)
if profile is not None:
return Profile.from_json(profile)
response = await httpx.get(
f"https://discord.com/api/v10/users/{id}",
headers={"Authorization": f"Bot {settings.DISCORD_TOKEN}"},
)
response.raise_for_status()
data: DiscordProfile = response.json()
profile = Profile(
id=data["id"],
url=f"https://discord.com/users/{data['id']}",
name=data.get("global_name") or _get_username(data),
username=_get_username(data),
avatar_url=_get_avatar_url(data),
banner_url=_get_banner_url(data),
)
await cache.set(CACHE_BY_ID_KEY % id, profile, expires_in=10 * 60)
return profile