mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
Implement /marker command (#2360)
This command works the same as it does on Twitch web chat - it creates a streamer marker at the current timestamp with an optional description
This commit is contained in:
parent
eda5e2b504
commit
278a00a700
5 changed files with 172 additions and 3 deletions
|
@ -6,6 +6,7 @@
|
||||||
- Major: Added "Channel Filters". See https://wiki.chatterino.com/Filters/ for how they work or how to configure them. (#1748, #2083, #2090, #2200)
|
- Major: Added "Channel Filters". See https://wiki.chatterino.com/Filters/ for how they work or how to configure them. (#1748, #2083, #2090, #2200)
|
||||||
- Major: Added Streamer Mode configuration (under `Settings -> General`), where you can select which features of Chatterino should behave differently when you are in Streamer Mode. (#2001, #2316, #2342, #2376)
|
- Major: Added Streamer Mode configuration (under `Settings -> General`), where you can select which features of Chatterino should behave differently when you are in Streamer Mode. (#2001, #2316, #2342, #2376)
|
||||||
- Major: Color mentions to match the mentioned users. You can disable this by unchecking "Color @usernames" under `Settings -> General -> Advanced (misc.)`. (#1963, #2284)
|
- Major: Color mentions to match the mentioned users. You can disable this by unchecking "Color @usernames" under `Settings -> General -> Advanced (misc.)`. (#1963, #2284)
|
||||||
|
- Minor: Added `/marker` command - similar to webchat, it creates a stream marker. (#2360)
|
||||||
- Minor: Added `/chatters` command showing chatter count. (#2344)
|
- Minor: Added `/chatters` command showing chatter count. (#2344)
|
||||||
- Minor: Added a button to the split context menu to open the moderation view for a channel when the account selected has moderator permissions. (#2321)
|
- Minor: Added a button to the split context menu to open the moderation view for a channel when the account selected has moderator permissions. (#2321)
|
||||||
- Minor: Made BetterTTV emote tooltips use authors' display name. (#2267)
|
- Minor: Made BetterTTV emote tooltips use authors' display name. (#2267)
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "singletons/Theme.hpp"
|
#include "singletons/Theme.hpp"
|
||||||
#include "singletons/WindowManager.hpp"
|
#include "singletons/WindowManager.hpp"
|
||||||
#include "util/CombinePath.hpp"
|
#include "util/CombinePath.hpp"
|
||||||
|
#include "util/FormatTime.hpp"
|
||||||
#include "util/Twitch.hpp"
|
#include "util/Twitch.hpp"
|
||||||
#include "widgets/Window.hpp"
|
#include "widgets/Window.hpp"
|
||||||
#include "widgets/dialogs/UserInfoPopup.hpp"
|
#include "widgets/dialogs/UserInfoPopup.hpp"
|
||||||
|
@ -465,6 +466,78 @@ void CommandController::initialize(Settings &, Paths &paths)
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this->registerCommand("/marker", [](const QStringList &words,
|
||||||
|
auto channel) {
|
||||||
|
if (!channel->isTwitchChannel())
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid Helix calls without Client ID and/or OAuth Token
|
||||||
|
if (getApp()->accounts->twitch.getCurrent()->isAnon())
|
||||||
|
{
|
||||||
|
channel->addMessage(makeSystemMessage(
|
||||||
|
"You need to be logged in to create stream markers!"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
||||||
|
|
||||||
|
// Exact same message as in webchat
|
||||||
|
if (!twitchChannel->isLive())
|
||||||
|
{
|
||||||
|
channel->addMessage(makeSystemMessage(
|
||||||
|
"You can only add stream markers during live streams. Try "
|
||||||
|
"again when the channel is live streaming."));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto arguments = words;
|
||||||
|
arguments.removeFirst();
|
||||||
|
|
||||||
|
getHelix()->createStreamMarker(
|
||||||
|
// Limit for description is 140 characters, webchat just crops description
|
||||||
|
// if it's >140 characters, so we're doing the same thing
|
||||||
|
twitchChannel->roomId(), arguments.join(" ").left(140),
|
||||||
|
[channel, arguments](const HelixStreamMarker &streamMarker) {
|
||||||
|
channel->addMessage(makeSystemMessage(
|
||||||
|
QString("Successfully added a stream marker at %1%2")
|
||||||
|
.arg(formatTime(streamMarker.positionSeconds))
|
||||||
|
.arg(streamMarker.description.isEmpty()
|
||||||
|
? ""
|
||||||
|
: QString(": \"%1\"")
|
||||||
|
.arg(streamMarker.description))));
|
||||||
|
},
|
||||||
|
[channel](auto error) {
|
||||||
|
QString errorMessage("Failed to create stream marker - ");
|
||||||
|
|
||||||
|
switch (error)
|
||||||
|
{
|
||||||
|
case HelixStreamMarkerError::UserNotAuthorized: {
|
||||||
|
errorMessage +=
|
||||||
|
"you don't have permission to perform that action.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HelixStreamMarkerError::UserNotAuthenticated: {
|
||||||
|
errorMessage += "you need to re-authenticate.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// This would most likely happen if the service is down, or if the JSON payload returned has changed format
|
||||||
|
case HelixStreamMarkerError::Unknown:
|
||||||
|
default: {
|
||||||
|
errorMessage += "an unknown error occurred.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
channel->addMessage(makeSystemMessage(errorMessage));
|
||||||
|
});
|
||||||
|
|
||||||
|
return "";
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandController::save()
|
void CommandController::save()
|
||||||
|
|
|
@ -442,6 +442,66 @@ void Helix::getChannel(QString broadcasterId,
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Helix::createStreamMarker(
|
||||||
|
QString broadcasterId, QString description,
|
||||||
|
ResultCallback<HelixStreamMarker> successCallback,
|
||||||
|
std::function<void(HelixStreamMarkerError)> failureCallback)
|
||||||
|
{
|
||||||
|
QJsonObject payload;
|
||||||
|
|
||||||
|
if (!description.isEmpty())
|
||||||
|
{
|
||||||
|
payload.insert("description", QJsonValue(description));
|
||||||
|
}
|
||||||
|
payload.insert("user_id", QJsonValue(broadcasterId));
|
||||||
|
|
||||||
|
this->makeRequest("streams/markers", QUrlQuery())
|
||||||
|
.type(NetworkRequestType::Post)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.payload(QJsonDocument(payload).toJson(QJsonDocument::Compact))
|
||||||
|
.onSuccess([successCallback, failureCallback](auto result) -> Outcome {
|
||||||
|
auto root = result.parseJson();
|
||||||
|
auto data = root.value("data");
|
||||||
|
|
||||||
|
if (!data.isArray())
|
||||||
|
{
|
||||||
|
failureCallback(HelixStreamMarkerError::Unknown);
|
||||||
|
return Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
HelixStreamMarker streamMarker(data.toArray()[0].toObject());
|
||||||
|
|
||||||
|
successCallback(streamMarker);
|
||||||
|
return Success;
|
||||||
|
})
|
||||||
|
.onError([failureCallback](NetworkResult result) {
|
||||||
|
switch (result.status())
|
||||||
|
{
|
||||||
|
case 403: {
|
||||||
|
// User isn't a Channel Editor, so he can't create markers
|
||||||
|
failureCallback(HelixStreamMarkerError::UserNotAuthorized);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 401: {
|
||||||
|
// User does not have the required scope to be able to create stream markers, user must reauthenticate
|
||||||
|
failureCallback(
|
||||||
|
HelixStreamMarkerError::UserNotAuthenticated);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
qCDebug(chatterinoTwitch)
|
||||||
|
<< "Failed to create a stream marker: "
|
||||||
|
<< result.status() << result.getData();
|
||||||
|
failureCallback(HelixStreamMarkerError::Unknown);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
};
|
||||||
|
|
||||||
NetworkRequest Helix::makeRequest(QString url, QUrlQuery urlQuery)
|
NetworkRequest Helix::makeRequest(QString url, QUrlQuery urlQuery)
|
||||||
{
|
{
|
||||||
assert(!url.startsWith("/"));
|
assert(!url.startsWith("/"));
|
||||||
|
|
|
@ -165,12 +165,33 @@ struct HelixChannel {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct HelixStreamMarker {
|
||||||
|
QString createdAt;
|
||||||
|
QString description;
|
||||||
|
QString id;
|
||||||
|
int positionSeconds;
|
||||||
|
|
||||||
|
explicit HelixStreamMarker(QJsonObject jsonObject)
|
||||||
|
: createdAt(jsonObject.value("created_at").toString())
|
||||||
|
, description(jsonObject.value("description").toString())
|
||||||
|
, id(jsonObject.value("id").toString())
|
||||||
|
, positionSeconds(jsonObject.value("position_seconds").toInt())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
enum class HelixClipError {
|
enum class HelixClipError {
|
||||||
Unknown,
|
Unknown,
|
||||||
ClipsDisabled,
|
ClipsDisabled,
|
||||||
UserNotAuthenticated,
|
UserNotAuthenticated,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class HelixStreamMarkerError {
|
||||||
|
Unknown,
|
||||||
|
UserNotAuthorized,
|
||||||
|
UserNotAuthenticated,
|
||||||
|
};
|
||||||
|
|
||||||
class Helix final : boost::noncopyable
|
class Helix final : boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -242,6 +263,12 @@ public:
|
||||||
ResultCallback<HelixChannel> successCallback,
|
ResultCallback<HelixChannel> successCallback,
|
||||||
HelixFailureCallback failureCallback);
|
HelixFailureCallback failureCallback);
|
||||||
|
|
||||||
|
// https://dev.twitch.tv/docs/api/reference/#create-stream-marker
|
||||||
|
void createStreamMarker(
|
||||||
|
QString broadcasterId, QString description,
|
||||||
|
ResultCallback<HelixStreamMarker> successCallback,
|
||||||
|
std::function<void(HelixStreamMarkerError)> failureCallback);
|
||||||
|
|
||||||
void update(QString clientId, QString oauthToken);
|
void update(QString clientId, QString oauthToken);
|
||||||
|
|
||||||
static void initialize();
|
static void initialize();
|
||||||
|
|
|
@ -84,7 +84,7 @@ URL: https://dev.twitch.tv/docs/api/reference#get-streams
|
||||||
URL: https://dev.twitch.tv/docs/api/reference#create-user-follows
|
URL: https://dev.twitch.tv/docs/api/reference#create-user-follows
|
||||||
Requires `user:edit:follows` scope
|
Requires `user:edit:follows` scope
|
||||||
|
|
||||||
* We implement this in `providers/twitch/api/Helix.cpp followUser`
|
* We implement this in `providers/twitch/api/Helix.cpp followUser`
|
||||||
Used in:
|
Used in:
|
||||||
* `widgets/dialogs/UserInfoPopup.cpp` to follow a user by ticking follow checkbox in usercard
|
* `widgets/dialogs/UserInfoPopup.cpp` to follow a user by ticking follow checkbox in usercard
|
||||||
* `controllers/commands/CommandController.cpp` in /follow command
|
* `controllers/commands/CommandController.cpp` in /follow command
|
||||||
|
@ -93,7 +93,7 @@ Requires `user:edit:follows` scope
|
||||||
URL: https://dev.twitch.tv/docs/api/reference#delete-user-follows
|
URL: https://dev.twitch.tv/docs/api/reference#delete-user-follows
|
||||||
Requires `user:edit:follows` scope
|
Requires `user:edit:follows` scope
|
||||||
|
|
||||||
* We implement this in `providers/twitch/api/Helix.cpp unfollowUser`
|
* We implement this in `providers/twitch/api/Helix.cpp unfollowUser`
|
||||||
Used in:
|
Used in:
|
||||||
* `widgets/dialogs/UserInfoPopup.cpp` to unfollow a user by unticking follow checkbox in usercard
|
* `widgets/dialogs/UserInfoPopup.cpp` to unfollow a user by unticking follow checkbox in usercard
|
||||||
* `controllers/commands/CommandController.cpp` in /unfollow command
|
* `controllers/commands/CommandController.cpp` in /unfollow command
|
||||||
|
@ -102,7 +102,7 @@ Requires `user:edit:follows` scope
|
||||||
URL: https://dev.twitch.tv/docs/api/reference#create-clip
|
URL: https://dev.twitch.tv/docs/api/reference#create-clip
|
||||||
Requires `clips:edit` scope
|
Requires `clips:edit` scope
|
||||||
|
|
||||||
* We implement this in `providers/twitch/api/Helix.cpp createClip`
|
* We implement this in `providers/twitch/api/Helix.cpp createClip`
|
||||||
Used in:
|
Used in:
|
||||||
* `TwitchChannel` to create a clip of a live broadcast
|
* `TwitchChannel` to create a clip of a live broadcast
|
||||||
|
|
||||||
|
@ -113,6 +113,14 @@ URL: https://dev.twitch.tv/docs/api/reference#get-channel-information
|
||||||
Used in:
|
Used in:
|
||||||
* `TwitchChannel` to refresh stream title
|
* `TwitchChannel` to refresh stream title
|
||||||
|
|
||||||
|
### Create Stream Marker
|
||||||
|
URL: https://dev.twitch.tv/docs/api/reference/#create-stream-marker
|
||||||
|
Requires `user:edit:broadcast` scope
|
||||||
|
|
||||||
|
* We implement this in `providers/twitch/api/Helix.cpp createStreamMarker`
|
||||||
|
Used in:
|
||||||
|
* `controllers/commands/CommandController.cpp` in /marker command
|
||||||
|
|
||||||
## TMI
|
## TMI
|
||||||
The TMI api is undocumented.
|
The TMI api is undocumented.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue