Files
TTW_Bot/ugeneral.cpp
T
2026-02-07 08:28:56 +03:00

3284 lines
112 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "ugeneral.h"
#include "fcreatenotify.h"
#include "filemanager.h"
#include "logmanager.h"
#include "ui_ugeneral.h"
#include <QStandardPaths>
#include <QDesktopServices>
#include <QUrl>
#include <QDir>
#include <QFileDialog>
#include <QMessageBox>
#include <QStandardItem>
#include <QDateTime>
#include <QRandomGenerator>
#include "ulink.h"
#include "udatabase.h"
#include "soundmanager.h"
#include "userwidget.h"
#include "websocketclient.h"
#include "twitchmessage.h"
#include "user.h"
#include "user_manager.h"
#include "emoteprovider.h"
#include "fcreatechat.h"
#include <QInputDialog>
#include <QPair>
#include <QCache>
#include <QSettings>
#include "timerinfo.h"
#include "mediafilemanager.h"
uGeneral::uGeneral(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::uGeneral)
, m_authBot(nullptr)
, m_authStreamer(nullptr)
, m_authDA(nullptr)
, fLinkForm(nullptr)
, m_isTwitchConnected(false)
, m_notificationServers()
, m_chatServers()
, m_createNotifyDialog(nullptr)
, m_createChatDialog(nullptr)
, m_randomManager(nullptr)
{
// ============================================================================
// ИНИЦИАЛИЗАЦИЯ ИНТЕРФЕЙСА
// ============================================================================
ui->setupUi(this);
setWindowTitle("TTW Bot app");
LogSettings logSettings;
logSettings.logToFile = true;
logSettings.logToConsole = true;
//logSettings.maxEntries = 5000;
// Цвета для разных уровней
logSettings.colors[LogLevel::Info] = Qt::darkGreen;
logSettings.colors[LogLevel::Warning] = Qt::darkYellow;
logSettings.colors[LogLevel::Error] = Qt::red;
logSettings.colors[LogLevel::Debug] = Qt::gray;
logSettings.colors[LogLevel::Critical] = Qt::darkRed;
LogManager::initialize(logSettings);
// Подключение сигналов к UI
LogManager* logger = LogManager::instance();
connect(logger, &LogManager::entryAdded,
this, &uGeneral::onLogEntryAdded);
connect(logger, &LogManager::logCleared,
this, &uGeneral::onLogCleared);
connect(logger, &LogManager::errorAdded,
this, &uGeneral::onLogEntryAdded);
connect(logger, &LogManager::warningAdded,
this, &uGeneral::onLogEntryAdded);
connect(logger, &LogManager::infoAdded,
this, &uGeneral::onLogEntryAdded);
connect(logger, &LogManager::debugAdded,
this, &uGeneral::onLogEntryAdded);
connect(logger, &LogManager::criticalAdded,
this, &uGeneral::onLogEntryAdded);
// Запуск приложения - используем новый логгер
LogManager::instance()->info("uGeneral", "constructor", "Главное окно создано");
// Инициализируем структуру папок
FileManager::instance().initializeFolderStructure();
FileManager::instance().copyDefaultFiles();
// Получаем пути через FileManager
QString sysPath = FileManager::instance().systemPath();
// Загружаем иконки
tabIcons = {
QIcon(FileManager::instance().getFullPath(FileManager::Icons, "settings.png")),
QIcon(FileManager::instance().getFullPath(FileManager::Icons, "ai.png")),
QIcon(FileManager::instance().getFullPath(FileManager::Icons, "chat.png")),
QIcon(FileManager::instance().getFullPath(FileManager::Icons, "skill.png")),
QIcon(FileManager::instance().getFullPath(FileManager::Icons, "obs.png")),
QIcon(FileManager::instance().getFullPath(FileManager::Icons, "notify.png")),
QIcon(FileManager::instance().getFullPath(FileManager::Icons, "user.png")),
QIcon(FileManager::instance().getFullPath(FileManager::Icons, "auto.png")),
QIcon(FileManager::instance().getFullPath(FileManager::Icons, "log.png")),
QIcon(FileManager::instance().getFullPath(FileManager::Icons, "add.png")),
QIcon(FileManager::instance().getFullPath(FileManager::Icons, "edit.png")),
QIcon(FileManager::instance().getFullPath(FileManager::Icons, "rm.png")),
QIcon(FileManager::instance().getFullPath(FileManager::Icons, "rmfolder.png")),
QIcon(FileManager::instance().getFullPath(FileManager::Icons, "open.png")),
};
for (int i = 0; i < ui->www->count() && i < tabIcons.size(); i++) {
ui->www->setTabIcon(i, tabIcons[i]);
}
setupButtonIcons();
// Загружаем QSS файлы при создании формы
loadQssFiles();
// ============================================================================
// ИНИЦИАЛИЗАЦИЯ БАЗЫ ДАННЫХ
// ============================================================================
initializeDatabase();
// ============================================================================
// НАСТРОЙКА ИНТЕРФЕЙСА ПОЛЬЗОВАТЕЛЯ
// ============================================================================
setupUI();
// ============================================================================
// НАСТРОЙКА ТАБЛИЦ
// ============================================================================
setupTables();
// ============================================================================
// ЗАГРУЗКА НАСТРОЕК
// ============================================================================
loadSettings();
// ============================================================================
// НАСТРОЙКА TWITCH API И WEBSOCKET
// ============================================================================
setupTwitchComponents();
// ============================================================================
// ИНИЦИАЛИЗАЦИЯ МЕНЕДЖЕРОВ
// ============================================================================
initializeManagers();
// ============================================================================
// НАСТРОЙКА ВИДЖЕТА ПОЛЬЗОВАТЕЛЕЙ
// ============================================================================
setupUserWidget();
// ============================================================================
// НАСТРОЙКА АВТОРИЗАЦИИ
// ============================================================================
setupAuthHandlers();
// ============================================================================
// ИНИЦИАЛИЗАЦИЯ НЕЙРОННОЙ СЕТИ
// ============================================================================
initializeNeuralNetwork();
loadEmoties();
// Настройка таблицы веб-серверов
QStringList headers = {"Название", "Тип", "Порт", "Ссылка", "Статус"};
ui->sgWebServers->setColumnCount(headers.size());
ui->sgWebServers->setHorizontalHeaderLabels(headers);
ui->sgWebServers->horizontalHeader()->setStretchLastSection(true);
// Инициализируем окна создания
m_createNotifyDialog = new FCreateNotify(db, this);
m_createChatDialog = new FCreateChat(db, this);
// Добавьте эту строку в конец метода:
initializeNotificationSounds();
if (db) {
m_randomManager = new RandomManager(this);
m_randomManager->initialize(db);
}
}
// ============================================================================
// ПРИВАТНЫЕ МЕТОДЫ ДЛЯ ИНИЦИАЛИЗАЦИИ
// ============================================================================
void uGeneral::setupButtonIcons() {
// Получаем все кнопки на форме
QList<QPushButton*> buttons = ui->www->findChildren<QPushButton*>();
// Если кнопки не в centralWidget, ищем во всем окне
// QList<QPushButton*> buttons = findChildren<QPushButton*>();
// Проходим по всем найденным кнопкам
foreach (QPushButton *button, buttons) {
QString buttonName = button->objectName().toLower(); // Приводим к нижнему регистру
// Проверяем наличие ключевых слов в имени
if (buttonName.contains("add")) {
button->setIcon(tabIcons[9]);
}
else if (buttonName.contains("del") || buttonName.contains("rm")) {
// Проверяем специальный случай RmGroup (регистрозависимый)
if (button->objectName().contains("RmGroup")) {
button->setIcon(tabIcons[12]);
} else {
button->setIcon(tabIcons[11]);
}
}
else if (buttonName.contains("edt")) {
button->setIcon(tabIcons[10]);
}
else if (buttonName.contains("open")) {
button->setIcon(tabIcons[13]);
}
// Устанавливаем размер иконки (опционально)
if (!button->icon().isNull()) {
button->setIconSize(QSize(16, 16));
}
}
}
/**
* @brief Инициализация базы данных
*/
void uGeneral::initializeDatabase()
{
QString roamingPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QDir dir(roamingPath);
if (!dir.exists()) {
dir.mkpath(".");
}
roamingPath += "/settings.db";
db = new uDataBase(roamingPath, this);
if (!db->isConnected()) {
LogManager::instance()->error("uGeneral", "Create", "Ошибка подключения к БД");
} else {
LogManager::instance()->info("uGeneral", "Create", "Успешное подключение к БД");
}
}
/**
* @brief Настройка пользовательского интерфейса
*/
void uGeneral::setupUI()
{
// Настройка видимости элементов
ui->lblAPI3->setText("");
ui->lblAPI3->setVisible(false);
ui->edtAIP3->setVisible(false);
ui->cbOllama->setVisible(false);
// Настройка режимов отображения паролей
QList<QLineEdit*> passwordFields = {
ui->edtDACode,
ui->edtBotToken,
ui->edtKandiKey,
ui->edtDAClientID,
ui->edtBotClientID,
ui->edtKandiSecret,
ui->edtDAClientSecret,
ui->edtBotTokenStreamer,
ui->edtAIP1,
ui->edtAIP2,
ui->edtAIP3
};
for (auto field : passwordFields) {
field->setEchoMode(QLineEdit::Password);
}
// Подключение фильтров логов
connect(ui->cbInfo, &QCheckBox::stateChanged, this, &uGeneral::applyLogFilter);
connect(ui->cbWarning, &QCheckBox::stateChanged, this, &uGeneral::applyLogFilter);
connect(ui->cbError, &QCheckBox::stateChanged, this, &uGeneral::applyLogFilter);
connect(ui->cbDebug, &QCheckBox::stateChanged, this, &uGeneral::applyLogFilter);
}
/**
* @brief Настройка таблиц интерфейса
*/
void uGeneral::setupTables()
{
// ========================================================================
// НАСТРОЙКА ТАБЛИЦЫ ЛОГОВ
// ========================================================================
QStringList headers;
headers.clear();
headers << "Дата" << "Тип" << "Модуль" << "Метод" << "Сообщение";
ui->sgLog->setHorizontalHeaderLabels(headers);
ui->sgLog->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->sgLog->setSelectionMode(QAbstractItemView::SingleSelection);
ui->sgLog->setEditTriggers(QAbstractItemView::NoEditTriggers);
// Настройка ширины колонок
ui->sgLog->setColumnWidth(0, 100); // Дата
ui->sgLog->setColumnWidth(1, 100); // Тип
ui->sgLog->setColumnWidth(2, 170); // Модуль
ui->sgLog->setColumnWidth(3, 170); // Метод
ui->sgLog->setColumnWidth(4, 390); // Сообщение
// ========================================================================
// НАСТРОЙКА ТАБЛИЦЫ КОМАНД
// ========================================================================
headers.clear();
headers << "Команда" << "Ответ";
ui->sgCommands->setHorizontalHeaderLabels(headers);
ui->sgCommands->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->sgCommands->setSelectionMode(QAbstractItemView::SingleSelection);
ui->sgCommands->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->sgCommands->setColumnWidth(0, 135); // Команда
ui->sgCommands->setColumnWidth(1, 410); // Ответ
// ========================================================================
// НАСТРОЙКА ТАБЛИЦЫ РАНДОМНЫХ ИНТЕРВАЛОВ
// ========================================================================
headers.clear();
headers << "Имя" << "От" << "До";
ui->sgRandomInt->setHorizontalHeaderLabels(headers);
ui->sgRandomInt->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->sgRandomInt->setSelectionMode(QAbstractItemView::SingleSelection);
ui->sgRandomInt->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->sgRandomInt->setColumnWidth(0, 70); // Имя
ui->sgRandomInt->setColumnWidth(1, 30); // От
ui->sgRandomInt->setColumnWidth(2, 30); // До
// ========================================================================
// НАСТРОЙКА ТАБЛИЦЫ ВЕБ СЕРВЕРОВ
// ========================================================================
headers.clear();
headers << "Порт" << "Тип" << "Ссылка";
ui->sgWebServers->setColumnCount(headers.size());
ui->sgWebServers->setHorizontalHeaderLabels(headers);
ui->sgWebServers->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->sgWebServers->setSelectionMode(QAbstractItemView::SingleSelection);
ui->sgWebServers->setEditTriggers(QAbstractItemView::NoEditTriggers);
// Настройка ширины колонок
ui->sgWebServers->setColumnWidth(0, 80); // Порт
ui->sgWebServers->setColumnWidth(1, 100); // Тип
ui->sgWebServers->setColumnWidth(2, 250); // Ссылка
// Подключение двойного клика
connect(ui->sgWebServers, &QTableWidget::cellDoubleClicked,
this, &uGeneral::on_sgWebServers_cellDoubleClicked);
// ========================================================================
// НАСТРОЙКА ТАБЛИЦЫ ТАЙМЕРОВ
// ========================================================================
ui->sgTimers->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->sgTimers->setSelectionMode(QAbstractItemView::SingleSelection);
ui->sgTimers->setEditTriggers(QAbstractItemView::NoEditTriggers);
// Подключение сигналов таблицы таймеров
connect(ui->sgTimers, &QTableWidget::cellClicked,
this, &uGeneral::on_sgTimers_cellClicked);
connect(ui->sgTimers, &QTableWidget::cellDoubleClicked,
this, &uGeneral::on_sgTimers_cellDoubleClicked);
db->LoadTimers(ui->sgTimers, m_timers);
updateTimerTable();
// ========================================================================
// ИНИЦИАЛИЗАЦИЯ СПЕЦИАЛЬНЫХ ВИДЖЕТОВ
// ========================================================================
ui->widget->initForm("Звук", "sgSounds", true);
ui->widget_2->initForm("Файлы", "sgFiles", true);
ui->widget_3->initForm("Нейроконструктор", "sgNeiro");
// Подключение двойных кликов для специальных виджетов
connect(ui->widget->tableWidget(), &QTableWidget::cellDoubleClicked,
this, &uGeneral::onSoundGridDoubleClicked);
connect(ui->widget_2->tableWidget(), &QTableWidget::cellDoubleClicked,
this, &uGeneral::onFilesGridDoubleClicked);
connect(ui->widget_3->tableWidget(), &QTableWidget::cellDoubleClicked,
this, &uGeneral::onNeiroGridDoubleClicked);
}
/**
* @brief Инициализация менеджеров
*/
void uGeneral::initializeManagers()
{
// Менеджер звуков
soundManager = new SoundManager(this);
// Менеджер пользователей
m_userManager = new UserManager(this);
// Менеджер случайных диапазонов
m_randomManager = new RandomManager(this);
if (db) {
m_randomManager->initialize(db);
m_randomManager->loadFromDatabase();
}
// Менеджер случайных ответов (групп)
m_randomResponses = new RandomResponses(this);
// Менеджер нейросети (если есть)
nnManager = new NeuralNetworkManager(this);
// Настройка нейросети (пример)
// nnManager->setApiKey(NeuralNetworkManager::DeepSeek, "ваш_api_ключ");
// nnManager->setModel(NeuralNetworkManager::DeepSeek, "deepseek-chat");
m_SoundFiles = new MediaFileManager();
// Менеджер команд
m_commandProcessor = new CommandProcessor(this);
if (db) {
// Загрузка команд из таблицы sgCommands в CommandProcessor
loadCommandsFromTableWidget();
// Загрузка случайных диапазонов из таблицы sgRandomInt в RandomManager
loadRandomRangesFromTableWidget();
// Загрузка групп случайных ответов из базы данных
loadRandomResponseGroupsFromDatabase();
// Загрузка звуков
loadSoundsFromDatabase();
// Настройка контекста для обработчика команд
CommandProcessor::Context context;
context.userManager = m_userManager;
context.twitchAPI = twitchAPI;
context.soundManager = soundManager;
context.neuralManager = nnManager;
context.randomManager = m_randomManager;
context.randomResponses = m_randomResponses;
context.mediaFileManager = m_SoundFiles;
context.channel = ui->edtChannel->text();
context.notifyVolume = ui->tbNotifyVolume->value();
m_commandProcessor->setContext(context);
}
}
void uGeneral::loadCommandsFromTableWidget()
{
if (!db || !m_commandProcessor) return;
QTableWidget* table = ui->sgCommands;
if (!table) return;
for (int row = 0; row < table->rowCount(); ++row) {
QTableWidgetItem *commandItem = table->item(row, 0);
QTableWidgetItem *responseItem = table->item(row, 1);
if (commandItem && responseItem) {
QString command = commandItem->text().trimmed();
QString response = responseItem->text();
if (!command.isEmpty() && !response.isEmpty()) {
m_commandProcessor->addCommand(command, response);
}
}
}
}
/**
* @brief Загрузка звуков
*/
void uGeneral::loadSoundsFromDatabase()
{
if (!db || !m_SoundFiles) return;
QTableWidget* table = ui->widget->tableWidget();
if (!table) return;
for (int row = 0; row < table->rowCount(); ++row) {
QTableWidgetItem *nameItem = table->item(row, 0);
QTableWidgetItem *fileItem = table->item(row, 1);
if (nameItem && fileItem) {
QString name = nameItem->text().trimmed();
QString file = fileItem->text().trimmed();
if (!name.isEmpty() && !file.isEmpty()) {
m_SoundFiles->addFile(name, file);
}
}
}
}
/**
* @brief Загрузка случайных диапазонов из таблицы sgRandomInt в RandomManager
*/
void uGeneral::loadRandomRangesFromTableWidget()
{
if (!db || !m_randomManager) return;
QTableWidget* table = ui->sgRandomInt;
if (!table) return;
for (int row = 0; row < table->rowCount(); ++row) {
QTableWidgetItem *nameItem = table->item(row, 0);
QTableWidgetItem *startItem = table->item(row, 1);
QTableWidgetItem *endItem = table->item(row, 2);
if (nameItem && startItem && endItem) {
QString name = nameItem->text().trimmed();
int start = startItem->text().toInt();
int end = endItem->text().toInt();
if (!name.isEmpty() && start <= end) {
m_randomManager->addRange(name, start, end);
}
}
}
}
/**
* @brief Загрузка групп случайных ответов из базы данных
*/
void uGeneral::loadRandomResponseGroupsFromDatabase()
{
if (!db || !m_randomResponses) return;
// Создаем временный QListWidget для получения списка групп
QListWidget tempGroupList;
if (!db->LoadRandomGroups(&tempGroupList)) {
qWarning() << "Failed to load random groups from database";
return;
}
// Для каждой группы загружаем её ответы
for (int i = 0; i < tempGroupList.count(); ++i) {
QString groupName = tempGroupList.item(i)->text().trimmed();
if (groupName.isEmpty()) continue;
// Создаем временный QListWidget для получения ответов группы
QListWidget tempResponseList;
if (!db->LoadRandomResponses(groupName, &tempResponseList)) {
qWarning() << "Failed to load responses for group:" << groupName;
continue;
}
// Добавляем каждый ответ в RandomResponses
for (int j = 0; j < tempResponseList.count(); ++j) {
QString response = tempResponseList.item(j)->text();
if (!response.isEmpty()) {
m_randomResponses->addResponse(groupName, response);
}
}
}
}
/**
* @brief Настройка компонентов Twitch
*/
void uGeneral::setupTwitchComponents()
{
// ========================================================================
// ИНИЦИАЛИЗАЦИЯ WEBSOCKET КЛИЕНТА ДЛЯ TWITCH
// ========================================================================
m_twitchClient = new WebSocketClient(this);
// Подключение сигналов WebSocket клиента
connect(m_twitchClient, &WebSocketClient::onNewMessage,
this, &uGeneral::handleNewMessage);
connect(m_twitchClient, &WebSocketClient::onConnected,
this, &uGeneral::handleConnected);
connect(m_twitchClient, &WebSocketClient::onDisconnected,
this, &uGeneral::handleDisconnected);
connect(m_twitchClient, &WebSocketClient::onError,
this, &uGeneral::handleError);
// ========================================================================
// ИНИЦИАЛИЗАЦИЯ TWITCH API
// ========================================================================
twitchAPI = new TTwAPI(this);
// Подключение сигналов Twitch API
connect(twitchAPI, &TTwAPI::apiError, this, &uGeneral::onApiError);
connect(twitchAPI, &TTwAPI::tokenExpired, this, &uGeneral::onTokenExpired);
connect(twitchAPI, &TTwAPI::rateLimitExceeded, this, &uGeneral::onRateLimit);
// Инициализация Twitch API
initTwitchAPI();
}
/**
* @brief Настройка виджета пользователей
*/
void uGeneral::setupUserWidget()
{
// Создание виджета пользователей
m_userWidget = new UserWidget(m_userManager, this);
// Настройка layout для вкладки
QVBoxLayout* layout = new QVBoxLayout(ui->tab_7);
layout->setContentsMargins(0, 0, 0, 0); // Убираем отступы
layout->addWidget(m_userWidget);
ui->tab_7->setLayout(layout);
// ========================================================================
// ПОДКЛЮЧЕНИЕ СИГНАЛОВ ВИДЖЕТА ПОЛЬЗОВАТЕЛЕЙ
// ========================================================================
// Бан пользователя
connect(m_userWidget, &UserWidget::banUserRequested, this, [this](const QString &userId, const QString &userName) {
if (twitchAPI) {
twitchAPI->banUser(userId);
}
});
// Таймаут пользователя
connect(m_userWidget, &UserWidget::timeoutUserRequested, this, [this](const QString &userId, const QString &userName, int minutes) {
if (twitchAPI) {
twitchAPI->banUserTime(userId, minutes);
}
});
// Разбан пользователя
connect(m_userWidget, &UserWidget::unbanUserRequested, this, [this](const QString &userId, const QString &userName) {
if (twitchAPI) {
twitchAPI->unbanUser(userId);
}
});
// Назначение модератором
connect(m_userWidget, &UserWidget::setModeratorRequested, this, [this](const QString &userId, const QString &userName) {
if (twitchAPI) {
twitchAPI->setModerator(userId);
// Обновляем статус в UserManager
User* user = m_userManager->findUserById(userId);
if (user) {
user->isModerator = true;
m_userManager->updateUserFromMessage(user->displayName, TwitchMessage());
}
}
});
// Удаление прав модератора
connect(m_userWidget, &UserWidget::removeModeratorRequested, this, [this](const QString &userId, const QString &userName) {
if (twitchAPI) {
twitchAPI->delModerator(userId);
// Обновляем статус в UserManager
User* user = m_userManager->findUserById(userId);
if (user) {
user->isModerator = false;
m_userManager->updateUserFromMessage(user->displayName, TwitchMessage());
}
}
});
// Назначение VIP
connect(m_userWidget, &UserWidget::setVIPRequested, this, [this](const QString &userId, const QString &userName) {
if (twitchAPI) {
twitchAPI->setVIP(userId);
// Обновляем статус в UserManager
User* user = m_userManager->findUserById(userId);
if (user) {
user->isVIP = true;
m_userManager->updateUserFromMessage(user->displayName, TwitchMessage());
}
}
});
// Удаление статуса VIP
connect(m_userWidget, &UserWidget::removeVIPRequested, this, [this](const QString &userId, const QString &userName) {
if (twitchAPI) {
twitchAPI->delVIP(userId);
// Обновляем статус в UserManager
User* user = m_userManager->findUserById(userId);
if (user) {
user->isVIP = false;
m_userManager->updateUserFromMessage(user->displayName, TwitchMessage());
}
}
});
// Запрос информации о пользователе
connect(m_userWidget, &UserWidget::userInfoRequested, this, [this](const QString &userId, const QString &userName) {
Q_UNUSED(userName);
User* user = m_userManager->findUserById(userId);
if (user) {
QString info = QString(
"Информация о пользователе:\n"
"Имя: %1\n"
"ID: %2\n"
"Логин: %3\n"
"Сообщений: %4\n"
"Модератор: %5\n"
"VIP: %6\n"
"Подписчик: %7\n"
"Последняя активность: %8"
).arg(user->displayName)
.arg(user->id)
.arg(user->login)
.arg(user->messageCount)
.arg(user->isModerator ? "Да" : "Нет")
.arg(user->isVIP ? "Да" : "Нет")
.arg(user->isSubscriber ? "Да" : "Нет")
.arg(user->lastMessageTime.isValid() ?
user->lastMessageTime.toString("dd.MM.yyyy hh:mm:ss") : "Неизвестно");
QMessageBox::information(this, "Информация о пользователе", info);
}
});
}
/**
* @brief Настройка обработчиков авторизации
*/
void uGeneral::setupAuthHandlers()
{
// ========================================================================
// НАСТРОЙКА АВТОРИЗАЦИИ БОТА
// ========================================================================
m_authBot = new TAuth(this);
connect(m_authBot, &TAuth::tokenReceived, this, &uGeneral::onTokenReceived);
connect(m_authBot, &TAuth::errorOccurred, this, &uGeneral::onAuthError);
connect(m_authBot, &TAuth::serverStarted, this, [this](int port) {
LogManager::instance()->info("General", "setupAuthHandlers", "Сервер авторизации запущен");
});
// ========================================================================
// НАСТРОЙКА АВТОРИЗАЦИИ СТРИМЕРА
// ========================================================================
m_authStreamer = new TAuth(this);
connect(m_authStreamer, &TAuth::tokenReceived, this, &uGeneral::onTokenReceived2);
connect(m_authStreamer, &TAuth::errorOccurred, this, &uGeneral::onAuthError);
connect(m_authStreamer, &TAuth::serverStarted, this, [this](int port) {
LogManager::instance()->info("General", "setupAuthHandlers", "Сервер авторизации запущен");
});
// ========================================================================
// НАСТРОЙКА АВТОРИЗАЦИИ DA
// ========================================================================
m_authDA = new TAuth(this);
connect(m_authDA, &TAuth::codeReceived, this, &uGeneral::onTokenReceived3);
connect(m_authDA, &TAuth::errorOccurred, this, &uGeneral::onAuthError);
connect(m_authDA, &TAuth::serverStarted, this, [this](int port) {
LogManager::instance()->info("General", "setupAuthHandlers", "Сервер авторизации запущен");
});
}
/**
* @brief Инициализация нейронной сети
*/
void uGeneral::initializeNeuralNetwork()
{
nnManager = new NeuralNetworkManager(this);
// Подключение сигналов менеджера нейронной сети
connect(nnManager, &NeuralNetworkManager::responseReceived,
this, &uGeneral::onNeuralResponse);
connect(nnManager, &NeuralNetworkManager::errorOccurred,
this, &uGeneral::onNeuralError);
}
uGeneral::~uGeneral()
{
for (HttpServer *server : m_notificationServers) {
server->stop();
delete server;
}
m_notificationServers.clear();
for (HttpServerChat *server : m_chatServers) {
server->stop();
delete server;
}
m_chatServers.clear();
if (m_commandProcessor) {
delete m_commandProcessor;
m_commandProcessor = nullptr;
}
if (m_randomManager) {
delete m_randomManager;
m_randomManager = nullptr;
}
delete m_createNotifyDialog;
delete m_createChatDialog;
delete ui;
delete m_userManager;
delete fLinkForm;
delete m_twitchClient;
delete m_authBot;
delete m_authStreamer;
delete m_authDA;
}
// ============================================================================
// ОТПРАВКА СООБЩЕНИЙ
// ============================================================================
// ============================================================================
// УПРАВЛЕНИЕ СЕРВЕРАМИ
// ============================================================================
void uGeneral::setTwitchConnected(bool connected)
{
m_isTwitchConnected = connected;
// Если подключение установлено, запускаем активные таймеры
if (connected) {
for (TimerInfo& timer : m_timers) {
if (timer.isActive && !timer.timer) {
startTimer(timer);
}
}
} else {
// Если подключение разорвано, останавливаем все таймеры
for (TimerInfo& timer : m_timers) {
if (timer.timer) {
stopTimer(timer);
}
}
}
}
void uGeneral::loadEmoties()
{
bttvProvider.fetchGlobal();
sevenTVProvider.fetchGlobal();
User user = twitchAPI->getUserByLogin(ui->edtChannel->text());
bttvProvider.fetchCustom(user.id);
sevenTVProvider.fetchCustom(user.id);
}
void uGeneral::loadChatBadges()
{
if (!twitchAPI) return;
m_chatBadges.clear();
QVector<ChatBadge> globalBadges;
twitchAPI->getGlobalChatBadges(globalBadges);
m_chatBadges.append(globalBadges);
QVector<ChatBadge> customBadges;
twitchAPI->getCustomChatBadges(customBadges);
m_chatBadges.append(customBadges);
}
void uGeneral::updateTimerTable() {
ui->sgTimers->setRowCount(0);
for (const TimerInfo& timer : m_timers) {
int row = ui->sgTimers->rowCount();
ui->sgTimers->insertRow(row);
// Чекбокс "Вкл"
QTableWidgetItem* enabledItem = new QTableWidgetItem();
enabledItem->setCheckState(timer.isActive ? Qt::Checked : Qt::Unchecked);
ui->sgTimers->setItem(row, 0, enabledItem);
// Сообщение
QTableWidgetItem* messageItem = new QTableWidgetItem(timer.message);
ui->sgTimers->setItem(row, 1, messageItem);
// Интервал
QTableWidgetItem* intervalItem = new QTableWidgetItem(QString::number(timer.interval));
ui->sgTimers->setItem(row, 2, intervalItem);
// Чекбокс "О"
QTableWidgetItem* announcementItem = new QTableWidgetItem();
announcementItem->setCheckState(timer.isAnnouncement ? Qt::Checked : Qt::Unchecked);
ui->sgTimers->setItem(row, 3, announcementItem);
}
}
void uGeneral::startTimer(TimerInfo& timerInfo) {
// Не запускаем таймер, если нет подключения к Twitch
if (!m_isTwitchConnected) {
return;
}
if (timerInfo.timer) {
timerInfo.timer->stop();
delete timerInfo.timer;
}
timerInfo.timer = new QTimer(this);
connect(timerInfo.timer, &QTimer::timeout, this, [this, timerInfo]() {
sendTimedMessage(timerInfo);
});
timerInfo.timer->start(timerInfo.interval * 60000);
}
void uGeneral::stopTimer(TimerInfo& timerInfo) {
if (timerInfo.timer) {
timerInfo.timer->stop();
delete timerInfo.timer;
timerInfo.timer = nullptr;
}
}
void uGeneral::sendTimedMessage(const TimerInfo& timerInfo) {
// Не отправляем сообщение, если нет подключения
if (!m_isTwitchConnected) {
return;
}
if (timerInfo.isAnnouncement) {
// Отправка через API как оповещение
if (twitchAPI) {
twitchAPI->sendAnnouncement(timerInfo.message);
}
} else {
// Обычное сообщение в чат
if (m_twitchClient) {
m_twitchClient->sendChatMessage(ui->edtChannel->text(), timerInfo.message);
}
}
}
// Слоты
void uGeneral::on_btnTimerAdd_clicked()
{
QString message = ui->edtTimerMessage->text().trimmed();
QString intervalStr = ui->edtTimerInterval->text().trimmed();
if (message.isEmpty()) {
QMessageBox::warning(this, "Ошибка", "Введите сообщение!");
return;
}
bool ok;
int interval = intervalStr.toInt(&ok);
if (!ok || interval <= 0) {
QMessageBox::warning(this, "Ошибка", "Введите корректный интервал в минутах!");
return;
}
TimerInfo newTimer;
newTimer.id = m_nextTimerId++;
newTimer.message = message;
newTimer.interval = interval;
newTimer.isActive = true; // По умолчанию включен
newTimer.isAnnouncement = false;
newTimer.timer = nullptr;
m_timers.append(newTimer);
if (m_isTwitchConnected) {
startTimer(m_timers.last());
}
updateTimerTable();
db->SaveTimers(ui->sgTimers, m_timers);
ui->edtTimerMessage->clear();
ui->edtTimerInterval->setText("10");
}
void uGeneral::on_btnTimerEdit_clicked() {
int currentRow = ui->sgTimers->currentRow();
if (currentRow < 0 || currentRow >= m_timers.size()) {
QMessageBox::warning(this, "Ошибка", "Выберите таймер для редактирования!");
return;
}
QString message = ui->edtTimerMessage->text().trimmed();
QString intervalStr = ui->edtTimerInterval->text().trimmed();
if (message.isEmpty()) {
QMessageBox::warning(this, "Ошибка", "Введите сообщение!");
return;
}
bool ok;
int interval = intervalStr.toInt(&ok);
if (!ok || interval <= 0) {
QMessageBox::warning(this, "Ошибка", "Введите корректный интервал в минутах!");
return;
}
TimerInfo& timer = m_timers[currentRow];
bool wasActive = timer.isActive;
if (wasActive) {
stopTimer(timer);
}
timer.message = message;
timer.interval = interval;
if (wasActive && m_isTwitchConnected) { // Добавлена проверка подключения
startTimer(timer);
}
updateTimerTable();
db->SaveTimers(ui->sgTimers, m_timers);
}
void uGeneral::on_btnTimerDelete_clicked() {
int currentRow = ui->sgTimers->currentRow();
if (currentRow < 0 || currentRow >= m_timers.size()) {
QMessageBox::warning(this, "Ошибка", "Выберите таймер для удаления!");
return;
}
TimerInfo timer = m_timers[currentRow];
stopTimer(timer);
m_timers.removeAt(currentRow);
updateTimerTable();
db->SaveTimers(ui->sgTimers, m_timers);
}
void uGeneral::on_btnTimerTest_clicked() {
int currentRow = ui->sgTimers->currentRow();
if (currentRow < 0 || currentRow >= m_timers.size()) {
QMessageBox::warning(this, "Ошибка", "Выберите таймер для теста!");
return;
}
const TimerInfo& timer = m_timers[currentRow];
sendTimedMessage(timer);
}
void uGeneral::on_sgTimers_cellClicked(int row, int column)
{
if (row < 0 || row >= m_timers.size()) return;
TimerInfo& timer = m_timers[row];
if (column == 0) { // Чекбокс "Вкл"
bool newState = ui->sgTimers->item(row, column)->checkState() == Qt::Checked;
if (newState != timer.isActive) {
m_timers[row].isActive = newState;
if (newState) {
// Запускаем только если есть подключение
if (m_isTwitchConnected) {
startTimer(m_timers[row]);
}
} else {
stopTimer(m_timers[row]);
}
db->SaveTimers(ui->sgTimers, m_timers);
}
}
else if (column == 3) { // Чекбокс "О"
bool newState = ui->sgTimers->item(row, column)->checkState() == Qt::Checked;
if (newState != timer.isAnnouncement) {
m_timers[row].isAnnouncement = newState;
db->SaveTimers(ui->sgTimers, m_timers);
}
}
}
void uGeneral::onTimerTimeout(int timerId)
{
}
void uGeneral::on_sgTimers_cellDoubleClicked(int row, int column) {
Q_UNUSED(column);
if (row < 0 || row >= m_timers.size()) return;
const TimerInfo& timer = m_timers[row];
ui->edtTimerMessage->setText(timer.message);
ui->edtTimerInterval->setText(QString::number(timer.interval));
}
void uGeneral::sendRequestToAI(const QString &q)
{
NeuralNetworkManager::NetworkType type;
if (ui->rbGC->isChecked())
{
type = NeuralNetworkManager::GigaChat;
nnManager->setGigaChatCredentials(
ui->edtAIP1->text(), // RqUID
ui->edtAIP2->text() // Basic авторизация в base64
);
}
if (ui->rbCG->isChecked())
{
type = NeuralNetworkManager::ChatGPT;
}
if (ui->rbDS->isChecked())
{
type = NeuralNetworkManager::DeepSeek;
}
if (ui->RBCustom->isChecked())
{
type = NeuralNetworkManager::Ollama;
}
nnManager->setApiKey(type, ui->edtAIP1->text());
nnManager->setPrefix(ui->edtGPTPrefix->text());
// Настройка Ollama
nnManager->setOllamaUrl(ui->edtAIP2->text());
// Отправляем вопрос
nnManager->sendMessage(q, type);
}
void uGeneral::onNeuralResponse(const QString &response) {
// Отправляем ответ в Twitch чат
qDebug() << "Ответ нейросети:" << response;
}
void uGeneral::onNeuralError(const QString &error) {
LogManager::instance()->error("General", "onNeuralError", error);
}
void uGeneral::onSoundGridDoubleClicked()
{
QTextCursor cursor = ui->textBrowser->textCursor();
cursor.insertText("||" + ui->widget->tableWidget()->item(ui->widget->tableWidget()->currentRow(), 0)->text() + "||");
}
void uGeneral::onFilesGridDoubleClicked()
{
QTextCursor cursor = ui->textBrowser->textCursor();
cursor.insertText("|(" + ui->widget_2->tableWidget()->item(ui->widget_2->tableWidget()->currentRow(), 0)->text() + "|(");
}
void uGeneral::onNeiroGridDoubleClicked()
{
QTextCursor cursor = ui->textBrowser->textCursor();
cursor.insertText("<|" + ui->widget_3->tableWidget()->item(ui->widget_3->tableWidget()->currentRow(), 0)->text() + "<|");
}
void uGeneral::initTwitchAPI()
{
QString botClientID = ui->edtBotClientID->text();
QString botToken = ui->edtBotToken->text();
QString botTokenStreamer = ui->edtBotTokenStreamer->text();
QString channel = ui->edtChannel->text();
QString botName = ui->edtBotName->text();
if (botClientID.isEmpty() || botToken.isEmpty() ||
botTokenStreamer.isEmpty() || channel.isEmpty() || botName.isEmpty()) {
LogManager::instance()->warning("uGeneral", "initTwitchAPI",
"Не все данные для инициализации TTwAPI заполнены. API не инициализировано.");
return;
}
// Инициализируем только если не инициализировали ранее
if (twitchAPI) {
// Если уже инициализировано, можно обновить параметры
delete twitchAPI;
}
twitchAPI = new TTwAPI(this);
connect(twitchAPI, &TTwAPI::apiError, this, &uGeneral::onApiError);
connect(twitchAPI, &TTwAPI::tokenExpired, this, &uGeneral::onTokenExpired);
connect(twitchAPI, &TTwAPI::rateLimitExceeded, this, &uGeneral::onRateLimit);
twitchAPI->init(
botClientID,
botToken,
botTokenStreamer,
channel,
botName
);
LogManager::instance()->info("uGeneral", "initTwitchAPI", "TTwAPI успешно инициализировано");
}
void uGeneral::onApiError(const QString &method, const QString &error)
{
LogManager::instance()->error("ttw_api", method, error);
}
void uGeneral::onTokenExpired(const QString &error)
{
LogManager::instance()->error("uGeneral", "onTokenExpired", error);
}
void uGeneral::onRateLimit()
{
LogManager::instance()->warning("uGeneral", "onRateLimit", "Превышен лимит запросов");
}
UserManager* uGeneral::getUserManager()
{
return m_userManager;
}
// Обработчик ответа от AI
void uGeneral::onAIResponseReceived(const QString &response)
{
// Отправляем ответ в чат
if (m_twitchClient) {
// Обрезаем ответ, если он слишком длинный для Twitch
QString chatResponse = response;
if (chatResponse.length() > 400) {
chatResponse = chatResponse.left(397) + "...";
}
m_twitchClient->sendChatMessage(ui->edtChannel->text(), chatResponse);
}
}
// Обработчик ошибок AI
void uGeneral::onAIErrorOccurred(const QString &error)
{
LogManager::instance()->error("General", "onAIErrorOccurred", error);
// Можно отправить сообщение об ошибке в чат
if (m_twitchClient) {
m_twitchClient->sendChatMessage(ui->edtChannel->text(),
"Извините, нейросеть временно недоступна");
}
}
void uGeneral::handleConnected()
{
LogManager::instance()->info("General", "handleConnected", "Connectiong");
setTwitchConnected(true);
loadChatBadges();
// Запускаем активные таймеры, если подключены к Twitch
if (m_isTwitchConnected) {
for (TimerInfo& timer : m_timers) {
if (timer.isActive && !timer.timer) {
startTimer(timer);
}
}
LogManager::instance()->info("General", "handleConnected", "Connected");
}
}
void uGeneral::handleDisconnected()
{
LogManager::instance()->info("General", "handleDisconnected", "Disconnected");
setTwitchConnected(false);
// Запускаем активные таймеры, если подключены к Twitch
if (m_isTwitchConnected) {
for (TimerInfo& timer : m_timers) {
if (timer.isActive && !timer.timer) {
stopTimer(timer);
}
}
}
}
void uGeneral::closeEvent(QCloseEvent *event)
{
Q_UNUSED(event);
// Выполнение действий перед закрытием
}
void uGeneral::toCommands(QString command, QString response)
{
// Добавляем новую строку в таблицу
int row = ui->sgCommands->rowCount();
ui->sgCommands->insertRow(row);
QTableWidgetItem *commandItem = new QTableWidgetItem(command);
QTableWidgetItem *responseItem = new QTableWidgetItem(response);
ui->sgCommands->setItem(row, 0, commandItem);
ui->sgCommands->setItem(row, 1, responseItem);
ui->sgCommands->scrollToBottom();
}
void uGeneral::onLogEntryAdded(const LogEntry& entry)
{
// Проверяем фильтры
if (!shouldShowLogEntry(entry.level)) {
return;
}
// Добавляем запись в таблицу
addLogToTable(entry, ui->sgLog->rowCount());
}
void uGeneral::onLogCleared()
{
ui->sgLog->setRowCount(0);
}
bool uGeneral::shouldShowLogEntry(LogLevel level)
{
switch (level) {
case LogLevel::Info:
return ui->cbInfo->isChecked();
case LogLevel::Warning:
return ui->cbWarning->isChecked();
case LogLevel::Error:
return ui->cbError->isChecked();
case LogLevel::Debug:
return ui->cbDebug->isChecked();
case LogLevel::Critical:
return true; // Критические ошибки всегда показываем
default:
return true;
}
}
void uGeneral::addLogToTable(const LogEntry &entry, int row)
{
// Добавляем новую строку
ui->sgLog->insertRow(row);
// Получаем цвет для уровня из настроек LogManager
LogSettings settings = LogManager::instance()->settings();
QColor color = settings.colors.value(entry.level, LogEntry::levelToColor(entry.level));
// Колонка 0: Дата
QTableWidgetItem* timeItem = new QTableWidgetItem(
entry.timestamp.toString("hh:mm:ss"));
timeItem->setForeground(color);
// Колонка 1: Тип
QTableWidgetItem* typeItem = new QTableWidgetItem(
LogEntry::levelToString(entry.level));
typeItem->setForeground(color);
// Колонка 2: Модуль
QTableWidgetItem* moduleItem = new QTableWidgetItem(entry.module);
moduleItem->setForeground(color);
// Колонка 3: Метод
QTableWidgetItem* methodItem = new QTableWidgetItem(entry.method);
methodItem->setForeground(color);
// Колонка 4: Сообщение
QTableWidgetItem* messageItem = new QTableWidgetItem(entry.message);
messageItem->setForeground(color);
ui->sgLog->setItem(row, 0, timeItem);
ui->sgLog->setItem(row, 1, typeItem);
ui->sgLog->setItem(row, 2, moduleItem);
ui->sgLog->setItem(row, 3, methodItem);
ui->sgLog->setItem(row, 4, messageItem);
ui->sgLog->scrollToBottom();
}
void uGeneral::applyLogFilter()
{
// Очищаем таблицу
ui->sgLog->setRowCount(0);
// Получаем все записи из LogManager
QList<LogEntry> allEntries = LogManager::instance()->allEntries();
// Добавляем только те записи, которые соответствуют фильтру
for (const LogEntry &entry : allEntries) {
if (shouldShowLogEntry(entry.level)) {
addLogToTable(entry, ui->sgLog->rowCount());
}
}
}
void uGeneral::loadSettings(){
//авторизация твитча
ui->edtBotName->setText(db->readSetting(ui->edtBotName->objectName(),""));
ui->edtChannel->setText(db->readSetting(ui->edtChannel->objectName(),""));
ui->edtBotToken->setText(db->readSetting(ui->edtBotToken->objectName(),""));
ui->edtBotClientID->setText(db->readSetting(ui->edtBotClientID->objectName(),""));
ui->edtBotTokenStreamer->setText(db->readSetting(ui->edtBotTokenStreamer->objectName(),""));
ui->cbTTVAutoLogin->setChecked(db->readSetting(ui->cbTTVAutoLogin->objectName()) == "True");
//авторизация донейшон алертс
ui->edtDACode->setText(db->readSetting(ui->edtDACode->objectName(),""));
ui->edtDAClientID->setText(db->readSetting(ui->edtDAClientID->objectName(),""));
ui->edtDARedirectURL->setText(db->readSetting(ui->edtDARedirectURL->objectName(),""));
ui->edtDAClientSecret->setText(db->readSetting(ui->edtDAClientSecret->objectName(),""));
ui->cbDAAutoLogin->setChecked(db->readSetting(ui->cbDAAutoLogin->objectName()) == "True");
//Нейронки
ui->edtGPTPrefix->setText(db->readSetting(ui->edtGPTPrefix->objectName(),""));
ui->edtAIP1->setText(db->readSetting(ui->edtAIP1->objectName(),""));
ui->edtAIP2->setText(db->readSetting(ui->edtAIP2->objectName(),""));
ui->edtKandiKey->setText(db->readSetting(ui->edtKandiKey->objectName(),""));
ui->edtKandiSecret->setText(db->readSetting(ui->edtKandiSecret->objectName(),""));
int rg = db->readSetting("aiIndex","0").toInt();
switch (rg) {
case 0:
ui->rbGC->setChecked(true);
ui->rbDS->setChecked(false);
ui->rbCG->setChecked(false);
ui->RBCustom->setChecked(false);
break;
case 1:
ui->rbGC->setChecked(false);
ui->rbDS->setChecked(true);
ui->rbCG->setChecked(false);
ui->RBCustom->setChecked(false);
break;
case 2:
ui->rbGC->setChecked(false);
ui->rbDS->setChecked(false);
ui->rbCG->setChecked(true);
ui->RBCustom->setChecked(false);
break;
case 3:
ui->rbGC->setChecked(false);
ui->rbDS->setChecked(false);
ui->rbCG->setChecked(false);
ui->RBCustom->setChecked(true);
break;
}
//уведомления
ui->edtNotifyFileName->setText(db->readSetting(ui->edtNotifyFileName->objectName(),""));
ui->edtNotifyFileNameMod->setText(db->readSetting(ui->edtNotifyFileNameMod->objectName(),""));
ui->edtNotifyFileNameSub->setText(db->readSetting(ui->edtNotifyFileNameSub->objectName(),""));
ui->edtNotifyFileNameVip->setText(db->readSetting(ui->edtNotifyFileNameVip->objectName(),""));
ui->chEnNotify->setChecked(db->readSetting(ui->chEnNotify->objectName()) == "True");
ui->chEnNotifyMod->setChecked(db->readSetting(ui->chEnNotifyMod->objectName()) == "True");
ui->chEnNotifySub->setChecked(db->readSetting(ui->chEnNotifySub->objectName()) == "True");
ui->chEnNotifyVip->setChecked(db->readSetting(ui->chEnNotifyVip->objectName()) == "True");
ui->tbNotifyVolume->setValue(db->readSetting(ui->tbNotifyVolume->objectName()).toInt());
ui->tbNotifyVolumeMod->setValue(db->readSetting(ui->tbNotifyVolumeMod->objectName()).toInt());
ui->tbNotifyVolumeSub->setValue(db->readSetting(ui->tbNotifyVolumeSub->objectName()).toInt());
ui->tbNotifyVolumeVip->setValue(db->readSetting(ui->tbNotifyVolumeVip->objectName()).toInt());
ui->cbNotifyFileAgain1->setChecked(db->readSetting(ui->cbNotifyFileAgain1->objectName()) == "True");
ui->cbNotifyFileAgain2->setChecked(db->readSetting(ui->cbNotifyFileAgain2->objectName()) == "True");
ui->cbNotifyFileAgain3->setChecked(db->readSetting(ui->cbNotifyFileAgain3->objectName()) == "True");
db->LoadTableWidget(ui->sgCommands);
db->LoadTableWidget(ui->sgRandomInt);
FSingleGrid *form = ui->widget;
form->setDatabase(db);
QTableWidget *table = form->findChild<QTableWidget*>("sgSounds");
db->LoadTableWidget(table);
form = ui->widget_2;
form->setDatabase(db);
table = form->findChild<QTableWidget*>("sgFiles");
db->LoadTableWidget(table);
form = ui->widget_3;
form->setDatabase(db);
table = form->findChild<QTableWidget*>("sgNeiro");
db->LoadTableWidget(table);
db->LoadRandomGroups(ui->lbRandomGroup);
ui->cbTheme->setCurrentIndex(db->readSetting(ui->cbTheme->objectName(), "0").toInt());
db->LoadTableWidget(ui->sgWebServers);
loadSavedChats();
loadSavedNotifications();
}
void uGeneral::on_btnGetTockenBot_clicked()
{
QString clientId = ui->edtBotClientID->text();
if (clientId.isEmpty()) {
QMessageBox::warning(this, "Ошибка", "Введите Client ID");
return;
}
QString scope = "moderator:manage:shoutouts+"
"moderator:manage:announcements+"
"moderator:manage:banned_users+"
"moderator:manage:warnings+"
"moderator:read:followers+"
"channel:manage:raids+"
"channel:manage:moderators+"
"channel:read:redemptions+"
"chat:read+"
"chat:edit+"
"user:read:emotes";
scope = scope.replace(":", "%3A");
QString authUrl = QString("https://id.twitch.tv/oauth2/authorize?"
"client_id=%1&"
"redirect_uri=http://localhost:8089&"
"response_type=token&"
"scope=%2")
.arg(clientId)
.arg(scope);
// Создаем и показываем окно с ссылкой
if (!fLinkForm) {
fLinkForm = new uLink(this);
}
// Устанавливаем ссылку в окно (предполагается, что в uLink есть метод setLink)
fLinkForm->setLinkText(authUrl);
fLinkForm->show();
// Запускаем сервер без открытия браузера (false)
m_authBot->startServer(authUrl, false);
}
void uGeneral::on_btnOpenFolderSettings_clicked()
{
QString roamingPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QUrl url = QUrl::fromLocalFile(roamingPath);
QDesktopServices::openUrl(url);
}
void uGeneral::on_btnGetTokenStreamer_clicked()
{
//ykui0quht3tvr06vfqhdj5idmhginn
QString clientId = ui->edtBotClientID->text();
if (clientId.isEmpty()) {
QMessageBox::warning(this, "Ошибка", "Введите Client ID");
return;
}
// Для стримера могут быть другие scope, если нужно
QString scope = "channel:manage:broadcast+"
"channel:read:subscriptions+"
"channel:read:redemptions+"
"user:read:email";
scope = scope.replace(":", "%3A");
QString authUrl = QString("https://id.twitch.tv/oauth2/authorize?"
"client_id=%1&"
"redirect_uri=http://localhost:8089&"
"response_type=token&"
"scope=%2")
.arg(clientId)
.arg(scope);
// Запускаем сервер с открытием браузера (true)
m_authStreamer->startServer(authUrl, true);
}
// Обработчик получения токена
void uGeneral::onTokenReceived(const QString &token)
{
ui->edtBotToken->setText(token);
}
void uGeneral::onTokenReceived2(const QString &token)
{
ui->edtBotTokenStreamer->setText(token);
fLinkForm->close();
}
void uGeneral::onTokenReceived3(const QString &token)
{
ui->edtDACode->setText(token);
}
void uGeneral::onAuthError(const QString &error)
{
}
void uGeneral::on_btnDAGetCode_clicked()
{
QString clientId = ui->edtDAClientID->text();
QString clientSecret = ui->edtDAClientSecret->text();
QString redirectUri = ui->edtDARedirectURL->text();
if (clientId.isEmpty() || clientSecret.isEmpty() || redirectUri.isEmpty()) {
QMessageBox::warning(this, "Ошибка", "Заполните все поля для DonationAlerts");
return;
}
QString encodedRedirectUri = QString::fromUtf8(QUrl::toPercentEncoding(redirectUri));
QString authUrl = QString("https://www.donationalerts.com/oauth/authorize?"
"client_id=%1&"
"redirect_uri=%2&"
"response_type=code&"
"scope=oauth-donation-index")
.arg(clientId)
.arg(encodedRedirectUri);
// Запускаем сервер с открытием браузера
m_authDA->startServer(authUrl, true);
}
void uGeneral::on_btnImportSettings_clicked()
{
}
void uGeneral::on_btnExportSettings_clicked()
{
}
void uGeneral::on_RBCustom_pressed()
{
ui->lblAPI1->setText("API Token");
ui->lblAPI1->setVisible(true);
ui->edtAIP1->setVisible(true);
ui->lblAPI2->setText("URL");
ui->lblAPI2->setVisible(true);
ui->edtAIP2->setVisible(true);
ui->lblAPI3->setText("");
ui->lblAPI3->setVisible(false);
ui->edtAIP3->setVisible(false);
ui->cbOllama->setVisible(true);
ui->edtAIP1->setEchoMode(QLineEdit::Password);
ui->edtAIP2->setEchoMode(QLineEdit::Normal);
ui->edtAIP3->setEchoMode(QLineEdit::Password);
}
void uGeneral::on_rbGC_clicked()
{
ui->lblAPI1->setText("ClientID");
ui->lblAPI1->setVisible(true);
ui->edtAIP1->setVisible(true);
ui->lblAPI2->setText("Autorization Code");
ui->lblAPI2->setVisible(true);
ui->edtAIP2->setVisible(true);
ui->lblAPI3->setText("");
ui->lblAPI3->setVisible(false);
ui->edtAIP3->setVisible(false);
ui->cbOllama->setVisible(false);
ui->edtAIP1->setEchoMode(QLineEdit::Password);
ui->edtAIP2->setEchoMode(QLineEdit::Password);
ui->edtAIP3->setEchoMode(QLineEdit::Password);
}
void uGeneral::on_rbDS_clicked()
{
ui->lblAPI1->setText("API Token");
ui->lblAPI1->setVisible(true);
ui->edtAIP1->setVisible(true);
ui->lblAPI2->setText("");
ui->lblAPI2->setVisible(false);
ui->edtAIP2->setVisible(false);
ui->lblAPI3->setText("");
ui->lblAPI3->setVisible(false);
ui->edtAIP3->setVisible(false);
ui->cbOllama->setVisible(false);
ui->edtAIP1->setEchoMode(QLineEdit::Password);
ui->edtAIP2->setEchoMode(QLineEdit::Password);
ui->edtAIP3->setEchoMode(QLineEdit::Password);
}
void uGeneral::on_rbCG_clicked()
{
ui->lblAPI1->setText("API Token");
ui->lblAPI1->setVisible(true);
ui->edtAIP1->setVisible(true);
ui->lblAPI2->setText("");
ui->lblAPI2->setVisible(false);
ui->edtAIP2->setVisible(false);
ui->lblAPI3->setText("");
ui->lblAPI3->setVisible(false);
ui->edtAIP3->setVisible(false);
ui->cbOllama->setVisible(false);
ui->edtAIP1->setEchoMode(QLineEdit::Password);
ui->edtAIP2->setEchoMode(QLineEdit::Password);
ui->edtAIP3->setEchoMode(QLineEdit::Password);
}
void uGeneral::on_btnNotifyCheck_clicked()
{
QString fn = ui->edtNotifyFileName->text();
soundManager->loadSound(SoundManager::Channel2, fn);
soundManager->setVolume(SoundManager::Channel2, ui->tbNotifyVolume->value());
soundManager->playSound(SoundManager::Channel2);
}
void uGeneral::on_btnNotifyCheckMod_clicked()
{
QString fn = ui->edtNotifyFileNameMod->text();
soundManager->loadSound(SoundManager::Channel2, fn);
soundManager->setVolume(SoundManager::Channel2, ui->tbNotifyVolumeMod->value());
soundManager->playSound(SoundManager::Channel2);
}
void uGeneral::on_btnNotifyCheckVip_clicked()
{
QString fn = ui->edtNotifyFileNameVip->text();
soundManager->loadSound(SoundManager::Channel2, fn);
soundManager->setVolume(SoundManager::Channel2, ui->tbNotifyVolumeVip->value());
soundManager->playSound(SoundManager::Channel2);
}
void uGeneral::on_btnNotifyCheckSub_clicked()
{
QString fn = ui->edtNotifyFileNameSub->text();
soundManager->loadSound(SoundManager::Channel2, fn);
soundManager->setVolume(SoundManager::Channel2, ui->tbNotifyVolumeSub->value());
soundManager->playSound(SoundManager::Channel2);
}
void uGeneral::on_btnNotifyOpen_clicked()
{
}
void uGeneral::on_btnNotifyOpenMod_clicked()
{
QString sourceFile = QFileDialog::getOpenFileName(this,
"Выберите файл для уведомлений",
QDir::homePath(),
"Звуковой файл (*.mp3);;Все файлы (*.*)");
if (sourceFile.isEmpty()) {
return; // Пользователь отменил выбор
}
ui->edtNotifyFileNameMod->setText(sourceFile);
}
void uGeneral::on_btnNotifyOpenVip_clicked()
{
QString sourceFile = QFileDialog::getOpenFileName(this,
"Выберите файл для уведомлений",
QDir::homePath(),
"Звуковой файл (*.mp3);;Все файлы (*.*)");
if (sourceFile.isEmpty()) {
return; // Пользователь отменил выбор
}
ui->edtNotifyFileNameVip->setText(sourceFile);
}
void uGeneral::on_btnNotifyOpenSub_clicked()
{
QString sourceFile = QFileDialog::getOpenFileName(this,
"Выберите файл для уведомлений",
QDir::homePath(),
"Звуковой файл (*.mp3);;Все файлы (*.*)");
if (sourceFile.isEmpty()) {
return; // Пользователь отменил выбор
}
ui->edtNotifyFileNameSub->setText(sourceFile);
}
void uGeneral::onStatus(const QString &statusText, int statusCode)
{
qDebug() << "[STATUS]" << statusCode << statusText;
}
void uGeneral::onDisconnected(const QString &reason)
{
qDebug() << "[DISCONNECTED]" << reason;
}
void uGeneral::onJoined(const QString &nickname)
{
qDebug() << "[JOINED]" << nickname << "joined";
}
void uGeneral::onMessage(const QString &message)
{
qDebug() << "[MESSAGE]" << message;
}
void uGeneral::playNotify(const bool &isMod, const bool &isVip, const bool &isSub)
{
// Проверяем модератора (самый высокий приоритет)
if (isMod && ui->chEnNotifyMod->isChecked() &&
!ui->edtNotifyFileNameMod->text().isEmpty())
{
QString fn;
if (ui->cbNotifyFileAgain1->isChecked())
fn = ui->edtNotifyFileName->text();
else
fn = ui->edtNotifyFileNameMod->text();
if (!fn.isEmpty())
{
// Проверяем, существует ли файл
if (QFile::exists(fn)) {
// Загружаем и воспроизводим звук
soundManager->loadSound(SoundManager::Channel2, fn);
soundManager->setVolume(SoundManager::Channel2, ui->tbNotifyVolumeMod->value());
soundManager->playSound(SoundManager::Channel2);
} else {
}
return;
}
}
// Проверяем VIP (второй приоритет)
if (isVip && ui->chEnNotifyVip->isChecked() &&
!ui->edtNotifyFileNameVip->text().isEmpty())
{
QString fn;
if (ui->cbNotifyFileAgain2->isChecked())
fn = ui->edtNotifyFileName->text();
else
fn = ui->edtNotifyFileNameVip->text();
if (!fn.isEmpty())
{
soundManager->loadSound(SoundManager::Channel2, fn);
soundManager->setVolume(SoundManager::Channel2, ui->tbNotifyVolumeVip->value());
soundManager->playSound(SoundManager::Channel2);
} else {
}
return;
}
// Проверяем подписчика (третий приоритет)
if (isSub && ui->chEnNotifySub->isChecked() &&
!ui->edtNotifyFileNameSub->text().isEmpty())
{
QString fn;
if (ui->cbNotifyFileAgain3->isChecked())
fn = ui->edtNotifyFileName->text();
else
fn = ui->edtNotifyFileNameSub->text();
if (!fn.isEmpty())
{
soundManager->loadSound(SoundManager::Channel2, fn);
soundManager->setVolume(SoundManager::Channel2, ui->tbNotifyVolumeSub->value());
soundManager->playSound(SoundManager::Channel2);
} else {
}
return;
}
// Проверяем общий звук для всех (низший приоритет)
if (ui->chEnNotify->isChecked() && !ui->edtNotifyFileName->text().isEmpty())
{
QString fn = ui->edtNotifyFileName->text();
if (QFile::exists(fn)) {
// Загружаем и воспроизводим звук
soundManager->loadSound(SoundManager::Channel2, fn);
soundManager->setVolume(SoundManager::Channel2, ui->tbNotifyVolume->value());
soundManager->playSound(SoundManager::Channel2);
} else {
}
return;
}
}
/**
* @brief Инициализирует звуковые уведомления
*/
void uGeneral::initializeNotificationSounds()
{
// Загружаем звук для обычных уведомлений
QString notifyFile = ui->edtNotifyFileName->text();
if (!notifyFile.isEmpty() && QFile::exists(notifyFile)) {
soundManager->loadSound(SoundManager::Channel2, notifyFile);
soundManager->setVolume(SoundManager::Channel2, ui->tbNotifyVolume->value());
} else {
}
// Загружаем звук для модераторов
QString notifyModFile = ui->edtNotifyFileNameMod->text();
if (!notifyModFile.isEmpty() && QFile::exists(notifyModFile)) {
// Загружаем в отдельный канал, если SoundManager поддерживает несколько каналов
// Или используем ту же логику, что и в playNotify
}
// Загружаем звук для VIP
QString notifyVipFile = ui->edtNotifyFileNameVip->text();
if (!notifyVipFile.isEmpty() && QFile::exists(notifyVipFile)) {
}
// Загружаем звук для подписчиков
QString notifySubFile = ui->edtNotifyFileNameSub->text();
if (!notifySubFile.isEmpty() && QFile::exists(notifySubFile)) {
}
}
void uGeneral::handleNewMessage( const QString &message){
TwitchMessage msg = TwitchMessage::parse(message);
// Проверяем и регистрируем пользователя
QString userId = m_userManager->checkUser(msg.displayName, msg);
m_userManager->m_totalMessages++;
// Обновляем статистику и воспроизводим уведомление
if (m_userWidget) {
m_userWidget->updateStatistics();
}
playNotify(msg.isMod, msg.isVIP, msg.isSubscriber);
// Обрабатываем сообщение Twitch (смайлы, бейджи и т.д.)
QString processedMessage = processTwitchMessage(msg);
QString formattedNickname = formatNicknameWithBadges(msg);
// Добавляем сообщение в чат
addChatMessage(formattedNickname, processedMessage);
// Обрабатываем команды если сообщение начинается с "!"
if (msg.message.startsWith("!!!")) {
QString cleanedMessage = msg.message.mid(3);
// speachMessage(cleanedMessage);
} else if (msg.message.startsWith("!")) {
QString cleanedMessage = msg.message.mid(1);
processUserCommand(userId, cleanedMessage);
} else {
// execClearMessage(msg.message);
}
}
/**
* @brief Обработка команды от пользователя
*/
void uGeneral::processUserCommand(const QString &username, const QString &commandText)
{
if (!m_commandProcessor || !m_userManager) return;
// Разделяем команду и параметры
QString command;
QString parameters;
int spacePos = commandText.indexOf(' ');
if (spacePos != -1) {
command = commandText.left(spacePos).trimmed().toLower();
parameters = commandText.mid(spacePos + 1).trimmed();
} else {
command = commandText.trimmed().toLower();
}
// Если команда пустая, ничего не делаем
if (command.isEmpty()) return;
// Генерируем ответ через CommandProcessor
QString response = m_commandProcessor->generateResponse(username, command, parameters);
// Если есть ответ, отправляем его в чат
if (!response.isEmpty()) {
sendChatResponse(response);
}
}
/**
* @brief Отправка ответа команды в чат
*/
void uGeneral::sendChatResponse(const QString &response)
{
m_twitchClient->sendChatMessage(ui->edtChannel->text(), response);
}
void uGeneral::handleError(const QString &errorMessage){
}
// Метод для обработки Twitch сообщения с эмодзи
QString uGeneral::processTwitchMessage(const TwitchMessage &msg)
{
QString processedMessage = msg.message;
// 1. Обрабатываем Twitch эмодзи (из поля emotes)
if (!msg.emotes.isEmpty()) {
processedMessage = replaceTwitchEmotes(msg.emotes, processedMessage);
}
// 2. Обрабатываем BTTV и 7TV эмодзи
processedMessage = replaceCustomEmotes(processedMessage);
return processedMessage;
}
// Метод для замены Twitch эмодзи на HTML изображения
QString uGeneral::replaceTwitchEmotes(const QString &emotesData, const QString &message)
{
if (emotesData.isEmpty()) return message;
QString result = message;
// Формат emotesData: "emote_id:start-end,start-end/emote_id2:start-end"
QStringList emoteList = emotesData.split('/', Qt::SkipEmptyParts);
// Создаем структуру для хранения замен
struct Replacement {
int start;
int end;
QString html;
};
QList<Replacement> replacements;
for (const QString &emote : emoteList) {
QStringList parts = emote.split(':');
if (parts.size() != 2) continue;
QString emoteId = parts[0];
QStringList positions = parts[1].split(',', Qt::SkipEmptyParts);
for (const QString &pos : positions) {
QStringList startEnd = pos.split('-');
if (startEnd.size() != 2) continue;
bool ok;
int start = startEnd[0].toInt(&ok);
if (!ok) continue;
int end = startEnd[1].toInt(&ok);
if (!ok) continue;
// Формируем HTML для эмодзи
QString emoteUrl = QString("https://static-cdn.jtvnw.net/emoticons/v2/%1/default/dark/1.0").arg(emoteId);
QString emoteHtml = QString("<img src=\"%1\" alt=\"%2\" style=\"height: 1em; vertical-align: middle;\">")
.arg(emoteUrl)
.arg(message.mid(start, end - start + 1));
replacements.append({start, end, emoteHtml});
}
}
// Сортируем по убыванию позиции начала, чтобы не сбивались индексы при замене
std::sort(replacements.begin(), replacements.end(),
[](const Replacement &a, const Replacement &b) {
return a.start > b.start;
});
// Выполняем замены
for (const auto &replacement : replacements) {
result.replace(replacement.start,
replacement.end - replacement.start + 1,
replacement.html);
}
return result;
}
QString uGeneral::replaceCustomEmotes(const QString &message)
{
QString result = message;
// Используем регулярное выражение для поиска слов
QRegularExpression wordRegex("([a-zA-Z0-9_-]+)");
QRegularExpressionMatchIterator matches = wordRegex.globalMatch(message);
// Структура для хранения замен
struct EmoteReplacement {
int start;
int length;
QString html;
};
QList<EmoteReplacement> replacements;
while (matches.hasNext()) {
QRegularExpressionMatch match = matches.next();
QString word = match.captured(1);
int start = match.capturedStart(1);
int length = match.capturedLength(1);
// Пропускаем слишком короткие слова (меньше 2 символов)
if (word.length() < 2) continue;
// Проверяем BTTV эмодзи
QString bttvUrl = bttvProvider.getEmoteUrl(word);
if (!bttvUrl.isEmpty()) {
QString emoteHtml = QString("<img src=\"%1\" alt=\"%2\" style=\"height: 1em; vertical-align: middle;\">")
.arg(bttvUrl)
.arg(word);
replacements.append({start, length, emoteHtml});
continue;
}
// Проверяем 7TV эмодзи
QString sevenTVUrl = sevenTVProvider.getEmoteUrl(word);
if (!sevenTVUrl.isEmpty()) {
QString emoteHtml = QString("<img src=\"%1\" alt=\"%2\" style=\"height: 1em; vertical-align: middle;\">")
.arg(sevenTVUrl)
.arg(word);
replacements.append({start, length, emoteHtml});
continue;
}
}
// Сортируем по убыванию позиции начала (заменяем с конца к началу)
std::sort(replacements.begin(), replacements.end(),
[](const EmoteReplacement &a, const EmoteReplacement &b) {
return a.start > b.start;
});
// Выполняем замены с конца к началу
for (const auto &replacement : replacements) {
result.replace(replacement.start, replacement.length, replacement.html);
}
return result;
}
void uGeneral::on_pushButton_2_clicked()
{
if (ui->pushButton_2->text() != "Отключиться")
{
QString oauthToken = "oauth:" + ui->edtBotToken->text();
QString nickname = ui->edtBotName->text();
QString channel = ui->edtChannel->text();
m_twitchClient->connectToTwitchChat(oauthToken, nickname, channel);
ui->pushButton_2->setText("Отключиться");
}
else
{
m_twitchClient->disconnectFromServer();
m_userManager->clear();
ui->pushButton_2->setText("Подключиться");
setTwitchConnected(false);
}
}
void uGeneral::execCommand(const QString &sender, const QString &message)
{
LogManager::instance()->debug("uGeneral", "execCommand",
QString("Обработка команды от %1: %2").arg(sender).arg(message));
}
void uGeneral::on_lbRandomGroup_itemClicked(QListWidgetItem *item)
{
db->LoadRandomResponses(item->text(), ui->lbRandomRespons);
}
void uGeneral::on_pushButton_clicked()
{
LogManager::instance()->clear();
}
void uGeneral::on_sgCommands_cellDoubleClicked(int row, int column)
{
Q_UNUSED(column);
ui->edtCommand->setText(ui->sgCommands->item(row, 0)->text());
ui->textBrowser->setPlainText(ui->sgCommands->item(row, 1)->text());
}
void uGeneral::on_btnRandAdd_clicked()
{
// Получаем данные из полей ввода
QString name = ui->edtRandomName->text().trimmed();
int otValue = ui->edtOt->value();
int toValue = ui->edtTo->value();
// Проверяем, что имя не пустое
if (name.isEmpty()) {
QMessageBox::warning(this, "Внимание", "Введите название!");
ui->edtRandomName->setFocus();
return;
}
// Проверяем корректность диапазона
if (otValue > toValue) {
QMessageBox::warning(this, "Внимание",
"Значение 'От' не может быть больше значения 'До'!");
ui->edtOt->setFocus();
return;
}
m_randomManager->rangeAdded(name, otValue, toValue);
}
void uGeneral::on_btnRandDel_clicked()
{
// Проверяем, есть ли выделенная строка
if (!ui->sgRandomInt->currentItem()) {
QMessageBox::warning(this, "Внимание", "Выберите строку для удаления!");
return;
}
// Получаем индекс выделенной строки
int row = ui->sgRandomInt->currentItem()->row();
m_randomManager->rangeRemoved(ui->sgRandomInt->item(row, 0)->text());
}
void uGeneral::on_sgRandomInt_cellClicked(int row, int column)
{
Q_UNUSED(column);
ui->edtRandomName->setText(ui->sgRandomInt->item(row, 0)->text());
ui->edtOt->setValue(ui->sgRandomInt->item(row, 1)->text().toInt());
ui->edtTo->setValue(ui->sgRandomInt->item(row, 2)->text().toInt());
}
void uGeneral::on_sgRandomInt_cellDoubleClicked(int row, int column)
{
Q_UNUSED(column);
QTextCursor cursor = ui->textBrowser->textCursor();
cursor.insertText("[[" + ui->sgRandomInt->item(row, 0)->text() + "]]");
}
void uGeneral::on_lbRandomGroup_doubleClicked(const QModelIndex &index)
{
Q_UNUSED(index);
QTextCursor cursor = ui->textBrowser->textCursor();
cursor.insertText("{{" + ui->lbRandomGroup->currentItem()->text() + "}}");
}
void uGeneral::on_lbRandomRespons_itemDoubleClicked(QListWidgetItem *item)
{
ui->edtRandomGroup->setText(ui->lbRandomGroup->currentItem()->text());
ui->edtRandomRespons->setText(item->text());
}
void uGeneral::on_btnRandomAdd_clicked()
{
QString groupName = ui->edtRandomGroup->text().trimmed();
QString response = ui->edtRandomRespons->text().trimmed();
// Проверка входных данных
if (groupName.isEmpty()) {
QMessageBox::warning(this, "Ошибка", "Введите название группы!");
return;
}
if (response.isEmpty()) {
QMessageBox::warning(this, "Ошибка", "Введите ответ!");
return;
}
// Добавляем ответ в базу данных
if (!db->AddGroupResponse(groupName, response)) {
QMessageBox::critical(this, "Ошибка",
"Не удалось добавить ответ в базу данных:\n" + db->lastError());
return;
}
// Обновляем список групп (если новая группа)
db->LoadRandomGroups(ui->lbRandomGroup);
// Находим и выбираем только что добавленную группу в списке
QList<QListWidgetItem*> items = ui->lbRandomGroup->findItems(groupName, Qt::MatchExactly);
if (!items.isEmpty()) {
ui->lbRandomGroup->setCurrentItem(items.first());
}
// Обновляем список ответов для выбранной группы
if (ui->lbRandomGroup->currentItem()) {
db->LoadRandomResponses(ui->lbRandomGroup->currentItem()->text(), ui->lbRandomRespons);
} else {
// Если группа не выбрана, очищаем список ответов
ui->lbRandomRespons->clear();
}
// Очищаем поля ввода
ui->edtRandomRespons->clear();
}
void uGeneral::on_btnRandomDel_clicked()
{
db->DeleteResponse(ui->lbRandomGroup->currentItem()->text(), ui->lbRandomRespons->currentItem()->text());
db->LoadRandomResponses(ui->lbRandomGroup->currentItem()->text(), ui->lbRandomRespons);
}
void uGeneral::on_btnRmGroup_clicked()
{
db->DeleteGroup(ui->lbRandomGroup->currentItem()->text());
db->LoadRandomGroups(ui->lbRandomGroup);
}
void uGeneral::on_btnAddUserName_clicked()
{
QTextCursor cursor = ui->textBrowser->textCursor();
cursor.insertText("[USERNAME]");
}
void uGeneral::on_btnGetDateFollow_clicked()
{
QTextCursor cursor = ui->textBrowser->textCursor();
cursor.insertText("[FOLLOW]");
}
void uGeneral::on_btnGetAgeAccaunt_clicked()
{
QTextCursor cursor = ui->textBrowser->textCursor();
cursor.insertText("[AGE]");
}
void uGeneral::on_btnGPT_clicked()
{
QTextCursor cursor = ui->textBrowser->textCursor();
cursor.insertText("[AI]");
}
void uGeneral::on_btnAIPic_clicked()
{
QTextCursor cursor = ui->textBrowser->textCursor();
cursor.insertText("[Kandinsky]");
}
void uGeneral::on_btnRandomUserName_clicked()
{
QTextCursor cursor = ui->textBrowser->textCursor();
cursor.insertText("[RANDOMUSER]");
}
void uGeneral::on_btnGetChannelStat_clicked()
{
QTextCursor cursor = ui->textBrowser->textCursor();
cursor.insertText("[STAT]");
}
void uGeneral::on_btnAddCommand_clicked()
{
QString name = ui->edtCommand->text().trimmed();
QString response = ui->textBrowser->toPlainText();
if (name.isEmpty()) {
QMessageBox::warning(this, "Внимание", "Введите команду!");
LogManager::instance()->warning("uGeneral", "on_btnAddCommand_clicked",
"Попытка добавить команду с пустым именем");
return;
}
// Просто добавляем в таблицу и сохраняем в БД
// CommandProcessor будет читать из таблицы при обработке
// Добавляем новую строку в таблицу
int row = ui->sgCommands->rowCount();
ui->sgCommands->insertRow(row);
ui->sgCommands->setItem(row, 0, new QTableWidgetItem(name));
ui->sgCommands->setItem(row, 1, new QTableWidgetItem(response));
// Сохраняем в БД
db->SaveTableWidget(ui->sgCommands);
LogManager::instance()->info("uGeneral", "on_btnAddCommand_clicked",
QString("Добавлена команда: %1").arg(name));
}
void uGeneral::on_btnRmCommand_clicked()
{
if (!ui->sgCommands->currentItem()) {
QMessageBox::warning(this, "Внимание", "Выберите команду для удаления!");
LogManager::instance()->warning("uGeneral", "on_btnRmCommand_clicked",
"Не выбрана команда для удаления");
return;
}
int row = ui->sgCommands->currentItem()->row();
QString commandName = ui->sgCommands->item(row, 0)->text();
ui->sgCommands->removeRow(row);
db->SaveTableWidget(ui->sgCommands);
LogManager::instance()->info("uGeneral", "on_btnRmCommand_clicked",
QString("Удалена команда: %1").arg(commandName));
}
void uGeneral::on_btnEdtCommand_clicked()
{
if (!ui->sgCommands->currentItem()) {
QMessageBox::warning(this, "Внимание", "Выберите команду для редактирования!");
LogManager::instance()->warning("uGeneral", "on_btnEdtCommand_clicked",
"Не выбрана команда для редактирования");
return;
}
int row = ui->sgCommands->currentItem()->row();
QString newName = ui->edtCommand->text().trimmed();
QString response = ui->textBrowser->toPlainText();
if (newName.isEmpty()) {
QMessageBox::warning(this, "Внимание", "Введите новое имя команды!");
return;
}
ui->sgCommands->item(row, 0)->setText(newName);
ui->sgCommands->item(row, 1)->setText(response);
db->SaveTableWidget(ui->sgCommands);
LogManager::instance()->info("uGeneral", "on_btnEdtCommand_clicked",
QString("Отредактирована команда в строке %1").arg(row));
}
void uGeneral::loadQssFiles()
{
}
void uGeneral::loadStylesFromDirectory(const QDir &stylesDir, const QString &category)
{
if (!stylesDir.exists()) {
return;
}
// Получаем список QSS файлов в папке
QStringList filters;
filters << "*.qss" << "*.QSS";
QStringList qssFiles = stylesDir.entryList(filters, QDir::Files);
// Добавляем файлы в ComboBox
foreach (const QString &file, qssFiles) {
QString displayName = QString("%1: %2").arg(category).arg(file);
ui->cbTheme->addItem(displayName, stylesDir.absoluteFilePath(file));
}
}
void uGeneral::on_cbTheme_currentIndexChanged(int index)
{
if (index < 0) return;
// Получаем полный путь к файлу из userData
QString filePath = ui->cbTheme->itemData(index).toString();
// Если выбрана "Без темы" (пустая строка в userData)
if (filePath.isEmpty()) {
qApp->setStyleSheet("");
return;
}
// Применяем выбранную тему
applyStyleSheet(filePath);
db->writeSetting(ui->cbTheme->objectName(), QString::number(index));
}
void uGeneral::applyStyleSheet(const QString &filename)
{
QFile file(filename);
// Проверяем, существует ли файл и можем ли мы его открыть
if (!file.exists()) {
qWarning() << "QSS файл не найден:" << filename;
return;
}
if (!file.open(QFile::ReadOnly | QFile::Text)) {
qWarning() << "Не удалось открыть QSS файл:" << filename;
return;
}
// Читаем содержимое файла
QTextStream stream(&file);
QString styleSheet = stream.readAll();
file.close();
// Применяем стили ко всему приложению
qApp->setStyleSheet(styleSheet);
}
void uGeneral::on_btnWSCreateChat_clicked()
{
// Создаем диалог каждый раз
FCreateChat *createDialog = new FCreateChat(db, this);
connect(createDialog, &FCreateChat::serverCreated, this, &uGeneral::onChatServerCreated);
connect(createDialog, &FCreateChat::serverUpdated, this, &uGeneral::onChatServerUpdated);
createDialog->setAttribute(Qt::WA_DeleteOnClose);
createDialog->exec();
}
void uGeneral::on_btnWSCreateNotify_clicked()
{
// Создаем диалог каждый раз
FCreateNotify *createDialog = new FCreateNotify(db, this);
connect(createDialog, &FCreateNotify::serverCreated, this, &uGeneral::onNotifyServerCreated);
createDialog->setAttribute(Qt::WA_DeleteOnClose); // Автоматическое удаление при закрытии
createDialog->exec();
}
// Слоты для приема созданных серверов:
void uGeneral::onChatServerCreated(HttpServerChat *server, const QString &name)
{
if (server) {
// Устанавливаем родителя - главное окно
server->setParent(this);
addChatServer(server, name);
}
}
void uGeneral::onNotifyServerCreated(HttpServer *server, const QString &name)
{
if (!server) return;
// Сохраняем сервер в базе данных
if (!db->saveNotification(name, server)) {
}
// Добавляем сервер в список
m_notificationServers.append(server);
// Добавляем в таблицу
QString url = QString("http://localhost:%1").arg(server->port());
addServerToTable(name, "Уведомления", server->port(), url, server);
}
void uGeneral::onNotifyServerUpdated(HttpServer *server, const QString &name)
{
if (!server) return;
// Найдем старый порт из таблицы
int oldPort = 0;
for (int row = 0; row < ui->sgWebServers->rowCount(); ++row) {
QTableWidgetItem *nameItem = ui->sgWebServers->item(row, 0);
if (nameItem && nameItem->data(Qt::UserRole).value<QObject*>() == server) {
QTableWidgetItem *portItem = ui->sgWebServers->item(row, 2);
if (portItem) {
oldPort = portItem->text().toInt();
}
break;
}
}
// Обновляем сервер в базе данных
if (!db->updateNotification(name, server, oldPort)) {
}
// Обновляем сервер в списке
int index = m_notificationServers.indexOf(server);
if (index >= 0) {
m_notificationServers[index] = server;
}
// Обновляем строку в таблице
for (int row = 0; row < ui->sgWebServers->rowCount(); ++row) {
QTableWidgetItem *nameItem = ui->sgWebServers->item(row, 0);
if (nameItem && nameItem->data(Qt::UserRole).value<QObject*>() == server) {
// Обновляем имя
nameItem->setText(name);
// Обновляем порт
ui->sgWebServers->item(row, 2)->setText(QString::number(server->port()));
// Обновляем ссылку
QString url = QString("http://localhost:%1").arg(server->port());
ui->sgWebServers->item(row, 3)->setText(url);
break;
}
}
}
// Методы добавления серверов:
void uGeneral::addNotificationServer(HttpServer *server, const QString &name)
{
if (!server) return;
m_notificationServers.append(server);
QString serverName = name.isEmpty() ?
QString("Уведомления %1").arg(m_notificationServers.size()) : name;
QString url = QString("http://localhost:%1").arg(server->port());
addServerToTable(serverName, "Уведомления", server->port(), url, server);
}
void uGeneral::addChatServer(HttpServerChat *server, const QString &name)
{
if (!server) return;
m_chatServers.append(server);
QString serverName = name.isEmpty() ?
QString("Чат %1").arg(m_chatServers.size()) : name;
QString url = QString("http://localhost:%1").arg(server->port());
addServerToTable(serverName, "Чат", server->port(), url, server);
}
void uGeneral::addServerToTable(const QString &name, const QString &type,
quint16 port, const QString &url, QObject *serverObj)
{
int row = ui->sgWebServers->rowCount();
ui->sgWebServers->insertRow(row);
// Колонка 0: Название
QTableWidgetItem *nameItem = new QTableWidgetItem(name);
nameItem->setData(Qt::UserRole, QVariant::fromValue<QObject*>(serverObj));
ui->sgWebServers->setItem(row, 0, nameItem);
// Колонка 1: Тип
ui->sgWebServers->setItem(row, 1, new QTableWidgetItem(type));
// Колонка 2: Порт
ui->sgWebServers->setItem(row, 2, new QTableWidgetItem(QString::number(port)));
// Колонка 3: Ссылка (редактируемая для копирования)
QTableWidgetItem *linkItem = new QTableWidgetItem(url);
linkItem->setForeground(QBrush(Qt::blue));
linkItem->setFlags(linkItem->flags() | Qt::ItemIsEditable);
ui->sgWebServers->setItem(row, 3, linkItem);
}
// Методы для внешнего добавления уведомлений и сообщений:
void uGeneral::addNotification(const QString &nickname, double amount, const QString &type)
{
if (m_notificationServers.isEmpty()) {
return;
}
// Берем первый активный сервер (или можно выбрать по ID)
HttpServer *server = m_notificationServers.first();
// Создаем уведомление
Notification notif;
notif.nickname = nickname.isEmpty() ? "Аноним" : nickname;
notif.content = QString("%1 пожертвовал %2 руб.").arg(notif.nickname).arg(amount);
// Настройки по умолчанию (можно сделать конфигурируемыми)
notif.blockColor = "#4CAF50";
notif.borderColor = "#2E7D32";
notif.borderSize = 2;
notif.duration = 10;
notif.titleColor = "#FFFFFF";
notif.titleFamily = "Arial";
notif.titleSize = 20;
notif.contentColor = "#F5F5F5";
notif.contentFamily = "Arial";
notif.contentSize = 16;
notif.pageBackgroundColor = "transparent";
// Можно добавить звук для доната
if (type == "donation") {
notif.soundURL = "/sounds/donation.mp3";
}
server->addNotification(notif);
}
void uGeneral::addChatMessage(const QString &nickname,
const QString &message)
{
if (m_chatServers.isEmpty()) {
return;
}
QString formattedNickname = nickname;
for (HttpServerChat *server : qAsConst(m_chatServers)) {
sendMessageToServer(server, formattedNickname, message);
}
}
// Метод для получения HTML бейджей
QString uGeneral::getBadgesHTML(const TwitchMessage &msg)
{
QString badgesHtml;
// Если у сообщения есть бейджи
for (const TwitchMessage::Badge &badge : msg.badges) {
QString badgeUrl = getBadgeUrl(badge.name, badge.version);
if (!badgeUrl.isEmpty()) {
badgesHtml += QString("<img src=\"%1\" alt=\"%2\" title=\"%3\" "
"style=\"height: 18px; width: 18px; "
"vertical-align: middle; margin-right: 2px;\">")
.arg(badgeUrl)
.arg(badge.name)
.arg(QString("%1 (версия %2)").arg(badge.name).arg(badge.version));
}
}
// Добавляем системные бейджи, если их нет в списке
auto addSystemBadge = [&](const QString &badgeName, bool condition) {
if (condition) {
bool alreadyHas = false;
for (const TwitchMessage::Badge &badge : msg.badges) {
if (badge.name == badgeName) {
alreadyHas = true;
break;
}
}
if (!alreadyHas) {
QString badgeUrl = getBadgeUrl(badgeName, 1);
if (!badgeUrl.isEmpty()) {
badgesHtml += QString("<img src=\"%1\" alt=\"%2\" title=\"%2\" "
"style=\"height: 18px; width: 18px; "
"vertical-align: middle; margin-right: 2px;\">")
.arg(badgeUrl)
.arg(badgeName);
}
}
}
};
addSystemBadge("moderator", msg.isMod);
addSystemBadge("vip", msg.isVIP);
addSystemBadge("subscriber", msg.isSubscriber);
if (!badgesHtml.isEmpty()) {
badgesHtml += " ";
}
return badgesHtml;
}
// Метод для получения URL бейджа
QString uGeneral::getBadgeUrl(const QString &setId, int versionId)
{
// Ищем в загруженных бейджах
for (const ChatBadge &badge : m_chatBadges) {
if (badge.setId == setId) {
for (const BadgeVersion &version : badge.versions) {
if (version.id == versionId) {
return version.imageUrl1x; // или version.imageUrl2x для ретины
}
}
// Если точной версии не нашли, возвращаем первую версию
if (!badge.versions.isEmpty()) {
return badge.versions.first().imageUrl1x;
}
}
}
// Стандартные Twitch бейджи (если не нашли в загруженных)
static const QMap<QString, QString> defaultBadgeUrls = {
{"moderator", "https://static-cdn.jtvnw.net/badges/v1/3267646d-33f0-4b17-b3df-f923a41db1d0/%1"},
{"vip", "https://static-cdn.jtvnw.net/badges/v1/1923c73d-70c9-4b1a-9c93-c8d8bd9e2f31/%1"},
{"subscriber", "https://static-cdn.jtvnw.net/badges/v1/5d9f2208-5dd8-11e7-8513-2ff4adfae661/%1"},
{"broadcaster", "https://static-cdn.jtvnw.net/badges/v1/5527c58c-fb7d-422d-b71b-f309dcb85cc1/%1"},
{"admin", "https://static-cdn.jtvnw.net/badges/v1/9ef7e029-4cdf-4d4d-a0d5-e2b3fb2583fe/%1"},
{"staff", "https://static-cdn.jtvnw.net/badges/v1/d97c37bd-a6f5-4c38-8f57-4e4bef88af34/%1"},
{"turbo", "https://static-cdn.jtvnw.net/badges/v1/bd444ec6-8f34-4bf9-91f4-af1e3428d80f/%1"},
{"partner", "https://static-cdn.jtvnw.net/badges/v1/d12a2e27-16f6-41d0-ab77-b780518f00a3/%1"},
{"bits", "https://static-cdn.jtvnw.net/badges/v1/73b5c3fb-24f9-4a82-a852-2f475b59411c/%1"}
};
if (defaultBadgeUrls.contains(setId)) {
return defaultBadgeUrls[setId].arg(versionId);
}
// Для subscriber бейджей с уровнями
if (setId.startsWith("subscriber-")) {
QString level = setId.mid(11);
return QString("https://static-cdn.jtvnw.net/badges/v1/5d9f2208-5dd8-11e7-8513-2ff4adfae661/%1").arg(level);
}
// Для bits бейджей с уровнями
if (setId.startsWith("bits-")) {
QString level = setId.mid(5);
return QString("https://static-cdn.jtvnw.net/badges/v1/73b5c3fb-24f9-4a82-a852-2f475b59411c/%1").arg(level);
}
// Пытаемся получить URL из стандартного API
return QString("https://static-cdn.jtvnw.net/badges/v1/%1/%2").arg(setId).arg(versionId);
}
// Метод для форматирования ника с бейджами
QString uGeneral::formatNicknameWithBadges(const TwitchMessage &msg)
{
QString result = getBadgesHTML(msg);
// Экранируем HTML-символы
QString escapedName = msg.displayName.toHtmlEscaped();
QString escapedColor = msg.color.toHtmlEscaped();
if (!escapedColor.isEmpty() && escapedColor != "#000000") {
result += QString("<span style=\"color: %1;\">%2</span>")
.arg(escapedColor)
.arg(escapedName);
} else {
result += escapedName;
}
return result;
}
// Вспомогательный метод для отправки сообщения на сервер
void uGeneral::sendMessageToServer(HttpServerChat *server, const QString &nickname,
const QString &message)
{
if (!server) return;
// Создаем стиль сообщения
StyleChat style;
style.nick = nickname;
style.context = message;
// Используем настройки сервера
style.fontFamily = server->getFontFamily();
style.fontSize = server->getFontSize();
style.fontColor = server->getFontColor();
style.blockColor = server->getBlockColor();
style.borderColor = server->getBorderColor();
style.borderSize = server->getBorderSize();
style.padding = server->getPadding();
style.timeMsg = server->getMessageTimeout();
style.bColor = server->getBackgroundColor();
style.transparency = server->getTransparency();
qDebug() << "sendMessageToServer";
// Убираем HTML теги из обычного текста для совместимости
// (если сервер их не поддерживает, можно оставить только для ника)
style.nick = nickname; // Ник уже с цветом
style.context = message; // Сообщение уже обработано с эмодзи
server->addMessage(style);
}
// Обработчик двойного клика по таблице веб-серверов
void uGeneral::on_sgWebServers_cellDoubleClicked(int row, int column)
{
Q_UNUSED(column);
if (row < 0 || row >= ui->sgWebServers->rowCount()) {
return;
}
QTableWidgetItem *nameItem = ui->sgWebServers->item(row, 0);
QTableWidgetItem *typeItem = ui->sgWebServers->item(row, 1);
if (!nameItem || !typeItem) {
return;
}
QString serverType = typeItem->text();
if (serverType.toLower() == "чат") {
// Получаем объект сервера из user data
QObject *serverObj = nameItem->data(Qt::UserRole).value<QObject*>();
HttpServerChat *existingServer = qobject_cast<HttpServerChat*>(serverObj);
if (existingServer) {
FCreateChat *createChatDialog = new FCreateChat(db, this);
createChatDialog->loadExistingServer(existingServer, nameItem->text());
connect(createChatDialog, &FCreateChat::serverUpdated, this, &uGeneral::onChatServerUpdated);
createChatDialog->setAttribute(Qt::WA_DeleteOnClose);
createChatDialog->exec();
}
} else if (serverType.toLower() == "уведомления") {
// Получаем объект сервера из user data
QObject *serverObj = nameItem->data(Qt::UserRole).value<QObject*>();
HttpServer *existingServer = qobject_cast<HttpServer*>(serverObj);
if (existingServer) {
FCreateNotify *createNotifyDialog = new FCreateNotify(db, this);
createNotifyDialog->loadExistingServer(existingServer, nameItem->text());
connect(createNotifyDialog, &FCreateNotify::serverUpdated,
this, &uGeneral::onNotifyServerUpdated);
createNotifyDialog->setAttribute(Qt::WA_DeleteOnClose);
createNotifyDialog->exec();
}
}
}
void uGeneral::loadSavedNotifications()
{
QList<NotificationSettings> notifications = db->loadAllNotifications();
for (const NotificationSettings &settings : notifications) {
if (settings.type.toLower() == "notification") {
// Создаем сервер уведомлений
HttpServer *server = new HttpServer(this);
// Настраиваем сервер
server->setBlockColor(settings.blockColor);
server->setBorderColor(settings.borderColor);
server->setBorderSize(settings.borderSize);
server->setTransparency(settings.transparency);
server->setPageBackgroundColor(settings.pageBackgroundColor);
server->setTitleFont(
settings.titleFamily,
settings.titleSize,
settings.titleColor
);
server->setContentFont(
settings.contentFamily,
settings.contentSize,
settings.contentColor
);
server->setDuration(settings.duration);
// Запускаем сервер
if (server->start(settings.port)) {
m_notificationServers.append(server);
// Добавляем в таблицу
QString url = QString("http://localhost:%1").arg(settings.port);
addServerToTable(settings.name, "Уведомления", settings.port, url, server);
} else {
delete server;
}
}
}
}
void uGeneral::onChatServerUpdated(HttpServerChat *server, const QString &name)
{
if (!server) return;
// Обновляем сервер в списке
int index = m_chatServers.indexOf(server);
if (index >= 0) {
m_chatServers[index] = server;
// Обновляем строку в таблице
for (int row = 0; row < ui->sgWebServers->rowCount(); ++row) {
QTableWidgetItem *portItem = ui->sgWebServers->item(row, 0);
if (portItem && portItem->text().toUShort() == server->port()) {
// Обновляем имя (если изменилось)
ui->sgWebServers->setItem(row, 0, new QTableWidgetItem(name));
// Обновляем порт (если изменился)
ui->sgWebServers->setItem(row, 0, new QTableWidgetItem(QString::number(server->port())));
// Обновляем ссылку
QString url = QString("http://localhost:%1").arg(server->port());
ui->sgWebServers->setItem(row, 2, new QTableWidgetItem(url));
break;
}
}
}
}
void uGeneral::on_www_currentChanged(int index)
{
}
void uGeneral::on_edtBotName_selectionChanged()
{
}
void uGeneral::on_edtBotName_editingFinished()
{
db->writeSetting(ui->edtBotName->objectName(), ui->edtBotName->text());
}
void uGeneral::on_edtBotToken_textEdited(const QString &arg1)
{
}
void uGeneral::on_edtBotToken_editingFinished()
{
db->writeSetting(ui->edtBotToken->objectName(), ui->edtBotToken->text());
}
void uGeneral::on_edtBotTokenStreamer_editingFinished()
{
db->writeSetting(ui->edtBotTokenStreamer->objectName(), ui->edtBotTokenStreamer->text());
}
void uGeneral::on_edtBotClientID_editingFinished()
{
db->writeSetting(ui->edtBotClientID->objectName(), ui->edtBotClientID->text());
}
void uGeneral::on_edtChannel_editingFinished()
{
db->writeSetting(ui->edtChannel->objectName(), ui->edtChannel->text());
}
void uGeneral::on_edtDAClientID_editingFinished()
{
db->writeSetting(ui->edtDAClientID->objectName(), ui->edtDAClientID->text());
}
void uGeneral::on_edtDAClientSecret_editingFinished()
{
db->writeSetting(ui->edtDAClientSecret->objectName(), ui->edtDAClientSecret->text());
}
void uGeneral::on_edtDARedirectURL_editingFinished()
{
db->writeSetting(ui->edtDARedirectURL->objectName(), ui->edtDARedirectURL->text());
}
void uGeneral::on_edtDACode_editingFinished()
{
db->writeSetting(ui->edtDACode->objectName(), ui->edtDACode->text());
}
void uGeneral::on_cbDAAutoLogin_stateChanged(int arg1)
{
db->writeSetting(ui->cbDAAutoLogin->objectName(), ui->cbDAAutoLogin->isChecked() ? "True" : "False");
}
void uGeneral::on_edtGPTPrefix_editingFinished()
{
db->writeSetting(ui->edtGPTPrefix->objectName(), ui->edtGPTPrefix->text());
}
void uGeneral::on_edtAIP1_editingFinished()
{
db->writeSetting(ui->edtAIP1->objectName(), ui->edtAIP1->text());
}
void uGeneral::on_edtAIP2_editingFinished()
{
db->writeSetting(ui->edtAIP2->objectName(), ui->edtAIP2->text());
}
void uGeneral::on_edtAIP3_editingFinished()
{
db->writeSetting(ui->edtAIP3->objectName(), ui->edtAIP3->text());
}
void uGeneral::on_edtKandiKey_editingFinished()
{
db->writeSetting(ui->edtKandiKey->objectName(), ui->edtKandiKey->text());
}
void uGeneral::on_edtKandiSecret_editingFinished()
{
db->writeSetting(ui->edtKandiSecret->objectName(), ui->edtKandiSecret->text());
}
void uGeneral::on_cbOllama_stateChanged(int arg1)
{
db->writeSetting(ui->cbOllama->objectName(), ui->cbOllama->isChecked() ? "True" : "False");
}
void uGeneral::on_tbNotifyVolume_valueChanged(int value)
{
}
void uGeneral::on_edtNotifyFileName_editingFinished()
{
db->writeSetting(ui->edtNotifyFileName->objectName(), ui->edtNotifyFileName->text());
}
void uGeneral::on_edtNotifyFileNameMod_editingFinished()
{
db->writeSetting(ui->edtNotifyFileNameMod->objectName(), ui->edtNotifyFileNameMod->text());
}
void uGeneral::on_edtNotifyFileNameVip_editingFinished()
{
db->writeSetting(ui->edtNotifyFileNameVip->objectName(), ui->edtNotifyFileNameVip->text());
}
void uGeneral::on_edtNotifyFileNameSub_editingFinished()
{
db->writeSetting(ui->edtNotifyFileNameSub->objectName(), ui->edtNotifyFileNameSub->text());
}
void uGeneral::on_chEnNotify_stateChanged(int arg1)
{
db->writeSetting(ui->chEnNotify->objectName(), ui->chEnNotify->isChecked() ? "True" : "False");
}
void uGeneral::on_chEnNotifyMod_stateChanged(int arg1)
{
db->writeSetting(ui->chEnNotifyMod->objectName(), ui->chEnNotifyMod->isChecked() ? "True" : "False");
}
void uGeneral::on_chEnNotifyVip_stateChanged(int arg1)
{
db->writeSetting(ui->chEnNotifyVip->objectName(), ui->chEnNotifyVip->isChecked() ? "True" : "False");
}
void uGeneral::on_chEnNotifySub_stateChanged(int arg1)
{
db->writeSetting(ui->chEnNotifySub->objectName(), ui->chEnNotifySub->isChecked() ? "True" : "False");
}
void uGeneral::on_tbNotifyVolume_sliderPressed()
{
}
void uGeneral::on_tbNotifyVolume_sliderReleased()
{
db->writeSetting(ui->tbNotifyVolume->objectName(), QString::number(ui->tbNotifyVolume->value()));
}
void uGeneral::on_tbNotifyVolumeMod_sliderReleased()
{
db->writeSetting(ui->tbNotifyVolumeMod->objectName(), QString::number(ui->tbNotifyVolumeMod->value()));
}
void uGeneral::on_tbNotifyVolumeVip_sliderReleased()
{
db->writeSetting(ui->tbNotifyVolumeVip->objectName(), QString::number(ui->tbNotifyVolumeVip->value()));
}
void uGeneral::on_tbNotifyVolumeSub_sliderReleased()
{
db->writeSetting(ui->tbNotifyVolumeSub->objectName(), QString::number(ui->tbNotifyVolumeSub->value()));
}
void uGeneral::on_cbNotifyFileAgain1_stateChanged(int arg1)
{
db->writeSetting(ui->cbNotifyFileAgain1->objectName(), ui->cbNotifyFileAgain1->isChecked() ? "True" : "False");
}
void uGeneral::on_cbNotifyFileAgain2_stateChanged(int arg1)
{
db->writeSetting(ui->cbNotifyFileAgain2->objectName(), ui->cbNotifyFileAgain2->isChecked() ? "True" : "False");
}
void uGeneral::on_cbNotifyFileAgain3_stateChanged(int arg1)
{
db->writeSetting(ui->cbNotifyFileAgain3->objectName(), ui->cbNotifyFileAgain3->isChecked() ? "True" : "False");
}
void uGeneral::on_btnThemesFolder_clicked()
{
}
/**
* @brief Загружает сохраненные чаты из базы данных и создает серверы
*/
void uGeneral::loadSavedChats()
{
QList<ChatSettings> chats = db->loadAllChats();
for (const ChatSettings &settings : chats) {
if (settings.type.toLower() == "chat") {
// Создаем сервер чата
HttpServerChat *server = new HttpServerChat(
settings.fontList,
settings.port,
settings.backgroundColor,
this
);
// Настраиваем сервер
server->setBlockColor(settings.blockColor);
server->setBorderColor(settings.borderColor);
server->setBorderSize(settings.borderSize);
server->setPadding(settings.padding);
server->setTransparency(settings.transparency);
server->setFontFamily(settings.fontFamily);
server->setFontSize(settings.fontSize);
server->setFontColor(settings.fontColor);
server->setFreez(settings.freez);
server->setMessageTimeout(settings.messageTimeout);
server->setDeleteMode(settings.deleteByTime, settings.maxMsgCount);
// Запускаем сервер
if (server->start()) {
m_chatServers.append(server);
// Добавляем в таблицу
QString url = QString("http://localhost:%1").arg(settings.port);
addServerToTable(settings.name, "Чат", settings.port, url, server);
} else {
delete server;
}
}
}
}