#  Python program to display a message to the operator for the
#  current scene.
#  Messages are in a datafile read at the beginning of the program
#  and any time the user clicks on the "Scene" button
#  OBS is queried every second to see if the user has changed scenes
#
#  You have to set up websocket access in OBS
#  Tools -> Websocket Server Settings
#  Click "Enable Websocket server" box
#  "Enable Authentication" is on by default I think, but if not
#  check the box to enable 
#  Note the Server Port number and the Server Password

import base64
import hashlib
import time
import json
import websocket
import os
from pprint import pprint
from tkinter import *
import tkinter.font as tkFont

#  This program can run on a different machine than OBS.  Put in the IP address
#  of the system running OBS if that is the case
host = "localhost"
#  Port number is from OBS
port = 4455 
password = "<Password from OBS>"

path = os.path.join('<Path to file>', 'scene_messages.txt')
f = open(path)
messages = json.load(f)
f.close

# Open the websocket connection to OBS
ws = websocket.WebSocket()
url = "ws://{}:{}".format(host, port)
ws.connect(url)

def _build_auth_string(salt, challenge):
    secret = base64.b64encode(
        hashlib.sha256(
            (password + salt).encode('utf-8')
        ).digest()
    )
    auth = base64.b64encode(
        hashlib.sha256(
            secret + challenge.encode('utf-8')
        ).digest()
    ).decode('utf-8')
    return auth



def _auth():
    message = ws.recv()
    result = json.loads(message) 
    server_version = result['d'].get('obsWebSocketVersion')
    auth = _build_auth_string(result['d']['authentication']['salt'], result['d']['authentication']['challenge'])

    payload = {
        "op": 1,
        "d": {
            "rpcVersion": 1,
            "authentication": auth,
            "eventSubscriptions": 1000 
        }
    }
    ws.send(json.dumps(payload))
    message = ws.recv()
    result = json.loads(message)

def _GetCurrentScene():
    payload =  {"op": 6, "d": {"requestId": "GetScene",
                           "requestType": "GetCurrentProgramScene"}}
    ws.send(json.dumps(payload))
    message=ws.recv()
    result = json.loads(message)
    while result['op'] != 7 :
        message=ws.recv()
        result = json.loads(message)
    scene = result['d']['responseData']['sceneName']
    return scene

def _end_program():
    exit()

def _CheckForSceneChange() :
    global curScene, messages,messageVar,window
    newscene = _GetCurrentScene()
    if (newscene != curScene) :
        new_message = ""
        if newscene in messages :
            new_message = messages[newscene]
        btn.config (text=newscene)
        window.update()
        if new_message != "" :
            messageVar.config (text=new_message)
            messageVar.pack()
            window.update()
        else :
            messageVar.pack_forget()
            window.update()
        curScene = newscene
    window.after(1000,_CheckForSceneChange)

def read_messages() :
    global messages
    path = os.path.join('<Path to File>', 'scene_messages.txt')
    f = open(path)
    messages = json.load(f)
    f.close

def _update_messages() :
    global messages
    read_messages()
    if curScene in messages :
        messageVar.config (text = messages[curScene])
        messageVar.pack()
        window.update()
         
_auth()


window = Tk()

window.title("MESSAGE PANEL")

window.geometry('400x500')

mfont = tkFont.Font(family="Helvetica", size=20, weight="bold")

lbl = Label(window, text="MESSAGE PANEL",font=('Helvetica',20,'bold'))
lbl.place(x=100, y=10)
lbl.pack()

curScene = _GetCurrentScene()
btn = Button(window, text=curScene,bd=2, bg="lightgray",\
                 font=("Helvetica",20,'bold'),height=2,\
                 activebackground="red",\
                 fg="blue", command = lambda : _update_messages())
btn.place (x=130, y=50)
btn.pack()

new_message = "Message Area"
if curScene in messages :
    new_message = messages[curScene]
messageVar = Message(window,
                     bg='lightblue',
                     width=350,
                     font=mfont,
                     pady=20,
                     text=new_message)
messageVar.pack()
window.update()

window.after(1000,_CheckForSceneChange)

window.mainloop()

