DisCum Documentation

repository·master·Indexed 20 days ago

https://github.com/merubokkusu/discord-s.c.u.m

A synchronous Python Discord API wrapper designed for automating user accounts (selfbots/userbots). It uses requests and websockets to mimic standard Discord client communication with private user APIs. Supports Python 2.7 and 3.5 through 3.9. Features include gateway event handling, remote authentication support, and tools for managing guilds, channels, and messages.

Tokens
21.4K
Snippets
64
Records
71
Agent score
69%

What's inside DisCum

  1. Navigate the DisCum Documentation

    master

    The docs/using.md file serves as a high-level table of contents for the DisCum library. It organizes documentation into logical functional areas to help you find specific implementation guides:

    • Get Started: Installation and client initialization.
    • General Functions and Variables: Logging, gateway variables, and utility functions (e.g., snowflake conversion).
    • Start: Authentication and initial handshake actions (REST and Gateway).
    • User: Actions related to user profiles, settings, security (2FA), and connections.
    • Science/Analytics: Client UUID management and analytics requests.
    • Guild: Guild management, member/role manipulation, and thread operations.
    • DMs: Direct Message and Group DM management.
    • Channels: Channel and invite management.
    • Messages: Sending, editing, deleting, and searching messages.
    • Stickers: Sticker data and file retrieval.
    • Media/Calling: Gateway-based call management.
  2. Manage gateway session data and memory

    master

    The bot.gateway.session object manages data tied to your last gateway connection. You can interact with session data using several methods:

    • bot.gateway.session.read(): Access all session data.
    • bot.gateway.session.saveMemory(): Deletes essentially useless data (some user data from ready and ready_supplemental) to save memory.

    By default, bot.gateway.keepData is set to ("dms", "guilds", "guild_channels"), which prevents accidental data deletion when being kicked/banned or when removing them. To manually remove this data from memory, use removeDmData, removeGuildData, or removeChannelData via the session functions.

    # Read all session data
    data = bot.gateway.session.read()
    
    # Optimize memory usage
    bot.gateway.session.saveMemory()
  3. Search for members by query using opcode 8

    master

    If you cannot see any channels in a guild, or if you need to scrape the entire member list (including offline members), use the query-based search method via bot.gateway.queryGuildMembers. This uses Discord's opcode 8.

    When to use

    • Use this when you have no visibility into guild categories/channels.
    • Pros: Can potentially get the entire member list and can scrape multiple guilds simultaneously.
    • Cons: It is significantly slower as it relies on a brute-force optimization algorithm.

    Usage

    To use the brute-force search, you typically invoke a command that runs the search algorithm. A wait time of at least 0.5 is recommended to prevent frequent rate limiting.

    Capabilities

    • With member-viewing permissions: You can fetch all members. Use limit=0 and keep="all" to attempt a full scrape.
    • Without member-viewing permissions: You are limited to the first 100 members if many users share the same nickname/username (since discriminators cannot be searched).
    # Example: Full guild search if permissions allow
    @bot.gateway.command
    def test(resp):
        if resp.event.ready_supplemental:
            # limit=0 and keep="all" attempts to get everyone
            bot.gateway.queryGuildMembers(['guildID'], '', limit=0, keep="all")
        if resp.event.guild_members_chunk and bot.gateway.finishedGuildSearch(['guildID'], ''):
            bot.gateway.close()
    
    bot.gateway.run()
  4. Handle Gateway connection events

    master

    When working with the gateway, you can listen for specific connection events using @bot.gateway.command.

    • resp.event.ready: Triggered when the gateway is ready.
    • resp.event.ready_supplemental: Used to verify if you have successfully connected to the gateway. It is recommended to use this event to trigger initial setup tasks like setting status or fetching channels.
    @bot.gateway.command
    def readyTest(resp):
        if resp.event.ready:
            print("received ready event")
    
    @bot.gateway.command
    def readySuppTest(resp):
        if resp.event.ready_supplemental:
            print("received ready supplemental event")
  5. How to fetch guild members using the member list sidebar

    master

    You can fetch members by simulating the client's member list sidebar behavior using bot.gateway.fetchMembers. This method uses Discord's opcode 14.

    When to use

    • Use this if you can see any categories or channels in the guild.
    • Pros: It is fast.
    • Cons: In large servers (where bot.gateway.session.guild('GUILD_ID').large == True), only members who are currently online will be fetched.

    Methods

    DisCum supports two ways to subscribe to member ranges:

    1. overlap: Subscribes to ranges that overlap to ensure coverage. Example sequence: [[0,99], [100,199]] -> [[0,99], [100,199], [200,299]].
    2. nonoverlap: Subscribes to distinct ranges. Example sequence: [[0,99], [100,199]] -> [[0,99], [200,299], [300,399]]. This is faster (approx. 200 members/sec vs 100 members/sec for overlap) but less reliable/consistent.

    Implementation Details

    The algorithm involves:

    1. Loading guild data (sending an op14 with range [0,99]).
    2. Subscribing to a list of ranges in the member list sidebar.
    3. Updating the saved member list data and subscribing to new ranges upon receiving a GUILD_MEMBER_LIST_UPDATE event.
    # Example using the overlap method
    bot.gateway.fetchMembers(guild_id, channel_id, method="overlap")
  6. How DisCum's Gateway and Events work

    master

    DisCum provides on-event capabilities via the gateway (websockets). You can register functions using the @bot.gateway.command decorator to react to specific Discord events.

    • resp.event: Used to check which event type was received (e.g., resp.event.message, resp.event.ready_supplemental).
    • resp.parsed.auto(): A helper to parse the incoming event data into a usable dictionary.
    • bot.gateway.run(auto_reconnect=True): Starts the websocket connection and begins listening for events.

    Note that for bot.gateway.session related data to be available, you must connect to the gateway at least once.

  7. Extend Discum with Gateway APIs

    master

    Gateway extensions follow a structured pattern involving three types of wrappers: request, parse, and combo. These are organized into folders (dms, guild, media, messages, user) containing __init__.py, combo.py, parse.py, and request.py.

    1. Implement the Wrapper Type

    Request Wrappers

    Located in request.py. These send messages to Discord via the gateway. The core requirement is calling self.gatewayobject.send(data).

    Parse Wrappers

    Located in parse.py. These transform raw gateway responses into usable data.

    • Must be a @staticmethod (unless using __init__).
    • The first parameter must be the response.
    • Must return a value.
    • Naming convention: Use lowercase versions of the event types (e.g., GUILD_MEMBER_LIST_UPDATE becomes guild_member_list_update).

    Combo Wrappers

    Located in combo.py. These combine request and parse functions. They are often used for complex flows that require multiple responses or self-removing commands.

    2. Wrap the Wrapper

    • Parse wrappers are wrapped in gateway/parse.py.
    • Request wrappers are wrapped in gateway/request.py.
    • Combo wrappers are wrapped in gateway/gateway.py using the self.command method.
    # Request wrapper example (gateway/guild/request.py)
    def searchGuildMembers(self, guild_ids, query, limit, presences, user_ids):
        if isinstance(guild_ids, str):
            guild_ids = [guild_ids]
        data = {
            "op": self.gatewayobject.OPCODE.REQUEST_GUILD_MEMBERS,
            "d": {"guild_id": guild_ids},
        }
        if isinstance(user_ids, list):
            data["d"]["user_ids"] = user_ids
        else:
            data["d"]["query"] = query
            data["d"]["limit"] = limit
            data["d"]["presences"] = presences
        self.gatewayobject.send(data)
    
    # Parse wrapper example (gateway/messages/parse.py)
    @staticmethod
    def message_create(response):
        message = response["d"]
        # ... logic to map message["type"] ...
        return message
    
    # Combo wrapper registration (gateway/gateway.py)
    def testfuncPOG(self, pog):
        self.command({'function': Guild(self).testfuncPOG, 'priority': 0, 'params': {'pog': pog}})
  8. Extend Discum with HTTP APIs

    master

    To add new HTTP API endpoints to Discum, you must implement the logic in a nested module file and then expose it in the main discum.py file.

    1. Implement the Wrapper

    Add the new method to the appropriate class within the nested directory structure (e.g., discum/messages/messages.py). Use Wrapper.sendRequest with the appropriate HTTP method.

    2. Wrap the Wrapper

    Expose the new method in discum.py to make it accessible to the end-user. This step handles organization and provides access to the necessary session and logging objects.

    Required context for the wrapper:

    • self.discord: The Discord API URL (e.g., https://discord.com/api/v9/).
    • self.s: The current client's requests session.
    • self.log: The logging configuration object.
    # Example GET wrapper in a nested file
    def wrapper(*args):
        url = "url"
        return Wrapper.sendRequest(self.s, 'get', url, log=self.log)
    
    # Example POST wrapper in a nested file
    def wrapper(*args):
        url = "url"
        body = {"something": something, ...}
        return Wrapper.sendRequest(self.s, 'post', url, body, log=self.log)
    
    # Example of wrapping the wrapper in discum.py
    def createDM(self, recipients):
        return Messages(self.discord, self.s, self.log).createDM(recipients)
  9. Handle Guild Rules and Verification

    master

    To handle Discord's guild rules verification flow:

    1. Call getMemberVerificationData(guildID) to retrieve the necessary verification fields and version.
    2. Use agreeGuildRules(guildID, form_fields, version) to accept the rules using the data obtained in step 1.
    # 1. Get verification data
    verification_data = bot.getMemberVerificationData("guildID000000000000").json()
    
    # 2. Agree to rules
    bot.agreeGuildRules(
        "guildID000000000000", 
        verification_data["form_fields"], 
        verification_data["version"]
    )
  10. How to fetch members backwards or with custom patterns

    master

    If you need to fetch members in a specific order (e.g., backwards to be less detectable), you can use bot.gateway.getMemberFetchingParams to calculate the necessary startIndex and method based on a list of target indices.

    Example: Fetching backwards

    To fetch members starting from index 800 down to 0:

    # Get params for a specific sequence of indices
    startIndex, method = bot.gateway.getMemberFetchingParams([800, 700, 600, 500, 400, 300, 200, 100, 0])
    
    # Use the calculated params
    bot.gateway.fetchMembers(guild_id, channel_id, startIndex=startIndex, method=method)
    startIndex, method = bot.gateway.getMemberFetchingParams([800, 700, 600, 500, 400, 300, 200, 100, 0])
    bot.gateway.fetchMembers(guild_id, channel_id, startIndex=startIndex, method=method)
  11. Install DisCum with Remote Authentication support

    master

    If you need to use remote authentication functions (such as logging in using a phone number and a QR code), install the [ra] extra:

    python -m pip install --user --upgrade -e git+https://github.com/Merubokkusu/Discord-S.C.U.M.git#egg=discum[ra]

    This installation includes additional prerequisites: pyqrcode, pycryptodome, and pypng.