229 lines
6.2 KiB
C++
229 lines
6.2 KiB
C++
// Author: tastytea <tastytea@tastytea.de>
|
|
// CC-0 / Public Domain
|
|
|
|
#include <string>
|
|
#include <exception>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <map>
|
|
#include <chrono>
|
|
#include <ctime>
|
|
#include <cstdint>
|
|
#include <curlpp/Options.hpp>
|
|
#include <curlpp/Exception.hpp>
|
|
#include <curlpp/Infos.hpp>
|
|
#include <json/json.h>
|
|
#include <mastodon-cpp/easy/all.hpp>
|
|
#include "xdgjson/src/xdgjson.hpp"
|
|
|
|
namespace curlopts = curlpp::options;
|
|
using std::string;
|
|
using std::cout;
|
|
using std::cerr;
|
|
using std::endl;
|
|
using std::vector;
|
|
using std::chrono::system_clock;
|
|
using std::chrono::hours;
|
|
using std::uint_fast16_t;
|
|
|
|
const string version = "2019-02-12_1";
|
|
|
|
struct Holiday
|
|
{
|
|
string date;
|
|
string description;
|
|
vector<string> regions;
|
|
};
|
|
|
|
const string decode_state(const string &abbr)
|
|
{
|
|
const std::map<string, string> states =
|
|
{
|
|
{ "BW", "Baden-Württemberg" },
|
|
{ "BY", "Bayern" },
|
|
{ "BE", "Berlin" },
|
|
{ "BB", "Brandenburg" },
|
|
{ "HB", "Bremen" },
|
|
{ "HH", "Hamburg" },
|
|
{ "HE", "Hessen" },
|
|
{ "MV", "Mecklenburg-Vorpommern" },
|
|
{ "NI", "Niedersachsen" },
|
|
{ "NW", "Nordrhein-Westfalen" },
|
|
{ "RP", "Rheinland-Pfalz" },
|
|
{ "SL", "Saarland" },
|
|
{ "SN", "Sachsen" },
|
|
{ "ST", "Sachsen-Anhalt" },
|
|
{ "SH", "Schleswig-Holstein" },
|
|
{ "TH", "Thüringen" }
|
|
};
|
|
|
|
if (states.find(abbr) != states.end())
|
|
{
|
|
return states.find(abbr)->second;
|
|
}
|
|
else
|
|
{
|
|
return abbr;
|
|
}
|
|
}
|
|
|
|
const string get_date(const system_clock::time_point &timepoint, const string &format)
|
|
{
|
|
std::time_t time = system_clock::to_time_t(timepoint);
|
|
std::tm *timeinfo = std::localtime(&time);
|
|
char buffer[1024];
|
|
std::strftime(buffer, 1024, format.c_str(), timeinfo);
|
|
return string(buffer);
|
|
}
|
|
|
|
const string get_token(const string &instance)
|
|
{
|
|
Mastodon::API masto(instance, "");
|
|
uint_fast16_t ret = 0;
|
|
string client_id, client_secret, url;
|
|
string code, access_token;
|
|
ret = masto.register_app1("feiertagebot",
|
|
"urn:ietf:wg:oauth:2.0:oob",
|
|
"write:statuses",
|
|
"",
|
|
client_id,
|
|
client_secret,
|
|
url);
|
|
if (ret > 0)
|
|
{
|
|
cerr << "Error " << std::to_string(ret) << endl;
|
|
return "";
|
|
}
|
|
|
|
cout << "Visit " << url << " to authorize this application.\n";
|
|
cout << "Insert code: ";
|
|
std::getline(std::cin, code);
|
|
ret = masto.register_app2(client_id,
|
|
client_secret,
|
|
"urn:ietf:wg:oauth:2.0:oob",
|
|
code,
|
|
access_token);
|
|
if (ret > 0)
|
|
{
|
|
cerr << "Error " << std::to_string(ret) << endl;
|
|
return "";
|
|
}
|
|
|
|
return access_token;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
string instance, access_token;
|
|
xdgjson config("feiertagebot.json");
|
|
config.read();
|
|
Json::Value &json = config.get_json();
|
|
if (json["instance"].isString())
|
|
{
|
|
instance = json["instance"].asString();
|
|
}
|
|
else
|
|
{
|
|
cout << "Instance domain: ";
|
|
std::getline(std::cin, instance);
|
|
json["instance"] = instance;
|
|
}
|
|
if (json["access_token"].isString())
|
|
{
|
|
access_token = json["access_token"].asString();
|
|
}
|
|
else
|
|
{
|
|
access_token = get_token(instance);
|
|
json["access_token"] = access_token;
|
|
config.write();
|
|
}
|
|
|
|
try
|
|
{
|
|
string year = get_date(system_clock::now(), "%Y");
|
|
string today = get_date(system_clock::now(), "%F");
|
|
string tomorrow = get_date(system_clock::now() + hours(24), "%F");
|
|
tomorrow = "2019-01-06";
|
|
|
|
curlpp::Easy request;
|
|
std::stringstream ss;
|
|
|
|
request.setOpt<curlopts::Url>("https://feiertage-api.de/api/?jahr=" + year);
|
|
request.setOpt<curlopts::UserAgent>("feiertagebot/" + version);
|
|
request.setOpt<curlopts::FollowLocation>(true);
|
|
ss << request;
|
|
Json::Value root;
|
|
ss >> root;
|
|
|
|
string output;
|
|
|
|
for (const string &date : { today, tomorrow })
|
|
{
|
|
Holiday current_day;
|
|
for (Json::Value::const_iterator it_root = root.begin(); it_root != root.end(); ++it_root)
|
|
{
|
|
for (Json::Value::const_iterator it_region = it_root->begin(); it_region != it_root->end(); ++it_region)
|
|
{
|
|
if ((*it_region)["datum"] == date)
|
|
{
|
|
current_day.date = date;
|
|
current_day.description = it_region.key().asString();
|
|
current_day.regions.push_back(it_root.key().asString());
|
|
}
|
|
}
|
|
}
|
|
if (current_day.date.empty())
|
|
{
|
|
continue;
|
|
}
|
|
output += "Am " + current_day.date + " ist "+ current_day.description + " in ";
|
|
if (std::find(current_day.regions.begin(), current_day.regions.end(), "NATIONAL") != current_day.regions.end())
|
|
{
|
|
output += "Deutschland.\n";
|
|
}
|
|
else
|
|
{
|
|
bool firstrun = true;
|
|
for (const string ®ion : current_day.regions)
|
|
{
|
|
if (!firstrun)
|
|
{
|
|
output += ", ";
|
|
}
|
|
else
|
|
{
|
|
firstrun = false;
|
|
}
|
|
output += decode_state(region);
|
|
}
|
|
output += "\n";
|
|
}
|
|
}
|
|
|
|
if (!output.empty())
|
|
{
|
|
uint_fast16_t ret;
|
|
Mastodon::Easy masto(instance, access_token);
|
|
masto.exceptions(true);
|
|
Mastodon::Easy::Status status;
|
|
status.content(output);
|
|
masto.send_post(status, ret);
|
|
if (ret > 0)
|
|
{
|
|
cerr << "Error " << std::to_string(ret) << endl;
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
catch (const std::exception &e)
|
|
{
|
|
cerr << e.what() << endl;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|