Seguro que conoceis la plataforma de streaming de moda Twitch, aquí tenéis el link a mi canal, donde a veces hago directos frikeando. La cosa, es que esta plataforma tiene una API para python (entre otros lenguajes), que te permite hacer unos bots, que responden a comandos del chat. De echo, cuando estuve probando a programarlo, lo estaba emitiendo en Twitch, así que lo podéis ver ahí 🙂

Total que el otro día me pregunté, ¿Cómo podría hacer un bot de Twitch en Python? Y aquí os traigo el resultado, un inicio, para luego podáis añadirle todo lo que queráis. Con vosotros, el tutorial del bot de Twitch!

Preparando el entorno

Antes de ponernos a programar necesitamos preparar un par de cosillas:

  1. Tener una cuenta en Twitch.
  2. Instalar Python 3.6 o superior.
  3. Instalar TwitchIO para Python pip install twitchio
  4. Obtener tu clave OAuth de https://twitchapps.com/tmi/
  5. Registrar una aplicación para el Client_ID https://dev.twitch.tv/console/apps/create
  6. Empezar a programar 😀

Esta primera parte no tiene mucho misterio, básicamente es importante guardar la clave de OAuth, y el Client_ID de la aplicación.

Ejemplo más básico

Básicamente, lo que vamos a usar del paquete twitchIO es el bot. Este bot, se encargará de recibir los comandos de nuestro canal, y ejecutar cosas cuando se reciban. Por ejemplo, vamos a hacer un ejemplo muy tonto en el que:

  • Nos conectamos a nuestro canal de Twitch
  • Avisamos de que estamos ahí
  • Activamos el comando !test

Archivo de configuración

Antes de empezar a picar el código, necesitamos generar un fichero de configuración. En realidad, no es necesario pero altamente recomendable. En este fichero pondremos los datos que no deberemos compartir nunca con nadie. En este fichero guardaremos el OAuth y el Client_ID por ejemplo, entre otras cosas:

TOKEN=oauth:....
CLIENT_ID=....
BOT_NICK=....
BOT_PREFIX=!
CHANNEL=....tu canal...

Este fichero así tan sencillo, yo lo he llamado config.secret, así que ahora solo tenemos que hacer una función que lea el fichero y nos devuelva los datos del mismo. Esto lo hacemos muy fácilmente leyendo cada línea y separándolo por el símbolo igual(=). Además lo vamos a guardar en un diccionario para luego poder usar cada campo con su nombre.

with open("config.secret","r") as fp:
   lines = fp.readlines()
   config = {}
   for line in lines:
   partes = line.replace("\n","").split("=")
       config[partes[0]] = partes[1]

Hasta aquí todo es muy sencillo y fácil, ya tenemos nuestra configuración cargada y lista para usarse.

Creando el bot

Crear el bot es muy sencillo, el constructor simplemente tiene, casualmente…, los mismos campos que nuestro fichero de configuración. Así que solo hay que pasarle los campos con sus nombres y lo tendríamos creado.

bot = commands.Bot(
     irc_token=config['TOKEN'],
     client_id =config['CLIENT_ID'],
     nick=config['BOT_NICK'],
     prefix=config['BOT_PREFIX'],
     initial_channels=[config['CHANNEL']]
 )

Si os fijais, la lista de canales es un array en sí mismo, porque parece ser que se le pueden mandar muchos canales. En principio, como lo queremos usar en el nuestro, con uno nos vale

Manejando eventos

Para crear los eventos, tenemos que definir funciones async, que se encargarán de ejecutarse cuando pase cualquier evento, con evento se entienden mensajes, comandos, o lo que sea. Todo lo que pase en vuestro canal pasará por aquí.

@bot.event
async def event_ready():
    print(f"{data['BOT_NICK']} online!")
    ws = bot._ws  # solo se necesita en event_ready
    await ws.send_privmsg(data['CHANNEL'], f"/Ha llegado")

@bot.event
async def event_message(ctx):
    'Runs every time a message is sent in chat.'
    print(ctx.author.name)

En este punto, ya se puede lanzar el bot y ver que funciona.

Lanzando el bot

Ponerle una sección a esto es tontería, pero me apetecía que apareciese en el índice, por si alguien quiere venir solo a esta parte. Lanzar el bot es literalmente una línea:

bot.run()

Cuando ejecutéis esto igual veis errores en la consola, pero no os preocupéis, lo importante es que en el chat del Twitch os tendría que salir algo como: “Tu canal ha llegado!”. Si no lo veis, tendréis que ir comprobando que habéis hecho todo los pasos correctamente, mirad que el oauth y el client_id, están bien puestos.

Añadiendo comandos al chat

Nada de esto sería divertido si no se pudiese hacer que interactuáse con algo, mi idea es hacer algún cacharro que se maneje a través del chat :D.

Para ello tenemos un decorador de python @bot.command(name="test") donde generamos el comando ‘test’ y después de el tenemos que definir la función con el mismo nombre que el evento!

En este ejemplo vamos a saludar a quien nos manda el test. En la variable de entrada ‘ctx’ recibimos un context del cual podemos recibir varios datos (más info en la API). 

@bot.command(name='test')
async def test(ctx):
    print(ctx)
    await ctx.send(f'Test Pasado! Gracias {ctx.author.name}')


#Cambiamos el manejador de mensajes, para que maneje los comandos
@bot.event
async def event_message(ctx):
    'Runs every time a message is sent in chat.'
    await bot.handle_commands(ctx)

Si ahora en nuestro chat alguien escribe !test se podrá ver que el bot le saluda de vuelta! y esto sería todo lo básico que necesitas para poder hacer tus bots de Twitch. Ahora te pongo un par de ejemplos de eventos que he creado par que veas ejemplos de lo que se puede hacer además de como juntar todo esto en una clase para que sea más manejable.

No te olvides dejarme un comentario con tu bot creado!

El bot en una clase

from twitchio.ext import commands

class Bot(commands.Bot):

    def __init__(self):

        nick = ""
        chanel = ""
        with open("config.secret","r") as fp:
            lines = fp.readlines()
            config = {}
            for line in lines:
                partes = line.replace("\n","").split("=")
                config[partes[0]] = partes[1]


            super().__init__(
                irc_token=config['TOKEN'],
                client_id =config['CLIENT_ID'],
                nick=config['BOT_NICK'],
                prefix=config['BOT_PREFIX'],
                initial_channels=[config['CHANNEL']]
            )

            self.nick = config['BOT_NICK']
            self.channel = config['CHANNEL']
            

    
    async def event_ready(self):
        print(f'Listo! | {self.nick}')
        ws = self._ws 
        await ws.send_privmsg(self.channel, f"/me has landed!")

    async def event_message(self, message):
        print(message.content)
        await self.handle_commands(message)

    # Decorador para los comandos
    @commands.command(name='saludo')
    async def saludo(self, ctx):
        await ctx.send(f'Hola {ctx.author.name}!')

Ejemplos

Votación

votos = {'si': 0, 'no':0}

@bot.command(name='votar')
async def prueba(ctx):
    global votos
    if "si" in ctx.message.raw_data:
        votos['si'] = votos['si'] + 1
        await ctx.send(f'Voto "si" contado!')
    elif "no" in ctx.message.raw_data:
        votos['no'] = votos['no'] + 1
        await ctx.send(f'Voto "no" contado!')
    else:
        await ctx.send(f'Vota algo decente!')

    if votos['si'] + votos['no'] >= 5:
        await ctx.send(f'Resultado: Si:{votos["si"]}/{votos["no"]}:No')

Apuntarse o borrarse de una lista

@commands.command(name="apuntame")
async def apuntame(self, ctx):
    with open("apuntados.txt","r+") as fp:
        gente = fp.readlines()
        encontrado = False

        if len(gente) > 0:
            
            for p in gente:
                if ctx.author.name == p:
                        encontrado = True
                        break
            
            if encontrado:
                print("Encontrado!")
                await ctx.send(f'Maj@, ya estás en la lista!')

        if not encontrado:
            print("No estaba antes")
            fp.write(str(ctx.author.name)+"\n")
            await ctx.send(f'Gracias {ctx.author.name}, apuntado!')


@commands.command(name="quienes")
async def quienes(self, ctx):
    with open("apuntados.txt","r+") as fp:
        gentes = fp.readlines()
        agrupados = ""
        if len(gentes) > 0:
            for p in gentes:
                agrupados = agrupados + p + ";" 
        texto_out = "De moment sois: " + agrupados[0:100]+"..."
        await ctx.send(texto_out)

Gluón

Teleco con ganas de aprender más y compartirlo. Viajero empedernido y amante de la fotografía y la tecnología. Espero dejar mi granito de arena y que este pueda servir de ayuda.