From 5918c6e39911ebe3f10949c648850f7d6d30b196 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sun, 12 Jun 2016 10:29:42 -0400 Subject: Initial commit --- .gitmodules | 6 ++ CMakeLists.txt | 11 ++++ toldya.cpp | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/libtwittercpp | 1 + vendor/yaml-cpp | 1 + 5 files changed, 200 insertions(+) create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 100644 toldya.cpp create mode 160000 vendor/libtwittercpp create mode 160000 vendor/yaml-cpp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8544219 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "vendor/libtwittercpp"] + path = vendor/libtwittercpp + url = https://github.com/hatkirby/libtwittercpp +[submodule "vendor/yaml-cpp"] + path = vendor/yaml-cpp + url = https://github.com/jbeder/yaml-cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..df9ccfe --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required (VERSION 3.1) +project (toldya) + +add_subdirectory(vendor/libtwittercpp) +add_subdirectory(vendor/yaml-cpp EXCLUDE_FROM_ALL) + +include_directories(vendor/libtwittercpp/src vendor/yaml-cpp/include) +add_executable(toldya toldya.cpp) +set_property(TARGET toldya PROPERTY CXX_STANDARD 11) +set_property(TARGET toldya PROPERTY CXX_STANDARD_REQUIRED ON) +target_link_libraries(toldya yaml-cpp twitter++) diff --git a/toldya.cpp b/toldya.cpp new file mode 100644 index 0000000..96d5f35 --- /dev/null +++ b/toldya.cpp @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + YAML::Node config = YAML::LoadFile("config.yml"); + + twitter::auth auth; + auth.setConsumerKey(config["consumer_key"].as()); + auth.setConsumerSecret(config["consumer_secret"].as()); + auth.setAccessKey(config["access_key"].as()); + auth.setAccessSecret(config["access_secret"].as()); + + std::vector captions { + "It begins.", + "Yikes.", + "Frightening.", + "This is how it starts..." + }; + + std::vector potential; + std::mutex potential_mutex; + + twitter::client client(auth); + std::set streamed_friends; + client.setUserStreamNotifyCallback([&] (twitter::notification n) { + if (n.getType() == twitter::notification::type::friends) + { + streamed_friends = n.getFriends(); + } else if (n.getType() == twitter::notification::type::follow) + { + streamed_friends.insert(n.getUser().getID()); + } else if (n.getType() == twitter::notification::type::unfollow) + { + streamed_friends.erase(n.getUser().getID()); + } else if (n.getType() == twitter::notification::type::tweet) + { + if ( + (streamed_friends.count(n.getTweet().getAuthor().getID()) == 1) // Only monitor people you are following + && (!n.getTweet().isRetweet()) // Ignore retweets + && (n.getTweet().getText().front() != '@') // Ignore messages + ) + { + std::lock_guard potential_guard(potential_mutex); + std::cout << n.getTweet().getText() << std::endl; + + potential.push_back(n.getTweet()); + } + } else if (n.getType() == twitter::notification::type::followed) + { + twitter::response resp = client.follow(n.getUser()); + if (resp != twitter::response::ok) + { + std::cout << "Twitter error while following @" << n.getUser().getScreenName() << ": " << resp << std::endl; + } + } + }); + + std::this_thread::sleep_for(std::chrono::minutes(1)); + + std::cout << "Starting streaming" << std::endl; + client.startUserStream(); + + for (;;) + { + // Wait until 9am + auto midtime = time(NULL); + auto midtm = localtime(&midtime); + midtm->tm_hour = 0; + midtm->tm_min = 0; + midtm->tm_sec = 0; + auto to_until = std::chrono::system_clock::from_time_t(std::mktime(midtm)); + auto to_wait = std::chrono::duration_cast((to_until + std::chrono::hours(24 + 9)) - std::chrono::system_clock::now()); + int waitlen = to_wait.count(); + if (waitlen == 0) + { + continue; + } else if (waitlen == 1) + { + std::cout << "Sleeping for 1 second..." << std::endl; + } else if (waitlen < 60) + { + std::cout << "Sleeping for " << waitlen << " seconds..." << std::endl; + } else if (waitlen == 60) + { + std::cout << "Sleeping for 1 minute..." << std::endl; + } else if (waitlen < 60*60) + { + std::cout << "Sleeping for " << (waitlen/60) << " minutes..." << std::endl; + } else if (waitlen == 60*60) + { + std::cout << "Sleeping for 1 hour..." << std::endl; + } else if (waitlen < 60*60*24) + { + std::cout << "Sleeping for " << (waitlen/60/60) << " hours..." << std::endl; + } else if (waitlen == 60*60*24) + { + std::cout << "Sleeping for 1 day..." << std::endl; + } else { + std::cout << "Sleeping for " << (waitlen/60/60/24) << " days..." << std::endl; + } + + std::this_thread::sleep_for(to_wait); + + // Unfollow people who have unfollowed us + std::set friends; + std::set followers; + twitter::response resp = client.getFriends(friends); + if (resp == twitter::response::ok) + { + resp = client.getFollowers(followers); + if (resp == twitter::response::ok) + { + std::list old_friends, new_followers; + std::set_difference(std::begin(friends), std::end(friends), std::begin(followers), std::end(followers), std::back_inserter(old_friends)); + std::set_difference(std::begin(followers), std::end(followers), std::begin(friends), std::end(friends), std::back_inserter(new_followers)); + + std::set old_friends_set; + for (auto f : old_friends) + { + old_friends_set.insert(f); + + resp = client.unfollow(f); + if (resp != twitter::response::ok) + { + std::cout << "Twitter error while unfollowing" << std::endl; + } + } + + for (auto f : new_followers) + { + resp = client.follow(f); + if (resp != twitter::response::ok) + { + std::cout << "Twitter error while following" << std::endl; + } + } + + std::lock_guard potential_guard(potential_mutex); + std::vector to_keep; + for (auto pt : potential) + { + if (old_friends_set.count(pt.getAuthor()) == 0) + { + to_keep.push_back(pt); + } + } + + potential = to_keep; + } else { + std::cout << "Twitter error while getting followers: " << resp << std::endl; + } + } else { + std::cout << "Twitter error while getting friends: " << resp << std::endl; + } + + // Tweet! + if (!potential.empty()) + { + auto to_quote = potential[rand() % potential.size()]; + potential.clear(); + + std::string caption = captions[rand() % captions.size()]; + std::string doc = caption + " " + to_quote.getURL(); + + twitter::tweet sent; + twitter::response resp = client.updateStatus(doc, sent); + if (resp != twitter::response::ok) + { + std::cout << "Error tweeting: " << resp << std::endl; + } + } + } + + client.stopUserStream(); +} diff --git a/vendor/libtwittercpp b/vendor/libtwittercpp new file mode 160000 index 0000000..c3cc763 --- /dev/null +++ b/vendor/libtwittercpp @@ -0,0 +1 @@ +Subproject commit c3cc76301d64320791f7097709ffcd36d7206266 diff --git a/vendor/yaml-cpp b/vendor/yaml-cpp new file mode 160000 index 0000000..728e26e --- /dev/null +++ b/vendor/yaml-cpp @@ -0,0 +1 @@ +Subproject commit 728e26e42645d4d70ca65522990f915f47b47a50 -- cgit 1.4.1