mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
Merge remote-tracking branch 'origin/master' into zneix/feat/chatrooms-user-impl
This commit is contained in:
commit
1e0e2eb67f
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
|
@ -83,8 +83,10 @@ jobs:
|
|||
- name: Test (Ubuntu)
|
||||
if: startsWith(matrix.os, 'ubuntu')
|
||||
run: |
|
||||
docker pull kennethreitz/httpbin
|
||||
docker pull ${{ env.TWITCH_PUBSUB_SERVER_IMAGE }}
|
||||
docker run --network=host --detach ${{ env.TWITCH_PUBSUB_SERVER_IMAGE }}
|
||||
docker run -p 9051:80 --detach kennethreitz/httpbin
|
||||
./bin/chatterino-test --platform minimal
|
||||
working-directory: build-test
|
||||
shell: bash
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
This guide assumes you are on a 64-bit system. You might need to manually search out alternate download links should you desire to build Chatterino on a 32-bit system.
|
||||
|
||||
## Visual Studio 2019
|
||||
## Visual Studio 2022
|
||||
|
||||
Download and install [Visual Studio 2019 Community](https://visualstudio.microsoft.com/downloads/). In the installer, select "Desktop development with C++" and "Universal Windows Platform development".
|
||||
Download and install [Visual Studio 2022 Community](https://visualstudio.microsoft.com/downloads/). In the installer, select "Desktop development with C++" and "Universal Windows Platform development".
|
||||
|
||||
Notes:
|
||||
|
||||
|
@ -20,14 +20,14 @@ Notes:
|
|||
- Visit the downloads list on [SourceForge](https://sourceforge.net/projects/boost/files/boost-binaries/).
|
||||
- Select the latest version from the list.
|
||||
- Download the `.exe` file appropriate to your Visual Studio installation version and system bitness (choose `-64` for 64-bit systems).
|
||||
Visual Studio versions map as follows: `14.2` in the filename corresponds to MSVC 2019, `14.1` to 2017, `14.0` to 2015. _Anything prior to Visual Studio 2015 is unsupported. Please upgrade should you have an older installation._
|
||||
Visual Studio versions map as follows: `14.3` in the filename corresponds to MSVC 2022,`14.2` to 2019, `14.1` to 2017, `14.0` to 2015. _Anything prior to Visual Studio 2015 is unsupported. Please upgrade should you have an older installation._
|
||||
|
||||
**Convenience link for Visual Studio 2019: [boost_1_76_0-msvc-14.2-64.exe](https://sourceforge.net/projects/boost/files/boost-binaries/1.76.0/boost_1_76_0-msvc-14.2-64.exe/download)**
|
||||
**Convenience link for Visual Studio 2022: [boost_1_79_0_b1-msvc-14.3-64.exe](https://sourceforge.net/projects/boost/files/boost-binaries/1.79.0_b1/boost_1_79_0_b1-msvc-14.3-64.exe/download)**
|
||||
|
||||
2. When prompted where to install Boost, set the location to `C:\local\boost`.
|
||||
3. After the installation finishes, rename the `C:\local\boost\lib64-msvc-14.2` (or similar) directory to simply `lib` (`C:\local\boost\lib`).
|
||||
3. After the installation finishes, rename the `C:\local\boost\boost_1_79_0_b1_rc1` (or similar) directory to simply `lib` (`C:\local\boost\lib`).
|
||||
|
||||
Note: This installation will take about 1.5 GB of disk space.
|
||||
Note: This installation will take about 2.1 GB of disk space.
|
||||
|
||||
## OpenSSL
|
||||
|
||||
|
@ -84,7 +84,7 @@ Compiling with Breakpad support enables crash reports that can be of use for dev
|
|||
|
||||
1. Open the `chatterino.pro` file by double-clicking it, or by opening it via Qt Creator.
|
||||
2. You will be presented with a screen that is titled "Configure Project". In this screen, you should have at least one option present ready to be configured, like this:
|
||||
![Qt Create Configure Project screenshot](https://user-images.githubusercontent.com/41973452/159462759-470e5371-671e-478e-85ca-33452ca9bea3.png)
|
||||
![Qt Create Configure Project screenshot](https://user-images.githubusercontent.com/69117321/169887645-2ae0871a-fe8a-4eb9-98db-7b996dea3a54.png)
|
||||
3. Select the profile(s) you want to build with and click "Configure Project".
|
||||
|
||||
### How to run and produce builds
|
||||
|
|
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -2,20 +2,25 @@
|
|||
|
||||
## Unversioned
|
||||
|
||||
- Major: Added multi-channel searching to search dialog via keyboard shortcut. [Ctrl+Shift+F by default] (#3694)
|
||||
- Minor: Added `is:first-msg` search option. (#3700)
|
||||
- Minor: Added quotation marks in the permitted/blocked Automod messages for clarity. (#3654)
|
||||
- Minor: Adjust large stream thumbnail to 16:9 (#3655)
|
||||
- Minor: Fixed being unable to load Twitch Usercards from the `/mentions` tab. (#3623)
|
||||
- Minor: Add information about the user's operating system in the About page. (#3663)
|
||||
- Bugfix: Connection to Twitch PubSub now recovers more reliably. (#3643, #3716)
|
||||
- Minor: Added chatter count for each category in viewer list. (#3683)
|
||||
- Minor: Added chatter count for each category in viewer list. (#3683, #3719)
|
||||
- Minor: Sorted usernames in /vips message to be case-insensitive. (#3696)
|
||||
- Minor: Added option to open a user's chat in a new tab from the usercard profile picture context menu. (#3625)
|
||||
- Minor: Fixed tag parsing for consecutive escaped characters. (#3711)
|
||||
- Minor: Prevent user from entering incorrect characters in Live Notifications channels list. (#3715, #3730)
|
||||
- Minor: Fixed automod caught message notice appearing twice for mods. (#3717)
|
||||
- Minor: Streamer mode now automatically detects if XSplit, PRISM Live Studio, Twitch Studio, or vMix are running. (#3740)
|
||||
- Minor: Add scrollbar to `Select filters` dialog. (#3737)
|
||||
- Minor: Added `/requests` command. Usage: `/requests [channel]`. Opens the channel points requests queue for the provided channel or the current channel if no input is provided. (#3746)
|
||||
- Minor: Added ability to execute commands on chat messages using the message context menu. (#3738)
|
||||
- Minor: Added ability to execute commands on chat messages using the message context menu. (#3738, #3765)
|
||||
- Minor: Added `/copy` command. Usage: `/copy <text>`. Copies provided text to clipboard - can be useful with custom commands. (#3763)
|
||||
- Bugfix: Fixed viewers list search not working when used before loading finishes. (#3774)
|
||||
- Bugfix: Fixed live notifications for usernames containing uppercase characters. (#3646)
|
||||
- Bugfix: Fixed live notifications not getting updated for closed streams going offline. (#3678)
|
||||
- Bugfix: Fixed certain settings dialogs appearing behind the main window, when `Always on top` was used. (#3679)
|
||||
|
@ -27,7 +32,7 @@
|
|||
- Bugfix: Fixed viewer list not closing after pressing escape key. (#3734)
|
||||
- Bugfix: Fixed links with no thumbnail having previous link's thumbnail. (#3720)
|
||||
- Dev: Use Game Name returned by Get Streams instead of querying it from the Get Games API. (#3662)
|
||||
- Dev: Batch checking live status for all channels after startup. (#3757, #3762)
|
||||
- Dev: Batch checking live status for all channels after startup. (#3757, #3762, #3767)
|
||||
|
||||
## 2.3.5
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ project(chatterino-benchmark)
|
|||
set(benchmark_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/main.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/Emojis.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/FormatTime.cpp
|
||||
# Add your new file above this line!
|
||||
)
|
||||
|
||||
|
|
38
benchmarks/src/FormatTime.cpp
Normal file
38
benchmarks/src/FormatTime.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include "util/FormatTime.hpp"
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
using namespace chatterino;
|
||||
|
||||
template <class... Args>
|
||||
void BM_TimeFormatting(benchmark::State &state, Args &&...args)
|
||||
{
|
||||
auto args_tuple = std::make_tuple(std::move(args)...);
|
||||
for (auto _ : state)
|
||||
{
|
||||
formatTime(std::get<0>(args_tuple));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, 0, 0);
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, qs0, "0");
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, 1337, 1337);
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, qs1337, "1337");
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, 623452, 623452);
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, qs623452, "623452");
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, 8345, 8345);
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, qs8345, "8345");
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, 314034, 314034);
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, qs314034, "314034");
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, 27, 27);
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, qs27, "27");
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, 34589, 34589);
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, qs34589, "34589");
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, 3659, 3659);
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, qs3659, "3659");
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, 1045345, 1045345);
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, qs1045345, "1045345");
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, 86432, 86432);
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, qs86432, "86432");
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, qsempty, "");
|
||||
BENCHMARK_CAPTURE(BM_TimeFormatting, qsinvalid, "asd");
|
|
@ -264,6 +264,7 @@ SOURCES += \
|
|||
src/util/NuulsUploader.cpp \
|
||||
src/util/RapidjsonHelpers.cpp \
|
||||
src/util/RatelimitBucket.cpp \
|
||||
src/util/SampleData.cpp \
|
||||
src/util/SplitCommand.cpp \
|
||||
src/util/StreamerMode.cpp \
|
||||
src/util/StreamLink.cpp \
|
||||
|
@ -529,7 +530,6 @@ HEADERS += \
|
|||
src/util/IncognitoBrowser.hpp \
|
||||
src/util/InitUpdateButton.hpp \
|
||||
src/util/IrcHelpers.hpp \
|
||||
src/util/IsBigEndian.hpp \
|
||||
src/util/LayoutCreator.hpp \
|
||||
src/util/LayoutHelper.hpp \
|
||||
src/util/NuulsUploader.hpp \
|
||||
|
@ -539,13 +539,11 @@ HEADERS += \
|
|||
src/util/QObjectRef.hpp \
|
||||
src/util/QStringHash.hpp \
|
||||
src/util/Qt.hpp \
|
||||
src/util/rangealgorithm.hpp \
|
||||
src/util/RapidjsonHelpers.hpp \
|
||||
src/util/RapidJsonSerializeQString.hpp \
|
||||
src/util/RatelimitBucket.hpp \
|
||||
src/util/RemoveScrollAreaBackground.hpp \
|
||||
src/util/SampleCheerMessages.hpp \
|
||||
src/util/SampleLinks.hpp \
|
||||
src/util/SampleData.hpp \
|
||||
src/util/SharedPtrElementLess.hpp \
|
||||
src/util/SplitCommand.hpp \
|
||||
src/util/StandardItemHelper.hpp \
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 87190b811c5d6bb90f970902bcda28740f6c07d3
|
||||
Subproject commit 6956c560330e21c7673ba8d5e43d53b71a7fce48
|
|
@ -4,7 +4,7 @@ resources_header = \
|
|||
|
||||
resources_footer = \
|
||||
''' </qresource>
|
||||
</RCC>'''
|
||||
</RCC>\n'''
|
||||
|
||||
header_header = \
|
||||
'''#include <QPixmap>
|
||||
|
@ -22,7 +22,7 @@ public:
|
|||
header_footer = \
|
||||
'''};
|
||||
|
||||
} // namespace chatterino'''
|
||||
} // namespace chatterino\n'''
|
||||
|
||||
source_header = \
|
||||
'''#include "ResourcesAutogen.hpp"
|
||||
|
@ -36,4 +36,4 @@ Resources2::Resources2()
|
|||
source_footer = \
|
||||
'''}
|
||||
|
||||
} // namespace chatterino'''
|
||||
} // namespace chatterino\n'''
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "singletons/Updates.hpp"
|
||||
#include "singletons/WindowManager.hpp"
|
||||
#include "util/Helpers.hpp"
|
||||
#include "util/IsBigEndian.hpp"
|
||||
#include "util/PostToThread.hpp"
|
||||
#include "util/RapidjsonHelpers.hpp"
|
||||
#include "widgets/Notebook.hpp"
|
||||
|
|
|
@ -58,19 +58,6 @@ namespace {
|
|||
|
||||
auto size = *reinterpret_cast<uint32_t *>(size_c);
|
||||
|
||||
#if 0
|
||||
bool bigEndian = isBigEndian();
|
||||
// To avoid breaking strict-aliasing rules and potentially inducing undefined behaviour, the following code can be run instead
|
||||
uint32_t size = 0;
|
||||
if (bigEndian) {
|
||||
size = size_c[3] | static_cast<uint32_t>(size_c[2]) << 8 |
|
||||
static_cast<uint32_t>(size_c[1]) << 16 | static_cast<uint32_t>(size_c[0]) << 24;
|
||||
} else {
|
||||
size = size_c[0] | static_cast<uint32_t>(size_c[1]) << 8 |
|
||||
static_cast<uint32_t>(size_c[2]) << 16 | static_cast<uint32_t>(size_c[3]) << 24;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::unique_ptr<char[]> buffer(new char[size + 1]);
|
||||
std::cin.read(buffer.get(), size);
|
||||
*(buffer.get() + size) = '\0';
|
||||
|
|
|
@ -322,6 +322,8 @@ set(SOURCE_FILES
|
|||
util/RapidjsonHelpers.hpp
|
||||
util/RatelimitBucket.cpp
|
||||
util/RatelimitBucket.hpp
|
||||
util/SampleData.cpp
|
||||
util/SampleData.hpp
|
||||
util/SplitCommand.cpp
|
||||
util/SplitCommand.hpp
|
||||
util/StreamLink.cpp
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "singletons/Settings.hpp"
|
||||
#include "singletons/Theme.hpp"
|
||||
#include "singletons/WindowManager.hpp"
|
||||
#include "util/Clipboard.hpp"
|
||||
#include "util/CombinePath.hpp"
|
||||
#include "util/FormatTime.hpp"
|
||||
#include "util/Helpers.hpp"
|
||||
|
@ -176,6 +177,11 @@ bool appendWhisperMessageStringLocally(const QString &textNoEmoji)
|
|||
return false;
|
||||
}
|
||||
|
||||
const std::function<QString(const QString &, const ChannelPtr &)>
|
||||
noOpPlaceholder = [](const auto &altText, const auto &channel) {
|
||||
return altText;
|
||||
};
|
||||
|
||||
const std::map<QString,
|
||||
std::function<QString(const QString &, const ChannelPtr &)>>
|
||||
COMMAND_VARS{
|
||||
|
@ -239,6 +245,11 @@ const std::map<QString,
|
|||
return name.isEmpty() ? altText : name;
|
||||
},
|
||||
},
|
||||
// variables used in mod buttons and the like, these make no sense in normal commands, so they are left empty
|
||||
{"input.text", noOpPlaceholder},
|
||||
{"msg.id", noOpPlaceholder},
|
||||
{"user.name", noOpPlaceholder},
|
||||
{"msg.text", noOpPlaceholder},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -825,6 +836,7 @@ void CommandController::initialize(Settings &, Paths &paths)
|
|||
}
|
||||
return "";
|
||||
});
|
||||
|
||||
this->registerCommand("/setgame", [](const QStringList &words,
|
||||
const ChannelPtr channel) {
|
||||
if (words.size() < 2)
|
||||
|
@ -923,6 +935,7 @@ void CommandController::initialize(Settings &, Paths &paths)
|
|||
|
||||
return "";
|
||||
});
|
||||
|
||||
this->registerCommand(
|
||||
"/delete", [](const QStringList &words, ChannelPtr channel) -> QString {
|
||||
// This is a wrapper over the standard Twitch /delete command
|
||||
|
@ -965,6 +978,7 @@ void CommandController::initialize(Settings &, Paths &paths)
|
|||
getApp()->twitch->sendRawMessage(words.mid(1).join(" "));
|
||||
return "";
|
||||
});
|
||||
|
||||
#ifndef NDEBUG
|
||||
this->registerCommand(
|
||||
"/fakemsg",
|
||||
|
@ -981,6 +995,19 @@ void CommandController::initialize(Settings &, Paths &paths)
|
|||
return "";
|
||||
});
|
||||
#endif
|
||||
|
||||
this->registerCommand(
|
||||
"/copy", [](const QStringList &words, ChannelPtr channel) -> QString {
|
||||
if (words.size() < 2)
|
||||
{
|
||||
channel->addMessage(
|
||||
makeSystemMessage("Usage: /copy <text> - copies provided "
|
||||
"text to clipboard."));
|
||||
return "";
|
||||
}
|
||||
crossPlatformCopy(words.mid(1).join(" "));
|
||||
return "";
|
||||
});
|
||||
}
|
||||
|
||||
void CommandController::save()
|
||||
|
@ -1134,18 +1161,18 @@ QString CommandController::execCustomCommand(const QStringList &words,
|
|||
auto varName = match.captured(4);
|
||||
auto altText = match.captured(5); // alt text or empty string
|
||||
|
||||
auto var = COMMAND_VARS.find(varName);
|
||||
auto var = context.find(varName);
|
||||
|
||||
if (var != COMMAND_VARS.end())
|
||||
if (var != context.end())
|
||||
{
|
||||
result += var->second(altText, channel);
|
||||
result += var->second.isEmpty() ? altText : var->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto it = context.find(varName);
|
||||
if (it != context.end())
|
||||
auto it = COMMAND_VARS.find(varName);
|
||||
if (it != COMMAND_VARS.end())
|
||||
{
|
||||
result += it->second.isEmpty() ? altText : it->second;
|
||||
result += it->second(altText, channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "HighlightBadge.hpp"
|
||||
|
||||
#include "messages/SharedMessageBuilder.hpp"
|
||||
#include "singletons/Resources.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
@ -86,21 +87,12 @@ bool HighlightBadge::compare(const QString &id, const Badge &badge) const
|
|||
{
|
||||
if (this->hasVersions_)
|
||||
{
|
||||
auto parts = id.split("/");
|
||||
if (parts.size() == 2)
|
||||
{
|
||||
return parts.at(0).compare(badge.key_, Qt::CaseInsensitive) == 0 &&
|
||||
parts.at(1).compare(badge.value_, Qt::CaseInsensitive) == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return parts.at(0).compare(badge.key_, Qt::CaseInsensitive) == 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return id.compare(badge.key_, Qt::CaseInsensitive) == 0;
|
||||
auto parts = SharedMessageBuilder::slashKeyValue(id);
|
||||
return parts.first.compare(badge.key_, Qt::CaseInsensitive) == 0 &&
|
||||
parts.second.compare(badge.value_, Qt::CaseInsensitive) == 0;
|
||||
}
|
||||
|
||||
return id.compare(badge.key_, Qt::CaseInsensitive) == 0;
|
||||
}
|
||||
|
||||
bool HighlightBadge::hasCustomSound() const
|
||||
|
|
|
@ -103,7 +103,8 @@ inline const std::map<HotkeyCategory, ActionDefinitionMap> actionNames{
|
|||
0,
|
||||
1,
|
||||
}},
|
||||
{"showSearch", ActionDefinition{"Search"}},
|
||||
{"showSearch", ActionDefinition{"Search current channel"}},
|
||||
{"showGlobalSearch", ActionDefinition{"Search all channels"}},
|
||||
{"startWatching", ActionDefinition{"Start watching"}},
|
||||
{"debug", ActionDefinition{"Show debug popup"}},
|
||||
}},
|
||||
|
|
|
@ -339,6 +339,9 @@ void HotkeyController::addDefaults(std::set<QString> &addedHotkeys)
|
|||
this->tryAddDefault(addedHotkeys, HotkeyCategory::Split,
|
||||
QKeySequence("Ctrl+F"), "showSearch",
|
||||
std::vector<QString>(), "show search");
|
||||
this->tryAddDefault(addedHotkeys, HotkeyCategory::Split,
|
||||
QKeySequence("Ctrl+Shift+F"), "showGlobalSearch",
|
||||
std::vector<QString>(), "show global search");
|
||||
this->tryAddDefault(addedHotkeys, HotkeyCategory::Split,
|
||||
QKeySequence("Ctrl+F5"), "reconnect",
|
||||
std::vector<QString>(), "reconnect");
|
||||
|
|
|
@ -191,6 +191,9 @@ void NotificationController::fetchFakeChannels()
|
|||
// we done fucked up.
|
||||
qCWarning(chatterinoNotification)
|
||||
<< "Failed to fetch live status for " << batch;
|
||||
},
|
||||
[]() {
|
||||
// finally
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,14 +138,6 @@ namespace detail {
|
|||
{
|
||||
QVector<Frame<QImage>> frames;
|
||||
|
||||
if (reader.imageCount() == 0)
|
||||
{
|
||||
qCDebug(chatterinoImage)
|
||||
<< "Error while reading image" << url.string << ": '"
|
||||
<< reader.errorString() << "'";
|
||||
return frames;
|
||||
}
|
||||
|
||||
QImage image;
|
||||
for (int index = 0; index < reader.imageCount(); ++index)
|
||||
{
|
||||
|
@ -413,8 +405,30 @@ void Image::actuallyLoad()
|
|||
buffer.open(QIODevice::ReadOnly);
|
||||
QImageReader reader(&buffer);
|
||||
|
||||
if (!reader.canRead())
|
||||
{
|
||||
qCDebug(chatterinoImage)
|
||||
<< "Error: image cant be read " << shared->url().string;
|
||||
return Failure;
|
||||
}
|
||||
|
||||
const auto size = reader.size();
|
||||
if (size.isEmpty())
|
||||
{
|
||||
return Failure;
|
||||
}
|
||||
|
||||
// returns 1 for non-animated formats
|
||||
if (reader.imageCount() <= 0)
|
||||
{
|
||||
qCDebug(chatterinoImage)
|
||||
<< "Error: image has less than 1 frame "
|
||||
<< shared->url().string << ": " << reader.errorString();
|
||||
return Failure;
|
||||
}
|
||||
|
||||
// use "double" to prevent int overflows
|
||||
if (double(reader.size().width()) * double(reader.size().height()) *
|
||||
if (double(size.width()) * double(size.height()) *
|
||||
double(reader.imageCount()) * 4.0 >
|
||||
double(Image::maxBytesRam))
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "common/FlagsEnum.hpp"
|
||||
#include "providers/twitch/TwitchBadge.hpp"
|
||||
#include "util/QStringHash.hpp"
|
||||
#include "widgets/helper/ScrollbarHighlight.hpp"
|
||||
|
||||
#include <QTime>
|
||||
|
@ -65,7 +66,7 @@ struct Message : boost::noncopyable {
|
|||
QColor usernameColor;
|
||||
QDateTime serverReceivedTime;
|
||||
std::vector<Badge> badges;
|
||||
std::map<QString, QString> badgeInfos;
|
||||
std::unordered_map<QString, QString> badgeInfos;
|
||||
std::shared_ptr<QColor> highlightColor;
|
||||
uint32_t count = 1;
|
||||
std::vector<std::unique_ptr<MessageElement>> elements;
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "util/FormatTime.hpp"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QImageReader>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include "common/QLogging.hpp"
|
||||
#include "controllers/ignores/IgnoreController.hpp"
|
||||
#include "controllers/ignores/IgnorePhrase.hpp"
|
||||
#include "messages/Message.hpp"
|
||||
#include "messages/MessageElement.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "singletons/WindowManager.hpp"
|
||||
|
@ -36,33 +35,6 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
QStringList parseTagList(const QVariantMap &tags, const QString &key)
|
||||
{
|
||||
auto iterator = tags.find(key);
|
||||
if (iterator == tags.end())
|
||||
return QStringList{};
|
||||
|
||||
return iterator.value().toString().split(',', Qt::SkipEmptyParts);
|
||||
}
|
||||
|
||||
std::vector<Badge> parseBadges(const QVariantMap &tags)
|
||||
{
|
||||
std::vector<Badge> badges;
|
||||
|
||||
for (QString badge : parseTagList(tags, "badges"))
|
||||
{
|
||||
QStringList parts = badge.split('/');
|
||||
if (parts.size() != 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
badges.emplace_back(parts[0], parts[1]);
|
||||
}
|
||||
|
||||
return badges;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SharedMessageBuilder::SharedMessageBuilder(
|
||||
|
@ -103,6 +75,46 @@ void SharedMessageBuilder::parse()
|
|||
this->message().flags.set(MessageFlag::Collapsed);
|
||||
}
|
||||
|
||||
// "foo/bar/baz,tri/hard" can be a valid badge-info tag
|
||||
// In that case, valid map content should be 'split by slash' only once:
|
||||
// {"foo": "bar/baz", "tri": "hard"}
|
||||
std::pair<QString, QString> SharedMessageBuilder::slashKeyValue(
|
||||
const QString &kvStr)
|
||||
{
|
||||
return {
|
||||
// part before first slash (index 0 of section)
|
||||
kvStr.section('/', 0, 0),
|
||||
// part after first slash (index 1 of section)
|
||||
kvStr.section('/', 1, -1),
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<Badge> SharedMessageBuilder::parseBadgeTag(const QVariantMap &tags)
|
||||
{
|
||||
std::vector<Badge> b;
|
||||
|
||||
auto badgesIt = tags.constFind("badges");
|
||||
if (badgesIt == tags.end())
|
||||
{
|
||||
return b;
|
||||
}
|
||||
|
||||
auto badges = badgesIt.value().toString().split(',', Qt::SkipEmptyParts);
|
||||
|
||||
for (const QString &badge : badges)
|
||||
{
|
||||
if (!badge.contains('/'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto pair = SharedMessageBuilder::slashKeyValue(badge);
|
||||
b.emplace_back(Badge{pair.first, pair.second});
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
bool SharedMessageBuilder::isIgnored() const
|
||||
{
|
||||
return isIgnoredMessage({
|
||||
|
@ -332,7 +344,7 @@ void SharedMessageBuilder::parseHighlights()
|
|||
}
|
||||
|
||||
// Highlight because of badge
|
||||
auto badges = parseBadges(this->tags);
|
||||
auto badges = this->parseBadgeTag(this->tags);
|
||||
auto badgeHighlights = getCSettings().highlightedBadges.readOnly();
|
||||
bool badgeHighlightSet = false;
|
||||
for (const HighlightBadge &highlight : *badgeHighlights)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "common/Aliases.hpp"
|
||||
#include "common/Outcome.hpp"
|
||||
#include "messages/MessageColor.hpp"
|
||||
#include "providers/twitch/TwitchBadge.hpp"
|
||||
|
||||
#include <IrcMessage>
|
||||
#include <QColor>
|
||||
|
@ -32,6 +33,11 @@ public:
|
|||
virtual void triggerHighlights();
|
||||
virtual MessagePtr build() = 0;
|
||||
|
||||
static std::pair<QString, QString> slashKeyValue(const QString &kvStr);
|
||||
|
||||
// Parses "badges" tag which contains a comma separated list of key-value elements
|
||||
static std::vector<Badge> parseBadgeTag(const QVariantMap &tags);
|
||||
|
||||
protected:
|
||||
virtual void parse();
|
||||
|
||||
|
|
|
@ -33,4 +33,9 @@ Badge::Badge(QString key, QString value)
|
|||
}
|
||||
}
|
||||
|
||||
bool Badge::operator==(const Badge &other) const
|
||||
{
|
||||
return this->key_ == other.key_ && this->value_ == other.value_;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -11,9 +11,13 @@ class Badge
|
|||
public:
|
||||
Badge(QString key, QString value);
|
||||
|
||||
QString key_; // e.g. bits
|
||||
QString value_; // e.g. 100
|
||||
QString extraValue_{}; // e.g. 5 (the number of months subscribed)
|
||||
bool operator==(const Badge &other) const;
|
||||
|
||||
// Class members are fetched from both "badges" and "badge-info" tags
|
||||
// E.g.: "badges": "subscriber/18", "badge-info": "subscriber/22"
|
||||
QString key_; // subscriber
|
||||
QString value_; // 18
|
||||
//QString info_; // 22 (should be parsed separetly into an std::unordered_map)
|
||||
MessageElementFlag flag_{
|
||||
MessageElementFlag::BadgeVanity}; // badge slot it takes up
|
||||
};
|
||||
|
|
|
@ -204,8 +204,18 @@ void TwitchBadges::loadEmoteImage(const QString &name, ImagePtr image,
|
|||
buffer.open(QIODevice::ReadOnly);
|
||||
QImageReader reader(&buffer);
|
||||
|
||||
QImage image;
|
||||
if (reader.imageCount() == 0 || !reader.read(&image))
|
||||
if (!reader.canRead() || reader.size().isEmpty())
|
||||
{
|
||||
return Failure;
|
||||
}
|
||||
|
||||
QImage image = reader.read();
|
||||
if (image.isNull())
|
||||
{
|
||||
return Failure;
|
||||
}
|
||||
|
||||
if (reader.imageCount() <= 0)
|
||||
{
|
||||
return Failure;
|
||||
}
|
||||
|
|
|
@ -708,6 +708,9 @@ void TwitchChannel::refreshLiveStatus()
|
|||
},
|
||||
[] {
|
||||
// failure
|
||||
},
|
||||
[] {
|
||||
// finally
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,35 @@ using namespace std::chrono_literals;
|
|||
|
||||
namespace chatterino {
|
||||
|
||||
namespace {
|
||||
// TODO: combine this with getEmoteSetBatches in TwitchAccount.cpp, maybe some templated thing
|
||||
template <class T>
|
||||
std::vector<T> getChannelsInBatches(T channels)
|
||||
{
|
||||
constexpr int batchSize = 100;
|
||||
|
||||
int batchCount = (channels.size() / batchSize) + 1;
|
||||
|
||||
std::vector<T> batches;
|
||||
batches.reserve(batchCount);
|
||||
|
||||
for (int i = 0; i < batchCount; i++)
|
||||
{
|
||||
T batch;
|
||||
|
||||
// I hate you, msvc
|
||||
int last = (std::min)(batchSize, channels.size() - batchSize * i);
|
||||
for (int j = 0; j < last; j++)
|
||||
{
|
||||
batch.push_back(channels.at(j + (batchSize * i)));
|
||||
}
|
||||
batches.emplace_back(batch);
|
||||
}
|
||||
|
||||
return batches;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TwitchIrcServer::TwitchIrcServer()
|
||||
: whispersChannel(new Channel("/whispers", Channel::Type::TwitchWhispers))
|
||||
, mentionsChannel(new Channel("/mentions", Channel::Type::TwitchMentions))
|
||||
|
@ -302,60 +331,55 @@ std::shared_ptr<Channel> TwitchIrcServer::getChannelOrEmptyByID(
|
|||
return Channel::getEmpty();
|
||||
}
|
||||
|
||||
namespace {
|
||||
// TODO: combine this with getEmoteSetBatches in TwitchAccount.cpp, maybe some templated thing
|
||||
std::vector<QStringList> getChannelsInBatches(QStringList channels)
|
||||
{
|
||||
constexpr int batchSize = 100;
|
||||
|
||||
int batchCount = (channels.size() / batchSize) + 1;
|
||||
|
||||
std::vector<QStringList> batches;
|
||||
batches.reserve(batchCount);
|
||||
|
||||
for (int i = 0; i < batchCount; i++)
|
||||
{
|
||||
QStringList batch;
|
||||
|
||||
// I hate you, msvc
|
||||
int last = (std::min)(batchSize, channels.size() - batchSize * i);
|
||||
for (int j = 0; j < last; j++)
|
||||
{
|
||||
batch.push_back(channels.at(j + (batchSize * i)));
|
||||
}
|
||||
batches.emplace_back(batch);
|
||||
}
|
||||
|
||||
return batches;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void TwitchIrcServer::bulkRefreshLiveStatus()
|
||||
{
|
||||
QStringList userIDs;
|
||||
this->forEachChannel([&userIDs](ChannelPtr chan) {
|
||||
auto twitchChan = dynamic_cast<TwitchChannel *>(chan.get());
|
||||
if (!twitchChan->roomId().isEmpty())
|
||||
userIDs.push_back(twitchChan->roomId());
|
||||
auto twitchChans = std::make_shared<QHash<QString, TwitchChannel *>>();
|
||||
|
||||
this->forEachChannel([twitchChans](ChannelPtr chan) {
|
||||
auto tc = dynamic_cast<TwitchChannel *>(chan.get());
|
||||
if (tc && !tc->roomId().isEmpty())
|
||||
{
|
||||
twitchChans->insert(tc->roomId(), tc);
|
||||
}
|
||||
});
|
||||
|
||||
for (const auto &batch : getChannelsInBatches(userIDs))
|
||||
// iterate over batches of channel IDs
|
||||
for (const auto &batch : getChannelsInBatches(twitchChans->keys()))
|
||||
{
|
||||
getHelix()->fetchStreams(
|
||||
batch, QStringList(),
|
||||
[this](std::vector<HelixStream> streams) {
|
||||
batch, {},
|
||||
[twitchChans](std::vector<HelixStream> streams) {
|
||||
for (const auto &stream : streams)
|
||||
{
|
||||
auto chan = this->getChannelOrEmpty(stream.userLogin);
|
||||
if (chan->getType() != Channel::Type::Twitch)
|
||||
// remaining channels will be used later to set their stream status as offline
|
||||
// so we use take(id) to remove it
|
||||
auto tc = twitchChans->take(stream.userId);
|
||||
if (tc == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto twitchChan = dynamic_cast<TwitchChannel *>(chan.get());
|
||||
twitchChan->parseLiveStatus(true, stream);
|
||||
tc->parseLiveStatus(true, stream);
|
||||
}
|
||||
},
|
||||
[]() {
|
||||
// failure
|
||||
},
|
||||
[batch, twitchChans] {
|
||||
// All the channels that were not present in fetchStreams response should be assumed to be offline
|
||||
// It is necessary to update their stream status in case they've gone live -> offline
|
||||
// Otherwise some of them will be marked as live forever
|
||||
for (const auto &chID : batch)
|
||||
{
|
||||
auto tc = twitchChans->value(chID);
|
||||
// early out in case channel does not exist anymore
|
||||
if (tc == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
tc->parseLiveStatus(false, {});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "messages/Message.hpp"
|
||||
#include "providers/chatterino/ChatterinoBadges.hpp"
|
||||
#include "providers/ffz/FfzBadges.hpp"
|
||||
#include "providers/twitch/TwitchBadge.hpp"
|
||||
#include "providers/twitch/TwitchBadges.hpp"
|
||||
#include "providers/twitch/TwitchChannel.hpp"
|
||||
#include "providers/twitch/TwitchIrcServer.hpp"
|
||||
|
@ -47,55 +48,6 @@ const QSet<QString> zeroWidthEmotes{
|
|||
|
||||
namespace chatterino {
|
||||
|
||||
namespace {
|
||||
|
||||
QStringList parseTagList(const QVariantMap &tags, const QString &key)
|
||||
{
|
||||
auto iterator = tags.find(key);
|
||||
if (iterator == tags.end())
|
||||
return QStringList{};
|
||||
|
||||
return iterator.value().toString().split(',', Qt::SkipEmptyParts);
|
||||
}
|
||||
|
||||
std::map<QString, QString> parseBadgeInfos(const QVariantMap &tags)
|
||||
{
|
||||
std::map<QString, QString> badgeInfos;
|
||||
|
||||
for (QString badgeInfo : parseTagList(tags, "badge-info"))
|
||||
{
|
||||
QStringList parts = badgeInfo.split('/');
|
||||
if (parts.size() != 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
badgeInfos.emplace(parts[0], parts[1]);
|
||||
}
|
||||
|
||||
return badgeInfos;
|
||||
}
|
||||
|
||||
std::vector<Badge> parseBadges(const QVariantMap &tags)
|
||||
{
|
||||
std::vector<Badge> badges;
|
||||
|
||||
for (QString badge : parseTagList(tags, "badges"))
|
||||
{
|
||||
QStringList parts = badge.split('/');
|
||||
if (parts.size() != 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
badges.emplace_back(parts[0], parts[1]);
|
||||
}
|
||||
|
||||
return badges;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TwitchMessageBuilder::TwitchMessageBuilder(
|
||||
Channel *_channel, const Communi::IrcPrivateMessage *_ircMessage,
|
||||
const MessageParseArgs &_args)
|
||||
|
@ -1033,6 +985,25 @@ boost::optional<EmotePtr> TwitchMessageBuilder::getTwitchBadge(
|
|||
return boost::none;
|
||||
}
|
||||
|
||||
std::unordered_map<QString, QString> TwitchMessageBuilder::parseBadgeInfoTag(
|
||||
const QVariantMap &tags)
|
||||
{
|
||||
std::unordered_map<QString, QString> infoMap;
|
||||
|
||||
auto infoIt = tags.constFind("badge-info");
|
||||
if (infoIt == tags.end())
|
||||
return infoMap;
|
||||
|
||||
auto info = infoIt.value().toString().split(',', Qt::SkipEmptyParts);
|
||||
|
||||
for (const QString &badge : info)
|
||||
{
|
||||
infoMap.emplace(SharedMessageBuilder::slashKeyValue(badge));
|
||||
}
|
||||
|
||||
return infoMap;
|
||||
}
|
||||
|
||||
void TwitchMessageBuilder::appendTwitchBadges()
|
||||
{
|
||||
if (this->twitchChannel == nullptr)
|
||||
|
@ -1040,8 +1011,8 @@ void TwitchMessageBuilder::appendTwitchBadges()
|
|||
return;
|
||||
}
|
||||
|
||||
auto badgeInfos = parseBadgeInfos(this->tags);
|
||||
auto badges = parseBadges(this->tags);
|
||||
auto badgeInfos = TwitchMessageBuilder::parseBadgeInfoTag(this->tags);
|
||||
auto badges = this->parseBadgeTag(this->tags);
|
||||
|
||||
for (const auto &badge : badges)
|
||||
{
|
||||
|
@ -1091,7 +1062,7 @@ void TwitchMessageBuilder::appendTwitchBadges()
|
|||
// (tier + amount of months with leading zero if less than 100)
|
||||
// e.g. 3054 - tier 3 4,5-year sub. 2108 - tier 2 9-year sub
|
||||
const auto &subTier =
|
||||
badge.value_.length() > 3 ? badge.value_.front() : '1';
|
||||
badge.value_.length() > 3 ? badge.value_.at(0) : '1';
|
||||
const auto &subMonths = badgeInfoIt->second;
|
||||
tooltip +=
|
||||
QString(" (%1%2 months)")
|
||||
|
@ -1107,9 +1078,9 @@ void TwitchMessageBuilder::appendTwitchBadges()
|
|||
{
|
||||
auto predictionText =
|
||||
badgeInfoIt->second
|
||||
.replace("\\s", " ") // standard IRC escapes
|
||||
.replace("\\:", ";")
|
||||
.replace("\\\\", "\\")
|
||||
.replace(R"(\s)", " ") // standard IRC escapes
|
||||
.replace(R"(\:)", ";")
|
||||
.replace(R"(\\)", R"(\)")
|
||||
.replace("⸝", ","); // twitch's comma escape
|
||||
// Careful, the first character is RIGHT LOW PARAPHRASE BRACKET or U+2E1D, which just looks like a comma
|
||||
|
||||
|
|
|
@ -68,6 +68,10 @@ public:
|
|||
Channel *channel,
|
||||
MessageBuilder *builder);
|
||||
|
||||
// Shares some common logic from SharedMessageBuilder::parseBadgeTag
|
||||
static std::unordered_map<QString, QString> parseBadgeInfoTag(
|
||||
const QVariantMap &tags);
|
||||
|
||||
private:
|
||||
void parseUsernameColor() override;
|
||||
void parseUsername() override;
|
||||
|
|
|
@ -145,7 +145,7 @@ void Helix::getUserFollowers(
|
|||
void Helix::fetchStreams(
|
||||
QStringList userIds, QStringList userLogins,
|
||||
ResultCallback<std::vector<HelixStream>> successCallback,
|
||||
HelixFailureCallback failureCallback)
|
||||
HelixFailureCallback failureCallback, std::function<void()> finallyCallback)
|
||||
{
|
||||
QUrlQuery urlQuery;
|
||||
|
||||
|
@ -186,19 +186,21 @@ void Helix::fetchStreams(
|
|||
// TODO: make better xd
|
||||
failureCallback();
|
||||
})
|
||||
.finally(finallyCallback)
|
||||
.execute();
|
||||
}
|
||||
|
||||
void Helix::getStreamById(QString userId,
|
||||
ResultCallback<bool, HelixStream> successCallback,
|
||||
HelixFailureCallback failureCallback)
|
||||
HelixFailureCallback failureCallback,
|
||||
std::function<void()> finallyCallback)
|
||||
{
|
||||
QStringList userIds{std::move(userId)};
|
||||
QStringList userLogins;
|
||||
|
||||
this->fetchStreams(
|
||||
userIds, userLogins,
|
||||
[successCallback, failureCallback](const auto &streams) {
|
||||
[successCallback](const auto &streams) {
|
||||
if (streams.empty())
|
||||
{
|
||||
successCallback(false, HelixStream());
|
||||
|
@ -206,12 +208,13 @@ void Helix::getStreamById(QString userId,
|
|||
}
|
||||
successCallback(true, streams[0]);
|
||||
},
|
||||
failureCallback);
|
||||
failureCallback, finallyCallback);
|
||||
}
|
||||
|
||||
void Helix::getStreamByName(QString userName,
|
||||
ResultCallback<bool, HelixStream> successCallback,
|
||||
HelixFailureCallback failureCallback)
|
||||
HelixFailureCallback failureCallback,
|
||||
std::function<void()> finallyCallback)
|
||||
{
|
||||
QStringList userIds;
|
||||
QStringList userLogins{std::move(userName)};
|
||||
|
@ -226,7 +229,7 @@ void Helix::getStreamByName(QString userName,
|
|||
}
|
||||
successCallback(true, streams[0]);
|
||||
},
|
||||
failureCallback);
|
||||
failureCallback, finallyCallback);
|
||||
}
|
||||
|
||||
///
|
||||
|
|
|
@ -352,15 +352,18 @@ public:
|
|||
virtual void fetchStreams(
|
||||
QStringList userIds, QStringList userLogins,
|
||||
ResultCallback<std::vector<HelixStream>> successCallback,
|
||||
HelixFailureCallback failureCallback) = 0;
|
||||
HelixFailureCallback failureCallback,
|
||||
std::function<void()> finallyCallback) = 0;
|
||||
|
||||
virtual void getStreamById(
|
||||
QString userId, ResultCallback<bool, HelixStream> successCallback,
|
||||
HelixFailureCallback failureCallback) = 0;
|
||||
HelixFailureCallback failureCallback,
|
||||
std::function<void()> finallyCallback) = 0;
|
||||
|
||||
virtual void getStreamByName(
|
||||
QString userName, ResultCallback<bool, HelixStream> successCallback,
|
||||
HelixFailureCallback failureCallback) = 0;
|
||||
HelixFailureCallback failureCallback,
|
||||
std::function<void()> finallyCallback) = 0;
|
||||
|
||||
// https://dev.twitch.tv/docs/api/reference#get-games
|
||||
virtual void fetchGames(
|
||||
|
@ -469,15 +472,18 @@ public:
|
|||
// https://dev.twitch.tv/docs/api/reference#get-streams
|
||||
void fetchStreams(QStringList userIds, QStringList userLogins,
|
||||
ResultCallback<std::vector<HelixStream>> successCallback,
|
||||
HelixFailureCallback failureCallback) final;
|
||||
HelixFailureCallback failureCallback,
|
||||
std::function<void()> finallyCallback) final;
|
||||
|
||||
void getStreamById(QString userId,
|
||||
ResultCallback<bool, HelixStream> successCallback,
|
||||
HelixFailureCallback failureCallback) final;
|
||||
HelixFailureCallback failureCallback,
|
||||
std::function<void()> finallyCallback) final;
|
||||
|
||||
void getStreamByName(QString userName,
|
||||
ResultCallback<bool, HelixStream> successCallback,
|
||||
HelixFailureCallback failureCallback) final;
|
||||
HelixFailureCallback failureCallback,
|
||||
std::function<void()> finallyCallback) final;
|
||||
|
||||
// https://dev.twitch.tv/docs/api/reference#get-games
|
||||
void fetchGames(QStringList gameIds, QStringList gameNames,
|
||||
|
|
|
@ -208,7 +208,7 @@ public:
|
|||
|
||||
/// Streamer Mode
|
||||
EnumSetting<StreamerModeSetting> enableStreamerMode = {
|
||||
"/streamerMode/enabled", StreamerModeSetting::DetectObs};
|
||||
"/streamerMode/enabled", StreamerModeSetting::DetectStreamingSoftware};
|
||||
BoolSetting streamerModeHideUsercardAvatars = {
|
||||
"/streamerMode/hideUsercardAvatars", true};
|
||||
BoolSetting streamerModeHideLinkThumbnails = {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <common/UniqueAccess.hpp>
|
||||
#include "common/UniqueAccess.hpp"
|
||||
|
||||
#include <mutex>
|
||||
#include <typeinfo>
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
#include "FormatTime.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
namespace {
|
||||
void appendDuration(int count, QChar &&order, QString &outString)
|
||||
|
||||
void appendDuration(int count, QChar &&suffix, QString &out)
|
||||
{
|
||||
outString.append(QString::number(count));
|
||||
outString.append(order);
|
||||
if (!out.isEmpty())
|
||||
{
|
||||
out.append(' ');
|
||||
}
|
||||
out.append(QString::number(count));
|
||||
out.append(suffix);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
QString formatTime(int totalSeconds)
|
||||
|
@ -25,26 +32,14 @@ QString formatTime(int totalSeconds)
|
|||
}
|
||||
if (hours > 0)
|
||||
{
|
||||
if (!res.isEmpty())
|
||||
{
|
||||
res.append(" ");
|
||||
}
|
||||
appendDuration(hours, 'h', res);
|
||||
}
|
||||
if (minutes > 0)
|
||||
{
|
||||
if (!res.isEmpty())
|
||||
{
|
||||
res.append(" ");
|
||||
}
|
||||
appendDuration(minutes, 'm', res);
|
||||
}
|
||||
if (seconds > 0)
|
||||
{
|
||||
if (!res.isEmpty())
|
||||
{
|
||||
res.append(" ");
|
||||
}
|
||||
appendDuration(seconds, 's', res);
|
||||
}
|
||||
return res;
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
bool isBigEndian()
|
||||
{
|
||||
int test = 1;
|
||||
char *p = reinterpret_cast<char *>(&test);
|
||||
|
||||
return p[0] == 0;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
|
@ -1,64 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
std::vector<QString> getSampleCheerMessage()
|
||||
{
|
||||
// clang-format off
|
||||
std::vector<QString> cheerMessageVector;
|
||||
cheerMessageVector.push_back(R"(@badge-info=subscriber/4;badges=moderator/1,subscriber/3,sub-gifter/5;bits=2;color=#FF0000;display-name=69_faith_420;emotes=;flags=;id=c5fd49c7-ecbc-46dd-a790-c9f10fdaaa67;mod=1;room-id=111448817;subscriber=1;tmi-sent-ts=1567282184553;turbo=0;user-id=125608098;user-type=mod :69_faith_420!69_faith_420@69_faith_420.tmi.twitch.tv PRIVMSG #pajlada :cheer2 Stop what? I'm not doing anything.)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=subscriber/4;badges=moderator/1,subscriber/3,sub-gifter/5;bits=2;color=#FF0000;display-name=69_faith_420;emotes=;flags=;id=397f4d2e-cac8-4689-922a-32709b9e8b4f;mod=1;room-id=111448817;subscriber=1;tmi-sent-ts=1567282159076;turbo=0;user-id=125608098;user-type=mod :69_faith_420!69_faith_420@69_faith_420.tmi.twitch.tv PRIVMSG #pajlada :cheer2 Who keeps getting their bits out now?)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=subscriber/1;badges=subscriber/0,bits/1;bits=2;color=#FF0000;display-name=FlameGodFlann;emotes=;flags=;id=664ddc92-649d-4889-9641-208a6e62ef1e;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567282066199;turbo=0;user-id=56442185;user-type= :flamegodflann!flamegodflann@flamegodflann.tmi.twitch.tv PRIVMSG #pajlada :Cheer2 I'm saving my only can of Stella for your upcoming win, lets go!)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=subscriber/3;badges=moderator/1,subscriber/3,bits/100;bits=10;color=#008000;display-name=k4izn;emotes=;flags=;id=3919af0b-93e0-412c-b238-d152f92ffea7;mod=1;room-id=111448817;subscriber=1;tmi-sent-ts=1567811485257;turbo=0;user-id=207114672;user-type=mod :k4izn!k4izn@k4izn.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Kleiner Cheer(s) !)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=subscriber/12;badges=subscriber/12,bits/1000;bits=20;color=#00CCFF;display-name=YaBoiBurnsy;emotes=;flags=;id=5b53975d-b339-484f-a2a0-3ffbedde0df2;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567529634584;turbo=0;user-id=45258137;user-type= :yaboiburnsy!yaboiburnsy@yaboiburnsy.tmi.twitch.tv PRIVMSG #pajlada :ShowLove20)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=subscriber/1;badges=moderator/1,subscriber/0,bits-leader/2;bits=1;color=;display-name=jdfellie;emotes=;flags=18-22:A.3/P.5;id=28c8f4b7-b1e3-4404-b0f8-5cfe46411ef9;mod=1;room-id=111448817;subscriber=1;tmi-sent-ts=1567668177856;turbo=0;user-id=137619637;user-type=mod :jdfellie!jdfellie@jdfellie.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 take a bit bitch)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/2;bits=30;color=#EC3B83;display-name=Sammay;emotes=;flags=;id=ccf058a6-c1f1-45de-a764-fc8f96f21449;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1566719874294;turbo=0;user-id=58283830;user-type= :sammay!sammay@sammay.tmi.twitch.tv PRIVMSG #pajlada :ShowLove30 @Emperor_Zhang)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/2;bits=6;color=#97E7FF;display-name=Emperor_Zhang;emotes=;flags=;id=53bab01b-9f6c-4123-a852-9916ab371cf9;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1566719803345;turbo=0;user-id=105292882;user-type= :emperor_zhang!emperor_zhang@emperor_zhang.tmi.twitch.tv PRIVMSG #pajlada :uni6)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits/1;bits=5;color=#97E7FF;display-name=Emperor_Zhang;emotes=;flags=;id=545caec6-8b5f-460a-8b4b-3e407e179689;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1566704926380;turbo=0;user-id=105292882;user-type= :emperor_zhang!emperor_zhang@emperor_zhang.tmi.twitch.tv PRIVMSG #pajlada :VoHiYo5)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits/100;bits=50;color=;display-name=Schmiddi55;emotes=;flags=;id=777f1018-941d-48aa-bf4e-ed8053d556c8;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567708393343;turbo=0;user-id=101444120;user-type= :schmiddi55!schmiddi55@schmiddi55.tmi.twitch.tv PRIVMSG #pajlada :cheer50 sere ihr radlertrinker)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=subscriber/3;badges=subscriber/3,sub-gifter/10;bits=100;color=#0000FF;display-name=MLPTheChad;emotes=;flags=87-91:P.5;id=ed7db31e-884b-4761-9c88-b1676caa8814;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567681752733;turbo=0;user-id=63179867;user-type= :mlpthechad!mlpthechad@mlpthechad.tmi.twitch.tv PRIVMSG #pajlada :Subway100 bonus10 Statistically speaking, 10 out of 10 constipated people don't give a shit.)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=subscriber/3;badges=subscriber/3,sub-gifter/10;bits=100;color=#0000FF;display-name=MLPTheChad;emotes=;flags=;id=506b482a-515a-4914-a694-2c69d2add23a;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567681618814;turbo=0;user-id=63179867;user-type= :mlpthechad!mlpthechad@mlpthechad.tmi.twitch.tv PRIVMSG #pajlada :Subway100 bonus10 That's some SUB par gameplay, Dabier.)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=premium/1;bits=100;color=;display-name=AkiraKurusu__;emotes=;flags=;id=6e343f5d-0e0e-47f7-bf6d-d5d7bf18b95a;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567765732657;turbo=0;user-id=151679027;user-type= :akirakurusu__!akirakurusu__@akirakurusu__.tmi.twitch.tv PRIVMSG #pajlada :TriHard100)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=premium/1;bits=1;color=;display-name=AkiraKurusu__;emotes=;flags=;id=dfdf6c2f-abee-4a4b-99fe-0d0b221f07de;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567765295301;turbo=0;user-id=151679027;user-type= :akirakurusu__!akirakurusu__@akirakurusu__.tmi.twitch.tv PRIVMSG #pajlada :TriHard1)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits/100;bits=500;color=#0000FF;display-name=Stabbr;emotes=;flags=;id=e28b384e-fb6a-4da5-9a36-1b6153c6089d;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567648284623;turbo=0;user-id=183081176;user-type= :stabbr!stabbr@stabbr.tmi.twitch.tv PRIVMSG #pajlada :cheer500 Gotta be on top)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=subscriber/1;badges=subscriber/0,bits-leader/1;bits=100;color=;display-name=dbf_sub;emotes=;flags=;id=7cf317b8-6e28-4615-a0ba-e0bbaa0d4b29;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567646349560;turbo=0;user-id=450101746;user-type= :dbf_sub!dbf_sub@dbf_sub.tmi.twitch.tv PRIVMSG #pajlada :EleGiggle100)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=subscriber/1;badges=subscriber/0,bits/1;bits=1;color=;display-name=dbf_sub;emotes=;flags=;id=43b5fc97-e7cc-4ac1-8d7e-7504c435c3f1;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567643510222;turbo=0;user-id=450101746;user-type= :dbf_sub!dbf_sub@dbf_sub.tmi.twitch.tv PRIVMSG #pajlada :SeemsGood1)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/2;bits=100;color=;display-name=RobertsonRobotics;emotes=;flags=;id=598dfa14-23e9-4e45-a2fe-7a0263828817;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567873463820;turbo=0;user-id=117177721;user-type= :robertsonrobotics!robertsonrobotics@robertsonrobotics.tmi.twitch.tv PRIVMSG #pajlada :firstCheer100 This is so cool! Can’t wait for the competition!)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits/100;bits=18;color=#1E90FF;display-name=Vipacman11;emotes=;flags=;id=07f59664-0c75-459e-b137-26c8d03e44be;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567873210379;turbo=0;user-id=89634839;user-type= :vipacman11!vipacman11@vipacman11.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=sub-gifter/5;bits=100;color=#FF7F50;display-name=darkside_sinner;emotes=;flags=;id=090102b3-369d-4ce4-ad1f-283849b10de0;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567822075293;turbo=0;user-id=104942909;user-type= :darkside_sinner!darkside_sinner@darkside_sinner.tmi.twitch.tv PRIVMSG #pajlada :Subway100 bonus10)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=sub-gifter/5;bits=200;color=#FF7F50;display-name=darkside_sinner;emotes=;flags=;id=2bdf7846-5ffa-4798-a397-997e7209a6d0;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567821695287;turbo=0;user-id=104942909;user-type= :darkside_sinner!darkside_sinner@darkside_sinner.tmi.twitch.tv PRIVMSG #pajlada :Subway200 bonus20)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits/1;bits=50;color=#0000FF;display-name=SincereBC;emotes=;flags=;id=b8c9236b-aeb9-4c72-a191-593e33c6c3f1;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567818308913;turbo=0;user-id=146097597;user-type= :sincerebc!sincerebc@sincerebc.tmi.twitch.tv PRIVMSG #pajlada :cheer50)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits/1;bits=1;color=#FF0000;display-name=AngryCh33s3puff;emotes=;flags=;id=6ab62185-ac1b-4ee5-bd93-165009917078;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567474810480;turbo=0;user-id=55399500;user-type= :angrych33s3puff!angrych33s3puff@angrych33s3puff.tmi.twitch.tv PRIVMSG #pajlada :cheer1 for the chair!)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=subscriber/3;badges=moderator/1,subscriber/0,bits/1000;bits=1500;color=#5F9EA0;display-name=LaurenJW28;emotes=;flags=;id=2403678c-6109-43ac-b3b5-1f5230f91729;mod=1;room-id=111448817;subscriber=1;tmi-sent-ts=1567746107991;turbo=0;user-id=244354979;user-type=mod :laurenjw28!laurenjw28@laurenjw28.tmi.twitch.tv PRIVMSG #pajlada :Cheer1000 Cheer100 Cheer100 Cheer100 Cheer100 Cheer100)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits/1;bits=5;color=#5F9EA0;display-name=drkwings;emotes=;flags=;id=ad45dae5-b985-4526-9b9e-0bdba2d23289;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567742106689;turbo=0;user-id=440230526;user-type= :drkwings!drkwings@drkwings.tmi.twitch.tv PRIVMSG #pajlada :SeemsGood1 SeemsGood1 SeemsGood1 SeemsGood1 SeemsGood1)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=subscriber/16;badges=subscriber/12,bits/1000;bits=1;color=;display-name=mustangbugatti;emotes=;flags=;id=ee987ee9-46a4-4c06-bf66-2cafff5d4cdd;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567883658780;turbo=0;user-id=115948494;user-type= :mustangbugatti!mustangbugatti@mustangbugatti.tmi.twitch.tv PRIVMSG #pajlada :(In clarkson accent) Some say...the only number in his contacts is himself..... And...that he is the international butt-dial champion... All we know is.... HES CALLED THE STIG Cheer1)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=subscriber/2;badges=subscriber/0,bits/1000;bits=1;color=;display-name=derpysaurus1;emotes=;flags=;id=c41c3d8b-c591-4db0-87e7-a78c5536de82;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567883655116;turbo=0;user-id=419221818;user-type= :derpysaurus1!derpysaurus1@derpysaurus1.tmi.twitch.tv PRIVMSG #pajlada :cheer1 OMG ur back yaaaaaaaaaaaaaaaaaaaaayyyyyyyyy)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=subscriber/5;badges=subscriber/0,premium/1;bits=1;color=#8A2BE2;display-name=sirlordstallion;emotes=;flags=;id=61a87aeb-88b1-42f9-90f5-74429d8bf387;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567882978939;turbo=0;user-id=92145441;user-type= :sirlordstallion!sirlordstallion@sirlordstallion.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 Alex is definetly not putting his eggs in Narreths basket)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=subscriber/1;badges=subscriber/0,bits/1;bits=1;color=;display-name=xplosivegingerx;emotes=;flags=;id=f8aac1e0-050a-44bf-abcc-c0cf12cbedfc;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567882249072;turbo=0;user-id=151265906;user-type= :xplosivegingerx!xplosivegingerx@xplosivegingerx.tmi.twitch.tv PRIVMSG #pajlada :Cheer1)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits/100;bits=500;color=;display-name=AlexJohanning;emotes=;flags=;id=4e4229a3-e7f2-4082-8c55-47d42db3b09c;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567881969862;turbo=0;user-id=190390930;user-type= :alexjohanning!alexjohanning@alexjohanning.tmi.twitch.tv PRIVMSG #pajlada :cheer500)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/1;bits=245;color=;display-name=undonebunion6;emotes=;flags=;id=331ec583-0a80-4299-9206-0efd9e33d934;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567881553759;turbo=0;user-id=452974274;user-type= :undonebunion6!undonebunion6@undonebunion6.tmi.twitch.tv PRIVMSG #pajlada :cheer245 can I join?)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits/100;bits=100;color=;display-name=therealruffnix;emotes=;flags=61-67:S.6;id=25f567ad-ac95-45ab-b12e-4d647f6a2345;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567524218162;turbo=0;user-id=55059620;user-type= :therealruffnix!therealruffnix@therealruffnix.tmi.twitch.tv PRIVMSG #pajlada :cheer100 This is the kind of ASMR I'm missing on YouTube and PornHub)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits/1;bits=1;color=;display-name=BeamMeUpSnotty;emotes=;flags=;id=8022f41f-dcb8-42f2-b46a-04d4a99180bd;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567270037926;turbo=0;user-id=261679182;user-type= :beammeupsnotty!beammeupsnotty@beammeupsnotty.tmi.twitch.tv PRIVMSG #pajlada :SeemsGood1)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits/1;bits=10;color=#00FF7F;display-name=EXDE_HUN;emotes=;flags=;id=60d8835b-23fa-418c-96ca-5874e5d5e8ba;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1566654664248;turbo=0;user-id=129793695;user-type= :exde_hun!exde_hun@exde_hun.tmi.twitch.tv PRIVMSG #pajlada :PogChamp10)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/3;bits=5;color=;display-name=slyckity;emotes=;flags=;id=fd6c5507-3a4e-4d24-8f6e-fadf07f520d3;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567824273752;turbo=0;user-id=143114011;user-type= :slyckity!slyckity@slyckity.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 Cheer1 Cheer1 Cheer1 Cheer1)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/3;bits=5;color=;display-name=slyckity;emotes=;flags=;id=7003f119-b9a6-4319-a1e8-8e99f96ab01a;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567824186437;turbo=0;user-id=143114011;user-type= :slyckity!slyckity@slyckity.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 Cheer1 Cheer1 Cheer1 Cheer1)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/3;bits=10;color=;display-name=slyckity;emotes=;flags=;id=3f7de686-77f6-46d2-919e-404312c6676f;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567824128736;turbo=0;user-id=143114011;user-type= :slyckity!slyckity@slyckity.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/3;bits=10;color=;display-name=slyckity;emotes=;flags=;id=9e830ed3-8735-4ccb-9a8b-80466598ca19;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567824118921;turbo=0;user-id=143114011;user-type= :slyckity!slyckity@slyckity.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/1;bits=377;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=262f4d54-9b21-4f13-aac3-6d3b1051282f;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440897074;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :NotLikeThis377)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/1;bits=144;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=3556e0ad-b5f8-4190-9c4c-e39c1940d191;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440861545;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :bday144)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/1;bits=89;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=96e380a5-786d-44b8-819a-529b6adb06ac;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440848361;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :SwiftRage89)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/1;bits=34;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=76239011-65fa-4f6a-a6d6-dc5d5dcbd674;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440816630;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :MrDestructoid34)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/1;bits=21;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=4c05c97c-7b6c-4ae9-bc91-04e98240c1d5;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440806389;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :TriHard21)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/1;bits=8;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=3b2ecce7-842e-429e-b6c8-9456c4646362;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440774009;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :EleGiggle8)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/1;bits=5;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=3b8736d1-832d-4152-832a-50c526714fd1;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440762580;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :uni5)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/1;bits=3;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=c13a1540-2a03-4c7d-af50-cb20ed88cefd;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440750103;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :Party3)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/1;bits=2;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=5d889eeb-b6b9-4a4e-91ff-0aecdf297edd;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440738337;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :ShowLove2)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits/1;bits=1;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=da47f91a-40d3-4209-ba1c-0219d8b8ecaf;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440720363;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :Scoops1)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits/1;bits=10;color=#8A2BE2;display-name=EkimSky;emotes=;flags=;id=8adea5b4-7430-44ea-a666-5ebaceb69441;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567833047623;turbo=0;user-id=42132818;user-type= :ekimsky!ekimsky@ekimsky.tmi.twitch.tv PRIVMSG #pajlada :Hi Cheer10)");
|
||||
cheerMessageVector.push_back(R"(@badge-info=;badges=bits-leader/2;bits=500;color=;display-name=godkiller76;emotes=;flags=;id=80e86bcc-d048-44f3-8073-9a1014568e0c;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567753685704;turbo=0;user-id=258838478;user-type= :godkiller76!godkiller76@godkiller76.tmi.twitch.tv PRIVMSG #pajlada :Party100 Party100 Party100 Party100 Party100)");
|
||||
|
||||
return cheerMessageVector;
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
328
src/util/SampleData.cpp
Normal file
328
src/util/SampleData.cpp
Normal file
|
@ -0,0 +1,328 @@
|
|||
#include "SampleData.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
/// Sample messages coming from IRC
|
||||
|
||||
const QStringList &getSampleCheerMessages()
|
||||
{
|
||||
static QStringList list{
|
||||
R"(@badge-info=subscriber/4;badges=moderator/1,subscriber/3,sub-gifter/5;bits=2;color=#FF0000;display-name=69_faith_420;emotes=;flags=;id=c5fd49c7-ecbc-46dd-a790-c9f10fdaaa67;mod=1;room-id=111448817;subscriber=1;tmi-sent-ts=1567282184553;turbo=0;user-id=125608098;user-type=mod :69_faith_420!69_faith_420@69_faith_420.tmi.twitch.tv PRIVMSG #pajlada :cheer2 Stop what? I'm not doing anything.)",
|
||||
R"(@badge-info=subscriber/4;badges=moderator/1,subscriber/3,sub-gifter/5;bits=2;color=#FF0000;display-name=69_faith_420;emotes=;flags=;id=397f4d2e-cac8-4689-922a-32709b9e8b4f;mod=1;room-id=111448817;subscriber=1;tmi-sent-ts=1567282159076;turbo=0;user-id=125608098;user-type=mod :69_faith_420!69_faith_420@69_faith_420.tmi.twitch.tv PRIVMSG #pajlada :cheer2 Who keeps getting their bits out now?)",
|
||||
R"(@badge-info=subscriber/1;badges=subscriber/0,bits/1;bits=2;color=#FF0000;display-name=FlameGodFlann;emotes=;flags=;id=664ddc92-649d-4889-9641-208a6e62ef1e;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567282066199;turbo=0;user-id=56442185;user-type= :flamegodflann!flamegodflann@flamegodflann.tmi.twitch.tv PRIVMSG #pajlada :Cheer2 I'm saving my only can of Stella for your upcoming win, lets go!)",
|
||||
R"(@badge-info=subscriber/3;badges=moderator/1,subscriber/3,bits/100;bits=10;color=#008000;display-name=k4izn;emotes=;flags=;id=3919af0b-93e0-412c-b238-d152f92ffea7;mod=1;room-id=111448817;subscriber=1;tmi-sent-ts=1567811485257;turbo=0;user-id=207114672;user-type=mod :k4izn!k4izn@k4izn.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Kleiner Cheer(s) !)",
|
||||
R"(@badge-info=subscriber/12;badges=subscriber/12,bits/1000;bits=20;color=#00CCFF;display-name=YaBoiBurnsy;emotes=;flags=;id=5b53975d-b339-484f-a2a0-3ffbedde0df2;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567529634584;turbo=0;user-id=45258137;user-type= :yaboiburnsy!yaboiburnsy@yaboiburnsy.tmi.twitch.tv PRIVMSG #pajlada :ShowLove20)",
|
||||
R"(@badge-info=subscriber/1;badges=moderator/1,subscriber/0,bits-leader/2;bits=1;color=;display-name=jdfellie;emotes=;flags=18-22:A.3/P.5;id=28c8f4b7-b1e3-4404-b0f8-5cfe46411ef9;mod=1;room-id=111448817;subscriber=1;tmi-sent-ts=1567668177856;turbo=0;user-id=137619637;user-type=mod :jdfellie!jdfellie@jdfellie.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 take a bit bitch)",
|
||||
R"(@badge-info=;badges=bits-leader/2;bits=30;color=#EC3B83;display-name=Sammay;emotes=;flags=;id=ccf058a6-c1f1-45de-a764-fc8f96f21449;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1566719874294;turbo=0;user-id=58283830;user-type= :sammay!sammay@sammay.tmi.twitch.tv PRIVMSG #pajlada :ShowLove30 @Emperor_Zhang)",
|
||||
R"(@badge-info=;badges=bits-leader/2;bits=6;color=#97E7FF;display-name=Emperor_Zhang;emotes=;flags=;id=53bab01b-9f6c-4123-a852-9916ab371cf9;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1566719803345;turbo=0;user-id=105292882;user-type= :emperor_zhang!emperor_zhang@emperor_zhang.tmi.twitch.tv PRIVMSG #pajlada :uni6)",
|
||||
R"(@badge-info=;badges=bits/1;bits=5;color=#97E7FF;display-name=Emperor_Zhang;emotes=;flags=;id=545caec6-8b5f-460a-8b4b-3e407e179689;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1566704926380;turbo=0;user-id=105292882;user-type= :emperor_zhang!emperor_zhang@emperor_zhang.tmi.twitch.tv PRIVMSG #pajlada :VoHiYo5)",
|
||||
R"(@badge-info=;badges=bits/100;bits=50;color=;display-name=Schmiddi55;emotes=;flags=;id=777f1018-941d-48aa-bf4e-ed8053d556c8;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567708393343;turbo=0;user-id=101444120;user-type= :schmiddi55!schmiddi55@schmiddi55.tmi.twitch.tv PRIVMSG #pajlada :cheer50 sere ihr radlertrinker)",
|
||||
R"(@badge-info=subscriber/3;badges=subscriber/3,sub-gifter/10;bits=100;color=#0000FF;display-name=MLPTheChad;emotes=;flags=87-91:P.5;id=ed7db31e-884b-4761-9c88-b1676caa8814;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567681752733;turbo=0;user-id=63179867;user-type= :mlpthechad!mlpthechad@mlpthechad.tmi.twitch.tv PRIVMSG #pajlada :Subway100 bonus10 Statistically speaking, 10 out of 10 constipated people don't give a shit.)",
|
||||
R"(@badge-info=subscriber/3;badges=subscriber/3,sub-gifter/10;bits=100;color=#0000FF;display-name=MLPTheChad;emotes=;flags=;id=506b482a-515a-4914-a694-2c69d2add23a;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567681618814;turbo=0;user-id=63179867;user-type= :mlpthechad!mlpthechad@mlpthechad.tmi.twitch.tv PRIVMSG #pajlada :Subway100 bonus10 That's some SUB par gameplay, Dabier.)",
|
||||
R"(@badge-info=;badges=premium/1;bits=100;color=;display-name=AkiraKurusu__;emotes=;flags=;id=6e343f5d-0e0e-47f7-bf6d-d5d7bf18b95a;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567765732657;turbo=0;user-id=151679027;user-type= :akirakurusu__!akirakurusu__@akirakurusu__.tmi.twitch.tv PRIVMSG #pajlada :TriHard100)",
|
||||
R"(@badge-info=;badges=premium/1;bits=1;color=;display-name=AkiraKurusu__;emotes=;flags=;id=dfdf6c2f-abee-4a4b-99fe-0d0b221f07de;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567765295301;turbo=0;user-id=151679027;user-type= :akirakurusu__!akirakurusu__@akirakurusu__.tmi.twitch.tv PRIVMSG #pajlada :TriHard1)",
|
||||
R"(@badge-info=;badges=bits/100;bits=500;color=#0000FF;display-name=Stabbr;emotes=;flags=;id=e28b384e-fb6a-4da5-9a36-1b6153c6089d;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567648284623;turbo=0;user-id=183081176;user-type= :stabbr!stabbr@stabbr.tmi.twitch.tv PRIVMSG #pajlada :cheer500 Gotta be on top)",
|
||||
R"(@badge-info=subscriber/1;badges=subscriber/0,bits-leader/1;bits=100;color=;display-name=dbf_sub;emotes=;flags=;id=7cf317b8-6e28-4615-a0ba-e0bbaa0d4b29;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567646349560;turbo=0;user-id=450101746;user-type= :dbf_sub!dbf_sub@dbf_sub.tmi.twitch.tv PRIVMSG #pajlada :EleGiggle100)",
|
||||
R"(@badge-info=subscriber/1;badges=subscriber/0,bits/1;bits=1;color=;display-name=dbf_sub;emotes=;flags=;id=43b5fc97-e7cc-4ac1-8d7e-7504c435c3f1;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567643510222;turbo=0;user-id=450101746;user-type= :dbf_sub!dbf_sub@dbf_sub.tmi.twitch.tv PRIVMSG #pajlada :SeemsGood1)",
|
||||
R"(@badge-info=;badges=bits-leader/2;bits=100;color=;display-name=RobertsonRobotics;emotes=;flags=;id=598dfa14-23e9-4e45-a2fe-7a0263828817;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567873463820;turbo=0;user-id=117177721;user-type= :robertsonrobotics!robertsonrobotics@robertsonrobotics.tmi.twitch.tv PRIVMSG #pajlada :firstCheer100 This is so cool! Can’t wait for the competition!)",
|
||||
R"(@badge-info=;badges=bits/100;bits=18;color=#1E90FF;display-name=Vipacman11;emotes=;flags=;id=07f59664-0c75-459e-b137-26c8d03e44be;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567873210379;turbo=0;user-id=89634839;user-type= :vipacman11!vipacman11@vipacman11.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1)",
|
||||
R"(@badge-info=;badges=sub-gifter/5;bits=100;color=#FF7F50;display-name=darkside_sinner;emotes=;flags=;id=090102b3-369d-4ce4-ad1f-283849b10de0;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567822075293;turbo=0;user-id=104942909;user-type= :darkside_sinner!darkside_sinner@darkside_sinner.tmi.twitch.tv PRIVMSG #pajlada :Subway100 bonus10)",
|
||||
R"(@badge-info=;badges=sub-gifter/5;bits=200;color=#FF7F50;display-name=darkside_sinner;emotes=;flags=;id=2bdf7846-5ffa-4798-a397-997e7209a6d0;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567821695287;turbo=0;user-id=104942909;user-type= :darkside_sinner!darkside_sinner@darkside_sinner.tmi.twitch.tv PRIVMSG #pajlada :Subway200 bonus20)",
|
||||
R"(@badge-info=;badges=bits/1;bits=50;color=#0000FF;display-name=SincereBC;emotes=;flags=;id=b8c9236b-aeb9-4c72-a191-593e33c6c3f1;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567818308913;turbo=0;user-id=146097597;user-type= :sincerebc!sincerebc@sincerebc.tmi.twitch.tv PRIVMSG #pajlada :cheer50)",
|
||||
R"(@badge-info=;badges=bits/1;bits=1;color=#FF0000;display-name=AngryCh33s3puff;emotes=;flags=;id=6ab62185-ac1b-4ee5-bd93-165009917078;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567474810480;turbo=0;user-id=55399500;user-type= :angrych33s3puff!angrych33s3puff@angrych33s3puff.tmi.twitch.tv PRIVMSG #pajlada :cheer1 for the chair!)",
|
||||
R"(@badge-info=subscriber/3;badges=moderator/1,subscriber/0,bits/1000;bits=1500;color=#5F9EA0;display-name=LaurenJW28;emotes=;flags=;id=2403678c-6109-43ac-b3b5-1f5230f91729;mod=1;room-id=111448817;subscriber=1;tmi-sent-ts=1567746107991;turbo=0;user-id=244354979;user-type=mod :laurenjw28!laurenjw28@laurenjw28.tmi.twitch.tv PRIVMSG #pajlada :Cheer1000 Cheer100 Cheer100 Cheer100 Cheer100 Cheer100)",
|
||||
R"(@badge-info=;badges=bits/1;bits=5;color=#5F9EA0;display-name=drkwings;emotes=;flags=;id=ad45dae5-b985-4526-9b9e-0bdba2d23289;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567742106689;turbo=0;user-id=440230526;user-type= :drkwings!drkwings@drkwings.tmi.twitch.tv PRIVMSG #pajlada :SeemsGood1 SeemsGood1 SeemsGood1 SeemsGood1 SeemsGood1)",
|
||||
R"(@badge-info=subscriber/16;badges=subscriber/12,bits/1000;bits=1;color=;display-name=mustangbugatti;emotes=;flags=;id=ee987ee9-46a4-4c06-bf66-2cafff5d4cdd;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567883658780;turbo=0;user-id=115948494;user-type= :mustangbugatti!mustangbugatti@mustangbugatti.tmi.twitch.tv PRIVMSG #pajlada :(In clarkson accent) Some say...the only number in his contacts is himself..... And...that he is the international butt-dial champion... All we know is.... HES CALLED THE STIG Cheer1)",
|
||||
R"(@badge-info=subscriber/2;badges=subscriber/0,bits/1000;bits=1;color=;display-name=derpysaurus1;emotes=;flags=;id=c41c3d8b-c591-4db0-87e7-a78c5536de82;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567883655116;turbo=0;user-id=419221818;user-type= :derpysaurus1!derpysaurus1@derpysaurus1.tmi.twitch.tv PRIVMSG #pajlada :cheer1 OMG ur back yaaaaaaaaaaaaaaaaaaaaayyyyyyyyy)",
|
||||
R"(@badge-info=subscriber/5;badges=subscriber/0,premium/1;bits=1;color=#8A2BE2;display-name=sirlordstallion;emotes=;flags=;id=61a87aeb-88b1-42f9-90f5-74429d8bf387;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567882978939;turbo=0;user-id=92145441;user-type= :sirlordstallion!sirlordstallion@sirlordstallion.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 Alex is definetly not putting his eggs in Narreths basket)",
|
||||
R"(@badge-info=subscriber/1;badges=subscriber/0,bits/1;bits=1;color=;display-name=xplosivegingerx;emotes=;flags=;id=f8aac1e0-050a-44bf-abcc-c0cf12cbedfc;mod=0;room-id=111448817;subscriber=1;tmi-sent-ts=1567882249072;turbo=0;user-id=151265906;user-type= :xplosivegingerx!xplosivegingerx@xplosivegingerx.tmi.twitch.tv PRIVMSG #pajlada :Cheer1)",
|
||||
R"(@badge-info=;badges=bits/100;bits=500;color=;display-name=AlexJohanning;emotes=;flags=;id=4e4229a3-e7f2-4082-8c55-47d42db3b09c;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567881969862;turbo=0;user-id=190390930;user-type= :alexjohanning!alexjohanning@alexjohanning.tmi.twitch.tv PRIVMSG #pajlada :cheer500)",
|
||||
R"(@badge-info=;badges=bits-leader/1;bits=245;color=;display-name=undonebunion6;emotes=;flags=;id=331ec583-0a80-4299-9206-0efd9e33d934;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567881553759;turbo=0;user-id=452974274;user-type= :undonebunion6!undonebunion6@undonebunion6.tmi.twitch.tv PRIVMSG #pajlada :cheer245 can I join?)",
|
||||
R"(@badge-info=;badges=bits/100;bits=100;color=;display-name=therealruffnix;emotes=;flags=61-67:S.6;id=25f567ad-ac95-45ab-b12e-4d647f6a2345;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567524218162;turbo=0;user-id=55059620;user-type= :therealruffnix!therealruffnix@therealruffnix.tmi.twitch.tv PRIVMSG #pajlada :cheer100 This is the kind of ASMR I'm missing on YouTube and PornHub)",
|
||||
R"(@badge-info=;badges=bits/1;bits=1;color=;display-name=BeamMeUpSnotty;emotes=;flags=;id=8022f41f-dcb8-42f2-b46a-04d4a99180bd;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567270037926;turbo=0;user-id=261679182;user-type= :beammeupsnotty!beammeupsnotty@beammeupsnotty.tmi.twitch.tv PRIVMSG #pajlada :SeemsGood1)",
|
||||
R"(@badge-info=;badges=bits/1;bits=10;color=#00FF7F;display-name=EXDE_HUN;emotes=;flags=;id=60d8835b-23fa-418c-96ca-5874e5d5e8ba;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1566654664248;turbo=0;user-id=129793695;user-type= :exde_hun!exde_hun@exde_hun.tmi.twitch.tv PRIVMSG #pajlada :PogChamp10)",
|
||||
R"(@badge-info=;badges=bits-leader/3;bits=5;color=;display-name=slyckity;emotes=;flags=;id=fd6c5507-3a4e-4d24-8f6e-fadf07f520d3;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567824273752;turbo=0;user-id=143114011;user-type= :slyckity!slyckity@slyckity.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 Cheer1 Cheer1 Cheer1 Cheer1)",
|
||||
R"(@badge-info=;badges=bits-leader/3;bits=5;color=;display-name=slyckity;emotes=;flags=;id=7003f119-b9a6-4319-a1e8-8e99f96ab01a;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567824186437;turbo=0;user-id=143114011;user-type= :slyckity!slyckity@slyckity.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 Cheer1 Cheer1 Cheer1 Cheer1)",
|
||||
R"(@badge-info=;badges=bits-leader/3;bits=10;color=;display-name=slyckity;emotes=;flags=;id=3f7de686-77f6-46d2-919e-404312c6676f;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567824128736;turbo=0;user-id=143114011;user-type= :slyckity!slyckity@slyckity.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1)",
|
||||
R"(@badge-info=;badges=bits-leader/3;bits=10;color=;display-name=slyckity;emotes=;flags=;id=9e830ed3-8735-4ccb-9a8b-80466598ca19;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567824118921;turbo=0;user-id=143114011;user-type= :slyckity!slyckity@slyckity.tmi.twitch.tv PRIVMSG #pajlada :Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1 Cheer1)",
|
||||
R"(@badge-info=;badges=bits-leader/1;bits=377;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=262f4d54-9b21-4f13-aac3-6d3b1051282f;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440897074;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :NotLikeThis377)",
|
||||
R"(@badge-info=;badges=bits-leader/1;bits=144;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=3556e0ad-b5f8-4190-9c4c-e39c1940d191;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440861545;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :bday144)",
|
||||
R"(@badge-info=;badges=bits-leader/1;bits=89;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=96e380a5-786d-44b8-819a-529b6adb06ac;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440848361;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :SwiftRage89)",
|
||||
R"(@badge-info=;badges=bits-leader/1;bits=34;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=76239011-65fa-4f6a-a6d6-dc5d5dcbd674;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440816630;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :MrDestructoid34)",
|
||||
R"(@badge-info=;badges=bits-leader/1;bits=21;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=4c05c97c-7b6c-4ae9-bc91-04e98240c1d5;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440806389;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :TriHard21)",
|
||||
R"(@badge-info=;badges=bits-leader/1;bits=8;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=3b2ecce7-842e-429e-b6c8-9456c4646362;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440774009;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :EleGiggle8)",
|
||||
R"(@badge-info=;badges=bits-leader/1;bits=5;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=3b8736d1-832d-4152-832a-50c526714fd1;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440762580;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :uni5)",
|
||||
R"(@badge-info=;badges=bits-leader/1;bits=3;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=c13a1540-2a03-4c7d-af50-cb20ed88cefd;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440750103;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :Party3)",
|
||||
R"(@badge-info=;badges=bits-leader/1;bits=2;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=5d889eeb-b6b9-4a4e-91ff-0aecdf297edd;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440738337;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :ShowLove2)",
|
||||
R"(@badge-info=;badges=bits/1;bits=1;color=#00FF7F;display-name=Baekjoon;emotes=;flags=;id=da47f91a-40d3-4209-ba1c-0219d8b8ecaf;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567440720363;turbo=0;user-id=73587716;user-type= :baekjoon!baekjoon@baekjoon.tmi.twitch.tv PRIVMSG #pajlada :Scoops1)",
|
||||
R"(@badge-info=;badges=bits/1;bits=10;color=#8A2BE2;display-name=EkimSky;emotes=;flags=;id=8adea5b4-7430-44ea-a666-5ebaceb69441;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567833047623;turbo=0;user-id=42132818;user-type= :ekimsky!ekimsky@ekimsky.tmi.twitch.tv PRIVMSG #pajlada :Hi Cheer10)",
|
||||
R"(@badge-info=;badges=bits-leader/2;bits=500;color=;display-name=godkiller76;emotes=;flags=;id=80e86bcc-d048-44f3-8073-9a1014568e0c;mod=0;room-id=111448817;subscriber=0;tmi-sent-ts=1567753685704;turbo=0;user-id=258838478;user-type= :godkiller76!godkiller76@godkiller76.tmi.twitch.tv PRIVMSG #pajlada :Party100 Party100 Party100 Party100 Party100)",
|
||||
};
|
||||
return list;
|
||||
}
|
||||
|
||||
const QStringList &getSampleSubMessages()
|
||||
{
|
||||
static QStringList list{
|
||||
R"(@badges=staff/1,broadcaster/1,turbo/1;color=#008000;display-name=ronni;emotes=;id=db25007f-7a18-43eb-9379-80131e44d633;login=ronni;mod=0;msg-id=resub;msg-param-months=6;msg-param-sub-plan=Prime;msg-param-sub-plan-name=Prime;room-id=1337;subscriber=1;system-msg=ronni\shas\ssubscribed\sfor\s6\smonths!;tmi-sent-ts=1507246572675;turbo=1;user-id=1337;user-type=staff :tmi.twitch.tv USERNOTICE #pajlada :Great stream -- keep it up!)",
|
||||
R"(@badges=staff/1,premium/1;color=#0000FF;display-name=TWW2;emotes=;id=e9176cd8-5e22-4684-ad40-ce53c2561c5e;login=tww2;mod=0;msg-id=subgift;msg-param-months=1;msg-param-recipient-display-name=Mr_Woodchuck;msg-param-recipient-id=89614178;msg-param-recipient-name=mr_woodchuck;msg-param-sub-plan-name=House\sof\sNyoro~n;msg-param-sub-plan=1000;room-id=19571752;subscriber=0;system-msg=TWW2\sgifted\sa\sTier\s1\ssub\sto\sMr_Woodchuck!;tmi-sent-ts=1521159445153;turbo=0;user-id=13405587;user-type=staff :tmi.twitch.tv USERNOTICE #pajlada)",
|
||||
|
||||
// hyperbolicxd gifted a sub to quote_if_nam
|
||||
R"(@badges=subscriber/0,premium/1;color=#00FF7F;display-name=hyperbolicxd;emotes=;id=b20ef4fe-cba8-41d0-a371-6327651dc9cc;login=hyperbolicxd;mod=0;msg-id=subgift;msg-param-months=1;msg-param-recipient-display-name=quote_if_nam;msg-param-recipient-id=217259245;msg-param-recipient-user-name=quote_if_nam;msg-param-sender-count=1;msg-param-sub-plan-name=Channel\sSubscription\s(nymn_hs);msg-param-sub-plan=1000;room-id=62300805;subscriber=1;system-msg=hyperbolicxd\sgifted\sa\sTier\s1\ssub\sto\squote_if_nam!\sThis\sis\stheir\sfirst\sGift\sSub\sin\sthe\schannel!;tmi-sent-ts=1528190938558;turbo=0;user-id=111534250;user-type= :tmi.twitch.tv USERNOTICE #pajlada)",
|
||||
|
||||
// first time sub
|
||||
R"(@badges=subscriber/0,premium/1;color=#0000FF;display-name=byebyeheart;emotes=;id=fe390424-ab89-4c33-bb5a-53c6e5214b9f;login=byebyeheart;mod=0;msg-id=sub;msg-param-months=0;msg-param-sub-plan-name=Dakotaz;msg-param-sub-plan=Prime;room-id=39298218;subscriber=0;system-msg=byebyeheart\sjust\ssubscribed\swith\sTwitch\sPrime!;tmi-sent-ts=1528190963670;turbo=0;user-id=131956000;user-type= :tmi.twitch.tv USERNOTICE #pajlada)",
|
||||
|
||||
// first time sub
|
||||
R"(@badges=subscriber/0,premium/1;color=;display-name=vJoeyzz;emotes=;id=b2476df5-fffe-4338-837b-380c5dd90051;login=vjoeyzz;mod=0;msg-id=sub;msg-param-months=0;msg-param-sub-plan-name=Dakotaz;msg-param-sub-plan=Prime;room-id=39298218;subscriber=0;system-msg=vJoeyzz\sjust\ssubscribed\swith\sTwitch\sPrime!;tmi-sent-ts=1528190995089;turbo=0;user-id=78945903;user-type= :tmi.twitch.tv USERNOTICE #pajlada)",
|
||||
|
||||
// first time sub
|
||||
R"(@badges=subscriber/0,premium/1;color=;display-name=Lennydog3;emotes=;id=44feb1eb-df60-45f6-904b-7bf0d5375a41;login=lennydog3;mod=0;msg-id=sub;msg-param-months=0;msg-param-sub-plan-name=Dakotaz;msg-param-sub-plan=Prime;room-id=39298218;subscriber=0;system-msg=Lennydog3\sjust\ssubscribed\swith\sTwitch\sPrime!;tmi-sent-ts=1528191098733;turbo=0;user-id=175759335;user-type= :tmi.twitch.tv USERNOTICE #pajlada)",
|
||||
|
||||
// resub with message
|
||||
R"(@badges=subscriber/0,premium/1;color=#1E90FF;display-name=OscarLord;emotes=;id=376529fd-31a8-4da9-9c0d-92a9470da2cd;login=oscarlord;mod=0;msg-id=resub;msg-param-months=2;msg-param-sub-plan-name=Dakotaz;msg-param-sub-plan=1000;room-id=39298218;subscriber=1;system-msg=OscarLord\sjust\ssubscribed\swith\sa\sTier\s1\ssub.\sOscarLord\ssubscribed\sfor\s2\smonths\sin\sa\srow!;tmi-sent-ts=1528191154801;turbo=0;user-id=162607810;user-type= :tmi.twitch.tv USERNOTICE #pajlada :Hey dk love to watch your streams keep up the good work)",
|
||||
|
||||
// resub with message
|
||||
R"(@badges=subscriber/0,premium/1;color=;display-name=samewl;emotes=9:22-23;id=599fda87-ca1e-41f2-9af7-6a28208daf1c;login=samewl;mod=0;msg-id=resub;msg-param-months=5;msg-param-sub-plan-name=Channel\sSubscription\s(forsenlol);msg-param-sub-plan=Prime;room-id=22484632;subscriber=1;system-msg=samewl\sjust\ssubscribed\swith\sTwitch\sPrime.\ssamewl\ssubscribed\sfor\s5\smonths\sin\sa\srow!;tmi-sent-ts=1528191317948;turbo=0;user-id=70273207;user-type= :tmi.twitch.tv USERNOTICE #pajlada :lot of love sebastian <3)",
|
||||
|
||||
// resub without message
|
||||
R"(@badges=subscriber/12;color=#CC00C2;display-name=cspice;emotes=;id=6fc4c3e0-ca61-454a-84b8-5669dee69fc9;login=cspice;mod=0;msg-id=resub;msg-param-months=12;msg-param-sub-plan-name=Channel\sSubscription\s(forsenlol):\s$9.99\sSub;msg-param-sub-plan=2000;room-id=22484632;subscriber=1;system-msg=cspice\sjust\ssubscribed\swith\sa\sTier\s2\ssub.\scspice\ssubscribed\sfor\s12\smonths\sin\sa\srow!;tmi-sent-ts=1528192510808;turbo=0;user-id=47894662;user-type= :tmi.twitch.tv USERNOTICE #pajlada)",
|
||||
};
|
||||
return list;
|
||||
}
|
||||
|
||||
const QStringList &getSampleMiscMessages()
|
||||
{
|
||||
static QStringList list{
|
||||
// display name renders strangely
|
||||
R"(@badges=;color=#00AD2B;display-name=Iamme420\s;emotes=;id=d47a1e4b-a3c6-4b9e-9bf1-51b8f3dbc76e;mod=0;room-id=11148817;subscriber=0;tmi-sent-ts=1529670347537;turbo=0;user-id=56422869;user-type= :iamme420!iamme420@iamme420.tmi.twitch.tv PRIVMSG #pajlada :offline chat gachiBASS)",
|
||||
R"(@badge-info=founder/47;badges=moderator/1,founder/0,premium/1;color=#00FF80;display-name=gempir;emotes=;flags=;id=d4514490-202e-43cb-b429-ef01a9d9c2fe;mod=1;room-id=11148817;subscriber=0;tmi-sent-ts=1575198233854;turbo=0;user-id=77829817;user-type=mod :gempir!gempir@gempir.tmi.twitch.tv PRIVMSG #pajlada :offline chat gachiBASS)",
|
||||
|
||||
// "first time chat" message
|
||||
R"(@badge-info=;badges=glhf-pledge/1;client-nonce=5d2627b0cbe56fa05faf5420def4807d;color=#1E90FF;display-name=oldcoeur;emote-only=1;emotes=84608:0-7;first-msg=1;flags=;id=7412fea4-8683-4cc9-a506-4228127a5c2d;mod=0;room-id=11148817;subscriber=0;tmi-sent-ts=1623429859222;turbo=0;user-id=139147886;user-type= :oldcoeur!oldcoeur@oldcoeur.tmi.twitch.tv PRIVMSG #pajlada :cmonBruh)",
|
||||
|
||||
// Message with founder badge
|
||||
R"(@badge-info=founder/72;badges=founder/0,bits/5000;color=#FF0000;display-name=TranRed;emotes=;first-msg=0;flags=;id=7482163f-493d-41d9-b36f-fba50e0701b7;mod=0;room-id=11148817;subscriber=0;tmi-sent-ts=1641123773885;turbo=0;user-id=57019243;user-type= :tranred!tranred@tranred.tmi.twitch.tv PRIVMSG #pajlada :GFMP pajaE)",
|
||||
|
||||
// mod announcement
|
||||
R"(@badge-info=subscriber/47;badges=broadcaster/1,subscriber/3012,twitchconAmsterdam2020/1;color=#FF0000;display-name=Supinic;emotes=;flags=;id=8c26e1ab-b50c-4d9d-bc11-3fd57a941d90;login=supinic;mod=0;msg-id=announcement;msg-param-color=PRIMARY;room-id=31400525;subscriber=1;system-msg=;tmi-sent-ts=1648762219962;user-id=31400525;user-type= :tmi.twitch.tv USERNOTICE #supinic :mm test lol)",
|
||||
};
|
||||
return list;
|
||||
}
|
||||
|
||||
const QStringList &getSampleEmoteTestMessages()
|
||||
{
|
||||
static QStringList list{
|
||||
R"(@badge-info=subscriber/3;badges=subscriber/3;color=#0000FF;display-name=Linkoping;emotes=25:40-44;flags=17-26:S.6;id=744f9c58-b180-4f46-bd9e-b515b5ef75c1;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1566335866017;turbo=0;user-id=91673457;user-type= :linkoping!linkoping@linkoping.tmi.twitch.tv PRIVMSG #pajlada :Då kan du begära skadestånd och förtal Kappa)",
|
||||
R"(@badge-info=subscriber/1;badges=subscriber/0;color=;display-name=jhoelsc;emotes=301683486:46-58,60-72,74-86/301683544:88-100;flags=0-4:S.6;id=1f1afcdd-d94c-4699-b35f-d214deb1e11a;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1588640587462;turbo=0;user-id=505763008;user-type= :jhoelsc!jhoelsc@jhoelsc.tmi.twitch.tv PRIVMSG #pajlada :pensé que no habría directo que bueno que si staryuukiLove staryuukiLove staryuukiLove staryuukiBits)",
|
||||
R"(@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=41:6-13,16-23;flags=;id=97c28382-e8d2-45a0-bb5d-2305fc4ef139;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922036771;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kreygasm, Kreygasm)",
|
||||
R"(@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=25:24-28/41:6-13,15-22;flags=;id=5a36536b-a952-43f7-9c41-88c829371b7a;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922039721;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kreygasm,Kreygasm Kappa (no space then space))",
|
||||
R"(@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=25:6-10/1902:12-16/88:18-25;flags=;id=aed9e67e-f8cd-493e-aa6b-da054edd7292;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922042881;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kappa.Keepo.PogChamp.extratext (3 emotes with extra text))",
|
||||
R"(@badge-info=;badges=moderator/1,partner/1;color=#5B99FF;display-name=StreamElements;emotes=86:30-39/822112:73-79;flags=22-27:S.5;id=03c3eec9-afd1-4858-a2e0-fccbf6ad8d1a;mod=1;room-id=11148817;subscriber=0;tmi-sent-ts=1588638345928;turbo=0;user-id=100135110;user-type=mod :streamelements!streamelements@streamelements.tmi.twitch.tv PRIVMSG #pajlada :╔ACTION A LOJA AINDA NÃO ESTÁ PRONTA BibleThump , AGUARDE... NOVIDADES EM BREVE FortOne╔)",
|
||||
R"(@badge-info=subscriber/20;badges=moderator/1,subscriber/12;color=#19E6E6;display-name=randers;emotes=25:39-43;flags=;id=3ea97f01-abb2-4acf-bdb8-f52e79cd0324;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1588837097115;turbo=0;user-id=40286300;user-type=mod :randers!randers@randers.tmi.twitch.tv PRIVMSG #pajlada :Då kan du begära skadestånd och förtal Kappa)",
|
||||
R"(@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=41:6-13,15-22;flags=;id=a3196c7e-be4c-4b49-9c5a-8b8302b50c2a;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922213730;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kreygasm,Kreygasm (no space))",
|
||||
};
|
||||
return list;
|
||||
}
|
||||
|
||||
/// Channel point reward tests
|
||||
|
||||
const QString &getSampleChannelRewardMessage()
|
||||
{
|
||||
static QString str{
|
||||
R"({ "type": "MESSAGE", "data": { "topic": "community-points-channel-v1.11148817", "message": { "type": "reward-redeemed", "data": { "timestamp": "2020-07-13T20:19:31.430785354Z", "redemption": { "id": "b9628798-1b4e-4122-b2a6-031658df6755", "user": { "id": "91800084", "login": "cranken1337", "display_name": "cranken1337" }, "channel_id": "11148817", "redeemed_at": "2020-07-13T20:19:31.345237005Z", "reward": { "id": "313969fe-cc9f-4a0a-83c6-172acbd96957", "channel_id": "11148817", "title": "annoying reward pogchamp", "prompt": "", "cost": 3000, "is_user_input_required": true, "is_sub_only": false, "image": null, "default_image": { "url_1x": "https://static-cdn.jtvnw.net/custom-reward-images/default-1.png", "url_2x": "https://static-cdn.jtvnw.net/custom-reward-images/default-2.png", "url_4x": "https://static-cdn.jtvnw.net/custom-reward-images/default-4.png" }, "background_color": "#52ACEC", "is_enabled": true, "is_paused": false, "is_in_stock": true, "max_per_stream": { "is_enabled": false, "max_per_stream": 0 }, "should_redemptions_skip_request_queue": false, "template_id": null, "updated_for_indicator_at": "2020-01-20T04:33:33.624956679Z" }, "user_input": "wow, amazing reward", "status": "UNFULFILLED", "cursor": "Yjk2Mjg3OTgtMWI0ZS00MTIyLWIyYTYtMDMxNjU4ZGY2NzU1X18yMDIwLTA3LTEzVDIwOjE5OjMxLjM0NTIzNzAwNVo=" } } } } })",
|
||||
};
|
||||
return str;
|
||||
}
|
||||
|
||||
const QString &getSampleChannelRewardMessage2()
|
||||
{
|
||||
static QString str{
|
||||
R"({ "type": "MESSAGE", "data": { "topic": "community-points-channel-v1.11148817", "message": { "type": "reward-redeemed", "data": { "timestamp": "2020-07-13T20:19:31.430785354Z", "redemption": { "id": "b9628798-1b4e-4122-b2a6-031658df6755", "user": { "id": "91800084", "login": "cranken1337", "display_name": "cranken1337" }, "channel_id": "11148817", "redeemed_at": "2020-07-13T20:19:31.345237005Z", "reward": { "id": "313969fe-cc9f-4a0a-83c6-172acbd96957", "channel_id": "11148817", "title": "annoying reward pogchamp", "prompt": "", "cost": 3000, "is_user_input_required": false, "is_sub_only": false, "image": null, "default_image": { "url_1x": "https://static-cdn.jtvnw.net/custom-reward-images/default-1.png", "url_2x": "https://static-cdn.jtvnw.net/custom-reward-images/default-2.png", "url_4x": "https://static-cdn.jtvnw.net/custom-reward-images/default-4.png" }, "background_color": "#52ACEC", "is_enabled": true, "is_paused": false, "is_in_stock": true, "max_per_stream": { "is_enabled": false, "max_per_stream": 0 }, "should_redemptions_skip_request_queue": false, "template_id": null, "updated_for_indicator_at": "2020-01-20T04:33:33.624956679Z" }, "status": "UNFULFILLED", "cursor": "Yjk2Mjg3OTgtMWI0ZS00MTIyLWIyYTYtMDMxNjU4ZGY2NzU1X18yMDIwLTA3LTEzVDIwOjE5OjMxLjM0NTIzNzAwNVo=" } } } } })",
|
||||
};
|
||||
return str;
|
||||
}
|
||||
|
||||
const QString &getSampleChannelRewardIRCMessage()
|
||||
{
|
||||
static QString str{
|
||||
R"(@badge-info=subscriber/43;badges=subscriber/42;color=#1E90FF;custom-reward-id=313969fe-cc9f-4a0a-83c6-172acbd96957;display-name=Cranken1337;emotes=;flags=;id=3cee3f27-a1d0-44d1-a606-722cebdad08b;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1594756484132;turbo=0;user-id=91800084;user-type= :cranken1337!cranken1337@cranken1337.tmi.twitch.tv PRIVMSG #pajlada :wow, amazing reward)",
|
||||
};
|
||||
return str;
|
||||
};
|
||||
|
||||
/// Links
|
||||
|
||||
const QStringList &getSampleLinkMessages()
|
||||
{
|
||||
static QStringList validLinks{
|
||||
R"(http://github.com/)",
|
||||
R"(https://github.com/)",
|
||||
R"(http://username@github.com/)",
|
||||
R"(https://username@github.com/)",
|
||||
R"(http://pajlada.github.io)",
|
||||
R"(https://pajlada.github.io)",
|
||||
R"(http://pajlada.github.io/)",
|
||||
R"(https://pajlada.github.io/)",
|
||||
R"(http://github.com/some/random/path)",
|
||||
R"(https://github.com/some/random/path)",
|
||||
R"(http://github.com?query=value)",
|
||||
R"(https://github.com?query=value)",
|
||||
R"(http://github.com?query=value&abc=123)",
|
||||
R"(https://github.com?query=value&abc=123)",
|
||||
R"(http://github.com/?query=value&abc=123&yhf=abc_def)",
|
||||
R"(http://github.com/?query=value&abc=123&yhf)",
|
||||
R"(http://github.com?query=value&abc=)",
|
||||
R"(http://github.com?query=value&abc=)",
|
||||
R"(http://github.com/#block)",
|
||||
R"(https://github.com/#anchor)",
|
||||
R"(http://github.com/path/?qs=true#block)",
|
||||
R"(https://github.com/path/?qs=true#anchor)",
|
||||
R"(github.com/)",
|
||||
R"(username@github.com/)",
|
||||
R"(pajlada.github.io)",
|
||||
R"(pajlada.github.io/)",
|
||||
R"(github.com/some/random/path)",
|
||||
R"(github.com?query=value)",
|
||||
R"(github.com?query=value&abc=123)",
|
||||
R"(github.com/?query=value&abc=123&yhf=abc_def)",
|
||||
R"(github.com/?query=value&abc=123&yhf)",
|
||||
R"(github.com?query=value&abc=)",
|
||||
R"(github.com?query=value&abc=)",
|
||||
R"(github.com/#block)",
|
||||
R"(github.com/path/?qs=true#block)",
|
||||
R"(HTTP://GITHUB.COM/)",
|
||||
R"(HTTPS://GITHUB.COM/)",
|
||||
R"(HTTP://USERNAME@GITHUB.COM/)",
|
||||
R"(HTTPS://USERNAME@GITHUB.COM/)",
|
||||
R"(HTTP://PAJLADA.GITHUB.IO)",
|
||||
R"(HTTPS://PAJLADA.GITHUB.IO)",
|
||||
R"(HTTP://PAJLADA.GITHUB.IO/)",
|
||||
R"(HTTPS://PAJLADA.GITHUB.IO/)",
|
||||
R"(HTTP://GITHUB.COM/SOME/RANDOM/PATH)",
|
||||
R"(HTTPS://GITHUB.COM/SOME/RANDOM/PATH)",
|
||||
R"(HTTP://GITHUB.COM?QUERY=VALUE)",
|
||||
R"(HTTPS://GITHUB.COM?QUERY=VALUE)",
|
||||
R"(HTTP://GITHUB.COM?QUERY=VALUE&ABC=123)",
|
||||
R"(HTTPS://GITHUB.COM?QUERY=VALUE&ABC=123)",
|
||||
R"(HTTP://GITHUB.COM/?QUERY=VALUE&ABC=123&YHF=ABC_DEF)",
|
||||
R"(HTTP://GITHUB.COM/?QUERY=VALUE&ABC=123&YHF)",
|
||||
R"(HTTP://GITHUB.COM?QUERY=VALUE&ABC=)",
|
||||
R"(HTTP://GITHUB.COM?QUERY=VALUE&ABC=)",
|
||||
R"(HTTP://GITHUB.COM/#BLOCK)",
|
||||
R"(HTTPS://GITHUB.COM/#ANCHOR)",
|
||||
R"(HTTP://GITHUB.COM/PATH/?QS=TRUE#BLOCK)",
|
||||
R"(HTTPS://GITHUB.COM/PATH/?QS=TRUE#ANCHOR)",
|
||||
R"(GITHUB.COM/)",
|
||||
R"(USERNAME@GITHUB.COM/)",
|
||||
R"(PAJLADA.GITHUB.IO)",
|
||||
R"(PAJLADA.GITHUB.IO/)",
|
||||
R"(GITHUB.COM/SOME/RANDOM/PATH)",
|
||||
R"(GITHUB.COM?QUERY=VALUE)",
|
||||
R"(GITHUB.COM?QUERY=VALUE&ABC=123)",
|
||||
R"(GITHUB.COM/?QUERY=VALUE&ABC=123&YHF=ABC_DEF)",
|
||||
R"(GITHUB.COM/?QUERY=VALUE&ABC=123&YHF)",
|
||||
R"(GITHUB.COM?QUERY=VALUE&ABC=)",
|
||||
R"(GITHUB.COM?QUERY=VALUE&ABC=)",
|
||||
R"(GITHUB.COM/#BLOCK)",
|
||||
R"(GITHUB.COM/PATH/?QS=TRUE#BLOCK)",
|
||||
R"(http://foo.com/blah_blah)",
|
||||
R"(http://foo.com/blah_blah/)",
|
||||
R"(http://foo.com/blah_blah_(wikipedia))",
|
||||
R"(http://foo.com/blah_blah_(wikipedia)_(again))",
|
||||
R"(http://www.example.com/wpstyle/?p=364)",
|
||||
R"(https://www.example.com/foo/?bar=baz&inga=42&quux)",
|
||||
R"(http://✪df.ws/123)",
|
||||
R"(http://userid@example.com)",
|
||||
R"(http://userid@example.com/)",
|
||||
R"(http://userid@example.com:8080)",
|
||||
R"(http://userid@example.com:8080/)",
|
||||
R"(http://142.42.1.1/)",
|
||||
R"(http://142.42.1.1:8080/)",
|
||||
R"(http://➡.ws/䨹)",
|
||||
R"(http://⌘.ws)",
|
||||
R"(http://⌘.ws/)",
|
||||
R"(http://foo.com/blah_(wikipedia)#cite-1)",
|
||||
R"(http://foo.com/blah_(wikipedia)_blah#cite-1)",
|
||||
R"(http://foo.com/unicode_(✪)_in_parens)",
|
||||
R"(http://foo.com/(something)?after=parens)",
|
||||
R"(http://☺.damowmow.com/)",
|
||||
R"(http://code.google.com/events/#&product=browser)",
|
||||
R"(http://j.mp)",
|
||||
R"(ftp://foo.bar/baz)",
|
||||
R"(http://foo.bar/?q=Test%20URL-encoded%20stuff)",
|
||||
R"(http://مثال.إختبار)",
|
||||
R"(http://例子.测试)",
|
||||
R"(http://उदाहरण.परीक्षा)",
|
||||
R"(http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com)",
|
||||
R"(http://1337.net)",
|
||||
R"(http://a.b-c.de)",
|
||||
R"(http://223.255.255.254)",
|
||||
};
|
||||
|
||||
static QStringList validButIgnoredLinks{
|
||||
R"(http://username:password@github.com/)",
|
||||
R"(https://username:password@github.com/)",
|
||||
R"(http://userid:password@example.com)",
|
||||
R"(http://userid:password@example.com/)",
|
||||
R"(http://userid:password@example.com:8080)",
|
||||
R"(http://userid:password@example.com:8080/)",
|
||||
};
|
||||
|
||||
static QStringList invalidLinks{
|
||||
R"(1.40)",
|
||||
R"(test..)",
|
||||
R"(test.)",
|
||||
R"(http://)",
|
||||
R"(http://.)",
|
||||
R"(http://..)",
|
||||
R"(http://../)",
|
||||
R"(http://?)",
|
||||
R"(http://??)",
|
||||
R"(http://??/)",
|
||||
R"(http://#)",
|
||||
R"(http://##)",
|
||||
R"(http://##/)",
|
||||
R"(http://foo.bar?q=Spaces should be encoded)",
|
||||
R"(//)",
|
||||
R"(//a)",
|
||||
R"(///a)",
|
||||
R"(///)",
|
||||
R"(http:///a)",
|
||||
R"(foo.com)",
|
||||
R"(rdar://1234)",
|
||||
R"(h://test)",
|
||||
R"(http:// shouldfail.com)",
|
||||
R"(:// should fail)",
|
||||
R"(http://foo.bar/foo(bar)baz quux)",
|
||||
R"(ftps://foo.bar/)",
|
||||
R"(http://-error-.invalid/)",
|
||||
R"(http://a.b--c.de/)",
|
||||
R"(http://-a.b.co)",
|
||||
R"(http://a.b-.co)",
|
||||
R"(http://0.0.0.0)",
|
||||
R"(http://10.1.1.0)",
|
||||
R"(http://10.1.1.255)",
|
||||
R"(http://224.1.1.1)",
|
||||
R"(http://1.1.1.1.1)",
|
||||
R"(http://123.123.123)",
|
||||
R"(http://3628126748)",
|
||||
R"(http://.www.foo.bar/)",
|
||||
R"(http://www.foo.bar./)",
|
||||
R"(http://.www.foo.bar./)",
|
||||
R"(http://10.1.1.1)",
|
||||
};
|
||||
|
||||
static QStringList linkList{
|
||||
R"(@badge-info=subscriber/48;badges=broadcaster/1,subscriber/36,partner/1;color=#CC44FF;display-name=pajlada;emotes=;flags=;id=3c23cf3c-0864-4699-a76b-089350141147;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1577628844607;turbo=0;user-id=11148817;user-type= :pajlada!pajlada@pajlada.tmi.twitch.tv PRIVMSG #pajlada : Links that should pass: )" +
|
||||
validLinks.join(' '),
|
||||
R"(@badge-info=subscriber/48;badges=broadcaster/1,subscriber/36,partner/1;color=#CC44FF;display-name=pajlada;emotes=;flags=;id=3c23cf3c-0864-4699-a76b-089350141147;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1577628844607;turbo=0;user-id=11148817;user-type= :pajlada!pajlada@pajlada.tmi.twitch.tv PRIVMSG #pajlada : Links that should NOT pass: )" +
|
||||
validButIgnoredLinks.join(' '),
|
||||
R"(@badge-info=subscriber/48;badges=broadcaster/1,subscriber/36,partner/1;color=#CC44FF;display-name=pajlada;emotes=;flags=;id=3c23cf3c-0864-4699-a76b-089350141147;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1577628844607;turbo=0;user-id=11148817;user-type= :pajlada!pajlada@pajlada.tmi.twitch.tv PRIVMSG #pajlada : Links that should technically pass but we choose not to parse them: )" +
|
||||
invalidLinks.join(' '),
|
||||
};
|
||||
|
||||
return linkList;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
24
src/util/SampleData.hpp
Normal file
24
src/util/SampleData.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
/// Sample messages coming from IRC
|
||||
|
||||
const QStringList &getSampleCheerMessages();
|
||||
const QStringList &getSampleSubMessages();
|
||||
const QStringList &getSampleMiscMessages();
|
||||
const QStringList &getSampleEmoteTestMessages();
|
||||
|
||||
/// Channel point reward tests
|
||||
|
||||
const QString &getSampleChannelRewardMessage();
|
||||
const QString &getSampleChannelRewardMessage2();
|
||||
const QString &getSampleChannelRewardIRCMessage();
|
||||
|
||||
/// Links
|
||||
|
||||
const QStringList &getSampleLinkMessages();
|
||||
|
||||
} // namespace chatterino
|
|
@ -1,174 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
QStringList getValidLinks()
|
||||
{
|
||||
return {
|
||||
R"(http://github.com/)",
|
||||
R"(https://github.com/)",
|
||||
R"(http://username@github.com/)",
|
||||
R"(https://username@github.com/)",
|
||||
R"(http://pajlada.github.io)",
|
||||
R"(https://pajlada.github.io)",
|
||||
R"(http://pajlada.github.io/)",
|
||||
R"(https://pajlada.github.io/)",
|
||||
R"(http://github.com/some/random/path)",
|
||||
R"(https://github.com/some/random/path)",
|
||||
R"(http://github.com?query=value)",
|
||||
R"(https://github.com?query=value)",
|
||||
R"(http://github.com?query=value&abc=123)",
|
||||
R"(https://github.com?query=value&abc=123)",
|
||||
R"(http://github.com/?query=value&abc=123&yhf=abc_def)",
|
||||
R"(http://github.com/?query=value&abc=123&yhf)",
|
||||
R"(http://github.com?query=value&abc=)",
|
||||
R"(http://github.com?query=value&abc=)",
|
||||
R"(http://github.com/#block)",
|
||||
R"(https://github.com/#anchor)",
|
||||
R"(http://github.com/path/?qs=true#block)",
|
||||
R"(https://github.com/path/?qs=true#anchor)",
|
||||
R"(github.com/)",
|
||||
R"(username@github.com/)",
|
||||
R"(pajlada.github.io)",
|
||||
R"(pajlada.github.io/)",
|
||||
R"(github.com/some/random/path)",
|
||||
R"(github.com?query=value)",
|
||||
R"(github.com?query=value&abc=123)",
|
||||
R"(github.com/?query=value&abc=123&yhf=abc_def)",
|
||||
R"(github.com/?query=value&abc=123&yhf)",
|
||||
R"(github.com?query=value&abc=)",
|
||||
R"(github.com?query=value&abc=)",
|
||||
R"(github.com/#block)",
|
||||
R"(github.com/path/?qs=true#block)",
|
||||
R"(HTTP://GITHUB.COM/)",
|
||||
R"(HTTPS://GITHUB.COM/)",
|
||||
R"(HTTP://USERNAME@GITHUB.COM/)",
|
||||
R"(HTTPS://USERNAME@GITHUB.COM/)",
|
||||
R"(HTTP://PAJLADA.GITHUB.IO)",
|
||||
R"(HTTPS://PAJLADA.GITHUB.IO)",
|
||||
R"(HTTP://PAJLADA.GITHUB.IO/)",
|
||||
R"(HTTPS://PAJLADA.GITHUB.IO/)",
|
||||
R"(HTTP://GITHUB.COM/SOME/RANDOM/PATH)",
|
||||
R"(HTTPS://GITHUB.COM/SOME/RANDOM/PATH)",
|
||||
R"(HTTP://GITHUB.COM?QUERY=VALUE)",
|
||||
R"(HTTPS://GITHUB.COM?QUERY=VALUE)",
|
||||
R"(HTTP://GITHUB.COM?QUERY=VALUE&ABC=123)",
|
||||
R"(HTTPS://GITHUB.COM?QUERY=VALUE&ABC=123)",
|
||||
R"(HTTP://GITHUB.COM/?QUERY=VALUE&ABC=123&YHF=ABC_DEF)",
|
||||
R"(HTTP://GITHUB.COM/?QUERY=VALUE&ABC=123&YHF)",
|
||||
R"(HTTP://GITHUB.COM?QUERY=VALUE&ABC=)",
|
||||
R"(HTTP://GITHUB.COM?QUERY=VALUE&ABC=)",
|
||||
R"(HTTP://GITHUB.COM/#BLOCK)",
|
||||
R"(HTTPS://GITHUB.COM/#ANCHOR)",
|
||||
R"(HTTP://GITHUB.COM/PATH/?QS=TRUE#BLOCK)",
|
||||
R"(HTTPS://GITHUB.COM/PATH/?QS=TRUE#ANCHOR)",
|
||||
R"(GITHUB.COM/)",
|
||||
R"(USERNAME@GITHUB.COM/)",
|
||||
R"(PAJLADA.GITHUB.IO)",
|
||||
R"(PAJLADA.GITHUB.IO/)",
|
||||
R"(GITHUB.COM/SOME/RANDOM/PATH)",
|
||||
R"(GITHUB.COM?QUERY=VALUE)",
|
||||
R"(GITHUB.COM?QUERY=VALUE&ABC=123)",
|
||||
R"(GITHUB.COM/?QUERY=VALUE&ABC=123&YHF=ABC_DEF)",
|
||||
R"(GITHUB.COM/?QUERY=VALUE&ABC=123&YHF)",
|
||||
R"(GITHUB.COM?QUERY=VALUE&ABC=)",
|
||||
R"(GITHUB.COM?QUERY=VALUE&ABC=)",
|
||||
R"(GITHUB.COM/#BLOCK)",
|
||||
R"(GITHUB.COM/PATH/?QS=TRUE#BLOCK)",
|
||||
R"(http://foo.com/blah_blah)",
|
||||
R"(http://foo.com/blah_blah/)",
|
||||
R"(http://foo.com/blah_blah_(wikipedia))",
|
||||
R"(http://foo.com/blah_blah_(wikipedia)_(again))",
|
||||
R"(http://www.example.com/wpstyle/?p=364)",
|
||||
R"(https://www.example.com/foo/?bar=baz&inga=42&quux)",
|
||||
R"(http://✪df.ws/123)",
|
||||
R"(http://userid@example.com)",
|
||||
R"(http://userid@example.com/)",
|
||||
R"(http://userid@example.com:8080)",
|
||||
R"(http://userid@example.com:8080/)",
|
||||
R"(http://142.42.1.1/)",
|
||||
R"(http://142.42.1.1:8080/)",
|
||||
R"(http://➡.ws/䨹)",
|
||||
R"(http://⌘.ws)",
|
||||
R"(http://⌘.ws/)",
|
||||
R"(http://foo.com/blah_(wikipedia)#cite-1)",
|
||||
R"(http://foo.com/blah_(wikipedia)_blah#cite-1)",
|
||||
R"(http://foo.com/unicode_(✪)_in_parens)",
|
||||
R"(http://foo.com/(something)?after=parens)",
|
||||
R"(http://☺.damowmow.com/)",
|
||||
R"(http://code.google.com/events/#&product=browser)",
|
||||
R"(http://j.mp)",
|
||||
R"(ftp://foo.bar/baz)",
|
||||
R"(http://foo.bar/?q=Test%20URL-encoded%20stuff)",
|
||||
R"(http://مثال.إختبار)",
|
||||
R"(http://例子.测试)",
|
||||
R"(http://उदाहरण.परीक्षा)",
|
||||
R"(http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com)",
|
||||
R"(http://1337.net)",
|
||||
R"(http://a.b-c.de)",
|
||||
R"(http://223.255.255.254)",
|
||||
};
|
||||
}
|
||||
|
||||
QStringList getValidButIgnoredLinks()
|
||||
{
|
||||
return {
|
||||
R"(http://username:password@github.com/)",
|
||||
R"(https://username:password@github.com/)",
|
||||
R"(http://userid:password@example.com)",
|
||||
R"(http://userid:password@example.com/)",
|
||||
R"(http://userid:password@example.com:8080)",
|
||||
R"(http://userid:password@example.com:8080/)",
|
||||
};
|
||||
}
|
||||
|
||||
QStringList getInvalidLinks()
|
||||
{
|
||||
return {
|
||||
R"(1.40)",
|
||||
R"(test..)",
|
||||
R"(test.)",
|
||||
R"(http://)",
|
||||
R"(http://.)",
|
||||
R"(http://..)",
|
||||
R"(http://../)",
|
||||
R"(http://?)",
|
||||
R"(http://??)",
|
||||
R"(http://??/)",
|
||||
R"(http://#)",
|
||||
R"(http://##)",
|
||||
R"(http://##/)",
|
||||
R"(http://foo.bar?q=Spaces should be encoded)",
|
||||
R"(//)",
|
||||
R"(//a)",
|
||||
R"(///a)",
|
||||
R"(///)",
|
||||
R"(http:///a)",
|
||||
R"(foo.com)",
|
||||
R"(rdar://1234)",
|
||||
R"(h://test)",
|
||||
R"(http:// shouldfail.com)",
|
||||
R"(:// should fail)",
|
||||
R"(http://foo.bar/foo(bar)baz quux)",
|
||||
R"(ftps://foo.bar/)",
|
||||
R"(http://-error-.invalid/)",
|
||||
R"(http://a.b--c.de/)",
|
||||
R"(http://-a.b.co)",
|
||||
R"(http://a.b-.co)",
|
||||
R"(http://0.0.0.0)",
|
||||
R"(http://10.1.1.0)",
|
||||
R"(http://10.1.1.255)",
|
||||
R"(http://224.1.1.1)",
|
||||
R"(http://1.1.1.1.1)",
|
||||
R"(http://123.123.123)",
|
||||
R"(http://3628126748)",
|
||||
R"(http://.www.foo.bar/)",
|
||||
R"(http://www.foo.bar./)",
|
||||
R"(http://.www.foo.bar./)",
|
||||
R"(http://10.1.1.1)",
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
|
@ -30,9 +30,11 @@ bool shouldShowWarning = true;
|
|||
const QStringList &broadcastingBinaries()
|
||||
{
|
||||
#ifdef USEWINSDK
|
||||
static QStringList bins = {"obs.exe", "obs64.exe"};
|
||||
static QStringList bins = {
|
||||
"obs.exe", "obs64.exe", "PRISMLiveStudio.exe",
|
||||
"XSplit.Core.exe", "TwitchStudio.exe", "vMix64.exe"};
|
||||
#else
|
||||
static QStringList bins = {"obs"};
|
||||
static QStringList bins = {"obs", "Twitch Studio", "Streamlabs Desktop"};
|
||||
#endif
|
||||
return bins;
|
||||
}
|
||||
|
@ -45,7 +47,7 @@ bool isInStreamerMode()
|
|||
return true;
|
||||
case StreamerModeSetting::Disabled:
|
||||
return false;
|
||||
case StreamerModeSetting::DetectObs:
|
||||
case StreamerModeSetting::DetectStreamingSoftware:
|
||||
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
||||
|
||||
|
|
|
@ -4,7 +4,11 @@
|
|||
|
||||
namespace chatterino {
|
||||
|
||||
enum StreamerModeSetting { Disabled = 0, Enabled = 1, DetectObs = 2 };
|
||||
enum StreamerModeSetting {
|
||||
Disabled = 0,
|
||||
Enabled = 1,
|
||||
DetectStreamingSoftware = 2,
|
||||
};
|
||||
|
||||
const QStringList &broadcastingBinaries();
|
||||
bool isInStreamerMode();
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace chatterino {
|
||||
namespace util {
|
||||
|
||||
template <typename Container, typename UnaryPredicate>
|
||||
typename Container::iterator find_if(Container &container,
|
||||
UnaryPredicate pred)
|
||||
{
|
||||
return std::find_if(container.begin(), container.end(), pred);
|
||||
}
|
||||
|
||||
template <typename Container, typename UnaryPredicate>
|
||||
bool any_of(Container &container, UnaryPredicate pred)
|
||||
{
|
||||
return std::any_of(container.begin(), container.end(), pred);
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace chatterino
|
|
@ -30,8 +30,7 @@
|
|||
# include <rapidjson/document.h>
|
||||
# include "providers/twitch/PubSubManager.hpp"
|
||||
# include "providers/twitch/PubSubMessages.hpp"
|
||||
# include "util/SampleCheerMessages.hpp"
|
||||
# include "util/SampleLinks.hpp"
|
||||
# include "util/SampleData.hpp"
|
||||
#endif
|
||||
|
||||
#include <QApplication>
|
||||
|
@ -188,82 +187,16 @@ void Window::addCustomTitlebarButtons()
|
|||
void Window::addDebugStuff(HotkeyController::HotkeyMap &actions)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
std::vector<QString> cheerMessages, subMessages, miscMessages, linkMessages,
|
||||
emoteTestMessages;
|
||||
|
||||
cheerMessages = getSampleCheerMessage();
|
||||
auto validLinks = getValidLinks();
|
||||
auto invalidLinks = getInvalidLinks();
|
||||
// clang-format off
|
||||
|
||||
subMessages.emplace_back(R"(@badges=staff/1,broadcaster/1,turbo/1;color=#008000;display-name=ronni;emotes=;id=db25007f-7a18-43eb-9379-80131e44d633;login=ronni;mod=0;msg-id=resub;msg-param-months=6;msg-param-sub-plan=Prime;msg-param-sub-plan-name=Prime;room-id=1337;subscriber=1;system-msg=ronni\shas\ssubscribed\sfor\s6\smonths!;tmi-sent-ts=1507246572675;turbo=1;user-id=1337;user-type=staff :tmi.twitch.tv USERNOTICE #pajlada :Great stream -- keep it up!)");
|
||||
subMessages.emplace_back(R"(@badges=staff/1,premium/1;color=#0000FF;display-name=TWW2;emotes=;id=e9176cd8-5e22-4684-ad40-ce53c2561c5e;login=tww2;mod=0;msg-id=subgift;msg-param-months=1;msg-param-recipient-display-name=Mr_Woodchuck;msg-param-recipient-id=89614178;msg-param-recipient-name=mr_woodchuck;msg-param-sub-plan-name=House\sof\sNyoro~n;msg-param-sub-plan=1000;room-id=19571752;subscriber=0;system-msg=TWW2\sgifted\sa\sTier\s1\ssub\sto\sMr_Woodchuck!;tmi-sent-ts=1521159445153;turbo=0;user-id=13405587;user-type=staff :tmi.twitch.tv USERNOTICE #pajlada)");
|
||||
|
||||
// hyperbolicxd gifted a sub to quote_if_nam
|
||||
subMessages.emplace_back(R"(@badges=subscriber/0,premium/1;color=#00FF7F;display-name=hyperbolicxd;emotes=;id=b20ef4fe-cba8-41d0-a371-6327651dc9cc;login=hyperbolicxd;mod=0;msg-id=subgift;msg-param-months=1;msg-param-recipient-display-name=quote_if_nam;msg-param-recipient-id=217259245;msg-param-recipient-user-name=quote_if_nam;msg-param-sender-count=1;msg-param-sub-plan-name=Channel\sSubscription\s(nymn_hs);msg-param-sub-plan=1000;room-id=62300805;subscriber=1;system-msg=hyperbolicxd\sgifted\sa\sTier\s1\ssub\sto\squote_if_nam!\sThis\sis\stheir\sfirst\sGift\sSub\sin\sthe\schannel!;tmi-sent-ts=1528190938558;turbo=0;user-id=111534250;user-type= :tmi.twitch.tv USERNOTICE #pajlada)");
|
||||
|
||||
// first time sub
|
||||
subMessages.emplace_back(R"(@badges=subscriber/0,premium/1;color=#0000FF;display-name=byebyeheart;emotes=;id=fe390424-ab89-4c33-bb5a-53c6e5214b9f;login=byebyeheart;mod=0;msg-id=sub;msg-param-months=0;msg-param-sub-plan-name=Dakotaz;msg-param-sub-plan=Prime;room-id=39298218;subscriber=0;system-msg=byebyeheart\sjust\ssubscribed\swith\sTwitch\sPrime!;tmi-sent-ts=1528190963670;turbo=0;user-id=131956000;user-type= :tmi.twitch.tv USERNOTICE #pajlada)");
|
||||
|
||||
// first time sub
|
||||
subMessages.emplace_back(R"(@badges=subscriber/0,premium/1;color=;display-name=vJoeyzz;emotes=;id=b2476df5-fffe-4338-837b-380c5dd90051;login=vjoeyzz;mod=0;msg-id=sub;msg-param-months=0;msg-param-sub-plan-name=Dakotaz;msg-param-sub-plan=Prime;room-id=39298218;subscriber=0;system-msg=vJoeyzz\sjust\ssubscribed\swith\sTwitch\sPrime!;tmi-sent-ts=1528190995089;turbo=0;user-id=78945903;user-type= :tmi.twitch.tv USERNOTICE #pajlada)");
|
||||
|
||||
// first time sub
|
||||
subMessages.emplace_back(R"(@badges=subscriber/0,premium/1;color=;display-name=Lennydog3;emotes=;id=44feb1eb-df60-45f6-904b-7bf0d5375a41;login=lennydog3;mod=0;msg-id=sub;msg-param-months=0;msg-param-sub-plan-name=Dakotaz;msg-param-sub-plan=Prime;room-id=39298218;subscriber=0;system-msg=Lennydog3\sjust\ssubscribed\swith\sTwitch\sPrime!;tmi-sent-ts=1528191098733;turbo=0;user-id=175759335;user-type= :tmi.twitch.tv USERNOTICE #pajlada)");
|
||||
|
||||
// resub with message
|
||||
subMessages.emplace_back(R"(@badges=subscriber/0,premium/1;color=#1E90FF;display-name=OscarLord;emotes=;id=376529fd-31a8-4da9-9c0d-92a9470da2cd;login=oscarlord;mod=0;msg-id=resub;msg-param-months=2;msg-param-sub-plan-name=Dakotaz;msg-param-sub-plan=1000;room-id=39298218;subscriber=1;system-msg=OscarLord\sjust\ssubscribed\swith\sa\sTier\s1\ssub.\sOscarLord\ssubscribed\sfor\s2\smonths\sin\sa\srow!;tmi-sent-ts=1528191154801;turbo=0;user-id=162607810;user-type= :tmi.twitch.tv USERNOTICE #pajlada :Hey dk love to watch your streams keep up the good work)");
|
||||
|
||||
// resub with message
|
||||
subMessages.emplace_back(R"(@badges=subscriber/0,premium/1;color=;display-name=samewl;emotes=9:22-23;id=599fda87-ca1e-41f2-9af7-6a28208daf1c;login=samewl;mod=0;msg-id=resub;msg-param-months=5;msg-param-sub-plan-name=Channel\sSubscription\s(forsenlol);msg-param-sub-plan=Prime;room-id=22484632;subscriber=1;system-msg=samewl\sjust\ssubscribed\swith\sTwitch\sPrime.\ssamewl\ssubscribed\sfor\s5\smonths\sin\sa\srow!;tmi-sent-ts=1528191317948;turbo=0;user-id=70273207;user-type= :tmi.twitch.tv USERNOTICE #pajlada :lot of love sebastian <3)");
|
||||
|
||||
// resub without message
|
||||
subMessages.emplace_back(R"(@badges=subscriber/12;color=#CC00C2;display-name=cspice;emotes=;id=6fc4c3e0-ca61-454a-84b8-5669dee69fc9;login=cspice;mod=0;msg-id=resub;msg-param-months=12;msg-param-sub-plan-name=Channel\sSubscription\s(forsenlol):\s$9.99\sSub;msg-param-sub-plan=2000;room-id=22484632;subscriber=1;system-msg=cspice\sjust\ssubscribed\swith\sa\sTier\s2\ssub.\scspice\ssubscribed\sfor\s12\smonths\sin\sa\srow!;tmi-sent-ts=1528192510808;turbo=0;user-id=47894662;user-type= :tmi.twitch.tv USERNOTICE #pajlada)");
|
||||
|
||||
// display name renders strangely
|
||||
miscMessages.emplace_back(R"(@badges=;color=#00AD2B;display-name=Iamme420\s;emotes=;id=d47a1e4b-a3c6-4b9e-9bf1-51b8f3dbc76e;mod=0;room-id=11148817;subscriber=0;tmi-sent-ts=1529670347537;turbo=0;user-id=56422869;user-type= :iamme420!iamme420@iamme420.tmi.twitch.tv PRIVMSG #pajlada :offline chat gachiBASS)");
|
||||
miscMessages.emplace_back(R"(@badge-info=founder/47;badges=moderator/1,founder/0,premium/1;color=#00FF80;display-name=gempir;emotes=;flags=;id=d4514490-202e-43cb-b429-ef01a9d9c2fe;mod=1;room-id=11148817;subscriber=0;tmi-sent-ts=1575198233854;turbo=0;user-id=77829817;user-type=mod :gempir!gempir@gempir.tmi.twitch.tv PRIVMSG #pajlada :offline chat gachiBASS)");
|
||||
|
||||
// "first time chat" message
|
||||
miscMessages.emplace_back(R"(@badge-info=;badges=glhf-pledge/1;client-nonce=5d2627b0cbe56fa05faf5420def4807d;color=#1E90FF;display-name=oldcoeur;emote-only=1;emotes=84608:0-7;first-msg=1;flags=;id=7412fea4-8683-4cc9-a506-4228127a5c2d;mod=0;room-id=11148817;subscriber=0;tmi-sent-ts=1623429859222;turbo=0;user-id=139147886;user-type= :oldcoeur!oldcoeur@oldcoeur.tmi.twitch.tv PRIVMSG #pajlada :cmonBruh)");
|
||||
|
||||
// Message with founder badge
|
||||
miscMessages.emplace_back(R"(@badge-info=founder/72;badges=founder/0,bits/5000;color=#FF0000;display-name=TranRed;emotes=;first-msg=0;flags=;id=7482163f-493d-41d9-b36f-fba50e0701b7;mod=0;room-id=11148817;subscriber=0;tmi-sent-ts=1641123773885;turbo=0;user-id=57019243;user-type= :tranred!tranred@tranred.tmi.twitch.tv PRIVMSG #pajlada :GFMP pajaE)");
|
||||
|
||||
// mod announcement
|
||||
miscMessages.emplace_back(R"(@badge-info=subscriber/47;badges=broadcaster/1,subscriber/3012,twitchconAmsterdam2020/1;color=#FF0000;display-name=Supinic;emotes=;flags=;id=8c26e1ab-b50c-4d9d-bc11-3fd57a941d90;login=supinic;mod=0;msg-id=announcement;msg-param-color=PRIMARY;room-id=31400525;subscriber=1;system-msg=;tmi-sent-ts=1648762219962;user-id=31400525;user-type= :tmi.twitch.tv USERNOTICE #supinic :mm test lol)");
|
||||
|
||||
// various link tests
|
||||
linkMessages.emplace_back(R"(@badge-info=subscriber/48;badges=broadcaster/1,subscriber/36,partner/1;color=#CC44FF;display-name=pajlada;emotes=;flags=;id=3c23cf3c-0864-4699-a76b-089350141147;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1577628844607;turbo=0;user-id=11148817;user-type= :pajlada!pajlada@pajlada.tmi.twitch.tv PRIVMSG #pajlada : Links that should pass: )" + getValidLinks().join(' '));
|
||||
linkMessages.emplace_back(R"(@badge-info=subscriber/48;badges=broadcaster/1,subscriber/36,partner/1;color=#CC44FF;display-name=pajlada;emotes=;flags=;id=3c23cf3c-0864-4699-a76b-089350141147;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1577628844607;turbo=0;user-id=11148817;user-type= :pajlada!pajlada@pajlada.tmi.twitch.tv PRIVMSG #pajlada : Links that should NOT pass: )" + getInvalidLinks().join(' '));
|
||||
linkMessages.emplace_back(R"(@badge-info=subscriber/48;badges=broadcaster/1,subscriber/36,partner/1;color=#CC44FF;display-name=pajlada;emotes=;flags=;id=3c23cf3c-0864-4699-a76b-089350141147;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1577628844607;turbo=0;user-id=11148817;user-type= :pajlada!pajlada@pajlada.tmi.twitch.tv PRIVMSG #pajlada : Links that should technically pass but we choose not to parse them: )" + getValidButIgnoredLinks().join(' '));
|
||||
|
||||
// channel point reward test
|
||||
const char *channelRewardMessage = "{ \"type\": \"MESSAGE\", \"data\": { \"topic\": \"community-points-channel-v1.11148817\", \"message\": { \"type\": \"reward-redeemed\", \"data\": { \"timestamp\": \"2020-07-13T20:19:31.430785354Z\", \"redemption\": { \"id\": \"b9628798-1b4e-4122-b2a6-031658df6755\", \"user\": { \"id\": \"91800084\", \"login\": \"cranken1337\", \"display_name\": \"cranken1337\" }, \"channel_id\": \"11148817\", \"redeemed_at\": \"2020-07-13T20:19:31.345237005Z\", \"reward\": { \"id\": \"313969fe-cc9f-4a0a-83c6-172acbd96957\", \"channel_id\": \"11148817\", \"title\": \"annoying reward pogchamp\", \"prompt\": \"\", \"cost\": 3000, \"is_user_input_required\": true, \"is_sub_only\": false, \"image\": null, \"default_image\": { \"url_1x\": \"https://static-cdn.jtvnw.net/custom-reward-images/default-1.png\", \"url_2x\": \"https://static-cdn.jtvnw.net/custom-reward-images/default-2.png\", \"url_4x\": \"https://static-cdn.jtvnw.net/custom-reward-images/default-4.png\" }, \"background_color\": \"#52ACEC\", \"is_enabled\": true, \"is_paused\": false, \"is_in_stock\": true, \"max_per_stream\": { \"is_enabled\": false, \"max_per_stream\": 0 }, \"should_redemptions_skip_request_queue\": false, \"template_id\": null, \"updated_for_indicator_at\": \"2020-01-20T04:33:33.624956679Z\" }, \"user_input\": \"wow, amazing reward\", \"status\": \"UNFULFILLED\", \"cursor\": \"Yjk2Mjg3OTgtMWI0ZS00MTIyLWIyYTYtMDMxNjU4ZGY2NzU1X18yMDIwLTA3LTEzVDIwOjE5OjMxLjM0NTIzNzAwNVo=\" } } } } }";
|
||||
const char *channelRewardMessage2 = "{ \"type\": \"MESSAGE\", \"data\": { \"topic\": \"community-points-channel-v1.11148817\", \"message\": { \"type\": \"reward-redeemed\", \"data\": { \"timestamp\": \"2020-07-13T20:19:31.430785354Z\", \"redemption\": { \"id\": \"b9628798-1b4e-4122-b2a6-031658df6755\", \"user\": { \"id\": \"91800084\", \"login\": \"cranken1337\", \"display_name\": \"cranken1337\" }, \"channel_id\": \"11148817\", \"redeemed_at\": \"2020-07-13T20:19:31.345237005Z\", \"reward\": { \"id\": \"313969fe-cc9f-4a0a-83c6-172acbd96957\", \"channel_id\": \"11148817\", \"title\": \"annoying reward pogchamp\", \"prompt\": \"\", \"cost\": 3000, \"is_user_input_required\": false, \"is_sub_only\": false, \"image\": null, \"default_image\": { \"url_1x\": \"https://static-cdn.jtvnw.net/custom-reward-images/default-1.png\", \"url_2x\": \"https://static-cdn.jtvnw.net/custom-reward-images/default-2.png\", \"url_4x\": \"https://static-cdn.jtvnw.net/custom-reward-images/default-4.png\" }, \"background_color\": \"#52ACEC\", \"is_enabled\": true, \"is_paused\": false, \"is_in_stock\": true, \"max_per_stream\": { \"is_enabled\": false, \"max_per_stream\": 0 }, \"should_redemptions_skip_request_queue\": false, \"template_id\": null, \"updated_for_indicator_at\": \"2020-01-20T04:33:33.624956679Z\" }, \"status\": \"UNFULFILLED\", \"cursor\": \"Yjk2Mjg3OTgtMWI0ZS00MTIyLWIyYTYtMDMxNjU4ZGY2NzU1X18yMDIwLTA3LTEzVDIwOjE5OjMxLjM0NTIzNzAwNVo=\" } } } } }";
|
||||
const char *channelRewardIRCMessage(R"(@badge-info=subscriber/43;badges=subscriber/42;color=#1E90FF;custom-reward-id=313969fe-cc9f-4a0a-83c6-172acbd96957;display-name=Cranken1337;emotes=;flags=;id=3cee3f27-a1d0-44d1-a606-722cebdad08b;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1594756484132;turbo=0;user-id=91800084;user-type= :cranken1337!cranken1337@cranken1337.tmi.twitch.tv PRIVMSG #pajlada :wow, amazing reward)");
|
||||
|
||||
emoteTestMessages.emplace_back(R"(@badge-info=subscriber/3;badges=subscriber/3;color=#0000FF;display-name=Linkoping;emotes=25:40-44;flags=17-26:S.6;id=744f9c58-b180-4f46-bd9e-b515b5ef75c1;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1566335866017;turbo=0;user-id=91673457;user-type= :linkoping!linkoping@linkoping.tmi.twitch.tv PRIVMSG #pajlada :Då kan du begära skadestånd och förtal Kappa)");
|
||||
emoteTestMessages.emplace_back(R"(@badge-info=subscriber/1;badges=subscriber/0;color=;display-name=jhoelsc;emotes=301683486:46-58,60-72,74-86/301683544:88-100;flags=0-4:S.6;id=1f1afcdd-d94c-4699-b35f-d214deb1e11a;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1588640587462;turbo=0;user-id=505763008;user-type= :jhoelsc!jhoelsc@jhoelsc.tmi.twitch.tv PRIVMSG #pajlada :pensé que no habría directo que bueno que si staryuukiLove staryuukiLove staryuukiLove staryuukiBits)");
|
||||
emoteTestMessages.emplace_back(R"(@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=41:6-13,16-23;flags=;id=97c28382-e8d2-45a0-bb5d-2305fc4ef139;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922036771;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kreygasm, Kreygasm)");
|
||||
emoteTestMessages.emplace_back(R"(@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=25:24-28/41:6-13,15-22;flags=;id=5a36536b-a952-43f7-9c41-88c829371b7a;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922039721;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kreygasm,Kreygasm Kappa (no space then space))");
|
||||
emoteTestMessages.emplace_back(R"(@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=25:6-10/1902:12-16/88:18-25;flags=;id=aed9e67e-f8cd-493e-aa6b-da054edd7292;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922042881;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kappa.Keepo.PogChamp.extratext (3 emotes with extra text))");
|
||||
emoteTestMessages.emplace_back(R"(@badge-info=;badges=moderator/1,partner/1;color=#5B99FF;display-name=StreamElements;emotes=86:30-39/822112:73-79;flags=22-27:S.5;id=03c3eec9-afd1-4858-a2e0-fccbf6ad8d1a;mod=1;room-id=11148817;subscriber=0;tmi-sent-ts=1588638345928;turbo=0;user-id=100135110;user-type=mod :streamelements!streamelements@streamelements.tmi.twitch.tv PRIVMSG #pajlada :╔ACTION A LOJA AINDA NÃO ESTÁ PRONTA BibleThump , AGUARDE... NOVIDADES EM BREVE FortOne╔)");
|
||||
emoteTestMessages.emplace_back(R"(@badge-info=subscriber/20;badges=moderator/1,subscriber/12;color=#19E6E6;display-name=randers;emotes=25:39-43;flags=;id=3ea97f01-abb2-4acf-bdb8-f52e79cd0324;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1588837097115;turbo=0;user-id=40286300;user-type=mod :randers!randers@randers.tmi.twitch.tv PRIVMSG #pajlada :Då kan du begära skadestånd och förtal Kappa)");
|
||||
emoteTestMessages.emplace_back(R"(@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=41:6-13,15-22;flags=;id=a3196c7e-be4c-4b49-9c5a-8b8302b50c2a;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922213730;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kreygasm,Kreygasm (no space))");
|
||||
// clang-format on
|
||||
|
||||
actions.emplace("addMiscMessage", [=](std::vector<QString>) -> QString {
|
||||
const auto &messages = miscMessages;
|
||||
const auto &messages = getSampleMiscMessages();
|
||||
static int index = 0;
|
||||
auto app = getApp();
|
||||
const auto &msg = messages[index++ % messages.size()];
|
||||
app->twitch->addFakeMessage(msg);
|
||||
getApp()->twitch->addFakeMessage(msg);
|
||||
return "";
|
||||
});
|
||||
|
||||
actions.emplace("addCheerMessage", [=](std::vector<QString>) -> QString {
|
||||
const auto &messages = cheerMessages;
|
||||
const auto &messages = getSampleCheerMessages();
|
||||
static int index = 0;
|
||||
const auto &msg = messages[index++ % messages.size()];
|
||||
getApp()->twitch->addFakeMessage(msg);
|
||||
|
@ -271,11 +204,10 @@ void Window::addDebugStuff(HotkeyController::HotkeyMap &actions)
|
|||
});
|
||||
|
||||
actions.emplace("addLinkMessage", [=](std::vector<QString>) -> QString {
|
||||
const auto &messages = linkMessages;
|
||||
const auto &messages = getSampleLinkMessages();
|
||||
static int index = 0;
|
||||
auto app = getApp();
|
||||
const auto &msg = messages[index++ % messages.size()];
|
||||
app->twitch->addFakeMessage(msg);
|
||||
getApp()->twitch->addFakeMessage(msg);
|
||||
return "";
|
||||
});
|
||||
|
||||
|
@ -285,19 +217,21 @@ void Window::addDebugStuff(HotkeyController::HotkeyMap &actions)
|
|||
static bool alt = true;
|
||||
if (alt)
|
||||
{
|
||||
auto oMessage = parsePubSubBaseMessage(channelRewardMessage);
|
||||
auto oMessage =
|
||||
parsePubSubBaseMessage(getSampleChannelRewardMessage());
|
||||
auto oInnerMessage =
|
||||
oMessage->toInner<PubSubMessageMessage>()
|
||||
->toInner<PubSubCommunityPointsChannelV1Message>();
|
||||
|
||||
app->twitch->addFakeMessage(channelRewardIRCMessage);
|
||||
app->twitch->addFakeMessage(getSampleChannelRewardIRCMessage());
|
||||
app->twitch->pubsub->signals_.pointReward.redeemed.invoke(
|
||||
oInnerMessage->data.value("redemption").toObject());
|
||||
alt = !alt;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto oMessage = parsePubSubBaseMessage(channelRewardMessage2);
|
||||
auto oMessage =
|
||||
parsePubSubBaseMessage(getSampleChannelRewardMessage2());
|
||||
auto oInnerMessage =
|
||||
oMessage->toInner<PubSubMessageMessage>()
|
||||
->toInner<PubSubCommunityPointsChannelV1Message>();
|
||||
|
@ -309,7 +243,7 @@ void Window::addDebugStuff(HotkeyController::HotkeyMap &actions)
|
|||
});
|
||||
|
||||
actions.emplace("addEmoteMessage", [=](std::vector<QString>) -> QString {
|
||||
const auto &messages = emoteTestMessages;
|
||||
const auto &messages = getSampleEmoteTestMessages();
|
||||
static int index = 0;
|
||||
const auto &msg = messages[index++ % messages.size()];
|
||||
getApp()->twitch->addFakeMessage(msg);
|
||||
|
@ -620,7 +554,7 @@ void Window::addShortcuts()
|
|||
else if (mode == 3)
|
||||
{
|
||||
getSettings()->enableStreamerMode.setValue(
|
||||
StreamerModeSetting::DetectObs);
|
||||
StreamerModeSetting::DetectStreamingSoftware);
|
||||
}
|
||||
return "";
|
||||
}},
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <QCheckBox>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace chatterino {
|
||||
|
@ -19,7 +20,15 @@ SelectChannelFiltersDialog::SelectChannelFiltersDialog(
|
|||
auto okButton = new QPushButton("Ok");
|
||||
auto cancelButton = new QPushButton("Cancel");
|
||||
|
||||
vbox->addLayout(itemVbox);
|
||||
auto scrollAreaContent = new QWidget;
|
||||
scrollAreaContent->setLayout(itemVbox);
|
||||
|
||||
auto scrollArea = new QScrollArea;
|
||||
scrollArea->setWidgetResizable(true);
|
||||
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
scrollArea->setWidget(scrollAreaContent);
|
||||
|
||||
vbox->addWidget(scrollArea);
|
||||
vbox->addLayout(buttonBox);
|
||||
|
||||
buttonBox->addStretch(1);
|
||||
|
|
|
@ -2119,7 +2119,7 @@ void ChannelView::addCommandExecutionContextMenuItems(
|
|||
|
||||
inputText.push_front(cmd.name + " ");
|
||||
|
||||
cmdMenu->addAction(cmd.name, [this, inputText] {
|
||||
cmdMenu->addAction(cmd.name, [this, layout, cmd, inputText] {
|
||||
ChannelPtr channel;
|
||||
|
||||
/* Search popups and user message history's underlyingChannels aren't of type TwitchChannel, but
|
||||
|
@ -2132,9 +2132,29 @@ void ChannelView::addCommandExecutionContextMenuItems(
|
|||
{
|
||||
channel = this->underlyingChannel_;
|
||||
}
|
||||
auto split = dynamic_cast<Split *>(this->parentWidget());
|
||||
QString userText;
|
||||
if (split)
|
||||
{
|
||||
userText = split->getInput().getInputText();
|
||||
}
|
||||
QString value = getApp()->commands->execCustomCommand(
|
||||
inputText.split(' '), cmd, true, channel,
|
||||
{
|
||||
{"user.name", layout->getMessage()->loginName},
|
||||
{"msg.id", layout->getMessage()->id},
|
||||
{"msg.text", layout->getMessage()->messageText},
|
||||
{"input.text", userText},
|
||||
|
||||
QString value =
|
||||
getApp()->commands->execCommand(inputText, channel, false);
|
||||
// old placeholders
|
||||
{"user", layout->getMessage()->loginName},
|
||||
{"msg-id", layout->getMessage()->id},
|
||||
{"message", layout->getMessage()->messageText},
|
||||
|
||||
{"channel", this->channel()->getName()},
|
||||
});
|
||||
|
||||
value = getApp()->commands->execCommand(value, channel, false);
|
||||
|
||||
channel->sendMessage(value);
|
||||
});
|
||||
|
|
|
@ -81,6 +81,8 @@ public:
|
|||
void pause(PauseReason reason, boost::optional<uint> msecs = boost::none);
|
||||
void unpause(PauseReason reason);
|
||||
|
||||
MessageElementFlags getFlags() const;
|
||||
|
||||
ChannelPtr channel();
|
||||
void setChannel(ChannelPtr channel_);
|
||||
|
||||
|
@ -158,7 +160,6 @@ private:
|
|||
|
||||
void drawMessages(QPainter &painter);
|
||||
void setSelection(const SelectionItem &start, const SelectionItem &end);
|
||||
MessageElementFlags getFlags() const;
|
||||
void selectWholeMessage(MessageLayout *layout, int &messageIndex);
|
||||
void getWordBounds(MessageLayout *layout,
|
||||
const MessageLayoutElement *element,
|
||||
|
|
|
@ -3,11 +3,9 @@
|
|||
#include <QHBoxLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "common/Channel.hpp"
|
||||
#include "controllers/hotkeys/HotkeyController.hpp"
|
||||
#include "messages/Message.hpp"
|
||||
#include "messages/search/AuthorPredicate.hpp"
|
||||
#include "messages/search/ChannelPredicate.hpp"
|
||||
#include "messages/search/LinkPredicate.hpp"
|
||||
|
@ -19,8 +17,7 @@
|
|||
namespace chatterino {
|
||||
|
||||
ChannelPtr SearchPopup::filter(const QString &text, const QString &channelName,
|
||||
const LimitedQueueSnapshot<MessagePtr> &snapshot,
|
||||
FilterSetPtr filterSet)
|
||||
const LimitedQueueSnapshot<MessagePtr> &snapshot)
|
||||
{
|
||||
ChannelPtr channel(new Channel(channelName, Channel::Type::None));
|
||||
|
||||
|
@ -44,9 +41,6 @@ ChannelPtr SearchPopup::filter(const QString &text, const QString &channelName,
|
|||
}
|
||||
}
|
||||
|
||||
if (accept && filterSet)
|
||||
accept = filterSet->filter(message, channel);
|
||||
|
||||
// If all predicates match, add the message to the channel
|
||||
if (accept)
|
||||
channel->addMessage(message);
|
||||
|
@ -67,13 +61,13 @@ void SearchPopup::addShortcuts()
|
|||
{
|
||||
HotkeyController::HotkeyMap actions{
|
||||
{"search",
|
||||
[this](std::vector<QString>) -> QString {
|
||||
[this](const std::vector<QString> &) -> QString {
|
||||
this->searchInput_->setFocus();
|
||||
this->searchInput_->selectAll();
|
||||
return "";
|
||||
}},
|
||||
{"delete",
|
||||
[this](std::vector<QString>) -> QString {
|
||||
[this](const std::vector<QString> &) -> QString {
|
||||
this->close();
|
||||
return "";
|
||||
}},
|
||||
|
@ -88,17 +82,25 @@ void SearchPopup::addShortcuts()
|
|||
HotkeyCategory::PopupWindow, actions, this);
|
||||
}
|
||||
|
||||
void SearchPopup::setChannelFilters(FilterSetPtr filters)
|
||||
void SearchPopup::addChannel(ChannelView &channel)
|
||||
{
|
||||
this->channelFilters_ = std::move(filters);
|
||||
}
|
||||
if (this->searchChannels_.empty())
|
||||
{
|
||||
this->channelView_->setSourceChannel(channel.channel());
|
||||
this->channelName_ = channel.channel()->getName();
|
||||
}
|
||||
else if (this->searchChannels_.size() == 1)
|
||||
{
|
||||
this->channelView_->setSourceChannel(
|
||||
std::make_shared<Channel>("multichannel", Channel::Type::None));
|
||||
|
||||
void SearchPopup::setChannel(const ChannelPtr &channel)
|
||||
{
|
||||
this->channelView_->setSourceChannel(channel);
|
||||
this->channelName_ = channel->getName();
|
||||
this->snapshot_ = channel->getMessageSnapshot();
|
||||
this->search();
|
||||
auto flags = this->channelView_->getFlags();
|
||||
flags.set(MessageElementFlag::ChannelName);
|
||||
flags.unset(MessageElementFlag::ModeratorTools);
|
||||
this->channelView_->setOverrideFlags(flags);
|
||||
}
|
||||
|
||||
this->searchChannels_.append(std::ref(channel));
|
||||
|
||||
this->updateWindowTitle();
|
||||
}
|
||||
|
@ -115,6 +117,10 @@ void SearchPopup::updateWindowTitle()
|
|||
{
|
||||
historyName = "mentions";
|
||||
}
|
||||
else if (this->searchChannels_.size() > 1)
|
||||
{
|
||||
historyName = "multiple channels'";
|
||||
}
|
||||
else if (this->channelName_.isEmpty())
|
||||
{
|
||||
historyName = "<empty>'s";
|
||||
|
@ -126,24 +132,90 @@ void SearchPopup::updateWindowTitle()
|
|||
this->setWindowTitle("Searching in " + historyName + " history");
|
||||
}
|
||||
|
||||
void SearchPopup::showEvent(QShowEvent *)
|
||||
{
|
||||
this->search();
|
||||
}
|
||||
|
||||
void SearchPopup::search()
|
||||
{
|
||||
if (this->snapshot_.size() == 0)
|
||||
{
|
||||
this->snapshot_ = this->buildSnapshot();
|
||||
}
|
||||
|
||||
this->channelView_->setChannel(filter(this->searchInput_->text(),
|
||||
this->channelName_, this->snapshot_,
|
||||
this->channelFilters_));
|
||||
this->channelName_, this->snapshot_));
|
||||
}
|
||||
|
||||
LimitedQueueSnapshot<MessagePtr> SearchPopup::buildSnapshot()
|
||||
{
|
||||
// no point in filtering/sorting if it's a single channel search
|
||||
if (this->searchChannels_.length() == 1)
|
||||
{
|
||||
const auto channelPtr = this->searchChannels_.at(0);
|
||||
return channelPtr.get().channel()->getMessageSnapshot();
|
||||
}
|
||||
|
||||
auto combinedSnapshot = std::vector<std::shared_ptr<const Message>>{};
|
||||
for (auto &channel : this->searchChannels_)
|
||||
{
|
||||
ChannelView &sharedView = channel.get();
|
||||
|
||||
const FilterSetPtr filterSet = sharedView.getFilterSet();
|
||||
const LimitedQueueSnapshot<MessagePtr> &snapshot =
|
||||
sharedView.channel()->getMessageSnapshot();
|
||||
|
||||
// TODO: implement iterator on LimitedQueueSnapshot?
|
||||
for (auto i = 0; i < snapshot.size(); ++i)
|
||||
{
|
||||
const MessagePtr &message = snapshot[i];
|
||||
if (filterSet && !filterSet->filter(message, sharedView.channel()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
combinedSnapshot.push_back(message);
|
||||
}
|
||||
}
|
||||
|
||||
// remove any duplicate messages from splits containing the same channel
|
||||
std::sort(combinedSnapshot.begin(), combinedSnapshot.end(),
|
||||
[](MessagePtr &a, MessagePtr &b) {
|
||||
return a->id > b->id;
|
||||
});
|
||||
|
||||
auto uniqueIterator =
|
||||
std::unique(combinedSnapshot.begin(), combinedSnapshot.end(),
|
||||
[](MessagePtr &a, MessagePtr &b) {
|
||||
return a->id == b->id;
|
||||
});
|
||||
|
||||
combinedSnapshot.erase(uniqueIterator, combinedSnapshot.end());
|
||||
|
||||
// resort by time for presentation
|
||||
std::sort(combinedSnapshot.begin(), combinedSnapshot.end(),
|
||||
[](MessagePtr &a, MessagePtr &b) {
|
||||
return a->serverReceivedTime < b->serverReceivedTime;
|
||||
});
|
||||
|
||||
auto queue = LimitedQueue<MessagePtr>(combinedSnapshot.size());
|
||||
queue.pushFront(combinedSnapshot);
|
||||
|
||||
return queue.getSnapshot();
|
||||
}
|
||||
|
||||
void SearchPopup::initLayout()
|
||||
{
|
||||
// VBOX
|
||||
{
|
||||
QVBoxLayout *layout1 = new QVBoxLayout(this);
|
||||
auto *layout1 = new QVBoxLayout(this);
|
||||
layout1->setMargin(0);
|
||||
layout1->setSpacing(0);
|
||||
|
||||
// HBOX
|
||||
{
|
||||
QHBoxLayout *layout2 = new QHBoxLayout(this);
|
||||
auto *layout2 = new QHBoxLayout(this);
|
||||
layout2->setMargin(8);
|
||||
layout2->setSpacing(8);
|
||||
|
||||
|
|
|
@ -17,16 +17,17 @@ class SearchPopup : public BasePopup
|
|||
public:
|
||||
SearchPopup(QWidget *parent);
|
||||
|
||||
virtual void setChannel(const ChannelPtr &channel);
|
||||
virtual void setChannelFilters(FilterSetPtr filters);
|
||||
virtual void addChannel(ChannelView &channel);
|
||||
|
||||
protected:
|
||||
virtual void updateWindowTitle();
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
private:
|
||||
void initLayout();
|
||||
void search();
|
||||
void addShortcuts() override;
|
||||
LimitedQueueSnapshot<MessagePtr> buildSnapshot();
|
||||
|
||||
/**
|
||||
* @brief Only retains those message from a list of messages that satisfy a
|
||||
|
@ -41,8 +42,7 @@ private:
|
|||
* "snapshot"
|
||||
*/
|
||||
static ChannelPtr filter(const QString &text, const QString &channelName,
|
||||
const LimitedQueueSnapshot<MessagePtr> &snapshot,
|
||||
FilterSetPtr filterSet);
|
||||
const LimitedQueueSnapshot<MessagePtr> &snapshot);
|
||||
|
||||
/**
|
||||
* @brief Checks the input for tags and registers their corresponding
|
||||
|
@ -58,7 +58,7 @@ private:
|
|||
QLineEdit *searchInput_{};
|
||||
ChannelView *channelView_{};
|
||||
QString channelName_{};
|
||||
FilterSetPtr channelFilters_;
|
||||
QList<std::reference_wrapper<ChannelView>> searchChannels_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -336,14 +336,14 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
|||
|
||||
layout.addTitle("Streamer Mode");
|
||||
layout.addDescription(
|
||||
"Chatterino can automatically change behavior if it detects that \"OBS "
|
||||
"Studio\" is running.\nSelect which things you want to change while "
|
||||
"streaming");
|
||||
"Chatterino can automatically change behavior if it detects that any "
|
||||
"streaming software is running.\nSelect which things you want to "
|
||||
"change while streaming");
|
||||
|
||||
ComboBox *dankDropdown =
|
||||
layout.addDropdown<std::underlying_type<StreamerModeSetting>::type>(
|
||||
"Enable Streamer Mode",
|
||||
{"Disabled", "Enabled", "Automatic (Detect OBS)"},
|
||||
{"Disabled", "Enabled", "Automatic (Detect streaming software)"},
|
||||
s.enableStreamerMode,
|
||||
[](int value) {
|
||||
return value;
|
||||
|
@ -352,7 +352,7 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
|||
return static_cast<StreamerModeSetting>(args.index);
|
||||
},
|
||||
false);
|
||||
dankDropdown->setMinimumWidth(dankDropdown->minimumSizeHint().width() + 10);
|
||||
dankDropdown->setMinimumWidth(dankDropdown->minimumSizeHint().width() + 30);
|
||||
|
||||
layout.addCheckbox("Hide usercard avatars",
|
||||
s.streamerModeHideUsercardAvatars);
|
||||
|
|
|
@ -273,7 +273,12 @@ void Split::addShortcuts()
|
|||
}},
|
||||
{"showSearch",
|
||||
[this](std::vector<QString>) -> QString {
|
||||
this->showSearch();
|
||||
this->showSearch(true);
|
||||
return "";
|
||||
}},
|
||||
{"showGlobalSearch",
|
||||
[this](std::vector<QString>) -> QString {
|
||||
this->showSearch(false);
|
||||
return "";
|
||||
}},
|
||||
{"reconnect",
|
||||
|
@ -985,6 +990,33 @@ void Split::showViewerList()
|
|||
"viewers"};
|
||||
auto loadingLabel = new QLabel("Loading...");
|
||||
|
||||
searchBar->setPlaceholderText("Search User...");
|
||||
|
||||
auto performListSearch = [=]() {
|
||||
auto query = searchBar->text();
|
||||
if (query.isEmpty())
|
||||
{
|
||||
resultList->hide();
|
||||
chattersList->show();
|
||||
return;
|
||||
}
|
||||
|
||||
auto results = chattersList->findItems(query, Qt::MatchContains);
|
||||
chattersList->hide();
|
||||
resultList->clear();
|
||||
for (auto &item : results)
|
||||
{
|
||||
if (!item->text().contains("("))
|
||||
{
|
||||
resultList->addItem(formatListItemText(item->text()));
|
||||
}
|
||||
}
|
||||
resultList->show();
|
||||
};
|
||||
|
||||
QObject::connect(searchBar, &QLineEdit::textEdited, this,
|
||||
performListSearch);
|
||||
|
||||
NetworkRequest::twitchRequest("https://tmi.twitch.tv/group/user/" +
|
||||
this->getChannel()->getName() + "/chatters")
|
||||
.caller(this)
|
||||
|
@ -1018,54 +1050,31 @@ void Split::showViewerList()
|
|||
chattersList->addItem(new QListWidgetItem());
|
||||
}
|
||||
|
||||
performListSearch();
|
||||
return Success;
|
||||
})
|
||||
.execute();
|
||||
|
||||
searchBar->setPlaceholderText("Search User...");
|
||||
QObject::connect(searchBar, &QLineEdit::textEdited, this, [=]() {
|
||||
auto query = searchBar->text();
|
||||
if (!query.isEmpty())
|
||||
{
|
||||
auto results = chattersList->findItems(query, Qt::MatchContains);
|
||||
chattersList->hide();
|
||||
resultList->clear();
|
||||
for (auto &item : results)
|
||||
{
|
||||
if (!labels.contains(item->text()))
|
||||
{
|
||||
resultList->addItem(formatListItemText(item->text()));
|
||||
}
|
||||
}
|
||||
resultList->show();
|
||||
}
|
||||
else
|
||||
{
|
||||
resultList->hide();
|
||||
chattersList->show();
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(viewerDock, &QDockWidget::topLevelChanged, this, [=]() {
|
||||
viewerDock->setMinimumWidth(300);
|
||||
});
|
||||
|
||||
auto listDoubleClick = [=](QString userName) {
|
||||
auto listDoubleClick = [this](const QModelIndex &index) {
|
||||
const auto itemText = index.data().toString();
|
||||
|
||||
// if the list item contains a parentheses it means that
|
||||
// it's a category label so don't show a usercard
|
||||
if (!userName.contains("(") && !userName.isEmpty())
|
||||
if (!itemText.contains("(") && !itemText.isEmpty())
|
||||
{
|
||||
this->view_->showUserInfoPopup(userName);
|
||||
this->view_->showUserInfoPopup(itemText);
|
||||
}
|
||||
};
|
||||
|
||||
QObject::connect(chattersList, &QListWidget::doubleClicked, this, [=]() {
|
||||
listDoubleClick(chattersList->currentItem()->text());
|
||||
});
|
||||
QObject::connect(chattersList, &QListWidget::doubleClicked, this,
|
||||
listDoubleClick);
|
||||
|
||||
QObject::connect(resultList, &QListWidget::doubleClicked, this, [=]() {
|
||||
listDoubleClick(resultList->currentItem()->text());
|
||||
});
|
||||
QObject::connect(resultList, &QListWidget::doubleClicked, this,
|
||||
listDoubleClick);
|
||||
|
||||
HotkeyController::HotkeyMap actions{
|
||||
{"delete",
|
||||
|
@ -1155,13 +1164,29 @@ const QList<QUuid> Split::getFilters() const
|
|||
return this->view_->getFilterIds();
|
||||
}
|
||||
|
||||
void Split::showSearch()
|
||||
void Split::showSearch(bool singleChannel)
|
||||
{
|
||||
SearchPopup *popup = new SearchPopup(this);
|
||||
|
||||
popup->setChannelFilters(this->view_->getFilterSet());
|
||||
auto *popup = new SearchPopup(this);
|
||||
popup->setAttribute(Qt::WA_DeleteOnClose);
|
||||
popup->setChannel(this->getChannel());
|
||||
|
||||
if (singleChannel)
|
||||
{
|
||||
popup->addChannel(this->getChannelView());
|
||||
popup->show();
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass every ChannelView for every Split across the app to the search popup
|
||||
auto ¬ebook = getApp()->windows->getMainWindow().getNotebook();
|
||||
for (int i = 0; i < notebook.getPageCount(); ++i)
|
||||
{
|
||||
auto container = dynamic_cast<SplitContainer *>(notebook.getPageAt(i));
|
||||
for (auto split : container->getSplits())
|
||||
{
|
||||
popup->addChannel(split->getChannelView());
|
||||
}
|
||||
}
|
||||
|
||||
popup->show();
|
||||
}
|
||||
|
||||
|
|
|
@ -171,7 +171,7 @@ public slots:
|
|||
void copyToClipboard();
|
||||
void startWatching();
|
||||
void setFiltersDialog();
|
||||
void showSearch();
|
||||
void showSearch(bool singleChannel);
|
||||
void showViewerList();
|
||||
void openSubPage();
|
||||
void reloadChannelAndSubscriberEmotes();
|
||||
|
|
|
@ -651,7 +651,8 @@ void SplitInput::insertCompletionText(const QString &input_)
|
|||
if (done)
|
||||
{
|
||||
auto cursor = edit.textCursor();
|
||||
edit.setText(text.remove(i, position - i + 1).insert(i, input));
|
||||
edit.setPlainText(
|
||||
text.remove(i, position - i + 1).insert(i, input));
|
||||
|
||||
cursor.setPosition(i + input.size());
|
||||
edit.setTextCursor(cursor);
|
||||
|
|
|
@ -17,6 +17,8 @@ set(test_SOURCES
|
|||
${CMAKE_CURRENT_LIST_DIR}/src/UtilTwitch.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/IrcHelpers.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/TwitchPubSubClient.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/TwitchMessageBuilder.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/FormatTime.cpp
|
||||
# Add your new file above this line!
|
||||
)
|
||||
|
||||
|
|
8
tests/README.md
Normal file
8
tests/README.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
To run tests all tests you will need to run the `kennethreitz/httpbin` and `ghcr.io/chatterino/twitch-pubsub-server-test:latest` docker images
|
||||
|
||||
For example:
|
||||
|
||||
```bash
|
||||
docker run --network=host --detach ghcr.io/chatterino/twitch-pubsub-server-test:latest
|
||||
docker run -p 9051:80 --detach kennethreitz/httpbin
|
||||
```
|
133
tests/src/FormatTime.cpp
Normal file
133
tests/src/FormatTime.cpp
Normal file
|
@ -0,0 +1,133 @@
|
|||
#include "util/FormatTime.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace chatterino;
|
||||
|
||||
TEST(FormatTime, Int)
|
||||
{
|
||||
struct TestCase {
|
||||
int input;
|
||||
QString expectedOutput;
|
||||
};
|
||||
|
||||
std::vector<TestCase> tests{
|
||||
{
|
||||
0,
|
||||
"",
|
||||
},
|
||||
{
|
||||
1337,
|
||||
"22m 17s",
|
||||
},
|
||||
{
|
||||
623452,
|
||||
"7d 5h 10m 52s",
|
||||
},
|
||||
{
|
||||
8345,
|
||||
"2h 19m 5s",
|
||||
},
|
||||
{
|
||||
314034,
|
||||
"3d 15h 13m 54s",
|
||||
},
|
||||
{
|
||||
27,
|
||||
"27s",
|
||||
},
|
||||
{
|
||||
34589,
|
||||
"9h 36m 29s",
|
||||
},
|
||||
{
|
||||
3659,
|
||||
"1h 59s",
|
||||
},
|
||||
{
|
||||
1045345,
|
||||
"12d 2h 22m 25s",
|
||||
},
|
||||
{
|
||||
86432,
|
||||
"1d 32s",
|
||||
},
|
||||
};
|
||||
|
||||
for (const auto &[input, expected] : tests)
|
||||
{
|
||||
const auto actual = formatTime(input);
|
||||
|
||||
EXPECT_EQ(actual, expected)
|
||||
<< qUtf8Printable(actual) << " (" << input
|
||||
<< ") did not match expected value " << qUtf8Printable(expected);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(FormatTime, QString)
|
||||
{
|
||||
struct TestCase {
|
||||
QString input;
|
||||
QString expectedOutput;
|
||||
};
|
||||
|
||||
std::vector<TestCase> tests{
|
||||
{
|
||||
"0",
|
||||
"",
|
||||
},
|
||||
{
|
||||
"1337",
|
||||
"22m 17s",
|
||||
},
|
||||
{
|
||||
"623452",
|
||||
"7d 5h 10m 52s",
|
||||
},
|
||||
{
|
||||
"8345",
|
||||
"2h 19m 5s",
|
||||
},
|
||||
{
|
||||
"314034",
|
||||
"3d 15h 13m 54s",
|
||||
},
|
||||
{
|
||||
"27",
|
||||
"27s",
|
||||
},
|
||||
{
|
||||
"34589",
|
||||
"9h 36m 29s",
|
||||
},
|
||||
{
|
||||
"3659",
|
||||
"1h 59s",
|
||||
},
|
||||
{
|
||||
"1045345",
|
||||
"12d 2h 22m 25s",
|
||||
},
|
||||
{
|
||||
"86432",
|
||||
"1d 32s",
|
||||
},
|
||||
{
|
||||
"",
|
||||
"n/a",
|
||||
},
|
||||
{
|
||||
"asd",
|
||||
"n/a",
|
||||
},
|
||||
};
|
||||
|
||||
for (const auto &[input, expected] : tests)
|
||||
{
|
||||
const auto actual = formatTime(input);
|
||||
|
||||
EXPECT_EQ(actual, expected)
|
||||
<< qUtf8Printable(actual) << " (" << qUtf8Printable(input)
|
||||
<< ") did not match expected value " << qUtf8Printable(expected);
|
||||
}
|
||||
}
|
|
@ -13,9 +13,17 @@ using namespace chatterino;
|
|||
|
||||
namespace {
|
||||
|
||||
static QString getStatusURL(int code)
|
||||
// Change to http://httpbin.org if you don't want to run the docker image yourself to test this
|
||||
const char *const HTTPBIN_BASE_URL = "http://127.0.0.1:9051";
|
||||
|
||||
QString getStatusURL(int code)
|
||||
{
|
||||
return QString("http://httpbin.org/status/%1").arg(code);
|
||||
return QString("%1/status/%2").arg(HTTPBIN_BASE_URL).arg(code);
|
||||
}
|
||||
|
||||
QString getDelayURL(int delay)
|
||||
{
|
||||
return QString("%1/delay/%2").arg(HTTPBIN_BASE_URL).arg(delay);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -201,7 +209,7 @@ TEST(NetworkRequest, TimeoutTimingOut)
|
|||
{
|
||||
EXPECT_TRUE(NetworkManager::workerThread.isRunning());
|
||||
|
||||
auto url = "http://httpbin.org/delay/5";
|
||||
auto url = getDelayURL(5);
|
||||
|
||||
std::mutex mut;
|
||||
bool requestDone = false;
|
||||
|
@ -248,7 +256,7 @@ TEST(NetworkRequest, TimeoutNotTimingOut)
|
|||
{
|
||||
EXPECT_TRUE(NetworkManager::workerThread.isRunning());
|
||||
|
||||
auto url = "http://httpbin.org/delay/1";
|
||||
auto url = getDelayURL(1);
|
||||
|
||||
std::mutex mut;
|
||||
bool requestDone = false;
|
||||
|
@ -293,7 +301,7 @@ TEST(NetworkRequest, FinallyCallbackOnTimeout)
|
|||
{
|
||||
EXPECT_TRUE(NetworkManager::workerThread.isRunning());
|
||||
|
||||
auto url = "http://httpbin.org/delay/5";
|
||||
auto url = getDelayURL(5);
|
||||
|
||||
std::mutex mut;
|
||||
bool requestDone = false;
|
||||
|
|
130
tests/src/TwitchMessageBuilder.cpp
Normal file
130
tests/src/TwitchMessageBuilder.cpp
Normal file
|
@ -0,0 +1,130 @@
|
|||
#include "providers/twitch/TwitchMessageBuilder.hpp"
|
||||
|
||||
#include "common/Channel.hpp"
|
||||
#include "messages/MessageBuilder.hpp"
|
||||
#include "providers/twitch/TwitchBadge.hpp"
|
||||
|
||||
#include "ircconnection.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
using namespace chatterino;
|
||||
|
||||
TEST(TwitchMessageBuilder, CommaSeparatedListTagParsing)
|
||||
{
|
||||
struct TestCase {
|
||||
QString input;
|
||||
std::pair<QString, QString> expectedOutput;
|
||||
};
|
||||
|
||||
std::vector<TestCase> testCases{
|
||||
{
|
||||
"broadcaster/1",
|
||||
{"broadcaster", "1"},
|
||||
},
|
||||
{
|
||||
"predictions/foo/bar/baz",
|
||||
{"predictions", "foo/bar/baz"},
|
||||
},
|
||||
{
|
||||
"test/",
|
||||
{"test", ""},
|
||||
},
|
||||
{
|
||||
"/",
|
||||
{"", ""},
|
||||
},
|
||||
{
|
||||
"/value",
|
||||
{"", "value"},
|
||||
},
|
||||
{
|
||||
"",
|
||||
{"", ""},
|
||||
},
|
||||
};
|
||||
|
||||
for (const auto &test : testCases)
|
||||
{
|
||||
auto output = TwitchMessageBuilder::slashKeyValue(test.input);
|
||||
|
||||
EXPECT_EQ(output, test.expectedOutput)
|
||||
<< "Input " << test.input.toStdString() << " failed";
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TwitchMessageBuilder, BadgeInfoParsing)
|
||||
{
|
||||
struct TestCase {
|
||||
QByteArray input;
|
||||
std::unordered_map<QString, QString> expectedBadgeInfo;
|
||||
std::vector<Badge> expectedBadges;
|
||||
};
|
||||
|
||||
std::vector<TestCase> testCases{
|
||||
{
|
||||
R"(@badge-info=predictions/<<<<<<\sHEAD[15A⸝asdf/test;badges=predictions/pink-2;client-nonce=9dbb88e516edf4efb055c011f91ea0cf;color=#FF4500;display-name=もっと頑張って;emotes=;first-msg=0;flags=;id=feb00b12-4ec5-4f77-9160-667de463dab1;mod=0;room-id=99631238;subscriber=0;tmi-sent-ts=1653494874297;turbo=0;user-id=648946956;user-type= :zniksbot!zniksbot@zniksbot.tmi.twitch.tv PRIVMSG #zneix :-tags")",
|
||||
{
|
||||
{"predictions", R"(<<<<<<\sHEAD[15A⸝asdf/test)"},
|
||||
},
|
||||
{
|
||||
Badge{"predictions", "pink-2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
R"(@badge-info=predictions/<<<<<<\sHEAD[15A⸝asdf/test,founder/17;badges=predictions/pink-2,vip/1,founder/0,bits/1;client-nonce=9b836e232170a9df213aefdcb458b67e;color=#696969;display-name=NotKarar;emotes=;first-msg=0;flags=;id=e00881bd-5f21-4993-8bbd-1736cd13d42e;mod=0;room-id=99631238;subscriber=1;tmi-sent-ts=1653494879409;turbo=0;user-id=89954186;user-type= :notkarar!notkarar@notkarar.tmi.twitch.tv PRIVMSG #zneix :-tags)",
|
||||
{
|
||||
{"predictions", R"(<<<<<<\sHEAD[15A⸝asdf/test)"},
|
||||
{"founder", "17"},
|
||||
},
|
||||
{
|
||||
Badge{"predictions", "pink-2"},
|
||||
Badge{"vip", "1"},
|
||||
Badge{"founder", "0"},
|
||||
Badge{"bits", "1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
R"(@badge-info=predictions/foo/bar/baz;badges=predictions/blue-1,moderator/1,glhf-pledge/1;client-nonce=f73f16228e6e32f8e92b47ab8283b7e1;color=#1E90FF;display-name=zneixbot;emotes=30259:6-12;first-msg=0;flags=;id=9682a5f1-a0b0-45e2-be9f-8074b58c5f8f;mod=1;room-id=99631238;subscriber=0;tmi-sent-ts=1653573594035;turbo=0;user-id=463521670;user-type=mod :zneixbot!zneixbot@zneixbot.tmi.twitch.tv PRIVMSG #zneix :-tags HeyGuys)",
|
||||
{
|
||||
{"predictions", "foo/bar/baz"},
|
||||
},
|
||||
{
|
||||
Badge{"predictions", "blue-1"},
|
||||
Badge{"moderator", "1"},
|
||||
Badge{"glhf-pledge", "1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
R"(@badge-info=subscriber/22;badges=broadcaster/1,subscriber/18,glhf-pledge/1;color=#F97304;display-name=zneix;emotes=;first-msg=0;flags=;id=1d99f67f-a566-4416-a4e2-e85d7fce9223;mod=0;room-id=99631238;subscriber=1;tmi-sent-ts=1653612232758;turbo=0;user-id=99631238;user-type= :zneix!zneix@zneix.tmi.twitch.tv PRIVMSG #zneix :-tags)",
|
||||
{
|
||||
{"subscriber", "22"},
|
||||
},
|
||||
{
|
||||
Badge{"broadcaster", "1"},
|
||||
Badge{"subscriber", "18"},
|
||||
Badge{"glhf-pledge", "1"},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
for (const auto &test : testCases)
|
||||
{
|
||||
auto privmsg =
|
||||
Communi::IrcPrivateMessage::fromData(test.input, nullptr);
|
||||
|
||||
auto outputBadgeInfo =
|
||||
TwitchMessageBuilder::parseBadgeInfoTag(privmsg->tags());
|
||||
EXPECT_EQ(outputBadgeInfo, test.expectedBadgeInfo)
|
||||
<< "Input for badgeInfo " << test.input.toStdString() << " failed";
|
||||
|
||||
auto outputBadges =
|
||||
SharedMessageBuilder::parseBadgeTag(privmsg->tags());
|
||||
EXPECT_EQ(outputBadges, test.expectedBadges)
|
||||
<< "Input for badges " << test.input.toStdString() << " failed";
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue