feat: add duration and title options to clip command (#6669)

Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
iProdigy
2025-12-28 05:26:48 -06:00
committed by GitHub
parent e084ae6ef1
commit a9ab584cbb
9 changed files with 60 additions and 10 deletions
+1
View File
@@ -20,6 +20,7 @@
- Minor: Added broadcaster-only `/poll`, `/cancelpoll`, and `/endpoll` commands. (#6583, #6605) - Minor: Added broadcaster-only `/poll`, `/cancelpoll`, and `/endpoll` commands. (#6583, #6605)
- Minor: Added broadcaster-only `/prediction`, `/cancelprediction`, `/lockprediction`, and `/completeprediction` commands. (#6583, #6612, #6632) - Minor: Added broadcaster-only `/prediction`, `/cancelprediction`, `/lockprediction`, and `/completeprediction` commands. (#6583, #6612, #6632)
- Minor: Added support for BetterTTV Pro subscriber badges. (#6625) - Minor: Added support for BetterTTV Pro subscriber badges. (#6625)
- Minor: Added title and duration options for `/clip` command. (#6669)
- Minor: Added Markdown support to user notes. (#6490) - Minor: Added Markdown support to user notes. (#6490)
- Bugfix: Moderation checks now include the lead moderator badge. (#6642) - Bugfix: Moderation checks now include the lead moderator badge. (#6642)
- Bugfix: Fixed lead moderator badges not being filtered by the `Channel` badge setting. (#6665) - Bugfix: Fixed lead moderator badges not being filtered by the `Channel` badge setting. (#6665)
+2 -1
View File
@@ -79,7 +79,8 @@ public:
(override)); (override));
MOCK_METHOD(void, createClip, MOCK_METHOD(void, createClip,
(QString channelId, ResultCallback<HelixClip> successCallback, (QString channelId, QString title, std::optional<int> duration,
ResultCallback<HelixClip> successCallback,
std::function<void(HelixClipError, QString)> failureCallback, std::function<void(HelixClipError, QString)> failureCallback,
std::function<void()> finallyCallback), std::function<void()> finallyCallback),
(override)); (override));
+35 -1
View File
@@ -200,7 +200,41 @@ QString clip(const CommandContext &ctx)
return ""; return "";
} }
ctx.twitchChannel->createClip(); QString title = "";
std::optional<int> duration = std::nullopt;
if (!ctx.words.empty())
{
QCommandLineParser parser;
parser.setSingleDashWordOptionMode(
QCommandLineParser::ParseAsLongOptions);
parser.setOptionsAfterPositionalArgumentsMode(
QCommandLineParser::ParseAsPositionalArguments);
parser.addPositionalArgument("title", "The title of the clip");
QCommandLineOption durationOption(
{"d", "duration"}, "The duration of the clip", "duration");
parser.addOptions({
durationOption,
});
parser.parse(ctx.words);
title = parser.positionalArguments().join(' ');
if (parser.isSet(durationOption))
{
bool ok = false;
duration = parser.value(durationOption).toInt(&ok);
if (!ok)
{
ctx.channel->addSystemMessage(
"Could not parse clip duration to an integer.");
return "";
}
}
}
ctx.twitchChannel->createClip(title, duration);
return ""; return "";
} }
+3 -2
View File
@@ -1956,7 +1956,8 @@ void TwitchChannel::setCheerEmoteSets(
*this->cheerEmoteSets_.access() = std::move(emoteSets); *this->cheerEmoteSets_.access() = std::move(emoteSets);
} }
void TwitchChannel::createClip() void TwitchChannel::createClip(const QString &title,
const std::optional<int> duration)
{ {
if (!this->isLive()) if (!this->isLive())
{ {
@@ -1980,7 +1981,7 @@ void TwitchChannel::createClip()
this->isClipCreationInProgress = true; this->isClipCreationInProgress = true;
getHelix()->createClip( getHelix()->createClip(
this->roomId(), this->roomId(), title, duration,
// successCallback // successCallback
[this](const HelixClip &clip) { [this](const HelixClip &clip) {
MessageBuilder builder; MessageBuilder builder;
+1 -1
View File
@@ -182,7 +182,7 @@ public:
bool canReconnect() const override; bool canReconnect() const override;
void reconnect() override; void reconnect() override;
QString getCurrentStreamID() const override; QString getCurrentStreamID() const override;
void createClip(); void createClip(const QString &title, std::optional<int> duration);
/// Delete the message with the specified ID as a moderator. /// Delete the message with the specified ID as a moderator.
/// ///
+12 -1
View File
@@ -354,13 +354,24 @@ void Helix::getGameById(QString gameId,
} }
void Helix::createClip( void Helix::createClip(
QString channelId, ResultCallback<HelixClip> successCallback, QString channelId, QString title, std::optional<int> duration,
ResultCallback<HelixClip> successCallback,
std::function<void(HelixClipError, QString)> 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);
if (!title.isEmpty())
{
urlQuery.addQueryItem("title", title);
}
if (duration.has_value())
{
urlQuery.addQueryItem("duration", QString::number(*duration));
}
this->makePost("clips", urlQuery) this->makePost("clips", urlQuery)
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.onSuccess([successCallback, failureCallback](auto result) { .onSuccess([successCallback, failureCallback](auto result) {
+4 -2
View File
@@ -1036,7 +1036,8 @@ public:
// https://dev.twitch.tv/docs/api/reference#create-clip // https://dev.twitch.tv/docs/api/reference#create-clip
virtual void createClip( virtual void createClip(
QString channelId, ResultCallback<HelixClip> successCallback, QString channelId, QString title, std::optional<int> duration,
ResultCallback<HelixClip> successCallback,
std::function<void(HelixClipError, QString)> failureCallback, std::function<void(HelixClipError, QString)> failureCallback,
std::function<void()> finallyCallback) = 0; std::function<void()> finallyCallback) = 0;
@@ -1428,7 +1429,8 @@ public:
// https://dev.twitch.tv/docs/api/reference#create-clip // https://dev.twitch.tv/docs/api/reference#create-clip
void createClip( void createClip(
QString channelId, ResultCallback<HelixClip> successCallback, QString channelId, QString title, std::optional<int> duration,
ResultCallback<HelixClip> successCallback,
std::function<void(HelixClipError, QString)> failureCallback, std::function<void(HelixClipError, QString)> failureCallback,
std::function<void()> finallyCallback) final; std::function<void()> finallyCallback) final;
+1 -1
View File
@@ -483,7 +483,7 @@ void Split::addShortcuts()
auto *twitchChannel = auto *twitchChannel =
dynamic_cast<TwitchChannel *>(this->getChannel().get()); dynamic_cast<TwitchChannel *>(this->getChannel().get());
twitchChannel->createClip(); twitchChannel->createClip({}, {});
return ""; return "";
}}, }},
{"reloadEmotes", {"reloadEmotes",
+1 -1
View File
@@ -478,7 +478,7 @@ std::unique_ptr<QMenu> SplitHeader::createMainMenu()
h->getDisplaySequence(HotkeyCategory::Split, "createClip"), h->getDisplaySequence(HotkeyCategory::Split, "createClip"),
this->split_, this->split_,
[twitchChannel] { [twitchChannel] {
twitchChannel->createClip(); twitchChannel->createClip({}, {});
}) })
->setVisible(twitchChannel->isLive()); ->setVisible(twitchChannel->isLive());