From 1d7ff5a8bdeb6dc48ae990222e0cf7e162631ace Mon Sep 17 00:00:00 2001 From: Michael Ennis Date: Sun, 24 Nov 2019 03:35:48 +0000 Subject: [PATCH 1/3] Make it so that the first level is not promoted to 'current' when it is added as the submitter might not stick around and 'current' is immune to the online status check. --- chat.cpp | 8 +++++--- quesoqueue.cpp | 12 ++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/chat.cpp b/chat.cpp index cd56aa4..ac26467 100644 --- a/chat.cpp +++ b/chat.cpp @@ -135,8 +135,10 @@ std::string Chat::LevelListMessage(std::optional current, PriorityQueso l ss << online.size() + (current ? 1 : 0) << " online level(s) in the queue: "; + std::string starter = current ? std::string(current->submitter + " (current)") : ""; + ss << std::accumulate(online.begin(), online.end(), - std::string(current->submitter + " (current)"), + starter, [](std::string acc, Level x){ return acc + ", " + x.submitter; }); @@ -151,7 +153,7 @@ std::string Chat::NextLevelMessage(std::optional l) { } std::stringstream ss; - ss << "Next up in queue is " << l->levelCode << ", submitted by " + ss << "Next is " << l->levelCode << ", submitted by " << l->submitter; return ss.str(); } @@ -177,7 +179,7 @@ std::string Chat::PositionMessage(int position) { msg << "Your level is being played right now!"; break; default: - msg << "You are currently in position " << position+1; + msg << "You are currently in position " << position; break; } return msg.str(); diff --git a/quesoqueue.cpp b/quesoqueue.cpp index 2ff63f1..68755b0 100644 --- a/quesoqueue.cpp +++ b/quesoqueue.cpp @@ -58,19 +58,15 @@ std::string QuesoQueue::Add(Level level) { if (result == _levels.end() || level.submitter == Auth::channel) { auto online_levels = std::get<0>(List()).size(); // push to the end of the queue - if (_levels.empty() && !Current().has_value()) { - _current = std::make_optional(level); - } else { - _levels.push_back(level); - online_levels++; - } + _levels.push_back(level); + online_levels++; std::stringstream ss; // Since they JUST added it, we can pretty safely assume they're online. ss << level.submitter; ss << ", "; ss << level.levelCode; ss << " has been added to the queue. Currently in position #"; - ss << online_levels + 1; + ss << online_levels + (_current ? 1 : 0); ss << "."; SaveState(); return ss.str(); @@ -169,7 +165,7 @@ int QuesoQueue::Position(std::string username) { for (Level l : both) { position++; if (l.submitter == username) { - return position; + return position + (_current ? 1 : 0); } } // not in queue From 3e82f001c97797d989d5d0a35fbdad9ee593f72c Mon Sep 17 00:00:00 2001 From: Michael Ennis Date: Sun, 24 Nov 2019 03:45:19 +0000 Subject: [PATCH 2/3] Adding a system to track users that recently used commands. They will be added to a list of online users that will supplement Twitch's API. Any user that used a command within the last 5 minutes will be seen as online. --- chat.cpp | 3 ++- chat.h | 3 ++- main.cpp | 2 +- quesoqueue.cpp | 1 + quesoqueue.h | 2 +- twitch.cpp | 20 ++++++++++++++++++++ twitch.h | 6 ++++++ 7 files changed, 33 insertions(+), 4 deletions(-) diff --git a/chat.cpp b/chat.cpp index ac26467..e02d3d8 100644 --- a/chat.cpp +++ b/chat.cpp @@ -14,7 +14,7 @@ #include #include -Chat::Chat(const QuesoQueue &qq, const Timer &timer) : _qq(qq), _timer(timer) { +Chat::Chat(const QuesoQueue &qq, const Twitch &twitch, const Timer &timer) : _qq(qq), _twitch(twitch), _timer(timer) { namespace fs = std::experimental::filesystem; static const std::regex chipModuleRegex(".*\\.so", std::regex_constants::egrep); @@ -109,6 +109,7 @@ void Chat::Listen() { // Get message body std::string messageBody = m[2]; + _twitch.markAsOnline(username); HandleMessage(std::stringstream(messageBody), username); continue; } diff --git a/chat.h b/chat.h index 5d1d141..5bf332a 100644 --- a/chat.h +++ b/chat.h @@ -14,7 +14,7 @@ class Chat { public: - Chat(const QuesoQueue &qq, const Timer &timer); + Chat(const QuesoQueue &qq, const Twitch &twitch, const Timer &timer); void HandleMessage(std::stringstream message, std::string sender); void WriteMessage(std::string message); void Write(std::string command); @@ -30,6 +30,7 @@ class Chat { bool _canAddToQueue = true; QuesoQueue _qq; + Twitch _twitch; Timer _timer; std::string _priorityText; diff --git a/main.cpp b/main.cpp index 58f4a8f..460f9de 100644 --- a/main.cpp +++ b/main.cpp @@ -8,7 +8,7 @@ int main(int, char **) { QuesoQueue qq(t); qq.LoadLastState(); Timer ti; - Chat c(qq, ti); + Chat c(qq, t, ti); c.Connect(); c.Listen(); } diff --git a/quesoqueue.cpp b/quesoqueue.cpp index 68755b0..f212215 100644 --- a/quesoqueue.cpp +++ b/quesoqueue.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/quesoqueue.h b/quesoqueue.h index 1912bc2..5617749 100644 --- a/quesoqueue.h +++ b/quesoqueue.h @@ -65,5 +65,5 @@ class QuesoQueue { std::deque _levels; std::optional _current; Twitch _twitch; // query online state - const size_t maxSize = 15; + const size_t maxSize = 30; }; diff --git a/twitch.cpp b/twitch.cpp index faf312e..dbdd9ba 100644 --- a/twitch.cpp +++ b/twitch.cpp @@ -1,7 +1,11 @@ #include "twitch.h" +#include +#include #include #include +#include +#include #include #include "SimpleJSON/JSON.h" @@ -67,9 +71,25 @@ std::set Twitch::getOnlineUsers(const std::string& channel) { } } + auto current_time = std::chrono::system_clock::now(); + auto user_snapshot = _recent_chatters; + _recent_chatters = {}; + for(auto const& [user, last_heard_from] : user_snapshot) { + //TODO: This time should be runtime configurable. + if (current_time - last_heard_from < std::chrono::minutes(5)) { + online_users.emplace(user); + _recent_chatters.emplace(user, last_heard_from); + } + } + return online_users; } +void Twitch::markAsOnline(std::string username) { + auto current = std::chrono::system_clock::now(); + _recent_chatters.emplace(username, current); +} + void placeStreamMarker() { // stub } diff --git a/twitch.h b/twitch.h index 8a075ab..decf2be 100644 --- a/twitch.h +++ b/twitch.h @@ -1,5 +1,8 @@ #pragma once +#include +#include +#include #include #include @@ -9,6 +12,9 @@ class Twitch { std::set getOnlineUsers(const std::string& channel); void placeStreamMarker(); + void markAsOnline(std::string username); + private: + std::map _recent_chatters; // IDK twitch API keys?????? }; From 61e2b0727125b84d08ac877cbe82cac14d5cd139 Mon Sep 17 00:00:00 2001 From: Michael Ennis Date: Sun, 24 Nov 2019 03:46:37 +0000 Subject: [PATCH 3/3] Add a 'random' command that will dip into the online levels (or offline ones if there are no online levels). --- chat.cpp | 8 ++++++++ quesoqueue.cpp | 36 ++++++++++++++++++++++++++++++++++++ quesoqueue.h | 5 +++++ 3 files changed, 49 insertions(+) diff --git a/chat.cpp b/chat.cpp index e02d3d8..5513c79 100644 --- a/chat.cpp +++ b/chat.cpp @@ -238,6 +238,14 @@ void Chat::HandleMessage(std::stringstream message, std::string sender) { WriteMessage(NextLevelMessage(l)); } else if (command == "current") { WriteMessage(CurrentLevelMessage(_qq.Current())); + } else if (command == "random" && sender == Auth::channel) { + _timer.Reset(); + std::optional l = _qq.Random(); + if (l) { + WriteMessage(std::string("/marker " + l->levelCode + ", submitted by " + + l->submitter)); + } + WriteMessage(NextLevelMessage(l)); } else if (command == "list") { WriteMessage(LevelListMessage(_qq.Current(), _qq.List())); } else if (command == "position") { diff --git a/quesoqueue.cpp b/quesoqueue.cpp index f212215..aa51b7f 100644 --- a/quesoqueue.cpp +++ b/quesoqueue.cpp @@ -222,6 +222,42 @@ std::optional QuesoQueue::Current() { return _current; } +std::optional QuesoQueue::Random() { + auto list = List(); + std::deque levels(std::get<0>(list)); // Use online levels first. + + if (levels.empty()) { + levels = std::get<1>(list); // See if there are offline levels. + if (levels.empty()) { + _current = std::nullopt; + return _current; + } + } + std::vector new_current = {}; + std::sample(levels.begin(), levels.end(), std::back_inserter(new_current), + 1, std::mt19937{std::random_device{}()}); + + if (new_current.empty()) { + _current = std::nullopt; + } else { + _current = std::make_optional(new_current[0]); + } + + // Remove current (it's in a special current place now) + _levels.erase( + std::find_if( + _levels.begin(), + _levels.end(), + [&](auto l){ + return l.submitter == _current->submitter && + l.levelCode == _current->levelCode; + } + ) + ); + SaveState(); + return _current; +} + PriorityQueso QuesoQueue::List() { std::deque online, offline; std::set online_users = _twitch.getOnlineUsers(Auth::channel); diff --git a/quesoqueue.h b/quesoqueue.h index 5617749..962c14c 100644 --- a/quesoqueue.h +++ b/quesoqueue.h @@ -46,6 +46,11 @@ class QuesoQueue { */ std::optional Punt(); + /** + * Selects a random level from the queue and returns the new top (subject to priority queue split) + */ + std::optional Random(); + /** * Split the stored level queue into online and offline for printing */