diff options
| -rw-r--r-- | ebooks.cpp | 170 | ||||
| m--------- | vendor/libtwittercpp | 0 |
2 files changed, 115 insertions, 55 deletions
| diff --git a/ebooks.cpp b/ebooks.cpp index 8582919..0644132 100644 --- a/ebooks.cpp +++ b/ebooks.cpp | |||
| @@ -12,20 +12,23 @@ | |||
| 12 | #include <chrono> | 12 | #include <chrono> |
| 13 | #include <algorithm> | 13 | #include <algorithm> |
| 14 | 14 | ||
| 15 | const auto QUEUE_TIMEOUT = std::chrono::minutes(1); | ||
| 16 | const auto POLL_TIMEOUT = std::chrono::minutes(5); | ||
| 17 | |||
| 15 | int main(int argc, char** args) | 18 | int main(int argc, char** args) |
| 16 | { | 19 | { |
| 17 | srand(time(NULL)); | 20 | srand(time(NULL)); |
| 18 | rand(); rand(); rand(); rand(); | 21 | rand(); rand(); rand(); rand(); |
| 19 | 22 | ||
| 20 | YAML::Node config = YAML::LoadFile("config.yml"); | 23 | YAML::Node config = YAML::LoadFile("config.yml"); |
| 21 | int delay = config["delay"].as<int>(); | 24 | int delay = config["delay"].as<int>(); |
| 22 | 25 | ||
| 23 | twitter::auth auth; | 26 | twitter::auth auth( |
| 24 | auth.setConsumerKey(config["consumer_key"].as<std::string>()); | 27 | config["consumer_key"].as<std::string>(), |
| 25 | auth.setConsumerSecret(config["consumer_secret"].as<std::string>()); | 28 | config["consumer_secret"].as<std::string>(), |
| 26 | auth.setAccessKey(config["access_key"].as<std::string>()); | 29 | config["access_key"].as<std::string>(), |
| 27 | auth.setAccessSecret(config["access_secret"].as<std::string>()); | 30 | config["access_secret"].as<std::string>()); |
| 28 | 31 | ||
| 29 | twitter::client client(auth); | 32 | twitter::client client(auth); |
| 30 | 33 | ||
| 31 | std::ifstream infile(config["corpus"].as<std::string>().c_str()); | 34 | std::ifstream infile(config["corpus"].as<std::string>().c_str()); |
| @@ -37,10 +40,10 @@ int main(int argc, char** args) | |||
| 37 | { | 40 | { |
| 38 | line.pop_back(); | 41 | line.pop_back(); |
| 39 | } | 42 | } |
| 40 | 43 | ||
| 41 | corpus += line + "\n"; | 44 | corpus += line + "\n"; |
| 42 | } | 45 | } |
| 43 | 46 | ||
| 44 | // Replace old-style freevars while I can't be bothered to remake the corpus yet | 47 | // Replace old-style freevars while I can't be bothered to remake the corpus yet |
| 45 | std::vector<std::string> fv_names; | 48 | std::vector<std::string> fv_names; |
| 46 | std::ifstream namefile("names.txt"); | 49 | std::ifstream namefile("names.txt"); |
| @@ -54,11 +57,11 @@ int main(int argc, char** args) | |||
| 54 | { | 57 | { |
| 55 | l.pop_back(); | 58 | l.pop_back(); |
| 56 | } | 59 | } |
| 57 | 60 | ||
| 58 | fv_names.push_back(l); | 61 | fv_names.push_back(l); |
| 59 | } | 62 | } |
| 60 | } | 63 | } |
| 61 | 64 | ||
| 62 | namefile.close(); | 65 | namefile.close(); |
| 63 | 66 | ||
| 64 | std::cout << "Preprocessing corpus..." << std::endl; | 67 | std::cout << "Preprocessing corpus..." << std::endl; |
| @@ -71,60 +74,114 @@ int main(int argc, char** args) | |||
| 71 | { | 74 | { |
| 72 | form.replace(pos, 6, fv_names[rand() % fv_names.size()]); | 75 | form.replace(pos, 6, fv_names[rand() % fv_names.size()]); |
| 73 | } | 76 | } |
| 74 | 77 | ||
| 75 | return form; | 78 | return form; |
| 76 | }); | 79 | }); |
| 77 | 80 | ||
| 78 | twitter::stream user_stream(client, [&kgramstats, &client] (const twitter::notification& n) { | 81 | std::list<std::tuple<std::string, bool, twitter::tweet_id>> postQueue; |
| 79 | if (n.getType() == twitter::notification::type::tweet) | 82 | |
| 83 | auto startedTime = std::chrono::system_clock::now(); | ||
| 84 | |||
| 85 | auto queueTimer = std::chrono::system_clock::now(); | ||
| 86 | auto pollTimer = std::chrono::system_clock::now(); | ||
| 87 | auto genTimer = std::chrono::system_clock::now(); | ||
| 88 | |||
| 89 | for (;;) | ||
| 90 | { | ||
| 91 | auto currentTime = std::chrono::system_clock::now(); | ||
| 92 | |||
| 93 | if (currentTime >= genTimer) | ||
| 94 | { | ||
| 95 | std::string doc = kgramstats.randomSentence(140); | ||
| 96 | doc.resize(140); | ||
| 97 | |||
| 98 | postQueue.emplace_back(std::move(doc), false, 0); | ||
| 99 | |||
| 100 | int genwait = rand() % delay + 1; | ||
| 101 | |||
| 102 | genTimer = currentTime + std::chrono::seconds(genwait); | ||
| 103 | } | ||
| 104 | |||
| 105 | if (currentTime >= pollTimer) | ||
| 80 | { | 106 | { |
| 81 | if ((!n.getTweet().isRetweet()) && (n.getTweet().getAuthor() != client.getUser())) | 107 | pollTimer = currentTime; |
| 108 | |||
| 109 | try | ||
| 82 | { | 110 | { |
| 83 | std::string original = n.getTweet().getText(); | 111 | std::list<twitter::tweet> newTweets = |
| 84 | std::string canonical; | 112 | client.getMentionsTimeline().poll(); |
| 85 | std::transform(std::begin(original), std::end(original), std::back_inserter(canonical), [] (char ch) { | 113 | |
| 86 | return std::tolower(ch); | 114 | for (const twitter::tweet& tweet : newTweets) |
| 87 | }); | ||
| 88 | |||
| 89 | if (canonical.find("@rawr_ebooks") != std::string::npos) | ||
| 90 | { | 115 | { |
| 91 | std::string doc = n.getTweet().generateReplyPrefill(client.getUser()); | 116 | auto createdTime = |
| 92 | doc += kgramstats.randomSentence(140 - doc.length()); | 117 | std::chrono::system_clock::from_time_t(tweet.getCreatedAt()); |
| 93 | doc.resize(140); | ||
| 94 | 118 | ||
| 95 | try | 119 | if ( |
| 120 | // Ignore tweets from before the bot started up | ||
| 121 | createdTime > startedTime | ||
| 122 | // Ignore retweets | ||
| 123 | && !tweet.isRetweet() | ||
| 124 | // Ignore tweets from yourself | ||
| 125 | && tweet.getAuthor() != client.getUser()) | ||
| 96 | { | 126 | { |
| 97 | client.replyToTweet(doc, n.getTweet()); | 127 | std::string doc = tweet.generateReplyPrefill(client.getUser()); |
| 98 | } catch (const twitter::twitter_error& error) | 128 | doc += kgramstats.randomSentence(140 - doc.length()); |
| 99 | { | 129 | doc.resize(140); |
| 100 | std::cout << "Twitter error while tweeting: " << error.what() << std::endl; | 130 | |
| 131 | postQueue.emplace_back(std::move(doc), true, tweet.getID()); | ||
| 101 | } | 132 | } |
| 102 | } | 133 | } |
| 134 | } catch (const twitter::rate_limit_exceeded&) | ||
| 135 | { | ||
| 136 | // Wait out the rate limit (10 minutes here and 5 below = 15). | ||
| 137 | pollTimer += std::chrono::minutes(10); | ||
| 138 | } catch (const twitter::twitter_error& e) | ||
| 139 | { | ||
| 140 | std::cout << "Twitter error while polling: " << e.what() << std::endl; | ||
| 103 | } | 141 | } |
| 142 | |||
| 143 | pollTimer += std::chrono::minutes(POLL_TIMEOUT); | ||
| 104 | } | 144 | } |
| 105 | }); | ||
| 106 | |||
| 107 | std::this_thread::sleep_for(std::chrono::minutes(1)); | ||
| 108 | 145 | ||
| 109 | std::cout << "Generating..." << std::endl; | 146 | if ((currentTime >= queueTimer) && (!postQueue.empty())) |
| 110 | for (;;) | ||
| 111 | { | ||
| 112 | std::string doc = kgramstats.randomSentence(140); | ||
| 113 | doc.resize(140); | ||
| 114 | |||
| 115 | try | ||
| 116 | { | 147 | { |
| 117 | client.updateStatus(doc); | 148 | auto post = postQueue.front(); |
| 118 | } catch (const twitter::twitter_error& error) | 149 | postQueue.pop_front(); |
| 150 | |||
| 151 | try | ||
| 152 | { | ||
| 153 | if (std::get<1>(post)) | ||
| 154 | { | ||
| 155 | client.replyToTweet(std::get<0>(post), std::get<2>(post)); | ||
| 156 | } else { | ||
| 157 | client.updateStatus(std::get<0>(post)); | ||
| 158 | } | ||
| 159 | } catch (const twitter::twitter_error& error) | ||
| 160 | { | ||
| 161 | std::cout << "Twitter error while tweeting: " << error.what() | ||
| 162 | << std::endl; | ||
| 163 | } | ||
| 164 | |||
| 165 | queueTimer = currentTime + std::chrono::minutes(QUEUE_TIMEOUT); | ||
| 166 | } | ||
| 167 | |||
| 168 | auto soonestTimer = genTimer; | ||
| 169 | |||
| 170 | if (pollTimer < soonestTimer) | ||
| 119 | { | 171 | { |
| 120 | std::cout << "Twitter error while tweeting: " << error.what() << std::endl; | 172 | soonestTimer = pollTimer; |
| 121 | } | 173 | } |
| 122 | 174 | ||
| 123 | int waitlen = rand() % delay; | 175 | if ((queueTimer < soonestTimer) && (!postQueue.empty())) |
| 124 | if (waitlen == 0) | ||
| 125 | { | 176 | { |
| 126 | continue; | 177 | soonestTimer = queueTimer; |
| 127 | } else if (waitlen == 1) | 178 | } |
| 179 | |||
| 180 | int waitlen = | ||
| 181 | std::chrono::duration_cast<std::chrono::seconds>( | ||
| 182 | soonestTimer - currentTime).count(); | ||
| 183 | |||
| 184 | if (waitlen == 1) | ||
| 128 | { | 185 | { |
| 129 | std::cout << "Sleeping for 1 second..." << std::endl; | 186 | std::cout << "Sleeping for 1 second..." << std::endl; |
| 130 | } else if (waitlen < 60) | 187 | } else if (waitlen < 60) |
| @@ -135,22 +192,25 @@ int main(int argc, char** args) | |||
| 135 | std::cout << "Sleeping for 1 minute..." << std::endl; | 192 | std::cout << "Sleeping for 1 minute..." << std::endl; |
| 136 | } else if (waitlen < 60*60) | 193 | } else if (waitlen < 60*60) |
| 137 | { | 194 | { |
| 138 | std::cout << "Sleeping for " << (waitlen/60) << " minutes..." << std::endl; | 195 | std::cout << "Sleeping for " << (waitlen/60) << " minutes..." |
| 196 | << std::endl; | ||
| 139 | } else if (waitlen == 60*60) | 197 | } else if (waitlen == 60*60) |
| 140 | { | 198 | { |
| 141 | std::cout << "Sleeping for 1 hour..." << std::endl; | 199 | std::cout << "Sleeping for 1 hour..." << std::endl; |
| 142 | } else if (waitlen < 60*60*24) | 200 | } else if (waitlen < 60*60*24) |
| 143 | { | 201 | { |
| 144 | std::cout << "Sleeping for " << (waitlen/60/60) << " hours..." << std::endl; | 202 | std::cout << "Sleeping for " << (waitlen/60/60) << " hours..." |
| 203 | << std::endl; | ||
| 145 | } else if (waitlen == 60*60*24) | 204 | } else if (waitlen == 60*60*24) |
| 146 | { | 205 | { |
| 147 | std::cout << "Sleeping for 1 day..." << std::endl; | 206 | std::cout << "Sleeping for 1 day..." << std::endl; |
| 148 | } else { | 207 | } else { |
| 149 | std::cout << "Sleeping for " << (waitlen/60/60/24) << " days..." << std::endl; | 208 | std::cout << "Sleeping for " << (waitlen/60/60/24) << " days..." |
| 209 | << std::endl; | ||
| 150 | } | 210 | } |
| 151 | 211 | ||
| 152 | std::this_thread::sleep_for(std::chrono::seconds(waitlen)); | 212 | std::this_thread::sleep_until(soonestTimer); |
| 153 | } | 213 | } |
| 154 | 214 | ||
| 155 | return 0; | 215 | return 0; |
| 156 | } | 216 | } |
| diff --git a/vendor/libtwittercpp b/vendor/libtwittercpp | |||
| Subproject d1d20515281e32b23657762e72bf37dcff14f0a | Subproject 4963c3dd55b765a33a16a77af432f2bfa12b835 | ||
