Using a Discord Bot to control OBS
In this entry im going to show you how to create a python bot to command OBS. This is useful when you're streaming in twitch and need admins to fix streaming problems without interruption
Discord api and OBS
first of all you need to create a bot in the developer portal (click on New Application), invite it to a server and copy the TOKEN then you need:
- python v3.12+
- pip (require discord and obswebsocket)
- obs (enable websocket server)
The bot in question
import discord from discord.ext import commands import obswebsocket from obswebsocket import obsws, requests DISCORD_TOKEN = '***' # OBS WS URL (normally your localhost) OBS_WS_URL = '127.0.0.1' OBS_WS_PORT = 4455 # use password if needed OBS_WS_PASSWORD = ''
once you have these things you're good to go
# Set up the Discord bot with commands intents = discord.Intents.default() intents.message_content = True # Required to read message content bot = commands.Bot(command_prefix='!', intents=intents) # Initialize OBS WebSocket client obs_client = obsws(OBS_WS_URL, OBS_WS_PORT, OBS_WS_PASSWORD) @bot.event async def on_ready(): print(f'Logged in as {bot.user.name}') obs_client.connect() @bot.event async def on_disconnect(): obs_client.disconnect() . . . # IN THE LAST LINE bot.run(DISCORD_TOKEN)
Functions and obs api commands
There are a lot of api commands especially in the last release. The protocol is documented here. I will show you some examples like:
- How to Start Streaming
@bot.command() async def start(ctx): try: response = obs_client.call(requests.StartStream()) await ctx.send('Streaming started.') except Exception as e: await ctx.send(f'Error: {e}')
use !start
in the server
- Change scenes remotely
@bot.command() async def scene(ctx, *, scene_name: str): try: response = obs_client.call(requests.SetCurrentProgramScene(sceneName=scene_name)) if response.status: await ctx.send(f'Scene changed to {scene_name}') else: await ctx.send(f'Failed to change scene. OBS WebSocket response: {response}') except Exception as e: await ctx.send(f'Error: {e}')
use !scene <scene_name>
to change to a specific scene.
the next function may be needed for this
- Get all scenes
@bot.command() async def get_scenes(ctx): try: text = "" scenes = obs_client.call(requests.GetSceneList()) for s in scenes.getScenes(): text += "NAME: " + s['sceneName'] + " UUID: " + s['sceneUuid'] + "\n" await ctx.send(text) except Exception as e: await ctx.send(f'Error: {e}')
!get_scenes
and you'll get a list of all scenes to switch to.
you can also make some complex things like make a website with a specific url to appear
- Make a website to appear!
# first define the screen HEGIHT and WIDTH SCREENW = 1920 SCREENH = 1080 def genr(min_num=1000, max_num=9999): random_number = random.randint(min_num, max_num) return random_number @bot.command() async def cib(ctx, url: str): try: data = obs_client.call(requests.GetCurrentProgramScene()) scene = data.datain['sceneName'] name=genr() response = obs_client.call(requests.CreateInput( inputName=f'{name}', inputKind="browser_source", sceneName=scene, inputSettings={ "height": 200, "reroute_audio": True, "url": url, "webpage_control_level": 1, "width": 200 } )) if response.status: d = obs_client.call(requests.GetSceneItemId(sceneName=scene, sourceName=f'{name}')) tdata = { "positionX": genr(100, SCREENW - 100), "positionY": genr(100, SCREENH - 100), } obs_client.call(requests.SetSceneItemTransform(sceneName=scene, sceneItemId=d.datain['sceneItemId'], sceneItemTransform=tdata)) await asyncio.sleep(30) await ctx.send(f"Welp?") obs_client.call(requests.RemoveInput(inputName=f'{name}')) else: await ctx.send(f'I think it already exists :P') except Exception as e: await ctx.send(f'Error: {e}')
thats all. i use to have fun doing this to troll my friends. hope you too.