Moved online status checking logic from ChatWidgetHeader to TwitchChannel

- Channel now needs to be initialized with a name. Special cases like the emote window just sends an empty string.
 - ChatWidget now has a signal which is called whenever the widgets channel is changed
 - Changed roomID from an std::string to a QString
This commit is contained in:
Rasmus Karlsson 2017-11-04 14:57:29 +01:00
parent 064daaa77a
commit 7b2e3a94a6
14 changed files with 132 additions and 105 deletions

View file

@ -1,11 +1,11 @@
#include "channel.hpp" #include "channel.hpp"
#include "debug/log.hpp"
#include "emotemanager.hpp" #include "emotemanager.hpp"
#include "ircmanager.hpp" #include "ircmanager.hpp"
#include "logging/loggingmanager.hpp" #include "logging/loggingmanager.hpp"
#include "messages/message.hpp" #include "messages/message.hpp"
#include "windowmanager.hpp" #include "windowmanager.hpp"
#include <QDebug>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
@ -18,7 +18,8 @@ using namespace chatterino::messages;
namespace chatterino { namespace chatterino {
Channel::Channel() Channel::Channel(const QString &_name)
: name(_name)
// , loggingChannel(logging::get(name)) // , loggingChannel(logging::get(name))
{ {
} }

View file

@ -24,7 +24,7 @@ class IrcManager;
class Channel class Channel
{ {
public: public:
explicit Channel(); explicit Channel(const QString &_name);
boost::signals2::signal<void(messages::SharedMessage &)> messageRemovedFromStart; boost::signals2::signal<void(messages::SharedMessage &)> messageRemovedFromStart;
boost::signals2::signal<void(messages::SharedMessage &)> messageAppended; boost::signals2::signal<void(messages::SharedMessage &)> messageAppended;

View file

@ -281,7 +281,7 @@ void IrcManager::handleRoomStateMessage(Communi::IrcMessage *message)
auto iterator = tags.find("room-id"); auto iterator = tags.find("room-id");
if (iterator != tags.end()) { if (iterator != tags.end()) {
std::string roomID = iterator.value().toString().toStdString(); auto roomID = iterator.value().toString();
auto channel = QString(message->toData()).split("#").at(1); auto channel = QString(message->toData()).split("#").at(1);
channelManager.getTwitchChannel(channel)->setRoomID(roomID); channelManager.getTwitchChannel(channel)->setRoomID(roomID);

View file

@ -58,12 +58,11 @@ Resources::BadgeVersion::BadgeVersion(QJsonObject &&root, EmoteManager &emoteMan
{ {
} }
void Resources::loadChannelData(const std::string &roomID, bool bypassCache) void Resources::loadChannelData(const QString &roomID, bool bypassCache)
{ {
qDebug() << "Load channel data for" << QString::fromStdString(roomID); qDebug() << "Load channel data for" << roomID;
QString url = "https://badges.twitch.tv/v1/badges/channels/" + QString::fromStdString(roomID) + QString url = "https://badges.twitch.tv/v1/badges/channels/" + roomID + "/display?language=en";
"/display?language=en";
util::NetworkRequest req(url); util::NetworkRequest req(url);
req.setCaller(QThread::currentThread()); req.setCaller(QThread::currentThread());

View file

@ -70,7 +70,7 @@ public:
}; };
// channelId // channelId
std::map<std::string, Channel> channels; std::map<QString, Channel> channels;
// Chatterino badges // Chatterino badges
struct ChatterinoBadge { struct ChatterinoBadge {
@ -87,7 +87,7 @@ public:
// username // username
std::map<std::string, std::shared_ptr<ChatterinoBadge>> chatterinoBadges; std::map<std::string, std::shared_ptr<ChatterinoBadge>> chatterinoBadges;
void loadChannelData(const std::string &roomID, bool bypassCache = false); void loadChannelData(const QString &roomID, bool bypassCache = false);
void loadDynamicTwitchBadges(); void loadDynamicTwitchBadges();
void loadChatterinoBadges(); void loadChatterinoBadges();
}; };

View file

@ -1,31 +1,48 @@
#include "twitchchannel.hpp" #include "twitchchannel.hpp"
#include "debug/log.hpp"
#include "emotemanager.hpp" #include "emotemanager.hpp"
#include "util/urlfetch.hpp"
#include <QDebug> #include <QThread>
#include <QTimer>
namespace chatterino { namespace chatterino {
namespace twitch { namespace twitch {
TwitchChannel::TwitchChannel(EmoteManager &emoteManager, IrcManager &ircManager, TwitchChannel::TwitchChannel(EmoteManager &emoteManager, IrcManager &ircManager,
const QString &channelName, bool isSpecial) const QString &channelName, bool _isSpecial)
: emoteManager(emoteManager) : Channel(channelName)
, emoteManager(emoteManager)
, ircManager(ircManager) , ircManager(ircManager)
// , name(channelName)
, bttvChannelEmotes(new EmoteMap) , bttvChannelEmotes(new EmoteMap)
, ffzChannelEmotes(new EmoteMap) , ffzChannelEmotes(new EmoteMap)
, subLink("https://www.twitch.tv/" + name + "/subscribe?ref=in_chat_subscriber_link") , subscriptionURL("https://www.twitch.tv/" + name + "/subscribe?ref=in_chat_subscriber_link")
, channelLink("https://twitch.tv/" + name) , channelURL("https://twitch.tv/" + name)
, popoutPlayerLink("https://player.twitch.tv/?channel=" + name) , popoutPlayerURL("https://player.twitch.tv/?channel=" + name)
, isLive(false) , isLive(false)
, isSpecial(isSpecial) , isSpecial(_isSpecial)
{ {
this->name = channelName; debug::Log("[TwitchChannel:{}] Opened", this->name);
qDebug() << "Open twitch channel:" << this->name; if (!this->isSpecial) {
if (!isSpecial) {
this->reloadChannelEmotes(); this->reloadChannelEmotes();
} }
this->liveStatusTimer = new QTimer;
QObject::connect(this->liveStatusTimer, &QTimer::timeout, [this]() {
this->refreshLiveStatus(); //
});
this->liveStatusTimer->start(60000);
this->roomIDchanged.connect([this]() {
this->refreshLiveStatus(); //
});
}
TwitchChannel::~TwitchChannel()
{
this->liveStatusTimer->stop();
this->liveStatusTimer->deleteLater();
} }
bool TwitchChannel::isEmpty() const bool TwitchChannel::isEmpty() const
@ -33,35 +50,20 @@ bool TwitchChannel::isEmpty() const
return this->name.isEmpty(); return this->name.isEmpty();
} }
const QString &TwitchChannel::getSubLink() const
{
return this->subLink;
}
bool TwitchChannel::canSendMessage() const bool TwitchChannel::canSendMessage() const
{ {
return !this->isEmpty() && !this->isSpecial; return !this->isEmpty() && !this->isSpecial;
} }
const QString &TwitchChannel::getChannelLink() const void TwitchChannel::setRoomID(const QString &_roomID)
{ {
return this->channelLink; this->roomID = _roomID;
}
const QString &TwitchChannel::getPopoutPlayerLink() const
{
return this->popoutPlayerLink;
}
void TwitchChannel::setRoomID(std::string id)
{
this->roomID = id;
this->roomIDchanged(); this->roomIDchanged();
} }
void TwitchChannel::reloadChannelEmotes() void TwitchChannel::reloadChannelEmotes()
{ {
printf("[TwitchChannel:%s] Reloading channel emotes\n", qPrintable(this->name)); debug::Log("[TwitchChannel:{}] Reloading channel emotes", this->name);
this->emoteManager.reloadBTTVChannelEmotes(this->name, this->bttvChannelEmotes); this->emoteManager.reloadBTTVChannelEmotes(this->name, this->bttvChannelEmotes);
this->emoteManager.reloadFFZChannelEmotes(this->name, this->ffzChannelEmotes); this->emoteManager.reloadFFZChannelEmotes(this->name, this->ffzChannelEmotes);
@ -69,12 +71,53 @@ void TwitchChannel::reloadChannelEmotes()
void TwitchChannel::sendMessage(const QString &message) void TwitchChannel::sendMessage(const QString &message)
{ {
qDebug() << "TwitchChannel send message: " << message; debug::Log("[TwitchChannel:{}] Send message: {}", this->name, message);
// Do last message processing // Do last message processing
QString parsedMessage = this->emoteManager.replaceShortCodes(message); QString parsedMessage = this->emoteManager.replaceShortCodes(message);
this->ircManager.sendMessage(this->name, parsedMessage); this->ircManager.sendMessage(this->name, parsedMessage);
} }
void TwitchChannel::setLive(bool newLiveStatus)
{
if (this->isLive == newLiveStatus) {
return;
}
this->isLive = newLiveStatus;
this->onlineStatusChanged();
} }
void TwitchChannel::refreshLiveStatus()
{
if (this->roomID.isEmpty()) {
this->setLive(false);
return;
}
debug::Log("[TwitchChannel:{}] Refreshing live status", this->name);
QString url("https://api.twitch.tv/kraken/streams/" + this->roomID);
util::twitch::get(url, QThread::currentThread(), [this](QJsonObject obj) {
if (obj.value("stream").isNull()) {
this->setLive(false);
} else {
auto stream = obj.value("stream").toObject();
this->streamViewerCount = QString::number(stream.value("viewers").toDouble());
this->streamGame = stream.value("game").toString();
this->streamStatus = stream.value("channel").toObject().value("status").toString();
QDateTime since =
QDateTime::fromString(stream.value("created_at").toString(), Qt::ISODate);
auto diff = since.secsTo(QDateTime::currentDateTime());
this->streamUptime =
QString::number(diff / 3600) + "h " + QString::number(diff % 3600 / 60) + "m";
this->setLive(true);
}
});
} }
} // namespace twitch
} // namespace chatterino

View file

@ -9,9 +9,12 @@ namespace twitch {
class TwitchChannel : public Channel class TwitchChannel : public Channel
{ {
QTimer *liveStatusTimer;
public: public:
explicit TwitchChannel(EmoteManager &emoteManager, IrcManager &ircManager, explicit TwitchChannel(EmoteManager &emoteManager, IrcManager &ircManager,
const QString &channelName, bool isSpecial = false); const QString &channelName, bool _isSpecial = false);
~TwitchChannel();
void reloadChannelEmotes(); void reloadChannelEmotes();
@ -19,14 +22,15 @@ public:
bool canSendMessage() const override; bool canSendMessage() const override;
void sendMessage(const QString &message) override; void sendMessage(const QString &message) override;
const QString &getSubLink() const; const QString subscriptionURL;
const QString &getChannelLink() const; const QString channelURL;
const QString &getPopoutPlayerLink() const; const QString popoutPlayerURL;
void setRoomID(std::string id); void setRoomID(const QString &_roomID);
boost::signals2::signal<void()> roomIDchanged; boost::signals2::signal<void()> roomIDchanged;
boost::signals2::signal<void()> onlineStatusChanged;
std::string roomID; QString roomID;
bool isLive; bool isLive;
QString streamViewerCount; QString streamViewerCount;
QString streamStatus; QString streamStatus;
@ -37,13 +41,14 @@ public:
const std::shared_ptr<EmoteMap> ffzChannelEmotes; const std::shared_ptr<EmoteMap> ffzChannelEmotes;
private: private:
void setLive(bool newLiveStatus);
void refreshLiveStatus();
EmoteManager &emoteManager; EmoteManager &emoteManager;
IrcManager &ircManager; IrcManager &ircManager;
QString subLink;
QString channelLink;
QString popoutPlayerLink;
bool isSpecial; bool isSpecial;
}; };
}
} } // namespace twitch
} // namespace chatterino

View file

@ -263,9 +263,9 @@ void TwitchMessageBuilder::parseRoomID()
auto iterator = this->tags.find("room-id"); auto iterator = this->tags.find("room-id");
if (iterator != std::end(this->tags)) { if (iterator != std::end(this->tags)) {
this->roomID = iterator.value().toString().toStdString(); this->roomID = iterator.value().toString();
if (this->twitchChannel->roomID.empty()) { if (this->twitchChannel->roomID.isEmpty()) {
this->twitchChannel->roomID = this->roomID; this->twitchChannel->roomID = this->roomID;
} }
} }

View file

@ -53,7 +53,7 @@ public:
// const std::pair<long int, messages::LazyLoadedImage *> &b); // const std::pair<long int, messages::LazyLoadedImage *> &b);
private: private:
std::string roomID; QString roomID;
QColor usernameColor; QColor usernameColor;

View file

@ -119,10 +119,7 @@ void ChatWidget::setChannel(std::shared_ptr<Channel> _newChannel)
this->channel = _newChannel; this->channel = _newChannel;
twitch::TwitchChannel *twitchChannel = dynamic_cast<twitch::TwitchChannel *>(_newChannel.get()); this->channelChanged();
if (twitchChannel != nullptr) {
twitchChannel->roomIDchanged.connect([this]() { this->header.checkLive(); });
}
} }
void ChatWidget::channelNameUpdated(const std::string &newChannelName) void ChatWidget::channelNameUpdated(const std::string &newChannelName)
@ -224,9 +221,6 @@ void ChatWidget::doCloseSplit()
{ {
NotebookPage *page = static_cast<NotebookPage *>(this->parentWidget()); NotebookPage *page = static_cast<NotebookPage *>(this->parentWidget());
page->removeFromLayout(this); page->removeFromLayout(this);
QTimer *timer = this->header.findChild<QTimer *>();
timer->stop();
timer->deleteLater();
} }
void ChatWidget::doChangeChannel() void ChatWidget::doChangeChannel()

View file

@ -59,6 +59,8 @@ public:
void layoutMessages(); void layoutMessages();
void updateGifEmotes(); void updateGifEmotes();
boost::signals2::signal<void()> channelChanged;
protected: protected:
virtual void paintEvent(QPaintEvent *) override; virtual void paintEvent(QPaintEvent *) override;

View file

@ -69,9 +69,26 @@ ChatWidgetHeader::ChatWidgetHeader(ChatWidget *_chatWidget)
this->rightLabel.getLabel().setTextFormat(Qt::RichText); this->rightLabel.getLabel().setTextFormat(Qt::RichText);
this->rightLabel.getLabel().setText("ayy"); this->rightLabel.getLabel().setText("ayy");
QTimer *timer = new QTimer(this); this->initializeChannelSignals();
connect(timer, &QTimer::timeout, this, &ChatWidgetHeader::checkLive);
timer->start(60000); this->chatWidget->channelChanged.connect([this]() {
this->initializeChannelSignals(); //
});
}
void ChatWidgetHeader::initializeChannelSignals()
{
// Disconnect any previous signal first
this->onlineStatusChangedConnection.disconnect();
auto channel = this->chatWidget->getChannel();
twitch::TwitchChannel *twitchChannel = dynamic_cast<twitch::TwitchChannel *>(channel.get());
if (twitchChannel) {
twitchChannel->onlineStatusChanged.connect([this]() {
this->updateChannelText(); //
});
}
} }
void ChatWidgetHeader::resizeEvent(QResizeEvent *event) void ChatWidgetHeader::resizeEvent(QResizeEvent *event)
@ -202,43 +219,5 @@ void ChatWidgetHeader::menuShowChangelog()
{ {
} }
// TODO: this needs to be moved out of here
void ChatWidgetHeader::checkLive()
{
twitch::TwitchChannel *channel =
dynamic_cast<twitch::TwitchChannel *>(this->chatWidget->getChannel().get());
if (channel == nullptr) {
return;
}
auto id = QString::fromStdString(channel->roomID);
if (id.isEmpty()) {
channel->isLive = false;
this->updateChannelText();
return;
}
util::twitch::get("https://api.twitch.tv/kraken/streams/" + id, this, [=](QJsonObject obj) {
if (obj.value("stream").isNull()) {
channel->isLive = false;
this->updateChannelText();
} else {
channel->isLive = true;
auto stream = obj.value("stream").toObject();
channel->streamViewerCount = QString::number(stream.value("viewers").toDouble());
channel->streamGame = stream.value("game").toString();
channel->streamStatus = stream.value("channel").toObject().value("status").toString();
QDateTime since =
QDateTime::fromString(stream.value("created_at").toString(), Qt::ISODate);
auto diff = since.secsTo(QDateTime::currentDateTime());
channel->streamUptime =
QString::number(diff / 3600) + "h " + QString::number(diff % 3600 / 60) + "m";
this->updateChannelText();
}
});
}
} // namespace widgets } // namespace widgets
} // namespace chatterino } // namespace chatterino

View file

@ -12,6 +12,7 @@
#include <QPaintEvent> #include <QPaintEvent>
#include <QPoint> #include <QPoint>
#include <QWidget> #include <QWidget>
#include <boost/signals2/connection.hpp>
namespace chatterino { namespace chatterino {
@ -29,7 +30,6 @@ public:
explicit ChatWidgetHeader(ChatWidget *_chatWidget); explicit ChatWidgetHeader(ChatWidget *_chatWidget);
// Update channel text from chat widget // Update channel text from chat widget
void updateChannelText(); void updateChannelText();
void checkLive();
protected: protected:
virtual void paintEvent(QPaintEvent *) override; virtual void paintEvent(QPaintEvent *) override;
@ -44,6 +44,8 @@ private:
QPoint dragStart; QPoint dragStart;
bool dragging = false; bool dragging = false;
boost::signals2::connection onlineStatusChangedConnection;
QHBoxLayout hbox; QHBoxLayout hbox;
// top left // top left
@ -62,6 +64,8 @@ private:
virtual void refreshTheme() override; virtual void refreshTheme() override;
void initializeChannelSignals();
public slots: public slots:
void menuMoveSplit(); void menuMoveSplit();
void menuReloadChannelEmotes(); void menuReloadChannelEmotes();

View file

@ -34,7 +34,7 @@ void EmotePopup::loadChannel(std::shared_ptr<Channel> _channel)
return; return;
} }
std::shared_ptr<Channel> emoteChannel(new Channel); std::shared_ptr<Channel> emoteChannel(new Channel(""));
auto addEmotes = [&](EmoteMap &map, const QString &title, const QString &emoteDesc) { auto addEmotes = [&](EmoteMap &map, const QString &title, const QString &emoteDesc) {
// TITLE // TITLE