mirror-chatterino2/src/controllers/notifications/NotificationController.cpp

245 lines
7.1 KiB
C++
Raw Normal View History

#include "controllers/notifications/NotificationController.hpp"
#include "Application.hpp"
#include "common/NetworkRequest.hpp"
2018-08-29 19:25:37 +02:00
#include "common/Outcome.hpp"
#include "common/QLogging.hpp"
#include "controllers/notifications/NotificationModel.hpp"
#include "providers/twitch/api/Helix.hpp"
#include "providers/twitch/TwitchIrcServer.hpp"
#include "providers/twitch/TwitchMessageBuilder.hpp"
#include "singletons/Toasts.hpp"
#include "singletons/WindowManager.hpp"
#include "util/Helpers.hpp"
2018-08-29 19:25:37 +02:00
#include "widgets/Window.hpp"
2018-09-01 13:01:54 +02:00
#ifdef Q_OS_WIN
# include <wintoastlib.h>
#endif
2018-08-11 12:47:03 +02:00
#include <QDesktopServices>
#include <QDir>
#include <QMediaPlayer>
2018-08-11 12:47:03 +02:00
#include <QUrl>
#include <unordered_set>
2018-08-11 12:47:03 +02:00
namespace chatterino {
void NotificationController::initialize(Settings &settings, Paths &paths)
{
this->initialized_ = true;
2018-10-21 13:43:02 +02:00
for (const QString &channelName : this->twitchSetting_.getValue())
{
this->channelMap[Platform::Twitch].append(channelName);
}
this->channelMap[Platform::Twitch].delayedItemsChanged.connect([this] {
this->twitchSetting_.setValue(this->channelMap[Platform::Twitch].raw());
2018-08-12 15:29:40 +02:00
});
liveStatusTimer_ = new QTimer();
2018-08-26 13:19:09 +02:00
this->fetchFakeChannels();
QObject::connect(this->liveStatusTimer_, &QTimer::timeout, [=] {
this->fetchFakeChannels();
});
2018-08-26 13:19:09 +02:00
this->liveStatusTimer_->start(60 * 1000);
}
void NotificationController::updateChannelNotification(
2018-08-12 18:54:32 +02:00
const QString &channelName, Platform p)
{
2018-10-21 13:43:02 +02:00
if (isChannelNotified(channelName, p))
{
removeChannelNotification(channelName, p);
2018-10-21 13:43:02 +02:00
}
else
{
addChannelNotification(channelName, p);
}
}
2018-08-12 15:29:40 +02:00
bool NotificationController::isChannelNotified(const QString &channelName,
2018-08-12 18:54:32 +02:00
Platform p)
{
for (const auto &channel : this->channelMap[p])
2018-10-21 13:43:02 +02:00
{
if (channelName.toLower() == channel.toLower())
{
return true;
}
}
return false;
}
2018-08-11 12:47:03 +02:00
void NotificationController::addChannelNotification(const QString &channelName,
Platform p)
{
channelMap[p].append(channelName);
}
void NotificationController::removeChannelNotification(
const QString &channelName, Platform p)
{
for (std::vector<int>::size_type i = 0; i != channelMap[p].raw().size();
i++)
2018-10-21 13:43:02 +02:00
{
2020-02-23 17:45:59 +01:00
if (channelMap[p].raw()[i].toLower() == channelName.toLower())
2018-10-21 13:43:02 +02:00
{
channelMap[p].removeAt(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");
2018-10-21 13:43:02 +02:00
if (currentPlayerUrl != highlightSoundUrl)
{
player->setMedia(highlightSoundUrl);
currentPlayerUrl = highlightSoundUrl;
}
player->play();
}
2018-08-12 18:54:32 +02:00
NotificationModel *NotificationController::createModel(QObject *parent,
Platform p)
{
NotificationModel *model = new NotificationModel(parent);
2020-02-23 19:31:43 +01:00
model->initialize(&this->channelMap[p]);
return model;
}
void NotificationController::fetchFakeChannels()
{
qCDebug(chatterinoNotification) << "fetching fake channels";
QStringList channels;
for (std::vector<int>::size_type i = 0;
i < channelMap[Platform::Twitch].raw().size(); i++)
2018-10-21 13:43:02 +02:00
{
auto chan = getApp()->twitch->getChannelOrEmpty(
2020-02-23 17:45:59 +01:00
channelMap[Platform::Twitch].raw()[i]);
2018-10-21 13:43:02 +02:00
if (chan->isEmpty())
{
channels.push_back(channelMap[Platform::Twitch].raw()[i]);
}
}
for (const auto &batch : splitListIntoBatches(channels))
{
getHelix()->fetchStreams(
{}, batch,
[batch, this](std::vector<HelixStream> streams) {
std::unordered_set<QString> liveStreams;
for (const auto &stream : streams)
{
liveStreams.insert(stream.userLogin);
}
for (const auto &name : batch)
{
auto it = liveStreams.find(name.toLower());
this->checkStream(it != liveStreams.end(), name);
}
},
[batch]() {
// we done fucked up.
qCWarning(chatterinoNotification)
<< "Failed to fetch live status for " << batch;
},
[]() {
// finally
});
}
}
void NotificationController::checkStream(bool live, QString channelName)
{
qCDebug(chatterinoNotification)
<< "[TwitchChannel" << channelName << "] Refreshing live status";
if (!live)
{
// Stream is offline
this->removeFakeChannel(channelName);
return;
}
// Stream is online
auto i = std::find(fakeTwitchChannels.begin(), fakeTwitchChannels.end(),
channelName);
if (i != fakeTwitchChannels.end())
{
// We have already pushed the live state of this stream
// Could not find stream in fake Twitch channels!
return;
}
if (Toasts::isEnabled())
{
getApp()->toasts->sendChannelNotification(channelName, QString(),
Platform::Twitch);
}
if (getSettings()->notificationPlaySound &&
!(isInStreamerMode() &&
getSettings()->streamerModeSuppressLiveNotifications))
{
getApp()->notifications->playSound();
}
if (getSettings()->notificationFlashTaskbar &&
!(isInStreamerMode() &&
getSettings()->streamerModeSuppressLiveNotifications))
{
getApp()->windows->sendAlert();
}
MessageBuilder builder;
TwitchMessageBuilder::liveMessage(channelName, &builder);
getApp()->twitch->liveChannel->addMessage(builder.release());
// Indicate that we have pushed notifications for this stream
fakeTwitchChannels.push_back(channelName);
}
void NotificationController::removeFakeChannel(const QString channelName)
{
auto i = std::find(fakeTwitchChannels.begin(), fakeTwitchChannels.end(),
channelName);
2018-10-21 13:43:02 +02:00
if (i != fakeTwitchChannels.end())
{
fakeTwitchChannels.erase(i);
// "delete" old 'CHANNEL is live' message
LimitedQueueSnapshot<MessagePtr> snapshot =
getApp()->twitch->liveChannel->getMessageSnapshot();
int snapshotLength = snapshot.size();
// MSVC hates this code if the parens are not there
int end = (std::max)(0, snapshotLength - 200);
// this assumes that channelName is a login name therefore will only delete messages from fake channels
auto liveMessageSearchText = QString("%1 is live!").arg(channelName);
for (int i = snapshotLength - 1; i >= end; --i)
{
auto &s = snapshot[i];
if (s->messageText == liveMessageSearchText)
{
s->flags.set(MessageFlag::Disabled);
break;
}
}
}
}
} // namespace chatterino