Browse Source

queue generation boilerplate

master
alistair 3 years ago
parent
commit
d06f609346
  1. 238
      telegram_bot.cpp

238
telegram_bot.cpp

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
#include "cpr/parameters.h"
#include "tgbot/net/BoostHttpOnlySslClient.h"
#include "tgbot/net/HttpParser.h"
#include <bits/c++config.h>
#include <bits/stdint-intn.h>
#include <bits/stdint-uintn.h>
#include <csignal>
@ -15,6 +16,7 @@ @@ -15,6 +16,7 @@
#include <memory>
#include "Base64.hpp"
#include <tuple>
#include <sys/types.h>
#include <tgbot/tgbot.h>
#include <cpr/cpr.h>
@ -22,6 +24,7 @@ @@ -22,6 +24,7 @@
#include <sqlite3.h>
#include <cstdlib>
#include <map>
#include <set>
#include <spdlog/spdlog.h>
using namespace TgBot;
@ -181,11 +184,19 @@ class spotify { @@ -181,11 +184,19 @@ class spotify {
class songdb {
/* need one table for every chat: keep it all in memory? */
std::string filepath;
sqlite3 *db;
public:
struct runtime_vals {
};
runtime_vals runtime_data;
protected:
enum error_codes {
NOT_FOUND,
ALREADY_ADDED
@ -373,7 +384,6 @@ class songdb { @@ -373,7 +384,6 @@ class songdb {
};
std::optional<track_entry> get_song(int64_t id) {
std::string check_exist = "SELECT * FROM tracks WHERE id = ?;";
@ -554,6 +564,136 @@ class songdb { @@ -554,6 +564,136 @@ class songdb {
return false;
}
struct vote {
int song;
int list;
int64_t user;
double value;
};
std::vector<vote>
get_votes_list(int64_t song_list)
{
std::string query = "SELECT * FROM votes WHERE list = ?";
sqlite3_stmt *statement;
int err;
err = sqlite3_prepare_v2(db, query.c_str(), query.length(), &statement, NULL);
check_error(err);
err = sqlite3_bind_int64(statement, 1, song_list);
check_error(err);
std::vector<vote> votes;
err = sqlite3_step(statement);
while (err == SQLITE_ROW) {
int song = sqlite3_column_int(statement, 0);
int list = sqlite3_column_int(statement, 1);
int user = sqlite3_column_int(statement, 2);
int value= sqlite3_column_int(statement, 3);
votes.push_back({song, list,user,value});
err = sqlite3_step(statement);
}
if (err != SQLITE_DONE) {
check_error(err);
}
sqlite3_finalize(statement);
return votes;
};
struct base_weight_vector {
std::vector<int64_t> person_order;
std::vector<size_t> song_order;
std::vector<std::vector<double>> weights;
};
//std::map<int, std::map<int64_t, double>>
base_weight_vector
get_base_weights (int64_t song_list)
{
std::vector<vote> list = get_votes_list(song_list);
std::set<int64_t> chat_members;
// {song, {user, vote}}
std::map<int, std::map<int64_t, double>> vote_info {};
for (auto v : list) {
chat_members.insert(v.user);
vote_info[v.song] = {{v.user, v.value}};
}
for (auto v : vote_info) {
// Insert zero values for members who have not voted
for (auto m : chat_members) {
if (!v.second.count(m)) {
v.second.insert({m, 0.0});
}
}
// normalise weightings
double total = 0;
for (auto m : v.second) {
total += m.second;
}
for (auto m : v.second) {
v.second[m.first] = m.second / total;
}
}
if (vote_info.size() == 0) {
return {};
}
/* turn it into a nice easy to use vector
* Relying on the fact maps are sorted and things will always be in the
* same order.
*/
base_weight_vector v;
for (auto song : vote_info) {
v.song_order.push_back(song.first);
}
auto a = vote_info.begin();
for (auto user : a->second) {
v.person_order.push_back(user.first);
}
for (auto song: vote_info) {
std::vector<double> user_votes;
for (auto user : song.second) {
user_votes.push_back(user.second);
}
assert(user_votes.size() == v.person_order.size());
v.weights.push_back(user_votes);
}
return v;
}
std::vector<track_entry>
generate_track_list(int64_t song_list)
{
auto base_weights = get_base_weights(song_list);
for (int i = 0; i < base_weights.song_order.size(); i++) {
spdlog::info("song {} nppl {}", base_weights.song_order[i], base_weights.weights.size());
}
std::vector<track_entry> retlist;
return retlist;
}
songdb (std::string filepath): filepath(filepath) {
int err = sqlite3_open(filepath.c_str(), &db);
if (err) {
@ -568,12 +708,6 @@ class songdb { @@ -568,12 +708,6 @@ class songdb {
sqlite3_close(db);
}
bool add_song(std::string spotify_track_id) {
// request spotify api for info
// yeet into db
return true;
};
};
};
@ -620,9 +754,16 @@ int main() { @@ -620,9 +754,16 @@ int main() {
Bot bot(teletoken);
InlineKeyboardMarkup::Ptr keyboard(new InlineKeyboardMarkup);
std::vector<InlineKeyboardButton::Ptr> row0;
InlineKeyboardButton::Ptr button5(new InlineKeyboardButton);
button5->text = "0";
button5->callbackData= "0";
row0.push_back(button5);
InlineKeyboardButton::Ptr button1(new InlineKeyboardButton);
button1->text = "1";
button1->callbackData = "1";
@ -643,18 +784,12 @@ int main() { @@ -643,18 +784,12 @@ int main() {
button4->callbackData = "4";
row0.push_back(button4);
InlineKeyboardButton::Ptr button5(new InlineKeyboardButton);
button5->text = "5";
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")) {
if ((query->data == "1") || (query->data == "2") || (query->data == "3") || (query->data == "4") || (query->data == "0")) {
std::istringstream is {query->data};
int value;
@ -679,7 +814,6 @@ int main() { @@ -679,7 +814,6 @@ int main() {
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);
@ -689,32 +823,49 @@ int main() { @@ -689,32 +823,49 @@ int main() {
bot.getEvents().onCommand("add", [&bot, &keyboard, &data, s](Message::Ptr message) {
std::string link = util::trim_whitespace(message->text.substr(message->text.find("add")));
auto resp = s->track_id_from_link(link);
if (!resp) {
bot.getApi().sendMessage(message->chat->id, "Sorry, I don't understand that link.");
return;
std::string title;
std::string artist;
int songid;
if (message->text.find("spotify.com") != std::string::npos) {
std::string link = util::trim_whitespace(message->text.substr(message->text.find("add") + 3));
auto resp = s->track_id_from_link(link);
if (!resp) {
bot.getApi().sendMessage(message->chat->id, "Sorry, I don't understand that link.");
return;
}
auto spot_resp = s->get_track(*resp);
if (!spot_resp) {
bot.getApi().sendMessage(message->chat->id, "Sorry, I cannot find that track in spotify.");
return;
}
json track_data = *spot_resp;
title = track_data["name"];
artist = track_data["artists"][0]["name"];
auto song = data.insert_song(title, artist, *resp);
songid = song->id;
} else {
title = util::trim_whitespace(message->text.substr(message->text.find("add") + 3));
artist = "";
auto song = data.insert_song(title, artist, {});
songid = song->id;
}
auto spot_resp = s->get_track(*resp);
std::string response = "Added song: " + title;
if (!spot_resp) {
bot.getApi().sendMessage(message->chat->id, "Sorry, I cannot find that track in spotify.");
return;
}
if (artist != "")
response += ", by " + artist;
json track_data = *spot_resp;
std::cout << spot_resp->dump(4);
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\n";
std::ostringstream os;
os << song->id;
response += "\n\rsongid:" + os.str() + "\n\r\n\r";
os << songid;
response += "songid:" + os.str() + "\n\r\n\r";
response += "Everyone, please rate how well you know this song /5";
bot.getApi().sendMessage(message->chat->id, response, false, 0, keyboard, "Markdown");
@ -725,15 +876,24 @@ int main() { @@ -725,15 +876,24 @@ int main() {
});
bot.getEvents().onCommand("start", [&bot](Message::Ptr message) {
bot.getEvents().onCommand("start", [&bot, &data](Message::Ptr message) {
data.generate_track_list(1);
bot.getApi().sendMessage(message->chat->id, "Hi!");
});
signal(SIGINT, [](int s) {
printf("SIGINT got\n");
exit(0);
});
std::string * a = new std::string("hello world");
try {
printf("Bot username: %s\n", bot.getApi().getMe()->username.c_str());

Loading…
Cancel
Save