feat: improve create clip error messaging (#5879)

This commit is contained in:
pajlada
2025-02-01 13:18:34 +01:00
committed by GitHub
parent 810d3cdfd6
commit f629eecaa7
5 changed files with 89 additions and 24 deletions
+1
View File
@@ -8,6 +8,7 @@
- Minor: Remove incognito browser support for `iexplore`, because internet explorer is EOL. (#5810) - Minor: Remove incognito browser support for `iexplore`, because internet explorer is EOL. (#5810)
- Minor: When (re-)connecting, visible channels are now joined first. (#5850) - Minor: When (re-)connecting, visible channels are now joined first. (#5850)
- Minor: Added the ability to filter on messages by the author's user ID (example: `author.user_id == "22484632"`). (#5862) - Minor: Added the ability to filter on messages by the author's user ID (example: `author.user_id == "22484632"`). (#5862)
- Minor: Improved error messaging of the `/clip` command. (#5879)
- Bugfix: Fixed a potential way to escape the Lua Plugin sandbox. (#5846) - Bugfix: Fixed a potential way to escape the Lua Plugin sandbox. (#5846)
- Bugfix: Fixed a crash relating to Lua HTTP. (#5800) - Bugfix: Fixed a crash relating to Lua HTTP. (#5800)
- Bugfix: Fixed a crash that could occur on Linux and macOS when clicking "Install" from the update prompt. (#5818) - Bugfix: Fixed a crash that could occur on Linux and macOS when clicking "Install" from the update prompt. (#5818)
+1 -1
View File
@@ -78,7 +78,7 @@ public:
MOCK_METHOD(void, createClip, MOCK_METHOD(void, createClip,
(QString channelId, ResultCallback<HelixClip> successCallback, (QString channelId, ResultCallback<HelixClip> successCallback,
std::function<void(HelixClipError)> failureCallback, std::function<void(HelixClipError, QString)> failureCallback,
std::function<void()> finallyCallback), std::function<void()> finallyCallback),
(override)); (override));
+39 -6
View File
@@ -67,13 +67,21 @@ namespace {
#endif #endif
constexpr int CLIP_CREATION_COOLDOWN = 5000; constexpr int CLIP_CREATION_COOLDOWN = 5000;
const QString CLIPS_LINK("https://clips.twitch.tv/%1"); const QString CLIPS_LINK("https://clips.twitch.tv/%1");
const QString CLIPS_FAILURE_CLIPS_UNAVAILABLE_TEXT(
"Failed to create a clip - clips are temporarily unavailable: %1");
const QString CLIPS_FAILURE_CLIPS_DISABLED_TEXT( const QString CLIPS_FAILURE_CLIPS_DISABLED_TEXT(
"Failed to create a clip - the streamer has clips disabled entirely or " "Failed to create a clip - the streamer has clips disabled in their "
"requires a certain subscriber or follower status to create clips."); "channel.");
const QString CLIPS_FAILURE_CLIPS_RESTRICTED_TEXT(
"Failed to create a clip - the streamer has restricted clip creation "
"to subscribers, or followers of an unknown duration.");
const QString CLIPS_FAILURE_CLIPS_RESTRICTED_CATEGORY_TEXT(
"Failed to create a clip - the streamer has disabled clips while in "
"this category.");
const QString CLIPS_FAILURE_NOT_AUTHENTICATED_TEXT( const QString CLIPS_FAILURE_NOT_AUTHENTICATED_TEXT(
"Failed to create a clip - you need to re-authenticate."); "Failed to create a clip - you need to re-authenticate.");
const QString CLIPS_FAILURE_UNKNOWN_ERROR_TEXT( const QString CLIPS_FAILURE_UNKNOWN_ERROR_TEXT(
"Failed to create a clip - an unknown error occurred."); "Failed to create a clip: %1");
const QString LOGIN_PROMPT_TEXT("Click here to add your account again."); const QString LOGIN_PROMPT_TEXT("Click here to add your account again.");
const Link ACCOUNTS_LINK(Link::OpenAccountsPage, QString()); const Link ACCOUNTS_LINK(Link::OpenAccountsPage, QString());
@@ -1771,7 +1779,7 @@ void TwitchChannel::createClip()
this->addMessage(builder.release(), MessageContext::Original); this->addMessage(builder.release(), MessageContext::Original);
}, },
// failureCallback // failureCallback
[this](auto error) { [this](auto error, auto errorMessage) {
MessageBuilder builder; MessageBuilder builder;
QString text; QString text;
builder.message().flags.set(MessageFlag::System); builder.message().flags.set(MessageFlag::System);
@@ -1780,6 +1788,15 @@ void TwitchChannel::createClip()
switch (error) switch (error)
{ {
case HelixClipError::ClipsUnavailable: {
builder.emplace<TextElement>(
CLIPS_FAILURE_CLIPS_UNAVAILABLE_TEXT.arg(errorMessage),
MessageElementFlag::Text, MessageColor::System);
text =
CLIPS_FAILURE_CLIPS_UNAVAILABLE_TEXT.arg(errorMessage);
}
break;
case HelixClipError::ClipsDisabled: { case HelixClipError::ClipsDisabled: {
builder.emplace<TextElement>( builder.emplace<TextElement>(
CLIPS_FAILURE_CLIPS_DISABLED_TEXT, CLIPS_FAILURE_CLIPS_DISABLED_TEXT,
@@ -1788,6 +1805,22 @@ void TwitchChannel::createClip()
} }
break; break;
case HelixClipError::ClipsRestricted: {
builder.emplace<TextElement>(
CLIPS_FAILURE_CLIPS_RESTRICTED_TEXT,
MessageElementFlag::Text, MessageColor::System);
text = CLIPS_FAILURE_CLIPS_RESTRICTED_TEXT;
}
break;
case HelixClipError::ClipsRestrictedCategory: {
builder.emplace<TextElement>(
CLIPS_FAILURE_CLIPS_RESTRICTED_CATEGORY_TEXT,
MessageElementFlag::Text, MessageColor::System);
text = CLIPS_FAILURE_CLIPS_RESTRICTED_CATEGORY_TEXT;
}
break;
case HelixClipError::UserNotAuthenticated: { case HelixClipError::UserNotAuthenticated: {
builder.emplace<TextElement>( builder.emplace<TextElement>(
CLIPS_FAILURE_NOT_AUTHENTICATED_TEXT, CLIPS_FAILURE_NOT_AUTHENTICATED_TEXT,
@@ -1807,9 +1840,9 @@ void TwitchChannel::createClip()
case HelixClipError::Unknown: case HelixClipError::Unknown:
default: { default: {
builder.emplace<TextElement>( builder.emplace<TextElement>(
CLIPS_FAILURE_UNKNOWN_ERROR_TEXT, CLIPS_FAILURE_UNKNOWN_ERROR_TEXT.arg(errorMessage),
MessageElementFlag::Text, MessageColor::System); MessageElementFlag::Text, MessageColor::System);
text = CLIPS_FAILURE_UNKNOWN_ERROR_TEXT; text = CLIPS_FAILURE_UNKNOWN_ERROR_TEXT.arg(errorMessage);
} }
break; break;
} }
+37 -9
View File
@@ -351,10 +351,10 @@ void Helix::getGameById(QString gameId,
failureCallback); failureCallback);
} }
void Helix::createClip(QString channelId, void Helix::createClip(
ResultCallback<HelixClip> successCallback, QString channelId, ResultCallback<HelixClip> successCallback,
std::function<void(HelixClipError)> failureCallback, std::function<void(HelixClipError, QString)> failureCallback,
std::function<void()> finallyCallback) std::function<void()> finallyCallback)
{ {
QUrlQuery urlQuery; QUrlQuery urlQuery;
urlQuery.addQueryItem("broadcaster_id", channelId); urlQuery.addQueryItem("broadcaster_id", channelId);
@@ -367,7 +367,7 @@ void Helix::createClip(QString channelId,
if (!data.isArray()) if (!data.isArray())
{ {
failureCallback(HelixClipError::Unknown); failureCallback(HelixClipError::Unknown, "No clip was created");
return; return;
} }
@@ -376,17 +376,45 @@ void Helix::createClip(QString channelId,
successCallback(clip); successCallback(clip);
}) })
.onError([failureCallback](auto result) { .onError([failureCallback](auto result) {
auto obj = result.parseJson();
auto message = obj.value("message").toString();
switch (result.status().value_or(0)) switch (result.status().value_or(0))
{ {
case 503: { case 503: {
// Channel has disabled clip-creation, or channel has made cliops only creatable by followers and the user is not a follower (or subscriber) // We should not necessarily handle this, so the error messaging will use `message` if it exists
failureCallback(HelixClipError::ClipsDisabled); failureCallback(HelixClipError::ClipsUnavailable, message);
} }
break; break;
case 401: { case 401: {
// User does not have the required scope to be able to create clips, user must reauthenticate // User does not have the required scope to be able to create clips, user must reauthenticate
failureCallback(HelixClipError::UserNotAuthenticated); failureCallback(HelixClipError::UserNotAuthenticated,
message);
}
break;
case 403: {
if (message.contains("restricted for this channel"))
{
failureCallback(HelixClipError::ClipsDisabled, message);
}
else if (message.contains("User does not have permissions"))
{
failureCallback(HelixClipError::ClipsRestricted,
message);
}
else if (message.contains("restricted for this category"))
{
failureCallback(HelixClipError::ClipsRestrictedCategory,
message);
}
else
{
qCDebug(chatterinoTwitch)
<< "Failed to create a clip: "
<< result.formatError() << result.getData();
failureCallback(HelixClipError::Unknown, message);
}
} }
break; break;
@@ -394,7 +422,7 @@ void Helix::createClip(QString channelId,
qCDebug(chatterinoTwitch) qCDebug(chatterinoTwitch)
<< "Failed to create a clip: " << result.formatError() << "Failed to create a clip: " << result.formatError()
<< result.getData(); << result.getData();
failureCallback(HelixClipError::Unknown); failureCallback(HelixClipError::Unknown, message);
} }
break; break;
} }
+11 -8
View File
@@ -474,7 +474,10 @@ enum class HelixAnnouncementColor {
enum class HelixClipError { enum class HelixClipError {
Unknown, Unknown,
ClipsUnavailable,
ClipsDisabled, ClipsDisabled,
ClipsRestricted,
ClipsRestrictedCategory,
UserNotAuthenticated, UserNotAuthenticated,
}; };
@@ -864,10 +867,10 @@ public:
HelixFailureCallback failureCallback) = 0; HelixFailureCallback failureCallback) = 0;
// https://dev.twitch.tv/docs/api/reference#create-clip // https://dev.twitch.tv/docs/api/reference#create-clip
virtual void createClip(QString channelId, virtual void createClip(
ResultCallback<HelixClip> successCallback, QString channelId, ResultCallback<HelixClip> successCallback,
std::function<void(HelixClipError)> failureCallback, std::function<void(HelixClipError, QString)> failureCallback,
std::function<void()> finallyCallback) = 0; std::function<void()> finallyCallback) = 0;
// https://dev.twitch.tv/docs/api/reference#get-channel-information // https://dev.twitch.tv/docs/api/reference#get-channel-information
virtual void fetchChannels( virtual void fetchChannels(
@@ -1207,10 +1210,10 @@ public:
HelixFailureCallback failureCallback) final; HelixFailureCallback failureCallback) final;
// https://dev.twitch.tv/docs/api/reference#create-clip // https://dev.twitch.tv/docs/api/reference#create-clip
void createClip(QString channelId, void createClip(
ResultCallback<HelixClip> successCallback, QString channelId, ResultCallback<HelixClip> successCallback,
std::function<void(HelixClipError)> failureCallback, std::function<void(HelixClipError, QString)> failureCallback,
std::function<void()> finallyCallback) final; std::function<void()> finallyCallback) final;
// https://dev.twitch.tv/docs/api/reference#get-channel-information // https://dev.twitch.tv/docs/api/reference#get-channel-information
void fetchChannels( void fetchChannels(