From 54c8a082aa513cb10860e16a74b7f2e7ae638b2b Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Wed, 28 Mar 2018 21:12:17 -0400 Subject: Migrated to hkutil --- .gitmodules | 3 + CMakeLists.txt | 5 +- database.cpp | 217 --------------------------------------------------------- database.h | 62 ----------------- lunatic.cpp | 105 ++++++++++++++++++---------- vendor/hkutil | 1 + 6 files changed, 75 insertions(+), 318 deletions(-) delete mode 100644 database.cpp delete mode 100644 database.h create mode 160000 vendor/hkutil diff --git a/.gitmodules b/.gitmodules index b7a969a..79e1759 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "vendor/libtwittercpp"] path = vendor/libtwittercpp url = git@github.com:hatkirby/libtwittercpp +[submodule "vendor/hkutil"] + path = vendor/hkutil + url = git@github.com:hatkirby/hkutil diff --git a/CMakeLists.txt b/CMakeLists.txt index 00c0ad9..d9a289c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,11 +11,12 @@ pkg_check_modules(sqlite3 sqlite3>=3.8.3 REQUIRED) include_directories( vendor/libtwittercpp/src ${yaml-cpp_INCLUDE_DIRS} - ${GraphicsMagick_INCLUDE_DIRS}) + ${GraphicsMagick_INCLUDE_DIRS} + vendor/hkutil) link_directories(${GraphicsMagick_LIBRARY_DIRS}) -add_executable(lunatic lunatic.cpp database.cpp) +add_executable(lunatic lunatic.cpp) set_property(TARGET lunatic PROPERTY CXX_STANDARD 11) set_property(TARGET lunatic PROPERTY CXX_STANDARD_REQUIRED ON) target_link_libraries(lunatic ${yaml-cpp_LIBRARIES} ${GraphicsMagick_LIBRARIES} ${sqlite3_LIBRARIES} twitter++) \ No newline at end of file diff --git a/database.cpp b/database.cpp deleted file mode 100644 index 19ba0e0..0000000 --- a/database.cpp +++ /dev/null @@ -1,217 +0,0 @@ -#include "database.h" -#include -#include -#include -#include - -database::database(std::string path) -{ - if (sqlite3_open_v2( - path.c_str(), - &ppdb_, - SQLITE_OPEN_READONLY, - NULL) != SQLITE_OK) - { - // We still have to free the resources allocated. In the event that - // allocation failed, ppdb will be null and sqlite3_close_v2 will just - // ignore it. - std::string errmsg(sqlite3_errmsg(ppdb_)); - sqlite3_close_v2(ppdb_); - - throw std::logic_error(errmsg); - } -} - -database::database(database&& other) : database() -{ - swap(*this, other); -} - -database& database::operator=(database&& other) -{ - swap(*this, other); - - return *this; -} - -void swap(database& first, database& second) -{ - std::swap(first.ppdb_, second.ppdb_); -} - -database::~database() -{ - sqlite3_close_v2(ppdb_); -} - -achievement database::getRandomAchievement() const -{ - std::string queryString = "SELECT achievements.achievement_id, achievements.game_id, achievements.title, games.color FROM achievements INNER JOIN games ON games.game_id = achievements.game_id ORDER BY RANDOM() LIMIT 1"; - - sqlite3_stmt* ppstmt; - if (sqlite3_prepare_v2( - ppdb_, - queryString.c_str(), - queryString.length(), - &ppstmt, - NULL) != SQLITE_OK) - { - std::string errorMsg = sqlite3_errmsg(ppdb_); - sqlite3_finalize(ppstmt); - - throw std::logic_error(errorMsg); - } - - if (sqlite3_step(ppstmt) != SQLITE_ROW) - { - std::string errorMsg = sqlite3_errmsg(ppdb_); - sqlite3_finalize(ppstmt); - - throw std::logic_error(errorMsg); - } - - achievement result; - - result.achievementId = sqlite3_column_int(ppstmt, 0); - result.gameId = sqlite3_column_int(ppstmt, 1); - result.title = reinterpret_cast(sqlite3_column_text(ppstmt, 2)); - result.color = reinterpret_cast(sqlite3_column_text(ppstmt, 3)); - - sqlite3_finalize(ppstmt); - - return result; -} - -bool database::doesGameHaveImages(int gameId) const -{ - std::string queryString = "SELECT COUNT(*) FROM images WHERE game_id = ? ORDER BY RANDOM() LIMIT 1"; - - sqlite3_stmt* ppstmt; - if (sqlite3_prepare_v2( - ppdb_, - queryString.c_str(), - queryString.length(), - &ppstmt, - NULL) != SQLITE_OK) - { - std::string errorMsg = sqlite3_errmsg(ppdb_); - sqlite3_finalize(ppstmt); - - throw std::logic_error(errorMsg); - } - - if (sqlite3_bind_int(ppstmt, 1, gameId) != SQLITE_OK) - { - std::string errorMsg = sqlite3_errmsg(ppdb_); - sqlite3_finalize(ppstmt); - - throw std::logic_error(errorMsg); - } - - if (sqlite3_step(ppstmt) != SQLITE_ROW) - { - std::string errorMsg = sqlite3_errmsg(ppdb_); - sqlite3_finalize(ppstmt); - - throw std::logic_error(errorMsg); - } - - int result = sqlite3_column_int(ppstmt, 0); - - sqlite3_finalize(ppstmt); - - return (result > 0); -} - -std::string database::getRandomImageForGame(int gameId) const -{ - std::string queryString = "SELECT filename FROM images WHERE game_id = ? ORDER BY RANDOM() LIMIT 1"; - - sqlite3_stmt* ppstmt; - if (sqlite3_prepare_v2( - ppdb_, - queryString.c_str(), - queryString.length(), - &ppstmt, - NULL) != SQLITE_OK) - { - std::string errorMsg = sqlite3_errmsg(ppdb_); - sqlite3_finalize(ppstmt); - - throw std::logic_error(errorMsg); - } - - if (sqlite3_bind_int(ppstmt, 1, gameId) != SQLITE_OK) - { - std::string errorMsg = sqlite3_errmsg(ppdb_); - sqlite3_finalize(ppstmt); - - throw std::logic_error(errorMsg); - } - - if (sqlite3_step(ppstmt) != SQLITE_ROW) - { - std::string errorMsg = sqlite3_errmsg(ppdb_); - sqlite3_finalize(ppstmt); - - throw std::logic_error(errorMsg); - } - - std::string result = reinterpret_cast(sqlite3_column_text(ppstmt, 0)); - - sqlite3_finalize(ppstmt); - - return result; -} - -did database::getRandomDidForAchievement(int achievementId) const -{ - std::string queryString = "SELECT profile_id, DATETIME(achieved_at) FROM dids WHERE achievement_id = ? ORDER BY RANDOM() LIMIT 1"; - - sqlite3_stmt* ppstmt; - if (sqlite3_prepare_v2( - ppdb_, - queryString.c_str(), - queryString.length(), - &ppstmt, - NULL) != SQLITE_OK) - { - std::string errorMsg = sqlite3_errmsg(ppdb_); - sqlite3_finalize(ppstmt); - - throw std::logic_error(errorMsg); - } - - if (sqlite3_bind_int(ppstmt, 1, achievementId) != SQLITE_OK) - { - std::string errorMsg = sqlite3_errmsg(ppdb_); - sqlite3_finalize(ppstmt); - - throw std::logic_error(errorMsg); - } - - if (sqlite3_step(ppstmt) != SQLITE_ROW) - { - std::string errorMsg = sqlite3_errmsg(ppdb_); - sqlite3_finalize(ppstmt); - - throw std::logic_error(errorMsg); - } - - did result; - result.profileId = sqlite3_column_int(ppstmt, 0); - - std::tm achievedAt = {}; - - std::stringstream dateParser; - dateParser << reinterpret_cast(sqlite3_column_text(ppstmt, 1)); - dateParser >> std::get_time(&achievedAt, "%Y-%m-%d %H:%M:%S"); - - std::stringstream dateFormatter; - dateFormatter << std::put_time(&achievedAt, "%m/%d/%Y"); - result.date = dateFormatter.str(); - - sqlite3_finalize(ppstmt); - - return result; -} diff --git a/database.h b/database.h deleted file mode 100644 index 50f5b55..0000000 --- a/database.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef DATABASE_H_75C3CE0F -#define DATABASE_H_75C3CE0F - -#include - -struct sqlite3; - -struct achievement { - int achievementId; - int gameId; - std::string title; - std::string color; -}; - -struct did { - int profileId; - std::string date; -}; - -class database { -public: - - // Constructor - - explicit database(std::string path); - - // Disable copying - - database(const database& other) = delete; - database& operator=(const database& other) = delete; - - // Move constructor and move assignment - - database(database&& other); - database& operator=(database&& other); - - // Swap - - friend void swap(database& first, database& second); - - // Destructor - - ~database(); - - // Accessors - - achievement getRandomAchievement() const; - - bool doesGameHaveImages(int gameId) const; - - std::string getRandomImageForGame(int gameId) const; - - did getRandomDidForAchievement(int achievementId) const; - -private: - - database() = default; - - sqlite3* ppdb_ = nullptr; -}; - -#endif /* end of include guard: DATABASE_H_75C3CE0F */ diff --git a/lunatic.cpp b/lunatic.cpp index daebc73..59241fa 100644 --- a/lunatic.cpp +++ b/lunatic.cpp @@ -10,30 +10,9 @@ #include #include #include -#include "database.h" - -template -Container split(std::string input, std::string delimiter) -{ - Container result; - - while (!input.empty()) - { - int divider = input.find(delimiter); - if (divider == std::string::npos) - { - result.push_back(input); - - input = ""; - } else { - result.push_back(input.substr(0, divider)); - - input = input.substr(divider+delimiter.length()); - } - } - - return result; -} +#include +#include +#include int main(int argc, char** argv) { @@ -56,7 +35,9 @@ int main(int argc, char** argv) twitter::client client(auth); - database db(config["database"].as()); + hatkirby::database database( + config["database"].as(), + hatkirby::dbmode::read); std::random_device randomDevice; std::mt19937 rng(randomDevice()); @@ -87,15 +68,29 @@ int main(int argc, char** argv) { std::cout << "Generating tweet" << std::endl; - achievement ach = db.getRandomAchievement(); - - if (blacklist.count(ach.title)) + hatkirby::row achRow = + database.queryFirst( + "SELECT achievements.achievement_id, \ + achievements.game_id, \ + achievements.title, \ + games.color \ + FROM achievements \ + INNER JOIN games ON games.game_id = achievements.game_id \ + ORDER BY RANDOM() \ + LIMIT 1"); + + int achId = mpark::get(achRow[0]); + int gameId = mpark::get(achRow[1]); + std::string achTitle = mpark::get(achRow[2]); + std::string achColor = mpark::get(achRow[3]); + + if (blacklist.count(achTitle)) { continue; } Magick::Image moonColor; - moonColor.read("res/" + ach.color + ".png"); + moonColor.read("res/" + achColor + ".png"); // Start with the Odyssey text overlay Magick::Image overlay; @@ -115,9 +110,11 @@ int main(int argc, char** argv) overlay.fillColor("white"); overlay.font("@" + config["title_font"].as()); - std::list words = split>( - ach.title, - " "); + std::list words = + hatkirby::split>( + achTitle, + " "); + std::ostringstream wrappingStream; std::string curline; int lines = 1; @@ -163,14 +160,32 @@ int main(int argc, char** argv) Magick::GravityType::NorthGravity); // Add the achievement date - did theDid = db.getRandomDidForAchievement(ach.achievementId); + hatkirby::row didRow = + database.queryFirst( + "SELECT DATETIME(achieved_at) \ + FROM dids \ + WHERE achievement_id = ? \ + ORDER BY RANDOM() \ + LIMIT 1", + { achId }); + + std::tm achievedAt = {}; + + std::stringstream dateParser; + dateParser << mpark::get(didRow[0]); + dateParser >> std::get_time(&achievedAt, "%Y-%m-%d %H:%M:%S"); + + std::stringstream dateFormatter; + dateFormatter << std::put_time(&achievedAt, "%m/%d/%Y"); + + std::string didDate = dateFormatter.str(); overlay.fontTypeMetrics(wrapped, &metric); overlay.fontPointsize(20); overlay.font("@" + config["date_font"].as()); overlay.annotate( - theDid.date, + didDate, Magick::Geometry(1600, 228, 0, 710 + metric.textHeight() * lines - 22), Magick::GravityType::NorthGravity); @@ -182,9 +197,25 @@ int main(int argc, char** argv) // Read the game image, using a default if the game has no images Magick::Image image; - if (db.doesGameHaveImages(ach.gameId)) + hatkirby::row checkRow = + database.queryFirst( + "SELECT COUNT(*) \ + FROM images \ + WHERE game_id = ?", + { gameId }); + + if (mpark::get(checkRow[0]) > 0) { - std::string imageName = db.getRandomImageForGame(ach.gameId); + hatkirby::row imageRow = + database.queryFirst( + "SELECT filename \ + FROM images \ + WHERE game_id = ? \ + ORDER BY RANDOM() \ + LIMIT 1", + { gameId }); + + std::string imageName = mpark::get(imageRow[0]); std::string imagePath = config["images"].as() + "/" + imageName; @@ -229,7 +260,7 @@ int main(int argc, char** argv) } std::string header = "YOU GOT A MOON!"; - std::string action = header + "\n" + ach.title; + std::string action = header + "\n" + achTitle; action.resize(140); std::cout << action << std::endl; diff --git a/vendor/hkutil b/vendor/hkutil new file mode 160000 index 0000000..eb30ce1 --- /dev/null +++ b/vendor/hkutil @@ -0,0 +1 @@ +Subproject commit eb30ce13012108fe38709cdf0732aa8b2ec2d52e -- cgit 1.4.1