Skip to content

Commit

Permalink
work on dynamic badge-loading
Browse files Browse the repository at this point in the history
  • Loading branch information
pajlada committed Jun 15, 2017
1 parent e7282b5 commit 7525dae
Show file tree
Hide file tree
Showing 11 changed files with 263 additions and 15 deletions.
1 change: 1 addition & 0 deletions chatterino.pro
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ SOURCES += \
src/main.cpp \
src/application.cpp \
src/channel.cpp \
src/channeldata.cpp \
src/colorscheme.cpp \
src/emojis.cpp \
src/ircmanager.cpp \
Expand Down
5 changes: 5 additions & 0 deletions src/channeldata.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include "channeldata.hpp"

namespace chatterino {

} // namespace chatterino
20 changes: 20 additions & 0 deletions src/channeldata.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include "lockedobject.hpp"
#include "messages/lazyloadedimage.hpp"

namespace chatterino {

class ChannelData
{
public:
ChannelData() = default;

LockedObject<std::string> username;
LockedObject<std::string> id;

private:
// std::map<std::string, BadgeData> subscriptionBadges;
};

}; // namespace chatterino
13 changes: 13 additions & 0 deletions src/channelmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,17 @@ void ChannelManager::removeChannel(const QString &channel)
}
}

const std::string &ChannelManager::getUserID(const std::string &username)
{
auto it = this->usernameToID.find(username);

/*
if (it != std::end(this->usernameToID)) {
return *it;
}
*/

return "xd";
}

} // namespace chatterino
8 changes: 8 additions & 0 deletions src/channelmanager.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#pragma once

#include "channel.hpp"
#include "channeldata.hpp"

#include <map>

namespace chatterino {

Expand All @@ -24,11 +27,16 @@ class ChannelManager
std::shared_ptr<Channel> getChannel(const QString &channel);
void removeChannel(const QString &channel);

const std::string &getUserID(const std::string &username);

private:
WindowManager &windowManager;
EmoteManager &emoteManager;
IrcManager &ircManager;

std::map<std::string, std::string> usernameToID;
std::map<std::string, ChannelData> channelDatas;

QMap<QString, std::tuple<std::shared_ptr<Channel>, int>> _channels;
QMutex _channelsMutex;

Expand Down
52 changes: 52 additions & 0 deletions src/concurrentmap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <QMutexLocker>

#include <functional>
#include <map>

namespace chatterino {

Expand Down Expand Up @@ -64,4 +65,55 @@ class ConcurrentMap
QMap<TKey, TValue> _map;
};

template <typename TKey, typename TValue>
class ConcurrentStdMap
{
public:
bool tryGet(const TKey &name, TValue &value) const
{
QMutexLocker lock(&_mutex);

auto a = _map.find(name);
if (a == _map.end()) {
return false;
}

value = a.value();

return true;
}

TValue getOrAdd(const TKey &name, std::function<TValue()> addLambda)
{
QMutexLocker lock(&_mutex);

auto a = _map.find(name);
if (a == _map.end()) {
TValue value = addLambda();
_map.insert(name, value);
return value;
}

return a.value();
}

void clear()
{
QMutexLocker lock(&_mutex);

_map.clear();
}

void insert(const TKey &name, const TValue &value)
{
QMutexLocker lock(&_mutex);

_map.insert(name, value);
}

private:
mutable QMutex _mutex;
std::map<TKey, TValue> _map;
};

} // namespace chatterino
38 changes: 38 additions & 0 deletions src/lockedobject.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma once

#include <mutex>

namespace chatterino {

template <typename Type>
class LockedObject
{
public:
LockedObject &operator=(const LockedObject<Type> &other)
{
this->mutex.lock();

this->data = other.getValue();

this->mutex.unlock();

return *this;
}

LockedObject &operator=(const Type &other)
{
this->mutex.lock();

this->data = other;

this->mutex.unlock();

return *this;
}

private:
Type value;
std::mutex mutex;
};

} // namespace chatterino
46 changes: 45 additions & 1 deletion src/resources.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "resources.hpp"
#include "emotemanager.hpp"
#include "util/urlfetch.hpp"
#include "windowmanager.hpp"

#include <QPixmap>
Expand All @@ -25,7 +26,7 @@ Resources::Resources(EmoteManager &emoteManager, WindowManager &windowManager)
, badgeTurbo(lli(emoteManager, windowManager, ":/images/turbo_bg.png"))
, badgeBroadcaster(lli(emoteManager, windowManager, ":/images/broadcaster_bg.png"))
, badgePremium(lli(emoteManager, windowManager, ":/images/twitchprime_bg.png"))
, badgeVerified(lli(emoteManager, windowManager, ":/images/verified.png"))
, badgeVerified(lli(emoteManager, windowManager, ":/images/verified.png", 0.25))
, cheerBadge100000(lli(emoteManager, windowManager, ":/images/cheer100000"))
, cheerBadge10000(lli(emoteManager, windowManager, ":/images/cheer10000"))
, cheerBadge5000(lli(emoteManager, windowManager, ":/images/cheer5000"))
Expand All @@ -35,6 +36,49 @@ Resources::Resources(EmoteManager &emoteManager, WindowManager &windowManager)
, buttonBan(lli(emoteManager, windowManager, ":/images/button_ban.png", 0.25))
, buttonTimeout(lli(emoteManager, windowManager, ":/images/button_timeout.png", 0.25))
{
QString badgesUrl("https://badges.twitch.tv/v1/badges/global/display?language=en");

util::urlJsonFetch(badgesUrl, [this](QJsonObject &root) {
QJsonObject sets = root.value("badge_sets").toObject();

for (auto it = std::begin(sets); it != std::end(sets); ++it) {
printf("%s\n", qPrintable(it.key()));

auto &badgeSet = this->badgeSets[it.key().toStdString()];

std::map<std::string, BadgeVersion> &versionsMap = badgeSet.versions;

QJsonObject versions = sets.value("versions").toObject();

for (auto versionIt = std::begin(versions); versionIt != std::end(versions);
++versionIt) {
/*
std::string kkey = versionIt.key().toStdString();
QJsonObject versionObj = versionIt.value().toObject();
versionsMap.emplace(std::make_pair(kkey, versionObj));
*/
}
}
});
}

Resources::BadgeVersion::BadgeVersion(QJsonObject &&root)
{
}

void Resources::Channel::loadData()
{
/*
if (this->loaded) {
return;
}
this->loaded = true;
if (this->id.empty()) {
//util::urlJsonFetch()
}
*/
}

} // namespace chatterino
41 changes: 41 additions & 0 deletions src/resources.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

#include "messages/lazyloadedimage.hpp"

#include <map>
#include <mutex>

namespace chatterino {

class EmoteManager;
Expand All @@ -28,8 +31,46 @@ class Resources
messages::LazyLoadedImage *cheerBadge100;
messages::LazyLoadedImage *cheerBadge1;

std::map<std::string, messages::LazyLoadedImage *> cheerBadges;

struct BadgeVersion {
BadgeVersion() = delete;

explicit BadgeVersion(QJsonObject &&root);

messages::LazyLoadedImage *badgeImage1x;
messages::LazyLoadedImage *badgeImage2x;
messages::LazyLoadedImage *badgeImage4x;
std::string description;
std::string title;
std::string clickAction;
std::string clickUrl;
};

struct BadgeSet {
std::map<std::string, BadgeVersion> versions;
};

std::map<std::string, BadgeSet> badgeSets;

bool bitBadgesLoaded = false;
bool dynamicBadgesLoaded = false;

messages::LazyLoadedImage *buttonBan;
messages::LazyLoadedImage *buttonTimeout;

struct Channel {
std::string id;

std::mutex globalMapMutex;

void loadData();

// std::atomic<bool> loaded = false;
};

// channelId
std::map<std::string, Channel> channels;
};

} // namespace chatterino
46 changes: 36 additions & 10 deletions src/twitch/twitchmessagebuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,17 @@ TwitchMessageBuilder::TwitchMessageBuilder()
{
}

SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircMessage,
Channel *channel, const MessageParseArgs &args,
const Resources &resources, EmoteManager &emoteManager,
// When a twitch message is being parsed it makes sense for the builder to have access to:
// - The IRC Message
// - Message-specific parsing arguments (i.e. if ping sounds are disabled)
// - The Channel that the message originated from
// - The resources class for Badges, Moderation buttons
// - The Emote Manager for all different kinds of emotes
SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircMessage, //
Channel *channel, //
const MessageParseArgs &args, //
Resources &resources, //
EmoteManager &emoteManager, //
WindowManager &windowManager)
{
TwitchMessageBuilder b;
Expand All @@ -37,6 +45,13 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM
b.messageId = iterator.value().toString();
}

// room id
iterator = tags.find("room-id");
std::string roomID;
if (iterator != std::end(tags)) {
roomID = iterator.value().toString().toStdString();
}

// timestamps
iterator = tags.find("tmi-sent-ts");

Expand All @@ -45,10 +60,12 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM
// badges
iterator = tags.find("badges");

const auto &channelResources = resources.channels[roomID];

if (iterator != tags.end()) {
auto badges = iterator.value().toString().split(',');

b.appendTwitchBadges(badges, resources, emoteManager);
b.appendTwitchBadges(badges, resources, emoteManager, channelResources);
}

// color
Expand Down Expand Up @@ -331,18 +348,26 @@ void TwitchMessageBuilder::appendTwitchEmote(
}
}

void TwitchMessageBuilder::appendTwitchBadges(const QStringList &badges, const Resources &resources,
EmoteManager &emoteManager)
void TwitchMessageBuilder::appendTwitchBadges(const QStringList &badges, Resources &resources,
EmoteManager &emoteManager,
const Resources::Channel &channelResources)
{
for (QString badge : badges) {
if (badge.isEmpty()) {
continue;
}

if (badge.startsWith("bits/")) {
long long int cheer = std::strtoll(badge.mid(5).toStdString().c_str(), nullptr, 10);
appendWord(Word(emoteManager.getCheerBadge(cheer), Word::BadgeCheer, QString(),
QString("Twitch Cheer" + QString::number(cheer))));
if (!resources.bitBadgesLoaded) {
// Do nothing
continue;
}

QString cheerAmountQS = badge.mid(5);
std::string cheerAmountString = cheerAmountQS.toStdString();

appendWord(Word(resources.cheerBadges[cheerAmountString], Word::BadgeCheer, QString(),
QString("Twitch Cheer" + cheerAmountQS)));
} else if (badge == "staff/1") {
appendWord(
Word(resources.badgeStaff, Word::BadgeStaff, QString(), QString("Twitch Staff")));
Expand Down Expand Up @@ -382,7 +407,8 @@ void TwitchMessageBuilder::appendTwitchBadges(const QStringList &badges, const R
// TODO: Implement subscriber badges here
switch (index) {
default: {
// printf("[TwitchMessageBuilder] Unhandled subscriber badge index: %d\n", index);
// printf("[TwitchMessageBuilder] Unhandled subscriber badge index: %d\n",
// index);
} break;
}
} else {
Expand Down
Loading

0 comments on commit 7525dae

Please sign in to comment.