mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
categorized emtotepopup
This commit is contained in:
parent
09b8a9d821
commit
c719bb6b74
55 changed files with 420 additions and 604 deletions
|
@ -233,7 +233,6 @@ SOURCES += \
|
|||
src/providers/twitch/PubsubClient.cpp \
|
||||
src/providers/twitch/TwitchApi.cpp \
|
||||
src/messages/Emote.cpp \
|
||||
src/messages/EmoteMap.cpp \
|
||||
src/messages/ImageSet.cpp \
|
||||
src/providers/bttv/BttvEmotes.cpp \
|
||||
src/providers/ffz/FfzEmotes.cpp \
|
||||
|
@ -250,7 +249,8 @@ SOURCES += \
|
|||
src/util/FunctionEventFilter.cpp \
|
||||
src/widgets/helper/EffectLabel.cpp \
|
||||
src/widgets/helper/Button.cpp \
|
||||
src/messages/MessageContainer.cpp
|
||||
src/messages/MessageContainer.cpp \
|
||||
src/debug/Benchmark.cpp
|
||||
|
||||
HEADERS += \
|
||||
src/Application.hpp \
|
||||
|
@ -258,7 +258,7 @@ HEADERS += \
|
|||
src/common/Common.hpp \
|
||||
src/common/CompletionModel.hpp \
|
||||
src/common/FlagsEnum.hpp \
|
||||
src/common/MutexValue.hpp \
|
||||
src/common/Atomic.hpp \
|
||||
src/common/NetworkCommon.hpp \
|
||||
src/common/NetworkData.hpp \
|
||||
src/common/NetworkManager.hpp \
|
||||
|
@ -305,7 +305,6 @@ HEADERS += \
|
|||
src/messages/MessageBuilder.hpp \
|
||||
src/messages/MessageColor.hpp \
|
||||
src/messages/MessageElement.hpp \
|
||||
src/messages/MessageParseArgs.hpp \
|
||||
src/messages/Selection.hpp \
|
||||
src/PrecompiledHeader.hpp \
|
||||
src/providers/emoji/Emojis.hpp \
|
||||
|
@ -414,7 +413,6 @@ HEADERS += \
|
|||
src/singletons/Updates.hpp \
|
||||
src/singletons/NativeMessaging.hpp \
|
||||
src/singletons/Theme.hpp \
|
||||
src/common/SimpleSignalVector.hpp \
|
||||
src/common/SignalVector.hpp \
|
||||
src/widgets/dialogs/LogsPopup.hpp \
|
||||
src/common/Singleton.hpp \
|
||||
|
@ -427,7 +425,6 @@ HEADERS += \
|
|||
src/providers/twitch/PubsubClient.hpp \
|
||||
src/providers/twitch/TwitchApi.hpp \
|
||||
src/messages/Emote.hpp \
|
||||
src/messages/EmoteMap.hpp \
|
||||
src/messages/EmoteCache.hpp \
|
||||
src/messages/ImageSet.hpp \
|
||||
src/common/Outcome.hpp \
|
||||
|
|
|
@ -113,11 +113,11 @@ void Application::initNm()
|
|||
void Application::initPubsub()
|
||||
{
|
||||
this->twitch.pubsub->signals_.whisper.sent.connect([](const auto &msg) {
|
||||
Log("WHISPER SENT LOL"); //
|
||||
log("WHISPER SENT LOL"); //
|
||||
});
|
||||
|
||||
this->twitch.pubsub->signals_.whisper.received.connect([](const auto &msg) {
|
||||
Log("WHISPER RECEIVED LOL"); //
|
||||
log("WHISPER RECEIVED LOL"); //
|
||||
});
|
||||
|
||||
this->twitch.pubsub->signals_.moderation.chatCleared.connect(
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
namespace chatterino {
|
||||
|
||||
template <typename T>
|
||||
class MutexValue : boost::noncopyable
|
||||
class Atomic : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
MutexValue()
|
||||
Atomic()
|
||||
{
|
||||
}
|
||||
|
||||
MutexValue(T &&val)
|
||||
Atomic(T &&val)
|
||||
: value_(val)
|
||||
{
|
||||
}
|
||||
|
@ -32,6 +32,13 @@ public:
|
|||
this->value_ = val;
|
||||
}
|
||||
|
||||
void set(T &&val)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(this->mutex_);
|
||||
|
||||
this->value_ = std::move(val);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::mutex mutex_;
|
||||
T value_;
|
|
@ -104,7 +104,7 @@ int CompletionModel::rowCount(const QModelIndex &) const
|
|||
|
||||
void CompletionModel::refresh()
|
||||
{
|
||||
Log("[CompletionModel:{}] Refreshing...]", this->channelName_);
|
||||
log("[CompletionModel:{}] Refreshing...]", this->channelName_);
|
||||
|
||||
auto app = getApp();
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ void NetworkRequest::execute()
|
|||
} break;
|
||||
|
||||
default: {
|
||||
Log("[Execute] Unhandled request type");
|
||||
log("[Execute] Unhandled request type");
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
@ -193,7 +193,8 @@ void NetworkRequest::doRequest()
|
|||
data->payload_);
|
||||
|
||||
case NetworkRequestType::Delete:
|
||||
return NetworkManager::accessManager.deleteResource(data->request_);
|
||||
return NetworkManager::accessManager.deleteResource(
|
||||
data->request_);
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
|
@ -201,13 +202,13 @@ void NetworkRequest::doRequest()
|
|||
}();
|
||||
|
||||
if (reply == nullptr) {
|
||||
Log("Unhandled request type");
|
||||
log("Unhandled request type");
|
||||
return;
|
||||
}
|
||||
|
||||
if (timer->isStarted()) {
|
||||
timer->onTimeout(worker, [reply, data]() {
|
||||
Log("Aborted!");
|
||||
log("Aborted!");
|
||||
reply->abort();
|
||||
if (data->onError_) {
|
||||
data->onError_(-2);
|
||||
|
@ -234,7 +235,7 @@ void NetworkRequest::doRequest()
|
|||
NetworkResult result(bytes);
|
||||
|
||||
DebugCount::increase("http request success");
|
||||
Log("starting {}", data->request_.url().toString());
|
||||
// log("starting {}", data->request_.url().toString());
|
||||
if (data->onSuccess_) {
|
||||
if (data->executeConcurrently)
|
||||
QtConcurrent::run(
|
||||
|
@ -243,7 +244,7 @@ void NetworkRequest::doRequest()
|
|||
else
|
||||
data->onSuccess_(result);
|
||||
}
|
||||
Log("finished {}", data->request_.url().toString());
|
||||
// log("finished {}", data->request_.url().toString());
|
||||
|
||||
reply->deleteLater();
|
||||
};
|
||||
|
|
|
@ -31,7 +31,7 @@ rapidjson::Document NetworkResult::parseRapidJson() const
|
|||
ret.Parse(this->data_.data(), this->data_.length());
|
||||
|
||||
if (result.Code() != rapidjson::kParseErrorNone) {
|
||||
Log("JSON parse error: {} ({})",
|
||||
log("JSON parse error: {} ({})",
|
||||
rapidjson::GetParseError_En(result.Code()), result.Offset());
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
template <typename TValue>
|
||||
class SimpleSignalVector
|
||||
{
|
||||
public:
|
||||
SimpleSignalVector &operator=(std::vector<TValue> &other)
|
||||
{
|
||||
this->data_ = other;
|
||||
|
||||
this->updated.invoke();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator std::vector<TValue> &()
|
||||
{
|
||||
return this->data_;
|
||||
}
|
||||
|
||||
pajlada::Signals::NoArgSignal updated;
|
||||
|
||||
private:
|
||||
std::vector<TValue> data_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
|
@ -46,16 +46,15 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
T *element_;
|
||||
std::mutex *mutex_;
|
||||
bool isValid_ = true;
|
||||
T *element_{};
|
||||
std::mutex *mutex_{};
|
||||
bool isValid_{true};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class UniqueAccess
|
||||
{
|
||||
public:
|
||||
// template <typename X = decltype(T())>
|
||||
UniqueAccess()
|
||||
: element_(T())
|
||||
{
|
||||
|
|
|
@ -78,7 +78,7 @@ void CommandController::save()
|
|||
{
|
||||
QFile textFile(this->filePath_);
|
||||
if (!textFile.open(QIODevice::WriteOnly)) {
|
||||
Log("[CommandController::saveCommands] Unable to open {} for writing",
|
||||
log("[CommandController::saveCommands] Unable to open {} for writing",
|
||||
this->filePath_);
|
||||
return;
|
||||
}
|
||||
|
|
21
src/debug/Benchmark.cpp
Normal file
21
src/debug/Benchmark.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "Benchmark.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
BenchmarkGuard::BenchmarkGuard(const QString &_name)
|
||||
: name_(_name)
|
||||
{
|
||||
timer_.start();
|
||||
}
|
||||
|
||||
BenchmarkGuard::~BenchmarkGuard()
|
||||
{
|
||||
log("{} {} ms", this->name_, float(timer_.nsecsElapsed()) / 1000000.0f);
|
||||
}
|
||||
|
||||
qreal BenchmarkGuard::getElapsedMs()
|
||||
{
|
||||
return qreal(timer_.nsecsElapsed()) / 1000000.0;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
|
@ -3,40 +3,20 @@
|
|||
#include "debug/Log.hpp"
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <boost/current_function.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#define BENCH(x) \
|
||||
QElapsedTimer x; \
|
||||
x.start();
|
||||
|
||||
#define MARK(x) \
|
||||
qDebug() << BOOST_CURRENT_FUNCTION << __LINE__ \
|
||||
<< static_cast<float>(x.nsecsElapsed()) / 1000000.0 << "ms";
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class BenchmarkGuard : boost::noncopyable
|
||||
{
|
||||
QElapsedTimer timer;
|
||||
QString name;
|
||||
|
||||
public:
|
||||
BenchmarkGuard(const QString &_name)
|
||||
: name(_name)
|
||||
{
|
||||
timer.start();
|
||||
}
|
||||
BenchmarkGuard(const QString &_name);
|
||||
~BenchmarkGuard();
|
||||
qreal getElapsedMs();
|
||||
|
||||
~BenchmarkGuard()
|
||||
{
|
||||
Log("{} {} ms", this->name, float(timer.nsecsElapsed()) / 1000000.0f);
|
||||
}
|
||||
|
||||
qreal getElapsedMs()
|
||||
{
|
||||
return qreal(timer.nsecsElapsed()) / 1000000.0;
|
||||
}
|
||||
private:
|
||||
QElapsedTimer timer_;
|
||||
QString name_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -8,17 +8,22 @@
|
|||
namespace chatterino {
|
||||
|
||||
template <typename... Args>
|
||||
inline void Log(const std::string &formatString, Args &&... args)
|
||||
inline void log(const std::string &formatString, Args &&... args)
|
||||
{
|
||||
qDebug().noquote() << QTime::currentTime().toString("hh:mm:ss.zzz")
|
||||
<< fS(formatString, std::forward<Args>(args)...).c_str();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void Warn(const std::string &formatString, Args &&... args)
|
||||
inline void log(const char *formatString, Args &&... args)
|
||||
{
|
||||
qWarning() << QTime::currentTime().toString("hh:mm:ss.zzz")
|
||||
<< fS(formatString, std::forward<Args>(args)...).c_str();
|
||||
log(std::string(formatString), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void log(const QString &formatString, Args &&... args)
|
||||
{
|
||||
log(formatString.toStdString(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -5,13 +5,15 @@
|
|||
|
||||
#include <QApplication>
|
||||
#include <QStringList>
|
||||
|
||||
#include <messages/Image.hpp>
|
||||
#include <memory>
|
||||
|
||||
using namespace chatterino;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
auto shared = std::make_shared<QString>();
|
||||
log(std::atomic_is_lock_free(&shared));
|
||||
|
||||
QApplication a(argc, argv);
|
||||
|
||||
// convert char** to QStringList
|
||||
|
|
|
@ -15,61 +15,13 @@ bool operator!=(const Emote &a, const Emote &b)
|
|||
return !(a == b);
|
||||
}
|
||||
|
||||
// EmotePtr Emote::create(const EmoteData2 &data)
|
||||
//{
|
||||
//}
|
||||
EmotePtr cachedOrMakeEmotePtr(Emote &&emote, const EmoteMap &cache)
|
||||
{
|
||||
// reuse old shared_ptr if nothing changed
|
||||
auto it = cache.find(emote.name);
|
||||
if (it != cache.end() && *it->second == emote) return it->second;
|
||||
|
||||
// EmotePtr Emote::create(EmoteData2 &&data)
|
||||
//{
|
||||
//}
|
||||
|
||||
// Emote::Emote(EmoteData2 &&data)
|
||||
// : data_(data)
|
||||
//{
|
||||
//}
|
||||
//
|
||||
// Emote::Emote(const EmoteData2 &data)
|
||||
// : data_(data)
|
||||
//{
|
||||
//}
|
||||
//
|
||||
// const Url &Emote::getHomePage() const
|
||||
//{
|
||||
// return this->data_.homePage;
|
||||
//}
|
||||
//
|
||||
// const EmoteName &Emote::getName() const
|
||||
//{
|
||||
// return this->data_.name;
|
||||
//}
|
||||
//
|
||||
// const Tooltip &Emote::getTooltip() const
|
||||
//{
|
||||
// return this->data_.tooltip;
|
||||
//}
|
||||
//
|
||||
// const ImageSet &Emote::getImages() const
|
||||
//{
|
||||
// return this->data_.images;
|
||||
//}
|
||||
//
|
||||
// const QString &Emote::getCopyString() const
|
||||
//{
|
||||
// return this->data_.name.string;
|
||||
//}
|
||||
//
|
||||
// bool Emote::operator==(const Emote &other) const
|
||||
//{
|
||||
// auto &a = this->data_;
|
||||
// auto &b = other.data_;
|
||||
//
|
||||
// return std::tie(a.homePage, a.name, a.tooltip, a.images) ==
|
||||
// std::tie(b.homePage, b.name, b.tooltip, b.images);
|
||||
//}
|
||||
//
|
||||
// bool Emote::operator!=(const Emote &other) const
|
||||
//{
|
||||
// return !this->operator==(other);
|
||||
//}
|
||||
return std::make_shared<Emote>(std::move(emote));
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -37,4 +37,6 @@ using EmoteIdMap = std::unordered_map<EmoteId, EmotePtr>;
|
|||
using WeakEmoteMap = std::unordered_map<EmoteName, std::weak_ptr<const Emote>>;
|
||||
using WeakEmoteIdMap = std::unordered_map<EmoteId, std::weak_ptr<const Emote>>;
|
||||
|
||||
EmotePtr cachedOrMakeEmotePtr(Emote &&emote, const EmoteMap &cache);
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
#include "EmoteMap.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
// EmoteData::EmoteData(Image *image)
|
||||
// : image1x(image)
|
||||
//{
|
||||
//}
|
||||
|
||||
//// Emotes must have a 1x image to be valid
|
||||
// bool EmoteData::isValid() const
|
||||
//{
|
||||
// return this->image1x != nullptr;
|
||||
//}
|
||||
|
||||
// Image *EmoteData::getImage(float scale) const
|
||||
//{
|
||||
// int quality = getApp()->settings->preferredEmoteQuality;
|
||||
|
||||
// if (quality == 0) {
|
||||
// scale *= getApp()->settings->emoteScale.getValue();
|
||||
// quality = [&] {
|
||||
// if (scale <= 1) return 1;
|
||||
// if (scale <= 2) return 2;
|
||||
// return 3;
|
||||
// }();
|
||||
// }
|
||||
|
||||
// Image *_image;
|
||||
// if (quality == 3 && this->image3x != nullptr) {
|
||||
// _image = this->image3x;
|
||||
// } else if (quality >= 2 && this->image2x != nullptr) {
|
||||
// _image = this->image2x;
|
||||
// } else {
|
||||
// _image = this->image1x;
|
||||
// }
|
||||
|
||||
// return _image;
|
||||
//}
|
||||
|
||||
} // namespace chatterino
|
|
@ -1,20 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "boost/optional.hpp"
|
||||
#include "messages/Emote.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
// class EmoteMap
|
||||
//{
|
||||
// public:
|
||||
// void add(Emote emote);
|
||||
// void remove(const Emote &emote);
|
||||
// void remove(const QString &name);
|
||||
|
||||
// private:
|
||||
//};
|
||||
|
||||
// using EmoteMap = ConcurrentMap<QString, EmoteData>;
|
||||
|
||||
} // namespace chatterino
|
|
@ -78,7 +78,7 @@ QVector<Frame<QImage>> readFrames(QImageReader &reader, const Url &url)
|
|||
QVector<Frame<QImage>> frames;
|
||||
|
||||
if (reader.imageCount() == 0) {
|
||||
Log("Error while reading image {}: '{}'", url.string,
|
||||
log("Error while reading image {}: '{}'", url.string,
|
||||
reader.errorString());
|
||||
return frames;
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ QVector<Frame<QImage>> readFrames(QImageReader &reader, const Url &url)
|
|||
}
|
||||
|
||||
if (frames.size() == 0) {
|
||||
Log("Error while reading image {}: '{}'", url.string,
|
||||
log("Error while reading image {}: '{}'", url.string,
|
||||
reader.errorString());
|
||||
}
|
||||
|
||||
|
@ -200,7 +200,7 @@ Image::Image(const Url &url, qreal scale)
|
|||
|
||||
Image::Image(const QPixmap &pixmap, qreal scale)
|
||||
: scale_(scale)
|
||||
, frames_(QVector<Frame<QPixmap>>{Frame<QPixmap>{pixmap}})
|
||||
, frames_(QVector<Frame<QPixmap>>{Frame<QPixmap>{pixmap, 1}})
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,14 @@ const TimeoutMessageTag timeoutMessage{};
|
|||
|
||||
MessagePtr makeSystemMessage(const QString &text);
|
||||
|
||||
struct MessageParseArgs {
|
||||
bool disablePingSounds = false;
|
||||
bool isReceivedWhisper = false;
|
||||
bool isSentWhisper = false;
|
||||
bool trimSubscriberUsername = false;
|
||||
bool isStaffOrBroadcaster = false;
|
||||
};
|
||||
|
||||
class MessageBuilder
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -2,12 +2,5 @@
|
|||
|
||||
namespace chatterino {
|
||||
|
||||
struct MessageParseArgs {
|
||||
bool disablePingSounds = false;
|
||||
bool isReceivedWhisper = false;
|
||||
bool isSentWhisper = false;
|
||||
bool trimSubscriberUsername = false;
|
||||
bool isStaffOrBroadcaster = false;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -35,7 +35,7 @@ struct SelectionItem {
|
|||
|
||||
bool operator>(const SelectionItem &b) const
|
||||
{
|
||||
return b.operator<(*this);
|
||||
return this->operator!=(b) && b.operator<(*this);
|
||||
}
|
||||
|
||||
bool operator==(const SelectionItem &b) const
|
||||
|
|
|
@ -31,13 +31,10 @@ public:
|
|||
|
||||
const Message *getMessage();
|
||||
|
||||
// Height
|
||||
int getHeight() const;
|
||||
|
||||
// Flags
|
||||
MessageLayoutFlags flags;
|
||||
|
||||
// Layout
|
||||
bool layout(int width, float scale_, MessageElementFlags flags);
|
||||
|
||||
// Painting
|
||||
|
|
|
@ -126,7 +126,8 @@ void MessageLayoutContainer::breakLine()
|
|||
int xOffset = 0;
|
||||
|
||||
if (this->flags_.has(MessageFlag::Centered) && this->elements_.size() > 0) {
|
||||
xOffset = (width_ - this->elements_.at(this->elements_.size() - 1)
|
||||
xOffset = (width_ - this->elements_.at(0)->getRect().left() -
|
||||
this->elements_.at(this->elements_.size() - 1)
|
||||
->getRect()
|
||||
.right()) /
|
||||
2;
|
||||
|
|
|
@ -10,9 +10,7 @@
|
|||
#include <QThread>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
namespace {
|
||||
|
||||
Url getEmoteLink(QString urlTemplate, const EmoteId &id,
|
||||
const QString &emoteScale)
|
||||
{
|
||||
|
@ -21,72 +19,14 @@ Url getEmoteLink(QString urlTemplate, const EmoteId &id,
|
|||
return {urlTemplate.replace("{{id}}", id.string)
|
||||
.replace("{{image}}", emoteScale)};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AccessGuard<const EmoteMap> BttvEmotes::accessGlobalEmotes() const
|
||||
{
|
||||
return this->globalEmotes_.accessConst();
|
||||
}
|
||||
|
||||
boost::optional<EmotePtr> BttvEmotes::getGlobalEmote(const EmoteName &name)
|
||||
{
|
||||
auto emotes = this->globalEmotes_.access();
|
||||
auto it = emotes->find(name);
|
||||
|
||||
if (it == emotes->end()) return boost::none;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// FOURTF: never returns anything
|
||||
// boost::optional<EmotePtr> BttvEmotes::getEmote(const EmoteId &id)
|
||||
//{
|
||||
// auto cache = this->channelEmoteCache_.access();
|
||||
// auto it = cache->find(id);
|
||||
//
|
||||
// if (it != cache->end()) {
|
||||
// auto shared = it->second.lock();
|
||||
// if (shared) {
|
||||
// return shared;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return boost::none;
|
||||
//}
|
||||
|
||||
void BttvEmotes::loadGlobalEmotes()
|
||||
{
|
||||
auto request = NetworkRequest(QString(globalEmoteApiUrl));
|
||||
|
||||
request.setCaller(QThread::currentThread());
|
||||
request.setTimeout(30000);
|
||||
request.onSuccess([this](auto result) -> Outcome {
|
||||
// if (auto shared = weak.lock()) {
|
||||
auto currentEmotes = this->globalEmotes_.access();
|
||||
|
||||
auto pair = this->parseGlobalEmotes(result.parseJson(), *currentEmotes);
|
||||
|
||||
if (pair.first) {
|
||||
*currentEmotes = std::move(pair.second);
|
||||
}
|
||||
|
||||
return pair.first;
|
||||
// }
|
||||
return Failure;
|
||||
});
|
||||
|
||||
request.execute();
|
||||
}
|
||||
|
||||
std::pair<Outcome, EmoteMap> BttvEmotes::parseGlobalEmotes(
|
||||
const QJsonObject &jsonRoot, const EmoteMap ¤tEmotes)
|
||||
std::pair<Outcome, EmoteMap> parseGlobalEmotes(const QJsonObject &jsonRoot,
|
||||
const EmoteMap ¤tEmotes)
|
||||
{
|
||||
auto emotes = EmoteMap();
|
||||
auto jsonEmotes = jsonRoot.value("emotes").toArray();
|
||||
auto urlTemplate =
|
||||
QString("https:" + jsonRoot.value("urlTemplate").toString());
|
||||
auto urlTemplate = qS("https:") + jsonRoot.value("urlTemplate").toString();
|
||||
|
||||
for (const QJsonValue &jsonEmote : jsonEmotes) {
|
||||
for (auto jsonEmote : jsonEmotes) {
|
||||
auto id = EmoteId{jsonEmote.toObject().value("id").toString()};
|
||||
auto name = EmoteName{jsonEmote.toObject().value("code").toString()};
|
||||
|
||||
|
@ -99,16 +39,49 @@ std::pair<Outcome, EmoteMap> BttvEmotes::parseGlobalEmotes(
|
|||
Tooltip{name.string + "<br />Global Bttv Emote"},
|
||||
Url{"https://manage.betterttv.net/emotes/" + id.string}});
|
||||
|
||||
auto it = currentEmotes.find(name);
|
||||
if (it != currentEmotes.end() && *it->second == emote) {
|
||||
// reuse old shared_ptr if nothing changed
|
||||
emotes[name] = it->second;
|
||||
} else {
|
||||
emotes[name] = std::make_shared<Emote>(std::move(emote));
|
||||
}
|
||||
emotes[name] = cachedOrMakeEmotePtr(std::move(emote), currentEmotes);
|
||||
}
|
||||
|
||||
return {Success, std::move(emotes)};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
BttvEmotes::BttvEmotes()
|
||||
: global_(std::make_shared<EmoteMap>())
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<const EmoteMap> BttvEmotes::global() const
|
||||
{
|
||||
return this->global_.get();
|
||||
}
|
||||
|
||||
boost::optional<EmotePtr> BttvEmotes::global(const EmoteName &name) const
|
||||
{
|
||||
auto emotes = this->global_.get();
|
||||
auto it = emotes->find(name);
|
||||
|
||||
if (it == emotes->end()) return boost::none;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void BttvEmotes::loadGlobal()
|
||||
{
|
||||
auto request = NetworkRequest(QString(globalEmoteApiUrl));
|
||||
|
||||
request.setCaller(QThread::currentThread());
|
||||
request.setTimeout(30000);
|
||||
|
||||
request.onSuccess([this](auto result) -> Outcome {
|
||||
auto emotes = this->global_.get();
|
||||
auto pair = parseGlobalEmotes(result.parseJson(), *emotes);
|
||||
if (pair.first)
|
||||
this->global_.set(
|
||||
std::make_shared<EmoteMap>(std::move(pair.second)));
|
||||
return pair.first;
|
||||
});
|
||||
|
||||
request.execute();
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -1,33 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "common/UniqueAccess.hpp"
|
||||
#include "common/Atomic.hpp"
|
||||
#include "messages/Emote.hpp"
|
||||
#include "messages/EmoteCache.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class BttvEmotes final : std::enable_shared_from_this<BttvEmotes>
|
||||
class BttvEmotes final
|
||||
{
|
||||
static constexpr const char *globalEmoteApiUrl =
|
||||
"https://api.betterttv.net/2/emotes";
|
||||
|
||||
public:
|
||||
// BttvEmotes();
|
||||
BttvEmotes();
|
||||
|
||||
AccessGuard<const EmoteMap> accessGlobalEmotes() const;
|
||||
boost::optional<EmotePtr> getGlobalEmote(const EmoteName &name);
|
||||
boost::optional<EmotePtr> getEmote(const EmoteId &id);
|
||||
|
||||
void loadGlobalEmotes();
|
||||
std::shared_ptr<const EmoteMap> global() const;
|
||||
boost::optional<EmotePtr> global(const EmoteName &name) const;
|
||||
void loadGlobal();
|
||||
|
||||
private:
|
||||
std::pair<Outcome, EmoteMap> parseGlobalEmotes(
|
||||
const QJsonObject &jsonRoot, const EmoteMap ¤tEmotes);
|
||||
|
||||
UniqueAccess<EmoteMap> globalEmotes_;
|
||||
// UniqueAccess<WeakEmoteIdMap> channelEmoteCache_;
|
||||
Atomic<std::shared_ptr<const EmoteMap>> global_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -118,7 +118,7 @@ void Emojis::loadEmojis()
|
|||
rapidjson::ParseResult result = root.Parse(data.toUtf8(), data.length());
|
||||
|
||||
if (result.Code() != rapidjson::kParseErrorNone) {
|
||||
Log("JSON parse error: {} ({})",
|
||||
log("JSON parse error: {} ({})",
|
||||
rapidjson::GetParseError_En(result.Code()), result.Offset());
|
||||
return;
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ void Emojis::loadEmojis()
|
|||
|
||||
auto toneNameIt = toneNames.find(tone);
|
||||
if (toneNameIt == toneNames.end()) {
|
||||
Log("Tone with key {} does not exist in tone names map",
|
||||
log("Tone with key {} does not exist in tone names map",
|
||||
tone);
|
||||
continue;
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ void Emojis::loadEmojiSet()
|
|||
auto app = getApp();
|
||||
|
||||
app->settings->emojiSet.connect([=](const auto &emojiSet, auto) {
|
||||
Log("Using emoji set {}", emojiSet);
|
||||
log("Using emoji set {}", emojiSet);
|
||||
this->emojis.each([=](const auto &name,
|
||||
std::shared_ptr<EmojiData> &emoji) {
|
||||
QString emojiSetToUse = emojiSet;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "common/SimpleSignalVector.hpp"
|
||||
#include "messages/Emote.hpp"
|
||||
#include "util/ConcurrentMap.hpp"
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ Url getEmoteLink(const QJsonObject &urls, const QString &emoteScale)
|
|||
|
||||
return {"https:" + emote.toString()};
|
||||
}
|
||||
|
||||
void fillInEmoteData(const QJsonObject &urls, const EmoteName &name,
|
||||
const QString &tooltip, Emote &emoteData)
|
||||
{
|
||||
|
@ -34,52 +33,11 @@ void fillInEmoteData(const QJsonObject &urls, const EmoteName &name,
|
|||
Image::fromUrl(url3x, 0.25)};
|
||||
emoteData.tooltip = {tooltip};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
AccessGuard<const EmoteCache<EmoteName>> FfzEmotes::accessGlobalEmotes() const
|
||||
{
|
||||
return this->globalEmotes_.accessConst();
|
||||
}
|
||||
|
||||
boost::optional<EmotePtr> FfzEmotes::getEmote(const EmoteId &id)
|
||||
{
|
||||
auto cache = this->channelEmoteCache_.access();
|
||||
auto it = cache->find(id);
|
||||
|
||||
if (it != cache->end()) {
|
||||
auto shared = it->second.lock();
|
||||
if (shared) {
|
||||
return shared;
|
||||
}
|
||||
}
|
||||
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
boost::optional<EmotePtr> FfzEmotes::getGlobalEmote(const EmoteName &name)
|
||||
{
|
||||
return this->globalEmotes_.access()->get(name);
|
||||
}
|
||||
|
||||
void FfzEmotes::loadGlobalEmotes()
|
||||
{
|
||||
QString url("https://api.frankerfacez.com/v1/set/global");
|
||||
|
||||
NetworkRequest request(url);
|
||||
request.setCaller(QThread::currentThread());
|
||||
request.setTimeout(30000);
|
||||
request.onSuccess([this](auto result) -> Outcome {
|
||||
return this->parseGlobalEmotes(result.parseJson());
|
||||
});
|
||||
|
||||
request.execute();
|
||||
}
|
||||
|
||||
Outcome FfzEmotes::parseGlobalEmotes(const QJsonObject &jsonRoot)
|
||||
std::pair<Outcome, EmoteMap> parseGlobalEmotes(const QJsonObject &jsonRoot,
|
||||
const EmoteMap ¤tEmotes)
|
||||
{
|
||||
auto jsonSets = jsonRoot.value("sets").toObject();
|
||||
auto emotes = this->globalEmotes_.access();
|
||||
auto replacement = emotes->makeReplacment();
|
||||
auto emotes = EmoteMap();
|
||||
|
||||
for (auto jsonSet : jsonSets) {
|
||||
auto jsonEmotes = jsonSet.toObject().value("emoticons").toArray();
|
||||
|
@ -99,14 +57,54 @@ Outcome FfzEmotes::parseGlobalEmotes(const QJsonObject &jsonRoot)
|
|||
.arg(id.string)
|
||||
.arg(name.string)};
|
||||
|
||||
replacement.add(name, emote);
|
||||
emotes[name] =
|
||||
cachedOrMakeEmotePtr(std::move(emote), currentEmotes);
|
||||
}
|
||||
}
|
||||
|
||||
return Success;
|
||||
return {Success, std::move(emotes)};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
FfzEmotes::FfzEmotes()
|
||||
: global_(std::make_shared<EmoteMap>())
|
||||
{
|
||||
}
|
||||
|
||||
void FfzEmotes::loadChannelEmotes(const QString &channelName,
|
||||
std::shared_ptr<const EmoteMap> FfzEmotes::global() const
|
||||
{
|
||||
return this->global_.get();
|
||||
}
|
||||
|
||||
boost::optional<EmotePtr> FfzEmotes::global(const EmoteName &name) const
|
||||
{
|
||||
auto emotes = this->global_.get();
|
||||
auto it = emotes->find(name);
|
||||
if (it != emotes->end()) return it->second;
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
void FfzEmotes::loadGlobal()
|
||||
{
|
||||
QString url("https://api.frankerfacez.com/v1/set/global");
|
||||
|
||||
NetworkRequest request(url);
|
||||
request.setCaller(QThread::currentThread());
|
||||
request.setTimeout(30000);
|
||||
|
||||
request.onSuccess([this](auto result) -> Outcome {
|
||||
auto emotes = this->global();
|
||||
auto pair = parseGlobalEmotes(result.parseJson(), *emotes);
|
||||
if (pair.first)
|
||||
this->global_.set(
|
||||
std::make_shared<EmoteMap>(std::move(pair.second)));
|
||||
return pair.first;
|
||||
});
|
||||
|
||||
request.execute();
|
||||
}
|
||||
|
||||
void FfzEmotes::loadChannel(const QString &channelName,
|
||||
std::function<void(EmoteMap &&)> callback)
|
||||
{
|
||||
// printf("[FFZEmotes] Reload FFZ Channel Emotes for channel %s\n",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include "common/UniqueAccess.hpp"
|
||||
#include "common/Atomic.hpp"
|
||||
#include "messages/Emote.hpp"
|
||||
#include "messages/EmoteCache.hpp"
|
||||
|
||||
|
@ -16,24 +16,17 @@ class FfzEmotes final : std::enable_shared_from_this<FfzEmotes>
|
|||
"https://api.betterttv.net/2/channels/";
|
||||
|
||||
public:
|
||||
// FfzEmotes();
|
||||
FfzEmotes();
|
||||
|
||||
static std::shared_ptr<FfzEmotes> create();
|
||||
std::shared_ptr<const EmoteMap> global() const;
|
||||
boost::optional<EmotePtr> global(const EmoteName &name) const;
|
||||
|
||||
AccessGuard<const EmoteCache<EmoteName>> accessGlobalEmotes() const;
|
||||
boost::optional<EmotePtr> getGlobalEmote(const EmoteName &name);
|
||||
boost::optional<EmotePtr> getEmote(const EmoteId &id);
|
||||
|
||||
void loadGlobalEmotes();
|
||||
void loadChannelEmotes(const QString &channelName,
|
||||
void loadGlobal();
|
||||
void loadChannel(const QString &channelName,
|
||||
std::function<void(EmoteMap &&)> callback);
|
||||
|
||||
protected:
|
||||
Outcome parseGlobalEmotes(const QJsonObject &jsonRoot);
|
||||
Outcome parseChannelEmotes(const QJsonObject &jsonRoot);
|
||||
|
||||
UniqueAccess<EmoteCache<EmoteName>> globalEmotes_;
|
||||
UniqueAccess<WeakEmoteIdMap> channelEmoteCache_;
|
||||
private:
|
||||
Atomic<std::shared_ptr<const EmoteMap>> global_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -131,7 +131,7 @@ std::shared_ptr<Channel> AbstractIrcServer::getOrAddChannel(
|
|||
chan->destroyed.connect([this, clojuresInCppAreShit] {
|
||||
// fourtf: issues when the server itself is destroyed
|
||||
|
||||
Log("[AbstractIrcServer::addChannel] {} was destroyed",
|
||||
log("[AbstractIrcServer::addChannel] {} was destroyed",
|
||||
clojuresInCppAreShit);
|
||||
this->channels.remove(clojuresInCppAreShit);
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ void IrcMessageHandler::handleClearChatMessage(Communi::IrcMessage *message)
|
|||
auto chan = app->twitch.server->getChannelOrEmpty(chanName);
|
||||
|
||||
if (chan->isEmpty()) {
|
||||
Log("[IrcMessageHandler:handleClearChatMessage] Twitch channel {} not "
|
||||
log("[IrcMessageHandler:handleClearChatMessage] Twitch channel {} not "
|
||||
"found",
|
||||
chanName);
|
||||
return;
|
||||
|
@ -209,7 +209,7 @@ void IrcMessageHandler::handleUserStateMessage(Communi::IrcMessage *message)
|
|||
void IrcMessageHandler::handleWhisperMessage(Communi::IrcMessage *message)
|
||||
{
|
||||
auto app = getApp();
|
||||
Log("Received whisper!");
|
||||
log("Received whisper!");
|
||||
MessageParseArgs args;
|
||||
|
||||
args.isReceivedWhisper = true;
|
||||
|
@ -326,7 +326,7 @@ void IrcMessageHandler::handleNoticeMessage(Communi::IrcNoticeMessage *message)
|
|||
auto channel = app->twitch.server->getChannelOrEmpty(channelName);
|
||||
|
||||
if (channel->isEmpty()) {
|
||||
Log("[IrcManager:handleNoticeMessage] Channel {} not found in channel "
|
||||
log("[IrcManager:handleNoticeMessage] Channel {} not found in channel "
|
||||
"manager ",
|
||||
channelName);
|
||||
return;
|
||||
|
@ -366,7 +366,7 @@ void IrcMessageHandler::handleWriteConnectionNoticeMessage(
|
|||
return;
|
||||
}
|
||||
|
||||
Log("Showing notice message from write connection with message id '{}'",
|
||||
log("Showing notice message from write connection with message id '{}'",
|
||||
msgID);
|
||||
}
|
||||
|
||||
|
|
|
@ -42,23 +42,23 @@ void PartialTwitchUser::getId(std::function<void(QString)> successCallback,
|
|||
request.onSuccess([successCallback](auto result) -> Outcome {
|
||||
auto root = result.parseJson();
|
||||
if (!root.value("users").isArray()) {
|
||||
Log("API Error while getting user id, users is not an array");
|
||||
log("API Error while getting user id, users is not an array");
|
||||
return Failure;
|
||||
}
|
||||
|
||||
auto users = root.value("users").toArray();
|
||||
if (users.size() != 1) {
|
||||
Log("API Error while getting user id, users array size is not 1");
|
||||
log("API Error while getting user id, users array size is not 1");
|
||||
return Failure;
|
||||
}
|
||||
if (!users[0].isObject()) {
|
||||
Log("API Error while getting user id, first user is not an object");
|
||||
log("API Error while getting user id, first user is not an object");
|
||||
return Failure;
|
||||
}
|
||||
auto firstUser = users[0].toObject();
|
||||
auto id = firstUser.value("_id");
|
||||
if (!id.isString()) {
|
||||
Log("API Error: while getting user id, first user object `_id` key "
|
||||
log("API Error: while getting user id, first user object `_id` key "
|
||||
"is not a "
|
||||
"string");
|
||||
return Failure;
|
||||
|
|
|
@ -109,7 +109,7 @@ void PubSubClient::handlePong()
|
|||
{
|
||||
assert(this->awaitingPong_);
|
||||
|
||||
Log("Got pong!");
|
||||
log("Got pong!");
|
||||
|
||||
this->awaitingPong_ = false;
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ void PubSubClient::ping()
|
|||
}
|
||||
|
||||
if (self->awaitingPong_) {
|
||||
Log("No pong respnose, disconnect!");
|
||||
log("No pong respnose, disconnect!");
|
||||
// TODO(pajlada): Label this connection as "disconnect me"
|
||||
}
|
||||
});
|
||||
|
@ -166,7 +166,7 @@ bool PubSubClient::send(const char *payload)
|
|||
websocketpp::frame::opcode::text, ec);
|
||||
|
||||
if (ec) {
|
||||
Log("Error sending message {}: {}", payload, ec.message());
|
||||
log("Error sending message {}: {}", payload, ec.message());
|
||||
// TODO(pajlada): Check which error code happened and maybe gracefully
|
||||
// handle it
|
||||
|
||||
|
@ -207,26 +207,26 @@ PubSub::PubSub()
|
|||
action.state = ModeChangedAction::State::On;
|
||||
|
||||
if (!data.HasMember("args")) {
|
||||
Log("Missing required args member");
|
||||
log("Missing required args member");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &args = data["args"];
|
||||
|
||||
if (!args.IsArray()) {
|
||||
Log("args member must be an array");
|
||||
log("args member must be an array");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Size() == 0) {
|
||||
Log("Missing duration argument in slowmode on");
|
||||
log("Missing duration argument in slowmode on");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &durationArg = args[0];
|
||||
|
||||
if (!durationArg.IsString()) {
|
||||
Log("Duration arg must be a string");
|
||||
log("Duration arg must be a string");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -314,7 +314,7 @@ PubSub::PubSub()
|
|||
return;
|
||||
}
|
||||
} catch (const std::runtime_error &ex) {
|
||||
Log("Error parsing moderation action: {}", ex.what());
|
||||
log("Error parsing moderation action: {}", ex.what());
|
||||
}
|
||||
|
||||
action.modded = false;
|
||||
|
@ -339,7 +339,7 @@ PubSub::PubSub()
|
|||
return;
|
||||
}
|
||||
} catch (const std::runtime_error &ex) {
|
||||
Log("Error parsing moderation action: {}", ex.what());
|
||||
log("Error parsing moderation action: {}", ex.what());
|
||||
}
|
||||
|
||||
action.modded = true;
|
||||
|
@ -380,7 +380,7 @@ PubSub::PubSub()
|
|||
|
||||
this->signals_.moderation.userBanned.invoke(action);
|
||||
} catch (const std::runtime_error &ex) {
|
||||
Log("Error parsing moderation action: {}", ex.what());
|
||||
log("Error parsing moderation action: {}", ex.what());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -410,7 +410,7 @@ PubSub::PubSub()
|
|||
|
||||
this->signals_.moderation.userBanned.invoke(action);
|
||||
} catch (const std::runtime_error &ex) {
|
||||
Log("Error parsing moderation action: {}", ex.what());
|
||||
log("Error parsing moderation action: {}", ex.what());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -436,7 +436,7 @@ PubSub::PubSub()
|
|||
|
||||
this->signals_.moderation.userUnbanned.invoke(action);
|
||||
} catch (const std::runtime_error &ex) {
|
||||
Log("Error parsing moderation action: {}", ex.what());
|
||||
log("Error parsing moderation action: {}", ex.what());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -462,7 +462,7 @@ PubSub::PubSub()
|
|||
|
||||
this->signals_.moderation.userUnbanned.invoke(action);
|
||||
} catch (const std::runtime_error &ex) {
|
||||
Log("Error parsing moderation action: {}", ex.what());
|
||||
log("Error parsing moderation action: {}", ex.what());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -493,7 +493,7 @@ void PubSub::addClient()
|
|||
auto con = this->websocketClient.get_connection(TWITCH_PUBSUB_URL, ec);
|
||||
|
||||
if (ec) {
|
||||
Log("Unable to establish connection: {}", ec.message());
|
||||
log("Unable to establish connection: {}", ec.message());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -512,7 +512,7 @@ void PubSub::listenToWhispers(std::shared_ptr<TwitchAccount> account)
|
|||
|
||||
std::string userID = account->getUserId().toStdString();
|
||||
|
||||
Log("Connection open!");
|
||||
log("Connection open!");
|
||||
websocketpp::lib::error_code ec;
|
||||
|
||||
std::vector<std::string> topics({"whispers." + userID});
|
||||
|
@ -520,7 +520,7 @@ void PubSub::listenToWhispers(std::shared_ptr<TwitchAccount> account)
|
|||
this->listen(createListenMessage(topics, account));
|
||||
|
||||
if (ec) {
|
||||
Log("Unable to send message to websocket server: {}", ec.message());
|
||||
log("Unable to send message to websocket server: {}", ec.message());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -544,11 +544,11 @@ void PubSub::listenToChannelModerationActions(
|
|||
std::string topic(fS("chat_moderator_actions.{}.{}", userID, channelID));
|
||||
|
||||
if (this->isListeningToTopic(topic)) {
|
||||
Log("We are already listening to topic {}", topic);
|
||||
log("We are already listening to topic {}", topic);
|
||||
return;
|
||||
}
|
||||
|
||||
Log("Listen to topic {}", topic);
|
||||
log("Listen to topic {}", topic);
|
||||
|
||||
this->listenToTopic(topic, account);
|
||||
}
|
||||
|
@ -564,18 +564,18 @@ void PubSub::listenToTopic(const std::string &topic,
|
|||
void PubSub::listen(rapidjson::Document &&msg)
|
||||
{
|
||||
if (this->tryListen(msg)) {
|
||||
Log("Successfully listened!");
|
||||
log("Successfully listened!");
|
||||
return;
|
||||
}
|
||||
|
||||
Log("Added to the back of the queue");
|
||||
log("Added to the back of the queue");
|
||||
this->requests.emplace_back(
|
||||
std::make_unique<rapidjson::Document>(std::move(msg)));
|
||||
}
|
||||
|
||||
bool PubSub::tryListen(rapidjson::Document &msg)
|
||||
{
|
||||
Log("tryListen with {} clients", this->clients.size());
|
||||
log("tryListen with {} clients", this->clients.size());
|
||||
for (const auto &p : this->clients) {
|
||||
const auto &client = p.second;
|
||||
if (client->listen(msg)) {
|
||||
|
@ -608,13 +608,13 @@ void PubSub::onMessage(websocketpp::connection_hdl hdl,
|
|||
rapidjson::ParseResult res = msg.Parse(payload.c_str());
|
||||
|
||||
if (!res) {
|
||||
Log("Error parsing message '{}' from PubSub: {}", payload,
|
||||
log("Error parsing message '{}' from PubSub: {}", payload,
|
||||
rapidjson::GetParseError_En(res.Code()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!msg.IsObject()) {
|
||||
Log("Error parsing message '{}' from PubSub. Root object is not an "
|
||||
log("Error parsing message '{}' from PubSub. Root object is not an "
|
||||
"object",
|
||||
payload);
|
||||
return;
|
||||
|
@ -623,7 +623,7 @@ void PubSub::onMessage(websocketpp::connection_hdl hdl,
|
|||
std::string type;
|
||||
|
||||
if (!rj::getSafe(msg, "type", type)) {
|
||||
Log("Missing required string member `type` in message root");
|
||||
log("Missing required string member `type` in message root");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -631,14 +631,14 @@ void PubSub::onMessage(websocketpp::connection_hdl hdl,
|
|||
this->handleListenResponse(msg);
|
||||
} else if (type == "MESSAGE") {
|
||||
if (!msg.HasMember("data")) {
|
||||
Log("Missing required object member `data` in message root");
|
||||
log("Missing required object member `data` in message root");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &data = msg["data"];
|
||||
|
||||
if (!data.IsObject()) {
|
||||
Log("Member `data` must be an object");
|
||||
log("Member `data` must be an object");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -654,7 +654,7 @@ void PubSub::onMessage(websocketpp::connection_hdl hdl,
|
|||
|
||||
client.second->handlePong();
|
||||
} else {
|
||||
Log("Unknown message type: {}", type);
|
||||
log("Unknown message type: {}", type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -699,7 +699,7 @@ PubSub::WebsocketContextPtr PubSub::onTLSInit(websocketpp::connection_hdl hdl)
|
|||
boost::asio::ssl::context::no_sslv2 |
|
||||
boost::asio::ssl::context::single_dh_use);
|
||||
} catch (const std::exception &e) {
|
||||
Log("Exception caught in OnTLSInit: {}", e.what());
|
||||
log("Exception caught in OnTLSInit: {}", e.what());
|
||||
}
|
||||
|
||||
return ctx;
|
||||
|
@ -714,12 +714,12 @@ void PubSub::handleListenResponse(const rapidjson::Document &msg)
|
|||
rj::getSafe(msg, "nonce", nonce);
|
||||
|
||||
if (error.empty()) {
|
||||
Log("Successfully listened to nonce {}", nonce);
|
||||
log("Successfully listened to nonce {}", nonce);
|
||||
// Nothing went wrong
|
||||
return;
|
||||
}
|
||||
|
||||
Log("PubSub error: {} on nonce {}", error, nonce);
|
||||
log("PubSub error: {} on nonce {}", error, nonce);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -729,14 +729,14 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData)
|
|||
QString topic;
|
||||
|
||||
if (!rj::getSafe(outerData, "topic", topic)) {
|
||||
Log("Missing required string member `topic` in outerData");
|
||||
log("Missing required string member `topic` in outerData");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string payload;
|
||||
|
||||
if (!rj::getSafe(outerData, "message", payload)) {
|
||||
Log("Expected string message in outerData");
|
||||
log("Expected string message in outerData");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -745,7 +745,7 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData)
|
|||
rapidjson::ParseResult res = msg.Parse(payload.c_str());
|
||||
|
||||
if (!res) {
|
||||
Log("Error parsing message '{}' from PubSub: {}", payload,
|
||||
log("Error parsing message '{}' from PubSub: {}", payload,
|
||||
rapidjson::GetParseError_En(res.Code()));
|
||||
return;
|
||||
}
|
||||
|
@ -754,7 +754,7 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData)
|
|||
std::string whisperType;
|
||||
|
||||
if (!rj::getSafe(msg, "type", whisperType)) {
|
||||
Log("Bad whisper data");
|
||||
log("Bad whisper data");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -765,7 +765,7 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData)
|
|||
} else if (whisperType == "thread") {
|
||||
// Handle thread?
|
||||
} else {
|
||||
Log("Invalid whisper type: {}", whisperType);
|
||||
log("Invalid whisper type: {}", whisperType);
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
@ -777,30 +777,30 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData)
|
|||
std::string moderationAction;
|
||||
|
||||
if (!rj::getSafe(data, "moderation_action", moderationAction)) {
|
||||
Log("Missing moderation action in data: {}", rj::stringify(data));
|
||||
log("Missing moderation action in data: {}", rj::stringify(data));
|
||||
return;
|
||||
}
|
||||
|
||||
auto handlerIt = this->moderationActionHandlers.find(moderationAction);
|
||||
|
||||
if (handlerIt == this->moderationActionHandlers.end()) {
|
||||
Log("No handler found for moderation action {}", moderationAction);
|
||||
log("No handler found for moderation action {}", moderationAction);
|
||||
return;
|
||||
}
|
||||
|
||||
// Invoke handler function
|
||||
handlerIt->second(data, topicParts[2]);
|
||||
} else {
|
||||
Log("Unknown topic: {}", topic);
|
||||
log("Unknown topic: {}", topic);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void PubSub::runThread()
|
||||
{
|
||||
Log("Start pubsub manager thread");
|
||||
log("Start pubsub manager thread");
|
||||
this->websocketClient.run();
|
||||
Log("Done with pubsub manager thread");
|
||||
log("Done with pubsub manager thread");
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -35,7 +35,7 @@ void runAfter(boost::asio::io_service &ioService, Duration duration,
|
|||
|
||||
timer->async_wait([timer, cb](const boost::system::error_code &ec) {
|
||||
if (ec) {
|
||||
Log("Error in runAfter: {}", ec.message());
|
||||
log("Error in runAfter: {}", ec.message());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ void runAfter(std::shared_ptr<boost::asio::steady_timer> timer,
|
|||
|
||||
timer->async_wait([timer, cb](const boost::system::error_code &ec) {
|
||||
if (ec) {
|
||||
Log("Error in runAfter: {}", ec.message());
|
||||
log("Error in runAfter: {}", ec.message());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ void TwitchAccount::loadIgnores()
|
|||
}
|
||||
TwitchUser ignoredUser;
|
||||
if (!rj::getSafe(userIt->value, ignoredUser)) {
|
||||
Log("Error parsing twitch user JSON {}",
|
||||
log("Error parsing twitch user JSON {}",
|
||||
rj::stringify(userIt->value));
|
||||
continue;
|
||||
}
|
||||
|
@ -368,13 +368,13 @@ std::set<TwitchUser> TwitchAccount::getIgnores() const
|
|||
|
||||
void TwitchAccount::loadEmotes()
|
||||
{
|
||||
Log("Loading Twitch emotes for user {}", this->getUserName());
|
||||
log("Loading Twitch emotes for user {}", this->getUserName());
|
||||
|
||||
const auto &clientID = this->getOAuthClient();
|
||||
const auto &oauthToken = this->getOAuthToken();
|
||||
|
||||
if (clientID.isEmpty() || oauthToken.isEmpty()) {
|
||||
Log("Missing Client ID or OAuth token");
|
||||
log("Missing Client ID or OAuth token");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -386,7 +386,7 @@ void TwitchAccount::loadEmotes()
|
|||
req.makeAuthorizedV5(this->getOAuthClient(), this->getOAuthToken());
|
||||
|
||||
req.onError([=](int errorCode) {
|
||||
Log("[TwitchAccount::loadEmotes] Error {}", errorCode);
|
||||
log("[TwitchAccount::loadEmotes] Error {}", errorCode);
|
||||
if (errorCode == 203) {
|
||||
// onFinished(FollowResult_NotFollowing);
|
||||
} else {
|
||||
|
@ -420,7 +420,7 @@ void TwitchAccount::parseEmotes(const rapidjson::Document &root)
|
|||
|
||||
auto emoticonSets = root.FindMember("emoticon_sets");
|
||||
if (emoticonSets == root.MemberEnd() || !emoticonSets->value.IsObject()) {
|
||||
Log("No emoticon_sets in load emotes response");
|
||||
log("No emoticon_sets in load emotes response");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -434,19 +434,19 @@ void TwitchAccount::parseEmotes(const rapidjson::Document &root)
|
|||
for (const rapidjson::Value &emoteJSON :
|
||||
emoteSetJSON.value.GetArray()) {
|
||||
if (!emoteJSON.IsObject()) {
|
||||
Log("Emote value was invalid");
|
||||
log("Emote value was invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t idNumber;
|
||||
if (!rj::getSafe(emoteJSON, "id", idNumber)) {
|
||||
Log("No ID key found in Emote value");
|
||||
log("No ID key found in Emote value");
|
||||
return;
|
||||
}
|
||||
|
||||
QString _code;
|
||||
if (!rj::getSafe(emoteJSON, "code", _code)) {
|
||||
Log("No code key found in Emote value");
|
||||
log("No code key found in Emote value");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -468,7 +468,7 @@ void TwitchAccount::parseEmotes(const rapidjson::Document &root)
|
|||
void TwitchAccount::loadEmoteSetData(std::shared_ptr<EmoteSet> emoteSet)
|
||||
{
|
||||
if (!emoteSet) {
|
||||
Log("null emote set sent");
|
||||
log("null emote set sent");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -486,7 +486,7 @@ void TwitchAccount::loadEmoteSetData(std::shared_ptr<EmoteSet> emoteSet)
|
|||
req.setUseQuickLoadCache(true);
|
||||
|
||||
req.onError([](int errorCode) -> bool {
|
||||
Log("Error code {} while loading emote set data", errorCode);
|
||||
log("Error code {} while loading emote set data", errorCode);
|
||||
return true;
|
||||
});
|
||||
|
||||
|
@ -507,16 +507,15 @@ void TwitchAccount::loadEmoteSetData(std::shared_ptr<EmoteSet> emoteSet)
|
|||
return Failure;
|
||||
}
|
||||
|
||||
Log("Loaded twitch emote set data for {}!", emoteSet->key);
|
||||
log("Loaded twitch emote set data for {}!", emoteSet->key);
|
||||
|
||||
if (type == "sub") {
|
||||
emoteSet->text =
|
||||
QString("Twitch Subscriber Emote (%1)").arg(channelName);
|
||||
} else {
|
||||
emoteSet->text =
|
||||
QString("Twitch Account Emote (%1)").arg(channelName);
|
||||
}
|
||||
auto name = channelName;
|
||||
name.detach();
|
||||
name[0] = name[0].toUpper();
|
||||
|
||||
emoteSet->text = name;
|
||||
|
||||
emoteSet->type = type;
|
||||
emoteSet->channelName = channelName;
|
||||
|
||||
return Success;
|
||||
|
|
|
@ -44,6 +44,7 @@ public:
|
|||
QString key;
|
||||
QString channelName;
|
||||
QString text;
|
||||
QString type;
|
||||
std::vector<TwitchEmote> emotes;
|
||||
};
|
||||
|
||||
|
|
|
@ -93,20 +93,20 @@ void TwitchAccountManager::reloadUsers()
|
|||
|
||||
switch (this->addUser(userData)) {
|
||||
case AddUserResponse::UserAlreadyExists: {
|
||||
Log("User {} already exists", userData.username);
|
||||
log("User {} already exists", userData.username);
|
||||
// Do nothing
|
||||
} break;
|
||||
case AddUserResponse::UserValuesUpdated: {
|
||||
Log("User {} already exists, and values updated!",
|
||||
log("User {} already exists, and values updated!",
|
||||
userData.username);
|
||||
if (userData.username == this->getCurrent()->getUserName()) {
|
||||
Log("It was the current user, so we need to reconnect "
|
||||
log("It was the current user, so we need to reconnect "
|
||||
"stuff!");
|
||||
this->currentUserChanged.invoke();
|
||||
}
|
||||
} break;
|
||||
case AddUserResponse::UserAdded: {
|
||||
Log("Added user {}", userData.username);
|
||||
log("Added user {}", userData.username);
|
||||
listUpdated = true;
|
||||
} break;
|
||||
}
|
||||
|
@ -125,12 +125,12 @@ void TwitchAccountManager::load()
|
|||
QString newUsername(QString::fromStdString(newValue));
|
||||
auto user = this->findUserByUsername(newUsername);
|
||||
if (user) {
|
||||
Log("[AccountManager:currentUsernameChanged] User successfully "
|
||||
log("[AccountManager:currentUsernameChanged] User successfully "
|
||||
"updated to {}",
|
||||
newUsername);
|
||||
this->currentUser_ = user;
|
||||
} else {
|
||||
Log("[AccountManager:currentUsernameChanged] User successfully "
|
||||
log("[AccountManager:currentUsernameChanged] User successfully "
|
||||
"updated to anonymous");
|
||||
this->currentUser_ = this->anonymousUser_;
|
||||
}
|
||||
|
|
|
@ -20,25 +20,25 @@ void TwitchApi::findUserId(const QString user,
|
|||
request.onSuccess([successCallback](auto result) mutable -> Outcome {
|
||||
auto root = result.parseJson();
|
||||
if (!root.value("users").isArray()) {
|
||||
Log("API Error while getting user id, users is not an array");
|
||||
log("API Error while getting user id, users is not an array");
|
||||
successCallback("");
|
||||
return Failure;
|
||||
}
|
||||
auto users = root.value("users").toArray();
|
||||
if (users.size() != 1) {
|
||||
Log("API Error while getting user id, users array size is not 1");
|
||||
log("API Error while getting user id, users array size is not 1");
|
||||
successCallback("");
|
||||
return Failure;
|
||||
}
|
||||
if (!users[0].isObject()) {
|
||||
Log("API Error while getting user id, first user is not an object");
|
||||
log("API Error while getting user id, first user is not an object");
|
||||
successCallback("");
|
||||
return Failure;
|
||||
}
|
||||
auto firstUser = users[0].toObject();
|
||||
auto id = firstUser.value("_id");
|
||||
if (!id.isString()) {
|
||||
Log("API Error: while getting user id, first user object `_id` key "
|
||||
log("API Error: while getting user id, first user object `_id` key "
|
||||
"is not a "
|
||||
"string");
|
||||
successCallback("");
|
||||
|
|
|
@ -56,7 +56,7 @@ TwitchChannel::TwitchChannel(const QString &name)
|
|||
, popoutPlayerUrl_("https://player.twitch.tv/?channel=" + name)
|
||||
, mod_(false)
|
||||
{
|
||||
Log("[TwitchChannel:{}] Opened", name);
|
||||
log("[TwitchChannel:{}] Opened", name);
|
||||
|
||||
// this->refreshChannelEmotes();
|
||||
// this->refreshViewerList();
|
||||
|
@ -116,7 +116,7 @@ void TwitchChannel::refreshChannelEmotes()
|
|||
if (auto shared = weak.lock()) //
|
||||
*this->bttvEmotes_.access() = emoteMap;
|
||||
});
|
||||
getApp()->emotes->ffz.loadChannelEmotes(
|
||||
getApp()->emotes->ffz.loadChannel(
|
||||
this->getName(), [this, weak = weakOf<Channel>(this)](auto &&emoteMap) {
|
||||
if (auto shared = weak.lock())
|
||||
*this->ffzEmotes_.access() = emoteMap;
|
||||
|
@ -136,7 +136,7 @@ void TwitchChannel::sendMessage(const QString &message)
|
|||
return;
|
||||
}
|
||||
|
||||
Log("[TwitchChannel:{}] Send message: {}", this->getName(), message);
|
||||
log("[TwitchChannel:{}] Send message: {}", this->getName(), message);
|
||||
|
||||
// Do last message processing
|
||||
QString parsedMessage = app->emotes->emojis.replaceShortCodes(message);
|
||||
|
@ -350,13 +350,13 @@ void TwitchChannel::refreshLiveStatus()
|
|||
auto roomID = this->getRoomId();
|
||||
|
||||
if (roomID.isEmpty()) {
|
||||
Log("[TwitchChannel:{}] Refreshing live status (Missing ID)",
|
||||
log("[TwitchChannel:{}] Refreshing live status (Missing ID)",
|
||||
this->getName());
|
||||
this->setLive(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Log("[TwitchChannel:{}] Refreshing live status", this->getName());
|
||||
log("[TwitchChannel:{}] Refreshing live status", this->getName());
|
||||
|
||||
QString url("https://api.twitch.tv/kraken/streams/" + roomID);
|
||||
|
||||
|
@ -381,12 +381,12 @@ void TwitchChannel::refreshLiveStatus()
|
|||
Outcome TwitchChannel::parseLiveStatus(const rapidjson::Document &document)
|
||||
{
|
||||
if (!document.IsObject()) {
|
||||
Log("[TwitchChannel:refreshLiveStatus] root is not an object");
|
||||
log("[TwitchChannel:refreshLiveStatus] root is not an object");
|
||||
return Failure;
|
||||
}
|
||||
|
||||
if (!document.HasMember("stream")) {
|
||||
Log("[TwitchChannel:refreshLiveStatus] Missing stream in root");
|
||||
log("[TwitchChannel:refreshLiveStatus] Missing stream in root");
|
||||
return Failure;
|
||||
}
|
||||
|
||||
|
@ -400,7 +400,7 @@ Outcome TwitchChannel::parseLiveStatus(const rapidjson::Document &document)
|
|||
|
||||
if (!stream.HasMember("viewers") || !stream.HasMember("game") ||
|
||||
!stream.HasMember("channel") || !stream.HasMember("created_at")) {
|
||||
Log("[TwitchChannel:refreshLiveStatus] Missing members in stream");
|
||||
log("[TwitchChannel:refreshLiveStatus] Missing members in stream");
|
||||
this->setLive(false);
|
||||
return Failure;
|
||||
}
|
||||
|
@ -408,7 +408,7 @@ Outcome TwitchChannel::parseLiveStatus(const rapidjson::Document &document)
|
|||
const rapidjson::Value &streamChannel = stream["channel"];
|
||||
|
||||
if (!streamChannel.IsObject() || !streamChannel.HasMember("status")) {
|
||||
Log("[TwitchChannel:refreshLiveStatus] Missing member \"status\" in "
|
||||
log("[TwitchChannel:refreshLiveStatus] Missing member \"status\" in "
|
||||
"channel");
|
||||
return Failure;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include "common/Channel.hpp"
|
||||
#include "common/Common.hpp"
|
||||
#include "common/MutexValue.hpp"
|
||||
#include "common/Atomic.hpp"
|
||||
#include "common/UniqueAccess.hpp"
|
||||
#include "messages/Emote.hpp"
|
||||
#include "singletons/Emotes.hpp"
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace chatterino {
|
|||
bool trimChannelName(const QString &channelName, QString &outChannelName)
|
||||
{
|
||||
if (channelName.length() < 3) {
|
||||
Log("channel name length below 3");
|
||||
log("channel name length below 3");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ bool TwitchMessageBuilder::isIgnored() const
|
|||
// TODO(pajlada): Do we need to check if the phrase is valid first?
|
||||
for (const auto &phrase : app->ignores->phrases.getVector()) {
|
||||
if (phrase.isMatch(this->originalMessage_)) {
|
||||
Log("Blocking message because it contains ignored phrase {}",
|
||||
log("Blocking message because it contains ignored phrase {}",
|
||||
phrase.getPattern());
|
||||
return true;
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ bool TwitchMessageBuilder::isIgnored() const
|
|||
for (const auto &user :
|
||||
app->accounts->twitch.getCurrent()->getIgnores()) {
|
||||
if (sourceUserID == user.id) {
|
||||
Log("Blocking message because it's from blocked user {}",
|
||||
log("Blocking message because it's from blocked user {}",
|
||||
user.name);
|
||||
return true;
|
||||
}
|
||||
|
@ -533,7 +533,7 @@ void TwitchMessageBuilder::parseHighlights(bool isPastMsg)
|
|||
if (!app->highlights->blacklistContains(this->ircMessage->nick())) {
|
||||
for (const HighlightPhrase &highlight : activeHighlights) {
|
||||
if (highlight.isMatch(this->originalMessage_)) {
|
||||
Log("Highlight because {} matches {}", this->originalMessage_,
|
||||
log("Highlight because {} matches {}", this->originalMessage_,
|
||||
highlight.getPattern());
|
||||
doHighlight = true;
|
||||
|
||||
|
@ -555,7 +555,7 @@ void TwitchMessageBuilder::parseHighlights(bool isPastMsg)
|
|||
}
|
||||
for (const HighlightPhrase &userHighlight : userHighlights) {
|
||||
if (userHighlight.isMatch(this->ircMessage->nick())) {
|
||||
Log("Highlight because user {} sent a message",
|
||||
log("Highlight because user {} sent a message",
|
||||
this->ircMessage->nick());
|
||||
doHighlight = true;
|
||||
|
||||
|
@ -638,12 +638,12 @@ Outcome TwitchMessageBuilder::tryAppendEmote(const EmoteName &name)
|
|||
auto flags = MessageElementFlags();
|
||||
auto emote = boost::optional<EmotePtr>{};
|
||||
|
||||
if ((emote = getApp()->emotes->bttv.getGlobalEmote(name))) {
|
||||
if ((emote = getApp()->emotes->bttv.global(name))) {
|
||||
flags = MessageElementFlag::BttvEmote;
|
||||
} else if (twitchChannel &&
|
||||
(emote = this->twitchChannel->getBttvEmote(name))) {
|
||||
flags = MessageElementFlag::BttvEmote;
|
||||
} else if ((emote = getApp()->emotes->ffz.getGlobalEmote(name))) {
|
||||
} else if ((emote = getApp()->emotes->ffz.global(name))) {
|
||||
flags = MessageElementFlag::FfzEmote;
|
||||
} else if (twitchChannel &&
|
||||
(emote = this->twitchChannel->getFfzEmote(name))) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "messages/MessageBuilder.hpp"
|
||||
#include "messages/MessageParseArgs.hpp"
|
||||
#include "singletons/Emotes.hpp"
|
||||
|
||||
#include <IrcMessage>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "common/MutexValue.hpp"
|
||||
#include "common/Atomic.hpp"
|
||||
#include "common/Singleton.hpp"
|
||||
#include "providers/irc/AbstractIrcServer.hpp"
|
||||
#include "providers/twitch/TwitchAccount.hpp"
|
||||
|
@ -29,7 +29,7 @@ public:
|
|||
|
||||
std::shared_ptr<Channel> getChannelOrEmptyByID(const QString &channelID);
|
||||
|
||||
MutexValue<QString> lastUserThatWhisperedMe;
|
||||
Atomic<QString> lastUserThatWhisperedMe;
|
||||
|
||||
const ChannelPtr whispersChannel;
|
||||
const ChannelPtr mentionsChannel;
|
||||
|
|
|
@ -15,8 +15,8 @@ void Emotes::initialize(Settings &settings, Paths &paths)
|
|||
[] { getApp()->accounts->twitch.getCurrent()->loadEmotes(); });
|
||||
|
||||
this->emojis.load();
|
||||
this->bttv.loadGlobalEmotes();
|
||||
this->ffz.loadGlobalEmotes();
|
||||
this->bttv.loadGlobal();
|
||||
this->ffz.loadGlobal();
|
||||
|
||||
this->gifTimer.initialize();
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ void Settings::saveSnapshot()
|
|||
|
||||
this->snapshot_.reset(d);
|
||||
|
||||
Log("hehe: {}", pajlada::Settings::SettingManager::stringify(*d));
|
||||
log("hehe: {}", pajlada::Settings::SettingManager::stringify(*d));
|
||||
}
|
||||
|
||||
void Settings::restoreSnapshot()
|
||||
|
@ -64,14 +64,14 @@ void Settings::restoreSnapshot()
|
|||
for (const auto &weakSetting : _settings) {
|
||||
auto setting = weakSetting.lock();
|
||||
if (!setting) {
|
||||
Log("Error stage 1 of loading");
|
||||
log("Error stage 1 of loading");
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *path = setting->getPath().c_str();
|
||||
|
||||
if (!snapshotObject.HasMember(path)) {
|
||||
Log("Error stage 2 of loading");
|
||||
log("Error stage 2 of loading");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -211,7 +211,7 @@ Window *WindowManager::windowAt(int index)
|
|||
if (index < 0 || (size_t)index >= this->windows_.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
Log("getting window at bad index {}", index);
|
||||
log("getting window at bad index {}", index);
|
||||
|
||||
return this->windows_.at(index);
|
||||
}
|
||||
|
|
|
@ -65,13 +65,13 @@ void LoggingChannel::openLogFile()
|
|||
this->baseDirectory + QDir::separator() + this->subDirectory;
|
||||
|
||||
if (!QDir().mkpath(directory)) {
|
||||
Log("Unable to create logging path");
|
||||
log("Unable to create logging path");
|
||||
return;
|
||||
}
|
||||
|
||||
// Open file handle to log file of current date
|
||||
QString fileName = directory + QDir::separator() + baseFileName;
|
||||
Log("Logging to {}", fileName);
|
||||
log("Logging to {}", fileName);
|
||||
this->fileHandle.setFileName(fileName);
|
||||
|
||||
this->fileHandle.open(QIODevice::Append);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
namespace chatterino {
|
||||
|
||||
template <typename... Args>
|
||||
auto fS(Args &&... args) -> decltype(fmt::format(std::forward<Args>(args)...))
|
||||
auto fS(Args &&... args)
|
||||
{
|
||||
return fmt::format(std::forward<Args>(args)...);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "Application.hpp"
|
||||
#include "controllers/accounts/AccountController.hpp"
|
||||
#include "debug/Benchmark.hpp"
|
||||
#include "messages/MessageBuilder.hpp"
|
||||
#include "providers/twitch/TwitchChannel.hpp"
|
||||
#include "widgets/Notebook.hpp"
|
||||
|
@ -11,36 +12,88 @@
|
|||
#include <QTabWidget>
|
||||
|
||||
namespace chatterino {
|
||||
namespace {
|
||||
auto makeTitleMessage(const QString &title)
|
||||
{
|
||||
MessageBuilder builder;
|
||||
builder.emplace<TextElement>(title, MessageElementFlag::Text);
|
||||
builder->flags.set(MessageFlag::Centered);
|
||||
return builder.release();
|
||||
}
|
||||
auto makeEmoteMessage(const EmoteMap &map)
|
||||
{
|
||||
MessageBuilder builder;
|
||||
builder->flags.set(MessageFlag::Centered);
|
||||
builder->flags.set(MessageFlag::DisableCompactEmotes);
|
||||
|
||||
for (const auto &emote : map) {
|
||||
builder
|
||||
.emplace<EmoteElement>(emote.second, MessageElementFlag::AlwaysShow)
|
||||
->setLink(Link(Link::InsertText, emote.first.string));
|
||||
}
|
||||
|
||||
return builder.release();
|
||||
}
|
||||
void addEmoteSets(std::vector<std::shared_ptr<TwitchAccount::EmoteSet>> sets,
|
||||
Channel &globalChannel, Channel &subChannel)
|
||||
{
|
||||
for (const auto &set : sets) {
|
||||
auto &channel = set->key == "0" ? globalChannel : subChannel;
|
||||
|
||||
// TITLE
|
||||
auto text =
|
||||
set->key == "0" || set->text.isEmpty() ? "Twitch" : set->text;
|
||||
channel.addMessage(makeTitleMessage(text));
|
||||
|
||||
// EMOTES
|
||||
MessageBuilder builder;
|
||||
builder->flags.set(MessageFlag::Centered);
|
||||
builder->flags.set(MessageFlag::DisableCompactEmotes);
|
||||
|
||||
for (const auto &emote : set->emotes) {
|
||||
builder
|
||||
.emplace<EmoteElement>(
|
||||
getApp()->emotes->twitch.getOrCreateEmote(emote.id,
|
||||
emote.name),
|
||||
MessageElementFlag::AlwaysShow)
|
||||
->setLink(Link(Link::InsertText, emote.name.string));
|
||||
}
|
||||
|
||||
channel.addMessage(builder.release());
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
EmotePopup::EmotePopup()
|
||||
: BaseWindow(nullptr, BaseWindow::EnableCustomFrame)
|
||||
{
|
||||
this->viewEmotes_ = new ChannelView();
|
||||
this->viewEmojis_ = new ChannelView();
|
||||
|
||||
this->viewEmotes_->setOverrideFlags(MessageElementFlags{
|
||||
MessageElementFlag::Default, MessageElementFlag::AlwaysShow,
|
||||
MessageElementFlag::EmoteImages});
|
||||
this->viewEmojis_->setOverrideFlags(MessageElementFlags{
|
||||
MessageElementFlag::Default, MessageElementFlag::AlwaysShow,
|
||||
MessageElementFlag::EmoteImages});
|
||||
|
||||
this->viewEmotes_->setEnableScrollingToBottom(false);
|
||||
this->viewEmojis_->setEnableScrollingToBottom(false);
|
||||
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
auto layout = new QVBoxLayout(this);
|
||||
this->getLayoutContainer()->setLayout(layout);
|
||||
|
||||
Notebook *notebook = new Notebook(this);
|
||||
auto notebook = new Notebook(this);
|
||||
layout->addWidget(notebook);
|
||||
layout->setMargin(0);
|
||||
|
||||
notebook->addPage(this->viewEmotes_, "Emotes");
|
||||
notebook->addPage(this->viewEmojis_, "Emojis");
|
||||
auto makeView = [&](QString tabTitle) {
|
||||
auto view = new ChannelView();
|
||||
|
||||
view->setOverrideFlags(MessageElementFlags{
|
||||
MessageElementFlag::Default, MessageElementFlag::AlwaysShow,
|
||||
MessageElementFlag::EmoteImages});
|
||||
view->setEnableScrollingToBottom(false);
|
||||
notebook->addPage(view, tabTitle);
|
||||
|
||||
return view;
|
||||
};
|
||||
|
||||
this->subEmotesView_ = makeView("Subs");
|
||||
this->channelEmotesView_ = makeView("Channel");
|
||||
this->globalEmotesView_ = makeView("Global");
|
||||
this->viewEmojis_ = makeView("Emojis");
|
||||
|
||||
this->loadEmojis();
|
||||
|
||||
this->viewEmotes_->linkClicked.connect(
|
||||
this->globalEmotesView_->linkClicked.connect(
|
||||
[this](const Link &link) { this->linkClicked.invoke(link); });
|
||||
this->viewEmojis_->linkClicked.connect(
|
||||
[this](const Link &link) { this->linkClicked.invoke(link); });
|
||||
|
@ -48,93 +101,41 @@ EmotePopup::EmotePopup()
|
|||
|
||||
void EmotePopup::loadChannel(ChannelPtr _channel)
|
||||
{
|
||||
BenchmarkGuard guard("loadChannel");
|
||||
|
||||
this->setWindowTitle("Emotes from " + _channel->getName());
|
||||
|
||||
TwitchChannel *channel = dynamic_cast<TwitchChannel *>(_channel.get());
|
||||
auto twitchChannel = dynamic_cast<TwitchChannel *>(_channel.get());
|
||||
if (twitchChannel == nullptr) return;
|
||||
|
||||
if (channel == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelPtr emoteChannel(new Channel("", Channel::Type::None));
|
||||
|
||||
auto addEmotes = [&](const EmoteMap &map, const QString &title,
|
||||
const QString &emoteDesc) {
|
||||
// TITLE
|
||||
MessageBuilder builder1;
|
||||
|
||||
builder1.emplace<TextElement>(title, MessageElementFlag::Text);
|
||||
|
||||
builder1->flags.set(MessageFlag::Centered);
|
||||
emoteChannel->addMessage(builder1.release());
|
||||
|
||||
// EMOTES
|
||||
MessageBuilder builder2;
|
||||
builder2->flags.set(MessageFlag::Centered);
|
||||
builder2->flags.set(MessageFlag::DisableCompactEmotes);
|
||||
|
||||
for (auto emote : map) {
|
||||
builder2
|
||||
.emplace<EmoteElement>(emote.second,
|
||||
MessageElementFlag::AlwaysShow)
|
||||
->setLink(Link(Link::InsertText, emote.first.string));
|
||||
}
|
||||
|
||||
emoteChannel->addMessage(builder2.release());
|
||||
auto addEmotes = [&](Channel &channel, const EmoteMap &map,
|
||||
const QString &title) {
|
||||
channel.addMessage(makeTitleMessage(title));
|
||||
channel.addMessage(makeEmoteMessage(map));
|
||||
};
|
||||
|
||||
auto app = getApp();
|
||||
auto subChannel = std::make_shared<Channel>("", Channel::Type::None);
|
||||
auto globalChannel = std::make_shared<Channel>("", Channel::Type::None);
|
||||
auto channelChannel = std::make_shared<Channel>("", Channel::Type::None);
|
||||
|
||||
// fourtf: the entire emote manager needs to be refactored so there's no
|
||||
// point in trying to fix this pile of garbage
|
||||
for (const auto &set :
|
||||
app->accounts->twitch.getCurrent()->accessEmotes()->emoteSets) {
|
||||
// TITLE
|
||||
MessageBuilder builder1;
|
||||
// twitch
|
||||
addEmoteSets(
|
||||
getApp()->accounts->twitch.getCurrent()->accessEmotes()->emoteSets,
|
||||
*globalChannel, *subChannel);
|
||||
|
||||
QString setText;
|
||||
if (set->text.isEmpty()) {
|
||||
if (set->channelName.isEmpty()) {
|
||||
setText = "Twitch Account Emotes";
|
||||
} else {
|
||||
setText = "Twitch Account Emotes (" + set->channelName + ")";
|
||||
}
|
||||
} else {
|
||||
setText = set->text;
|
||||
}
|
||||
// global
|
||||
addEmotes(*globalChannel, *getApp()->emotes->bttv.global(), "BetterTTV");
|
||||
addEmotes(*globalChannel, *getApp()->emotes->ffz.global(), "FrankerFaceZ");
|
||||
|
||||
builder1.emplace<TextElement>(setText, MessageElementFlag::Text);
|
||||
// channel
|
||||
// addEmotes(*channel->accessBttvEmotes(), "BetterTTV Channel Emotes",
|
||||
// "BetterTTV Channel Emote");
|
||||
// addEmotes(*channel->accessFfzEmotes(), "FrankerFaceZ Channel Emotes",
|
||||
// "FrankerFaceZ Channel Emote");
|
||||
|
||||
builder1->flags.set(MessageFlag::Centered);
|
||||
emoteChannel->addMessage(builder1.release());
|
||||
|
||||
// EMOTES
|
||||
MessageBuilder builder2;
|
||||
builder2->flags.set(MessageFlag::Centered);
|
||||
builder2->flags.set(MessageFlag::DisableCompactEmotes);
|
||||
|
||||
for (const auto &emote : set->emotes) {
|
||||
builder2
|
||||
.emplace<EmoteElement>(
|
||||
app->emotes->twitch.getOrCreateEmote(emote.id, emote.name),
|
||||
MessageElementFlag::AlwaysShow)
|
||||
->setLink(Link(Link::InsertText, emote.name.string));
|
||||
}
|
||||
|
||||
emoteChannel->addMessage(builder2.release());
|
||||
}
|
||||
|
||||
addEmotes(*app->emotes->bttv.accessGlobalEmotes(),
|
||||
"BetterTTV Global Emotes", "BetterTTV Global Emote");
|
||||
addEmotes(*channel->accessBttvEmotes(), "BetterTTV Channel Emotes",
|
||||
"BetterTTV Channel Emote");
|
||||
// addEmotes(*app->emotes->ffz.accessGlobalEmotes(), "FrankerFaceZ Global
|
||||
// Emotes",
|
||||
// "FrankerFaceZ Global Emote");
|
||||
addEmotes(*channel->accessFfzEmotes(), "FrankerFaceZ Channel Emotes",
|
||||
"FrankerFaceZ Channel Emote");
|
||||
|
||||
this->viewEmotes_->setChannel(emoteChannel);
|
||||
this->globalEmotesView_->setChannel(globalChannel);
|
||||
this->subEmotesView_->setChannel(subChannel);
|
||||
this->channelEmotesView_->setChannel(channelChannel);
|
||||
}
|
||||
|
||||
void EmotePopup::loadEmojis()
|
||||
|
@ -143,13 +144,6 @@ void EmotePopup::loadEmojis()
|
|||
|
||||
ChannelPtr emojiChannel(new Channel("", Channel::Type::None));
|
||||
|
||||
// title
|
||||
MessageBuilder builder1;
|
||||
|
||||
builder1.emplace<TextElement>("emojis", MessageElementFlag::Text);
|
||||
builder1->flags.set(MessageFlag::Centered);
|
||||
emojiChannel->addMessage(builder1.release());
|
||||
|
||||
// emojis
|
||||
MessageBuilder builder;
|
||||
builder->flags.set(MessageFlag::Centered);
|
||||
|
|
|
@ -19,8 +19,10 @@ public:
|
|||
pajlada::Signals::Signal<Link> linkClicked;
|
||||
|
||||
private:
|
||||
ChannelView *viewEmotes_;
|
||||
ChannelView *viewEmojis_;
|
||||
ChannelView *globalEmotesView_{};
|
||||
ChannelView *channelEmotesView_{};
|
||||
ChannelView *subEmotesView_{};
|
||||
ChannelView *viewEmojis_{};
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -47,7 +47,7 @@ void QualityPopup::okButtonClicked()
|
|||
try {
|
||||
openStreamlink(channelURL, this->ui_.selector.currentText());
|
||||
} catch (const Exception &ex) {
|
||||
Log("Exception caught trying to open streamlink: {}", ex.what());
|
||||
log("Exception caught trying to open streamlink: {}", ex.what());
|
||||
}
|
||||
|
||||
this->close();
|
||||
|
|
|
@ -492,7 +492,7 @@ void ChannelView::setChannel(ChannelPtr newChannel)
|
|||
MessageLayoutPtr newItem(new MessageLayout(replacement));
|
||||
auto snapshot = this->messages.getSnapshot();
|
||||
if (index >= snapshot.getLength()) {
|
||||
Log("Tried to replace out of bounds message. Index: {}. "
|
||||
log("Tried to replace out of bounds message. Index: {}. "
|
||||
"Length: {}",
|
||||
index, snapshot.getLength());
|
||||
return;
|
||||
|
@ -1169,19 +1169,18 @@ void ChannelView::handleLinkClick(QMouseEvent *event, const Link &link,
|
|||
userPopup->show();
|
||||
|
||||
qDebug() << "Clicked " << user << "s message";
|
||||
break;
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case Link::Url: {
|
||||
QDesktopServices::openUrl(QUrl(link.value));
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Link::UserAction: {
|
||||
QString value = link.value;
|
||||
value.replace("{user}", layout->getMessage()->loginName);
|
||||
this->channel_->sendMessage(value);
|
||||
}
|
||||
} break;
|
||||
|
||||
default:;
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ AboutPage::AboutPage()
|
|||
QStringList contributorParts = line.split("|");
|
||||
|
||||
if (contributorParts.size() != 4) {
|
||||
Log("Missing parts in line '{}'", line);
|
||||
log("Missing parts in line '{}'", line);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -429,7 +429,7 @@ void Split::openInStreamlink()
|
|||
try {
|
||||
openStreamlinkForChannel(this->getChannel()->getName());
|
||||
} catch (const Exception &ex) {
|
||||
Log("Error in doOpenStreamlink: {}", ex.what());
|
||||
log("Error in doOpenStreamlink: {}", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue