mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
feat: include more data when copying messages as JSON (#5600)
This commit is contained in:
parent
edf18a7a0f
commit
e149be3820
|
@ -90,6 +90,7 @@
|
|||
- Dev: The timer for `StreamerMode` is now destroyed on the correct thread. (#5571)
|
||||
- Dev: Cleanup some parts of the `magic_enum` adaptation for Qt. (#5587)
|
||||
- Dev: Refactored `static`s in headers to only be present once in the final app. (#5588)
|
||||
- Dev: The JSON output when copying a message (<kbd>SHIFT</kbd> + right-click) is now more extensive. (#5600)
|
||||
|
||||
## 2.5.1
|
||||
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
#include "messages/Emote.hpp"
|
||||
|
||||
#include "common/Literals.hpp"
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
using namespace literals;
|
||||
|
||||
bool operator==(const Emote &a, const Emote &b)
|
||||
{
|
||||
return std::tie(a.homePage, a.name, a.tooltip, a.images) ==
|
||||
|
@ -15,6 +21,37 @@ bool operator!=(const Emote &a, const Emote &b)
|
|||
return !(a == b);
|
||||
}
|
||||
|
||||
QJsonObject Emote::toJson() const
|
||||
{
|
||||
QJsonObject obj{
|
||||
{"name"_L1, this->name.string},
|
||||
{"images"_L1, this->images.toJson()},
|
||||
{"tooltip"_L1, this->tooltip.string},
|
||||
};
|
||||
if (!this->homePage.string.isEmpty())
|
||||
{
|
||||
obj["homePage"_L1] = this->homePage.string;
|
||||
}
|
||||
if (this->zeroWidth)
|
||||
{
|
||||
obj["zeroWidth"_L1] = this->zeroWidth;
|
||||
}
|
||||
if (!this->id.string.isEmpty())
|
||||
{
|
||||
obj["id"_L1] = this->id.string;
|
||||
}
|
||||
if (!this->author.string.isEmpty())
|
||||
{
|
||||
obj["author"_L1] = this->author.string;
|
||||
}
|
||||
if (this->baseName)
|
||||
{
|
||||
obj["baseName"_L1] = this->baseName->string;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
EmotePtr cachedOrMakeEmotePtr(Emote &&emote, const EmoteMap &cache)
|
||||
{
|
||||
// reuse old shared_ptr if nothing changed
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <optional>
|
||||
#include <unordered_map>
|
||||
|
||||
class QJsonObject;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
struct Emote {
|
||||
|
@ -30,6 +32,8 @@ struct Emote {
|
|||
{
|
||||
return name.string;
|
||||
}
|
||||
|
||||
QJsonObject toJson() const;
|
||||
};
|
||||
|
||||
bool operator==(const Emote &a, const Emote &b);
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include "messages/Image.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
ImageSet::ImageSet()
|
||||
|
@ -135,4 +137,22 @@ bool ImageSet::operator!=(const ImageSet &other) const
|
|||
return !this->operator==(other);
|
||||
}
|
||||
|
||||
QJsonObject ImageSet::toJson() const
|
||||
{
|
||||
QJsonObject obj;
|
||||
if (!this->imageX1_->isEmpty())
|
||||
{
|
||||
obj[u"1x"] = this->imageX1_->url().string;
|
||||
}
|
||||
if (!this->imageX2_->isEmpty())
|
||||
{
|
||||
obj[u"2x"] = this->imageX2_->url().string;
|
||||
}
|
||||
if (!this->imageX3_->isEmpty())
|
||||
{
|
||||
obj[u"3x"] = this->imageX3_->url().string;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
class QJsonObject;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class Image;
|
||||
|
@ -34,6 +36,8 @@ public:
|
|||
bool operator==(const ImageSet &other) const;
|
||||
bool operator!=(const ImageSet &other) const;
|
||||
|
||||
QJsonObject toJson() const;
|
||||
|
||||
private:
|
||||
ImagePtr imageX1_;
|
||||
ImagePtr imageX2_;
|
||||
|
|
|
@ -1,13 +1,23 @@
|
|||
#include "messages/Message.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "common/Literals.hpp"
|
||||
#include "messages/MessageThread.hpp"
|
||||
#include "providers/colors/ColorProvider.hpp"
|
||||
#include "providers/twitch/TwitchBadge.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "util/DebugCount.hpp"
|
||||
#include "util/QMagicEnum.hpp"
|
||||
#include "widgets/helper/ScrollbarHighlight.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
using namespace literals;
|
||||
|
||||
Message::Message()
|
||||
: parseTime(QTime::currentTime())
|
||||
{
|
||||
|
@ -80,4 +90,72 @@ ScrollbarHighlight Message::getScrollBarHighlight() const
|
|||
return {};
|
||||
}
|
||||
|
||||
QJsonObject Message::toJson() const
|
||||
{
|
||||
QJsonObject msg{
|
||||
{"flags"_L1, qmagicenum::enumFlagsName(this->flags.value())},
|
||||
{"id"_L1, this->id},
|
||||
{"searchText"_L1, this->searchText},
|
||||
{"messageText"_L1, this->messageText},
|
||||
{"loginName"_L1, this->loginName},
|
||||
{"displayName"_L1, this->displayName},
|
||||
{"localizedName"_L1, this->localizedName},
|
||||
{"timeoutUser"_L1, this->timeoutUser},
|
||||
{"channelName"_L1, this->channelName},
|
||||
{"usernameColor"_L1, this->usernameColor.name(QColor::HexArgb)},
|
||||
{"count"_L1, static_cast<qint64>(this->count)},
|
||||
{"serverReceivedTime"_L1,
|
||||
this->serverReceivedTime.toString(Qt::ISODate)},
|
||||
};
|
||||
|
||||
QJsonArray badges;
|
||||
for (const auto &badge : this->badges)
|
||||
{
|
||||
badges.append(badge.key_);
|
||||
}
|
||||
msg["badges"_L1] = badges;
|
||||
|
||||
QJsonObject badgeInfos;
|
||||
for (const auto &[key, value] : this->badgeInfos)
|
||||
{
|
||||
badgeInfos.insert(key, value);
|
||||
}
|
||||
msg["badgeInfos"_L1] = badgeInfos;
|
||||
|
||||
if (this->highlightColor)
|
||||
{
|
||||
msg["highlightColor"_L1] = this->highlightColor->name(QColor::HexArgb);
|
||||
}
|
||||
|
||||
if (this->replyThread)
|
||||
{
|
||||
msg["replyThread"_L1] = this->replyThread->toJson();
|
||||
}
|
||||
|
||||
if (this->replyParent)
|
||||
{
|
||||
msg["replyParent"_L1] = this->replyParent->id;
|
||||
}
|
||||
|
||||
if (this->reward)
|
||||
{
|
||||
msg["reward"_L1] = this->reward->toJson();
|
||||
}
|
||||
|
||||
// XXX: figure out if we can add this in tests
|
||||
if (!getApp()->isTest())
|
||||
{
|
||||
msg["parseTime"_L1] = this->parseTime.toString(Qt::ISODate);
|
||||
}
|
||||
|
||||
QJsonArray elements;
|
||||
for (const auto &element : this->elements)
|
||||
{
|
||||
elements.append(element->toJson());
|
||||
}
|
||||
msg["elements"_L1] = elements;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class QJsonObject;
|
||||
|
||||
namespace chatterino {
|
||||
class MessageElement;
|
||||
class MessageThread;
|
||||
|
@ -62,6 +64,8 @@ struct Message {
|
|||
ScrollbarHighlight getScrollBarHighlight() const;
|
||||
|
||||
std::shared_ptr<ChannelPointReward> reward = nullptr;
|
||||
|
||||
QJsonObject toJson() const;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -33,4 +33,21 @@ const QColor &MessageColor::getColor(Theme &themeManager) const
|
|||
return _default;
|
||||
}
|
||||
|
||||
QString MessageColor::toString() const
|
||||
{
|
||||
switch (this->type_)
|
||||
{
|
||||
case Type::Custom:
|
||||
return this->customColor_.name(QColor::HexArgb);
|
||||
case Type::Text:
|
||||
return QStringLiteral("Text");
|
||||
case Type::System:
|
||||
return QStringLiteral("System");
|
||||
case Type::Link:
|
||||
return QStringLiteral("Link");
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <QColor>
|
||||
#include <QString>
|
||||
|
||||
namespace chatterino {
|
||||
class Theme;
|
||||
|
@ -13,6 +14,8 @@ struct MessageColor {
|
|||
|
||||
const QColor &getColor(Theme &themeManager) const;
|
||||
|
||||
QString toString() const;
|
||||
|
||||
private:
|
||||
Type type_;
|
||||
QColor customColor_;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "messages/MessageElement.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "common/Literals.hpp"
|
||||
#include "controllers/moderationactions/ModerationAction.hpp"
|
||||
#include "debug/Benchmark.hpp"
|
||||
#include "messages/Emote.hpp"
|
||||
|
@ -14,8 +15,14 @@
|
|||
#include "util/DebugCount.hpp"
|
||||
#include "util/Variant.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
using namespace literals;
|
||||
|
||||
namespace {
|
||||
|
||||
// Computes the bounding box for the given vector of images
|
||||
|
@ -88,6 +95,22 @@ void MessageElement::addFlags(MessageElementFlags flags)
|
|||
this->flags_.set(flags);
|
||||
}
|
||||
|
||||
QJsonObject MessageElement::toJson() const
|
||||
{
|
||||
return {
|
||||
{"trailingSpace"_L1, this->trailingSpace},
|
||||
{
|
||||
"link"_L1,
|
||||
{{
|
||||
{"type"_L1, qmagicenum::enumNameString(this->link_.type)},
|
||||
{"value"_L1, this->link_.value},
|
||||
}},
|
||||
},
|
||||
{"tooltip"_L1, this->tooltip_},
|
||||
{"flags"_L1, qmagicenum::enumFlagsName(this->flags_.value())},
|
||||
};
|
||||
}
|
||||
|
||||
// IMAGE
|
||||
ImageElement::ImageElement(ImagePtr image, MessageElementFlags flags)
|
||||
: MessageElement(flags)
|
||||
|
@ -108,6 +131,15 @@ void ImageElement::addToContainer(MessageLayoutContainer &container,
|
|||
}
|
||||
}
|
||||
|
||||
QJsonObject ImageElement::toJson() const
|
||||
{
|
||||
auto base = MessageElement::toJson();
|
||||
base["type"_L1] = u"ImageElement"_s;
|
||||
base["url"_L1] = this->image_->url().string;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
CircularImageElement::CircularImageElement(ImagePtr image, int padding,
|
||||
QColor background,
|
||||
MessageElementFlags flags)
|
||||
|
@ -131,6 +163,17 @@ void CircularImageElement::addToContainer(MessageLayoutContainer &container,
|
|||
}
|
||||
}
|
||||
|
||||
QJsonObject CircularImageElement::toJson() const
|
||||
{
|
||||
auto base = MessageElement::toJson();
|
||||
base["type"_L1] = u"CircularImageElement"_s;
|
||||
base["url"_L1] = this->image_->url().string;
|
||||
base["padding"_L1] = this->padding_;
|
||||
base["background"_L1] = this->background_.name(QColor::HexArgb);
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
// EMOTE
|
||||
EmoteElement::EmoteElement(const EmotePtr &emote, MessageElementFlags flags,
|
||||
const MessageColor &textElementColor)
|
||||
|
@ -187,6 +230,19 @@ MessageLayoutElement *EmoteElement::makeImageLayoutElement(
|
|||
return new ImageLayoutElement(*this, image, size);
|
||||
}
|
||||
|
||||
QJsonObject EmoteElement::toJson() const
|
||||
{
|
||||
auto base = MessageElement::toJson();
|
||||
base["type"_L1] = u"EmoteElement"_s;
|
||||
base["emote"_L1] = this->emote_->toJson();
|
||||
if (this->textElement_)
|
||||
{
|
||||
base["text"_L1] = this->textElement_->toJson();
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
LayeredEmoteElement::LayeredEmoteElement(
|
||||
std::vector<LayeredEmoteElement::Emote> &&emotes, MessageElementFlags flags,
|
||||
const MessageColor &textElementColor)
|
||||
|
@ -350,6 +406,38 @@ std::vector<LayeredEmoteElement::Emote> LayeredEmoteElement::getUniqueEmotes()
|
|||
return unique;
|
||||
}
|
||||
|
||||
QJsonObject LayeredEmoteElement::toJson() const
|
||||
{
|
||||
auto base = MessageElement::toJson();
|
||||
base["type"_L1] = u"LayeredEmoteElement"_s;
|
||||
|
||||
QJsonArray emotes;
|
||||
for (const auto &emote : this->emotes_)
|
||||
{
|
||||
emotes.append({{
|
||||
{"flags"_L1, qmagicenum::enumFlagsName(emote.flags.value())},
|
||||
{"emote"_L1, emote.ptr->toJson()},
|
||||
}});
|
||||
}
|
||||
base["emotes"_L1] = emotes;
|
||||
|
||||
QJsonArray tooltips;
|
||||
for (const auto &tooltip : this->emoteTooltips_)
|
||||
{
|
||||
emotes.append(tooltip);
|
||||
}
|
||||
base["tooltips"_L1] = tooltips;
|
||||
|
||||
if (this->textElement_)
|
||||
{
|
||||
base["text"_L1] = this->textElement_->toJson();
|
||||
}
|
||||
|
||||
base["textElementColor"_L1] = this->textElementColor_.toString();
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
// BADGE
|
||||
BadgeElement::BadgeElement(const EmotePtr &emote, MessageElementFlags flags)
|
||||
: MessageElement(flags)
|
||||
|
@ -390,6 +478,15 @@ MessageLayoutElement *BadgeElement::makeImageLayoutElement(
|
|||
return element;
|
||||
}
|
||||
|
||||
QJsonObject BadgeElement::toJson() const
|
||||
{
|
||||
auto base = MessageElement::toJson();
|
||||
base["type"_L1] = u"BadgeElement"_s;
|
||||
base["emote"_L1] = this->emote_->toJson();
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
// MOD BADGE
|
||||
ModBadgeElement::ModBadgeElement(const EmotePtr &data,
|
||||
MessageElementFlags flags_)
|
||||
|
@ -408,6 +505,14 @@ MessageLayoutElement *ModBadgeElement::makeImageLayoutElement(
|
|||
return element;
|
||||
}
|
||||
|
||||
QJsonObject ModBadgeElement::toJson() const
|
||||
{
|
||||
auto base = BadgeElement::toJson();
|
||||
base["type"_L1] = u"ModBadgeElement"_s;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
// VIP BADGE
|
||||
VipBadgeElement::VipBadgeElement(const EmotePtr &data,
|
||||
MessageElementFlags flags_)
|
||||
|
@ -423,6 +528,14 @@ MessageLayoutElement *VipBadgeElement::makeImageLayoutElement(
|
|||
return element;
|
||||
}
|
||||
|
||||
QJsonObject VipBadgeElement::toJson() const
|
||||
{
|
||||
auto base = BadgeElement::toJson();
|
||||
base["type"_L1] = u"VipBadgeElement"_s;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
// FFZ Badge
|
||||
FfzBadgeElement::FfzBadgeElement(const EmotePtr &data,
|
||||
MessageElementFlags flags_, QColor color_)
|
||||
|
@ -440,6 +553,15 @@ MessageLayoutElement *FfzBadgeElement::makeImageLayoutElement(
|
|||
return element;
|
||||
}
|
||||
|
||||
QJsonObject FfzBadgeElement::toJson() const
|
||||
{
|
||||
auto base = BadgeElement::toJson();
|
||||
base["type"_L1] = u"FfzBadgeElement"_s;
|
||||
base["color"_L1] = this->color.name(QColor::HexArgb);
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
// TEXT
|
||||
TextElement::TextElement(const QString &text, MessageElementFlags flags,
|
||||
const MessageColor &color, FontStyle style)
|
||||
|
@ -549,6 +671,17 @@ void TextElement::addToContainer(MessageLayoutContainer &container,
|
|||
}
|
||||
}
|
||||
|
||||
QJsonObject TextElement::toJson() const
|
||||
{
|
||||
auto base = MessageElement::toJson();
|
||||
base["type"_L1] = u"TextElement"_s;
|
||||
base["words"_L1] = QJsonArray::fromStringList(this->words_);
|
||||
base["color"_L1] = this->color_.toString();
|
||||
base["style"_L1] = qmagicenum::enumNameString(this->style_);
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
SingleLineTextElement::SingleLineTextElement(const QString &text,
|
||||
MessageElementFlags flags,
|
||||
const MessageColor &color,
|
||||
|
@ -677,6 +810,22 @@ void SingleLineTextElement::addToContainer(MessageLayoutContainer &container,
|
|||
}
|
||||
}
|
||||
|
||||
QJsonObject SingleLineTextElement::toJson() const
|
||||
{
|
||||
auto base = MessageElement::toJson();
|
||||
base["type"_L1] = u"SingleLineTextElement"_s;
|
||||
QJsonArray words;
|
||||
for (const auto &word : this->words_)
|
||||
{
|
||||
words.append(word.text);
|
||||
}
|
||||
base["words"_L1] = words;
|
||||
base["color"_L1] = this->color_.toString();
|
||||
base["style"_L1] = qmagicenum::enumNameString(this->style_);
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
LinkElement::LinkElement(const Parsed &parsed, const QString &fullUrl,
|
||||
MessageElementFlags flags, const MessageColor &color,
|
||||
FontStyle style)
|
||||
|
@ -701,6 +850,17 @@ Link LinkElement::getLink() const
|
|||
return {Link::Url, this->linkInfo_.url()};
|
||||
}
|
||||
|
||||
QJsonObject LinkElement::toJson() const
|
||||
{
|
||||
auto base = TextElement::toJson();
|
||||
base["type"_L1] = u"LinkElement"_s;
|
||||
base["link"_L1] = this->linkInfo_.originalUrl();
|
||||
base["lowercase"_L1] = QJsonArray::fromStringList(this->lowercase_);
|
||||
base["original"_L1] = QJsonArray::fromStringList(this->original_);
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
MentionElement::MentionElement(const QString &displayName, QString loginName_,
|
||||
MessageColor fallbackColor_,
|
||||
MessageColor userColor_)
|
||||
|
@ -756,7 +916,24 @@ Link MentionElement::getLink() const
|
|||
return {Link::UserInfo, this->userLoginName};
|
||||
}
|
||||
|
||||
QJsonObject MentionElement::toJson() const
|
||||
{
|
||||
auto base = TextElement::toJson();
|
||||
base["type"_L1] = u"MentionElement"_s;
|
||||
base["fallbackColor"_L1] = this->fallbackColor.toString();
|
||||
base["userColor"_L1] = this->userColor.toString();
|
||||
base["userLoginName"_L1] = this->userLoginName;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
// TIMESTAMP
|
||||
TimestampElement::TimestampElement()
|
||||
: TimestampElement(getApp()->isTest() ? QTime::fromMSecsSinceStartOfDay(0)
|
||||
: QTime::currentTime())
|
||||
{
|
||||
}
|
||||
|
||||
TimestampElement::TimestampElement(QTime time)
|
||||
: MessageElement(MessageElementFlag::Timestamp)
|
||||
, time_(time)
|
||||
|
@ -790,6 +967,17 @@ TextElement *TimestampElement::formatTime(const QTime &time)
|
|||
MessageColor::System, FontStyle::ChatMedium);
|
||||
}
|
||||
|
||||
QJsonObject TimestampElement::toJson() const
|
||||
{
|
||||
auto base = MessageElement::toJson();
|
||||
base["type"_L1] = u"TimestampElement"_s;
|
||||
base["time"_L1] = this->time_.toString(Qt::ISODate);
|
||||
base["element"_L1] = this->element_->toJson();
|
||||
base["format"_L1] = this->format_;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
// TWITCH MODERATION
|
||||
TwitchModerationElement::TwitchModerationElement()
|
||||
: MessageElement(MessageElementFlag::ModeratorTools)
|
||||
|
@ -824,6 +1012,14 @@ void TwitchModerationElement::addToContainer(MessageLayoutContainer &container,
|
|||
}
|
||||
}
|
||||
|
||||
QJsonObject TwitchModerationElement::toJson() const
|
||||
{
|
||||
auto base = MessageElement::toJson();
|
||||
base["type"_L1] = u"TwitchModerationElement"_s;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
LinebreakElement::LinebreakElement(MessageElementFlags flags)
|
||||
: MessageElement(flags)
|
||||
{
|
||||
|
@ -838,6 +1034,14 @@ void LinebreakElement::addToContainer(MessageLayoutContainer &container,
|
|||
}
|
||||
}
|
||||
|
||||
QJsonObject LinebreakElement::toJson() const
|
||||
{
|
||||
auto base = MessageElement::toJson();
|
||||
base["type"_L1] = u"LinebreakElement"_s;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
ScalingImageElement::ScalingImageElement(ImageSet images,
|
||||
MessageElementFlags flags)
|
||||
: MessageElement(flags)
|
||||
|
@ -864,6 +1068,15 @@ void ScalingImageElement::addToContainer(MessageLayoutContainer &container,
|
|||
}
|
||||
}
|
||||
|
||||
QJsonObject ScalingImageElement::toJson() const
|
||||
{
|
||||
auto base = MessageElement::toJson();
|
||||
base["type"_L1] = u"ScalingImageElement"_s;
|
||||
base["image"_L1] = this->images_.getImage1()->url().string;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
ReplyCurveElement::ReplyCurveElement()
|
||||
: MessageElement(MessageElementFlag::RepliedMessage)
|
||||
{
|
||||
|
@ -886,4 +1099,12 @@ void ReplyCurveElement::addToContainer(MessageLayoutContainer &container,
|
|||
}
|
||||
}
|
||||
|
||||
QJsonObject ReplyCurveElement::toJson() const
|
||||
{
|
||||
auto base = MessageElement::toJson();
|
||||
base["type"_L1] = u"ReplyCurveElement"_s;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "providers/links/LinkInfo.hpp"
|
||||
#include "singletons/Fonts.hpp"
|
||||
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
#include <pajlada/signals/signalholder.hpp>
|
||||
#include <QRect>
|
||||
#include <QString>
|
||||
|
@ -16,6 +17,8 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class QJsonObject;
|
||||
|
||||
namespace chatterino {
|
||||
class Channel;
|
||||
struct MessageLayoutContainer;
|
||||
|
@ -183,6 +186,8 @@ public:
|
|||
virtual void addToContainer(MessageLayoutContainer &container,
|
||||
MessageElementFlags flags) = 0;
|
||||
|
||||
virtual QJsonObject toJson() const;
|
||||
|
||||
protected:
|
||||
MessageElement(MessageElementFlags flags);
|
||||
bool trailingSpace = true;
|
||||
|
@ -202,6 +207,8 @@ public:
|
|||
void addToContainer(MessageLayoutContainer &container,
|
||||
MessageElementFlags flags) override;
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
|
||||
private:
|
||||
ImagePtr image_;
|
||||
};
|
||||
|
@ -216,6 +223,8 @@ public:
|
|||
void addToContainer(MessageLayoutContainer &container,
|
||||
MessageElementFlags flags) override;
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
|
||||
private:
|
||||
ImagePtr image_;
|
||||
int padding_;
|
||||
|
@ -234,6 +243,8 @@ public:
|
|||
void addToContainer(MessageLayoutContainer &container,
|
||||
MessageElementFlags flags) override;
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
|
||||
protected:
|
||||
QStringList words_;
|
||||
|
||||
|
@ -253,6 +264,8 @@ public:
|
|||
void addToContainer(MessageLayoutContainer &container,
|
||||
MessageElementFlags flags) override;
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
|
||||
private:
|
||||
MessageColor color_;
|
||||
FontStyle style_;
|
||||
|
@ -294,6 +307,8 @@ public:
|
|||
return &this->linkInfo_;
|
||||
}
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
|
||||
private:
|
||||
LinkInfo linkInfo_;
|
||||
// these are implicitly shared
|
||||
|
@ -328,6 +343,8 @@ public:
|
|||
MessageElement *setLink(const Link &link) override;
|
||||
Link getLink() const override;
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* The color of the element in case the "Colorize @usernames" is disabled
|
||||
|
@ -355,6 +372,8 @@ public:
|
|||
MessageElementFlags flags_) override;
|
||||
EmotePtr getEmote() const;
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
|
||||
protected:
|
||||
virtual MessageLayoutElement *makeImageLayoutElement(const ImagePtr &image,
|
||||
const QSize &size);
|
||||
|
@ -390,6 +409,8 @@ public:
|
|||
std::vector<Emote> getUniqueEmotes() const;
|
||||
const std::vector<QString> &getEmoteTooltips() const;
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
|
||||
private:
|
||||
MessageLayoutElement *makeImageLayoutElement(
|
||||
const std::vector<ImagePtr> &image, const std::vector<QSize> &sizes,
|
||||
|
@ -416,6 +437,8 @@ public:
|
|||
|
||||
EmotePtr getEmote() const;
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
|
||||
protected:
|
||||
virtual MessageLayoutElement *makeImageLayoutElement(const ImagePtr &image,
|
||||
const QSize &size);
|
||||
|
@ -429,6 +452,8 @@ class ModBadgeElement : public BadgeElement
|
|||
public:
|
||||
ModBadgeElement(const EmotePtr &data, MessageElementFlags flags_);
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
|
||||
protected:
|
||||
MessageLayoutElement *makeImageLayoutElement(const ImagePtr &image,
|
||||
const QSize &size) override;
|
||||
|
@ -439,6 +464,8 @@ class VipBadgeElement : public BadgeElement
|
|||
public:
|
||||
VipBadgeElement(const EmotePtr &data, MessageElementFlags flags_);
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
|
||||
protected:
|
||||
MessageLayoutElement *makeImageLayoutElement(const ImagePtr &image,
|
||||
const QSize &size) override;
|
||||
|
@ -450,6 +477,8 @@ public:
|
|||
FfzBadgeElement(const EmotePtr &data, MessageElementFlags flags_,
|
||||
QColor color_);
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
|
||||
protected:
|
||||
MessageLayoutElement *makeImageLayoutElement(const ImagePtr &image,
|
||||
const QSize &size) override;
|
||||
|
@ -460,7 +489,8 @@ protected:
|
|||
class TimestampElement : public MessageElement
|
||||
{
|
||||
public:
|
||||
TimestampElement(QTime time_ = QTime::currentTime());
|
||||
TimestampElement();
|
||||
TimestampElement(QTime time_);
|
||||
~TimestampElement() override = default;
|
||||
|
||||
void addToContainer(MessageLayoutContainer &container,
|
||||
|
@ -468,6 +498,8 @@ public:
|
|||
|
||||
TextElement *formatTime(const QTime &time);
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
|
||||
private:
|
||||
QTime time_;
|
||||
std::unique_ptr<TextElement> element_;
|
||||
|
@ -483,6 +515,8 @@ public:
|
|||
|
||||
void addToContainer(MessageLayoutContainer &container,
|
||||
MessageElementFlags flags) override;
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
};
|
||||
|
||||
// Forces a linebreak
|
||||
|
@ -493,6 +527,8 @@ public:
|
|||
|
||||
void addToContainer(MessageLayoutContainer &container,
|
||||
MessageElementFlags flags) override;
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
};
|
||||
|
||||
// Image element which will pick the quality of the image based on ui scale
|
||||
|
@ -504,6 +540,8 @@ public:
|
|||
void addToContainer(MessageLayoutContainer &container,
|
||||
MessageElementFlags flags) override;
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
|
||||
private:
|
||||
ImageSet images_;
|
||||
};
|
||||
|
@ -515,6 +553,13 @@ public:
|
|||
|
||||
void addToContainer(MessageLayoutContainer &container,
|
||||
MessageElementFlags flags) override;
|
||||
|
||||
QJsonObject toJson() const override;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<chatterino::MessageElementFlag> {
|
||||
static constexpr bool is_flags = true; // NOLINT(readability-identifier-*)
|
||||
};
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
#include "messages/MessageThread.hpp"
|
||||
|
||||
#include "common/Literals.hpp"
|
||||
#include "messages/Message.hpp"
|
||||
#include "util/DebugCount.hpp"
|
||||
#include "util/QMagicEnum.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
using namespace literals;
|
||||
|
||||
MessageThread::MessageThread(std::shared_ptr<const Message> rootMessage)
|
||||
: rootMessageId_(rootMessage->id)
|
||||
, rootMessage_(std::move(rootMessage))
|
||||
|
@ -80,4 +88,29 @@ void MessageThread::markUnsubscribed()
|
|||
this->subscriptionUpdated();
|
||||
}
|
||||
|
||||
QJsonObject MessageThread::toJson() const
|
||||
{
|
||||
QJsonObject obj{
|
||||
{"rootId"_L1, this->rootMessageId_},
|
||||
{"subscription"_L1, qmagicenum::enumNameString(this->subscription_)},
|
||||
};
|
||||
|
||||
QJsonArray replies;
|
||||
for (const auto &msg : this->replies_)
|
||||
{
|
||||
auto locked = msg.lock();
|
||||
if (locked)
|
||||
{
|
||||
replies.append(locked->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
replies.append(QJsonValue::Null);
|
||||
}
|
||||
}
|
||||
obj["replies"_L1] = replies;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class QJsonObject;
|
||||
|
||||
namespace chatterino {
|
||||
struct Message;
|
||||
|
||||
|
@ -62,6 +64,8 @@ public:
|
|||
return replies_;
|
||||
}
|
||||
|
||||
QJsonObject toJson() const;
|
||||
|
||||
boost::signals2::signal<void()> subscriptionUpdated;
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "providers/twitch/ChannelPointReward.hpp"
|
||||
|
||||
#include "common/Literals.hpp"
|
||||
#include "messages/Image.hpp"
|
||||
|
||||
#include <QStringBuilder>
|
||||
|
@ -15,6 +16,8 @@ QString twitchChannelPointRewardUrl(const QString &file)
|
|||
|
||||
namespace chatterino {
|
||||
|
||||
using namespace literals;
|
||||
|
||||
ChannelPointReward::ChannelPointReward(const QJsonObject &redemption)
|
||||
{
|
||||
auto reward = redemption.value("reward").toObject();
|
||||
|
@ -113,4 +116,25 @@ ChannelPointReward::ChannelPointReward(const QJsonObject &redemption)
|
|||
}
|
||||
}
|
||||
|
||||
QJsonObject ChannelPointReward::toJson() const
|
||||
{
|
||||
return {
|
||||
{"id"_L1, this->id},
|
||||
{"channelId"_L1, this->channelId},
|
||||
{"title"_L1, this->title},
|
||||
{"cost"_L1, this->cost},
|
||||
{"image"_L1, this->image.toJson()},
|
||||
{"isUserInputRequired"_L1, this->isUserInputRequired},
|
||||
{"isBits"_L1, this->isBits},
|
||||
{"emoteId"_L1, this->emoteId},
|
||||
{"emoteName"_L1, this->emoteName},
|
||||
{"user"_L1,
|
||||
{{
|
||||
{"id"_L1, this->user.id},
|
||||
{"login"_L1, this->user.login},
|
||||
{"displayName"_L1, this->user.displayName},
|
||||
}}},
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -24,6 +24,8 @@ struct ChannelPointReward {
|
|||
QString login;
|
||||
QString displayName;
|
||||
} user;
|
||||
|
||||
QJsonObject toJson() const;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -256,40 +256,14 @@ void addHiddenContextMenuItems(QMenu *menu,
|
|||
});
|
||||
}
|
||||
|
||||
const auto *message = layout->getMessage();
|
||||
auto message = layout->getMessagePtr();
|
||||
|
||||
if (message != nullptr)
|
||||
if (message)
|
||||
{
|
||||
QJsonDocument jsonDocument;
|
||||
|
||||
QJsonObject jsonObject;
|
||||
|
||||
jsonObject["id"] = message->id;
|
||||
jsonObject["searchText"] = message->searchText;
|
||||
jsonObject["messageText"] = message->messageText;
|
||||
jsonObject["flags"] = qmagicenum::enumFlagsName(message->flags.value());
|
||||
if (message->reward)
|
||||
{
|
||||
QJsonObject reward;
|
||||
reward["id"] = message->reward->id;
|
||||
reward["title"] = message->reward->title;
|
||||
reward["cost"] = message->reward->cost;
|
||||
reward["isUserInputRequired"] =
|
||||
message->reward->isUserInputRequired;
|
||||
jsonObject["reward"] = reward;
|
||||
}
|
||||
else
|
||||
{
|
||||
jsonObject["reward"] = QJsonValue();
|
||||
}
|
||||
|
||||
jsonDocument.setObject(jsonObject);
|
||||
|
||||
auto jsonString =
|
||||
jsonDocument.toJson(QJsonDocument::JsonFormat::Indented);
|
||||
|
||||
menu->addAction("Copy message &JSON", [jsonString] {
|
||||
crossPlatformCopy(jsonString);
|
||||
menu->addAction("Copy message &JSON", [message] {
|
||||
auto jsonString = QJsonDocument{message->toJson()}.toJson(
|
||||
QJsonDocument::Indented);
|
||||
crossPlatformCopy(QString::fromUtf8(jsonString));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue