109 lines
6.4 KiB
Markdown
109 lines
6.4 KiB
Markdown
|
|
# Send2Streamer
|
|||
|
|
|
|||
|
|
Сервис для стримеров: зрители пишут сообщения через веб-страницу (вход
|
|||
|
|
через Google) — сообщения всплывают у стримера на оверлее в OBS/StreamLabs,
|
|||
|
|
с текстом и голосовой озвучкой. Опционально на сообщение может ответить ИИ
|
|||
|
|
(DeepSeek), тоже с озвучкой. Мат автоматически цензурится.
|
|||
|
|
|
|||
|
|
## Быстрый старт
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cp .env.example .env # и заполнить реальными значениями (см. таблицу ниже)
|
|||
|
|
docker compose up -d --build
|
|||
|
|
docker compose logs -f
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Сервис поднимется на `http://localhost:3000`.
|
|||
|
|
|
|||
|
|
### Первичная настройка
|
|||
|
|
|
|||
|
|
1. Создать OAuth 2.0 Client ID (Web application) в
|
|||
|
|
[Google Cloud Console](https://console.cloud.google.com/apis/credentials),
|
|||
|
|
добавить в Authorized JavaScript origins домен, с которого открывается
|
|||
|
|
сайт (`http://localhost:3000` для локальной разработки, плюс боевой
|
|||
|
|
домен). **OAuth consent screen должен быть в статусе "In production"**,
|
|||
|
|
иначе войти смогут только явно добавленные test users.
|
|||
|
|
2. (Опционально) Получить ключ [DeepSeek API](https://platform.deepseek.com)
|
|||
|
|
для функции "ответ от ИИ".
|
|||
|
|
3. Открыть сайт → войти через Google как стример → на дашборде появятся
|
|||
|
|
две ссылки:
|
|||
|
|
- **Ссылка для OBS/StreamLabs** — вставить в свойства Browser Source.
|
|||
|
|
- **Ссылка для зрителей** — опубликовать, зрители сами авторизуются
|
|||
|
|
через Google и пишут сообщения.
|
|||
|
|
|
|||
|
|
## Как это работает
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph LR
|
|||
|
|
Viewer[Зритель] -->|логин Google + текст| Send["/s/:token (send.js)"]
|
|||
|
|
Send -->|WebSocket send_message| Server[server.js]
|
|||
|
|
Server -->|censorText| Server
|
|||
|
|
Server -->|display_message| Overlay["/overlay/:token (overlay.js)"]
|
|||
|
|
Server -->|edge-tts CLI| TTS[edge-tts]
|
|||
|
|
TTS -->|mp3 base64| Server
|
|||
|
|
Server -->|display_audio| Overlay
|
|||
|
|
Server -.->|если включена галка| DeepSeek[DeepSeek API]
|
|||
|
|
DeepSeek -.->|текст ответа| Server
|
|||
|
|
Overlay -->|очередь: текст + голос| OBS[OBS / StreamLabs Browser Source]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- **Один процесс на несколько стримеров.** Каждый стример получает пару
|
|||
|
|
уникальных токенов (overlay + sender), сообщения маршрутизируются через
|
|||
|
|
комнаты Socket.IO (`streamer-<id>`) — зрители одного стримера не видят
|
|||
|
|
сообщений другого.
|
|||
|
|
- **Очередь на оверлее.** Сообщения показываются по одному, каждое —
|
|||
|
|
заданное стримером время (по умолчанию 10 сек), а не перебивают друг
|
|||
|
|
друга.
|
|||
|
|
- **Озвучка** — `edge-tts` (бесплатный Microsoft Edge Read Aloud, тот же
|
|||
|
|
движок, что в `t2sTelegramBot`), CLI вызывается из Node дочерним
|
|||
|
|
процессом.
|
|||
|
|
- **ИИ-ответ** — опционален, только если у стримера настроен
|
|||
|
|
`DEEPSEEK_API_KEY`. Промпт-инструкция для ИИ лежит в `ai-prompt.txt` и
|
|||
|
|
редактируется без изменения кода.
|
|||
|
|
- **Цензура мата** (`profanity.js`) — при отправке применяется всегда: на
|
|||
|
|
экране матное слово превращается в `...`, в озвучке — в "бип".
|
|||
|
|
|
|||
|
|
## Структура проекта
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
.
|
|||
|
|
├── server.js # Express + Socket.IO, вся серверная логика
|
|||
|
|
├── db.js # SQLite (node:sqlite) — стримеры, имена зрителей
|
|||
|
|
├── profanity.js # Цензура мата
|
|||
|
|
├── ai-prompt.txt # Системный промпт для ИИ-ответов (редактируется свободно)
|
|||
|
|
├── public/
|
|||
|
|
│ ├── index.html # Лендинг + вход для стримера
|
|||
|
|
│ ├── dashboard.html # Личный кабинет стримера (ссылки, настройки)
|
|||
|
|
│ ├── send.html/.js # Страница отправки сообщений (для зрителей)
|
|||
|
|
│ └── overlay.html/.js # Страница для Browser Source в OBS/StreamLabs
|
|||
|
|
├── Dockerfile
|
|||
|
|
├── docker-compose.yml # Локальная разработка (build: .)
|
|||
|
|
├── docker-compose.prod.yml # Прод (только image:, без build)
|
|||
|
|
└── .forgejo/workflows/deploy.yml # CI/CD: билд → push в registry → деплой по SSH
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Конфигурация (.env)
|
|||
|
|
|
|||
|
|
| Переменная | Описание |
|
|||
|
|
|---|---|
|
|||
|
|
| `PORT` | Порт сервера (по умолчанию 3000) |
|
|||
|
|
| `GOOGLE_CLIENT_ID` | OAuth Client ID для входа через Google |
|
|||
|
|
| `SESSION_SECRET` | Случайная строка для подписи сессионной cookie |
|
|||
|
|
| `TTS_VOICE` | Голос по умолчанию для новых стримеров (`ru-RU-DmitryNeural`) |
|
|||
|
|
| `DEEPSEEK_API_KEY` | Опционально — включает функцию "ответ от ИИ" |
|
|||
|
|
| `AI_VOICE` | Голос для ИИ-ответов (`ru-RU-SvetlanaNeural` по умолчанию, отличается от голоса стримера) |
|
|||
|
|
|
|||
|
|
## Деплой
|
|||
|
|
|
|||
|
|
Пуш в `main` триггерит `.forgejo/workflows/deploy.yml`: сборка образа,
|
|||
|
|
smoke-test, push в локальный registry, затем SSH на прод-хост
|
|||
|
|
(`docker pull` + `docker compose up -d`). Прод-хост сам хранит свой `.env`
|
|||
|
|
(не через git) — при первом деплое его нужно создать вручную рядом с
|
|||
|
|
`docker-compose.prod.yml`.
|
|||
|
|
|
|||
|
|
## Требования
|
|||
|
|
|
|||
|
|
- Docker + Docker Compose
|
|||
|
|
- Доступ к `accounts.google.com` (логин), `api.deepseek.com` (если включён
|
|||
|
|
ИИ-ответ) и Microsoft edge-tts CDN (озвучка)
|