Browse Source

Posting works now

tags/0.1.3
tastytea 2 years ago
parent
commit
8f083e127d
Signed by: tastytea GPG Key ID: 59346E0EA35C67E5
6 changed files with 298 additions and 9 deletions
  1. +2
    -2
      CMakeLists.txt
  2. +9
    -2
      README.md
  3. +44
    -1
      src/expandurl-mastodon.hpp
  4. +83
    -3
      src/main.cpp
  5. +157
    -0
      src/masto.cpp
  6. +3
    -1
      src/url.cpp

+ 2
- 2
CMakeLists.txt View File

@@ -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})

+ 9
- 2
README.md View File

@@ -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



+ 44
- 1
src/expandurl-mastodon.hpp View File

@@ -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

+ 83
- 3
src/main.cpp View File

@@ -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
- 0
src/masto.cpp View 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;
}
}

+ 3
- 1
src/url.cpp View File

@@ -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…
Cancel
Save