Давным-давно я построил сервер Twitch Plays 2048, который взаимодействовал с протоколом Twitch IRC, чтобы зрители могли вместе играть в игру. Это был хакерский беспорядок: Chromium не поддерживал удаленное управление из автоматизированного программного обеспечения, протокол чата было трудно реализовать, а общее впечатление от просмотра было некачественным из-за задержек.

Несколько дней назад мы с моим другом говорили о том, что нужно сделать, чтобы создать облако слов в реальном времени из сообщений чата на Twitch. Моей целью было заставить прототип работать менее чем за час. Поехали 🚀.

Хотите сразу перейти к коду? Вы можете ознакомиться с полным репозиторием GitHub здесь.

Архитектура

Сервис состоит из сервера Node.js, который использует tmi.js для подключения к протоколу IRC Twitch.tv с использованием учетной записи бота для прослушивания сообщений чата. Служба также подключается к Redis для выполнения ранжирования слов в реальном времени и сохраняет их для последующего извлечения. Наконец, сервис использует Express для размещения статического HTML-файла с d3-cloud для генерации облаков слов.

Реализация

Сервер

Начнем с создания серверного компонента. Напомним, у сервера есть две основные функции: а) предоставление конечных точек для обслуживания клиентского HTML / REST API и б) подключение к Twitch IRC и запись ключевых слов в Redis по мере их поступления.

В этом разделе я настроил базовый сервер Express, который считывает шаблон index.html (подробнее об этом позже) и обслуживает его на / (root), когда сервер запущен. Он также заменяет CHANNEL_NAME в шаблоне для загрузки определенного канала в браузере.

Затем давайте создадим обработчики событий чата Twitch и наше соединение с Redis.

Во-первых, я использую bluebird для обещания пакета Redis (он не поддерживает Promises на момент написания). Это позволяет нам использовать клиент Redis с async / await. Затем я настраиваю параметры для пакета tmi.js, который удобно обертывает логику связи для протокола Twitch IRC, поэтому нам не о чем беспокоиться. Я создал учетную запись бота и запросил для нее токен OAuth, который мы также передаем в конфигурацию.

Клиент Redis настраивается путем простой передачи строки подключения функции createClient.

Чтобы tmi.js работал правильно, мы должны настроить обработчики событий, наиболее интересно событие message. Это событие запускается для каждого сообщения, поступающего на канал определенного стримера. В нашем onMessageHandler мы берем сообщение, разбиваем его на отдельные слова и вызываем команду Redis ZINCRBY. Это добавляет слово к отсортированному набору канала (ZSET) и увеличивает вхождение на единицу. Со временем это создает отсортированный рекорд слов для определенного канала.

Теперь, когда у нас есть данные, давайте добавим маршрут API к нашему серверу Express, чтобы он отвечал 50 наиболее частыми словами из чата.

Эта конечная точка интенсивно использует команду Redis ZREVRANGE, которая возвращает первые n баллов из нашего отсортированного набора. Аргумент WITHSCORES используется для включения оценок в ответ, который мы позже используем для вычисления относительного размера слова при его отображении. Маршрут содержит параметр :channel, который мы используем для выбора правильного отсортированного набора из Redis.

Это для реализации сервера; Давайте теперь сосредоточимся на клиенте. Для простоты я встроил тег <script> в HTML. Обычно мы обслуживаем отдельный файл 😅. Вы можете увидеть полный HTML в образце репо.

Клиент

Наш клиент сделает одно: сгенерирует облако слов из ключевых слов, которые мы получаем через API. Мы будем использовать d3 и d3-cloud, которые предлагают богатый API для визуализации. Давай перейдем к делу.

Вышеупомянутая функция - это функция, оборачивающая запрос к нашему внутреннему REST API для наиболее частых слов для определенного канала с помощью выборки. Когда мы обслуживаем встроенный сценарий с помощью Express, мы заменяем $CHANNEL_NAME предварительно настроенным каналом. Эта функция возвращает массив объектов в формате [{ text: 'word', size: 10 }, ... ], который мы будем использовать для привязки к функции рендеринга d3-clouds.

Здесь мы настраиваем 500x500 пиксельный холст и привязываем к нему наше облако слов. Функция в основном содержит специальную логику рендеринга d3 для упорядочивания слов и вычисления относительного размера слова. Особый интерес представляет расчет .fontSize():

Мы вычисляем highestScore (самое большое, наиболее частое слово), находя самое большое size в наших данных из API. Затем мы линейно интерполируем относительный размер каждого слова, разделив его на highestScore и умножив на максимальный размер (90 в примере). Это гарантирует, что размер шрифта каждого слова находится в диапазоне от 1 до 90 и что размер слова соответствует его частоте.

В целях тестирования я запустил сервер против канала BobRoss на Twitch примерно на 30 минут, пока он рисовал изображение хижины в лесу.

Вот результат:

Заключение

В этой статье я описал способ использования типа данных Redis sorted set (ZSET) для записи сообщений чата Twitch.tv в реальном времени и создания на их основе облаков слов.

Код очень простой и отнюдь не идеальный. Во время кодирования я придумал множество функций, которые могли бы его улучшить, но попытался ограничить свои усилия одним часом.

В целом, это был забавный проект «Могу ли я сделать это за один час?», Который вышел достаточно приличным.

Некоторые идеи, которые у меня были для версии 2:

  • Позвольте клиенту инициировать канал для мониторинга (в настоящее время встроен сервером)
  • Сбросить функциональность, чтобы начать с нуля.
  • Интерактивно повторно привязать данные облака слов (в настоящее время выполняется перезагрузка)

Спасибо, что нашли время прочитать мою статью. Если вам понравилось, нажмите кнопку «Хлопок» несколько раз 👏! Если эта статья была для вас полезной, не стесняйтесь делиться ею!

Чтобы получить больше от меня, не забудьте подписаться на меня в Twitter, здесь, на Medium, или загляните на мой сайт!

использованная литература