diff --git a/src/channel.cpp b/src/channel.cpp index 6d70b7953..51b599b44 100644 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -1,11 +1,11 @@ #include "channel.hpp" +#include "debug/log.hpp" #include "emotemanager.hpp" #include "ircmanager.hpp" #include "logging/loggingmanager.hpp" #include "messages/message.hpp" #include "windowmanager.hpp" -#include #include #include #include @@ -18,7 +18,8 @@ using namespace chatterino::messages; namespace chatterino { -Channel::Channel() +Channel::Channel(const QString &_name) + : name(_name) // , loggingChannel(logging::get(name)) { } diff --git a/src/channel.hpp b/src/channel.hpp index d257c2779..5ad469b11 100644 --- a/src/channel.hpp +++ b/src/channel.hpp @@ -24,7 +24,7 @@ class IrcManager; class Channel { public: - explicit Channel(); + explicit Channel(const QString &_name); boost::signals2::signal messageRemovedFromStart; boost::signals2::signal messageAppended; diff --git a/src/ircmanager.cpp b/src/ircmanager.cpp index b59e15900..9a1bcf3d5 100644 --- a/src/ircmanager.cpp +++ b/src/ircmanager.cpp @@ -281,7 +281,7 @@ void IrcManager::handleRoomStateMessage(Communi::IrcMessage *message) auto iterator = tags.find("room-id"); if (iterator != tags.end()) { - std::string roomID = iterator.value().toString().toStdString(); + auto roomID = iterator.value().toString(); auto channel = QString(message->toData()).split("#").at(1); channelManager.getTwitchChannel(channel)->setRoomID(roomID); diff --git a/src/resources.cpp b/src/resources.cpp index cedf51929..7ac6cde99 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -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) + - "/display?language=en"; + QString url = "https://badges.twitch.tv/v1/badges/channels/" + roomID + "/display?language=en"; util::NetworkRequest req(url); req.setCaller(QThread::currentThread()); diff --git a/src/resources.hpp b/src/resources.hpp index 992110854..161f16c36 100644 --- a/src/resources.hpp +++ b/src/resources.hpp @@ -70,7 +70,7 @@ public: }; // channelId - std::map channels; + std::map channels; // Chatterino badges struct ChatterinoBadge { @@ -87,7 +87,7 @@ public: // username std::map> chatterinoBadges; - void loadChannelData(const std::string &roomID, bool bypassCache = false); + void loadChannelData(const QString &roomID, bool bypassCache = false); void loadDynamicTwitchBadges(); void loadChatterinoBadges(); }; diff --git a/src/twitch/twitchchannel.cpp b/src/twitch/twitchchannel.cpp index bf3ee193f..c0e038bbd 100644 --- a/src/twitch/twitchchannel.cpp +++ b/src/twitch/twitchchannel.cpp @@ -1,31 +1,48 @@ #include "twitchchannel.hpp" +#include "debug/log.hpp" #include "emotemanager.hpp" +#include "util/urlfetch.hpp" -#include +#include +#include namespace chatterino { namespace twitch { TwitchChannel::TwitchChannel(EmoteManager &emoteManager, IrcManager &ircManager, - const QString &channelName, bool isSpecial) - : emoteManager(emoteManager) + const QString &channelName, bool _isSpecial) + : Channel(channelName) + , emoteManager(emoteManager) , ircManager(ircManager) - // , name(channelName) , bttvChannelEmotes(new EmoteMap) , ffzChannelEmotes(new EmoteMap) - , subLink("https://www.twitch.tv/" + name + "/subscribe?ref=in_chat_subscriber_link") - , channelLink("https://twitch.tv/" + name) - , popoutPlayerLink("https://player.twitch.tv/?channel=" + name) + , subscriptionURL("https://www.twitch.tv/" + name + "/subscribe?ref=in_chat_subscriber_link") + , channelURL("https://twitch.tv/" + name) + , popoutPlayerURL("https://player.twitch.tv/?channel=" + name) , isLive(false) - , isSpecial(isSpecial) + , isSpecial(_isSpecial) { - this->name = channelName; + debug::Log("[TwitchChannel:{}] Opened", this->name); - qDebug() << "Open twitch channel:" << this->name; - - if (!isSpecial) { + if (!this->isSpecial) { 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 @@ -33,35 +50,20 @@ bool TwitchChannel::isEmpty() const return this->name.isEmpty(); } -const QString &TwitchChannel::getSubLink() const -{ - return this->subLink; -} - bool TwitchChannel::canSendMessage() const { return !this->isEmpty() && !this->isSpecial; } -const QString &TwitchChannel::getChannelLink() const +void TwitchChannel::setRoomID(const QString &_roomID) { - return this->channelLink; -} - -const QString &TwitchChannel::getPopoutPlayerLink() const -{ - return this->popoutPlayerLink; -} - -void TwitchChannel::setRoomID(std::string id) -{ - this->roomID = id; + this->roomID = _roomID; this->roomIDchanged(); } 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.reloadFFZChannelEmotes(this->name, this->ffzChannelEmotes); @@ -69,12 +71,53 @@ void TwitchChannel::reloadChannelEmotes() void TwitchChannel::sendMessage(const QString &message) { - qDebug() << "TwitchChannel send message: " << message; + debug::Log("[TwitchChannel:{}] Send message: {}", this->name, message); // Do last message processing QString parsedMessage = this->emoteManager.replaceShortCodes(message); 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 diff --git a/src/twitch/twitchchannel.hpp b/src/twitch/twitchchannel.hpp index 2e87d7d07..0caa97f03 100644 --- a/src/twitch/twitchchannel.hpp +++ b/src/twitch/twitchchannel.hpp @@ -9,9 +9,12 @@ namespace twitch { class TwitchChannel : public Channel { + QTimer *liveStatusTimer; + public: explicit TwitchChannel(EmoteManager &emoteManager, IrcManager &ircManager, - const QString &channelName, bool isSpecial = false); + const QString &channelName, bool _isSpecial = false); + ~TwitchChannel(); void reloadChannelEmotes(); @@ -19,14 +22,15 @@ public: bool canSendMessage() const override; void sendMessage(const QString &message) override; - const QString &getSubLink() const; - const QString &getChannelLink() const; - const QString &getPopoutPlayerLink() const; + const QString subscriptionURL; + const QString channelURL; + const QString popoutPlayerURL; - void setRoomID(std::string id); + void setRoomID(const QString &_roomID); boost::signals2::signal roomIDchanged; + boost::signals2::signal onlineStatusChanged; - std::string roomID; + QString roomID; bool isLive; QString streamViewerCount; QString streamStatus; @@ -37,13 +41,14 @@ public: const std::shared_ptr ffzChannelEmotes; private: + void setLive(bool newLiveStatus); + void refreshLiveStatus(); + EmoteManager &emoteManager; IrcManager &ircManager; - QString subLink; - QString channelLink; - QString popoutPlayerLink; bool isSpecial; }; -} -} + +} // namespace twitch +} // namespace chatterino diff --git a/src/twitch/twitchmessagebuilder.cpp b/src/twitch/twitchmessagebuilder.cpp index 33e116852..3966ae312 100644 --- a/src/twitch/twitchmessagebuilder.cpp +++ b/src/twitch/twitchmessagebuilder.cpp @@ -263,9 +263,9 @@ void TwitchMessageBuilder::parseRoomID() auto iterator = this->tags.find("room-id"); 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; } } diff --git a/src/twitch/twitchmessagebuilder.hpp b/src/twitch/twitchmessagebuilder.hpp index 55096eaea..6ddc35055 100644 --- a/src/twitch/twitchmessagebuilder.hpp +++ b/src/twitch/twitchmessagebuilder.hpp @@ -53,7 +53,7 @@ public: // const std::pair &b); private: - std::string roomID; + QString roomID; QColor usernameColor; diff --git a/src/widgets/chatwidget.cpp b/src/widgets/chatwidget.cpp index 85cd57f01..5a9e72076 100644 --- a/src/widgets/chatwidget.cpp +++ b/src/widgets/chatwidget.cpp @@ -119,10 +119,7 @@ void ChatWidget::setChannel(std::shared_ptr _newChannel) this->channel = _newChannel; - twitch::TwitchChannel *twitchChannel = dynamic_cast(_newChannel.get()); - if (twitchChannel != nullptr) { - twitchChannel->roomIDchanged.connect([this]() { this->header.checkLive(); }); - } + this->channelChanged(); } void ChatWidget::channelNameUpdated(const std::string &newChannelName) @@ -224,9 +221,6 @@ void ChatWidget::doCloseSplit() { NotebookPage *page = static_cast(this->parentWidget()); page->removeFromLayout(this); - QTimer *timer = this->header.findChild(); - timer->stop(); - timer->deleteLater(); } void ChatWidget::doChangeChannel() diff --git a/src/widgets/chatwidget.hpp b/src/widgets/chatwidget.hpp index a355d4c9a..1e937ce51 100644 --- a/src/widgets/chatwidget.hpp +++ b/src/widgets/chatwidget.hpp @@ -59,6 +59,8 @@ public: void layoutMessages(); void updateGifEmotes(); + boost::signals2::signal channelChanged; + protected: virtual void paintEvent(QPaintEvent *) override; diff --git a/src/widgets/chatwidgetheader.cpp b/src/widgets/chatwidgetheader.cpp index e7cc15726..07f6de5fb 100644 --- a/src/widgets/chatwidgetheader.cpp +++ b/src/widgets/chatwidgetheader.cpp @@ -69,9 +69,26 @@ ChatWidgetHeader::ChatWidgetHeader(ChatWidget *_chatWidget) this->rightLabel.getLabel().setTextFormat(Qt::RichText); this->rightLabel.getLabel().setText("ayy"); - QTimer *timer = new QTimer(this); - connect(timer, &QTimer::timeout, this, &ChatWidgetHeader::checkLive); - timer->start(60000); + this->initializeChannelSignals(); + + 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(channel.get()); + + if (twitchChannel) { + twitchChannel->onlineStatusChanged.connect([this]() { + this->updateChannelText(); // + }); + } } 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(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 chatterino diff --git a/src/widgets/chatwidgetheader.hpp b/src/widgets/chatwidgetheader.hpp index 3e4188342..a067e3b91 100644 --- a/src/widgets/chatwidgetheader.hpp +++ b/src/widgets/chatwidgetheader.hpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace chatterino { @@ -29,7 +30,6 @@ public: explicit ChatWidgetHeader(ChatWidget *_chatWidget); // Update channel text from chat widget void updateChannelText(); - void checkLive(); protected: virtual void paintEvent(QPaintEvent *) override; @@ -44,6 +44,8 @@ private: QPoint dragStart; bool dragging = false; + boost::signals2::connection onlineStatusChangedConnection; + QHBoxLayout hbox; // top left @@ -62,6 +64,8 @@ private: virtual void refreshTheme() override; + void initializeChannelSignals(); + public slots: void menuMoveSplit(); void menuReloadChannelEmotes(); diff --git a/src/widgets/emotepopup.cpp b/src/widgets/emotepopup.cpp index c137e5e55..c812f0e1f 100644 --- a/src/widgets/emotepopup.cpp +++ b/src/widgets/emotepopup.cpp @@ -34,7 +34,7 @@ void EmotePopup::loadChannel(std::shared_ptr _channel) return; } - std::shared_ptr emoteChannel(new Channel); + std::shared_ptr emoteChannel(new Channel("")); auto addEmotes = [&](EmoteMap &map, const QString &title, const QString &emoteDesc) { // TITLE