Posting works now

Cette révision appartient à :
tastytea 2018-05-11 06:57:41 +02:00
Parent b5d75af9fb
révision 8f083e127d
Signé par: tastytea
ID de la clé GPG: 59346E0EA35C67E5
6 fichiers modifiés avec 298 ajouts et 9 suppressions

Voir le fichier

@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 3.7)
project (expandurl-mastodon
VERSION 0.0.2
VERSION 0.1.0
LANGUAGES CXX
)
@ -25,5 +25,5 @@ include_directories(${CURL_INCLUDE_DIR})
file(GLOB sources src/*.cpp)
add_executable(expandurl-mastodon ${sources})
target_link_libraries(expandurl-mastodon mastodon-cpp curl curlpp)
target_link_libraries(expandurl-mastodon jsoncpp mastodon-cpp curl curlpp pthread)
install(TARGETS expandurl-mastodon DESTINATION ${CMAKE_INSTALL_BINDIR})

Voir le fichier

@ -1,5 +1,7 @@
**expandurl-mastodon** is a Mastodon bot that expands a shortened URL.
If you want the bot to expand an URL, reply to the post with the URL in it and
mention the bot account (@expandurl@botsin.space for example).
# Install
@ -28,9 +30,14 @@ Install with `make install`.
# Usage
## Error codes
You will need to generate an access token yourself at the moment. Create a
config file with your account and access token in
`${HOME}/.config/expandurl-mastodon.cfg`:
Same as [mastodon-cpp](https://github.com/tastytea/mastodon-cpp/blob/master/README.md#error-codes)
expandurl@example.social
abc123
Now start expandurl-mastodon without parameters.
# Copyright

Voir le fichier

@ -18,9 +18,24 @@
#define EXPANDURL_MASTODON_HPP
#include <string>
#include <memory>
#include <thread>
#include <vector>
#include <cstdint>
#include <mastodon-cpp/mastodon-cpp.hpp>
#include <mastodon-cpp/easy/all.hpp>
using std::string;
void signal_handler(int signum);
/*!
* @brief Extract URLs from HTML
*
* @return vector of URLs
*/
const std::vector<string> get_urls(const string &html);
/*!
* @brief Expands shortened URLs
*
@ -33,7 +48,7 @@ const string expand(const string &url);
/*!
* @brief Filters out tracking stuff
*
* Currently remoces all arguments beginning with `utm_`
* Currently removes all arguments beginning with `utm_`
*
* @param url URL to filter
*
@ -41,4 +56,32 @@ const string expand(const string &url);
*/
const string strip(const string &url);
class Listener
{
public:
Listener();
/*!
* @brief Starts listening on Mastodon
*/
const bool start();
/*!
* @brief Stops listening on Mastodon
*/
const void stop();
std::vector<Mastodon::Easy::Notification> get_new_messages();
Mastodon::Easy::Status get_status(const std::uint_fast64_t &id);
const bool send_reply(const Mastodon::Easy::Status &status,
const string &message);
private:
string _instance;
string _access_token;
string _stream;
std::unique_ptr<Mastodon::API::http> _ptr;
std::thread _thread;
};
#endif // EXPANDURL_MASTODON_HPP

Voir le fichier

@ -15,19 +15,99 @@
*/
#include <iostream>
#include <string>
#include <chrono>
#include <csignal>
#include <regex>
#include <curlpp/cURLpp.hpp>
#include "expandurl-mastodon.hpp"
using std::cout;
using std::cerr;
using std::string;
using Mastodon::Easy;
bool running = true;
void signal_handler(int signum)
{
switch (signum)
{
case SIGINT:
if (!running)
{
cout << "Forced close.\n";
exit(signum);
}
running = false;
cout << "Closing program, this could take a few seconds...\n";
break;
default:
break;
}
}
const std::vector<string> get_urls(const string &html)
{
const std::regex re_url("href=\"([^\"]+)\" rel");
std::smatch match;
string buffer = html;
std::vector<string> v;
while (std::regex_search(buffer, match, re_url))
{
string url = Easy::unescape_html(match[1].str());
v.push_back(strip(expand(url)));
buffer = match.suffix().str();
}
return v;
}
int main(int argc, char *argv[])
{
signal(SIGINT, signal_handler);
curlpp::initialize();
// cout << expand(argv[1]) << '\n';
cout << strip(argv[1]) << '\n';
Listener listener;
listener.start();
while (running)
{
std::this_thread::sleep_for(std::chrono::seconds(10));
for (Easy::Notification &notif : listener.get_new_messages())
{
const std::uint_fast64_t id = notif.status().in_reply_to_id();
Easy::Status status;
if (id > 0)
{
status = listener.get_status(id);
}
else
{
listener.send_reply(notif.status(),
"I couldn't find the message you replied to. 😞");
}
if (status.valid())
{
string message = "";
for (const string &url : get_urls(status.content()))
{
message += url + " \n";
}
if (listener.send_reply(notif.status(), message))
{
cout << "Sent reply: " << message;
}
else
{
cerr << "ERROR: could not send reply to " <<
notif.status().id() << '\n';
}
}
}
}
listener.stop();
curlpp::Cleanup();

157
src/masto.cpp Fichier normal
Voir le fichier

@ -0,0 +1,157 @@
/* This file is part of expandurl-mastodon.
* Copyright © 2018 tastytea <tastytea@tastytea.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <fstream>
#include <cstdlib> // getenv()
#include <iostream>
#include "version.hpp"
#include "expandurl-mastodon.hpp"
using std::cerr;
using std::string;
using Mastodon::Easy;
Listener::Listener()
: _instance("")
, _access_token("")
, _stream("")
, _ptr(nullptr)
{}
const bool Listener::start()
{
const string filepath = static_cast<const string>(getenv("HOME")) +
"/.config/expandurl-mastodon.cfg";
std::ifstream file(filepath);
if (file.is_open())
{
std::getline(file, _instance);
_instance = _instance.substr(_instance.find('@') + 1);
std::getline(file, _access_token);
file.close();
}
else
{
cerr << "ERROR: Could not open " << filepath << '\n';
return false;
}
_thread = std::thread([=]
{
Easy masto(_instance, _access_token);
masto.set_useragent(static_cast<const string>("expandurl-mastodon/") +
global::version);
masto.get_stream(Mastodon::API::v1::streaming_user, _stream, _ptr);
});
return true;
}
const void Listener::stop()
{
if (_ptr)
{
_ptr->abort_stream();
_thread.join();
}
}
std::vector<Easy::Notification> Listener::get_new_messages()
{
const string buffer = _stream;
_stream.clear();
std::vector<Easy::Notification> v;
for (const Easy::stream_event &event : Easy::parse_stream(buffer))
{
if (event.first == Easy::event_type::Notification)
{
v.push_back(Easy::Notification(event.second));
}
}
return v;
}
Mastodon::Easy::Status Listener::get_status(const std::uint_fast64_t &id)
{
Easy masto(_instance, _access_token);
std::uint_fast16_t ret;
string answer;
ret = masto.get(Easy::v1::statuses_id, {{ "id", { std::to_string(id) }}}, answer);
if (ret == 0)
{
return Easy::Status(answer);
}
else
{
cerr << "ERROR: " << ret << '\n';
return Easy::Status();
}
}
const bool Listener::send_reply(const Easy::Status &status,
const string &message)
{
Easy masto(_instance, _access_token);
std::uint_fast16_t ret;
string answer;
const string id = std::to_string(status.id());
string strvisibility;
switch (status.visibility())
{
case Easy::visibility_type::Private:
strvisibility = "private";
break;
case Easy::visibility_type::Direct:
strvisibility = "direct";
break;
default:
strvisibility = "unlisted";
break;
}
Easy::parametermap parameters =
{
{ "in_reply_to_id", { id } },
{ "visibility", { strvisibility } },
{ "status", { '@' + status.account().acct() + ' ' + message } }
};
if (status.sensitive())
{
parameters.insert({ "sensitive", { "true" } });
}
if (!status.spoiler_text().empty())
{
parameters.insert({ "spoiler_text", { status.spoiler_text() } });
}
ret = masto.post(Easy::v1::statuses, parameters, answer);
if (ret == 0)
{
return true;
}
else
{
return false;
}
}

Voir le fichier

@ -15,7 +15,7 @@
*/
#include <iostream>
#include <string>
#include <sstream>
#include <regex>
#include <curlpp/cURLpp.hpp>
#include <curlpp/Options.hpp>
@ -30,7 +30,9 @@ namespace curlopts = curlpp::options;
const string expand(const string &url)
{
curlpp::Easy request;
std::stringstream ss;
request.setOpt(curlopts::WriteStream(&ss));
request.setOpt<curlopts::CustomRequest>("HEAD");
request.setOpt<curlopts::Url>(url);
request.setOpt<curlopts::UserAgent>