Chatterino
TwitchChannel.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include "Application.hpp"
4 #include "common/Aliases.hpp"
5 #include "common/Atomic.hpp"
6 #include "common/Channel.hpp"
8 #include "common/ChatterSet.hpp"
9 #include "common/Outcome.hpp"
10 #include "common/UniqueAccess.hpp"
16 #include "util/QStringHash.hpp"
17 
18 #include <QColor>
19 #include <QElapsedTimer>
20 #include <QRegularExpression>
21 #include <boost/optional.hpp>
22 #include <boost/signals2.hpp>
23 #include <pajlada/signals/signalholder.hpp>
24 
25 #include <atomic>
26 #include <mutex>
27 #include <unordered_map>
28 
29 namespace chatterino {
30 
31 // This is to make sure that combined emoji go through properly, see
32 // https://github.com/Chatterino/chatterino2/issues/3384 and
33 // https://mm2pl.github.io/emoji_rfc.pdf for more details
34 const QString ZERO_WIDTH_JOINER = QString(QChar(0x200D));
35 
36 // Here be MSVC: Do NOT replace with "\U" literal, it will fail silently.
37 namespace {
38  const QChar ESCAPE_TAG_CHARS[2] = {QChar::highSurrogate(0xE0002),
39  QChar::lowSurrogate(0xE0002)};
40 }
41 const QString ESCAPE_TAG = QString(ESCAPE_TAG_CHARS, 2);
42 
43 const static QRegularExpression COMBINED_FIXER(
44  QString("(?<!%1)%1").arg(ESCAPE_TAG),
45  QRegularExpression::UseUnicodePropertiesOption);
46 
47 enum class HighlightState;
48 
49 struct Emote;
50 using EmotePtr = std::shared_ptr<const Emote>;
51 class EmoteMap;
52 
53 class TwitchBadges;
54 class FfzEmotes;
55 class BttvEmotes;
56 class SeventvEmotes;
57 
58 class TwitchIrcServer;
59 
60 class TwitchChannel : public Channel, public ChannelChatters
61 {
62 public:
63  struct StreamStatus {
64  bool live = false;
65  bool rerun = false;
66  unsigned viewerCount = 0;
67  QString title;
68  QString game;
69  QString gameId;
70  QString uptime;
71  QString streamType;
72  };
73 
74  struct RoomModes {
75  bool submode = false;
76  bool r9k = false;
77  bool emoteOnly = false;
78  int followerOnly = -1;
79  int slowMode = 0;
80  };
81 
82  explicit TwitchChannel(const QString &channelName);
83 
84  void initialize();
85 
86  // Channel methods
87  virtual bool isEmpty() const override;
88  virtual bool canSendMessage() const override;
89  virtual void sendMessage(const QString &message) override;
90  virtual void sendReply(const QString &message, const QString &replyId);
91  virtual bool isMod() const override;
92  bool isVip() const;
93  bool isStaff() const;
94  virtual bool isBroadcaster() const override;
95  virtual bool hasHighRateLimit() const override;
96  virtual bool canReconnect() const override;
97  virtual void reconnect() override;
98  void refreshTitle();
99  void createClip();
100 
101  // Data
102  const QString &subscriptionUrl();
103  const QString &channelUrl();
104  const QString &popoutPlayerUrl();
105  int chatterCount();
106  virtual bool isLive() const override;
107  QString roomId() const;
110 
111  // Emotes
112  boost::optional<EmotePtr> bttvEmote(const EmoteName &name) const;
113  boost::optional<EmotePtr> ffzEmote(const EmoteName &name) const;
114  boost::optional<EmotePtr> seventvEmote(const EmoteName &name) const;
115  std::shared_ptr<const EmoteMap> bttvEmotes() const;
116  std::shared_ptr<const EmoteMap> ffzEmotes() const;
117  std::shared_ptr<const EmoteMap> seventvEmotes() const;
118 
119  virtual void refreshBTTVChannelEmotes(bool manualRefresh);
120  virtual void refreshFFZChannelEmotes(bool manualRefresh);
121  virtual void refreshSevenTVChannelEmotes(bool manualRefresh);
122 
123  const QString &seventvUserID() const;
124  const QString &seventvEmoteSetID() const;
125 
127  void addSeventvEmote(const SeventvEventAPIEmoteAddDispatch &dispatch);
133  void updateSeventvUser(
135 
136  // Update the channel's 7TV information (the channel's 7TV user ID and emote set ID)
137  void updateSeventvData(const QString &newUserID,
138  const QString &newEmoteSetID);
139 
140  // Badges
141  boost::optional<EmotePtr> ffzCustomModBadge() const;
142  boost::optional<EmotePtr> ffzCustomVipBadge() const;
143  boost::optional<EmotePtr> twitchBadge(const QString &set,
144  const QString &version) const;
145 
146  // Cheers
147  boost::optional<CheerEmote> cheerEmote(const QString &string);
148 
149  // Replies
156  void addReplyThread(const std::shared_ptr<MessageThread> &thread);
157  const std::unordered_map<QString, std::weak_ptr<MessageThread>> &threads()
158  const;
159 
160  // Signals
161  pajlada::Signals::NoArgSignal roomIdChanged;
162  pajlada::Signals::NoArgSignal userStateChanged;
163  pajlada::Signals::NoArgSignal liveStatusChanged;
164  pajlada::Signals::NoArgSignal roomModesChanged;
165 
166  // Channel point rewards
167  pajlada::Signals::SelfDisconnectingSignal<ChannelPointReward>
169  void addChannelPointReward(const ChannelPointReward &reward);
170  bool isChannelPointRewardKnown(const QString &rewardId);
171  boost::optional<ChannelPointReward> channelPointReward(
172  const QString &rewardId) const;
173 
174 private:
175  struct NameOptions {
176  QString displayName;
177  QString localizedName;
178  } nameOptions;
179 
180 private:
181  // Methods
182  void refreshLiveStatus();
183  void parseLiveStatus(bool live, const HelixStream &stream);
184  void refreshPubSub();
185  void refreshChatters();
186  void refreshBadges();
187  void refreshCheerEmotes();
188  void loadRecentMessages();
189  void loadRecentMessagesReconnect();
190  void fetchDisplayName();
191  void cleanUpReplyThreads();
192  void showLoginMessage();
193 
194  void setLive(bool newLiveStatus);
195  void setMod(bool value);
196  void setVIP(bool value);
197  void setStaff(bool value);
198  void setRoomId(const QString &id);
199  void setRoomModes(const RoomModes &roomModes_);
200  void setDisplayName(const QString &name);
201  void setLocalizedName(const QString &name);
202 
203  const QString &getDisplayName() const override;
204  const QString &getLocalizedName() const override;
205 
206  QString prepareMessage(const QString &message) const;
207 
218  void addOrReplaceLiveUpdatesAddRemove(bool isEmoteAdd,
219  const QString &platform,
220  const QString &actor,
221  const QString &emoteName);
222 
238  bool tryReplaceLastLiveUpdateAddOrRemove(MessageFlag op,
239  const QString &platform,
240  const QString &actor,
241  const QString &emoteName);
242 
243  // Data
244  const QString subscriptionUrl_;
245  const QString channelUrl_;
246  const QString popoutPlayerUrl_;
247  int chatterCount_;
248  UniqueAccess<StreamStatus> streamStatus_;
249  UniqueAccess<RoomModes> roomModes_;
250  std::atomic_flag loadingRecentMessages_ = ATOMIC_FLAG_INIT;
251  std::unordered_map<QString, std::weak_ptr<MessageThread>> threads_;
252 
253 protected:
259 
260 private:
261  // Badges
263  badgeSets_; // "subscribers": { "0": ... "3": ... "6": ...
266 
267  bool mod_ = false;
268  bool vip_ = false;
269  bool staff_ = false;
270  UniqueAccess<QString> roomID_;
271 
272  // --
273  QString lastSentMessage_;
274  QObject lifetimeGuard_;
275  QTimer chattersListTimer_;
276  QTimer threadClearTimer_;
277  QElapsedTimer titleRefreshedTimer_;
278  QElapsedTimer clipCreationTimer_;
279  bool isClipCreationInProgress{false};
280 
285  QString seventvUserID_;
290  QString seventvEmoteSetID_;
295  size_t seventvUserTwitchConnectionIndex_;
296 
298  QString lastLiveUpdateEmotePlatform_;
300  QString lastLiveUpdateEmoteActor_;
302  std::weak_ptr<const Message> lastLiveUpdateMessage_;
304  std::vector<QString> lastLiveUpdateEmoteNames_;
305 
306  pajlada::Signals::SignalHolder signalHolder_;
307  std::vector<boost::signals2::scoped_connection> bSignals_;
308 
309  friend class TwitchIrcServer;
310  friend class TwitchMessageBuilder;
311  friend class IrcMessageHandler;
312 };
313 
314 } // namespace chatterino
QString game
Definition: TwitchChannel.hpp:68
std::shared_ptr< const EmoteMap > bttvEmotes() const
Definition: TwitchChannel.cpp:588
QString title
Definition: TwitchChannel.hpp:67
Definition: BttvEmotes.hpp:15
QString emoteOnly(const CommandContext &ctx)
Definition: ChatSettings.cpp:100
const QString & channelUrl()
Definition: TwitchChannel.cpp:805
std::shared_ptr< const EmoteMap > ffzEmotes() const
Definition: TwitchChannel.cpp:593
Definition: TwitchChannel.hpp:63
Definition: Emote.hpp:14
virtual bool isLive() const override
Definition: TwitchChannel.cpp:544
std::shared_ptr< const EmoteMap > seventvEmotes() const
Definition: TwitchChannel.cpp:598
Definition: TwitchChannel.hpp:60
Atomic< boost::optional< EmotePtr > > ffzCustomModBadge_
Definition: TwitchChannel.hpp:257
void addChannelPointReward(const ChannelPointReward &reward)
Definition: TwitchChannel.cpp:261
unsigned viewerCount
Definition: TwitchChannel.hpp:66
Definition: UniqueAccess.hpp:10
void addReplyThread(const std::shared_ptr< MessageThread > &thread)
Definition: TwitchChannel.cpp:1161
Definition: TwitchBadges.hpp:27
pajlada::Signals::NoArgSignal roomIdChanged
Definition: TwitchChannel.hpp:161
QString streamType
Definition: TwitchChannel.hpp:71
bool isChannelPointRewardKnown(const QString &rewardId)
Definition: TwitchChannel.cpp:289
Definition: Application.cpp:48
Definition: SeventvEventAPIDispatch.hpp:21
boost::optional< ChannelPointReward > channelPointReward(const QString &rewardId) const
Definition: TwitchChannel.cpp:296
Atomic< std::shared_ptr< const EmoteMap > > ffzEmotes_
Definition: TwitchChannel.hpp:255
virtual void sendMessage(const QString &message) override
Definition: TwitchChannel.cpp:382
const QString ESCAPE_TAG
Definition: TwitchChannel.hpp:41
Definition: TwitchMessageBuilder.hpp:37
pajlada::Signals::SelfDisconnectingSignal< ChannelPointReward > channelPointRewardAdded
Definition: TwitchChannel.hpp:168
pajlada::Signals::NoArgSignal userStateChanged
Definition: TwitchChannel.hpp:162
virtual bool canSendMessage() const override
Definition: TwitchChannel.cpp:163
boost::optional< EmotePtr > ffzCustomModBadge() const
Definition: TwitchChannel.cpp:1448
QString displayName
Definition: InputCompletionPopup.cpp:21
boost::optional< CheerEmote > cheerEmote(const QString &string)
Definition: TwitchChannel.cpp:1458
HighlightState
Definition: Common.hpp:16
Definition: SeventvEmotes.hpp:57
std::shared_ptr< const Emote > EmotePtr
Definition: Emote.hpp:38
Definition: Emote.hpp:40
const QString & seventvEmoteSetID() const
Definition: TwitchChannel.cpp:607
boost::optional< EmotePtr > twitchBadge(const QString &set, const QString &version) const
Definition: TwitchChannel.cpp:1432
void initialize()
Definition: TwitchChannel.cpp:151
boost::optional< EmotePtr > ffzCustomVipBadge() const
Definition: TwitchChannel.cpp:1453
Definition: TwitchChannel.hpp:74
Definition: UniqueAccess.hpp:53
virtual void refreshFFZChannelEmotes(bool manualRefresh)
Definition: TwitchChannel.cpp:206
Definition: FfzEmotes.hpp:15
MessageFlag
Definition: Message.hpp:18
pajlada::Signals::NoArgSignal liveStatusChanged
Definition: TwitchChannel.hpp:163
Definition: SeventvEventAPIDispatch.hpp:45
Definition: Channel.hpp:30
const std::unordered_map< QString, std::weak_ptr< MessageThread > > & threads() const
Definition: TwitchChannel.cpp:1167
virtual bool canReconnect() const override
Definition: TwitchChannel.cpp:506
const QString & subscriptionUrl()
Definition: TwitchChannel.cpp:800
boost::optional< EmotePtr > bttvEmote(const EmoteName &name) const
Definition: TwitchChannel.cpp:555
TwitchChannel(const QString &channelName)
Definition: TwitchChannel.cpp:57
Definition: Helix.hpp:85
virtual void reconnect() override
Definition: TwitchChannel.cpp:511
bool rerun
Definition: TwitchChannel.hpp:65
const QString & seventvUserID() const
Definition: TwitchChannel.cpp:603
virtual void refreshBTTVChannelEmotes(bool manualRefresh)
Definition: TwitchChannel.cpp:188
virtual void sendReply(const QString &message, const QString &replyId)
Definition: TwitchChannel.cpp:415
Definition: ChannelChatters.hpp:13
bool isVip() const
Definition: TwitchChannel.cpp:454
Definition: ChannelPointReward.hpp:14
virtual bool isMod() const override
Definition: TwitchChannel.cpp:449
bool isStaff() const
Definition: TwitchChannel.cpp:459
bool live
Definition: TwitchChannel.hpp:64
void addSeventvEmote(const SeventvEventAPIEmoteAddDispatch &dispatch)
Definition: TwitchChannel.cpp:612
Definition: TwitchIrcServer.hpp:24
SharedAccessGuard< const StreamStatus > accessStreamStatus() const
Definition: TwitchChannel.cpp:550
virtual bool isBroadcaster() const override
Definition: TwitchChannel.cpp:494
QString roomId() const
Definition: TwitchChannel.cpp:516
void updateSeventvUser(const SeventvEventAPIUserConnectionUpdateDispatch &dispatch)
Definition: TwitchChannel.cpp:651
Definition: SeventvEventAPIDispatch.hpp:58
QString name
Definition: Credentials.cpp:94
pajlada::Signals::NoArgSignal roomModesChanged
Definition: TwitchChannel.hpp:164
boost::optional< EmotePtr > ffzEmote(const EmoteName &name) const
Definition: TwitchChannel.cpp:565
virtual void refreshSevenTVChannelEmotes(bool manualRefresh)
Definition: TwitchChannel.cpp:236
const QString ZERO_WIDTH_JOINER
Definition: TwitchChannel.hpp:34
Definition: IrcMessageHandler.hpp:16
SharedAccessGuard< const RoomModes > accessRoomModes() const
Definition: TwitchChannel.cpp:532
void refreshTitle()
Definition: TwitchChannel.cpp:906
QString uptime
Definition: TwitchChannel.hpp:70
void updateSeventvData(const QString &newUserID, const QString &newEmoteSetID)
Definition: TwitchChannel.cpp:690
void updateSeventvEmote(const SeventvEventAPIEmoteUpdateDispatch &dispatch)
Definition: TwitchChannel.cpp:624
void removeSeventvEmote(const SeventvEventAPIEmoteRemoveDispatch &dispatch)
Definition: TwitchChannel.cpp:638
int chatterCount()
Definition: TwitchChannel.cpp:815
virtual bool isEmpty() const override
Definition: TwitchChannel.cpp:158
void createClip()
Definition: TwitchChannel.cpp:1319
Atomic< boost::optional< EmotePtr > > ffzCustomVipBadge_
Definition: TwitchChannel.hpp:258
QString gameId
Definition: TwitchChannel.hpp:69
virtual bool hasHighRateLimit() const override
Definition: TwitchChannel.cpp:501
const QString & popoutPlayerUrl()
Definition: TwitchChannel.cpp:810
Definition: SeventvEventAPIDispatch.hpp:33
Atomic< std::shared_ptr< const EmoteMap > > bttvEmotes_
Definition: TwitchChannel.hpp:254
Atomic< std::shared_ptr< const EmoteMap > > seventvEmotes_
Definition: TwitchChannel.hpp:256
boost::optional< EmotePtr > seventvEmote(const EmoteName &name) const
Definition: TwitchChannel.cpp:575
Definition: Atomic.hpp:9