mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-22 09:15:57 -05:00
Add option to query reward information
This commit is contained in:
@@ -1144,10 +1144,13 @@ AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.enable="Enable chat's emote-o
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="Disable chat's emote-only mode"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.sendMessage="Send chat message"
|
||||
AdvSceneSwitcher.action.twitch.type.user.getInfo="Get user information"
|
||||
AdvSceneSwitcher.action.twitch.type.reward.getInfo="Get channel points reward information"
|
||||
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.entry.default="On{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.default="On{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.chat="Using account{{account}}{{actions}}on{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.user.getInfo="Using account{{account}}{{actions}}for{{userInfoQueryType}}{{userLogin}}{{userId}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.reward.getInfo="Using account{{account}}{{actions}}for channel{{channel}}{{pointsReward}}{{rewardVariable}}{{toggleRewardSelection}}"
|
||||
AdvSceneSwitcher.action.twitch.title.title="Enter title"
|
||||
AdvSceneSwitcher.action.twitch.marker.description="Describe marker"
|
||||
AdvSceneSwitcher.action.twitch.clip.hasDelay="Add a slight delay before capturing the clip"
|
||||
@@ -1631,22 +1634,37 @@ AdvSceneSwitcher.tempVar.twitch.title.reward="Reward title"
|
||||
AdvSceneSwitcher.tempVar.twitch.cost.reward="Reward cost"
|
||||
AdvSceneSwitcher.tempVar.twitch.prompt.reward="Reward description"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_user_input_required.reward="Reward requires user input"
|
||||
AdvSceneSwitcher.tempVar.twitch.should_redemptions_skip_request_queue.reward="Redemptions skip request queue"
|
||||
AdvSceneSwitcher.tempVar.twitch.should_redemptions_skip_request_queue.reward.description="Should redemptions be set to fulfilled status immediately when redeemed and skip the request queue instead of the normal unfulfilled status."
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_stream.reward="Reward maximum per stream"
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_user_per_stream.reward="Reward maximum per user per stream"
|
||||
AdvSceneSwitcher.tempVar.twitch.background_color.reward="Reward background color"
|
||||
AdvSceneSwitcher.tempVar.twitch.image.reward="Reward image"
|
||||
AdvSceneSwitcher.tempVar.twitch.image.reward="Reward image (JSON)"
|
||||
AdvSceneSwitcher.tempVar.twitch.image.reward.description="Set of custom images of 1x, 2x and 4x sizes for the reward. Can be null if no images have been uploaded."
|
||||
AdvSceneSwitcher.tempVar.twitch.default_image.reward="Reward default image"
|
||||
AdvSceneSwitcher.tempVar.twitch.image.url_4x.reward="Reward image URL"
|
||||
AdvSceneSwitcher.tempVar.twitch.image.url_4x.reward.description="The URL to the custom image for the reward. This field is null if the broadcaster didn’t upload images."
|
||||
AdvSceneSwitcher.tempVar.twitch.default_image.reward="Reward default image (JSON)"
|
||||
AdvSceneSwitcher.tempVar.twitch.default_image.reward.description="Set of default images of 1x, 2x and 4x sizes for the reward."
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.reward="Reward cooldown"
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.reward.description="Whether a cooldown is enabled and what the cooldown is in seconds."
|
||||
AdvSceneSwitcher.tempVar.twitch.cooldown_expires_at.reward="Reward cooldown expiration"
|
||||
AdvSceneSwitcher.tempVar.twitch.cooldown_expires_at.reward.description="Timestamp of the cooldown expiration. null if the reward isn’t on cooldown."
|
||||
AdvSceneSwitcher.tempVar.twitch.default_image.url_4x.reward="Reward default image URL"
|
||||
AdvSceneSwitcher.tempVar.twitch.default_image.url_4x.reward.description="The URL to the default image for the reward."
|
||||
AdvSceneSwitcher.tempVar.twitch.redemptions_redeemed_current_stream.reward="Redemption count"
|
||||
AdvSceneSwitcher.tempVar.twitch.redemptions_redeemed_current_stream.reward.description="The number of redemptions redeemed during the current live stream. Counts against the max_per_stream limit. null if the broadcasters stream isn’t live or max_per_stream isn’t enabled."
|
||||
AdvSceneSwitcher.tempVar.twitch.redemptions_redeemed_current_stream.reward.description="The number of redemptions redeemed during the current live stream. Counts against the max_per_stream limit. null if the broadcasters stream isn’t live or max_per_stream isn’t enabled."
|
||||
AdvSceneSwitcher.tempVar.twitch.should_redemptions_skip_request_queue.reward="Redemptions skip request queue"
|
||||
AdvSceneSwitcher.tempVar.twitch.should_redemptions_skip_request_queue.reward.description="Should redemptions be set to fulfilled status immediately when redeemed and skip the request queue instead of the normal unfulfilled status."
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_stream.reward="Maximum redemptions per stream (JSON)"
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_stream.is_enabled.reward="Maximum redemptions per stream enabled"
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_stream.is_enabled.reward.description="A Boolean value that determines whether the reward applies a limit on the number of redemptions allowed per live stream. Is true if the reward applies a limit."
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_stream.max_per_stream.reward="Maximum redemptions per stream"
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_stream.max_per_stream.reward.description="The maximum number of redemptions allowed per live stream."
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_user_per_stream.reward="Reward maximum per user per stream (JSON)"
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_user_per_stream.is_enabled.reward="Maximum redemptions per user per stream enabled"
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_user_per_stream.is_enabled.reward.description="A Boolean value that determines whether the reward applies a limit on the number of redemptions allowed per user per live stream. Is true if the reward applies a limit."
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_user_per_stream.max_per_user_per_stream.reward="Maximum redemptions per user per stream"
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_user_per_stream.max_per_user_per_stream.reward.description="The settings used to determine whether to apply a maximum to the number of redemptions allowed per user per live stream."
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.reward="Global cooldown (JSON)"
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.reward.description="Whether a cooldown is enabled and what the cooldown is in seconds."
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.is_enabled.reward="Global cooldown enabled"
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.is_enabled.reward.description="A Boolean value that determines whether to apply a cooldown period. Is true if a cooldown period is enabled."
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.global_cooldown_seconds.reward="Global cooldown"
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.global_cooldown_seconds.reward.description="The cooldown period, in seconds."
|
||||
AdvSceneSwitcher.tempVar.twitch.cooldown_expires_at.reward="Reward cooldown expiration"
|
||||
AdvSceneSwitcher.tempVar.twitch.cooldown_expires_at.reward.description="Timestamp of the cooldown expiration. null if the reward isn’t on cooldown."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.charity_name="Charity name"
|
||||
AdvSceneSwitcher.tempVar.twitch.charity_description="Charity description"
|
||||
|
||||
@@ -1072,7 +1072,7 @@ AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.enable="Habilitar modo apenas
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="Desabilitar modo apenas emotes no chat"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.sendMessage="Enviar mensagem de chat"
|
||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Não é possível selecionar categoria sem selecionar uma conta Twitch primeiro!"
|
||||
AdvSceneSwitcher.action.twitch.entry.default="Em{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.default="Em{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.chat="Usando conta{{account}}{{actions}}em{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.title.title="Digite o título"
|
||||
AdvSceneSwitcher.action.twitch.marker.description="Descreva o marcador"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <log-helper.hpp>
|
||||
#include <layout-helpers.hpp>
|
||||
#include <ui-helpers.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -23,6 +24,16 @@ void MacroActionTwitch::ResolveVariablesToFixedValues()
|
||||
_chatMessage.ResolveVariables();
|
||||
_userLogin.ResolveVariables();
|
||||
_userId.ResolveVariables();
|
||||
_useVariableForRewardSelection = false;
|
||||
auto token = _token.lock();
|
||||
if (token) {
|
||||
ResolveVariableSelectionToRewardId(token);
|
||||
_pointsReward.title = _lastResolvedRewardTitle;
|
||||
_pointsReward.id = _lastResolvedRewardId;
|
||||
} else {
|
||||
_pointsReward.id = "";
|
||||
_pointsReward.id = "";
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroAction> MacroActionTwitch::Create(Macro *m)
|
||||
@@ -63,6 +74,8 @@ const static std::map<MacroActionTwitch::Action, std::string> actionTypes = {
|
||||
"AdvSceneSwitcher.action.twitch.type.chat.sendMessage"},
|
||||
{MacroActionTwitch::Action::USER_GET_INFO,
|
||||
"AdvSceneSwitcher.action.twitch.type.user.getInfo"},
|
||||
{MacroActionTwitch::Action::POINTS_REWARD_GET_INFO,
|
||||
"AdvSceneSwitcher.action.twitch.type.reward.getInfo"},
|
||||
};
|
||||
|
||||
const static std::map<MacroActionTwitch::AnnouncementColor, std::string>
|
||||
@@ -282,7 +295,7 @@ void MacroActionTwitch::GetUserInfo(const std::shared_ptr<TwitchToken> &token)
|
||||
break;
|
||||
}
|
||||
auto result = SendGetRequest(*token, "https://api.twitch.tv",
|
||||
"/helix/users", params);
|
||||
"/helix/users", params, true);
|
||||
|
||||
if (result.status != 200) {
|
||||
blog(LOG_INFO, "Failed get user info! (%d)\n", result.status);
|
||||
@@ -297,80 +310,196 @@ void MacroActionTwitch::GetUserInfo(const std::shared_ptr<TwitchToken> &token)
|
||||
}
|
||||
|
||||
OBSDataAutoRelease data = obs_data_array_item(array, 0);
|
||||
SetJsonTempVars(data, [this](const char *id, const char *value) {
|
||||
SetTempVarValue(id, value);
|
||||
});
|
||||
}
|
||||
|
||||
SetTempVarValue("id", obs_data_get_string(data, "id"));
|
||||
SetTempVarValue("login", obs_data_get_string(data, "login"));
|
||||
SetTempVarValue("display_name",
|
||||
obs_data_get_string(data, "display_name"));
|
||||
SetTempVarValue("type", obs_data_get_string(data, "type"));
|
||||
SetTempVarValue("broadcaster_type",
|
||||
obs_data_get_string(data, "broadcaster_type"));
|
||||
SetTempVarValue("description",
|
||||
obs_data_get_string(data, "description"));
|
||||
SetTempVarValue("profile_image_url",
|
||||
obs_data_get_string(data, "profile_image_url"));
|
||||
SetTempVarValue("offline_image_url",
|
||||
obs_data_get_string(data, "offline_image_url"));
|
||||
SetTempVarValue("created_at", obs_data_get_string(data, "created_at"));
|
||||
bool MacroActionTwitch::ResolveVariableSelectionToRewardId(
|
||||
const std::shared_ptr<TwitchToken> &token)
|
||||
{
|
||||
if (!token) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto variable = _rewardVariable.lock();
|
||||
if (!variable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto rewardTitle = variable->Value();
|
||||
if (rewardTitle.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_lastResolvedRewardTitle == rewardTitle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto rewards = GetPointsRewardsForChannel(token, _channel);
|
||||
if (!rewards) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &reward : *rewards) {
|
||||
if (reward.title == rewardTitle) {
|
||||
_lastResolvedRewardId = reward.id;
|
||||
_lastResolvedRewardTitle = reward.title;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MacroActionTwitch::GetRewardInfo(const std::shared_ptr<TwitchToken> &token)
|
||||
{
|
||||
if (_useVariableForRewardSelection &&
|
||||
!ResolveVariableSelectionToRewardId(token)) {
|
||||
if (VerboseLoggingEnabled()) {
|
||||
auto variable = _rewardVariable.lock();
|
||||
if (!variable) {
|
||||
blog(LOG_WARNING,
|
||||
"failed to resolve variable reward name to reward id (invalid selection)");
|
||||
return;
|
||||
}
|
||||
blog(LOG_WARNING,
|
||||
"failed to resolve variable reward name '%s' to reward id",
|
||||
variable->Value().c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
httplib::Params params = {
|
||||
{"broadcaster_id", token->GetUserID()},
|
||||
{"id", _useVariableForRewardSelection ? _lastResolvedRewardId
|
||||
: _pointsReward.id},
|
||||
};
|
||||
auto result = SendGetRequest(*token, "https://api.twitch.tv",
|
||||
"/helix/channel_points/custom_rewards",
|
||||
params, true);
|
||||
|
||||
if (result.status != 200) {
|
||||
blog(LOG_INFO, "Failed get reward info! (%d)\n", result.status);
|
||||
return;
|
||||
}
|
||||
|
||||
OBSDataArrayAutoRelease array = obs_data_get_array(result.data, "data");
|
||||
size_t count = obs_data_array_count(array);
|
||||
if (count == 0) {
|
||||
blog(LOG_WARNING, "%s did not return any data!", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
OBSDataAutoRelease data = obs_data_array_item(array, 0);
|
||||
|
||||
SetJsonTempVars(data, [this](const char *id, const char *value) {
|
||||
SetTempVarValue(id, value);
|
||||
});
|
||||
|
||||
OBSDataAutoRelease image = obs_data_get_obj(data, "image");
|
||||
SetTempVarValue("image.url_4x", obs_data_get_string(image, "url_4x"));
|
||||
|
||||
OBSDataAutoRelease default_image =
|
||||
obs_data_get_obj(data, "default_image");
|
||||
SetTempVarValue("default_image.url_4x",
|
||||
obs_data_get_string(default_image, "url_4x"));
|
||||
|
||||
OBSDataAutoRelease max_per_stream_setting =
|
||||
obs_data_get_obj(data, "max_per_stream_setting");
|
||||
SetTempVarValue("max_per_stream.is_enabled",
|
||||
obs_data_get_bool(max_per_stream_setting,
|
||||
"is_enabled"));
|
||||
SetTempVarValue("max_per_stream.max_per_stream",
|
||||
std::to_string(obs_data_get_int(max_per_stream_setting,
|
||||
"max_per_stream")));
|
||||
|
||||
OBSDataAutoRelease max_per_user_per_stream_setting =
|
||||
obs_data_get_obj(data, "max_per_user_per_stream_setting");
|
||||
SetTempVarValue("max_per_user_per_stream.is_enabled",
|
||||
obs_data_get_bool(max_per_user_per_stream_setting,
|
||||
"is_enabled"));
|
||||
SetTempVarValue(
|
||||
"max_per_user_per_stream.max_per_user_per_stream",
|
||||
std::to_string(obs_data_get_int(max_per_user_per_stream_setting,
|
||||
"max_per_user_per_stream")));
|
||||
|
||||
OBSDataAutoRelease global_cooldown_setting =
|
||||
obs_data_get_obj(data, "global_cooldown_setting");
|
||||
SetTempVarValue("global_cooldown.is_enabled",
|
||||
obs_data_get_bool(global_cooldown_setting,
|
||||
"is_enabled"));
|
||||
SetTempVarValue(
|
||||
"max_per_user_per_stream.global_cooldown_seconds",
|
||||
std::to_string(obs_data_get_int(max_per_user_per_stream_setting,
|
||||
"global_cooldown_seconds")));
|
||||
}
|
||||
|
||||
static std::string tryTranslate(const std::string &testString)
|
||||
{
|
||||
auto translated = obs_module_text(testString.c_str());
|
||||
if (testString != translated) {
|
||||
return translated;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void MacroActionTwitch::SetupTempVars()
|
||||
{
|
||||
MacroAction::SetupTempVars();
|
||||
if (_action != Action::USER_GET_INFO) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddTempvar(
|
||||
"id",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.id.user.getInfo"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.id.user.getInfo.description"));
|
||||
AddTempvar(
|
||||
"login",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.login.user.getInfo"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.login.user.getInfo.description"));
|
||||
AddTempvar(
|
||||
"display_name",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.display_name.user.getInfo"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.display_name.user.getInfo.description"));
|
||||
AddTempvar(
|
||||
"type",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.type.user.getInfo"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.type.user.getInfo.description"));
|
||||
AddTempvar(
|
||||
"broadcaster_type",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.broadcaster_type.user.getInfo"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.broadcaster_type.user.getInfo.description"));
|
||||
AddTempvar(
|
||||
"description",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.description.user.getInfo"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.description.user.getInfo.description"));
|
||||
AddTempvar(
|
||||
"profile_image_url",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.profile_image_url.user.getInfo"));
|
||||
AddTempvar(
|
||||
"offline_image_url",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.offline_image_url.user.getInfo"));
|
||||
AddTempvar(
|
||||
"created_at",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.created_at.user.getInfo"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.twitch.created_at.user.getInfo.description"));
|
||||
auto setupTempVarHelper = [&](const std::string &id,
|
||||
const std::string &extra = "") {
|
||||
std::string name = tryTranslate(
|
||||
"AdvSceneSwitcher.tempVar.twitch." + id + extra);
|
||||
std::string description =
|
||||
tryTranslate("AdvSceneSwitcher.tempVar.twitch." + id +
|
||||
extra + ".description");
|
||||
AddTempvar(id, name.empty() ? id : name, description);
|
||||
};
|
||||
|
||||
switch (_action) {
|
||||
case Action::POINTS_REWARD_GET_INFO:
|
||||
setupTempVarHelper("title", ".reward");
|
||||
setupTempVarHelper("prompt", ".reward");
|
||||
setupTempVarHelper("cost", ".reward");
|
||||
setupTempVarHelper("background_color", ".reward");
|
||||
setupTempVarHelper("is_enabled", ".reward");
|
||||
setupTempVarHelper("is_user_input_required", ".reward");
|
||||
setupTempVarHelper("is_paused", ".reward");
|
||||
setupTempVarHelper("is_in_stock", ".reward");
|
||||
setupTempVarHelper("should_redemptions_skip_request_queue",
|
||||
".reward");
|
||||
setupTempVarHelper("redemptions_redeemed_current_stream",
|
||||
".reward");
|
||||
setupTempVarHelper("cooldown_expires_at", ".reward");
|
||||
setupTempVarHelper("max_per_stream.is_enabled", ".reward");
|
||||
setupTempVarHelper("max_per_stream.max_per_stream", ".reward");
|
||||
setupTempVarHelper("max_per_user_per_stream.is_enabled",
|
||||
".reward");
|
||||
setupTempVarHelper(
|
||||
"max_per_user_per_stream.max_per_user_per_stream",
|
||||
".reward");
|
||||
setupTempVarHelper("global_cooldown.is_enabled", ".reward");
|
||||
setupTempVarHelper("global_cooldown.global_cooldown_seconds",
|
||||
".reward");
|
||||
setupTempVarHelper("image.url_4x", ".reward");
|
||||
setupTempVarHelper("default_image.url_4x", ".reward");
|
||||
break;
|
||||
case Action::USER_GET_INFO:
|
||||
setupTempVarHelper("id", ".user.getInfo");
|
||||
setupTempVarHelper("login", ".user.getInfo");
|
||||
setupTempVarHelper("display_name", ".user.getInfo");
|
||||
setupTempVarHelper("type", ".user.getInfo");
|
||||
setupTempVarHelper("broadcaster_type", ".user.getInfo");
|
||||
setupTempVarHelper("description", ".user.getInfo");
|
||||
setupTempVarHelper("profile_image_url", ".user.getInfo");
|
||||
setupTempVarHelper("offline_image_url", ".user.getInfo");
|
||||
setupTempVarHelper("created_at", ".user.getInfo");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool MacroActionTwitch::PerformAction()
|
||||
@@ -414,6 +543,9 @@ bool MacroActionTwitch::PerformAction()
|
||||
case MacroActionTwitch::Action::USER_GET_INFO:
|
||||
GetUserInfo(token);
|
||||
break;
|
||||
case MacroActionTwitch::Action::POINTS_REWARD_GET_INFO:
|
||||
GetRewardInfo(token);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -455,6 +587,11 @@ bool MacroActionTwitch::Save(obs_data_t *obj) const
|
||||
static_cast<int>(_userInfoQueryType));
|
||||
_userLogin.Save(obj, "userLogin");
|
||||
_userId.Save(obj, "userId");
|
||||
_pointsReward.Save(obj);
|
||||
obs_data_set_string(obj, "rewardVariable",
|
||||
GetWeakVariableName(_rewardVariable).c_str());
|
||||
obs_data_set_bool(obj, "useVariableForRewardSelection",
|
||||
_useVariableForRewardSelection);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -478,6 +615,12 @@ bool MacroActionTwitch::Load(obs_data_t *obj)
|
||||
obs_data_get_int(obj, "userInfoQueryType"));
|
||||
_userLogin.Load(obj, "userLogin");
|
||||
_userId.Load(obj, "userId");
|
||||
_pointsReward.Load(obj);
|
||||
_rewardVariable = GetWeakVariableByName(
|
||||
obs_data_get_string(obj, "rewardVariable"));
|
||||
_useVariableForRewardSelection =
|
||||
obs_data_get_bool(obj, "useVariableForRewardSelection");
|
||||
|
||||
SetAction(static_cast<Action>(obs_data_get_int(obj, "action")));
|
||||
|
||||
return true;
|
||||
@@ -602,7 +745,9 @@ bool MacroActionTwitch::ActionIsSupportedByToken()
|
||||
{Action::WHISPER_SEND, {{"user:manage:whispers"}}},
|
||||
{Action::SEND_CHAT_MESSAGE, {{"chat:edit"}}},
|
||||
{Action::USER_GET_INFO, {}},
|
||||
};
|
||||
{Action::POINTS_REWARD_GET_INFO,
|
||||
{{"channel:read:redemptions"},
|
||||
{"channel:manage:redemptions"}}}};
|
||||
|
||||
auto token = _token.lock();
|
||||
if (!token) {
|
||||
@@ -679,7 +824,10 @@ MacroActionTwitchEdit::MacroActionTwitchEdit(
|
||||
_chatMessage(new VariableTextEdit(this)),
|
||||
_userInfoQueryType(new QComboBox(this)),
|
||||
_userLogin(new VariableLineEdit(this)),
|
||||
_userId(new VariableSpinBox(this))
|
||||
_userId(new VariableSpinBox(this)),
|
||||
_pointsReward(new TwitchPointsRewardWidget(this)),
|
||||
_rewardVariable(new VariableSelection(this)),
|
||||
_toggleRewardSelection(new QPushButton())
|
||||
{
|
||||
SetWidgetProperties();
|
||||
SetWidgetSignalConnections();
|
||||
@@ -726,6 +874,7 @@ void MacroActionTwitchEdit::TwitchTokenChanged(const QString &token)
|
||||
_entryData->_token = GetWeakTwitchTokenByQString(token);
|
||||
_category->SetToken(_entryData->_token);
|
||||
_channel->SetToken(_entryData->_token);
|
||||
_pointsReward->SetToken(_entryData->_token);
|
||||
_entryData->ResetChatConnection();
|
||||
|
||||
SetWidgetVisibility();
|
||||
@@ -835,6 +984,15 @@ void MacroActionTwitchEdit::SetWidgetProperties()
|
||||
populateUserQueryInfoTypeSelection(_userInfoQueryType);
|
||||
|
||||
_userId->setMaximum(999999999);
|
||||
|
||||
_toggleRewardSelection->setCheckable(true);
|
||||
_toggleRewardSelection->setMaximumWidth(11);
|
||||
SetButtonIcon(_toggleRewardSelection,
|
||||
GetThemeTypeName() == "Light"
|
||||
? ":/res/images/dots-vert.svg"
|
||||
: "theme:Dark/dots-vert.svg");
|
||||
_toggleRewardSelection->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.action.twitch.reward.toggleControl"));
|
||||
}
|
||||
|
||||
void MacroActionTwitchEdit::SetWidgetSignalConnections()
|
||||
@@ -873,6 +1031,15 @@ void MacroActionTwitchEdit::SetWidgetSignalConnections()
|
||||
_userId,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(UserIdChanged(const NumberVariable<int> &)));
|
||||
QWidget::connect(
|
||||
_pointsReward,
|
||||
SIGNAL(PointsRewardChanged(const TwitchPointsReward &)), this,
|
||||
SLOT(PointsRewardChanged(const TwitchPointsReward &)));
|
||||
QWidget::connect(_rewardVariable,
|
||||
SIGNAL(SelectionChanged(const QString &)), this,
|
||||
SLOT(RewardVariableChanged(const QString &)));
|
||||
QWidget::connect(_toggleRewardSelection, SIGNAL(toggled(bool)), this,
|
||||
SLOT(ToggleRewardSelection(bool)));
|
||||
}
|
||||
|
||||
void MacroActionTwitchEdit::SetWidgetVisibility()
|
||||
@@ -889,7 +1056,9 @@ void MacroActionTwitchEdit::SetWidgetVisibility()
|
||||
_entryData->GetAction() ==
|
||||
MacroActionTwitch::Action::RAID_END ||
|
||||
_entryData->GetAction() ==
|
||||
MacroActionTwitch::Action::SEND_CHAT_MESSAGE);
|
||||
MacroActionTwitch::Action::SEND_CHAT_MESSAGE ||
|
||||
_entryData->GetAction() ==
|
||||
MacroActionTwitch::Action::POINTS_REWARD_GET_INFO);
|
||||
_duration->setVisible(_entryData->GetAction() ==
|
||||
MacroActionTwitch::Action::COMMERCIAL_START);
|
||||
_markerDescription->setVisible(
|
||||
@@ -917,6 +1086,17 @@ void MacroActionTwitchEdit::SetWidgetVisibility()
|
||||
MacroActionTwitch::Action::USER_GET_INFO &&
|
||||
_entryData->_userInfoQueryType ==
|
||||
MacroActionTwitch::UserInfoQueryType::ID);
|
||||
_pointsReward->setVisible(
|
||||
_entryData->GetAction() ==
|
||||
MacroActionTwitch::Action::POINTS_REWARD_GET_INFO &&
|
||||
!_entryData->_useVariableForRewardSelection);
|
||||
_rewardVariable->setVisible(
|
||||
_entryData->GetAction() ==
|
||||
MacroActionTwitch::Action::POINTS_REWARD_GET_INFO &&
|
||||
_entryData->_useVariableForRewardSelection);
|
||||
_toggleRewardSelection->setVisible(
|
||||
_entryData->GetAction() ==
|
||||
MacroActionTwitch::Action::POINTS_REWARD_GET_INFO);
|
||||
|
||||
if (_entryData->GetAction() ==
|
||||
MacroActionTwitch::Action::CHANNEL_INFO_TITLE_SET ||
|
||||
@@ -937,6 +1117,7 @@ void MacroActionTwitchEdit::ChannelChanged(const TwitchChannel &channel)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_channel = channel;
|
||||
_pointsReward->SetChannel(channel);
|
||||
_entryData->ResetChatConnection();
|
||||
}
|
||||
|
||||
@@ -964,12 +1145,32 @@ void MacroActionTwitchEdit::UserLoginChanged()
|
||||
_entryData->_userLogin = _userLogin->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionTwitchEdit::RewardVariableChanged(const QString &text)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK()
|
||||
_entryData->_rewardVariable = GetWeakVariableByQString(text);
|
||||
}
|
||||
|
||||
void MacroActionTwitchEdit::ToggleRewardSelection(bool)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_useVariableForRewardSelection =
|
||||
!_entryData->_useVariableForRewardSelection;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionTwitchEdit::UserIdChanged(const NumberVariable<int> &value)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_userId = value;
|
||||
}
|
||||
|
||||
void MacroActionTwitchEdit::PointsRewardChanged(const TwitchPointsReward &reward)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_pointsReward = reward;
|
||||
}
|
||||
|
||||
void MacroActionTwitchEdit::SetWidgetLayout()
|
||||
{
|
||||
const std::vector<QWidget *> widgets{_tokens,
|
||||
@@ -983,7 +1184,10 @@ void MacroActionTwitchEdit::SetWidgetLayout()
|
||||
_channel,
|
||||
_userInfoQueryType,
|
||||
_userLogin,
|
||||
_userId};
|
||||
_userId,
|
||||
_pointsReward,
|
||||
_rewardVariable,
|
||||
_toggleRewardSelection};
|
||||
for (auto widget : widgets) {
|
||||
_layout->removeWidget(widget);
|
||||
}
|
||||
@@ -999,6 +1203,10 @@ void MacroActionTwitchEdit::SetWidgetLayout()
|
||||
layoutText = obs_module_text(
|
||||
"AdvSceneSwitcher.action.twitch.entry.user.getInfo");
|
||||
break;
|
||||
case MacroActionTwitch::Action::POINTS_REWARD_GET_INFO:
|
||||
layoutText = obs_module_text(
|
||||
"AdvSceneSwitcher.action.twitch.entry.reward.getInfo");
|
||||
break;
|
||||
default:
|
||||
layoutText = obs_module_text(
|
||||
"AdvSceneSwitcher.action.twitch.entry.default");
|
||||
@@ -1017,7 +1225,10 @@ void MacroActionTwitchEdit::SetWidgetLayout()
|
||||
{"{{channel}}", _channel},
|
||||
{"{{userInfoQueryType}}", _userInfoQueryType},
|
||||
{"{{userLogin}}", _userLogin},
|
||||
{"{{userId}}", _userId}});
|
||||
{"{{userId}}", _userId},
|
||||
{"{{pointsReward}}", _pointsReward},
|
||||
{"{{rewardVariable}}", _rewardVariable},
|
||||
{"{{toggleRewardSelection}}", _toggleRewardSelection}});
|
||||
|
||||
_layout->setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
@@ -1047,6 +1258,10 @@ void MacroActionTwitchEdit::UpdateEntryData()
|
||||
static_cast<int>(_entryData->_userInfoQueryType)));
|
||||
_userLogin->setText(_entryData->_userLogin);
|
||||
_userId->SetValue(_entryData->_userId);
|
||||
_pointsReward->SetToken(_entryData->_token);
|
||||
_pointsReward->SetChannel(_entryData->_channel);
|
||||
_pointsReward->SetPointsReward(_entryData->_pointsReward);
|
||||
_rewardVariable->SetVariable(_entryData->_rewardVariable);
|
||||
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -54,6 +54,9 @@ public:
|
||||
// Reward add
|
||||
POINTS_REWARD_ADD = 600, // TODO
|
||||
|
||||
// Get reward information
|
||||
POINTS_REWARD_GET_INFO = 650,
|
||||
|
||||
// Reward update
|
||||
POINTS_REWARD_ENABLE = 710,
|
||||
POINTS_REWARD_DISABLE = 711,
|
||||
@@ -177,6 +180,9 @@ public:
|
||||
UserInfoQueryType _userInfoQueryType = UserInfoQueryType::LOGIN;
|
||||
StringVariable _userLogin = "user login";
|
||||
IntVariable _userId = 0;
|
||||
TwitchPointsReward _pointsReward;
|
||||
std::weak_ptr<Variable> _rewardVariable;
|
||||
bool _useVariableForRewardSelection = false;
|
||||
|
||||
private:
|
||||
void SetStreamTitle(const std::shared_ptr<TwitchToken> &) const;
|
||||
@@ -190,12 +196,19 @@ private:
|
||||
void StartRaid(const std::shared_ptr<TwitchToken> &);
|
||||
void SendChatMessage(const std::shared_ptr<TwitchToken> &);
|
||||
void GetUserInfo(const std::shared_ptr<TwitchToken> &);
|
||||
void GetRewardInfo(const std::shared_ptr<TwitchToken> &);
|
||||
|
||||
bool ResolveVariableSelectionToRewardId(
|
||||
const std::shared_ptr<TwitchToken> &);
|
||||
|
||||
void SetupTempVars();
|
||||
|
||||
Action _action = Action::CHANNEL_INFO_TITLE_SET;
|
||||
std::shared_ptr<TwitchChatConnection> _chatConnection;
|
||||
|
||||
std::string _lastResolvedRewardTitle;
|
||||
std::string _lastResolvedRewardId;
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
@@ -232,6 +245,9 @@ private slots:
|
||||
void UserInfoQueryTypeChanged(int);
|
||||
void UserLoginChanged();
|
||||
void UserIdChanged(const NumberVariable<int> &);
|
||||
void PointsRewardChanged(const TwitchPointsReward &);
|
||||
void RewardVariableChanged(const QString &);
|
||||
void ToggleRewardSelection(bool);
|
||||
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
@@ -263,6 +279,9 @@ private:
|
||||
QComboBox *_userInfoQueryType;
|
||||
VariableLineEdit *_userLogin;
|
||||
VariableSpinBox *_userId;
|
||||
TwitchPointsRewardWidget *_pointsReward;
|
||||
VariableSelection *_rewardVariable;
|
||||
QPushButton *_toggleRewardSelection;
|
||||
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
@@ -88,7 +88,7 @@ void TwitchPointsRewardSelection::PopulateSelection()
|
||||
const QSignalBlocker b(this);
|
||||
clear();
|
||||
|
||||
auto pointsRewards = GetPointsRewards(token, *_channel);
|
||||
auto pointsRewards = GetPointsRewardsForChannel(token, *_channel);
|
||||
if (!pointsRewards) {
|
||||
DisplayErrorMessage(obs_module_text(
|
||||
"AdvSceneSwitcher.twitch.selection.points.reward.tooltip.error"));
|
||||
@@ -127,47 +127,6 @@ void TwitchPointsRewardSelection::HideErrorMessage()
|
||||
setToolTip("");
|
||||
}
|
||||
|
||||
std::optional<std::vector<TwitchPointsReward>>
|
||||
TwitchPointsRewardSelection::GetPointsRewards(
|
||||
const std::shared_ptr<TwitchToken> &token, const TwitchChannel &channel)
|
||||
{
|
||||
httplib::Params params = {
|
||||
{"broadcaster_id", channel.GetUserID(*token)}};
|
||||
|
||||
auto response = SendGetRequest(*token, "https://api.twitch.tv",
|
||||
"/helix/channel_points/custom_rewards",
|
||||
params, true);
|
||||
|
||||
if (response.status != 200) {
|
||||
blog(LOG_WARNING,
|
||||
"Failed to fetch points rewards for user %s and channel %s! (%d)",
|
||||
token->GetName().c_str(), channel.GetName().c_str(),
|
||||
response.status);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return ParseResponse(response.data);
|
||||
}
|
||||
|
||||
std::vector<TwitchPointsReward>
|
||||
TwitchPointsRewardSelection::ParseResponse(obs_data_t *response)
|
||||
{
|
||||
std::vector<TwitchPointsReward> pointRewards;
|
||||
OBSDataArrayAutoRelease jsonArray =
|
||||
obs_data_get_array(response, "data");
|
||||
size_t count = obs_data_array_count(jsonArray);
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
OBSDataAutoRelease jsonObj = obs_data_array_item(jsonArray, i);
|
||||
std::string id = obs_data_get_string(jsonObj, "id");
|
||||
std::string title = obs_data_get_string(jsonObj, "title");
|
||||
pointRewards.push_back({id, title});
|
||||
}
|
||||
|
||||
return pointRewards;
|
||||
}
|
||||
|
||||
void TwitchPointsRewardSelection::SelectionChanged(int index)
|
||||
{
|
||||
TwitchPointsReward pointsReward{
|
||||
@@ -218,4 +177,44 @@ void TwitchPointsRewardWidget::SetToken(const std::weak_ptr<TwitchToken> &token)
|
||||
_selection->SetToken(token);
|
||||
}
|
||||
|
||||
static std::vector<TwitchPointsReward> parseApiResponse(obs_data_t *response)
|
||||
{
|
||||
std::vector<TwitchPointsReward> pointRewards;
|
||||
OBSDataArrayAutoRelease jsonArray =
|
||||
obs_data_get_array(response, "data");
|
||||
size_t count = obs_data_array_count(jsonArray);
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
OBSDataAutoRelease jsonObj = obs_data_array_item(jsonArray, i);
|
||||
std::string id = obs_data_get_string(jsonObj, "id");
|
||||
std::string title = obs_data_get_string(jsonObj, "title");
|
||||
pointRewards.push_back({id, title});
|
||||
}
|
||||
|
||||
return pointRewards;
|
||||
}
|
||||
|
||||
std::optional<std::vector<TwitchPointsReward>>
|
||||
GetPointsRewardsForChannel(const std::shared_ptr<TwitchToken> &token,
|
||||
const TwitchChannel &channel)
|
||||
{
|
||||
httplib::Params params = {
|
||||
{"broadcaster_id", channel.GetUserID(*token)}};
|
||||
|
||||
auto response = SendGetRequest(*token, "https://api.twitch.tv",
|
||||
"/helix/channel_points/custom_rewards",
|
||||
params, true);
|
||||
|
||||
if (response.status != 200) {
|
||||
blog(LOG_WARNING,
|
||||
"Failed to fetch points rewards for user %s and channel %s! (%d)",
|
||||
token->GetName().c_str(), channel.GetName().c_str(),
|
||||
response.status);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return parseApiResponse(response.data);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -35,10 +35,6 @@ protected:
|
||||
|
||||
private:
|
||||
void AddPredefinedItems();
|
||||
std::optional<std::vector<TwitchPointsReward>>
|
||||
GetPointsRewards(const std::shared_ptr<TwitchToken> &token,
|
||||
const TwitchChannel &channel);
|
||||
std::vector<TwitchPointsReward> ParseResponse(obs_data_t *response);
|
||||
|
||||
bool _allowAny;
|
||||
const std::vector<TokenOption> _supportedTokenOptions = {
|
||||
@@ -71,4 +67,8 @@ protected:
|
||||
QPushButton *_refreshButton;
|
||||
};
|
||||
|
||||
std::optional<std::vector<TwitchPointsReward>>
|
||||
GetPointsRewardsForChannel(const std::shared_ptr<TwitchToken> &token,
|
||||
const TwitchChannel &channel);
|
||||
|
||||
} // namespace advss
|
||||
|
||||
Reference in New Issue
Block a user