#include "controllers/notifications/NotificationController.hpp" #include "Application.hpp" #include "common/NetworkRequest.hpp" #include "common/Outcome.hpp" #include "controllers/notifications/NotificationModel.hpp" #include "providers/twitch/TwitchApi.hpp" #include "providers/twitch/TwitchIrcServer.hpp" #include "singletons/Toasts.hpp" #include "singletons/WindowManager.hpp" #include "widgets/Window.hpp" #ifdef Q_OS_WIN # include #endif #include #include #include #include namespace chatterino { void NotificationController::initialize(Settings &settings, Paths &paths) { this->initialized_ = true; for (const QString &channelName : this->twitchSetting_.getValue()) { this->channelMap[Platform::Twitch].appendItem(channelName); } this->channelMap[Platform::Twitch].delayedItemsChanged.connect([this] { // this->twitchSetting_.setValue( this->channelMap[Platform::Twitch].getVector()); }); /* for (const QString &channelName : this->mixerSetting_.getValue()) { this->channelMap[Platform::Mixer].appendItem(channelName); } this->channelMap[Platform::Mixer].delayedItemsChanged.connect([this] { // this->mixerSetting_.setValue( this->channelMap[Platform::Mixer]); });*/ liveStatusTimer_ = new QTimer(); this->fetchFakeChannels(); QObject::connect(this->liveStatusTimer_, &QTimer::timeout, [=] { this->fetchFakeChannels(); }); this->liveStatusTimer_->start(60 * 1000); } void NotificationController::updateChannelNotification( const QString &channelName, Platform p) { if (isChannelNotified(channelName, p)) { removeChannelNotification(channelName, p); } else { addChannelNotification(channelName, p); } } bool NotificationController::isChannelNotified(const QString &channelName, Platform p) { for (const auto &channel : this->channelMap[p]) { if (channelName.toLower() == channel.toLower()) { return true; } } return false; } void NotificationController::addChannelNotification(const QString &channelName, Platform p) { channelMap[p].appendItem(channelName); } void NotificationController::removeChannelNotification( const QString &channelName, Platform p) { for (std::vector::size_type i = 0; i != channelMap[p].getVector().size(); i++) { if (channelMap[p].getVector()[i].toLower() == channelName.toLower()) { channelMap[p].removeItem(i); i--; } } } void NotificationController::playSound() { static auto player = new QMediaPlayer; static QUrl currentPlayerUrl; QUrl highlightSoundUrl = getSettings()->notificationCustomSound ? QUrl::fromLocalFile( getSettings()->notificationPathSound.getValue()) : QUrl("qrc:/sounds/ping2.wav"); if (currentPlayerUrl != highlightSoundUrl) { player->setMedia(highlightSoundUrl); currentPlayerUrl = highlightSoundUrl; } player->play(); } NotificationModel *NotificationController::createModel(QObject *parent, Platform p) { NotificationModel *model = new NotificationModel(parent); model->init(&this->channelMap[p]); return model; } void NotificationController::fetchFakeChannels() { for (std::vector::size_type i = 0; i != channelMap[Platform::Twitch].getVector().size(); i++) { auto chan = getApp()->twitch.server->getChannelOrEmpty( channelMap[Platform::Twitch].getVector()[i]); if (chan->isEmpty()) { getFakeTwitchChannelLiveStatus( channelMap[Platform::Twitch].getVector()[i]); } } } void NotificationController::getFakeTwitchChannelLiveStatus( const QString &channelName) { TwitchApi::findUserId(channelName, [channelName, this](QString roomID) { if (roomID.isEmpty()) { qDebug() << "[TwitchChannel" << channelName << "] Refreshing live status (Missing ID)"; removeFakeChannel(channelName); return; } qDebug() << "[TwitchChannel" << channelName << "] Refreshing live status"; QString url("https://api.twitch.tv/kraken/streams/" + roomID); NetworkRequest::twitchRequest(url) .onSuccess([this, channelName](auto result) -> Outcome { rapidjson::Document document = result.parseRapidJson(); if (!document.IsObject()) { qDebug() << "[TwitchChannel:refreshLiveStatus] root is not " "an object"; return Failure; } if (!document.HasMember("stream")) { qDebug() << "[TwitchChannel:refreshLiveStatus] Missing " "stream in root"; return Failure; } const auto &stream = document["stream"]; if (!stream.IsObject()) { // Stream is offline (stream is most likely null) // removeFakeChannel(channelName); return Failure; } // Stream is live auto i = std::find(fakeTwitchChannels.begin(), fakeTwitchChannels.end(), channelName); if (!(i != fakeTwitchChannels.end())) { fakeTwitchChannels.push_back(channelName); if (Toasts::isEnabled()) { getApp()->toasts->sendChannelNotification( channelName, Platform::Twitch); } if (getSettings()->notificationPlaySound) { getApp()->notifications->playSound(); } if (getSettings()->notificationFlashTaskbar) { getApp()->windows->sendAlert(); } } return Success; }) .execute(); }); } void NotificationController::removeFakeChannel(const QString channelName) { auto i = std::find(fakeTwitchChannels.begin(), fakeTwitchChannels.end(), channelName); if (i != fakeTwitchChannels.end()) { fakeTwitchChannels.erase(i); } } } // namespace chatterino