Migrate /commercial command to the Helix API

This commit is contained in:
Rasmus Karlsson 2022-09-18 12:15:45 +02:00
parent 4f1976b1be
commit 366ba2b2d4
3 changed files with 170 additions and 0 deletions

View file

@ -1269,6 +1269,73 @@ void CommandController::initialize(Settings &, Paths &paths)
return ""; return "";
}); });
this->registerCommand(
"/commercial", [](const QStringList &words, auto channel) {
auto user = getApp()->accounts->twitch.getCurrent();
// Avoid Helix calls without Client ID and/or OAuth Token
if (user->isAnon())
{
channel->addMessage(makeSystemMessage(
"You must be logged in to use the /commercial command"));
return "";
}
auto *tc = dynamic_cast<TwitchChannel *>(channel.get());
if (tc == nullptr)
{
return "";
}
auto broadcasterID = tc->roomId();
auto length = 30; // TODO: Parse from words
using Error = HelixStartCommercialError;
getHelix()->startCommercial(
broadcasterID, length,
[channel](auto response) {
qDebug() << "commercial success";
},
[channel](auto error, auto message) {
MessageBuilder messageBuilder(
systemMessage, "Failed to start commercial - ");
messageBuilder
.emplace<TextElement>(QString("test xD"),
MessageElementFlag::Text)
->setLink({Link::Url, "https://pajlada.se"});
switch (error)
{
case Error::Forwarded: {
messageBuilder.emplace<TextElement>(
message, MessageElementFlag::Text);
}
break;
case Error::TokenMustMatchBroadcaster: {
messageBuilder.emplace<TextElement>(
message, MessageElementFlag::Text);
}
break;
case Error::Unknown:
default: {
messageBuilder.emplace<TextElement>(
QString("An unknown error has occurred (%1).")
.arg(message),
MessageElementFlag::Text);
}
break;
}
channel->addMessage(messageBuilder.release());
});
return "";
});
} }
void CommandController::save() void CommandController::save()

View file

@ -843,6 +843,69 @@ void Helix::updateUserChatColor(
.execute(); .execute();
}; };
void Helix::startCommercial(
QString broadcasterID, int length,
ResultCallback<HelixStartCommercialResponse> successCallback,
FailureCallback<HelixStartCommercialError, QString> failureCallback)
{
using Error = HelixStartCommercialError;
QJsonObject payload;
payload.insert("broadcaster_id", QJsonValue(broadcasterID));
payload.insert("length", QJsonValue(length));
this->makeRequest("channels/commercial", QUrlQuery())
.type(NetworkRequestType::Post)
.header("Content-Type", "application/json")
.payload(QJsonDocument(payload).toJson(QJsonDocument::Compact))
.onSuccess([successCallback, failureCallback](auto result) -> Outcome {
auto obj = result.parseJson();
if (obj.isEmpty())
{
failureCallback(Error::Unknown, "no json object");
return Failure;
}
qDebug() << "Success obj:" << obj;
successCallback(HelixStartCommercialResponse(obj));
return Success;
})
.onError([failureCallback](auto result) {
auto obj = result.parseJson();
auto message = obj.value("message").toString();
qDebug() << "failure obj: " << obj << "nmessage: " << message;
switch (result.status())
{
case 401: {
if (message.contains(
"The ID in broadcaster_id must match the user ID "
"found in the request's OAuth token.",
Qt::CaseInsensitive))
{
failureCallback(Error::TokenMustMatchBroadcaster,
message);
}
else
{
failureCallback(Error::Forwarded, message);
}
}
break;
default: {
qCDebug(chatterinoTwitch)
<< "Unhandled error starting commercial:"
<< result.status() << result.getData() << obj;
failureCallback(Error::Unknown, message);
}
break;
}
})
.execute();
}
NetworkRequest Helix::makeRequest(QString url, QUrlQuery urlQuery) NetworkRequest Helix::makeRequest(QString url, QUrlQuery urlQuery)
{ {
assert(!url.startsWith("/")); assert(!url.startsWith("/"));

View file

@ -329,6 +329,32 @@ enum class HelixUpdateUserChatColorError {
Forwarded, Forwarded,
}; };
struct HelixStartCommercialResponse {
// Length of the triggered commercial
int length;
// Provides contextual information on why the request failed
QString message;
// Seconds until the next commercial can be served on this channel
int retryAfter;
explicit HelixStartCommercialResponse(QJsonObject jsonObject)
{
auto jsonData = jsonObject.value("data").toArray().at(0).toObject();
this->length = jsonData.value("length").toInt();
this->message = jsonData.value("message").toString();
this->retryAfter = jsonData.value("retry_after").toInt();
}
};
enum class HelixStartCommercialError {
Unknown,
TokenMustMatchBroadcaster,
UserMissingScope,
// The error message is forwarded directly from the Twitch API
Forwarded,
};
class IHelix class IHelix
{ {
public: public:
@ -458,6 +484,13 @@ public:
FailureCallback<HelixUpdateUserChatColorError, QString> FailureCallback<HelixUpdateUserChatColorError, QString>
failureCallback) = 0; failureCallback) = 0;
// https://dev.twitch.tv/docs/api/reference#start-commercial
virtual void startCommercial(
QString broadcasterID, int length,
ResultCallback<HelixStartCommercialResponse> successCallback,
FailureCallback<HelixStartCommercialError, QString>
failureCallback) = 0;
virtual void update(QString clientId, QString oauthToken) = 0; virtual void update(QString clientId, QString oauthToken) = 0;
}; };
@ -580,6 +613,13 @@ public:
FailureCallback<HelixUpdateUserChatColorError, QString> failureCallback) FailureCallback<HelixUpdateUserChatColorError, QString> failureCallback)
final; final;
// https://dev.twitch.tv/docs/api/reference#start-commercial
void startCommercial(
QString broadcasterID, int length,
ResultCallback<HelixStartCommercialResponse> successCallback,
FailureCallback<HelixStartCommercialError, QString> failureCallback)
final;
void update(QString clientId, QString oauthToken) final; void update(QString clientId, QString oauthToken) final;
static void initialize(); static void initialize();