Давным-давно я построил сервер 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, или загляните на мой сайт!