Files
2025-09-12 10:01:18 -04:00

102 lines
2.7 KiB
Python

from roku import Roku
import os
import json
import threading
ROKU_IP = os.environ.get("ROKU_IP")
if not ROKU_IP:
print("Roku IP not found in env!")
COMMANDS = {
# Standard Keys
"home": "Home",
"reverse": "Rev",
"forward": "Fwd",
"play": "Play",
"select": "Select",
"left": "Left",
"right": "Right",
"down": "Down",
"up": "Up",
"back": "Back",
"replay": "InstantReplay",
"info": "Info",
"backspace": "Backspace",
"search": "Search",
"enter": "Enter",
"literal": "Lit",
# For devices that support "Find Remote"
"find_remote": "FindRemote",
# For Roku TV
"volume_down": "VolumeDown",
"volume_up": "VolumeUp",
"volume_mute": "VolumeMute",
# For Roku TV while on TV tuner channel
"channel_up": "ChannelUp",
"channel_down": "ChannelDown",
# For Roku TV current input
"input_tuner": "InputTuner",
"input_hdmi1": "InputHDMI1",
"input_hdmi2": "InputHDMI2",
"input_hdmi3": "InputHDMI3",
"input_hdmi4": "InputHDMI4",
"input_av1": "InputAV1",
# For devices that support being turned on/off
"power": "Power",
"poweroff": "PowerOff",
"poweron": "PowerOn",
}
class RokuWrapper():
def _send_msg(self, code: int, msg: object):
try:
content = json.dumps(msg).encode()
self.parent._send(code, content)
except Exception as e:
print(e)
def __init__(self, parent):
self.parent = parent
# eh maybe close the connection? Not really needed
self.timer: threading.Timer | None = None
try:
self.rapp = Roku(ROKU_IP)
print(f"Roku client connected to {ROKU_IP}", flush=True)
except Exception as e:
self.parent.log_error("Failed to create Roku client: %s", e)
return self._send_msg(500, {"error": "roku connection failed"})
def run_command(self, command: str):
if not ROKU_IP:
return self._send_msg(500, {"error": "Roku IP not found in env! Do not attempt further Roku requests"})
if not command:
return self._send_msg(404, {"error": "command not given"})
command = command.split('/')[0]
# If command is not known, nothing to do
if command not in COMMANDS:
return self._send_msg(404, {"error": f"unknown command. Available commands: {", ".join(COMMANDS.keys())}"})
if hasattr(self.rapp, command):
attr = getattr(self.rapp, command)
if callable(attr):
attr()
return self._send_msg(200, {"result": f"{command} executed"})
# Fallback: send the Roku key name using common API methods
key_name = COMMANDS[command]
# common method names in Roku libs
for send_fn in ("press", "keypress", "send_key", "send_keypress", "button"):
if hasattr(self.rapp, send_fn):
fn = getattr(self.rapp, send_fn)
try:
fn(key_name)
return self._send_msg(200, {"result": f"{command} sent as {key_name} via {send_fn}"})
except TypeError:
continue
self._send_msg(404, {"error": "unknown endpoint"})