最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

wrapping text in obs with python - Stack Overflow

programmeradmin3浏览0评论

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}")

    @commandsmand(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()
发布评论

评论列表(0)

  1. 暂无评论