#pragma once #include "macro-condition-edit.hpp" #include "token.hpp" #include "category-selection.hpp" #include "channel-selection.hpp" #include "points-reward-selection.hpp" #include "chat-connection.hpp" #include "chat-message-pattern.hpp" #include #include #include namespace advss { class MacroConditionTwitch : public MacroCondition { public: MacroConditionTwitch(Macro *m) : MacroCondition(m, true) {} static std::shared_ptr Create(Macro *m) { return std::make_shared(m); } std::string GetId() const { return id; }; std::string GetShortDesc() const; enum class Condition { // Event based STREAM_ONLINE_EVENT = 0, STREAM_ONLINE_LIVE_EVENT = 1, STREAM_ONLINE_PLAYLIST_EVENT = 2, STREAM_ONLINE_WATCHPARTY_EVENT = 3, STREAM_ONLINE_PREMIERE_EVENT = 4, STREAM_ONLINE_RERUN_EVENT = 5, STREAM_OFFLINE_EVENT = 100, CHANNEL_INFO_UPDATE_EVENT = 200, FOLLOW_EVENT = 300, SUBSCRIPTION_START_EVENT = 400, SUBSCRIPTION_END_EVENT = 500, SUBSCRIPTION_GIFT_EVENT = 600, SUBSCRIPTION_MESSAGE_EVENT = 700, CHEER_EVENT = 800, RAID_OUTBOUND_EVENT = 900, RAID_INBOUND_EVENT = 1000, SHOUTOUT_OUTBOUND_EVENT = 1100, SHOUTOUT_INBOUND_EVENT = 1200, COMMERCIAL_START = 1250, POLL_START_EVENT = 1300, POLL_PROGRESS_EVENT = 1400, POLL_END_EVENT = 1500, PREDICTION_START_EVENT = 1600, PREDICTION_PROGRESS_EVENT = 1700, PREDICTION_LOCK_EVENT = 1800, PREDICTION_END_EVENT = 1900, GOAL_START_EVENT = 2000, GOAL_PROGRESS_EVENT = 2100, GOAL_END_EVENT = 2200, HYPE_TRAIN_START_EVENT = 2300, HYPE_TRAIN_PROGRESS_EVENT = 2400, HYPE_TRAIN_END_EVENT = 2500, CHARITY_CAMPAIGN_START_EVENT = 2600, CHARITY_CAMPAIGN_PROGRESS_EVENT = 2700, CHARITY_CAMPAIGN_DONATION_EVENT = 2800, CHARITY_CAMPAIGN_END_EVENT = 2900, SHIELD_MODE_START_EVENT = 3000, SHIELD_MODE_END_EVENT = 3100, POINTS_REWARD_ADDITION_EVENT = 3200, POINTS_REWARD_UPDATE_EVENT = 3300, POINTS_REWARD_DELETION_EVENT = 3400, POINTS_REWARD_REDEMPTION_EVENT = 3500, POINTS_REWARD_REDEMPTION_UPDATE_EVENT = 3600, USER_BAN_EVENT = 3700, USER_UNBAN_EVENT = 3800, USER_MODERATOR_ADDITION_EVENT = 3900, USER_MODERATOR_DELETION_EVENT = 4000, // Chat CHAT_MESSAGE_RECEIVED = 500000, CHAT_MESSAGE_REMOVED = 500030, CHAT_CLEARED = 500060, CHAT_USER_JOINED = 500100, CHAT_USER_LEFT = 500200, // Polling LIVE_POLLING = 1000000, TITLE_POLLING = 1000100, CATEGORY_POLLING = 1000200, }; void SetCondition(const Condition &condition); Condition GetCondition() const { return _condition; } void SetToken(const std::weak_ptr &); std::weak_ptr GetToken() const { return _token; } void SetChannel(const TwitchChannel &channel); TwitchChannel GetChannel() const { return _channel; } void SetPointsReward(const TwitchPointsReward &pointsReward); TwitchPointsReward GetPointsReward() const { return _pointsReward; } void ResetChatConnection(); bool IsUsingEventSubCondition(); bool CheckCondition(); bool Save(obs_data_t *obj) const; bool Load(obs_data_t *obj); bool ConditionIsSupportedByToken(); TwitchChannel _channel; TwitchPointsReward _pointsReward; StringVariable _streamTitle = obs_module_text( "AdvSceneSwitcher.condition.twitch.title.title"); RegexConfig _regexTitle = RegexConfig::PartialMatchRegexConfig(); ChatMessagePattern _chatMessagePattern; TwitchCategory _category; bool _clearBufferOnMatch = false; private: bool CheckChannelGenericEvents(); bool CheckChannelLiveEvents(); bool CheckChannelRewardChangeEvents(); bool CheckChannelRewardRedemptionEvents(); bool HandleMatchingSubscriptionEvents( const std::function &matchCb); bool CheckChatMessages(TwitchToken &token); bool CheckChatUserJoinOrLeave(TwitchToken &token); bool CheckChatClear(TwitchToken &token); bool CheckChatMessageRemove(TwitchToken &token); bool ChatConnectionIsSetup(TwitchToken &token); bool HandleChatEvents( const std::function &matchCb); void RegisterEventSubscription(); void ResetSubscription(); void SetupEventSubscription(EventSub &); bool EventSubscriptionIsSetup(const std::shared_ptr &); void AddChannelGenericEventSubscription( const char *version, bool includeModeratorId = false, const char *mainUserIdFieldName = "broadcaster_user_id", obs_data_t *extraConditions = nullptr); void HandleMacroPause(); void SetupTempVars(); void SetTempVarValues(const ChannelLiveInfo &); void SetTempVarValues(const ChannelInfo &); Condition _condition = Condition::LIVE_POLLING; std::weak_ptr _token; EventSubMessageBuffer _eventBuffer; std::future _subscriptionIDFuture; std::string _subscriptionID; ChatMessageBuffer _chatBuffer; std::shared_ptr _chatConnection; std::chrono::high_resolution_clock::time_point _lastCheck{}; static bool _registered; static const std::string id; }; class MacroConditionTwitchEdit : public QWidget { Q_OBJECT public: MacroConditionTwitchEdit( QWidget *parent, std::shared_ptr entryData = nullptr); static QWidget *Create(QWidget *parent, std::shared_ptr cond) { return new MacroConditionTwitchEdit( parent, std::dynamic_pointer_cast(cond)); } void UpdateEntryData(); private slots: void ConditionChanged(int); void TwitchTokenChanged(const QString &); void CheckToken(); void ChannelChanged(const TwitchChannel &); void PointsRewardChanged(const TwitchPointsReward &); void StreamTitleChanged(); void RegexTitleChanged(const RegexConfig &); void ChatMessagePatternChanged(const ChatMessagePattern &); void CategoryChanged(const TwitchCategory &); void ClearBufferOnMatchChanged(int); signals: void HeaderInfoChanged(const QString &); private: void SetWidgetVisibility(); void SetTokenWarning(bool visible, const QString &text = ""); QHBoxLayout *_layout; FilterComboBox *_conditions; TwitchConnectionSelection *_tokens; QLabel *_tokenWarning; QTimer _tokenCheckTimer; TwitchChannelSelection *_channel; TwitchPointsRewardWidget *_pointsReward; VariableLineEdit *_streamTitle; RegexConfigWidget *_regexTitle; ChatMessageEdit *_chatMesageEdit; TwitchCategoryWidget *_category; QCheckBox *_clearBufferOnMatch; std::shared_ptr _entryData; bool _loading = true; }; } // namespace advss