Skip to content

Instantly share code, notes, and snippets.

@bennyscripts
Last active July 30, 2023 19:06
Show Gist options
  • Save bennyscripts/394350f1a6beecc9d87c7451e1ddecf8 to your computer and use it in GitHub Desktop.
Save bennyscripts/394350f1a6beecc9d87c7451e1ddecf8 to your computer and use it in GitHub Desktop.
A very basic Python wrapper for Discord's new soundboard feature

Discord Soundboard Wrapper

A very basic Python wrapper for Discord's new soundboard feature

A bit of information

Creating this wrapper involved a lot of tinkering with the API, we found two endpoints to play and add a sound to the soundboard. We're still trying to find out how Discord gets the list of sounds, so getting the sound ID involves manually playing the sound through the client and listening to the http requests.

Example

soundboard = Soundboard("token", "guild_id", "channel_id")

new_sound = soundboard.upload_sound("my_sound.mp3", "testing", None, 1)
soundboard.play_sound(new_sound.id)

default_sounds = soundboard.get_default_sound()
for sound in default_sounds:
    print(sound.name)
    soundboard.play_sound(sound.id, override_path=sound.override_path) 
    # when playing a default sound you need to put the override path
import requests
import base64
import mimetypes
class Sound:
def __init__(self, name, sound_id, volume, emoji_id, emoji_name, override_path, user_id, available):
self.name = name
self.id = sound_id
self.volume = volume
self.emoji_id = emoji_id
self.emoji_name = emoji_name
self.override_path = override_path
self.user_id = user_id
self.available = available
class Soundboard:
def __init__(self, token, guild_id, channel_id):
self.token = token
self.guild_id = guild_id
self.channel_id = channel_id
self.headers = {
"Authorization": self.token,
"content-type": "application/json"
}
@staticmethod
def encode(sound_file):
with open(sound_file, "rb") as sound:
encoded = base64.b64encode(sound.read()).decode('utf-8')
content_type = mimetypes.guess_type(sound_file)[0]
return f"data:{content_type};base64,{encoded}"
def upload_sound(self, sound_file, name, emoji_id, volume):
endpoint = f"https://discord.com/api/v9/guilds/{self.guild_id}/soundboard-sounds"
encoded = self.encode(sound_file)
data = {
"name": name,
"emoji_id": emoji_id,
"volume": volume,
"sound": encoded
}
res = requests.post(endpoint, json=data, headers=self.headers)
if res.status_code in [200, 201]:
data = res.json()
return Sound(
name=data["name"],
sound_id=data["sound_id"],
volume=data["volume"],
emoji_id=data["emoji_id"],
emoji_name=data["emoji_name"],
override_path=data["override_path"],
user_id=data["user_id"],
available=data.get("available", False)
)
else:
return res
def delete_sound(self, sound_id):
endpoint = f"https://discord.com/api/v9/guilds/{self.guild_id}/soundboard-sounds/{sound_id}"
res = requests.delete(endpoint, headers=self.headers)
return True if res.status_code == 204 else False
def play_sound(self, sound_id, source_guild_id = True, override_path = None):
endpoint = f"https://discord.com/api/v9/channels/{self.channel_id}/voice-channel-effects"
data = {"sound_id": sound_id, "source_guild_id": self.guild_id, "override_path": override_path}
if source_guild_id == False or source_guild_id == None:
data.pop("source_guild_id")
if override_path == None or override_path == False:
data.pop("override_path")
return requests.post(endpoint, json=data, headers=self.headers)
def get_default_sounds(self):
endpoint = f"https://discord.com/api/v9/soundboard-default-sounds"
res = requests.get(endpoint, headers=self.headers)
sounds = []
if res.status_code == 200:
data = res.json()
for obj in data:
sounds.append(Sound(
name=obj["name"],
sound_id=obj["sound_id"],
volume=obj["volume"],
emoji_id=obj["emoji_id"],
emoji_name=obj["emoji_name"],
override_path=obj["override_path"],
user_id=obj["user_id"],
available=True
))
return sounds

Documentation

A simple documentation for Discord's soundboard API endpoints

Base URL

https://discord.com/api/v9

(GET) /soundboard-default-sounds

Returns a JSON array with a sound object for each default sound.

Example Response

[
    {
        "name": "quack",
        "sound_id": "1",
        "volume": 1,
        "emoji_id": null,
        "emoji_name": "🦆",
        "override_path": "default_quack.mp3",
        "user_id": "643945264868098049"
    },
    ...
]

(POST) /channels/{channel.id}/voice-channel-effects

Plays the sound given in JSON body in the given channel; returns nothing.

JSON Params

FIELD TYPE DESCRIPTION
sound_id string The sound's ID
emoji_id string The emoji's ID
emoji_name string The utf-8 version of the emoji or name of the custom emoji, example: 👻
override_path string Read below for further information about this
source_guild_id string The guild id the sound is from

We're unsure what the override_path is but from speculations it seems that it is the name of the sound file discord hosts. We've found that you only need to input this when playing a default sound.

(POST) /guilds/{guild.id}/soundboard-sounds

Uploads a custom sound to the given guild.

JSON Params

FIELD TYPE DESCRIPTION
name string The name for the sound
emoji_id string The emoji's ID
volume int The volume level of the sound, max is 1
sound base64 data uri Read below for further information about this

To upload the sound through the API you need to encode your audio in Data URI base64.

(DELETE) /guilds/{guild.id}/soundboard-sounds/{sound.id}

Delete the given sound from the given guild.

@CodeByAidan
Copy link

I did not enjoy this Gist on the GitHub open-sourced code platform.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment