#pragma once #include "common/Aliases.hpp" #include "common/Atomic.hpp" #include "common/Channel.hpp" #include "common/ChannelChatters.hpp" #include "common/ChatterSet.hpp" #include "common/Outcome.hpp" #include "common/UniqueAccess.hpp" #include "providers/twitch/ChannelPointReward.hpp" #include "providers/twitch/TwitchEmotes.hpp" #include "providers/twitch/api/Helix.hpp" #include "util/QStringHash.hpp" #include #include #include #include #include #include #include #include namespace chatterino { // This is to make sure that combined emoji go through properly, see // https://github.com/Chatterino/chatterino2/issues/3384 and // https://mm2pl.github.io/emoji_rfc.pdf for more details const QString ZERO_WIDTH_JOINER = QString(QChar(0x200D)); // Here be MSVC: Do NOT replace with "\U" literal, it will fail silently. namespace { const QChar ESCAPE_TAG_CHARS[2] = {QChar::highSurrogate(0xE0002), QChar::lowSurrogate(0xE0002)}; } const QString ESCAPE_TAG = QString(ESCAPE_TAG_CHARS, 2); const static QRegularExpression COMBINED_FIXER( QString("(?; class EmoteMap; class TwitchBadges; class FfzEmotes; class BttvEmotes; class TwitchIrcServer; class TwitchChannel : public Channel, public ChannelChatters { public: struct StreamStatus { bool live = false; bool rerun = false; unsigned viewerCount = 0; QString title; QString game; QString gameId; QString uptime; QString streamType; }; struct RoomModes { bool submode = false; bool r9k = false; bool emoteOnly = false; int followerOnly = -1; int slowMode = 0; }; void initialize(); // Channel methods virtual bool isEmpty() const override; virtual bool canSendMessage() const override; virtual void sendMessage(const QString &message) override; virtual bool isMod() const override; bool isVip() const; bool isStaff() const; virtual bool isBroadcaster() const override; virtual bool hasHighRateLimit() const override; virtual bool canReconnect() const override; virtual void reconnect() override; void refreshTitle(); void createClip(); // Data const QString &subscriptionUrl(); const QString &channelUrl(); const QString &popoutPlayerUrl(); int chatterCount(); virtual bool isLive() const override; QString roomId() const; SharedAccessGuard accessRoomModes() const; SharedAccessGuard accessStreamStatus() const; // Emotes boost::optional bttvEmote(const EmoteName &name) const; boost::optional ffzEmote(const EmoteName &name) const; std::shared_ptr bttvEmotes() const; std::shared_ptr ffzEmotes() const; virtual void refreshBTTVChannelEmotes(bool manualRefresh); virtual void refreshFFZChannelEmotes(bool manualRefresh); // Badges boost::optional ffzCustomModBadge() const; boost::optional ffzCustomVipBadge() const; boost::optional twitchBadge(const QString &set, const QString &version) const; // Cheers boost::optional cheerEmote(const QString &string); // Signals pajlada::Signals::NoArgSignal roomIdChanged; pajlada::Signals::NoArgSignal userStateChanged; pajlada::Signals::NoArgSignal liveStatusChanged; pajlada::Signals::NoArgSignal roomModesChanged; // Channel point rewards pajlada::Signals::SelfDisconnectingSignal channelPointRewardAdded; void addChannelPointReward(const ChannelPointReward &reward); bool isChannelPointRewardKnown(const QString &rewardId); boost::optional channelPointReward( const QString &rewardId) const; private: struct NameOptions { QString displayName; QString localizedName; } nameOptions; protected: explicit TwitchChannel(const QString &channelName); private: // Methods void refreshLiveStatus(); void parseLiveStatus(bool live, const HelixStream &stream); void refreshPubSub(); void refreshChatters(); void refreshBadges(); void refreshCheerEmotes(); void loadRecentMessages(); void fetchDisplayName(); void setLive(bool newLiveStatus); void setMod(bool value); void setVIP(bool value); void setStaff(bool value); void setRoomId(const QString &id); void setRoomModes(const RoomModes &roomModes_); void setDisplayName(const QString &name); void setLocalizedName(const QString &name); const QString &getDisplayName() const override; const QString &getLocalizedName() const override; // Data const QString subscriptionUrl_; const QString channelUrl_; const QString popoutPlayerUrl_; int chatterCount_; UniqueAccess streamStatus_; UniqueAccess roomModes_; protected: Atomic> bttvEmotes_; Atomic> ffzEmotes_; Atomic> ffzCustomModBadge_; Atomic> ffzCustomVipBadge_; private: // Badges UniqueAccess>> badgeSets_; // "subscribers": { "0": ... "3": ... "6": ... UniqueAccess> cheerEmoteSets_; UniqueAccess> channelPointRewards_; bool mod_ = false; bool vip_ = false; bool staff_ = false; UniqueAccess roomID_; // -- QString lastSentMessage_; QObject lifetimeGuard_; QTimer chattersListTimer_; QElapsedTimer titleRefreshedTimer_; QElapsedTimer clipCreationTimer_; bool isClipCreationInProgress{false}; pajlada::Signals::SignalHolder signalHolder_; std::vector bSignals_; friend class TwitchIrcServer; friend class TwitchMessageBuilder; friend class IrcMessageHandler; }; } // namespace chatterino