Skip to content

Models

Data models representing Geometry Dash entities.

User

gdpy.models.user.User

Bases: BaseModel

Represents a Geometry Dash user profile.

Contains all information about a user including stats, icons, social links, and moderation status.

Attributes:

Name Type Description
username str

The user's display name.

user_id int

The user's ID (different from account ID).

account_id int

The user's account ID.

stars int

Total stars collected.

diamonds int

Total diamonds collected.

moons int

Total moons collected.

secret_coins int

Secret coins collected (max 3).

user_coins int

User coins collected.

demons int

Demons completed.

creator_points int

Creator points earned.

icon_id int

Current icon ID.

color1 int

Primary icon color.

color2 int

Secondary icon color.

color3 int | None

Glow color (if has_glow is True).

icon_type int

Current icon type (cube, ship, ball, etc.).

has_glow bool

Whether glow is enabled.

youtube str | None

YouTube channel (if set).

twitter str | None

Twitter handle (if set).

twitch str | None

Twitch channel (if set).

discord str | None

Discord handle (if set).

instagram str | None

Instagram username (if set).

tiktok str | None

TikTok handle (if set).

mod_level ModLevel

Moderator status.

message_state MessageState

Message privacy setting.

friend_state int

Friend request setting.

comment_history_state int

Comment history visibility.

global_rank int | None

Global leaderboard rank (if on leaderboard).

Example
user = await client.get_user(account_id=71)
print(f"{user.username} has {user.stars} stars")

parse_bool classmethod

parse_bool(v: Any) -> bool

Parse boolean values from string responses.

Source code in gdpy/models/user.py
@field_validator("has_glow", mode="before")
@classmethod
def parse_bool(cls, v: Any) -> bool:
    """Parse boolean values from string responses."""
    if isinstance(v, bool):
        return v
    if isinstance(v, str):
        if v == "" or v == "0":
            return False
        return v != "0"
    return bool(v)

Level

gdpy.models.user.Level

Bases: BaseModel

Represents a Geometry Dash level.

Contains all information about a level including stats, difficulty, and audio information.

Attributes:

Name Type Description
level_id int

Unique level identifier.

name str

Level name.

description str

Level description.

version int

Level version number.

author_id int

Creator's player ID.

downloads int

Total downloads.

likes int

Total likes.

stars int

Star rating (0 if not rated).

difficulty LevelDifficulty

Level difficulty (includes AUTO and demon difficulties).

featured bool

Whether level is featured.

objects int

Object count in level.

length LevelLength

Level length classification.

song_id int | None

Custom song ID (if using custom song).

official_song_id int | None

Official song ID (if using official song).

coins int

Number of user coins in level.

verified_coins bool

Whether coins are verified.

two_player bool

Whether level supports two players.

level_string str | None

Level data (only in downloads).

epic_rating EpicRating

Epic/legendary/mythic rating.

password str | None

Level password (if copyable).

Example:

level = await client.get_level(level_id=3009486)
print(f"{level.name} has {level.objects} objects")

compute_difficulty classmethod

compute_difficulty(data: Any) -> Any

Compute difficulty from raw API fields.

Uses: - Key 9: difficulty_numerator (0=auto/unrated, 10=easy, 20=normal, 30=hard, 40=harder, 50=insane) - Key 17: is_demon - Key 25: is_auto - Key 43: demon_difficulty (3=easy, 4=medium, 0=hard, 5=insane, 6=extreme)

Source code in gdpy/models/user.py
@model_validator(mode="before")
@classmethod
def compute_difficulty(cls, data: Any) -> Any:
    """Compute difficulty from raw API fields.

    Uses:
    - Key 9: difficulty_numerator (0=auto/unrated, 10=easy, 20=normal,
      30=hard, 40=harder, 50=insane)
    - Key 17: is_demon
    - Key 25: is_auto
    - Key 43: demon_difficulty (3=easy, 4=medium, 0=hard, 5=insane, 6=extreme)
    """
    if not isinstance(data, dict):
        return data

    # Skip if difficulty already computed
    if "difficulty" in data and isinstance(data.get("difficulty"), LevelDifficulty):
        return data

    # Get raw values
    raw_17 = data.get("17", "")
    raw_25 = data.get("25", "")
    raw_43 = data.get("43", "0")
    raw_9 = data.get("9", "0")

    # Parse boolean strings - "1" means true, "" or "0" means false
    is_auto = raw_25 == "1"
    is_demon = raw_17 == "1"
    demon_diff = int(raw_43) if isinstance(raw_43, str) and raw_43.isdigit() else 0
    diff_num = int(raw_9) if isinstance(raw_9, str) and raw_9.isdigit() else 0

    # Compute difficulty
    if is_demon:
        # Demon levels - use demon_difficulty
        if demon_diff == 3:
            data["difficulty"] = LevelDifficulty.EASY_DEMON
        elif demon_diff == 4:
            data["difficulty"] = LevelDifficulty.MEDIUM_DEMON
        elif demon_diff == 5:
            data["difficulty"] = LevelDifficulty.INSANE_DEMON
        elif demon_diff == 6:
            data["difficulty"] = LevelDifficulty.EXTREME_DEMON
        else:
            data["difficulty"] = LevelDifficulty.HARD_DEMON
    elif is_auto or diff_num == 0:
        # Auto levels have is_auto="1" OR diff_num=0
        data["difficulty"] = LevelDifficulty.AUTO
    elif diff_num == 10:
        data["difficulty"] = LevelDifficulty.EASY
    elif diff_num == 20:
        data["difficulty"] = LevelDifficulty.NORMAL
    elif diff_num == 30:
        data["difficulty"] = LevelDifficulty.HARD
    elif diff_num == 40:
        data["difficulty"] = LevelDifficulty.HARDER
    elif diff_num == 50:
        data["difficulty"] = LevelDifficulty.INSANE
    else:
        data["difficulty"] = LevelDifficulty.UNSPECIFIED

    return data

decode_description classmethod

decode_description(v: Any) -> str

Decode base64 encoded level description.

Source code in gdpy/models/user.py
@field_validator("description", mode="before")
@classmethod
def decode_description(cls, v: Any) -> str:
    """Decode base64 encoded level description."""
    if isinstance(v, str):
        try:
            import base64

            return base64.b64decode(v).decode("utf-8")
        except Exception:
            return v
    return str(v) if v else ""

decode_level_string classmethod

decode_level_string(v: Any) -> str | None

Decode base64 and decompress level string.

Source code in gdpy/models/user.py
@field_validator("level_string", mode="before")
@classmethod
def decode_level_string(cls, v: Any) -> str | None:
    """Decode base64 and decompress level string."""
    if v is None or v == "":
        return None
    if isinstance(v, str):
        try:
            import base64
            import zlib

            # Official levels need prefix added
            level_data = v
            if not level_data.startswith("H4sIA"):
                level_data = "H4sIAAAAAAAAA" + level_data
            decoded = base64.urlsafe_b64decode(level_data.encode())
            # window_bits = 15 | 32 autodetects gzip or not
            decompressed = zlib.decompress(decoded, 15 | 32)
            return decompressed.decode()
        except Exception:
            return str(v)
    return str(v) if v else None

parse_bool classmethod

parse_bool(v: Any) -> bool

Parse boolean values from string responses.

Source code in gdpy/models/user.py
@field_validator(
    "featured",
    "verified_coins",
    "two_player",
    mode="before",
)
@classmethod
def parse_bool(cls, v: Any) -> bool:
    """Parse boolean values from string responses."""
    if isinstance(v, bool):
        return v
    if isinstance(v, str):
        if v == "" or v == "0":
            return False
        return v != "0"
    return bool(v)

Comment

gdpy.models.user.Comment

Bases: BaseModel

Represents a level or profile comment.

Attributes:

Name Type Description
content str

Comment text content.

author str

Comment author's username.

author_id int

Comment author's user ID.

likes int

Number of likes on the comment.

message_id int

Unique comment/message ID.

percent int

Progress percentage shown in comment.

age str

How long ago the comment was posted.

is_spam bool

Whether comment is marked as spam.

decode_base64 classmethod

decode_base64(v: Any) -> str

Decode base64 encoded comment content.

Source code in gdpy/models/user.py
@field_validator("content", mode="before")
@classmethod
def decode_base64(cls, v: Any) -> str:
    """Decode base64 encoded comment content."""
    if isinstance(v, str):
        try:
            import base64

            return base64.b64decode(v).decode("utf-8")
        except Exception:
            return v
    return str(v)

Song

gdpy.models.user.Song

Bases: BaseModel

Represents a custom song from Newgrounds.

Attributes:

Name Type Description
song_id int

Unique song identifier.

name str

Song name.

author str

Song artist name.

size float

File size in MB.

download_url str

URL to download the song.

Message

gdpy.models.user.Message

Bases: BaseModel

Represents a private message.

Attributes:

Name Type Description
message_id int

Unique message identifier.

subject str

Message subject.

sender_id int

Sender's account ID.

sender_name str

Sender's username.

age str

How long ago the message was sent.

is_read bool

Whether the message has been read.

content str | None

Message content (only when downloading).

decode_base64 classmethod

decode_base64(v: Any) -> str | None

Decode base64 encoded message content.

Source code in gdpy/models/user.py
@field_validator("subject", "content", mode="before")
@classmethod
def decode_base64(cls, v: Any) -> str | None:
    """Decode base64 encoded message content."""
    if v is None:
        return None
    if isinstance(v, str):
        try:
            import base64

            return base64.b64decode(v).decode("utf-8")
        except Exception:
            return v
    return str(v) if v else None

FriendRequest

gdpy.models.user.FriendRequest

Bases: BaseModel

Represents a friend request.

Attributes:

Name Type Description
request_id int

Unique request identifier.

sender_id int

Sender's account ID.

sender_name str

Sender's username.

age str

How long ago the request was sent.

is_read bool

Whether the request has been read.

LeaderboardScore

gdpy.models.user.LeaderboardScore

Bases: BaseModel

Represents a leaderboard entry.

Attributes:

Name Type Description
username str

Player's username.

user_id int

Player's user ID.

stars int

Total stars.

demons int

Demons completed.

ranking int

Global rank position.

creator_points int

Creator points earned.

icon_id int

Current icon ID.

color1 int

Primary icon color.

color2 int

Secondary icon color.

secret_coins int

Secret coins collected (max 3).

icon_type int

Current icon type.

account_id int

Player's account ID.

user_coins int

User coins collected.

diamonds int

Total diamonds.

Enums

ModLevel

gdpy.models.user.ModLevel

Bases: IntEnum

Moderator level for a user.

Attributes:

Name Type Description
NONE

Not a moderator.

MODERATOR

Regular moderator (yellow badge).

ELDER_MOD

Elder moderator (orange badge).

MessageState

gdpy.models.user.MessageState

Bases: IntEnum

Message privacy settings.

Attributes:

Name Type Description
ALL

Anyone can send messages.

FRIENDS_ONLY

Only friends can send messages.

NONE

No one can send messages.

LevelDifficulty

gdpy.models.user.LevelDifficulty

Bases: IntEnum

Level difficulty rating.

Attributes:

Name Type Description
UNSPECIFIED

No difficulty specified.

AUTO

Auto level (no skill required).

EASY

Easy difficulty.

NORMAL

Normal difficulty.

HARD

Hard difficulty.

HARDER

Harder difficulty.

INSANE

Insane difficulty.

EASY_DEMON

Easy demon.

MEDIUM_DEMON

Medium demon.

HARD_DEMON

Hard demon (default demon).

INSANE_DEMON

Insane demon.

EXTREME_DEMON

Extreme demon.

LevelLength

gdpy.models.user.LevelLength

Bases: IntEnum

Level length classification.

Attributes:

Name Type Description
TINY

Very short level.

SHORT

Short level.

MEDIUM

Medium length level.

LONG

Long level.

XL

Extra long level.

handlers: python: docstring_style: google

EpicRating

gdpy.models.user.EpicRating

Bases: IntEnum

Level epic/featured rating.

Attributes:

Name Type Description
NONE

Not epic rated.

EPIC

Epic rating.

LEGENDARY

Legendary rating.

MYTHIC

Mythic rating.

handlers: python: docstring_style: google