Cómo hacer una extensión de Chrome con filtro de blasfemias para Twitch

Ingeniero de Nintendo
28 de diciembre, 2020 – 7 min read

Hago muchos proyectos relacionados con Twitch aquí y allá, tratando de ver cuáles son las posibilidades. Uno de mis últimos proyectos consistió en crear una extensión de Twitch Emote para Chrome en la que mostraba cómo conseguir «ranuras» de emote adicionales de forma gratuita. Eso me llevó a las extensiones del navegador, así que pensé en mostrar cómo hacer uno desde cero mediante la construcción de un filtro de blasfemia para el chat de Twitch.

Al final de esto, queremos tener una extensión que, cuando se instala, comprueba un conjunto de palabras marcadas en el chat y las sustituye por versiones más amigables. Esto podría ser útil para los niños que ven streams, por ejemplo.

Si sólo quieres el código para esta extensión, hay un enlace al resultado final en la parte inferior de este artículo.

De acuerdo, así que vamos a entrar en él de cabeza. Crea una carpeta en algún lugar que te guste y llámala profanity-filter. Yo he creado la mía en un lugar en el que me sincronizo con GitHub.

Cualquier nombre sirve, pero este parece adecuado

Ahora, dentro de esta carpeta, crea dos archivos nuevos: manifest.json y content.js. Ya verás cómo los usaremos cuando construyamos la extensión.

Ahí vamos

Abre manifest.json, que es el archivo que Google busca los metadatos relativos a tu extensión, y pega lo siguiente en él:

{ "manifest_version": 2, "name": "Twitch Profanity Filter Extension", "version": "0.1", "content_scripts": , "js": } ]}

Como puedes ver, le estamos diciendo a Google que esta extensión debería funcionar en cualquier página de Twitch y también estamos diciendo que la lógica que debería ejecutarse en estas páginas reside en el archivo llamado content.js. Ten en cuenta que he puesto la versión como 0.1, ya que este es mi intento inicial.

Consiguiendo la lógica en

Ahora abre content.js en el editor de texto de tu elección. Yo recomendaría encarecidamente Visual Studio Code, es mi editor de texto go-to para cualquier cosa relacionada con la codificación y es gratis.

Ahora, la forma en que vamos a configurar esto es en unos pocos pasos. ¿Qué queremos lograr y cómo vamos a lograrlo? Sabemos que queremos cambiar ciertas palabras por otras, lo que significa leer los mensajes del chat, escanearlos en busca de palabras marcadas y luego actualizar esas palabras por otras más amigables. Así que cuando la página se cargue, queremos que nuestra lógica sea capaz de hacer lo siguiente:

  • Buscar el chatbox
  • Cada vez que aparezca un nuevo mensaje de chat, obtener el mensaje o el contenedor de mensajes
  • Cambiar las palabras marcadas por sus equivalentes amigables

Así que vamos a ello. La primera parte es realmente activar el script cuando la página, o más específicamente la ventana, se ha cargado. En javascript, se puede enganchar en ese evento de carga y vamos a hacer precisamente eso. Actualiza tu content.js para que contenga lo siguiente:

Eso asegurará que cualquier cosa que pongamos dentro de esa función, sea llamada cuando la página se haya cargado.

Busca el chatbox

¿Y cómo encontramos el chatbox? Bueno, en la versión de Chrome del sitio web de Twitch, el chatbox está contenido en un elemento <div> que tiene una clase llamada chat-scrollable-area__message-container. Vamos a obtener ese elemento, o nodo, a través de javascript. Actualiza el archivo para que quede así:

La razón por la que añadimos .item(0) detrás, es porque getElementsByClassName() devuelve un array de elementos. Como sabemos que sólo un elemento tiene esta clase, lo tomamos del array especificando que queremos lo primero (la mayoría de los lenguajes de programación empiezan a contar en 0).

Obtener cada nuevo mensaje en el chat

Esto es un poco más complicado de entender si no estás acostumbrado a programar o no estás acostumbrado a los patrones de los observadores. La forma en que vamos a obtener cada nuevo mensaje es utilizando un MutationObserver en el nodo del chatbox que acabamos de recoger. Actualiza el archivo para que coincida con lo siguiente y luego recorreremos lo que sucede:

Primero, en la línea 4, definimos una función callback que toma una lista de mutaciones y el observador que crearemos en la línea 8. La lógica de esta función es la que se llama cada vez que algo cambia, o muta, en el nodo que estamos observando.

En la línea 8 creamos el observador y le pasamos nuestra función callback. Luego, en la línea 9, le decimos al observador que empiece a observar nuestro nodo objetivo y le pasamos una configuración que dice que sólo nos interesan las mutaciones a la childList. Los mensajes aparecen como nodos hijos del nodo chatbox que estamos observando, por lo que nuestra función callback se activará cada vez que aparezca un nuevo mensaje de chat. ¡Eso es exactamente lo que queremos!

Pero ahora todavía tenemos que obtener los elementos de los mensajes reales y para ello añadimos una línea más de código en nuestro callback:

El nombre puede parecer un poco extraño, pero todas las partes de texto de un mensaje (no estamos escaneando emotes, sólo los textos reales) se colocan en <span> elementos HTML que tienen la clase texto-fragmento. Además, como esta función se activa con cada nuevo mensaje, sabemos que el mensaje que queremos debe ser el último elemento del nodo del chatbox, así que por eso cogemos el lastElementChild.

Cambiar las palabras marcadas por sus equivalentes amigables

Vayamos a la parte más jugosa. Si queremos cambiar las palabras marcadas, primero necesitamos algo que nos diga cuáles son las palabras marcadas y sus equivalentes. Para ello, utilizaremos un simple diccionario. Actualiza el archivo para que se vea así:

Puedes añadir más palabras si quieres, sólo recuerda la coma al final

Ahora vamos a leer el texto real en todos los elementos del fragmento de texto, hacer un bucle sobre todas las palabras prohibidas y reemplazarlas si es necesario. Vamos a empezar ese bucle, así que actualiza tu función de devolución de llamada con lo siguiente:

Lo que ocurre aquí es que estamos recorriendo todos estos elementos que contienen texto. En la línea 18 estamos tomando un elemento específico a la vez y en la línea 19 obtenemos el texto real de él en minúsculas, porque nuestras palabras marcadas están todas en minúsculas también. Esto facilita la comparación, pero en una versión más avanzada nos encargaríamos de mantener las mayúsculas y minúsculas. Ahora que tenemos nuestro texto, queremos hacer un bucle sobre nuestras palabras marcadas y comprobar si están presentes. Si es así, las eliminamos. Actualiza la función:

El diccionario que hicimos funciona con pares clave-valor, donde las claves son las palabras marcadas y los valores son las palabras amigables, así que en la línea 21 simplemente obtenemos un array de todas las claves, que es el array de palabras marcadas que queremos recorrer. En el bucle tomamos la palabra marcada que estamos viendo actualmente y si nuestro texto incluye una o más de ellas, tomamos la palabra amigable y actualizamos nuestro texto reemplazando las palabras marcadas. Eso es casi todo, ahora sólo tenemos que coger nuestro nuevo y mejorado texto y ponerlo de nuevo en el elemento del que lo hemos cogido:

¡En la línea 31 ya hemos colocado el texto de nuevo en el elemento y eso es todo! Vamos a probar esto en Chrome.

La prueba

Abre Chrome y navega hasta chrome://extensions. Deberías ver tus extensiones y en la parte superior derecha verás el modo desarrollador. Actívalo si aún no lo está. Después, en la parte superior derecha, verás la opción Load unpacked. Vamos a usarla para cargar nuestra extensión local sin tener que pasar por la ruta de la Chrome Web Store todavía. Haz clic en ella y selecciona la carpeta donde se encuentran los archivos:

Eso debería hacer que aparezca al instante en nuestra lista de extensiones:

¡Bien! Ahora vamos a cualquier canal donde podamos charlar. Iré al canal de mi amigo Bjarke, un divertidísimo streamer danés, y lo probaré:

¡Ya está, funciona! Nuestro propio filtro de blasfemia. No fue tan difícil, ¿verdad? Sólo queda lanzarlo en la Chrome Web Store si se quiere. Iré ampliando esta lista de palabras y liberando esto, así que si no necesitas más que esto, no tienes que liberarlo, ya que requiere una cuota para entrar en el programa. No voy a entrar en cómo funciona la liberación, pero si usted está interesado, hice una extensión de Twitch Emote para obtener sus propias ranuras ilimitadas emote y este artículo explica cómo liberar extensiones al final.

Si quieres ver todo el código de esta extensión, echa un vistazo a la repo de GitHub aquí. Feliz codificación!