i am building a live translator for Twitch that uses OBS. i am trying to change the size of a text element in OBS using python depending on the size of the text itself, so that the text never goes off the 16x9 border, but i cant seem to figure it out. I don't get any particular error, it just does not change the size of the element or font size. import time import speech_recognition as sr from googletrans import Translator from obsws_python import ReqClient # Use ReqClient for OBS WebSocket 5.x from twitchio.ext import commands # For Twitch chat integration import threading import tkinter as tk from tkinter import messagebox # Global variable to control translation state translation_enabled = False src_lang = 'fr' dest_lang = 'en' # Function to recognize speech from microphone input def recognize_speech_from_mic(recognizer, microphone): with microphone as source: recognizer.adjust_for_ambient_noise(source) audio = recognizer.listen(source) response = { "success": True, "error": None, "transcription": None } try: response["transcription"] = recognizer.recognize_google(audio, language=src_lang) except sr.RequestError: response["success"] = False response["error"] = "API unavailable" except sr.UnknownValueError: response["error"] = "Unable to recognize speech" return response # Function to translate text using Google Translate def translate_text(text, src_lang='fr', dest_lang='en'): translator = Translator() translation = translator.translate(text, src=src_lang, dest=dest_lang) return translation.text # Function to get the transform properties of a source in OBS def get_source_transform(client, scene_name, source_name): # Get the scene item ID response = client.get_scene_item_id(scene_name=scene_name, source_name=source_name) myItemID = response.scene_item_id # Get the transform properties of the scene item response = client.get_scene_item_transform(scene_name=scene_name, item_id=myItemID) transform = { "positionX": response.scene_item_transform.positionX, "positionY": response.scene_item_transform.positionY, "scaleX": response.scene_item_transform.scaleX, "scaleY": response.scene_item_transform.scaleY, "rotation": response.scene_item_transform.rotation, "width": response.scene_item_transform.width, "height": response.scene_item_transform.height, "sourceWidth": response.scene_item_transform.sourceWidth, "sourceHeight": response.scene_item_transform.sourceHeight, "cropLeft": response.scene_item_transform.cropLeft, "cropRight": response.scene_item_transform.cropRight, "cropTop": response.scene_item_transform.cropTop, "cropBottom": response.scene_item_transform.cropBottom, } return transform # Function to set the transform properties of a source in OBS def set_source_transform(client, scene_name, source_name, new_transform): # Get the scene item ID response = client.get_scene_item_id(scene_name=scene_name, source_name=source_name) myItemID = response.scene_item_id # Set the transform properties of the scene item client.set_scene_item_transform(scene_name=scene_name, item_id=myItemID, scene_item_transform=new_transform) # Function to calculate the required scale for the text to fit within the screen def calculate_scale(text, max_width=1920, max_height=1080): """ Calculate the required scale for the text to fit within the screen. """ base_font_size = 50 # Starting font size avg_char_width = 20 # Average width of a character in pixels for font size 50 # Calculate the required width based on text length required_width = len(text) * avg_char_width # Calculate the required scale to fit within the screen width if required_width > max_width: scale = max_width / required_width else: scale = 1.0 # Ensure the scale doesn't go too small scale = max(scale, 0.5) return scale # Function to display text one word at a time with dynamic scaling def display_text_word_by_word(client, text, scene_name="Scene", source_name="TranslatedText", delay=0.5): words = text.split() # Split the text into words for word in words: if not translation_enabled: break # Stop if translation is disabled # Calculate the required scale for the current word scale = calculate_scale(word) # Update the text in OBS client.set_input_settings( source_name, {"text": word}, overlay=True ) # Adjust the scale of the text source transform = get_source_transform(client, scene_name, source_name) transform["scaleX"] = scale transform["scaleY"] = scale set_source_transform(client, scene_name, source_name, transform) time.sleep(delay) # Delay between words # Function to connect to OBS WebSocket def connect_to_obs(host='localhost', port=4455, password='TwitchChat9'): try: print(f"Attempting to connect to OBS WebSocket at {host}:{port} with password: {password}") client = ReqClient(host=host, port=port, password=password) print("Connected to OBS WebSocket server!") return client except Exception as e: print(f"Failed to connect to OBS WebSocket: {e}") return None # Retry logic for OBS WebSocket connection def connect_to_obs_with_retry(host='localhost', port=4455, password='TwitchChat9', retries=5, delay=5): for attempt in range(retries): client = connect_to_obs(host, port, password) if client: return client else: print(f"Retry {attempt + 1}/{retries} failed, retrying in {delay} seconds...") time.sleep(delay) return None # Function to handle live translation def live_translation(obs_client): recognizer = sr.Recognizer() microphone = sr.Microphone() while True: if translation_enabled: print("Listening...") # Recognize speech from the microphone speech_result = recognize_speech_from_mic(recognizer, microphone) if speech_result["success"] and speech_result["transcription"]: # Get the recognized text text = speech_result["transcription"] print(f"Recognized: {text}") # Translate the text translated_text = translate_text(text, src_lang, dest_lang) print(f"Translated: {translated_text}") # Display the translated text one word at a time display_text_word_by_word(obs_client, translated_text) # Non-blocking loop time.sleep(0.5) # Twitch bot class class TwitchBot(commands.Bot): def __init__(self, oauth_token, twitch_username): super().__init__( token=oauth_token, prefix="!", initial_channels=[twitch_username] ) self.oauth_token = oauth_token self.twitch_username = twitch_username async def event_ready(self): print(f"Logged in as {self.nick}") @commands.command(name="translate") async def translate_command(self, ctx): global translation_enabled translation_enabled = not translation_enabled # Toggle translation state status = "enabled" if translation_enabled else "disabled" await ctx.send(f"Live translation is now {status}.") # Function to create the GUI for user input def create_gui(): def start_program(): oauth_token = oauth_token_entry.get() twitch_username = twitch_username_entry.get() obs_password = obs_password_entry.get() if not oauth_token or not twitch_username or not obs_password: messagebox.showerror("Error", "All fields are required!") return # Try connecting to OBS obs_client = connect_to_obs_with_retry(password=obs_password) if not obs_client: messagebox.showerror("Error", "Failed to connect to OBS WebSocket after multiple attempts.") return # Start translation thread translation_thread = threading.Thread(target=live_translation, args=(obs_client,)) translation_thread.daemon = True translation_thread.start() # Start the Twitch bot bot = TwitchBot(oauth_token, twitch_username) bot.run() # This should be called after everything else is ready # GUI Setup window = tk.Tk() window.title("Translation Settings") # Create GUI components tk.Label(window, text="OAuth Token:").grid(row=0, column=0) oauth_token_entry = tk.Entry(window, width=30) oauth_token_entry.grid(row=0, column=1) tk.Label(window, text="Twitch Username:").grid(row=1, column=0) twitch_username_entry = tk.Entry(window, width=30) twitch_username_entry.grid(row=1, column=1) tk.Label(window, text="OBS WebSocket Password:").grid(row=2, column=0) obs_password_entry = tk.Entry(window, width=30) obs_password_entry.grid(row=2, column=1) # Start button start_button = tk.Button(window, text="Start Program", command=start_program) start_button.grid(row=3, columnspan=2) # Language selection (for future feature) def update_languages(): global src_lang, dest_lang src_lang = src_lang_var.get() dest_lang = dest_lang_var.get() tk.Label(window, text="Source Language:").grid(row=4, column=0) src_lang_var = tk.StringVar(window) src_lang_var.set("fr") # Default source language src_lang_menu = tk.OptionMenu(window, src_lang_var, "fr", "en", "es", "de", "ja", "ko", "zh") src_lang_menu.grid(row=4, column=1) tk.Label(window, text="Destination Language:").grid(row=5, column=0) dest_lang_var = tk.StringVar(window) dest_lang_var.set("en") # Default destination language dest_lang_menu = tk.OptionMenu(window, dest_lang_var, "en", "fr", "es", "de", "ja", "ko","zh") dest_lang_menu.grid(row=5, column=1) update_button = tk.Button(window, text="Update Languages", command=update_languages) update_button.grid(row=6, columnspan=2) window.mainloop() # Main function to run the program def main(): create_gui() # Run the program if __name__ == "__main__": main() Continue reading...