about summary refs log tree commit diff stats
path: root/database.cpp
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2018-03-01 16:03:16 -0500
committerKelly Rauchenberger <fefferburbia@gmail.com>2018-03-01 16:03:16 -0500
commit473b327ceed3afb5e5683002b39fd9c1947cb25a (patch)
tree0dd2eac68605ad8cf34a2e2e54c6a44ad3ab14c1 /database.cpp
parentd85fed8541a9580e820a907d83a2184b020572ba (diff)
downloadlunatic-473b327ceed3afb5e5683002b39fd9c1947cb25a.tar.gz
lunatic-473b327ceed3afb5e5683002b39fd9c1947cb25a.tar.bz2
lunatic-473b327ceed3afb5e5683002b39fd9c1947cb25a.zip
Redesigned persistent data formta
This is the start of a project to add imagery to the bot's output. We began by rewriting the scraper to use a SQLite datafile instead of dumping achievement names to a text file. This allows storage of additional information about each achievement, and allows for more sophisticated scraping.

Profiles to be scraped can be added on the command line using the scraper script, instead of being specified in a config file. The scraper can conduct full or delta scrapes; in a delta scrape, only each profile's recent games are scraped, whereas they are all scraped in a full scrape.

When a game is scraped for the first time, images from the store page of that game are saved locally to be used by the bot. The bot has been altered to not use Twitter, and instead generate a pixelated image based on an image from the game of the chosen achievement. This is just for development purposes. It also crashes occasionally due to picking an achievement from a game that does not have any images saved.

Sprites of the moons from Odyssey have been included in the repository. A short message denoting their copyright is included.
Diffstat (limited to 'database.cpp')
-rw-r--r--database.cpp122
1 files changed, 122 insertions, 0 deletions
diff --git a/database.cpp b/database.cpp new file mode 100644 index 0000000..f8b5016 --- /dev/null +++ b/database.cpp
@@ -0,0 +1,122 @@
1#include "database.h"
2#include <sqlite3.h>
3#include <stdexcept>
4
5database::database(std::string path)
6{
7 if (sqlite3_open_v2(
8 path.c_str(),
9 &ppdb_,
10 SQLITE_OPEN_READONLY,
11 NULL) != SQLITE_OK)
12 {
13 // We still have to free the resources allocated. In the event that
14 // allocation failed, ppdb will be null and sqlite3_close_v2 will just
15 // ignore it.
16 std::string errmsg(sqlite3_errmsg(ppdb_));
17 sqlite3_close_v2(ppdb_);
18
19 throw std::logic_error(errmsg);
20 }
21}
22
23database::database(database&& other) : database()
24{
25 swap(*this, other);
26}
27
28database& database::operator=(database&& other)
29{
30 swap(*this, other);
31
32 return *this;
33}
34
35void swap(database& first, database& second)
36{
37 std::swap(first.ppdb_, second.ppdb_);
38}
39
40database::~database()
41{
42 sqlite3_close_v2(ppdb_);
43}
44
45achievement database::getRandomAchievement() const
46{
47 std::string queryString = "SELECT achievements.achievement_id, achievements.game_id, achievements.title, games.moon_image FROM achievements INNER JOIN games ON games.game_id = achievements.game_id ORDER BY RANDOM() LIMIT 1";
48
49 sqlite3_stmt* ppstmt;
50 if (sqlite3_prepare_v2(
51 ppdb_,
52 queryString.c_str(),
53 queryString.length(),
54 &ppstmt,
55 NULL) != SQLITE_OK)
56 {
57 std::string errorMsg = sqlite3_errmsg(ppdb_);
58 sqlite3_finalize(ppstmt);
59
60 throw std::logic_error(errorMsg);
61 }
62
63 if (sqlite3_step(ppstmt) != SQLITE_ROW)
64 {
65 std::string errorMsg = sqlite3_errmsg(ppdb_);
66 sqlite3_finalize(ppstmt);
67
68 throw std::logic_error(errorMsg);
69 }
70
71 achievement result;
72
73 result.achievementId = sqlite3_column_int(ppstmt, 0);
74 result.gameId = sqlite3_column_int(ppstmt, 1);
75 result.title = reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2));
76 result.moonImage = reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 3));
77
78 sqlite3_finalize(ppstmt);
79
80 return result;
81}
82
83std::string database::getRandomImageForGame(int gameId) const
84{
85 std::string queryString = "SELECT filename FROM images WHERE game_id = ? ORDER BY RANDOM() LIMIT 1";
86
87 sqlite3_stmt* ppstmt;
88 if (sqlite3_prepare_v2(
89 ppdb_,
90 queryString.c_str(),
91 queryString.length(),
92 &ppstmt,
93 NULL) != SQLITE_OK)
94 {
95 std::string errorMsg = sqlite3_errmsg(ppdb_);
96 sqlite3_finalize(ppstmt);
97
98 throw std::logic_error(errorMsg);
99 }
100
101 if (sqlite3_bind_int(ppstmt, 1, gameId) != SQLITE_OK)
102 {
103 std::string errorMsg = sqlite3_errmsg(ppdb_);
104 sqlite3_finalize(ppstmt);
105
106 throw std::logic_error(errorMsg);
107 }
108
109 if (sqlite3_step(ppstmt) != SQLITE_ROW)
110 {
111 std::string errorMsg = sqlite3_errmsg(ppdb_);
112 sqlite3_finalize(ppstmt);
113
114 throw std::logic_error(errorMsg);
115 }
116
117 std::string result = reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 0));
118
119 sqlite3_finalize(ppstmt);
120
121 return result;
122}