diff options
Diffstat (limited to 'difference.cpp')
-rw-r--r-- | difference.cpp | 313 |
1 files changed, 152 insertions, 161 deletions
diff --git a/difference.cpp b/difference.cpp index 3d3bb18..c2e3b37 100644 --- a/difference.cpp +++ b/difference.cpp | |||
@@ -1,16 +1,17 @@ | |||
1 | #include <verbly.h> | 1 | #include <verbly.h> |
2 | #include <twitter.h> | 2 | #include <twitter.h> |
3 | #include <curl_easy.h> | 3 | #include <curl_easy.h> |
4 | #include <curl_header.h> | ||
4 | #include <list> | 5 | #include <list> |
5 | #include <set> | 6 | #include <set> |
6 | #include <vector> | 7 | #include <vector> |
7 | #include <algorithm> | 8 | #include <algorithm> |
8 | #include <cstdlib> | ||
9 | #include <ctime> | ||
10 | #include <Magick++.h> | 9 | #include <Magick++.h> |
11 | #include <iostream> | 10 | #include <iostream> |
12 | #include <yaml-cpp/yaml.h> | 11 | #include <yaml-cpp/yaml.h> |
13 | #include <unistd.h> | 12 | #include <chrono> |
13 | #include <thread> | ||
14 | #include <random> | ||
14 | 15 | ||
15 | std::string capitalize(std::string input) | 16 | std::string capitalize(std::string input) |
16 | { | 17 | { |
@@ -65,7 +66,8 @@ bool downloadImage(std::string url, curl::curl_header headers, Magick::Blob& img | |||
65 | return false; | 66 | return false; |
66 | } | 67 | } |
67 | 68 | ||
68 | if (std::string(imghandle.get_info<CURLINFO_CONTENT_TYPE>().get()).substr(0, 6) != "image/") | 69 | std::string content_type = imghandle.get_info<CURLINFO_CONTENT_TYPE>().get(); |
70 | if (content_type.substr(0, 6) != "image/") | ||
69 | { | 71 | { |
70 | return false; | 72 | return false; |
71 | } | 73 | } |
@@ -85,7 +87,6 @@ bool downloadImage(std::string url, curl::curl_header headers, Magick::Blob& img | |||
85 | 87 | ||
86 | int main(int argc, char** argv) | 88 | int main(int argc, char** argv) |
87 | { | 89 | { |
88 | srand(time(NULL)); | ||
89 | Magick::InitializeMagick(nullptr); | 90 | Magick::InitializeMagick(nullptr); |
90 | 91 | ||
91 | int delay = 60 * 60; | 92 | int delay = 60 * 60; |
@@ -99,6 +100,9 @@ int main(int argc, char** argv) | |||
99 | 100 | ||
100 | twitter::client client(auth); | 101 | twitter::client client(auth); |
101 | 102 | ||
103 | std::random_device random_device; | ||
104 | std::mt19937 random_engine{random_device()}; | ||
105 | |||
102 | verbly::data database("data.sqlite3"); | 106 | verbly::data database("data.sqlite3"); |
103 | 107 | ||
104 | auto whitelist = database.nouns(); | 108 | auto whitelist = database.nouns(); |
@@ -149,194 +153,181 @@ int main(int argc, char** argv) | |||
149 | std::cout << "Started!" << std::endl; | 153 | std::cout << "Started!" << std::endl; |
150 | for (;;) | 154 | for (;;) |
151 | { | 155 | { |
152 | std::cout << "Generating noun..." << std::endl; | 156 | try |
153 | verbly::noun pictured = database.nouns().full_hyponym_of(whitefilter).at_least_n_images(2).random().limit(1).run().front(); | 157 | { |
154 | std::cout << "Noun: " << pictured.singular_form() << std::endl; | 158 | std::cout << "Generating noun..." << std::endl; |
155 | std::cout << "Getting URLs..." << std::endl; | 159 | verbly::noun pictured = database.nouns().full_hyponym_of(whitefilter).at_least_n_images(2).random().limit(1).run().front(); |
156 | std::ostringstream lstbuf; | 160 | std::cout << "Noun: " << pictured.singular_form() << std::endl; |
157 | curl::curl_ios<std::ostringstream> lstios(lstbuf); | 161 | std::cout << "Getting URLs..." << std::endl; |
158 | curl::curl_easy lsthandle(lstios); | 162 | std::ostringstream lstbuf; |
159 | std::string lsturl = pictured.imagenet_url(); | 163 | curl::curl_ios<std::ostringstream> lstios(lstbuf); |
160 | lsthandle.add<CURLOPT_URL>(lsturl.c_str()); | 164 | curl::curl_easy lsthandle(lstios); |
161 | try { | 165 | std::string lsturl = pictured.imagenet_url(); |
166 | lsthandle.add<CURLOPT_URL>(lsturl.c_str()); | ||
162 | lsthandle.perform(); | 167 | lsthandle.perform(); |
163 | } catch (curl::curl_easy_exception error) { | ||
164 | error.print_traceback(); | ||
165 | sleep(delay); | ||
166 | |||
167 | continue; | ||
168 | } | ||
169 | 168 | ||
170 | if (lsthandle.get_info<CURLINFO_RESPONSE_CODE>().get() != 200) | 169 | if (lsthandle.get_info<CURLINFO_RESPONSE_CODE>().get() != 200) |
171 | { | 170 | { |
172 | std::cout << "Could not get URLs" << std::endl; | 171 | std::cout << "Could not get URLs" << std::endl; |
173 | continue; | 172 | continue; |
174 | } | 173 | } |
175 | 174 | ||
176 | std::cout << "Got URLs." << std::endl; | 175 | std::cout << "Got URLs." << std::endl; |
177 | std::string lstdata = lstbuf.str(); | 176 | std::string lstdata = lstbuf.str(); |
178 | auto lstlist = verbly::split<std::list<std::string>>(lstdata, "\r\n"); | 177 | auto lstlist = verbly::split<std::list<std::string>>(lstdata, "\r\n"); |
179 | std::set<std::string> lstset; | 178 | std::set<std::string> lstset; |
180 | for (auto url : lstlist) | 179 | for (auto url : lstlist) |
181 | { | 180 | { |
182 | lstset.insert(url); | 181 | lstset.insert(url); |
183 | } | 182 | } |
184 | 183 | ||
185 | if (lstset.size() < 2) | 184 | if (lstset.size() < 2) |
186 | { | 185 | { |
187 | continue; | 186 | continue; |
188 | } | 187 | } |
189 | 188 | ||
190 | std::vector<std::string> lstvec; | 189 | std::vector<std::string> lstvec; |
191 | for (auto url : lstset) | 190 | for (auto url : lstset) |
192 | { | 191 | { |
193 | lstvec.push_back(url); | 192 | lstvec.push_back(url); |
194 | } | 193 | } |
195 | 194 | ||
196 | std::random_shuffle(std::begin(lstvec), std::end(lstvec)); | 195 | std::shuffle(std::begin(lstvec), std::end(lstvec), random_engine); |
197 | 196 | ||
198 | Magick::Blob img1; | 197 | Magick::Blob img1; |
199 | Magick::Image pic1; | 198 | Magick::Image pic1; |
200 | bool success = false; | 199 | bool success = false; |
201 | int curind = 0; | 200 | int curind = 0; |
202 | for (; curind < lstvec.size(); curind++) | 201 | for (; curind < lstvec.size(); curind++) |
203 | { | ||
204 | if (downloadImage(lstvec[curind], headers, img1, pic1)) | ||
205 | { | 202 | { |
206 | success = true; | 203 | if (downloadImage(lstvec[curind], headers, img1, pic1)) |
207 | break; | 204 | { |
205 | success = true; | ||
206 | break; | ||
207 | } | ||
208 | } | 208 | } |
209 | } | ||
210 | 209 | ||
211 | if (!success) | 210 | if (!success) |
212 | { | 211 | { |
213 | continue; | 212 | continue; |
214 | } | 213 | } |
215 | 214 | ||
216 | success = false; | 215 | success = false; |
217 | Magick::Blob img2; | 216 | Magick::Blob img2; |
218 | Magick::Image pic2; | 217 | Magick::Image pic2; |
219 | for (curind++; curind < lstvec.size(); curind++) | 218 | for (curind++; curind < lstvec.size(); curind++) |
220 | { | ||
221 | if (downloadImage(lstvec[curind], headers, img2, pic2)) | ||
222 | { | 219 | { |
223 | success = true; | 220 | if (downloadImage(lstvec[curind], headers, img2, pic2)) |
224 | break; | 221 | { |
222 | success = true; | ||
223 | break; | ||
224 | } | ||
225 | } | 225 | } |
226 | } | ||
227 | 226 | ||
228 | if (!success) | 227 | if (!success) |
229 | { | 228 | { |
230 | continue; | 229 | continue; |
231 | } | 230 | } |
232 | 231 | ||
233 | std::string ant1, ant2; | 232 | std::string ant1, ant2; |
234 | if (rand()%2==0) | 233 | std::uniform_int_distribution<int> coinflip(0, 1); |
235 | { | 234 | if (coinflip(random_engine)==0) |
236 | verbly::noun n1 = database.nouns().has_antonyms().random().limit(1).run().front(); | 235 | { |
237 | verbly::noun n2 = n1.antonyms().random().limit(1).run().front(); | 236 | verbly::noun n1 = database.nouns().has_antonyms().random().limit(1).run().front(); |
238 | ant1 = n1.singular_form(); | 237 | verbly::noun n2 = n1.antonyms().random().limit(1).run().front(); |
239 | ant2 = n2.singular_form(); | 238 | ant1 = n1.singular_form(); |
240 | } else { | 239 | ant2 = n2.singular_form(); |
241 | verbly::adjective a1 = database.adjectives().has_antonyms().random().limit(1).run().front(); | 240 | } else { |
242 | verbly::adjective a2 = a1.antonyms().random().limit(1).run().front(); | 241 | verbly::adjective a1 = database.adjectives().has_antonyms().random().limit(1).run().front(); |
243 | ant1 = a1.base_form(); | 242 | verbly::adjective a2 = a1.antonyms().random().limit(1).run().front(); |
244 | ant2 = a2.base_form(); | 243 | ant1 = a1.base_form(); |
245 | } | 244 | ant2 = a2.base_form(); |
245 | } | ||
246 | 246 | ||
247 | if (pic1.columns() < 320) | 247 | if (pic1.columns() < 320) |
248 | { | 248 | { |
249 | pic1.zoom(Magick::Geometry(320, pic1.rows() * 320 / pic1.columns(), 0, 0)); | 249 | pic1.zoom(Magick::Geometry(320, pic1.rows() * 320 / pic1.columns(), 0, 0)); |
250 | } | 250 | } |
251 | 251 | ||
252 | if (pic2.columns() < 320) | 252 | if (pic2.columns() < 320) |
253 | { | 253 | { |
254 | pic2.zoom(Magick::Geometry(320, pic2.rows() * 320 / pic2.columns(), 0, 0)); | 254 | pic2.zoom(Magick::Geometry(320, pic2.rows() * 320 / pic2.columns(), 0, 0)); |
255 | } | 255 | } |
256 | 256 | ||
257 | int width = std::min(pic1.columns(), pic2.columns()); | 257 | int width = std::min(pic1.columns(), pic2.columns()); |
258 | int height = std::min(pic1.rows(), pic2.rows()); | 258 | int height = std::min(pic1.rows(), pic2.rows()); |
259 | Magick::Geometry geo1(width, height, pic1.columns()/2 - width/2, pic1.rows()/2 - height/2); | 259 | Magick::Geometry geo1(width, height, pic1.columns()/2 - width/2, pic1.rows()/2 - height/2); |
260 | Magick::Geometry geo2(width, height, pic2.columns()/2 - width/2, pic2.rows()/2 - height/2); | 260 | Magick::Geometry geo2(width, height, pic2.columns()/2 - width/2, pic2.rows()/2 - height/2); |
261 | pic1.crop(geo1); | 261 | pic1.crop(geo1); |
262 | pic2.crop(geo2); | 262 | pic2.crop(geo2); |
263 | 263 | ||
264 | Magick::Image composite(Magick::Geometry(width*2, height, 0, 0), "white"); | 264 | Magick::Image composite(Magick::Geometry(width*2, height, 0, 0), "white"); |
265 | composite.draw(Magick::DrawableCompositeImage(0, 0, pic1)); | 265 | composite.draw(Magick::DrawableCompositeImage(0, 0, pic1)); |
266 | composite.draw(Magick::DrawableCompositeImage(width, 0, pic2)); | 266 | composite.draw(Magick::DrawableCompositeImage(width, 0, pic2)); |
267 | composite.font("@coolvetica.ttf"); | 267 | composite.font("@coolvetica.ttf"); |
268 | 268 | ||
269 | double fontsize = 72; | 269 | double fontsize = 72; |
270 | for (;;) | 270 | for (;;) |
271 | { | ||
272 | composite.fontPointsize(fontsize); | ||
273 | |||
274 | Magick::TypeMetric metric; | ||
275 | composite.fontTypeMetrics(ant1, &metric); | ||
276 | if (metric.textWidth() > 300) | ||
277 | { | 271 | { |
278 | fontsize -= 0.5; | 272 | composite.fontPointsize(fontsize); |
279 | continue; | ||
280 | } | ||
281 | 273 | ||
282 | composite.fontTypeMetrics(ant2, &metric); | 274 | Magick::TypeMetric metric; |
283 | if (metric.textWidth() > 300) | 275 | composite.fontTypeMetrics(ant1, &metric); |
284 | { | 276 | if (metric.textWidth() > 300) |
285 | fontsize -= 0.5; | 277 | { |
286 | continue; | 278 | fontsize -= 0.5; |
287 | } | 279 | continue; |
280 | } | ||
288 | 281 | ||
289 | break; | 282 | composite.fontTypeMetrics(ant2, &metric); |
290 | } | 283 | if (metric.textWidth() > 300) |
291 | 284 | { | |
292 | Magick::TypeMetric metric; | 285 | fontsize -= 0.5; |
293 | composite.fontTypeMetrics(ant1, &metric); | 286 | continue; |
294 | int y = rand() % ((int)(composite.rows() - 40 - metric.textHeight())) + 20; | 287 | } |
295 | y = composite.rows() - y; | 288 | |
296 | int x1 = (width - 40 - metric.textWidth())/2+20; | 289 | break; |
297 | composite.fontTypeMetrics(ant2, &metric); | 290 | } |
298 | int x2 = (width - 40 - metric.textWidth())/2+20+width; | ||
299 | composite.strokeColor("white"); | ||
300 | composite.strokeWidth(2); | ||
301 | composite.antiAlias(false); | ||
302 | composite.draw(Magick::DrawableText(x1, y, ant1)); | ||
303 | composite.draw(Magick::DrawableText(x2, y, ant2)); | ||
304 | 291 | ||
305 | composite.magick("png"); | 292 | Magick::TypeMetric metric; |
293 | composite.fontTypeMetrics(ant1, &metric); | ||
294 | std::uniform_int_distribution<int> rowdist(20, (int)(composite.rows() - 19 - metric.textHeight())); | ||
295 | int y = rowdist(random_engine); | ||
296 | y = composite.rows() - y; | ||
297 | int x1 = (width - 40 - metric.textWidth())/2+20; | ||
298 | composite.fontTypeMetrics(ant2, &metric); | ||
299 | int x2 = (width - 40 - metric.textWidth())/2+20+width; | ||
300 | composite.strokeColor("white"); | ||
301 | composite.strokeWidth(2); | ||
302 | composite.antiAlias(false); | ||
303 | composite.draw(Magick::DrawableText(x1, y, ant1)); | ||
304 | composite.draw(Magick::DrawableText(x2, y, ant2)); | ||
306 | 305 | ||
307 | Magick::Blob outputimg; | 306 | composite.magick("png"); |
308 | composite.write(&outputimg); | ||
309 | 307 | ||
310 | std::cout << "Generated image!" << std::endl << "Tweeting..." << std::endl; | 308 | Magick::Blob outputimg; |
309 | composite.write(&outputimg); | ||
311 | 310 | ||
312 | std::stringstream msg; | 311 | std::cout << "Generated image!" << std::endl << "Tweeting..." << std::endl; |
313 | msg << capitalize(ant1); | ||
314 | msg << " vs. "; | ||
315 | msg << capitalize(ant2); | ||
316 | 312 | ||
317 | long media_id; | 313 | std::stringstream msg; |
318 | twitter::response resp = client.uploadMedia("image/png", (const char*) outputimg.data(), outputimg.length(), media_id); | 314 | msg << capitalize(ant1); |
319 | if (resp != twitter::response::ok) | 315 | msg << " vs. "; |
316 | msg << capitalize(ant2); | ||
317 | |||
318 | long media_id = client.uploadMedia("image/png", (const char*) outputimg.data(), outputimg.length()); | ||
319 | client.updateStatus(msg.str(), {media_id}); | ||
320 | |||
321 | std::cout << "Done!" << std::endl << "Waiting..." << std::endl << std::endl; | ||
322 | } catch (const curl::curl_easy_exception& error) | ||
320 | { | 323 | { |
321 | std::cout << "Twitter error while uploading image: " << resp << std::endl; | 324 | error.print_traceback(); |
322 | sleep(delay); | 325 | } catch (const twitter::twitter_error& e) |
323 | |||
324 | continue; | ||
325 | } | ||
326 | |||
327 | twitter::tweet tw; | ||
328 | resp = client.updateStatus(msg.str(), tw, {media_id}); | ||
329 | if (resp != twitter::response::ok) | ||
330 | { | 326 | { |
331 | std::cout << "Twitter error while tweeting: " << resp << std::endl; | 327 | std::cout << "Twitter error: " << e.what() << std::endl; |
332 | sleep(delay); | ||
333 | |||
334 | continue; | ||
335 | } | 328 | } |
336 | 329 | ||
337 | std::cout << "Done!" << std::endl << "Waiting..." << std::endl << std::endl; | 330 | std::this_thread::sleep_for(std::chrono::seconds(delay)); |
338 | |||
339 | sleep(delay); | ||
340 | } | 331 | } |
341 | 332 | ||
342 | return 0; | 333 | return 0; |