Posting works now
This commit is contained in:
parent
b5d75af9fb
commit
8f083e127d
|
@ -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})
|
||||
|
|
11
README.md
11
README.md
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
86
src/main.cpp
86
src/main.cpp
|
@ -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 ¬if : 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
Normal file
157
src/masto.cpp
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue
Block a user