From 0daf373d3ce43f953d9953ccfe001ca9075492f3 Mon Sep 17 00:00:00 2001
From: tastytea
Date: Sun, 18 Feb 2018 14:27:01 +0100
Subject: [PATCH] refactoring
---
CMakeLists.txt | 4 +-
src/config.cpp | 117 ++++++++++++++++++++++++++++
src/mastorss.cpp | 193 ++---------------------------------------------
src/mastorss.hpp | 3 +
src/parse.cpp | 128 +++++++++++++++++++++++++++++++
5 files changed, 255 insertions(+), 190 deletions(-)
create mode 100644 src/config.cpp
create mode 100644 src/parse.cpp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e1388d1..b2e4e58 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 3.7)
include(GNUInstallDirs)
project (mastorss
- VERSION 0.2.2
+ VERSION 0.2.3
LANGUAGES CXX
)
@@ -21,6 +21,6 @@ configure_file (
include(FindCURL)
find_package(CURL REQUIRED)
-add_executable(mastorss src/mastorss.cpp src/http.cpp)
+add_executable(mastorss src/mastorss.cpp src/http.cpp src/config.cpp src/parse.cpp)
target_link_libraries(mastorss mastodon-cpp boost_system boost_filesystem ssl crypto ${CURL_LIBRARIES} curlpp)
install(TARGETS mastorss DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/src/config.cpp b/src/config.cpp
new file mode 100644
index 0000000..9e1269a
--- /dev/null
+++ b/src/config.cpp
@@ -0,0 +1,117 @@
+/* This file is part of mastorss.
+ * Copyright © 2018 tastytea
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "mastorss.hpp"
+
+namespace pt = boost::property_tree;
+
+using std::cout;
+using std::cerr;
+using std::cin;
+using std::string;
+
+std::uint16_t read_config(pt::ptree &config, const string &profile, string &instance, string &access_token, string &feedurl)
+{
+ bool config_changed = false;
+
+ // Read config file, get access token
+ try {
+ pt::read_json(filepath + "config-" + profile + ".json", config);
+ instance = config.get(profile + ".instance", "");
+ access_token = config.get(profile + ".access_token", "");
+ feedurl = config.get(profile + ".feedurl", "");
+ }
+ catch (std::exception &e)
+ {
+ // most likely no config file found
+ cout << "Config file not readable. Building new one.\n";
+ const boost::filesystem::path path(filepath);
+ boost::filesystem::create_directory(filepath);
+ }
+
+ if (instance.empty())
+ {
+ cout << "Instance: ";
+ cin >> instance;
+ config.put(profile + ".instance", instance);
+ config_changed = true;
+ }
+ if (access_token.empty())
+ {
+ cout << "No access token found.\n";
+ string client_id, client_secret, url;
+ Mastodon::API masto(instance, "");
+ std::uint16_t ret = masto.register_app1(instance,
+ "mastorss",
+ "urn:ietf:wg:oauth:2.0:oob",
+ "write",
+ "https://github.com/tastytea/mastorss",
+ client_id,
+ client_secret,
+ url);
+ if (ret == 0)
+ {
+ string code;
+ cout << "Visit " << url << " to authorize this application.\n";
+ cout << "Insert code: ";
+ cin >> code;
+
+ masto.register_app2(instance,
+ client_id,
+ client_secret,
+ "urn:ietf:wg:oauth:2.0:oob",
+ code,
+ access_token);
+ if (ret == 0)
+ {
+ config.put(profile + ".access_token", access_token);
+ config_changed = true;
+ }
+ else
+ {
+ cerr << "Error code: " << ret << '\n';
+ return ret;
+ }
+ }
+ else
+ {
+ cerr << "Error code: " << ret << '\n';
+ return ret;
+ }
+
+ }
+ if (feedurl.empty())
+ {
+ cout << "feedurl: ";
+ cin >> feedurl;
+ config.put(profile + ".feedurl", feedurl);
+ config_changed = true;
+ }
+ if (config_changed)
+ {
+ pt::write_json(filepath + "config-" + profile + ".json", config);
+ }
+
+ return 0;
+}
diff --git a/src/mastorss.cpp b/src/mastorss.cpp
index 0eb6780..fdcd93a 100644
--- a/src/mastorss.cpp
+++ b/src/mastorss.cpp
@@ -17,11 +17,8 @@
#include
#include
#include
+#include // getenv()
#include
-#include
-#include
-#include
-#include
#include
#include
#include
@@ -39,188 +36,10 @@ using std::cerr;
using std::cin;
using std::string;
+// Initialize global variables
std::uint16_t max_size = 500;
const string filepath = string(getenv("HOME")) + "/.config/mastorss/";
-std::uint16_t read_config(pt::ptree &config, const string &profile, string &instance, string &access_token, string &feedurl)
-{
- bool config_changed = false;
-
- // Read config file, get access token
- try {
- pt::read_json(filepath + "config-" + profile + ".json", config);
- instance = config.get(profile + ".instance", "");
- access_token = config.get(profile + ".access_token", "");
- feedurl = config.get(profile + ".feedurl", "");
- }
- catch (std::exception &e)
- {
- // most likely no config file found
- cout << "Config file not readable. Building new one.\n";
- const boost::filesystem::path path(filepath);
- boost::filesystem::create_directory(filepath);
- }
-
- if (instance.empty())
- {
- cout << "Instance: ";
- cin >> instance;
- config.put(profile + ".instance", instance);
- config_changed = true;
- }
- if (access_token.empty())
- {
- cout << "No access token found.\n";
- string client_id, client_secret, url;
- Mastodon::API masto(instance, "");
- std::uint16_t ret = masto.register_app1(instance,
- "mastorss",
- "urn:ietf:wg:oauth:2.0:oob",
- "write",
- "https://github.com/tastytea/mastorss",
- client_id,
- client_secret,
- url);
- if (ret == 0)
- {
- string code;
- cout << "Visit " << url << " to authorize this application.\n";
- cout << "Insert code: ";
- cin >> code;
-
- masto.register_app2(instance,
- client_id,
- client_secret,
- "urn:ietf:wg:oauth:2.0:oob",
- code,
- access_token);
- if (ret == 0)
- {
- config.put(profile + ".access_token", access_token);
- config_changed = true;
- }
- else
- {
- cerr << "Error code: " << ret << '\n';
- return ret;
- }
- }
- else
- {
- cerr << "Error code: " << ret << '\n';
- return ret;
- }
-
- }
- if (feedurl.empty())
- {
- cout << "feedurl: ";
- cin >> feedurl;
- config.put(profile + ".feedurl", feedurl);
- config_changed = true;
- }
- if (config_changed)
- {
- pt::write_json(filepath + "config-" + profile + ".json", config);
- }
-
- return 0;
-}
-
-std::vector parse_website(const string &profile, const string &xml)
-{
- pt::ptree json;
- std::vector watchwords;
-
- try
- {
- pt::read_json(filepath + "watchwords.json", json);
- }
- catch (std::exception &e)
- {
- // most likely file not found
- std::cerr << "ERROR: " << filepath << "watchwords.json not found or not readable.\n";
- std::cerr << e.what() << '\n';
- return {};
- }
-
- try
- {
- for (const pt::ptree::value_type &value : json.get_child(profile + ".tags"))
- {
- watchwords.push_back(value.second.data());
- }
- }
- catch (const std::exception &e)
- {
- // Node not found, no problem
- }
- try
- {
- for (const pt::ptree::value_type &value : json.get_child("global.tags"))
- {
- watchwords.push_back(value.second.data());
- }
- }
- catch (const std::exception &e)
- {
- // Node not found, no problem
- }
-
- pt::ptree rss;
- std::istringstream iss(xml);
- pt::read_xml(iss, rss);
- std::vector ret;
-
- for (const pt::ptree::value_type &v : rss.get_child("rss.channel"))
- {
- if (v.second.size() > 0)
- {
- if (string(v.first.data()).compare("item") == 0)
- {
- string title = v.second.get_child("title").data();
- string link = v.second.get_child("link").data();
- string desc = v.second.get_child("description").data();
- string str = title + "\n\n" + desc;
-
- // Some feeds contain encoded xhtml-tags >:|
- std::regex relt("<");
- std::regex regt(">");
- std::regex reparagraph("
");
- std::regex recdata1("");
- std::regex restrip("<[^>]*>");
- std::regex reindyfuckup("\\/\\* Style Definitions \\*\\/[.[:space:]]*$");
-
- str = std::regex_replace(str, relt, "<");
- str = std::regex_replace(str, regt, ">");
- str = std::regex_replace(str, reparagraph, "\n\n");
- str = std::regex_replace(str, recdata1, "");
- str = std::regex_replace(str, recdata2, "");
- str = std::regex_replace(str, restrip, "");
- str = std::regex_replace(str, reindyfuckup, "");
-
- for (const string &hashtag : watchwords)
- {
- std::regex rehashtag("([[:space:][:punct:]]|^)(" + hashtag + ")([[:space:][:punct:]]|$)",
- std::regex_constants::icase);
- str = std::regex_replace(str, rehashtag, "$1#$2$3",
- std::regex_constants::format_first_only);
- }
- if ((str.size() + link.size()) > (std::uint16_t)(max_size - 15))
- {
- str.resize((max_size - link.size() - 15));
- str += " […]";
- }
- str += "\n\n" + link + "\n\n#bot";
- ret.push_back(str);
- }
- }
- }
-
- return ret;
-}
-
int main(int argc, char *argv[])
{
if (argc < 2)
@@ -284,11 +103,7 @@ int main(int argc, char *argv[])
};
ret = masto.post(API::v1::statuses, parameters, answer);
- if (ret == 0)
- {
- pt::write_json(filepath + "config-" + profile + ".json", config);
- }
- else
+ if (ret != 0)
{
std::cerr << "Error code: " << ret << '\n';
std::cerr << answer << '\n';
@@ -298,5 +113,7 @@ int main(int argc, char *argv[])
std::this_thread::sleep_for(std::chrono::seconds(2));
}
+ pt::write_json(filepath + "config-" + profile + ".json", config);
+
return 0;
}
diff --git a/src/mastorss.hpp b/src/mastorss.hpp
index d80603f..a5d3f4b 100644
--- a/src/mastorss.hpp
+++ b/src/mastorss.hpp
@@ -9,6 +9,9 @@
namespace pt = boost::property_tree;
using std::string;
+extern std::uint16_t max_size;
+extern const string filepath;
+
std::uint16_t read_config(pt::ptree &config, const string &profile, string &instance, string &access_token, string &feedurl);
std::vector parse_website(const string &profile, const string &xml);
diff --git a/src/parse.cpp b/src/parse.cpp
new file mode 100644
index 0000000..e37dc5d
--- /dev/null
+++ b/src/parse.cpp
@@ -0,0 +1,128 @@
+/* This file is part of mastorss.
+ * Copyright © 2018 tastytea
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "mastorss.hpp"
+
+namespace pt = boost::property_tree;
+
+using std::cerr;
+using std::string;
+
+std::vector parse_website(const string &profile, const string &xml)
+{
+ pt::ptree json;
+ std::vector watchwords;
+
+ try
+ {
+ pt::read_json(filepath + "watchwords.json", json);
+ }
+ catch (std::exception &e)
+ {
+ // most likely file not found
+ cerr << "ERROR: " << filepath << "watchwords.json not found or not readable.\n";
+ cerr << e.what() << '\n';
+ return {};
+ }
+
+ try
+ {
+ for (const pt::ptree::value_type &value : json.get_child(profile + ".tags"))
+ {
+ watchwords.push_back(value.second.data());
+ }
+ }
+ catch (const std::exception &e)
+ {
+ // Node not found, no problem
+ }
+ try
+ {
+ for (const pt::ptree::value_type &value : json.get_child("global.tags"))
+ {
+ watchwords.push_back(value.second.data());
+ }
+ }
+ catch (const std::exception &e)
+ {
+ // Node not found, no problem
+ }
+
+ pt::ptree rss;
+ std::istringstream iss(xml);
+ pt::read_xml(iss, rss);
+ std::vector ret;
+
+ for (const pt::ptree::value_type &v : rss.get_child("rss.channel"))
+ {
+ if (v.second.size() > 0)
+ {
+ if (string(v.first.data()).compare("item") == 0)
+ {
+ string title = v.second.get_child("title").data();
+ string link = v.second.get_child("link").data();
+ string desc = v.second.get_child("description").data();
+ string str = title + "\n\n" + desc;
+
+ // Some feeds contain encoded xhtml-tags >:|
+ std::regex relt("<");
+ std::regex regt(">");
+ std::regex reparagraph("
");
+ std::regex recdata1("");
+ std::regex restrip("<[^>]*>");
+ std::regex reindyfuckup("\\/\\* Style Definitions \\*\\/[.[:space:]]*$");
+
+ str = std::regex_replace(str, relt, "<");
+ str = std::regex_replace(str, regt, ">");
+ str = std::regex_replace(str, reparagraph, "\n\n");
+ str = std::regex_replace(str, recdata1, "");
+ str = std::regex_replace(str, recdata2, "");
+ str = std::regex_replace(str, restrip, "");
+ str = std::regex_replace(str, reindyfuckup, "");
+ str = std::regex_replace(str, std::regex("[\\n\\r]+"), "\n"); // remove excess newlines
+
+ for (const string &hashtag : watchwords)
+ {
+ std::regex rehashtag("([[:space:][:punct:]]|^)(" + hashtag + ")([[:space:][:punct:]]|$)",
+ std::regex_constants::icase);
+ str = std::regex_replace(str, rehashtag, "$1#$2$3",
+ std::regex_constants::format_first_only);
+ }
+ if ((str.size() + link.size()) > (std::uint16_t)(max_size - 15))
+ {
+ str.resize((max_size - link.size() - 15));
+ str += " […]";
+ }
+ str += "\n\n" + link + "\n\n#bot";
+ ret.push_back(str);
+ }
+ }
+ }
+
+ return ret;
+}