2018-08-10 00:04:50 +02:00
|
|
|
#include "controllers/notifications/NotificationController.hpp"
|
2018-08-09 15:41:03 +02:00
|
|
|
|
|
|
|
#include "Application.hpp"
|
2018-08-25 14:13:26 +02:00
|
|
|
#include "common/NetworkRequest.hpp"
|
2018-08-29 19:25:37 +02:00
|
|
|
#include "common/Outcome.hpp"
|
2018-08-09 15:41:03 +02:00
|
|
|
#include "controllers/notifications/NotificationModel.hpp"
|
2018-08-29 19:25:37 +02:00
|
|
|
#include "debug/Log.hpp"
|
2018-08-25 14:13:26 +02:00
|
|
|
#include "providers/twitch/TwitchApi.hpp"
|
|
|
|
#include "providers/twitch/TwitchServer.hpp"
|
2018-08-14 16:29:52 +02:00
|
|
|
#include "singletons/Toasts.hpp"
|
2018-08-25 14:13:26 +02:00
|
|
|
#include "singletons/WindowManager.hpp"
|
2018-08-29 19:25:37 +02:00
|
|
|
#include "widgets/Window.hpp"
|
2018-08-09 15:41:03 +02:00
|
|
|
|
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>
|
2018-08-12 20:21:21 +02:00
|
|
|
#include <QMediaPlayer>
|
2018-08-11 12:47:03 +02:00
|
|
|
#include <QUrl>
|
|
|
|
|
2018-08-09 15:41: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())
|
|
|
|
{
|
2018-08-12 20:21:21 +02:00
|
|
|
this->channelMap[Platform::Twitch].appendItem(channelName);
|
2018-08-09 15:41:03 +02:00
|
|
|
}
|
|
|
|
|
2018-08-12 20:21:21 +02:00
|
|
|
this->channelMap[Platform::Twitch].delayedItemsChanged.connect([this] { //
|
|
|
|
this->twitchSetting_.setValue(
|
|
|
|
this->channelMap[Platform::Twitch].getVector());
|
2018-08-12 15:29:40 +02:00
|
|
|
});
|
2018-08-12 21:05:12 +02:00
|
|
|
/*
|
2018-08-12 15:29:40 +02:00
|
|
|
for (const QString &channelName : this->mixerSetting_.getValue()) {
|
2018-08-12 20:21:21 +02:00
|
|
|
this->channelMap[Platform::Mixer].appendItem(channelName);
|
2018-08-12 15:29:40 +02:00
|
|
|
}
|
|
|
|
|
2018-08-12 20:21:21 +02:00
|
|
|
this->channelMap[Platform::Mixer].delayedItemsChanged.connect([this] { //
|
|
|
|
this->mixerSetting_.setValue(
|
|
|
|
this->channelMap[Platform::Mixer].getVector());
|
2018-08-26 13:19:09 +02:00
|
|
|
});*/
|
2018-08-25 14:13:26 +02:00
|
|
|
|
|
|
|
liveStatusTimer_ = new QTimer();
|
2018-08-26 13:19:09 +02:00
|
|
|
|
|
|
|
this->fetchFakeChannels();
|
|
|
|
|
2018-08-29 22:22:32 +02:00
|
|
|
QObject::connect(this->liveStatusTimer_, &QTimer::timeout,
|
|
|
|
[=] { this->fetchFakeChannels(); });
|
2018-08-26 13:19:09 +02:00
|
|
|
this->liveStatusTimer_->start(60 * 1000);
|
2018-08-09 15:41:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void NotificationController::updateChannelNotification(
|
2018-08-12 18:54:32 +02:00
|
|
|
const QString &channelName, Platform p)
|
2018-08-09 15:41:03 +02:00
|
|
|
{
|
2018-10-21 13:43:02 +02:00
|
|
|
if (isChannelNotified(channelName, p))
|
|
|
|
{
|
2018-08-12 20:21:21 +02:00
|
|
|
removeChannelNotification(channelName, p);
|
2018-10-21 13:43:02 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-08-12 20:21:21 +02:00
|
|
|
addChannelNotification(channelName, p);
|
2018-08-09 15:41:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-12 15:29:40 +02:00
|
|
|
bool NotificationController::isChannelNotified(const QString &channelName,
|
2018-08-12 18:54:32 +02:00
|
|
|
Platform p)
|
2018-08-09 15:41:03 +02:00
|
|
|
{
|
2018-10-21 13:43:02 +02:00
|
|
|
for (const auto &channel : this->channelMap[p].getVector())
|
|
|
|
{
|
|
|
|
if (channelName.toLower() == channel.toLower())
|
|
|
|
{
|
2018-08-12 20:21:21 +02:00
|
|
|
return true;
|
|
|
|
}
|
2018-08-11 16:11:51 +02:00
|
|
|
}
|
2018-08-10 00:04:50 +02:00
|
|
|
return false;
|
2018-08-09 15:41:03 +02:00
|
|
|
}
|
2018-08-11 12:47:03 +02:00
|
|
|
|
2018-08-12 20:21:21 +02:00
|
|
|
void NotificationController::addChannelNotification(const QString &channelName,
|
|
|
|
Platform p)
|
2018-08-09 15:41:03 +02:00
|
|
|
{
|
2018-08-12 20:21:21 +02:00
|
|
|
channelMap[p].appendItem(channelName);
|
2018-08-09 15:41:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void NotificationController::removeChannelNotification(
|
2018-08-12 20:21:21 +02:00
|
|
|
const QString &channelName, Platform p)
|
2018-08-09 15:41:03 +02:00
|
|
|
{
|
2018-08-12 20:21:21 +02:00
|
|
|
for (std::vector<int>::size_type i = 0;
|
2018-10-21 13:43:02 +02:00
|
|
|
i != channelMap[p].getVector().size(); i++)
|
|
|
|
{
|
|
|
|
if (channelMap[p].getVector()[i].toLower() == channelName.toLower())
|
|
|
|
{
|
2018-08-12 20:21:21 +02:00
|
|
|
channelMap[p].removeItem(i);
|
2018-08-10 00:04:50 +02:00
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
2018-08-09 15:41:03 +02:00
|
|
|
}
|
2018-08-12 20:21:21 +02:00
|
|
|
void NotificationController::playSound()
|
|
|
|
{
|
|
|
|
static auto player = new QMediaPlayer;
|
|
|
|
static QUrl currentPlayerUrl;
|
|
|
|
|
2019-05-08 08:51:14 +02:00
|
|
|
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)
|
|
|
|
{
|
2018-08-12 20:21:21 +02:00
|
|
|
player->setMedia(highlightSoundUrl);
|
|
|
|
|
|
|
|
currentPlayerUrl = highlightSoundUrl;
|
|
|
|
}
|
|
|
|
player->play();
|
|
|
|
}
|
2018-08-24 18:38:27 +02:00
|
|
|
|
2018-08-12 18:54:32 +02:00
|
|
|
NotificationModel *NotificationController::createModel(QObject *parent,
|
|
|
|
Platform p)
|
2018-08-09 15:41:03 +02:00
|
|
|
{
|
|
|
|
NotificationModel *model = new NotificationModel(parent);
|
2018-08-12 20:21:21 +02:00
|
|
|
model->init(&this->channelMap[p]);
|
2018-08-09 15:41:03 +02:00
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
2018-08-25 14:13:26 +02:00
|
|
|
void NotificationController::fetchFakeChannels()
|
|
|
|
{
|
|
|
|
for (std::vector<int>::size_type i = 0;
|
2018-10-21 13:43:02 +02:00
|
|
|
i != channelMap[Platform::Twitch].getVector().size(); i++)
|
|
|
|
{
|
2018-08-25 14:13:26 +02:00
|
|
|
auto chan = getApp()->twitch.server->getChannelOrEmpty(
|
|
|
|
channelMap[Platform::Twitch].getVector()[i]);
|
2018-10-21 13:43:02 +02:00
|
|
|
if (chan->isEmpty())
|
|
|
|
{
|
2018-08-26 13:19:09 +02:00
|
|
|
getFakeTwitchChannelLiveStatus(
|
|
|
|
channelMap[Platform::Twitch].getVector()[i]);
|
2018-08-25 14:13:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotificationController::getFakeTwitchChannelLiveStatus(
|
|
|
|
const QString &channelName)
|
|
|
|
{
|
|
|
|
TwitchApi::findUserId(channelName, [channelName, this](QString roomID) {
|
2018-10-21 13:43:02 +02:00
|
|
|
if (roomID.isEmpty())
|
|
|
|
{
|
2018-08-29 19:25:37 +02:00
|
|
|
log("[TwitchChannel:{}] Refreshing live status (Missing ID)",
|
2018-08-25 14:13:26 +02:00
|
|
|
channelName);
|
|
|
|
removeFakeChannel(channelName);
|
|
|
|
return;
|
|
|
|
}
|
2018-08-29 19:25:37 +02:00
|
|
|
log("[TwitchChannel:{}] Refreshing live status", channelName);
|
2018-08-25 14:13:26 +02:00
|
|
|
|
|
|
|
QString url("https://api.twitch.tv/kraken/streams/" + roomID);
|
|
|
|
auto request = NetworkRequest::twitchRequest(url);
|
|
|
|
request.setCaller(QThread::currentThread());
|
|
|
|
|
|
|
|
request.onSuccess([this, channelName](auto result) -> Outcome {
|
|
|
|
rapidjson::Document document = result.parseRapidJson();
|
2018-10-21 13:43:02 +02:00
|
|
|
if (!document.IsObject())
|
|
|
|
{
|
2018-08-29 19:25:37 +02:00
|
|
|
log("[TwitchChannel:refreshLiveStatus]root is not an object");
|
2018-08-25 14:13:26 +02:00
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
|
2018-10-21 13:43:02 +02:00
|
|
|
if (!document.HasMember("stream"))
|
|
|
|
{
|
2018-08-29 19:25:37 +02:00
|
|
|
log("[TwitchChannel:refreshLiveStatus] Missing stream in root");
|
2018-08-25 14:13:26 +02:00
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto &stream = document["stream"];
|
|
|
|
|
2018-10-21 13:43:02 +02:00
|
|
|
if (!stream.IsObject())
|
|
|
|
{
|
2018-08-25 14:13:26 +02:00
|
|
|
// Stream is offline (stream is most likely null)
|
2018-08-29 19:25:37 +02:00
|
|
|
// removeFakeChannel(channelName);
|
2018-08-25 14:13:26 +02:00
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
// Stream is live
|
|
|
|
auto i = std::find(fakeTwitchChannels.begin(),
|
|
|
|
fakeTwitchChannels.end(), channelName);
|
2018-08-26 13:19:09 +02:00
|
|
|
|
2018-10-21 13:43:02 +02:00
|
|
|
if (!(i != fakeTwitchChannels.end()))
|
|
|
|
{
|
2018-08-25 14:13:26 +02:00
|
|
|
fakeTwitchChannels.push_back(channelName);
|
2018-10-21 13:43:02 +02:00
|
|
|
if (Toasts::isEnabled())
|
|
|
|
{
|
2018-08-25 14:13:26 +02:00
|
|
|
getApp()->toasts->sendChannelNotification(channelName,
|
|
|
|
Platform::Twitch);
|
|
|
|
}
|
2018-10-21 13:43:02 +02:00
|
|
|
if (getSettings()->notificationPlaySound)
|
|
|
|
{
|
2018-08-25 14:13:26 +02:00
|
|
|
getApp()->notifications->playSound();
|
|
|
|
}
|
2018-10-21 13:43:02 +02:00
|
|
|
if (getSettings()->notificationFlashTaskbar)
|
|
|
|
{
|
2018-10-07 12:55:44 +02:00
|
|
|
getApp()->windows->sendAlert();
|
2018-08-25 14:13:26 +02:00
|
|
|
}
|
|
|
|
}
|
2018-08-29 19:25:37 +02:00
|
|
|
return Success;
|
2018-08-25 14:13:26 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
request.execute();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
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())
|
|
|
|
{
|
2018-08-25 14:13:26 +02:00
|
|
|
fakeTwitchChannels.erase(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-09 15:41:03 +02:00
|
|
|
} // namespace chatterino
|