|
|
|
@ -9,6 +9,7 @@
@@ -9,6 +9,7 @@
|
|
|
|
|
#include <cstdlib> |
|
|
|
|
#include <exception> |
|
|
|
|
#include <istream> |
|
|
|
|
#include <sstream> |
|
|
|
|
#include <string> |
|
|
|
|
#include <nlohmann/json.hpp> |
|
|
|
|
#include <memory> |
|
|
|
@ -198,6 +199,7 @@ class songdb {
@@ -198,6 +199,7 @@ class songdb {
|
|
|
|
|
for (int i = 0; i < argc; i++) { |
|
|
|
|
values->insert({azColName[i], argv[i]}); |
|
|
|
|
} |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
@ -229,7 +231,9 @@ class songdb {
@@ -229,7 +231,9 @@ class songdb {
|
|
|
|
|
"user INT NOT NULL, " |
|
|
|
|
"rating NOT NULL, " |
|
|
|
|
" FOREIGN KEY (song) REFERENCES tracks (id)," |
|
|
|
|
" FOREIGN KEY (list) REFERENCES songlists (id));"; |
|
|
|
|
" FOREIGN KEY (list) REFERENCES songlists (id)," |
|
|
|
|
" PRIMARY KEY (song, list, user)" |
|
|
|
|
");"; |
|
|
|
|
|
|
|
|
|
std::string create_tracks_table =
|
|
|
|
|
"CREATE TABLE IF NOT EXISTS tracks ("
|
|
|
|
@ -295,11 +299,15 @@ class songdb {
@@ -295,11 +299,15 @@ class songdb {
|
|
|
|
|
check_error(err); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sqlite3_reset(statement); |
|
|
|
|
sqlite3_finalize(statement); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int get_song_list_id(int64_t group_id) { |
|
|
|
|
/* Retrieve or create the song list id for a group.
|
|
|
|
|
* |
|
|
|
|
* As is, song lists are unique to telegram groups |
|
|
|
|
*/ |
|
|
|
|
int64_t get_song_list_id(int64_t group_id) { |
|
|
|
|
spdlog::debug("get_song_list_id {}", group_id); |
|
|
|
|
|
|
|
|
|
std::string list_query = "SELECT * FROM songlists WHERE groupid = ?;"; |
|
|
|
@ -308,6 +316,7 @@ class songdb {
@@ -308,6 +316,7 @@ class songdb {
|
|
|
|
|
*/ |
|
|
|
|
int err; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sqlite3_stmt *statement; |
|
|
|
|
sqlite3_prepare_v2(db, list_query.c_str(), list_query.length(), &statement, NULL); |
|
|
|
|
err = sqlite3_bind_int64(statement, 1, group_id); |
|
|
|
@ -330,40 +339,85 @@ class songdb {
@@ -330,40 +339,85 @@ class songdb {
|
|
|
|
|
|
|
|
|
|
} else if (err == SQLITE_DONE) { |
|
|
|
|
// create the list
|
|
|
|
|
sqlite3_reset(statement); |
|
|
|
|
sqlite3_finalize(statement); |
|
|
|
|
create_new_list(group_id); |
|
|
|
|
|
|
|
|
|
sqlite3_prepare_v2(db, list_query.c_str(), list_query.length(), &statement, NULL); |
|
|
|
|
err = sqlite3_bind_int64(statement, 0, group_id); |
|
|
|
|
err = sqlite3_prepare_v2(db, list_query.c_str(), list_query.length(), &statement, NULL); |
|
|
|
|
check_error(err); |
|
|
|
|
err = sqlite3_bind_int64(statement, 1, group_id); |
|
|
|
|
check_error(err); |
|
|
|
|
|
|
|
|
|
err = sqlite3_step(statement); |
|
|
|
|
|
|
|
|
|
if (err == SQLITE_ROW){ |
|
|
|
|
list_id = sqlite3_column_int64(statement, 0); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
else if (err != SQLITE_DONE) { |
|
|
|
|
|
|
|
|
|
check_error(err); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
check_error(err); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return list_id; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool insert_song(std::string name, std::string artist, std::optional<std::string> spotify_id) { |
|
|
|
|
struct track_entry { |
|
|
|
|
int64_t id; |
|
|
|
|
std::string name; |
|
|
|
|
std::string artist; |
|
|
|
|
std::optional<std::string> spotify_id; |
|
|
|
|
|
|
|
|
|
spdlog::debug("insert_song"); |
|
|
|
|
std::string check_exist_spot = "SELECT * FROM tracks WHERE spotifyid = ?;"; |
|
|
|
|
std::string check_exist_nospot = "SELECT * FROM tracks WHERE name = ? AND artist = ?;"; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
std::string ins_query_spot = "INSERT INTO tracks (name, artist, spotifyid) VALUES(?, ?, ?);"; |
|
|
|
|
std::string ins_query_nospot = "INSERT INTO tracks (name, artist) VALUES(?, ?);"; |
|
|
|
|
|
|
|
|
|
// int list_id = get_song_list_id(group_id);
|
|
|
|
|
std::optional<track_entry> get_song(int64_t id) { |
|
|
|
|
std::string check_exist = "SELECT * FROM tracks WHERE id = ?;"; |
|
|
|
|
|
|
|
|
|
int err; |
|
|
|
|
sqlite3_stmt *statement; |
|
|
|
|
err = sqlite3_prepare_v2(db, check_exist.c_str(), check_exist.length(), &statement, NULL); |
|
|
|
|
check_error(err); |
|
|
|
|
err = sqlite3_bind_int64(statement, 1, id); |
|
|
|
|
check_error(err); |
|
|
|
|
|
|
|
|
|
err = sqlite3_step(statement); |
|
|
|
|
if (err == SQLITE_ROW) { |
|
|
|
|
|
|
|
|
|
int64_t id = sqlite3_column_int64(statement, 0); |
|
|
|
|
std::string name {(char *)sqlite3_column_text(statement, 1)}; |
|
|
|
|
std::string artist {(char *)sqlite3_column_text(statement, 2)}; |
|
|
|
|
char * spotid = (char *)sqlite3_column_text(statement, 3); |
|
|
|
|
|
|
|
|
|
if (spotid) { |
|
|
|
|
track_entry e {id, name, artist, std::string(spotid)}; |
|
|
|
|
sqlite3_finalize(statement); |
|
|
|
|
return e; |
|
|
|
|
} |
|
|
|
|
track_entry e {id, name, artist}; |
|
|
|
|
sqlite3_finalize(statement); |
|
|
|
|
return e; |
|
|
|
|
} |
|
|
|
|
sqlite3_finalize(statement); |
|
|
|
|
return {}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::optional<track_entry> get_song(std::string name, std::string artist) { |
|
|
|
|
return get_song(name, artist, {}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::optional<track_entry> get_song(std::string name, std::string artist, std::optional<std::string> spotify_id) { |
|
|
|
|
|
|
|
|
|
spdlog::debug("get_song"); |
|
|
|
|
|
|
|
|
|
std::string check_exist_spot = "SELECT * FROM tracks WHERE spotifyid = ?;"; |
|
|
|
|
std::string check_exist_nospot = "SELECT * FROM tracks WHERE name = ? AND artist = ?;"; |
|
|
|
|
|
|
|
|
|
int err; |
|
|
|
|
sqlite3_stmt *statement; |
|
|
|
|
|
|
|
|
|
/* check whether the song exists */ |
|
|
|
|
if (spotify_id) { |
|
|
|
@ -383,16 +437,49 @@ class songdb {
@@ -383,16 +437,49 @@ class songdb {
|
|
|
|
|
check_error(err); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
err = sqlite3_step(statement); |
|
|
|
|
if (err == SQLITE_ROW) { |
|
|
|
|
|
|
|
|
|
int64_t id = sqlite3_column_int64(statement, 0); |
|
|
|
|
std::string name {(char *)sqlite3_column_text(statement, 1)}; |
|
|
|
|
std::string artist {(char *)sqlite3_column_text(statement, 2)}; |
|
|
|
|
char * spotid = (char *)sqlite3_column_text(statement, 3); |
|
|
|
|
|
|
|
|
|
if (spotid) { |
|
|
|
|
track_entry e {id, name, artist, std::string(spotid)}; |
|
|
|
|
sqlite3_finalize(statement); |
|
|
|
|
return e; |
|
|
|
|
} |
|
|
|
|
track_entry e {id, name, artist}; |
|
|
|
|
sqlite3_finalize(statement); |
|
|
|
|
return e; |
|
|
|
|
spdlog::info("Entry exists."); |
|
|
|
|
return true; |
|
|
|
|
} else if (err != SQLITE_DONE) { |
|
|
|
|
check_error(err); |
|
|
|
|
return true; |
|
|
|
|
sqlite3_finalize(statement); |
|
|
|
|
return {}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sqlite3_finalize(statement); |
|
|
|
|
return {}; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::optional<track_entry> insert_song(std::string name, std::string artist, std::optional<std::string> spotify_id) { |
|
|
|
|
|
|
|
|
|
spdlog::debug("insert_song"); |
|
|
|
|
|
|
|
|
|
std::string ins_query_spot = "INSERT INTO tracks (name, artist, spotifyid) VALUES(?, ?, ?);"; |
|
|
|
|
std::string ins_query_nospot = "INSERT INTO tracks (name, artist) VALUES(?, ?);"; |
|
|
|
|
|
|
|
|
|
// int list_id = get_song_list_id(group_id);
|
|
|
|
|
sqlite3_stmt *statement; |
|
|
|
|
int err; |
|
|
|
|
|
|
|
|
|
auto e = get_song(name, artist, spotify_id); |
|
|
|
|
if (e) { |
|
|
|
|
return e; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (spotify_id) { |
|
|
|
|
err = sqlite3_prepare_v2(db, ins_query_spot.c_str(), ins_query_spot.length(), &statement, NULL); |
|
|
|
@ -413,12 +500,57 @@ class songdb {
@@ -413,12 +500,57 @@ class songdb {
|
|
|
|
|
|
|
|
|
|
err = sqlite3_step(statement); |
|
|
|
|
if (err != SQLITE_DONE) { |
|
|
|
|
sqlite3_reset(statement); |
|
|
|
|
sqlite3_finalize(statement); |
|
|
|
|
spdlog::warn("Failed insertion Sqlite: {}", sqlite3_errstr(err)); |
|
|
|
|
spdlog::dump_backtrace(); |
|
|
|
|
sqlite3_finalize(statement); |
|
|
|
|
return {}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sqlite3_finalize(statement); |
|
|
|
|
return get_song(name, artist, spotify_id); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
insert_vote(int64_t user, int64_t group, int value, int64_t songid)
|
|
|
|
|
{ |
|
|
|
|
spdlog::debug("insert_vote"); |
|
|
|
|
auto song = get_song(songid); |
|
|
|
|
if (!song) { |
|
|
|
|
spdlog::error("Failed to add vote, couldnt find song id: {}", songid); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int64_t list = get_song_list_id(group); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* find existing vote */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string ins_query = "INSERT OR REPLACE INTO votes (song, list, user, rating) " |
|
|
|
|
"VALUES (?, ?, ?, ?);"; |
|
|
|
|
|
|
|
|
|
sqlite3_stmt *statement; |
|
|
|
|
int err; |
|
|
|
|
err = sqlite3_prepare_v2(db, ins_query.c_str(), ins_query.length(), &statement, NULL); |
|
|
|
|
check_error(err); |
|
|
|
|
err = sqlite3_bind_int64(statement, 1, song->id); |
|
|
|
|
check_error(err); |
|
|
|
|
err = sqlite3_bind_int64(statement, 2, list); |
|
|
|
|
check_error(err); |
|
|
|
|
err = sqlite3_bind_int64(statement, 3, user); |
|
|
|
|
check_error(err); |
|
|
|
|
err= sqlite3_bind_int64(statement, 4, value); |
|
|
|
|
check_error(err); |
|
|
|
|
|
|
|
|
|
err = sqlite3_step(statement); |
|
|
|
|
if (err != SQLITE_DONE) { |
|
|
|
|
check_error(err); |
|
|
|
|
sqlite3_finalize(statement); |
|
|
|
|
return true; |
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sqlite3_finalize(statement); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -488,8 +620,6 @@ int main() {
@@ -488,8 +620,6 @@ int main() {
|
|
|
|
|
|
|
|
|
|
Bot bot(teletoken); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
InlineKeyboardMarkup::Ptr keyboard(new InlineKeyboardMarkup); |
|
|
|
|
std::vector<InlineKeyboardButton::Ptr> row0; |
|
|
|
|
|
|
|
|
@ -518,14 +648,42 @@ int main() {
@@ -518,14 +648,42 @@ int main() {
|
|
|
|
|
button5->callbackData= "5"; |
|
|
|
|
row0.push_back(button5); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
keyboard->inlineKeyboard.push_back(row0); |
|
|
|
|
|
|
|
|
|
bot.getEvents().onCallbackQuery([&bot, &keyboard, &data](CallbackQuery::Ptr query) { |
|
|
|
|
|
|
|
|
|
spdlog::info("Query: {}, mesg {}", query->data, query->message->text); |
|
|
|
|
|
|
|
|
|
if ((query->data == "1") || (query->data == "2") || (query->data == "3") || (query->data == "4") || (query->data == "5")) { |
|
|
|
|
|
|
|
|
|
std::istringstream is {query->data}; |
|
|
|
|
int value; |
|
|
|
|
is >> value; |
|
|
|
|
|
|
|
|
|
std::string songidflag = "songid:"; |
|
|
|
|
auto a = query->message->text.find(songidflag); |
|
|
|
|
auto b = query->message->text.find("\n", a); |
|
|
|
|
|
|
|
|
|
if (a==std::string::npos || b==std::string::npos) { |
|
|
|
|
spdlog::error("Parse songid"); |
|
|
|
|
spdlog::dump_backtrace(); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
a += songidflag.length(); |
|
|
|
|
|
|
|
|
|
std::istringstream is2 {query->message->text.substr(a, b - a)}; |
|
|
|
|
int64_t songid; |
|
|
|
|
is2 >> songid; |
|
|
|
|
auto song = data.get_song(songid); |
|
|
|
|
if (!song) { |
|
|
|
|
spdlog::error ("bad song id"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
spdlog::info("Adding vote for {}: {}",song->name, value); |
|
|
|
|
|
|
|
|
|
data.insert_vote(query->from->id, query->message->chat->id, value, songid); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bot.getEvents().onCallbackQuery([&bot, &keyboard](CallbackQuery::Ptr query) { |
|
|
|
|
if (StringTools::startsWith(query->data, "check")) { |
|
|
|
|
std::string response = "ok"; |
|
|
|
|
bot.getApi().sendMessage(query->message->chat->id, response, false, 0, keyboard, "Markdown"); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
@ -551,14 +709,21 @@ int main() {
@@ -551,14 +709,21 @@ int main() {
|
|
|
|
|
std::string title = track_data["name"]; |
|
|
|
|
std::string artist = track_data["artists"][0]["name"]; |
|
|
|
|
|
|
|
|
|
auto song = data.insert_song(title, artist, *resp); |
|
|
|
|
|
|
|
|
|
std::string response = "Added song: " + title + ", by " + artist; |
|
|
|
|
response += "\n\r\n\r"; |
|
|
|
|
std::ostringstream os; |
|
|
|
|
os << song->id; |
|
|
|
|
response += "\n\rsongid:" + os.str() + "\n\r\n\r"; |
|
|
|
|
response += "Everyone, please rate how well you know this song /5"; |
|
|
|
|
|
|
|
|
|
data.insert_song(title, artist, {}); |
|
|
|
|
bot.getApi().sendMessage(message->chat->id, response, false, 0, keyboard, "Markdown"); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
bot.getEvents().onCommand("vote", [&bot](Message::Ptr message) { |
|
|
|
|
bot.getApi().sendMessage(message->chat->id, "Hi!"); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bot.getEvents().onCommand("start", [&bot](Message::Ptr message) { |
|
|
|
|
bot.getApi().sendMessage(message->chat->id, "Hi!"); |
|
|
|
|