mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-04-13 21:26:42 -05:00
Add helper classes to handle Twitch channel point rewards
This commit is contained in:
parent
53a0b76e8c
commit
626606100f
|
|
@ -48,6 +48,8 @@ target_sources(
|
|||
macro-action-twitch.hpp
|
||||
macro-condition-twitch.cpp
|
||||
macro-condition-twitch.hpp
|
||||
points-reward-selection.cpp
|
||||
points-reward-selection.hpp
|
||||
token.cpp
|
||||
token.hpp
|
||||
twitch-helpers.cpp
|
||||
|
|
|
|||
219
src/macro-external/twitch/points-reward-selection.cpp
Normal file
219
src/macro-external/twitch/points-reward-selection.cpp
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
#include "points-reward-selection.hpp"
|
||||
#include "twitch-helpers.hpp"
|
||||
|
||||
#include <obs-module.h>
|
||||
#include <utility.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
void TwitchPointsReward::Load(obs_data_t *obj)
|
||||
{
|
||||
OBSDataAutoRelease data = obs_data_get_obj(obj, "pointsReward");
|
||||
id = obs_data_get_string(data, "id");
|
||||
title = obs_data_get_string(data, "title");
|
||||
}
|
||||
|
||||
void TwitchPointsReward::Save(obs_data_t *obj) const
|
||||
{
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
obs_data_set_string(data, "id", id.c_str());
|
||||
obs_data_set_string(data, "title", title.c_str());
|
||||
obs_data_set_obj(obj, "pointsReward", data);
|
||||
}
|
||||
|
||||
TwitchPointsRewardSelection::TwitchPointsRewardSelection(QWidget *parent,
|
||||
bool allowAny)
|
||||
: FilterComboBox(
|
||||
parent,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.twitch.selection.points.reward.placeholder")),
|
||||
_allowAny(allowAny)
|
||||
{
|
||||
setDuplicatesEnabled(true);
|
||||
setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
|
||||
QWidget::connect(this, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(SelectionChanged(int)));
|
||||
}
|
||||
|
||||
void TwitchPointsRewardSelection::SetPointsReward(
|
||||
const TwitchPointsReward &pointsReward)
|
||||
{
|
||||
int index = findData(QString::fromStdString(pointsReward.id));
|
||||
if (index != -1) {
|
||||
setCurrentIndex(index);
|
||||
return;
|
||||
}
|
||||
|
||||
setCurrentIndex(-1);
|
||||
}
|
||||
|
||||
void TwitchPointsRewardSelection::SetChannel(const TwitchChannel &channel)
|
||||
{
|
||||
_channel = channel;
|
||||
PopulateSelection();
|
||||
}
|
||||
|
||||
void TwitchPointsRewardSelection::SetToken(
|
||||
const std::weak_ptr<TwitchToken> &token)
|
||||
{
|
||||
_token = token;
|
||||
|
||||
if (token.expired()) {
|
||||
DisplayErrorMessage(obs_module_text(
|
||||
"AdvSceneSwitcher.twitch.selection.points.reward.tooltip.noAccount"));
|
||||
return;
|
||||
}
|
||||
|
||||
PopulateSelection();
|
||||
}
|
||||
|
||||
void TwitchPointsRewardSelection::PopulateSelection()
|
||||
{
|
||||
auto token = _token.lock();
|
||||
|
||||
if (!token || !token->AnyOptionIsEnabled(SUPPORTED_TOKEN_OPTIONS)) {
|
||||
DisplayErrorMessage(obs_module_text(
|
||||
"AdvSceneSwitcher.twitch.selection.points.reward.tooltip.noPermission"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_channel || (*_channel).GetName().empty()) {
|
||||
DisplayErrorMessage(obs_module_text(
|
||||
"AdvSceneSwitcher.twitch.selection.points.reward.tooltip.noChannel"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto currentSelection = currentText();
|
||||
const QSignalBlocker b(this);
|
||||
clear();
|
||||
|
||||
auto pointsRewards = GetPointsRewards(token, *_channel);
|
||||
if (!pointsRewards) {
|
||||
DisplayErrorMessage(obs_module_text(
|
||||
"AdvSceneSwitcher.twitch.selection.points.reward.tooltip.error"));
|
||||
return;
|
||||
}
|
||||
|
||||
HideErrorMessage();
|
||||
AddPredefinedItems();
|
||||
|
||||
for (const auto &pointsReward : *pointsRewards) {
|
||||
addItem(QString::fromStdString(pointsReward.title),
|
||||
QString::fromStdString(pointsReward.id));
|
||||
}
|
||||
|
||||
setCurrentText(currentSelection);
|
||||
}
|
||||
|
||||
void TwitchPointsRewardSelection::AddPredefinedItems()
|
||||
{
|
||||
if (_allowAny) {
|
||||
addItem(obs_module_text(
|
||||
"AdvSceneSwitcher.twitch.selection.points.reward.option.any"),
|
||||
"-");
|
||||
}
|
||||
}
|
||||
|
||||
void TwitchPointsRewardSelection::DisplayErrorMessage(const char *errorMessage)
|
||||
{
|
||||
setDisabled(true);
|
||||
setToolTip(errorMessage);
|
||||
}
|
||||
|
||||
void TwitchPointsRewardSelection::HideErrorMessage()
|
||||
{
|
||||
setDisabled(false);
|
||||
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("https://api.twitch.tv",
|
||||
"/helix/channel_points/custom_rewards",
|
||||
*token, params);
|
||||
|
||||
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{
|
||||
itemData(index).toString().toStdString(),
|
||||
currentText().toStdString()};
|
||||
emit PointsRewardChanged(pointsReward);
|
||||
}
|
||||
|
||||
TwitchPointsRewardWidget::TwitchPointsRewardWidget(QWidget *parent)
|
||||
: QWidget(parent),
|
||||
_selection(new TwitchPointsRewardSelection(this)),
|
||||
_refreshButton(new QPushButton(this))
|
||||
{
|
||||
_refreshButton->setMaximumWidth(22);
|
||||
SetButtonIcon(_refreshButton, ":res/images/refresh.svg");
|
||||
_refreshButton->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.twitch.selection.points.reward.refresh"));
|
||||
|
||||
auto layout = new QHBoxLayout();
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(_selection);
|
||||
layout->addWidget(_refreshButton);
|
||||
setLayout(layout);
|
||||
|
||||
QWidget::connect(
|
||||
_selection,
|
||||
SIGNAL(PointsRewardChanged(const TwitchPointsReward &)), this,
|
||||
SIGNAL(PointsRewardChanged(const TwitchPointsReward &)));
|
||||
QWidget::connect(_refreshButton, SIGNAL(clicked()), _selection,
|
||||
SLOT(PopulateSelection()));
|
||||
}
|
||||
|
||||
void TwitchPointsRewardWidget::SetPointsReward(
|
||||
const TwitchPointsReward &pointsReward)
|
||||
{
|
||||
_selection->SetPointsReward(pointsReward);
|
||||
}
|
||||
|
||||
void TwitchPointsRewardWidget::SetChannel(const TwitchChannel &channel)
|
||||
{
|
||||
_selection->SetChannel(channel);
|
||||
}
|
||||
|
||||
void TwitchPointsRewardWidget::SetToken(const std::weak_ptr<TwitchToken> &token)
|
||||
{
|
||||
_selection->SetToken(token);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
74
src/macro-external/twitch/points-reward-selection.hpp
Normal file
74
src/macro-external/twitch/points-reward-selection.hpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#pragma once
|
||||
#include "channel-selection.hpp"
|
||||
#include "token.hpp"
|
||||
|
||||
#include <filter-combo-box.hpp>
|
||||
#include <obs-data.h>
|
||||
#include <string>
|
||||
|
||||
namespace advss {
|
||||
|
||||
struct TwitchPointsReward {
|
||||
void Load(obs_data_t *obj);
|
||||
void Save(obs_data_t *obj) const;
|
||||
|
||||
std::string id = "-";
|
||||
std::string title = "-";
|
||||
};
|
||||
|
||||
class TwitchPointsRewardSelection : public FilterComboBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TwitchPointsRewardSelection(QWidget *parent, bool allowAny = true);
|
||||
|
||||
void SetPointsReward(const TwitchPointsReward &pointsReward);
|
||||
void SetChannel(const TwitchChannel &channel);
|
||||
void SetToken(const std::weak_ptr<TwitchToken> &token);
|
||||
|
||||
protected:
|
||||
void DisplayErrorMessage(const char *errorMessage);
|
||||
void HideErrorMessage();
|
||||
|
||||
std::optional<TwitchChannel> _channel = {};
|
||||
std::weak_ptr<TwitchToken> _token;
|
||||
|
||||
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> SUPPORTED_TOKEN_OPTIONS = {
|
||||
{"channel:read:redemptions"},
|
||||
{"channel:manage:redemptions"}};
|
||||
|
||||
private slots:
|
||||
void PopulateSelection();
|
||||
void SelectionChanged(int);
|
||||
|
||||
signals:
|
||||
void PointsRewardChanged(const TwitchPointsReward &);
|
||||
};
|
||||
|
||||
class TwitchPointsRewardWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TwitchPointsRewardWidget(QWidget *parent);
|
||||
|
||||
void SetPointsReward(const TwitchPointsReward &pointsReward);
|
||||
void SetChannel(const TwitchChannel &channel);
|
||||
void SetToken(const std::weak_ptr<TwitchToken> &token);
|
||||
|
||||
signals:
|
||||
void PointsRewardChanged(const TwitchPointsReward &);
|
||||
|
||||
protected:
|
||||
TwitchPointsRewardSelection *_selection;
|
||||
QPushButton *_refreshButton;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
Loading…
Reference in New Issue
Block a user