Files
TTW_Bot/ugeneral.cpp
T

3029 lines
102 KiB
C++

#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_randomManager(nullptr)
, m_neuralTemplateManager(nullptr)
, m_isTwitchConnected(false)
, m_notificationServers()
, m_chatServers()
, m_createNotifyDialog(nullptr)
, m_createChatDialog(nullptr)
{
// ============================================================================
// ИНИЦИАЛИЗАЦИЯ ИНТЕРФЕЙСА
// ============================================================================
ui->setupUi(this);
setWindowTitle("TTW Bot app");
LogSettings logSettings;
logSettings.logToFile = true;
logSettings.logToConsole = true;
// Цвета для разных уровней
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();
// Загружаем иконки
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();
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();
}
// ============================================================================
// ПРИВАТНЫЕ МЕТОДЫ ДЛЯ ИНИЦИАЛИЗАЦИИ
// ============================================================================
void uGeneral::setupButtonIcons() {
QList<QPushButton*> buttons = ui->www->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")) {
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));
}
}
}
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", "Успешное подключение к БД");
}
}
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);
}
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->setWordWrap(true);
ui->sgLog->horizontalHeader()->setStretchLastSection(true);
ui->sgLog->setColumnWidth(0, 100);
ui->sgLog->setColumnWidth(1, 100);
ui->sgLog->setColumnWidth(2, 170);
ui->sgLog->setColumnWidth(3, 170);
// ========================================================================
// НАСТРОЙКА ТАБЛИЦЫ КОМАНД (адаптивная)
// ========================================================================
headers.clear();
headers << "Команда" << "Ответ";
ui->sgCommands->setHorizontalHeaderLabels(headers);
ui->sgCommands->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->sgCommands->setSelectionMode(QAbstractItemView::SingleSelection);
ui->sgCommands->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->sgCommands->setWordWrap(true);
ui->sgCommands->horizontalHeader()->setStretchLastSection(true);
ui->sgCommands->setColumnWidth(0, 135);
// ========================================================================
// НАСТРОЙКА ТАБЛИЦЫ РАНДОМНЫХ ИНТЕРВАЛОВ (адаптивная)
// ========================================================================
headers.clear();
headers << "Имя" << "От" << "До";
ui->sgRandomInt->setHorizontalHeaderLabels(headers);
ui->sgRandomInt->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->sgRandomInt->setSelectionMode(QAbstractItemView::SingleSelection);
ui->sgRandomInt->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->sgRandomInt->setWordWrap(true);
ui->sgRandomInt->horizontalHeader()->setStretchLastSection(true);
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->setWordWrap(true);
ui->sgWebServers->horizontalHeader()->setStretchLastSection(true);
ui->sgWebServers->setColumnWidth(0, 80);
ui->sgWebServers->setColumnWidth(1, 100);
// Подключение двойного клика
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);
ui->sgTimers->setWordWrap(true);
ui->sgTimers->horizontalHeader()->setStretchLastSection(true);
ui->sgTimers->setColumnWidth(0, 40);
ui->sgTimers->setColumnWidth(1, 400);
ui->sgTimers->setColumnWidth(2, 80);
ui->sgTimers->setColumnWidth(3, 40);
// Подключение сигналов таблицы таймеров
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");
// Принудительно устанавливаем Expanding политику для правильной работы в layout
ui->widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
ui->widget_2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
ui->widget_3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// Подключение двойных кликов для специальных виджетов
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);
}
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->setPrefix(ui->edtGPTPrefix->text());
if (ui->rbGC->isChecked()) {
nnManager->setCurrentNetworkType(NeuralNetworkManager::GigaChat);
nnManager->setGigaChatCredentials(ui->edtAIP1->text(), ui->edtAIP2->text());
}
else if (ui->rbDS->isChecked()) {
nnManager->setCurrentNetworkType(NeuralNetworkManager::DeepSeek);
nnManager->setApiKey(NeuralNetworkManager::DeepSeek, ui->edtAIP1->text());
}
else if (ui->rbCG->isChecked()) {
nnManager->setCurrentNetworkType(NeuralNetworkManager::ChatGPT);
nnManager->setApiKey(NeuralNetworkManager::ChatGPT, ui->edtAIP1->text());
}
else if (ui->RBCustom->isChecked()) {
nnManager->setCurrentNetworkType(NeuralNetworkManager::Ollama);
nnManager->setApiKey(NeuralNetworkManager::Ollama, ui->edtAIP1->text());
nnManager->setOllamaUrl(ui->edtAIP2->text());
}
m_SoundFiles = new MediaFileManager();
ui->widget->setSoundManager(m_SoundFiles);
ui->widget->setManagerType(FSingleGrid::SoundManager);
ui->widget->setDatabase(db);
m_TextFiles = new MediaFileManager();
ui->widget_2->setTextManager(m_TextFiles);
ui->widget_2->setManagerType(FSingleGrid::TextManager);
ui->widget_2->setDatabase(db);
m_neuralTemplateManager = new NeuralTemplateManager(this);
ui->widget_3->setTemplateManager(m_neuralTemplateManager);
ui->widget_3->setManagerType(FSingleGrid::TemplateManager);
ui->widget_3->setDatabase(db);
m_commandProcessor = new CommandProcessor(this);
if (db) {
loadCommandsFromTableWidget();
loadRandomRangesFromTableWidget();
loadRandomResponseGroupsFromDatabase();
loadSoundsFromDatabase();
loadTextFromDatabase();
loadTemplatesFromDatabase();
CommandProcessor::Context context;
context.userManager = m_userManager;
context.twitchAPI = twitchAPI;
context.soundManager = soundManager;
context.neuralManager = nnManager;
context.randomManager = m_randomManager;
context.neuralTemplateManager = m_neuralTemplateManager;
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);
}
}
}
}
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);
}
}
}
}
void uGeneral::loadTextFromDatabase()
{
if (!db || !m_TextFiles) return;
QTableWidget* table = ui->widget_2->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_TextFiles->addFile(name, file);
}
}
}
}
void uGeneral::loadTemplatesFromDatabase()
{
if (!db || !m_neuralTemplateManager) return;
QTableWidget* table = ui->widget_3->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_neuralTemplateManager->addTemplate(name, file);
}
}
}
}
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);
}
}
}
}
void uGeneral::loadRandomResponseGroupsFromDatabase()
{
if (!db || !m_randomResponses) return;
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 tempResponseList;
if (!db->LoadRandomResponses(groupName, &tempResponseList)) {
qWarning() << "Failed to load responses for group:" << groupName;
continue;
}
for (int j = 0; j < tempResponseList.count(); ++j) {
QString response = tempResponseList.item(j)->text();
if (!response.isEmpty()) {
m_randomResponses->addResponse(groupName, response);
}
}
}
}
void uGeneral::setupTwitchComponents()
{
m_twitchClient = new WebSocketClient(this);
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);
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);
initTwitchAPI();
}
void uGeneral::setupUserWidget()
{
m_userWidget = new UserWidget(m_userManager, this);
QVBoxLayout* layout = qobject_cast<QVBoxLayout*>(ui->tab_7->layout());
if (!layout) {
layout = new QVBoxLayout(ui->tab_7);
ui->tab_7->setLayout(layout);
}
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_userWidget);
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);
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);
User* user = m_userManager->findUserById(userId);
if (user) {
user->isModerator = false;
m_userManager->updateUserFromMessage(user->displayName, TwitchMessage());
}
}
});
connect(m_userWidget, &UserWidget::setVIPRequested, this, [this](const QString &userId, const QString &userName) {
if (twitchAPI) {
twitchAPI->setVIP(userId);
User* user = m_userManager->findUserById(userId);
if (user) {
user->isVIP = true;
m_userManager->updateUserFromMessage(user->displayName, TwitchMessage());
}
}
});
connect(m_userWidget, &UserWidget::removeVIPRequested, this, [this](const QString &userId, const QString &userName) {
if (twitchAPI) {
twitchAPI->delVIP(userId);
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);
}
});
}
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", "Сервер авторизации запущен");
});
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", "Сервер авторизации запущен");
});
}
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;
}
if (m_neuralTemplateManager) {
delete m_neuralTemplateManager;
m_neuralTemplateManager = 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) {
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) {
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)
{
Q_UNUSED(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(),
ui->edtAIP2->text()
);
}
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());
nnManager->setOllamaUrl(ui->edtAIP2->text());
nnManager->sendMessage(q, type);
}
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;
}
void uGeneral::onAIResponseReceived(const QString &response)
{
if (m_twitchClient) {
QString chatResponse = response;
if (chatResponse.length() > 400) {
chatResponse = chatResponse.left(397) + "...";
}
m_twitchClient->sendChatMessage(ui->edtChannel->text(), chatResponse);
}
}
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", "Connected");
setTwitchConnected(true);
loadChatBadges();
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);
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);
LogSettings settings = LogManager::instance()->settings();
QColor color = settings.colors.value(entry.level, LogEntry::levelToColor(entry.level));
QTableWidgetItem* timeItem = new QTableWidgetItem(
entry.timestamp.toString("hh:mm:ss"));
timeItem->setForeground(color);
QTableWidgetItem* typeItem = new QTableWidgetItem(
LogEntry::levelToString(entry.level));
typeItem->setForeground(color);
QTableWidgetItem* moduleItem = new QTableWidgetItem(entry.module);
moduleItem->setForeground(color);
QTableWidgetItem* methodItem = new QTableWidgetItem(entry.method);
methodItem->setForeground(color);
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);
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);
}
fLinkForm->setLinkText(authUrl);
fLinkForm->show();
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()
{
QString clientId = ui->edtBotClientID->text();
if (clientId.isEmpty()) {
QMessageBox::warning(this, "Ошибка", "Введите Client ID");
return;
}
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);
m_authStreamer->startServer(authUrl, true);
}
void uGeneral::onTokenReceived(const QString &token)
{
ui->edtBotToken->setText(token);
if (fLinkForm && fLinkForm->isVisible()) {
fLinkForm->close();
}
db->writeSetting(ui->edtBotToken->objectName(), ui->edtBotToken->text());
}
void uGeneral::onTokenReceived2(const QString &token)
{
ui->edtBotTokenStreamer->setText(token);
db->writeSetting(ui->edtBotTokenStreamer->objectName(), ui->edtBotTokenStreamer->text());
}
void uGeneral::onTokenReceived3(const QString &token)
{
ui->edtDACode->setText(token);
db->writeSetting(ui->edtDACode->objectName(), ui->edtDACode->text());
}
void uGeneral::onAuthError(const QString &error)
{
Q_UNUSED(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()
{
// TODO
}
void uGeneral::on_btnExportSettings_clicked()
{
// TODO
}
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()
{
QString sourceFile = QFileDialog::getOpenFileName(this,
"Выберите файл для уведомлений",
QDir::homePath(),
"Звуковой файл (*.mp3);;Все файлы (*.*)");
if (sourceFile.isEmpty()) {
return;
}
ui->edtNotifyFileName->setText(sourceFile);
}
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::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);
}
return;
}
}
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);
}
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);
}
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);
}
return;
}
}
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());
}
QString notifyModFile = ui->edtNotifyFileNameMod->text();
if (!notifyModFile.isEmpty() && QFile::exists(notifyModFile)) {
// загружается по необходимости
}
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);
LogManager::instance()->debug("uGeneral", "handleNewMessage", message);
m_userManager->m_totalMessages++;
if (m_userWidget) {
m_userWidget->updateStatistics();
}
playNotify(msg.isMod, msg.isVIP, msg.isSubscriber);
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);
}
}
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;
QString response = m_commandProcessor->generateResponse(username, command, parameters);
if (!response.isEmpty()) {
sendChatResponse(response);
}
}
void uGeneral::sendChatResponse(const QString &response)
{
m_twitchClient->sendChatMessage(ui->edtChannel->text(), response);
}
void uGeneral::handleError(const QString &errorMessage){
Q_UNUSED(errorMessage);
}
QString uGeneral::processTwitchMessage(const TwitchMessage &msg)
{
QString processedMessage = msg.message;
if (!msg.emotes.isEmpty()) {
processedMessage = replaceTwitchEmotes(msg.emotes, processedMessage);
}
processedMessage = replaceCustomEmotes(processedMessage);
return processedMessage;
}
QString uGeneral::replaceTwitchEmotes(const QString &emotesData, const QString &message)
{
if (emotesData.isEmpty()) return message;
QString result = message;
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;
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);
if (word.length() < 2) continue;
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;
}
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() == "Отключиться")
{
disconnectFromTwitch();
return;
}
connectToTwitch();
}
void uGeneral::connectToTwitch()
{
int botTokenDays = 0;
int streamerTokenDays = 0;
QString botToken = ui->edtBotToken->text();
QString streamerToken = ui->edtBotTokenStreamer->text();
if (!twitchAPI->validateTwitchToken("Бот", botToken, botTokenDays))
{
return;
}
if (!twitchAPI->validateTwitchToken("Стример", streamerToken, streamerTokenDays))
{
return;
}
QString oauthToken = "oauth:" + botToken;
QString nickname = ui->edtBotName->text();
QString channel = ui->edtChannel->text();
if (m_twitchClient->connectToTwitchChat(oauthToken, nickname, channel))
{
ui->pushButton_2->setText("Отключиться");
ui->lbBotDays->setText(QString::number(botTokenDays));
ui->lbStreamerDays->setText(QString::number(streamerTokenDays));
setTwitchConnected(true);
}
}
void uGeneral::disconnectFromTwitch()
{
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();
m_randomResponses->addResponse(groupName, response);
}
void uGeneral::on_btnRandomDel_clicked()
{
db->DeleteResponse(ui->lbRandomGroup->currentItem()->text(), ui->lbRandomRespons->currentItem()->text());
db->LoadRandomResponses(ui->lbRandomGroup->currentItem()->text(), ui->lbRandomRespons);
m_randomResponses->removeResponse(ui->lbRandomGroup->currentItem()->text(), ui->lbRandomRespons->currentItem()->text());
}
void uGeneral::on_btnRmGroup_clicked()
{
db->DeleteGroup(ui->lbRandomGroup->currentItem()->text());
db->LoadRandomGroups(ui->lbRandomGroup);
m_randomResponses->removeGroup(ui->lbRandomGroup->currentItem()->text());
}
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;
}
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);
m_commandProcessor->addCommand(name, response);
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);
m_commandProcessor->deleteCommand(commandName);
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;
}
QString oldCommand = ui->sgCommands->item(row, 0)->text();
ui->sgCommands->item(row, 0)->setText(newName);
ui->sgCommands->item(row, 1)->setText(response);
db->SaveTableWidget(ui->sgCommands);
m_commandProcessor->editCommand(oldCommand, newName, response);
LogManager::instance()->info("uGeneral", "on_btnEdtCommand_clicked",
QString("Отредактирована команда в строке %1").arg(row));
}
void uGeneral::loadQssFiles()
{
ui->cbTheme->clear();
ui->cbTheme->addItem("Без темы", "");
QString systemStylesPath = FileManager::instance().getPath(FileManager::SystemStyles);
QDir systemStylesDir(systemStylesPath);
if (systemStylesDir.exists()) {
loadStylesFromDirectory(systemStylesDir, "Системные");
} else {
qWarning() << "Папка системных стилей не найдена:" << systemStylesPath;
systemStylesDir.mkpath(".");
}
QString userStylesPath = FileManager::instance().getPath(FileManager::Styles);
QDir userStylesDir(userStylesPath);
if (userStylesDir.exists()) {
loadStylesFromDirectory(userStylesDir, "Пользовательские");
} else {
qWarning() << "Папка пользовательских стилей не найдена:" << userStylesPath;
userStylesDir.mkpath(".");
}
if (ui->cbTheme->count() <= 1) {
qWarning() << "Темы не найдены, создаем базовые";
}
}
void uGeneral::loadStylesFromDirectory(const QDir &stylesDir, const QString &category)
{
if (!stylesDir.exists()) {
return;
}
QStringList filters;
filters << "*.qss" << "*.QSS";
QStringList qssFiles = stylesDir.entryList(filters, QDir::Files);
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;
QString filePath = ui->cbTheme->itemData(index).toString();
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);
QTableWidgetItem *nameItem = new QTableWidgetItem(name);
nameItem->setData(Qt::UserRole, QVariant::fromValue<QObject*>(serverObj));
ui->sgWebServers->setItem(row, 0, nameItem);
ui->sgWebServers->setItem(row, 1, new QTableWidgetItem(type));
ui->sgWebServers->setItem(row, 2, new QTableWidgetItem(QString::number(port)));
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;
}
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);
}
}
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;
}
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;
}
}
if (!badge.versions.isEmpty()) {
return badge.versions.first().imageUrl1x;
}
}
}
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);
}
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);
}
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);
}
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);
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();
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() == "чат") {
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() == "уведомления") {
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)
{
Q_UNUSED(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)
{
Q_UNUSED(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)
{
Q_UNUSED(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)
{
Q_UNUSED(arg1);
db->writeSetting(ui->cbOllama->objectName(), ui->cbOllama->isChecked() ? "True" : "False");
}
void uGeneral::on_tbNotifyVolume_valueChanged(int value)
{
Q_UNUSED(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)
{
Q_UNUSED(arg1);
db->writeSetting(ui->chEnNotify->objectName(), ui->chEnNotify->isChecked() ? "True" : "False");
}
void uGeneral::on_chEnNotifyMod_stateChanged(int arg1)
{
Q_UNUSED(arg1);
db->writeSetting(ui->chEnNotifyMod->objectName(), ui->chEnNotifyMod->isChecked() ? "True" : "False");
}
void uGeneral::on_chEnNotifyVip_stateChanged(int arg1)
{
Q_UNUSED(arg1);
db->writeSetting(ui->chEnNotifyVip->objectName(), ui->chEnNotifyVip->isChecked() ? "True" : "False");
}
void uGeneral::on_chEnNotifySub_stateChanged(int arg1)
{
Q_UNUSED(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)
{
Q_UNUSED(arg1);
db->writeSetting(ui->cbNotifyFileAgain1->objectName(), ui->cbNotifyFileAgain1->isChecked() ? "True" : "False");
}
void uGeneral::on_cbNotifyFileAgain2_stateChanged(int arg1)
{
Q_UNUSED(arg1);
db->writeSetting(ui->cbNotifyFileAgain2->objectName(), ui->cbNotifyFileAgain2->isChecked() ? "True" : "False");
}
void uGeneral::on_cbNotifyFileAgain3_stateChanged(int arg1)
{
Q_UNUSED(arg1);
db->writeSetting(ui->cbNotifyFileAgain3->objectName(), ui->cbNotifyFileAgain3->isChecked() ? "True" : "False");
}
void uGeneral::on_btnThemesFolder_clicked()
{
QString userThemesPath = FileManager::instance().getPath(FileManager::Styles);
QDesktopServices::openUrl(QUrl::fromLocalFile(userThemesPath));
}
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;
}
}
}
}
void uGeneral::on_btnOpenStream_clicked()
{
QDesktopServices::openUrl("https://www.twitch.tv/" + ui->edtChannel->text());
}
void uGeneral::on_btnAUserName_clicked()
{
QTextCursor cursor = ui->textBrowser->textCursor();
cursor.insertText("[USERNAME]");
}
void uGeneral::on_btnRmWebService_clicked()
{
int currentRow = ui->sgWebServers->currentRow();
if (currentRow < 0) {
QMessageBox::warning(this, "Ошибка", "Выберите веб-сервис для удаления!");
return;
}
QTableWidgetItem *nameItem = ui->sgWebServers->item(currentRow, 0);
QTableWidgetItem *typeItem = ui->sgWebServers->item(currentRow, 1);
QTableWidgetItem *portItem = ui->sgWebServers->item(currentRow, 2);
if (!nameItem || !typeItem || !portItem) {
QMessageBox::warning(this, "Ошибка", "Не удалось получить данные о сервисе!");
return;
}
QString serviceName = nameItem->text();
QString serviceType = typeItem->text();
quint16 port = portItem->text().toUShort();
int result = QMessageBox::question(this, "Подтверждение удаления",
QString("Вы уверены, что хотите удалить сервис '%1'?\n"
"Тип: %2\n"
"Порт: %3").arg(serviceName, serviceType, QString::number(port)),
QMessageBox::Yes | QMessageBox::No);
if (result != QMessageBox::Yes) {
return;
}
QObject *serverObj = nameItem->data(Qt::UserRole).value<QObject*>();
bool deletedFromDB = false;
if (serviceType.toLower() == "чат" || serviceType.toLower() == "chat") {
HttpServerChat *chatServer = qobject_cast<HttpServerChat*>(serverObj);
if (chatServer) {
chatServer->stop();
int chatIndex = m_chatServers.indexOf(chatServer);
if (chatIndex >= 0) {
m_chatServers.removeAt(chatIndex);
}
deletedFromDB = db->deleteChat(port);
delete chatServer;
}
}
else if (serviceType.toLower() == "уведомления" || serviceType.toLower() == "notification") {
HttpServer *notifyServer = qobject_cast<HttpServer*>(serverObj);
if (notifyServer) {
notifyServer->stop();
int notifyIndex = m_notificationServers.indexOf(notifyServer);
if (notifyIndex >= 0) {
m_notificationServers.removeAt(notifyIndex);
}
deletedFromDB = db->deleteNotification(port);
delete notifyServer;
}
}
ui->sgWebServers->removeRow(currentRow);
if (deletedFromDB) {
LogManager::instance()->info("uGeneral", "on_btnRmWebService_clicked",
QString("Удален веб-сервис: %1 (тип: %2, порт: %3)")
.arg(serviceName, serviceType, QString::number(port)));
QMessageBox::information(this, "Успех",
QString("Сервис '%1' успешно удален!").arg(serviceName));
} else {
LogManager::instance()->warning("uGeneral", "on_btnRmWebService_clicked",
QString("Сервис удален из интерфейса, но возникли проблемы с БД: %1")
.arg(serviceName));
QMessageBox::warning(this, "Внимание",
QString("Сервис '%1' удален из интерфейса, но не удалось удалить его из базы данных!")
.arg(serviceName));
}
}