From 89ffa6611c02adcdb0940f1f93de96adc80a5b6b Mon Sep 17 00:00:00 2001 From: WarmUpTill <19472752+WarmUpTill@users.noreply.github.com> Date: Mon, 15 Jun 2026 20:01:01 +0200 Subject: [PATCH] Add option to get commercial info --- data/locale/en-US.ini | 14 +++++++ plugins/twitch/macro-action-twitch.cpp | 54 ++++++++++++++++++++++++++ plugins/twitch/macro-action-twitch.hpp | 6 ++- 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 8104a32f..b87ff2eb 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -1395,6 +1395,7 @@ AdvSceneSwitcher.action.twitch.type.user.vip.add="Add user as VIP" AdvSceneSwitcher.action.twitch.type.user.vip.delete="Remove user as VIP" AdvSceneSwitcher.action.twitch.type.reward.getInfo="Get channel points reward information" AdvSceneSwitcher.action.twitch.type.channel.getInfo="Get channel information" +AdvSceneSwitcher.action.twitch.type.channel.ads.getInfo="Get channel ad schedule" AdvSceneSwitcher.action.twitch.reward.toggleControl="Toggle reward name / variable selection control" AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Cannot select category without selecting a Twitch account first!" AdvSceneSwitcher.action.twitch.layout.default="On{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{nonModDelayDuration}}{{channel}}{{pointsReward}}" @@ -2278,6 +2279,19 @@ AdvSceneSwitcher.tempVar.twitch.requester_user_login.commercial.description="The AdvSceneSwitcher.tempVar.twitch.requester_user_name.commercial="Requester user name" AdvSceneSwitcher.tempVar.twitch.requester_user_name.commercial.description="The display name of the user that requested the ad." +AdvSceneSwitcher.tempVar.twitch.snooze_count.ads="Snooze count" +AdvSceneSwitcher.tempVar.twitch.snooze_count.ads.description="The number of snoozes available for the broadcaster." +AdvSceneSwitcher.tempVar.twitch.snooze_refresh_at.ads="Snooze refresh time" +AdvSceneSwitcher.tempVar.twitch.snooze_refresh_at.ads.description="The UTC timestamp of when the broadcaster will have an additional snooze available, in RFC3339 format." +AdvSceneSwitcher.tempVar.twitch.next_ad_at.ads="Next ad time" +AdvSceneSwitcher.tempVar.twitch.next_ad_at.ads.description="The UTC timestamp of when the channel's next scheduled ad break will begin, in RFC3339 format." +AdvSceneSwitcher.tempVar.twitch.duration.ads="Ad duration" +AdvSceneSwitcher.tempVar.twitch.duration.ads.description="The length in seconds of the scheduled ad break." +AdvSceneSwitcher.tempVar.twitch.last_ad_at.ads="Last ad time" +AdvSceneSwitcher.tempVar.twitch.last_ad_at.ads.description="The UTC timestamp of the channel's last ad break, in RFC3339 format." +AdvSceneSwitcher.tempVar.twitch.preroll_free_time.ads="Pre-roll free time" +AdvSceneSwitcher.tempVar.twitch.preroll_free_time.ads.description="The amount of time in seconds the broadcaster must wait before running another commercial." + AdvSceneSwitcher.tempVar.audio.output_volume="Output volume" AdvSceneSwitcher.tempVar.audio.output_volume.description="The volume the audio source is outputting." AdvSceneSwitcher.tempVar.audio.configured_volume="Configured volume" diff --git a/plugins/twitch/macro-action-twitch.cpp b/plugins/twitch/macro-action-twitch.cpp index 96e6f1b7..d0438490 100644 --- a/plugins/twitch/macro-action-twitch.cpp +++ b/plugins/twitch/macro-action-twitch.cpp @@ -136,6 +136,8 @@ const static std::map actionTypes = { "AdvSceneSwitcher.action.twitch.type.reward.getInfo"}, {MacroActionTwitch::Action::CHANNEL_GET_INFO, "AdvSceneSwitcher.action.twitch.type.channel.getInfo"}, + {MacroActionTwitch::Action::CHANNEL_ADS_GET_INFO, + "AdvSceneSwitcher.action.twitch.type.channel.ads.getInfo"}, }; const static std::map @@ -450,6 +452,43 @@ void MacroActionTwitch::GetChannelInfo(const std::shared_ptr &token info->is_branded_content ? "true" : "false"); } +void MacroActionTwitch::GetAdsInfo(const std::shared_ptr &token) +{ + const auto id = token->GetUserID(); + if (!id) { + vblog(LOG_INFO, "%s skip - invalid user id", __func__); + return; + } + + auto result = SendGetRequest(*token, "https://api.twitch.tv", + "/helix/channels/ads", + {{"broadcaster_id", *id}}); + + if (result.status != 200) { + blog(LOG_INFO, "Failed to get ads info! (%d)", result.status); + return; + } + + OBSDataArrayAutoRelease array = obs_data_get_array(result.data, "data"); + if (obs_data_array_count(array) == 0) { + blog(LOG_WARNING, "%s did not return any data!", __func__); + return; + } + + OBSDataAutoRelease data = obs_data_array_item(array, 0); + SetTempVarValue("snooze_count", + std::to_string(obs_data_get_int(data, "snooze_count"))); + SetTempVarValue("snooze_refresh_at", + obs_data_get_string(data, "snooze_refresh_at")); + SetTempVarValue("next_ad_at", obs_data_get_string(data, "next_ad_at")); + SetTempVarValue("duration", + std::to_string(obs_data_get_int(data, "duration"))); + SetTempVarValue("last_ad_at", obs_data_get_string(data, "last_ad_at")); + SetTempVarValue( + "preroll_free_time", + std::to_string(obs_data_get_int(data, "preroll_free_time"))); +} + std::optional MacroActionTwitch::GetTargetUserID( const std::shared_ptr &token) const { @@ -688,6 +727,14 @@ void MacroActionTwitch::SetupTempVars() setupTempVarHelper("content_classification_labels"); setupTempVarHelper("is_branded_content"); break; + case Action::CHANNEL_ADS_GET_INFO: + setupTempVarHelper("snooze_count", ".ads"); + setupTempVarHelper("snooze_refresh_at", ".ads"); + setupTempVarHelper("next_ad_at", ".ads"); + setupTempVarHelper("duration", ".ads"); + setupTempVarHelper("last_ad_at", ".ads"); + setupTempVarHelper("preroll_free_time", ".ads"); + break; default: break; } @@ -1054,6 +1101,9 @@ bool MacroActionTwitch::PerformAction() case MacroActionTwitch::Action::CHANNEL_GET_INFO: GetChannelInfo(token); break; + case MacroActionTwitch::Action::CHANNEL_ADS_GET_INFO: + GetAdsInfo(token); + break; default: break; } @@ -1273,6 +1323,7 @@ bool MacroActionTwitch::ActionIsSupportedByToken() {Action::SEND_CHAT_MESSAGE, {{"chat:edit"}}}, {Action::USER_GET_INFO, {}}, {Action::CHANNEL_GET_INFO, {}}, + {Action::CHANNEL_ADS_GET_INFO, {{"channel:read:ads"}}}, {Action::POINTS_REWARD_GET_INFO, {{"channel:read:redemptions"}, {"channel:manage:redemptions"}}}}; @@ -1660,6 +1711,7 @@ void MacroActionTwitchEdit::SetWidgetVisibility() action == MacroActionTwitch::Action::USER_VIP_DELETE; _channel->setVisible( action == MacroActionTwitch::Action::CHANNEL_GET_INFO || + action == MacroActionTwitch::Action::CHANNEL_ADS_GET_INFO || action == MacroActionTwitch::Action::RAID_START || action == MacroActionTwitch::Action::RAID_END || action == MacroActionTwitch::Action::SHOUTOUT_SEND || @@ -1879,6 +1931,7 @@ void MacroActionTwitchEdit::SetWidgetLayout() "AdvSceneSwitcher.action.twitch.layout.reward.getInfo.row2"); break; case MacroActionTwitch::Action::CHANNEL_GET_INFO: + case MacroActionTwitch::Action::CHANNEL_ADS_GET_INFO: layoutText = obs_module_text( "AdvSceneSwitcher.action.twitch.layout.channel.getInfo"); break; @@ -1898,6 +1951,7 @@ void MacroActionTwitchEdit::SetWidgetLayout() const bool showVariableMapping = action == MacroActionTwitch::Action::CHANNEL_GET_INFO || + action == MacroActionTwitch::Action::CHANNEL_ADS_GET_INFO || action == MacroActionTwitch::Action::USER_GET_INFO || action == MacroActionTwitch::Action::POINTS_REWARD_GET_INFO; emit ShowVariableMappings(showVariableMapping); diff --git a/plugins/twitch/macro-action-twitch.hpp b/plugins/twitch/macro-action-twitch.hpp index aa17784f..3323f39e 100644 --- a/plugins/twitch/macro-action-twitch.hpp +++ b/plugins/twitch/macro-action-twitch.hpp @@ -142,9 +142,10 @@ public: SEND_CHAT_MESSAGE = 5000, - // Get user info + // Get info USER_GET_INFO = 6000, CHANNEL_GET_INFO = 6100, + CHANNEL_ADS_GET_INFO = 6200, }; enum class AnnouncementColor { @@ -205,7 +206,8 @@ private: void SendChatMessage(const std::shared_ptr &); void GetUserInfo(const std::shared_ptr &); void GetRewardInfo(const std::shared_ptr &); - void GetChannelInfo(const std::shared_ptr &token); + void GetChannelInfo(const std::shared_ptr &); + void GetAdsInfo(const std::shared_ptr &); std::optional GetTargetUserID(const std::shared_ptr &) const;