Pytchat y AsyncIO... ¿Cómo hago?

Buenas, gente. Primero, la introducción: uso OBS y me conecto con él mediante obs-websockets, usando obs-websockets-py. Lo vengo usando muy bien y descubrí que cada comando que envío a websocket, hay un delay… que puede ser eliminado si la tarea la hago usando threading:

...
def source_set_video_file(source_input, video_file):
    ws.call(requests.SetSourceSettings(source_input, sourceSettings={'local_file': video_file})

threading.Thread(target=source_set_video_file, args=('archivo.mp4')).start()`)

Solo con esto, evado ese delay y puedo enviar muchos comandos a OBS y se ejecutan en tiempo.

También conecto mi código con PureData mediante mensajes OSC.

Ahora… quiero ejecutar pytchat (librería que captura el chat en vivo de un video de YouTube) dentro de mi código. Pero necesito poner este código ejecutándose paralelamente al resto de mi código, porque si no, se me bloquea todo. Primero intenté hacerlo como lo expliqué más arriba, con threading. Pero al hacerlo con este método, me devuelve error:

Traceback (most recent call last):
  File "/usr/lib/python3.7/threading.py", line 917, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.7/threading.py", line 865, in run
    self._target(*self._args, **self._kwargs)
  File "/media/ssd-120gb/videoconfestejo/scripts/j_ytchat.py", line 61, in chat
    chat = pytchat.create(video_id=video_id)
  File "/media/ssd-120gb/videoconfestejo/scripts/pytchat/core/__init__.py", line 7, in create
    return PytchatCore(_vid, **kwargs)
  File "/media/ssd-120gb/videoconfestejo/scripts/pytchat/core/pytchat.py", line 84, in __init__
    signal.signal(signal.SIGINT, lambda a, b: self.terminate())
  File "/usr/lib/python3.7/signal.py", line 47, in signal
    handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler))
ValueError: signal only works in main thread

No entiendo ni goma qué quiere decir con eso… así que, mirando en wiki de pytchat, hay una version LiveChatAsync. Si hago tal cual dice en la wiki, el código se ejecuta bien. El código sería este:

from pytchat import LiveChatAsync
import asyncio

async def main():
  livechat = LiveChatAsync("uIx8l2xlYVY", callback = func)
  while livechat.is_alive():
    await asyncio.sleep(3)
    #other background operation.

  # If you want to check the reason for the termination, 
  # you can use `raise_for_status()` function.
  try:
    livechat.raise_for_status()
  except pytchat.ChatDataFinished:
    print("Chat data finished.")
  except Exception as e:
    print(type(e), str(e))

#callback function is automatically called periodically.
async def func(chatdata):
  for c in chatdata.items:
    print(f"{c.datetime} [{c.author.name}]-{c.message} {c.amountString}")
    await chatdata.tick_async()


if __name__=='__main__':
  try:
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
  except asyncio.exceptions.CancelledError:
    pass

Pero como no soy programador, me cuesta muchísimo entender asyncio. Lo que yo necesito es ejecutar pytchat en paralelo a el resto de mi código. O sea y como ejemplo, que en una linea mande a ejecutar pytchat y en la siguiente, algo así:

while True:
    print('¡Chancho!')
    time.sleep(1)

¿Cómo puedo lograr esto?

La forma que se me ocurre, dentro de mis conocimientos, pero se trata de algo muy desprolijo es ejecutar pytchat en otra ventana y comunicarlo por OSC con la principal, como lo hago con PureData. Pero noooo eeees looo queee quieeeroooo…

Posteé esta duda en el Github de pytchat y el desarrollador me dijo que agregue interruptable=False al constructor.

# "/media/ssd-120gb/videoconfestejo/scripts/j_ytchat.py", line 61
-    chat = pytchat.create(video_id=video_id)
+    chat = pytchat.create(video_id=video_id, interruptable=False)

Y vualá… parece que funciona de maravillas con threadding, sin tener que meterme en el mundo de asyncio.

1 me gusta