1 #pragma once
2 
3 #include "common/Aliases.hpp"
4 #include "common/Atomic.hpp"
5 #include "common/Channel.hpp"
6 #include "common/ChannelChatters.hpp"
7 #include "common/ChatterSet.hpp"
8 #include "common/Outcome.hpp"
9 #include "common/UniqueAccess.hpp"
10 #include "providers/twitch/ChannelPointReward.hpp"
11 #include "providers/twitch/TwitchEmotes.hpp"
12 #include "providers/twitch/api/Helix.hpp"
13 #include "util/QStringHash.hpp"
14 
15 #include <QColor>
16 #include <QElapsedTimer>
17 #include <QRegularExpression>
18 #include <boost/optional.hpp>
19 #include <pajlada/signals/signalholder.hpp>
20 
21 #include <mutex>
22 #include <unordered_map>
23 
24 namespace chatterino {
25 
26 enum class HighlightState;
27 
28 struct Emote;
29 using EmotePtr = std::shared_ptr<const Emote>;
30 class EmoteMap;
31 
32 class TwitchBadges;
33 class FfzEmotes;
34 class BttvEmotes;
35 
36 class TwitchIrcServer;
37 
38 class TwitchChannel : public Channel,
39                       public ChannelChatters,
40                       pajlada::Signals::SignalHolder
41 {
42 public:
43     struct StreamStatus {
44         bool live = false;
45         bool rerun = false;
46         unsigned viewerCount = 0;
47         QString title;
48         QString game;
49         QString gameId;
50         QString uptime;
51         QString streamType;
52     };
53 
54     struct RoomModes {
55         bool submode = false;
56         bool r9k = false;
57         bool emoteOnly = false;
58         int followerOnly = -1;
59         int slowMode = 0;
60     };
61 
62     void initialize();
63 
64     // Channel methods
65     virtual bool isEmpty() const override;
66     virtual bool canSendMessage() const override;
67     virtual void sendMessage(const QString &message) override;
68     virtual bool isMod() const override;
69     bool isVip() const;
70     bool isStaff() const;
71     virtual bool isBroadcaster() const override;
72     virtual bool hasHighRateLimit() const override;
73     virtual bool canReconnect() const override;
74     virtual void reconnect() override;
75     void refreshTitle();
76     void createClip();
77 
78     // Data
79     const QString &subscriptionUrl();
80     const QString &channelUrl();
81     const QString &popoutPlayerUrl();
82     int chatterCount();
83     virtual bool isLive() const override;
84     QString roomId() const;
85     SharedAccessGuard<const RoomModes> accessRoomModes() const;
86     SharedAccessGuard<const StreamStatus> accessStreamStatus() const;
87 
88     // Emotes
89     boost::optional<EmotePtr> bttvEmote(const EmoteName &name) const;
90     boost::optional<EmotePtr> ffzEmote(const EmoteName &name) const;
91     std::shared_ptr<const EmoteMap> bttvEmotes() const;
92     std::shared_ptr<const EmoteMap> ffzEmotes() const;
93 
94     virtual void refreshBTTVChannelEmotes(bool manualRefresh);
95     virtual void refreshFFZChannelEmotes(bool manualRefresh);
96 
97     // Badges
98     boost::optional<EmotePtr> ffzCustomModBadge() const;
99     boost::optional<EmotePtr> ffzCustomVipBadge() const;
100     boost::optional<EmotePtr> twitchBadge(const QString &set,
101                                           const QString &version) const;
102 
103     // Cheers
104     boost::optional<CheerEmote> cheerEmote(const QString &string);
105 
106     // Signals
107     pajlada::Signals::NoArgSignal roomIdChanged;
108     pajlada::Signals::NoArgSignal userStateChanged;
109     pajlada::Signals::NoArgSignal liveStatusChanged;
110     pajlada::Signals::NoArgSignal roomModesChanged;
111 
112     // Channel point rewards
113     pajlada::Signals::SelfDisconnectingSignal<ChannelPointReward>
114         channelPointRewardAdded;
115     void addChannelPointReward(const ChannelPointReward &reward);
116     bool isChannelPointRewardKnown(const QString &rewardId);
117     boost::optional<ChannelPointReward> channelPointReward(
118         const QString &rewardId) const;
119 
120 private:
121     struct NameOptions {
122         QString displayName;
123         QString localizedName;
124     } nameOptions;
125 
126 protected:
127     explicit TwitchChannel(const QString &channelName);
128 
129 private:
130     // Methods
131     void refreshLiveStatus();
132     void parseLiveStatus(bool live, const HelixStream &stream);
133     void refreshPubsub();
134     void refreshChatters();
135     void refreshBadges();
136     void refreshCheerEmotes();
137     void loadRecentMessages();
138     void fetchDisplayName();
139 
140     void setLive(bool newLiveStatus);
141     void setMod(bool value);
142     void setVIP(bool value);
143     void setStaff(bool value);
144     void setRoomId(const QString &id);
145     void setRoomModes(const RoomModes &roomModes_);
146     void setDisplayName(const QString &name);
147     void setLocalizedName(const QString &name);
148 
149     const QString &getDisplayName() const override;
150     const QString &getLocalizedName() const override;
151 
152     // Data
153     const QString subscriptionUrl_;
154     const QString channelUrl_;
155     const QString popoutPlayerUrl_;
156     int chatterCount_;
157     UniqueAccess<StreamStatus> streamStatus_;
158     UniqueAccess<RoomModes> roomModes_;
159 
160 protected:
161     Atomic<std::shared_ptr<const EmoteMap>> bttvEmotes_;
162     Atomic<std::shared_ptr<const EmoteMap>> ffzEmotes_;
163     Atomic<boost::optional<EmotePtr>> ffzCustomModBadge_;
164     Atomic<boost::optional<EmotePtr>> ffzCustomVipBadge_;
165 
166 private:
167     // Badges
168     UniqueAccess<std::map<QString, std::map<QString, EmotePtr>>>
169         badgeSets_;  // "subscribers": { "0": ... "3": ... "6": ...
170     UniqueAccess<std::vector<CheerEmoteSet>> cheerEmoteSets_;
171     UniqueAccess<std::map<QString, ChannelPointReward>> channelPointRewards_;
172 
173     bool mod_ = false;
174     bool vip_ = false;
175     bool staff_ = false;
176     UniqueAccess<QString> roomID_;
177 
178     // --
179     QString lastSentMessage_;
180     QObject lifetimeGuard_;
181     QTimer liveStatusTimer_;
182     QTimer chattersListTimer_;
183     QElapsedTimer titleRefreshedTimer_;
184     QElapsedTimer clipCreationTimer_;
185     bool isClipCreationInProgress{false};
186 
187     friend class TwitchIrcServer;
188     friend class TwitchMessageBuilder;
189     friend class IrcMessageHandler;
190 };
191 
192 }  // namespace chatterino
193