Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 0 additions & 102 deletions docs/superpowers/plans/2026-07-24-auto-open-settings.md

This file was deleted.

46 changes: 0 additions & 46 deletions docs/superpowers/specs/2026-07-24-auto-open-settings-design.md

This file was deleted.

16 changes: 14 additions & 2 deletions js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ class MultiChatApp {

if (openBtn) {
openBtn.addEventListener('click', () => {
this.settings.populateForm();
modalEl.classList.remove('hidden');
this.openSettingsModal();
});
}

Expand Down Expand Up @@ -139,6 +138,19 @@ class MultiChatApp {
});

this.applyFontSettings(this.settings.settings.fontSize);

// Auto-open settings modal if no channel address is specified
if (!this.settings.hasAnyChannelConfigured()) {
this.openSettingsModal();
}
}

openSettingsModal() {
const modalEl = document.getElementById('settingsModal');
if (modalEl) {
this.settings.populateForm();
modalEl.classList.remove('hidden');
}
}

applyFontSettings(sizePx) {
Expand Down
50 changes: 39 additions & 11 deletions js/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,21 @@ class SettingsManager {
try {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) {
return { ...defaultSettings, ...JSON.parse(saved) };
const parsed = JSON.parse(saved);
const settings = { ...defaultSettings, ...parsed };
const stringFields = [
'twitchChannel',
'kickChannel',
'vkChannel',
'youtubeChannel',
'extraNicknames'
];
stringFields.forEach(field => {
if (typeof settings[field] !== 'string') {
settings[field] = defaultSettings[field] || '';
}
});
return settings;
}
} catch (e) {
console.error('[MultiChat Settings] Error reading settings from localStorage:', e);
Expand All @@ -45,28 +59,42 @@ class SettingsManager {
}
}

/**
* Returns true if at least one platform channel is configured.
*/
hasAnyChannelConfigured() {
const s = this.settings;
return [
s.twitchChannel,
s.kickChannel,
s.vkChannel,
s.youtubeChannel
].some(channel => typeof channel === 'string' && channel.trim().length > 0);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/**
* Returns a normalized array of all streamer nicknames
* (channel names from all platforms + extra nicknames), stripping leading '@'.
*/
getStreamerNicknames() {
const names = new Set();

const cleanNick = (str) => (str || '').toLowerCase().trim().replace(/^@+/, '');
const cleanNick = (str) => (typeof str === 'string' ? str : '').toLowerCase().trim().replace(/^@+/, '');
const addIfNotEmpty = (str) => {
const cleaned = cleanNick(str);
if (cleaned) names.add(cleaned);
};

// Add channel names
if (this.settings.twitchChannel) names.add(cleanNick(this.settings.twitchChannel));
if (this.settings.kickChannel) names.add(cleanNick(this.settings.kickChannel));
if (this.settings.vkChannel) names.add(cleanNick(this.settings.vkChannel));
if (this.settings.youtubeChannel) names.add(cleanNick(this.settings.youtubeChannel));
addIfNotEmpty(this.settings.twitchChannel);
addIfNotEmpty(this.settings.kickChannel);
addIfNotEmpty(this.settings.vkChannel);
addIfNotEmpty(this.settings.youtubeChannel);

// Add extra nicknames
if (this.settings.extraNicknames) {
if (typeof this.settings.extraNicknames === 'string' && this.settings.extraNicknames) {
const extraList = this.settings.extraNicknames.split(',');
extraList.forEach(n => {
const cleaned = cleanNick(n);
if (cleaned) names.add(cleaned);
});
extraList.forEach(n => addIfNotEmpty(n));
}

return Array.from(names);
Expand Down
48 changes: 48 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# MultiChat

Универсальный и легкий мультичат для стримеров на **HTML / CSS / JavaScript**, агрегирующий сообщения с нескольких стриминговых платформ в единую удобную ленту в реальном времени.

![MultiChat Overview](index.html) *(Интерфейс мультичата готов к работе в браузере и OBS)*

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use a real image source or a normal link.

![MultiChat Overview](index.html) is parsed as an image request for an HTML document, so the README will show a broken image. Point it to a screenshot asset, or use [MultiChat Overview](index.html) if the intent is to link to the app.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@readme.md` at line 5, Update the MultiChat Overview Markdown in the README to
use a valid screenshot image asset, or convert it to a normal link if it is
intended to navigate to index.html; do not retain image syntax pointing at the
HTML document.


---

## 🚀 Поддерживаемые платформы

- **Twitch** — прямое подключение через WebSocket IRC (`wss://irc-ws.chat.twitch.tv:443`) с поддержкой IRC-тегов, бейджей и цветов чаттеров.
- **Kick** — WebSocket-подключение через Pusher (`wss://ws-us2.pusher.com`).
- **VK Play Live / VK Video Live** — WebSocket-подключение через Centrifugo (`wss://pubsub.live.vkvideo.ru`) с автоматическим получением гостевых токенов.
- **YouTube Live** — автоматически находит активную трансляцию по хэндлу канала (`@channel`), URL видео или Video ID и подтягивает Live Chat.

---

## ✨ Ключевые возможности

- **Единый поток сообщений**: Все чаты объединяются в одну ленту с цветовой индикацией платформ.
- **Интеграция смайлов и бейджей**:
- Поддержка глобальных и канальных смайлов **7TV**, **BetterTTV (BTTV)** и **FrankerFaceZ (FFZ)**.
- Кастомные смайлики Kick и глобальные бейджи Twitch/Kick.
- **Умная фильтрация «Чаттерсы общаются»**:
- Сообщения, адресованные другими зрителями друг другу, могут автоматически сворачиваться в кликабельные плашки `[чаттерсы общаются]`, не отвлекая стримера.
- Упоминания стримера **никогда не скрываются**.
- **Автономность**:
- Не требует сложного бэкенда или баз данных. Настройки сохраняются локально в `localStorage`.
- Содержит встроенные механизмы смены CORS-прокси (`Corsproxy.io`, `AllOrigins`, `Codetabs`) и опциональный собственный `proxy.php`.

---

## 🛠️ Запуск и использование

### Простой запуск (Браузер)
1. Откройте `index.html` в любом современном веб-браузере.
2. Нажмите на иконку ⚙️ **Настройки** в шапке.
3. Укажите название ваших каналов для нужных платформ (Twitch, Kick, VK Live, YouTube).

Comment on lines +35 to +39

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document the automatic first-run modal.

When no channel is saved, Settings opens automatically, so the manual “press Settings” step is redundant and does not explain the new startup behavior. Mention the automatic opening while retaining the button as the way to edit settings later.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@readme.md` around lines 35 - 39, Update the “Простой запуск (Браузер)”
instructions to state that Settings opens automatically when no channel is
saved, and retain the ⚙️ Настройки button as the way to edit settings later.

### Использование в качестве док-панели OBS Studio
1. Укажите путь к локальному файлу `index.html` или URL вашего веб-сервера.
2. Разместите панель в удобном месте, заполните адреса каналов.

---

## 📄 Лицензия

MIT License. Свободно для использования и модификации.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add the missing MIT license text

The README now tells users the project is MIT-licensed, but I checked the repo for license files/text and there is no LICENSE, COPYING, or full MIT terms included. Users who need to redistribute or modify the project will not have the actual permission/notice terms the README promises, so either add the MIT license file or remove this claim until the license is provided.

Useful? React with 👍 / 👎.

Loading