diff --git a/CMakeLists.txt b/CMakeLists.txt index eb77d5a..c9da687 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,12 +18,13 @@ cmake_minimum_required(VERSION 3.16) cmake_policy(VERSION 3.16...3.27) -project(dtranslatebot VERSION 0.3.0 LANGUAGES CXX) +project(dtranslatebot VERSION 0.3.3 LANGUAGES CXX) include(GNUInstallDirs) # dtranslatebot Source files set(DTRANSLATEBOT_HEADERS src/core/database.h + src/core/http_headers.h src/core/http_request.h src/core/http_response.h src/core/message_queue.h @@ -43,6 +44,7 @@ set(DTRANSLATEBOT_HEADERS ) set(DTRANSLATEBOT_SOURCES src/core/database.cpp + src/core/http_headers.cpp src/core/http_request.cpp src/core/main.cpp src/core/message_queue.cpp diff --git a/README.md b/README.md index 8e68dab..79e1ebc 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Open Source Discord Translation Bot - [LibreTranslate](https://libretranslate.com/) (Default) - [Lingva Translate](https://lingva.ml/) - [Mozhi](https://codeberg.org/aryak/mozhi) -- [DeepL](https://deepl.com/) (Experimental) +- [DeepL](https://deepl.com/) #### Build dtranslatebot diff --git a/rpmsrc/dtranslatebot.spec b/rpmsrc/dtranslatebot.spec index e93596c..0338a06 100644 --- a/rpmsrc/dtranslatebot.spec +++ b/rpmsrc/dtranslatebot.spec @@ -15,7 +15,7 @@ %endif Name: dtranslatebot -Version: 0.3.0 +Version: 0.3.3 Release: 1%{?dist} Summary: Discord Translation Bot License: BSD-2-Clause diff --git a/src/core/http_headers.cpp b/src/core/http_headers.cpp new file mode 100644 index 0000000..c118d1f --- /dev/null +++ b/src/core/http_headers.cpp @@ -0,0 +1,136 @@ +/***************************************************************************** +* dtranslatebot Discord Translate Bot +* Copyright (C) 2026 Syping +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* This software is provided as-is, no warranties are given to you, we are not +* responsible for anything with use of the software, you are self responsible. +*****************************************************************************/ + +#include "http_headers.h" +using namespace bot::http; + +http_headers::http_headers() { + instance = nullptr; +} + +http_headers::http_headers(const http_headers &headers) { + instance = copy_from(headers.data()); +} + +http_headers::http_headers(const std::string &field, const std::string &value) { + instance = nullptr; + add(field, value); +} + +http_headers::http_headers(const http_header &header) { + instance = nullptr; + add(header); +} + +http_headers::http_headers(const std::initializer_list &headers) { + instance = nullptr; + try { + add(headers); + } + catch (const std::bad_alloc &exception) { + curl_slist_free_all(instance); + throw; + } +} + +http_headers::http_headers(const std::vector &headers) { + instance = nullptr; + try { + add(headers); + } + catch (const std::bad_alloc &exception) { + curl_slist_free_all(instance); + throw; + } +} + +http_headers::~http_headers() { + curl_slist_free_all(instance); +} + +http_headers& http_headers::operator=(const curl_slist *other) { + if (this->data() == other) + return *this; + if (curl_slist *headers = copy_from(other)) { + curl_slist_free_all(instance); + instance = headers; + } + return *this; +} + +http_headers& http_headers::operator=(const http_headers &other) { + if (this == &other) + return *this; + if (curl_slist *headers = copy_from(other.data())) { + curl_slist_free_all(instance); + instance = headers; + } + return *this; +} + +void http_headers::add(const std::string &field, const std::string &value) { + const std::string header = field + ": " + value; + curl_slist *headers = curl_slist_append(instance, header.c_str()); + if (!headers) + throw std::bad_alloc(); + instance = headers; +} + +void http_headers::add(const http_header &header) { + add(header.first, header.second); +} + +void http_headers::add(const std::initializer_list &headers) { + for (const auto &header : headers) + add(header); +} + +void http_headers::add(const std::vector &headers) { + for (const auto &header : headers) + add(header); +} + +void http_headers::remove(const std::string &field) { + const std::string header = field + ":"; + curl_slist *headers = curl_slist_append(instance, header.c_str()); + if (!headers) + throw std::bad_alloc(); + instance = headers; +} + +void http_headers::remove(const std::vector &fields) { + for (const auto &field : fields) + remove(field); +} + +const curl_slist* http_headers::data() const { + return instance; +} + +curl_slist* http_headers::copy_from(const curl_slist *headers) { + curl_slist *instance = nullptr; + for (const curl_slist *i = headers; i; i = i->next) { + curl_slist *headers = curl_slist_append(instance, i->data); + if (!headers) { + curl_slist_free_all(instance); + throw std::bad_alloc(); + } + instance = headers; + } + return instance; +} diff --git a/src/core/http_headers.h b/src/core/http_headers.h new file mode 100644 index 0000000..7e488cd --- /dev/null +++ b/src/core/http_headers.h @@ -0,0 +1,57 @@ +/***************************************************************************** +* dtranslatebot Discord Translate Bot +* Copyright (C) 2026 Syping +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* This software is provided as-is, no warranties are given to you, we are not +* responsible for anything with use of the software, you are self responsible. +*****************************************************************************/ + +#ifndef HTTP_HEADERS_H +#define HTTP_HEADERS_H +#include +#include +#include +#include +#include + +namespace bot { + namespace http { + typedef std::pair http_header; + + class http_headers { + public: + http_headers(); + http_headers(const http_headers &headers); + http_headers(const std::string &field, const std::string &value); + http_headers(const http_header &header); + http_headers(const std::initializer_list &headers); + http_headers(const std::vector &headers); + ~http_headers(); + http_headers& operator=(const curl_slist *headers); + http_headers& operator=(const http_headers &headers); + void add(const std::string &field, const std::string &value); + void add(const http_header &header); + void add(const std::initializer_list &headers); + void add(const std::vector &headers); + void remove(const std::string &field); + void remove(const std::vector &fields); + const curl_slist* data() const; + + private: + static curl_slist* copy_from(const curl_slist *headers); + curl_slist *instance; + }; + } +} + +#endif // HTTP_HEADERS_H diff --git a/src/core/http_request.cpp b/src/core/http_request.cpp index 58d9e0e..dde7872 100644 --- a/src/core/http_request.cpp +++ b/src/core/http_request.cpp @@ -17,6 +17,7 @@ *****************************************************************************/ #include "http_request.h" +using namespace bot::http; http_request::http_request() { instance = curl_easy_init(); @@ -24,56 +25,23 @@ http_request::http_request() { throw std::bad_alloc(); } -const http_response http_request::get(const std::string &url, const dpp::http_headers &headers) { +const http_response http_request::get(const std::string &url, const http_headers &headers) { http_response response; curl_easy_setopt(instance, CURLOPT_URL, url.c_str()); - curl_slist *header_slist = nullptr; - if (!headers.empty()) { - for (const auto &header : headers) { - curl_slist *new_header_slist = curl_slist_append(header_slist, std::string(header.first + ": " + header.second).c_str()); - if (!new_header_slist) { - curl_slist_free_all(header_slist); - throw std::bad_alloc(); - } - header_slist = new_header_slist; - } - } - if (!header_slist) - curl_easy_setopt(instance, CURLOPT_HTTPHEADER, header_slist); + curl_easy_setopt(instance, CURLOPT_HTTPHEADER, headers.data()); curl_easy_setopt(instance, CURLOPT_WRITEDATA, &response.content); curl_easy_setopt(instance, CURLOPT_WRITEFUNCTION, &writer); CURLcode result = curl_easy_perform(instance); if (result == CURLE_OK) curl_easy_getinfo(instance, CURLINFO_RESPONSE_CODE, &response.status); curl_easy_reset(instance); - curl_slist_free_all(header_slist); return response; } -const http_response http_request::post(const std::string &url, const std::string &content, const std::string &content_type, const dpp::http_headers &headers) { +const http_response http_request::post(const std::string &url, const std::string &content, const http_headers &headers) { http_response response; curl_easy_setopt(instance, CURLOPT_URL, url.c_str()); - curl_slist *header_slist = nullptr; - if (!content_type.empty()) { - curl_slist *new_header_slist = curl_slist_append(header_slist, std::string("Content-Type: " + content_type).c_str()); - if (!new_header_slist) { - curl_slist_free_all(header_slist); - throw std::bad_alloc(); - } - header_slist = new_header_slist; - } - if (!headers.empty()) { - for (const auto &header : headers) { - curl_slist *new_header_slist = curl_slist_append(header_slist, std::string(header.first + ": " + header.second).c_str()); - if (!new_header_slist) { - curl_slist_free_all(header_slist); - throw std::bad_alloc(); - } - header_slist = new_header_slist; - } - } - if (!header_slist) - curl_easy_setopt(instance, CURLOPT_HTTPHEADER, header_slist); + curl_easy_setopt(instance, CURLOPT_HTTPHEADER, headers.data()); curl_easy_setopt(instance, CURLOPT_POSTFIELDS, content.data()); curl_easy_setopt(instance, CURLOPT_POSTFIELDSIZE, content.size()); curl_easy_setopt(instance, CURLOPT_WRITEDATA, &response.content); @@ -82,7 +50,6 @@ const http_response http_request::post(const std::string &url, const std::string if (result == CURLE_OK) curl_easy_getinfo(instance, CURLINFO_RESPONSE_CODE, &response.status); curl_easy_reset(instance); - curl_slist_free_all(header_slist); return response; } diff --git a/src/core/http_request.h b/src/core/http_request.h index e9bb387..104b5f4 100644 --- a/src/core/http_request.h +++ b/src/core/http_request.h @@ -20,21 +20,26 @@ #define HTTP_REQUEST_H #include #include -#include +#include "http_headers.h" #include "http_response.h" -class http_request -{ -public: - http_request(); - ~http_request(); - const http_response get(const std::string &url, const dpp::http_headers &headers = {}); - const http_response post(const std::string &url, const std::string &content, const std::string &content_type, const dpp::http_headers &headers = {}); - static std::string legacy_url(const std::string &hostname, uint16_t port, const std::string &url, bool tls); +namespace bot { + namespace http { + class http_request { + public: + http_request(); + http_request(const http_request&) = delete; + http_request& operator=(const http_request&) = delete; + ~http_request(); + const http_response get(const std::string &url, const http_headers &headers = {}); + const http_response post(const std::string &url, const std::string &content, const http_headers &headers = {}); + static std::string legacy_url(const std::string &hostname, uint16_t port, const std::string &url, bool tls); -private: - static size_t writer(char *source, size_t size, size_t nmemb, std::string *target); - CURL *instance; -}; + private: + static size_t writer(char *source, size_t size, size_t nmemb, std::string *target); + CURL *instance; + }; + } +} #endif // HTTP_REQUEST_H diff --git a/src/core/http_response.h b/src/core/http_response.h index 2364e13..e4cc06a 100644 --- a/src/core/http_response.h +++ b/src/core/http_response.h @@ -20,10 +20,13 @@ #define HTTP_RESPONSE_H #include -struct http_response -{ - std::string content; - long status; -}; +namespace bot { + namespace http { + struct http_response { + std::string content; + long status; + }; + } +} #endif // HTTP_RESPONSE_H diff --git a/src/core/slashcommands.cpp b/src/core/slashcommands.cpp index cbfe365..4ea7408 100644 --- a/src/core/slashcommands.cpp +++ b/src/core/slashcommands.cpp @@ -191,14 +191,31 @@ void slashcommands::process_my_command(dpp::cluster *bot, bot::settings::setting if (interaction.options[0].name == "language") { const std::string target = std::get(event.get_parameter("target")); - const std::lock_guard guard(*settings); - settings->set_user_target(event.command.usr.id, target); + const auto languages = settings->get_translator()->get_languages(); - auto database = settings->get_database(); - database->set_user_target(event.command.usr.id, target); - database->sync(); + std::ostringstream language_codes; + bool target_valid = false; + for (const bot::translator::language &language : languages) { + if (language.code == target) { + target_valid = true; + break; + } + language_codes << ' ' << language.code; + } - event.reply(dpp::message("Your target language has being set!").set_flags(dpp::m_ephemeral)); + if (target_valid) { + const std::lock_guard guard(*settings); + settings->set_user_target(event.command.usr.id, target); + + auto database = settings->get_database(); + database->set_user_target(event.command.usr.id, target); + database->sync(); + + event.reply(dpp::message("Your target language has being set!").set_flags(dpp::m_ephemeral)); + } + else { + event.reply(dpp::message("Target language is not valid!\nAvailable languages are:" + language_codes.str()).set_flags(dpp::m_ephemeral)); + } } else { throw std::invalid_argument("Option " + interaction.options[0].name + " is not known"); diff --git a/src/translator/deepl/deepl.cpp b/src/translator/deepl/deepl.cpp index 8658fb2..a8b8047 100644 --- a/src/translator/deepl/deepl.cpp +++ b/src/translator/deepl/deepl.cpp @@ -17,12 +17,11 @@ *****************************************************************************/ #include -#include -#include "../../core/http_request.h" +#include #include "deepl.h" +using namespace bot::http; using namespace bot::translator; using namespace std::chrono_literals; -using namespace std::string_literals; deepl::deepl(const std::string &hostname, const std::string apiKey) : m_hostname(hostname), m_apiKey(apiKey) @@ -43,8 +42,8 @@ const std::vector deepl::get_languages() } try { - http_request request; - http_response response = request.get(http_request::legacy_url(m_hostname, 443, "/v2/languages?type=target"s, true), { {"Authorization"s, "DeepL-Auth-Key "s + m_apiKey} }); + http_response response = m_http.get(http_request::legacy_url(m_hostname, 443, "/v2/languages?type=target", true), + {{"Authorization", "DeepL-Auth-Key " + m_apiKey}}); if (response.status == 200) { const dpp::json json_response = dpp::json::parse(response.content); if (json_response.is_array()) { @@ -57,10 +56,16 @@ const std::vector deepl::get_languages() if (json_lang_code != json_language->end()) language.code = *json_lang_code; - if (language.code.size() > 2) + if (language.code.size() == 5) { std::transform(language.code.begin(), language.code.begin() + 2, language.code.begin(), ::tolower); - else + } + else if (language.code.size() > 5) { + std::transform(language.code.begin(), language.code.begin() + 2, language.code.begin(), ::tolower); + std::transform(language.code.begin() + 4, language.code.end(), language.code.begin() + 4, ::tolower); + } + else { std::transform(language.code.begin(), language.code.end(), language.code.begin(), ::tolower); + } auto json_lang_name = json_language->find("name"); if (json_lang_name != json_language->end()) @@ -70,6 +75,23 @@ const std::vector deepl::get_languages() m_languages.languages.push_back(std::move(language)); } } + // Improving DeepL compatibility + if (std::find_if(m_languages.languages.begin(), m_languages.languages.end(), [](language language) { + return language.code == "en"; + }) == m_languages.languages.end()) { + language english; + english.code = "en"; + english.name = "English (Default)"; + m_languages.languages.push_back(english); + } + if (std::find_if(m_languages.languages.begin(), m_languages.languages.end(), [](language language) { + return language.code == "pt"; + }) == m_languages.languages.end()) { + language portuguese; + portuguese.code = "pt"; + portuguese.name = "Portuguese (Default)"; + m_languages.languages.push_back(portuguese); + } m_languages.query_time = std::chrono::system_clock::now(); } } @@ -83,21 +105,16 @@ const std::vector deepl::get_languages() const std::string deepl::translate(const std::string &text, const std::string &source, const std::string &target) { - const dpp::http_headers http_headers = { - {"Authorization"s, "DeepL-Auth-Key " + m_apiKey}, - {"Content-Type"s, "application/json"s} - }; - dpp::json json_body = { - {"text"s, { text } }, - {"target_lang"s, target} + {"text", { text } }, + {"target_lang", target == "en" ? "en-US" : target == "pt" ? "pt-PT" : target} }; - if (!source.empty()) - json_body["source_lang"] = source; + if (!source.empty() && source != "auto") + json_body["source_lang"] = source.length() > 2 ? source.substr(0, 2) : source; try { - http_request request; - http_response response = request.post(http_request::legacy_url(m_hostname, 443, "/v2/translate", true), json_body.dump(), "application/json", { {"Authorization"s, "DeepL-Auth-Key " + m_apiKey} }); + http_response response = m_http.post(http_request::legacy_url(m_hostname, 443, "/v2/translate", true), json_body.dump(), + {{"Authorization", "DeepL-Auth-Key " + m_apiKey}, {"Content-Type", "application/json"}}); if (response.status == 200) { const dpp::json json_response = dpp::json::parse(response.content); if (json_response.is_object()) { diff --git a/src/translator/deepl/deepl.h b/src/translator/deepl/deepl.h index 6fd90f9..0e07aa6 100644 --- a/src/translator/deepl/deepl.h +++ b/src/translator/deepl/deepl.h @@ -19,7 +19,7 @@ #ifndef TRANSLATOR_DEEPL_H #define TRANSLATOR_DEEPL_H -#include +#include "../../core/http_request.h" #include "../../core/translator.h" namespace bot { @@ -34,6 +34,7 @@ namespace bot { private: std::string m_apiKey; std::string m_hostname; + bot::http::http_request m_http; supported_languages m_languages; }; } diff --git a/src/translator/libretranslate/libretranslate.cpp b/src/translator/libretranslate/libretranslate.cpp index b198268..8cc6926 100644 --- a/src/translator/libretranslate/libretranslate.cpp +++ b/src/translator/libretranslate/libretranslate.cpp @@ -17,12 +17,11 @@ *****************************************************************************/ #include -#include -#include "../../core/http_request.h" +#include #include "libretranslate.h" +using namespace bot::http; using namespace bot::translator; using namespace std::chrono_literals; -using namespace std::string_literals; libretranslate::libretranslate(const std::string &hostname, uint16_t port, const std::string &url, bool tls, const std::string apiKey) : m_hostname(hostname), m_port(port), m_url(url), m_tls(tls), m_apiKey(apiKey) @@ -43,8 +42,7 @@ const std::vector libretranslate::get_languages() } try { - http_request request; - http_response response = request.get(http_request::legacy_url(m_hostname, m_port, m_url + "languages"s, m_tls)); + http_response response = m_http.get(http_request::legacy_url(m_hostname, m_port, m_url + "languages", m_tls)); if (response.status == 200) { const dpp::json json_response = dpp::json::parse(response.content); if (json_response.is_array()) { @@ -78,23 +76,19 @@ const std::vector libretranslate::get_languages() const std::string libretranslate::translate(const std::string &text, const std::string &source, const std::string &target) { - const dpp::http_headers http_headers = { - {"Content-Type"s, "application/json"s} - }; - dpp::json json_body = { - {"q"s, text}, - {"source"s, source.empty() ? "auto"s : source}, - {"target"s, target}, - {"format"s, "text"s} + {"q", text}, + {"source", source.empty() ? "auto" : source}, + {"target", target}, + {"format", "text"} }; if (!m_apiKey.empty()) json_body["apiKey"] = m_apiKey; try { - http_request request; - http_response response = request.post(http_request::legacy_url(m_hostname, m_port, m_url + "translate"s, m_tls), json_body.dump(), "application/json"); + http_response response = m_http.post(http_request::legacy_url(m_hostname, m_port, m_url + "translate", m_tls), json_body.dump(), + {{"Content-Type", "application/json"}}); if (response.status == 200) { const dpp::json json_response = dpp::json::parse(response.content); if (json_response.is_object()) { diff --git a/src/translator/libretranslate/libretranslate.h b/src/translator/libretranslate/libretranslate.h index 04c0439..d0237ec 100644 --- a/src/translator/libretranslate/libretranslate.h +++ b/src/translator/libretranslate/libretranslate.h @@ -20,7 +20,7 @@ #define TRANSLATOR_LIBRETRANSLATE_H #include -#include +#include "../../core/http_request.h" #include "../../core/translator.h" namespace bot { @@ -36,6 +36,7 @@ namespace bot { private: std::string m_apiKey; std::string m_hostname; + bot::http::http_request m_http; supported_languages m_languages; uint16_t m_port; std::string m_url; diff --git a/src/translator/lingvatranslate/lingvatranslate.cpp b/src/translator/lingvatranslate/lingvatranslate.cpp index 1159f24..e9eaad1 100644 --- a/src/translator/lingvatranslate/lingvatranslate.cpp +++ b/src/translator/lingvatranslate/lingvatranslate.cpp @@ -17,13 +17,12 @@ *****************************************************************************/ #include -#include #include -#include "../../core/http_request.h" +#include #include "lingvatranslate.h" +using namespace bot::http; using namespace bot::translator; using namespace std::chrono_literals; -using namespace std::string_literals; lingvatranslate::lingvatranslate(const std::string &hostname, uint16_t port, const std::string &url, bool tls) : m_hostname(hostname), m_port(port), m_url(url), m_tls(tls) @@ -44,8 +43,7 @@ const std::vector lingvatranslate::get_languages() } try { - http_request request; - http_response response = request.get(http_request::legacy_url(m_hostname, m_port, m_url + "api/v1/languages/target"s, m_tls)); + http_response response = m_http.get(http_request::legacy_url(m_hostname, m_port, m_url + "api/v1/languages/target", m_tls)); if (response.status == 200) { const dpp::json json_response = dpp::json::parse(response.content); if (json_response.is_object()) { @@ -83,8 +81,7 @@ const std::vector lingvatranslate::get_languages() const std::string lingvatranslate::translate(const std::string &text, const std::string &source, const std::string &target) { try { - http_request request; - http_response response = request.get(http_request::legacy_url(m_hostname, m_port, m_url + "api/v1/"s + (source.empty() ? "auto"s : source) + "/"s + target + "/"s + dpp::utility::url_encode(text), m_tls)); + http_response response = m_http.get(http_request::legacy_url(m_hostname, m_port, m_url + "api/v1/" + (source.empty() ? "auto" : source) + "/" + target + "/" + dpp::utility::url_encode(text), m_tls)); if (response.status == 200) { const dpp::json json_response = dpp::json::parse(response.content); if (json_response.is_object()) { diff --git a/src/translator/lingvatranslate/lingvatranslate.h b/src/translator/lingvatranslate/lingvatranslate.h index cf65739..c18b67b 100644 --- a/src/translator/lingvatranslate/lingvatranslate.h +++ b/src/translator/lingvatranslate/lingvatranslate.h @@ -20,7 +20,7 @@ #define TRANSLATOR_LINGVATRANSLATE_H #include -#include +#include "../../core/http_request.h" #include "../../core/translator.h" namespace bot { @@ -35,6 +35,7 @@ namespace bot { private: std::string m_hostname; + bot::http::http_request m_http; supported_languages m_languages; uint16_t m_port; std::string m_url; diff --git a/src/translator/mozhi/mozhi.cpp b/src/translator/mozhi/mozhi.cpp index 6645985..5231113 100644 --- a/src/translator/mozhi/mozhi.cpp +++ b/src/translator/mozhi/mozhi.cpp @@ -17,13 +17,12 @@ *****************************************************************************/ #include -#include #include -#include "../../core/http_request.h" +#include #include "mozhi.h" +using namespace bot::http; using namespace bot::translator; using namespace std::chrono_literals; -using namespace std::string_literals; mozhi::mozhi(const std::string &hostname, uint16_t port, const std::string &url, bool tls, const std::string &engine) : m_hostname(hostname), m_port(port), m_url(url), m_tls(tls), m_engine(engine) @@ -45,10 +44,9 @@ const std::vector mozhi::get_languages() try { const std::string parameters = dpp::utility::make_url_parameters({ - {"engine"s, m_engine} + {"engine", m_engine} }); - http_request request; - http_response response = request.get(http_request::legacy_url(m_hostname, m_port, m_url + "api/target_languages"s, m_tls)); + http_response response = m_http.get(http_request::legacy_url(m_hostname, m_port, m_url + "api/target_languages", m_tls)); if (response.status == 200) { const dpp::json json_response = dpp::json::parse(response.content); if (json_response.is_array()) { @@ -84,13 +82,12 @@ const std::string mozhi::translate(const std::string &text, const std::string &s { try { const std::string parameters = dpp::utility::make_url_parameters({ - {"engine"s, m_engine}, - {"from"s, source.empty() ? "auto"s : source}, - {"to"s, target}, - {"text"s, text} + {"engine", m_engine}, + {"from", source.empty() ? "auto" : source}, + {"to", target}, + {"text", text} }); - http_request request; - http_response response = request.get(http_request::legacy_url(m_hostname, m_port, m_url + "api/translate"s + parameters, m_tls)); + http_response response = m_http.get(http_request::legacy_url(m_hostname, m_port, m_url + "api/translate" + parameters, m_tls)); if (response.status == 200) { const dpp::json json_response = dpp::json::parse(response.content); if (json_response.is_object()) { diff --git a/src/translator/mozhi/mozhi.h b/src/translator/mozhi/mozhi.h index 1602096..fb40aa4 100644 --- a/src/translator/mozhi/mozhi.h +++ b/src/translator/mozhi/mozhi.h @@ -20,7 +20,7 @@ #define TRANSLATOR_MOZHI_H #include -#include +#include "../../core/http_request.h" #include "../../core/translator.h" namespace bot { @@ -36,6 +36,7 @@ namespace bot { private: std::string m_engine; std::string m_hostname; + bot::http::http_request m_http; supported_languages m_languages; uint16_t m_port; std::string m_url;