DisCum Documentation
repository·master·Indexed 20 days ago
https://github.com/merubokkusu/discord-s.c.u.mA 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.
What's inside DisCum
- Discum is a simple, synchronous Discord API wrapper written in Python, specifically designed for creating selfbots and userbots. It is non-restrictive and supports Python versions 2.7 and 3.5 through 3.9.
Navigate the DisCum Documentation
masterThe
docs/using.mdfile 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.
Manage gateway session data and memory
masterThe
bot.gateway.sessionobject 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 fromreadyandready_supplemental) to save memory.
By default,
bot.gateway.keepDatais 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, useremoveDmData,removeGuildData, orremoveChannelDatavia the session functions.# Read all session data data = bot.gateway.session.read() # Optimize memory usage bot.gateway.session.saveMemory()Search for members by query using opcode 8
masterIf 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.5is recommended to prevent frequent rate limiting.Capabilities
- With member-viewing permissions: You can fetch all members. Use
limit=0andkeep="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()Handle Gateway connection events
masterWhen 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")How to fetch guild members using the member list sidebar
masterYou 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:
overlap: Subscribes to ranges that overlap to ensure coverage. Example sequence:[[0,99], [100,199]]->[[0,99], [100,199], [200,299]].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:
- Loading guild data (sending an op14 with range
[0,99]). - Subscribing to a list of ranges in the member list sidebar.
- Updating the saved member list data and subscribing to new ranges upon receiving a
GUILD_MEMBER_LIST_UPDATEevent.
# Example using the overlap method bot.gateway.fetchMembers(guild_id, channel_id, method="overlap")How DisCum's Gateway and Events work
masterDisCum provides
on-eventcapabilities via the gateway (websockets). You can register functions using the@bot.gateway.commanddecorator 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.sessionrelated data to be available, you must connect to the gateway at least once.Extend Discum with Gateway APIs
masterGateway 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, andrequest.py.1. Implement the Wrapper Type
Request Wrappers
Located in
request.py. These send messages to Discord via the gateway. The core requirement is callingself.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_UPDATEbecomesguild_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.pyusing theself.commandmethod.
# 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}})- Must be a
Extend Discum with HTTP APIs
masterTo 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.pyfile.1. Implement the Wrapper
Add the new method to the appropriate class within the nested directory structure (e.g.,
discum/messages/messages.py). UseWrapper.sendRequestwith the appropriate HTTP method.2. Wrap the Wrapper
Expose the new method in
discum.pyto 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)Handle Guild Rules and Verification
masterTo handle Discord's guild rules verification flow:
- Call
getMemberVerificationData(guildID)to retrieve the necessary verification fields and version. - 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"] )- Call
How to fetch members backwards or with custom patterns
masterIf you need to fetch members in a specific order (e.g., backwards to be less detectable), you can use
bot.gateway.getMemberFetchingParamsto calculate the necessarystartIndexandmethodbased 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)Install DisCum with Remote Authentication support
masterIf 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, andpypng.