fix: PageHead header alignment, analytics proxy, and infra improvements (#64)

🤖 Pull request created from `various-fixes` containing PageHead
breadcrumbs and navigation alignment fixes, Umami analytics proxy, and
infrastructure updates.
This commit is contained in:
deytenit authored and GitHub committed 2026-10-24 16:52:49 +03:00
1 parent ff5a50bad8
commit 9ee672504f
110 files changed
+2649 -1760

No files matched your search

@@ -1,39 +1,39 @@
---
title: Интерактивные голосовые функции
title: Голосовые функции
weight: 3
---
**Цель:** Реализовать сложные голосовые взаимодействия, которые учитывают границы серверов (гильдий) и управляют временными ресурсами.
**Цель:** реализовать голосовое взаимодействие с изоляцией ресурсов по серверам (гильдиям) и корректным управлением аудиосессиями.
## 1. Стратегия ограничения ресурсов
## 1. Изоляция ресурсов
Голосовые функции **ОБЯЗАТЕЛЬНО** должны быть ограничены рамками Гильдии (Guild).
Голосовые функции бота **обязательно** изолируются на уровне отдельного сервера (гильдии):
- **Паттерн:** Контроллер поддерживает `Map<GuildID, Player>`.
- **Архитектурный шаблон:** контроллер хранит соответствие `Map<GuildID, Player>`.
- **Поведение:**
- **Подключение (Join):** Создать Player для `Гильдии A`, если он еще не существует.
- **Отключение (Leave):** Уничтожить Player и освободить соединения.
- **Изоляция:** Команды в `Гильдии B` никогда не влияют на `Гильдию A`.
- **Подключение (Join):** создать `Player` для сервера A, если он ещё не существует.
- **Отключение (Leave):** удалить `Player` и освободить соединение.
- **Изоляция:** команды на сервере B никак не влияют на сервер A.
## 2. Оркестрация команд
## 2. Маршрутизация команд
Голосовые функции требуют набора команд, координируемых через Контроллер.
Голосовые функции опираются на набор команд, работу которых координирует контроллер:
| Команда | Действие | Логика Контроллера |
| Команда | Действие | Логика контроллера |
| :--- | :--- | :--- |
| `/join` | Подключиться к каналу | `createPlayer(guildId, channelId)` |
| `/play` | Добавить трек в очередь | `getPlayer(guildId).enqueue(track)` |
| `/stop` | Отключиться | `destroyPlayer(guildId)` |
| `/join` | Подключиться к голосовому каналу | `createPlayer(guildId, channelId)` |
| `/play` | Добавить трек в очередь | `getPlayer(guildId).enqueue(track)` |
| `/stop` | Отключиться от канала | `destroyPlayer(guildId)` |
## 3. Сохранение состояния
## 3. Управление состоянием
Аудиосессии эфемерны.
Аудиосессии по своей природе эфемерны:
- **Временное состояние:** Активный аудиопоток (Теряется при отключении).
- **Постоянное состояние:** Очередь / Плейлист (Сохраняется в Контроллере до перезапуска).
- **Временное состояние:** активный аудиопоток (сбрасывается при отключении).
- **Долговременное состояние:** очередь воспроизведения или плейлист (хранится в контроллере до перезапуска бота).
> [!TIP]
> **Устойчивость:** Разделяйте логику _Очереди_ и логику _Голосового соединения_. Это позволяет боту переподключаться без потери плейлиста пользователя.
> **Надёжность:** разделяйте логику очереди воспроизведения и логику голосового соединения. Тогда бот сможет переподключиться без потери пользовательского плейлиста.
## 4. Пример реализации
@@ -60,4 +60,4 @@ class MusicController {
**См. также:**
- [Руководство Discord.js Voice](https://discordjs.guide/voice/)
- [Руководство Discord.js по голосовым функциям](https://discordjs.guide/voice/)