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.


Author: ashandme Date: 2025-02-10 Mon 00:39