Ups, habe das committen vergessen. :-)
This commit is contained in:
parent
377d2d768d
commit
3fb2225392
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "xdgjson"]
|
||||||
|
path = xdgjson
|
||||||
|
url = https://schlomp.space/tastytea/xdgjson.git
|
|
@ -6,7 +6,6 @@ project(feiertagebot
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(LIBXDG_BASEDIR REQUIRED libxdg-basedir)
|
pkg_check_modules(LIBXDG_BASEDIR REQUIRED libxdg-basedir)
|
||||||
pkg_check_modules(LIBCONFIG REQUIRED libconfig++)
|
|
||||||
pkg_check_modules(CURLPP REQUIRED curlpp)
|
pkg_check_modules(CURLPP REQUIRED curlpp)
|
||||||
pkg_check_modules(JSONCPP REQUIRED jsoncpp)
|
pkg_check_modules(JSONCPP REQUIRED jsoncpp)
|
||||||
|
|
||||||
|
@ -19,20 +18,18 @@ set(CMAKE_CXX_FLAGS_DEBUG
|
||||||
|
|
||||||
include_directories(${PROJECT_BINARY_DIR})
|
include_directories(${PROJECT_BINARY_DIR})
|
||||||
include_directories(${LIBXDG_BASEDIR_INCLUDE_DIRS})
|
include_directories(${LIBXDG_BASEDIR_INCLUDE_DIRS})
|
||||||
include_directories(${LIBCONFIG_INCLUDE_DIRS})
|
|
||||||
include_directories(${CURL_INCLUDE_DIRS})
|
include_directories(${CURL_INCLUDE_DIRS})
|
||||||
include_directories(${CURLPP_INCLUDE_DIRS})
|
include_directories(${CURLPP_INCLUDE_DIRS})
|
||||||
include_directories(${JSONCPP_INCLUDE_DIRS})
|
include_directories(${JSONCPP_INCLUDE_DIRS})
|
||||||
|
|
||||||
link_directories(${LIBXDG_BASEDIR_LIBRARY_DIRS})
|
link_directories(${LIBXDG_BASEDIR_LIBRARY_DIRS})
|
||||||
link_directories(${LIBCONFIG_LIBRARY_DIRS})
|
|
||||||
link_directories(${CURL_LIBRARY_DIRS})
|
link_directories(${CURL_LIBRARY_DIRS})
|
||||||
link_directories(${CURLPP_LIBRARY_DIRS})
|
link_directories(${CURLPP_LIBRARY_DIRS})
|
||||||
link_directories(${JSONCPP_LIBRARY_DIRS})
|
link_directories(${JSONCPP_LIBRARY_DIRS})
|
||||||
|
|
||||||
add_executable(${CMAKE_PROJECT_NAME} feiertagebot.cpp)
|
add_executable(${CMAKE_PROJECT_NAME} feiertagebot.cpp xdgjson/src/xdgjson.cpp)
|
||||||
target_link_libraries(${CMAKE_PROJECT_NAME}
|
target_link_libraries(${CMAKE_PROJECT_NAME}
|
||||||
"${LIBXDG_BASEDIR_LDFLAGS} ${LIBCONFIG_LDFLAGS}"
|
"${LIBXDG_BASEDIR_LDFLAGS} ${LIBCONFIG_LDFLAGS}"
|
||||||
"${CURLPP_LDFLAGS} ${JSONCPP_LDFLAGS}"
|
"${CURLPP_LDFLAGS} ${JSONCPP_LDFLAGS}"
|
||||||
"-lstdc++fs")
|
"-lstdc++fs -lmastodon-cpp")
|
||||||
install(TARGETS ${CMAKE_PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS ${CMAKE_PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
|
17
README.adoc
17
README.adoc
|
@ -3,8 +3,6 @@
|
||||||
*feiertagebot* ist ein Mastodon-bot, der über anstehende feiertage in
|
*feiertagebot* ist ein Mastodon-bot, der über anstehende feiertage in
|
||||||
Deutschland informiert. Die daten stammen von https://feiertage-api.de/.
|
Deutschland informiert. Die daten stammen von https://feiertage-api.de/.
|
||||||
|
|
||||||
NOTE: Ist noch in arbeit, tut bis jetzt noch nix.
|
|
||||||
|
|
||||||
== Installation
|
== Installation
|
||||||
|
|
||||||
=== Gentoo
|
=== Gentoo
|
||||||
|
@ -17,9 +15,9 @@ https://schlomp.space/tastytea/overlay[repository].
|
||||||
* C++ compiler
|
* C++ compiler
|
||||||
* https://cmake.org/[cmake] (mindestens 3.2)
|
* https://cmake.org/[cmake] (mindestens 3.2)
|
||||||
* http://repo.or.cz/w/libxdg-basedir.git[libxdg-basedir] (getested: 1.2)
|
* http://repo.or.cz/w/libxdg-basedir.git[libxdg-basedir] (getested: 1.2)
|
||||||
* https://github.com/hyperrealm/libconfig[libconfig++] (getested: 1.5)
|
|
||||||
* http://www.curlpp.org/[curlpp] (getested: 0.8)
|
* http://www.curlpp.org/[curlpp] (getested: 0.8)
|
||||||
* https://github.com/open-source-parsers/jsoncpp[jsoncpp] (getested: 1.8)
|
* https://github.com/open-source-parsers/jsoncpp[jsoncpp] (getested: 1.8)
|
||||||
|
* https://schlomp.space/tastytea/mastodon-cpp[mastodon-cpp] (mindestens 0.30.1)
|
||||||
|
|
||||||
=== Kompilieren
|
=== Kompilieren
|
||||||
|
|
||||||
|
@ -35,6 +33,19 @@ make install
|
||||||
.cmake options:
|
.cmake options:
|
||||||
* `-DCMAKE_BUILD_TYPE=Debug` für ein debug-build
|
* `-DCMAKE_BUILD_TYPE=Debug` für ein debug-build
|
||||||
|
|
||||||
|
== Benutzung
|
||||||
|
|
||||||
|
Beim ersten aufruf wirst du nach der instanz gefragt, dann wird ein access_token
|
||||||
|
generiert. Danach kannst du das programm einfach per cron aufrufen
|
||||||
|
(`crontab -e`).
|
||||||
|
|
||||||
|
.Beispieleintrag crontab
|
||||||
|
[source,crontab]
|
||||||
|
----
|
||||||
|
# m h dom mon dow command
|
||||||
|
10 14 * * * feiertagebot
|
||||||
|
----
|
||||||
|
|
||||||
== Lizenz
|
== Lizenz
|
||||||
|
|
||||||
CC-0 / Public Domain
|
CC-0 / Public Domain
|
||||||
|
|
190
feiertagebot.cpp
190
feiertagebot.cpp
|
@ -5,26 +5,149 @@
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
|
#include <chrono>
|
||||||
|
#include <ctime>
|
||||||
|
#include <cstdint>
|
||||||
#include <curlpp/Options.hpp>
|
#include <curlpp/Options.hpp>
|
||||||
#include <curlpp/Exception.hpp>
|
#include <curlpp/Exception.hpp>
|
||||||
#include <curlpp/Infos.hpp>
|
#include <curlpp/Infos.hpp>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
#include <mastodon-cpp/easy/all.hpp>
|
||||||
|
#include "xdgjson/src/xdgjson.hpp"
|
||||||
|
|
||||||
namespace curlopts = curlpp::options;
|
namespace curlopts = curlpp::options;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::cout;
|
using std::cout;
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
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()
|
int main()
|
||||||
{
|
{
|
||||||
const string version = "2019-02-11_1";
|
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
|
try
|
||||||
{
|
{
|
||||||
string year = "2019";
|
string year = get_date(system_clock::now(), "%Y");
|
||||||
string today = "2019-12-25";
|
string today = get_date(system_clock::now(), "%F");
|
||||||
string tomorrow = "2019-12-26";
|
string tomorrow = get_date(system_clock::now() + hours(24), "%F");
|
||||||
|
tomorrow = "2019-01-06";
|
||||||
|
|
||||||
curlpp::Easy request;
|
curlpp::Easy request;
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
|
@ -32,19 +155,67 @@ int main()
|
||||||
request.setOpt<curlopts::UserAgent>("feiertagebot/" + version);
|
request.setOpt<curlopts::UserAgent>("feiertagebot/" + version);
|
||||||
request.setOpt<curlopts::FollowLocation>(true);
|
request.setOpt<curlopts::FollowLocation>(true);
|
||||||
ss << request;
|
ss << request;
|
||||||
|
|
||||||
Json::Value root;
|
Json::Value root;
|
||||||
ss >> root;
|
ss >> root;
|
||||||
|
|
||||||
for (Json::Value::const_iterator it_root = root.begin(); it_root != root.end(); ++it_root)
|
string output;
|
||||||
|
|
||||||
|
for (const string &date : { today, tomorrow })
|
||||||
{
|
{
|
||||||
for (Json::Value::const_iterator it_region = it_root->begin(); it_region != it_root->end(); ++it_region)
|
Holiday current_day;
|
||||||
|
for (Json::Value::const_iterator it_root = root.begin(); it_root != root.end(); ++it_root)
|
||||||
{
|
{
|
||||||
if ((*it_region)["datum"] == today)
|
for (Json::Value::const_iterator it_region = it_root->begin(); it_region != it_root->end(); ++it_region)
|
||||||
{
|
{
|
||||||
cout << it_root.key() << ": " << (*it_region)["datum"] << ": " << it_region.key() << endl;
|
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)
|
catch (const std::exception &e)
|
||||||
|
@ -52,5 +223,6 @@ int main()
|
||||||
cerr << e.what() << endl;
|
cerr << e.what() << endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 1a10ef6686a34b7170f52490b7b9841da4476a2c
|
Loading…
Reference in New Issue