Twitch Extensions (Расширения Twitch) — это новая система взаимодействия стримеров и зрителей, предоставленная разработчиками популярной стриминговой платформы Twitch пару лет назад. Этот способ позволяет разработчикам дополнять и улучшать интерфейс как сайта, так и мобильного приложения, создавая различные интерактивные элементы. В этой статье я расскажу, как работают расширения для Twitch и как создать такое расширение самому.
Бэкенд
Самое главное — интерактивность и налаженное взаимодействие между пользователями и стримером. Для этого нам потребуется хороший сервер.
Такой сервер для расширений Twitch называется Extension Backend Service (EBS). В отличие от фронтенда, ответственность за непрерывную работу которого берет на себя Twitch, хостинг и размещение EBS стриминговым сервисом не обеспечивается — а значит, эту проблему нам нужно решать самостоятельно.
Бэк состоит из нескольких частей.
- Общение с пользователями и верификация JWT. Twitch для каждого человека, который активирует расширение, генерирует уникальный токен JWT, подписанный секретным ключом. Это позволяет идентифицировать пользователя, не раскрывая его персональных данных, и отделять настоящих зрителей от ботов, спама и DDoS.
- Обработка действий пользователей внутри расширения. Это может быть, например, подсчет голосов зрителей или работа с базой данных.
- Взаимодействие с Twitch API и в первую очередь с PubSub — сервисом, который позволяет фронтенду и бэкенду общаться без задержек.
Здесь мы используем популярное и надежное решение — ExpressJS. Для хостинга бэкенда можно использовать любой сервис, даже собственный ПК. Для небольших разработок нам пригодится сервис Heroku, который, помимо хостинга, предоставит удобоваримый URL.
Фронтенд
Фронтенд каждого расширения состоит из одного или нескольких экранов (view), они бывают разных типов и вместе составляют пользовательский интерфейс.
- Mobile extension — специальный блок, предназначенный для показа внутри официального приложения Twitch с помощью WebView.
- Video-overlay extension — виджет, который накладывается поверх всего видео (максимум на один стрим).
- Video-component extension — блок, который занимает лишь часть видеопотока. Стример может расположить его на свое усмотрение.
- Panel extension — полностью настраиваемая панель, которая отображается не поверх видео, а внизу, вместе с другими панелями.
Кроме различных view, предназначенных для зрителей, есть также два view для самого стримера, которые нужны для управления расширением.
- Live-config (Live Dashboard) — настройки, доступные в прямом эфире, прямо в дашборде — там же, где и все остальные самые необходимые элементы управления.
- Config (Configuration) — параметры, которые устанавливаются при инсталляции расширения (или в отдельном меню всех расширений).
На самом деле каждый из этих view — это не более чем специально оформленный тег <iframe> или отдельный WebView (для телефонов), который занимается отображением своего интерфейса и обработкой действий пользователя. Именно поэтому, чтобы упростить разработку фронтенда, мы используем React.
РЕКОМЕНДУЕМ:
Как самому создать игру
Создание расширения для Twitch
Теперь давайте я на примере покажу, как написать основу для собственного расширения. Пусть это будет онлайновое голосование с обновлением голосов в реальном времени.
Упростить разработку расширений для Twitch помогает специальное приложение, которое работает в Windows, macOS или Linux. Оно называется Twitch Developer Rig и нужно исключительно для создания и тестирования расширений.
Developer Rig
При запуске программа предложит вам войти через свой аккаунт на Twitch, и только после этого можно начинать работу.
Здесь нужно выбрать для своего расширения уникальное имя, которое не только не используется сейчас, а вообще никогда никем не использовалось.
На этом шаге нам предлагают выбрать папку, где будет располагаться проект, и основу для проекта.
Если ты выберешь какой-либо базовый код, то он будет клонирован с официального репозитория Twitch на GitHub.
Фронт
Для работы расширения Twitch предоставляет специальный пользовательский интерфейс, который доступен в коде страницы через объект window.Twitch.ext. Этот интерфейс используется в первую очередь для управления событиями.
Ключевое событие — это, конечно, появление пользователя. Оно называется onAuthorized() и получает данные юзера: его токен (со всеми правами доступа — стример или зритель) и идентификатор.
Другое важное событие, onContext(), передает расширению данные об окружении во время инициализации (например, какой используется браузер).
Кроме того, API предоставляет возможность подписаться на события Twitch PubSub.
Создадим основу клиентского приложения — video_component.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
import React from 'react'; export class App extends React.Component { constructor() { super(); this.twitch = window.Twitch.ext; this.state = { active: false, poll: [], }; this.twitch.onAuthorized(this.authorize); } async authorize({ token, userId }) { this.token = token; this.userId = userId; const result = await fetch(`${host}/poll`, { headers: { Authorization: `Bearer ${this.token}`, }, method: 'GET' }); this.setState(result); } render() { const { active, poll, } = this.state; return ( <> /* код отображения */ </> ); } } |
Код, который будет отображаться у стримера в панели ( config):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
import React from 'react'; export class App extends React.Component { constructor() { super(); this.twitch = window.Twitch.ext; // Сохраним для быстрого доступа this.state = { active: false, poll: [], role: null, }; // Пустое состояние — новое будет загружено с сервера this.twitch.onAuthorized(this.authorize); } async authorize({ token, userId }) { this.token = token; this.userId = userId; // Получаем токен из данных от Twitch const { role, } = await jwt.decode(token); // Проверяем роль пользователя (на всякий случай) const result = await fetch(`${host}/poll`, { headers: { Authorization: `Bearer ${this.token}`, }, method: 'GET', }); // Запрашиваем актуальные данные this.setState({ ...result, role, }); } render() { const { active, poll, role } = this.state; if (role !== 'broadcaster') { /* * Проверка, является пользователь * настоящим стримером или нет */ return null; } return ( <> /* код отображения */ </> ); } } |
Бэк
Основная задача нашего бэкенда — хранить и распространять опросы, созданные стримерами, и собирать голоса пользователей, для чего пригодится база данных, например MongoDB. Кроме этого, стоит обратить внимание на обработку заголовков CORS, так как запросы будут идти от имени сервера Twitch.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
import express from 'express'; import jwt from 'jsonwebtoken'; import cors from 'cors'; const app = express(); var polls = []; // Маленькая база данных function getPoll(chanell_id) { /* * Получить опрос из базы данных * или из переменной (ради простоты) */ const poll = polls[chanell_id]; if (poll) { return poll; } else { // Стример не активировал опрос // Возвращаем пустые данные return { active: false, poll: [], }; } } /* * Здесь можно связываться с базой данных * и обновлять данные */ function setPoll(channel_id, poll) { polls[channel_id] = poll; } function deletePoll(channel_id) { polls[channel_id] = null; } function votePoll(channel_id, vote) { if (polls[chanell_id] && polls[channel_id].poll[vote]) { polls[channel_id].poll[vote].votes += 1; } } app.use(express.json()); app.use(cors()); // CORS-заголовки app.use(async (req, res, next) => { const auth = req.get('Authorization'); if (!auth.startsWith('Bearer ')) { res.sendStatus(403); // Данные авторизации не были предоставлены return; } const token = auth.slice(7); // Пропускаем 'Bearer ' try { req.user = await jwt.verify(token, Buffer.from(process.env.SECRET, 'base64')); } catch (e) { res.sendStatus(403); // Неверный или истекший токен return; } next(); }) // Разрешаем всем пользоваться нашим расширением app.options('/poll', cors()); app.get('/poll', (req, res) => { const { chanell_id } = req.user; const poll = getPoll(chanell_id); res.json(poll); }); app.post('/poll', (req, res) => { const { chanell_id, role, } = req.user; if (role !== 'broadcaster') { res.sendStatus(403); // Пользователь — не владелец канала return; } setPoll(chanell_id, req.body); res.sendStatus(200); }); app.delete('/poll', (req, res) => { const { channel_id, role, } = req.user; if (role !== 'broadcaster') { res.sendStatus(403); // Пользователь — не владелец канала return; } deletePoll(channel_id); res.sendStatus(200); }); app.post('/vote', (req, res) => { const { channel_id, } = req.user; votePoll(channel_id, req.body.vote); res.sendStatus(200); }); app.listen(process.env.PORT || 8080); |
Теперь, когда есть все составные части, дело за малым — запустить это!
РЕКОМЕНДУЕМ:
Как писать читы для игр
Развертывание и публикация расширения
В первую очередь нам необходим работающий бэкенд. Создадим в папке с файлом, содержащим код сервера, репозиторий Git и файл package.json (с помощью npm init). При инициализации укажите в качестве точки входа (entry point) свой файл.
Затем необходимо закоммитить изменения, создать приложение Heroku и запустить его.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
$ git init Инициализирован пустой репозиторий Git в backend/.git/ $ npm init -y Wrote to backend/package.json: { "name": "backend", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" } $ heroku create miracles-polls Creating ⬢ miracles-polls... done https://miracles-polls.herokuapp.com/ | https://git.heroku.com/miracles-polls.git $ git add . $ git commit -m "Version 1.0" $ git push heroku master remote: Compressing source files... done. remote: Building source: remote: -> Node.js app detected ... remote: -> Build succeeded! remote: -> Compressing... remote: Done: 19.9M remote: -> Launching... remote: Released v3 remote: https://miracles-polls.herokuapp.com/ deployed to Heroku remote: Verifying deploy... done. |
Так, наш сервер запущен и уже ждет новые опросы. Займемся фронтендом.
Для улучшения качества загрузки хостинг этой части Twitch целиком берет на себя, поэтому, чтобы наше расширение стало доступно, нужно зайти в консоль разработчика расширений, в раздел управления вашим расширением, выбрать версию (у нас пока она одна), затем открыть вкладку Go to Files.
Кроме загрузки файлов, в других вкладках можно настроить параметры отображения (например, размеры video-component или типы видов расширения), управлять версиями расширения, а также включить монетизацию.
РЕКОМЕНДУЕМ:
Методы защиты от читов
Выводы
Как видите, расширения — мощнейший инструмент, который в корне меняет способ взаимодействия стримера со зрителями. Twitch Extensions позволяет устраивать небывалые интерактивные трансляции и шоу, и я показал вам лишь самую вершину айсберга. Это новое направление, где только начали появляться стоящие проекты. Теперь и вы тоже сможете поучаствовать в этом.
Для дальнейшего изучения и разработки расширений вы можете почитать официальный гайд или справку по всем методам.
для написания расширений для твитча само то!