Comience a escribir complementos para OBS con Lua

A menudo grabo mis sesiones de D&D con mis amigos que están a distancia a través de OBS. Software de emisora ​​abierta (también conocido como OBS) es un programa de grabación y transmisión multiplataforma popular, gratuito y de código abierto.

Tengo un texto que es una marca de tiempo del día que jugamos D&D en la pantalla para que cada vez que revisemos el metraje, siempre sepamos de qué sesión fue:

Cerrar imagen con marca de tiempo

Pero no quería seguir reescribiendo la fecha manualmente cada vez.

A veces me olvidaba y el metraje tenía la fecha incorrecta y afectaba el orden de los videos. Así que me propuse averiguar cómo escribir un guión en OBS que estableciera la fecha de hoy para mí.

Como beneficio adicional, quería ver si podía agregar un prefijo y sufijo opciones a la fecha también, en caso de que quisiera agregar texto adicional antes o después de la fecha.


OBS está escrito en C, C ++. Pero para los propósitos de esta publicación, es mostrar una de las mejores características de OBS, que es que desde la versión 21.0+, cualquiera puede escribir un script que puede usar «ganchos» que están disponibles para hacer cualquier cosa de manera efectiva.

Documentación de secuencias de comandos de OBS se encuentra aquí y hay dos notas importantes. Puede escribir sus scripts en Python 3 o Luajit 2 (Lua 5.2) que se conectan a los métodos C / C ++ que ejecutan OBS.

A pesar de conocer a Python más que a Lua; esta pequeña tarea que tiene un ciclo iterativo rápido parecía el mejor momento para aprender cómo funciona Lua.


Descubriendo los ganchos de OBS para escribir complementos:

Los ganchos principales de OBS están contenidos en este documento pero me concentré en los siguientes ganchos:

script_load
script_update
script_defaults
script_properties

script_load en el «ciclo de vida» de OBS, se llama cada vez que se crea una nueva fuente o se activa una fuente. Las fuentes son una colección de entradas (audio / video / en movimiento / estática) que se asignan a una escena específica.

script_update se llama siempre que el usuario ha modificado el script que está en uso.

script_defaults se llama siempre que se inicializa el script.

script_properties se llama para cargar todas las opciones posibles para el script.


Ingeniería inversa de un script Lua

Seguí un script que viene precargado con OBS llamado countdown.lua situado dentro de frontend-tools/scripts/ y diseccionó las siguientes cosas:

Para importar la biblioteca OBS

Hay que configurar variables globales

source_name = ""
prefix = ""
suffix = ""

Lua es funcional, todo lo demás es una función de aquí en adelante. Para enganchar en script_properties, uno debe convertirlo en una función:

function script_properties()

   ...

end

Específico obs se deben llamar funciones para registrar la fuente que estamos modificando y las opciones que modificarían la fuente. Mirando a script_properties nuevamente, mostraré el guión que escribí para este gancho:

obs = obslua

source_name = ""
prefix = ""
suffix = ""

function script_properties()
    local props = obs.obs_properties_create()

    local p = obs.obs_properties_add_list(props, "source", "Text Source", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
    local sources = obs.obs_enum_sources()

    -- As long as the sources are not empty, then
    if sources ~= nil then
        -- iterate over all the sources
        for _, source in ipairs(sources) do
            source_id = obs.obs_source_get_id(source)
            if source_id == "text_gdiplus" or source_id == "text_ft2_source" then
                local name = obs.obs_source_get_name(source)
                obs.obs_property_list_add_string(p, name, name)
            end
        end
    end

    obs.source_list_release(sources)

    obs.obs_properties_add_text(props, "prefix", "Prefix Text", obs.OBS_TEXT_DEFAULT)
    obs.obs_properties_add_text(props, "suffix", "Suffix Text", obs.OBS_TEXT_DEFAULT)

    return props
end
  • obs.obs_properties_create() se utiliza para crear una instancia de un props tipo de datos que se asigna a un objeto en C / C ++ para OBS.

  • Paso props dentro obs.obs_properties_add_list(props, "source", "Text Source", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING) crea una lista desplegable que tiene una cara de usuario Text Source que asigna sus valores a "source".

El bucle que comienza aquí:

local sources = obs.obs_enum_sources()

    -- As long as the sources are not empty, then
    if sources ~= nil then
        -- iterate over all the sources
        for _, source in ipairs(sources) do

se llama cargando todas las fuentes que tiene el usuario, asegurándose de que exista al menos una y luego iterando sobre ellas. Solo quiero orientarme a fuentes para las que la fuente es solo una fuente de texto. Eso es lo que está pasando aquí:

for _, source in ipairs(sources) do
            source_id = obs.obs_source_get_id(source)
            if source_id == "text_gdiplus" or source_id == "text_ft2_source" then
                local name = obs.obs_source_get_name(source)
                obs.obs_property_list_add_string(p, name, name)
            end
        end

Si la fuente tiene una identificación interna de "text_gdiplus" o "text_ft2_source", tomamos el nombre de esa fuente y modificamos las propiedades de la lista anterior y agregamos el name de esa fuente en el menú desplegable.

Nota importante, todavía está escribiendo en C / C ++

A pesar de que podemos escribir estos scripts en Lua o Python, estos scripts están vinculados a los componentes internos de C / C ++ de OBS y, por lo tanto, siguen las mismas reglas de necesidad de liberar memoria siempre que ya no necesitemos el recurso.

Eso significa que si lo hacemos: local sources = obs.obs_enum_sources(), una vez que hayamos terminado de jugar con el sources, nosotros necesitar para liberar esto de la memoria haciendo lo siguiente:

obs.source_list_release(sources)

El hecho de que estemos usando lenguajes de nivel superior en este script no significa que podamos olvidarnos de la gestión de la memoria.

La última parte es la necesidad de agregar una opción para el prefijo y sufijo y téngalo disponible como un campo de texto libre para que el usuario lo complete:

    obs.obs_properties_add_text(props, "prefix", "Prefix Text", obs.OBS_TEXT_DEFAULT)
    obs.obs_properties_add_text(props, "suffix", "Suffix Text", obs.OBS_TEXT_DEFAULT)

Una vez que hayamos terminado con la configuración del script, necesitamos devolver el props:

Script cargado


Los otros 3 «ganchos» para esta implementación se pueden ver en mi página de Github, donde he puesto este código a disposición de cualquier otra persona:

https://github.com/hectorleiva/obs_current_date