mirror of
https://github.com/Syping/dtranslatebot.git
synced 2025-08-21 01:08:13 +02:00
Compare commits
53 commits
Author | SHA1 | Date | |
---|---|---|---|
|
c76210a30c | ||
|
b2da36e576 | ||
|
13d384b14e | ||
|
2da43810a1 | ||
|
b318df79e1 | ||
|
d6d22d34a8 | ||
|
24a7b3bc99 | ||
|
1dc2b2dffa | ||
|
691e46a507 | ||
|
a42932de12 | ||
|
6d89aef67c | ||
|
500c43d4e6 | ||
|
e94fbbf5ac | ||
|
f98478bc4d | ||
|
6bcef831c9 | ||
|
420f536c9b | ||
|
4e71f417d0 | ||
|
b1329aa961 | ||
|
0e369f5a1d | ||
|
42755811aa | ||
|
24c14efce2 | ||
|
6764c9c2f3 | ||
|
9a5f37929a | ||
|
66a504ac55 | ||
|
7d8bbd12ce | ||
|
9380dd14ea | ||
|
382f029c3b | ||
|
6a89203415 | ||
|
6f6b5eaa69 | ||
|
fb709b8919 | ||
|
94429ca718 | ||
|
de121beaac | ||
|
0dfb2cebe9 | ||
|
92d9aba8d0 | ||
|
0dbf987ff2 | ||
|
616ce0055b | ||
|
c8239e2517 | ||
|
d0139afd26 | ||
|
67b4b73400 | ||
|
6220277305 | ||
|
dd2de72f94 | ||
|
024400be46 | ||
|
bb099d644a | ||
|
c21ed31889 | ||
|
820593ca2d | ||
|
4fe57d1a24 | ||
|
716a03c43b | ||
|
912ac1eced | ||
|
87961fe611 | ||
|
5191dcbefc | ||
|
531c24b050 | ||
|
46b80f3bdf | ||
|
ea2c6c460f |
46 changed files with 1524 additions and 352 deletions
.gitattributes
.github/workflows
CMakeLists.txtREADME.mdcmake
etc
rpmsrc
src
core
database.cppdatabase.hmain.cppmessage_queue.cppmessage_queue.hregex.hsettings.cppsettings.hsettings_types.hslashcommands.cppslashcommands.hsubmit_queue.cppsubmit_queue.htranslator.cpptranslator.hwebhook_push.cppwebhook_push.h
database/file
resources/win32
systemd
translator
deepl
libretranslate
lingvatranslate
mozhi
stub
16
.gitattributes
vendored
Normal file
16
.gitattributes
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
* text=auto eol=lf
|
||||
|
||||
# Configuration files
|
||||
*.json text eol=crlf
|
||||
|
||||
# Development files
|
||||
CMakeLists.txt text eol=lf
|
||||
*.cmake text eol=lf
|
||||
*.cpp text eol=lf
|
||||
*.h text eol=lf
|
||||
|
||||
# BSD and Linux development files
|
||||
*.pc.in text eol=lf
|
||||
|
||||
# Windows development files
|
||||
*.rc.in text encoding=cp1252 eol=crlf
|
45
.github/workflows/linux-rpm.yml
vendored
Normal file
45
.github/workflows/linux-rpm.yml
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
name: Linux
|
||||
on: push
|
||||
jobs:
|
||||
Release:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- name: Enterprise Linux 7
|
||||
version: el7
|
||||
- name: Enterprise Linux 8
|
||||
version: el8
|
||||
- name: Enterprise Linux 9
|
||||
version: el9
|
||||
- name: openSUSE Leap 15.5
|
||||
version: lp155
|
||||
steps:
|
||||
- name: Cloning
|
||||
uses: actions/checkout@v4
|
||||
- name: Preparing
|
||||
run: mkdir -m 777 ${{github.workspace}}/rpms
|
||||
- name: Build RPM
|
||||
uses: addnab/docker-run-action@v3
|
||||
with:
|
||||
image: docker.io/syping/dtranslatebot-build:${{matrix.version}}
|
||||
options: -v ${{github.workspace}}:/home/rpmbuild/dtranslatebot -v ${{github.workspace}}/rpms:/home/rpmbuild/rpmbuild/RPMS
|
||||
run: |
|
||||
VERSION=$(cat dtranslatebot/CMakeLists.txt | grep -oP "project\(dtranslatebot VERSION \K(\S*)(?= LANGUAGES CXX\))")
|
||||
mkdir -p dtranslatebot-$VERSION
|
||||
shopt -s extglob
|
||||
cp -R dtranslatebot/!(rpms|rpmsrc) \
|
||||
dtranslatebot-$VERSION
|
||||
tar cfz dtranslatebot-$VERSION.tar.gz dtranslatebot-$VERSION
|
||||
cp dtranslatebot-$VERSION.tar.gz \
|
||||
dtranslatebot/rpmsrc/!(*.spec) \
|
||||
rpmbuild/SOURCES
|
||||
cp dtranslatebot/rpmsrc/*.spec \
|
||||
rpmbuild/SPECS
|
||||
rpmbuild -ba rpmbuild/SPECS/dtranslatebot.spec
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{matrix.name}}
|
||||
path: |
|
||||
${{github.workspace}}/rpms/x86_64/*.rpm
|
43
.github/workflows/windows.yml
vendored
Normal file
43
.github/workflows/windows.yml
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
name: Windows
|
||||
on: push
|
||||
jobs:
|
||||
Release:
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: Setup MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: clang64
|
||||
update: true
|
||||
install: >-
|
||||
git
|
||||
make
|
||||
mingw-w64-clang-x86_64-clang
|
||||
mingw-w64-clang-x86_64-cmake
|
||||
mingw-w64-clang-x86_64-ninja
|
||||
perl
|
||||
- name: Cloning
|
||||
uses: actions/checkout@v4
|
||||
- name: Configure CMake
|
||||
run: cmake -B dtranslatebot-build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_EXE_LINKER_FLAGS="-static -lc++" -DWITH_DPP_STATIC_BUNDLE=TRUE -GNinja
|
||||
- name: Download and build OpenSSL
|
||||
run: cmake --build dtranslatebot-build --config ${{env.BUILD_TYPE}} --target OpenSSL
|
||||
- name: Download and build zlib
|
||||
run: cmake --build dtranslatebot-build --config ${{env.BUILD_TYPE}} --target ZLIB
|
||||
- name: Download and build DPP
|
||||
run: cmake --build dtranslatebot-build --config ${{env.BUILD_TYPE}} --target DPP
|
||||
- name: Build dtranslatebot
|
||||
run: cmake --build dtranslatebot-build --config ${{env.BUILD_TYPE}}
|
||||
- name: Install
|
||||
run: cmake --install dtranslatebot-build --config ${{env.BUILD_TYPE}} --prefix dtranslatebot-install --strip
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Windows
|
||||
path: |
|
||||
dtranslatebot-install/bin/dtranslatebot.exe
|
|
@ -17,34 +17,43 @@
|
|||
****************************************************************************]]
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(dtranslatebot VERSION 0.1 LANGUAGES CXX)
|
||||
cmake_policy(VERSION 3.16...3.27)
|
||||
project(dtranslatebot VERSION 0.2.0 LANGUAGES CXX)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# dtranslatebot Source files
|
||||
set(DTRANSLATEBOT_HEADERS
|
||||
src/database_core.h
|
||||
src/database_file.h
|
||||
src/message_queue.h
|
||||
src/regex.h
|
||||
src/settings.h
|
||||
src/settings_types.h
|
||||
src/slashcommands.h
|
||||
src/submit_queue.h
|
||||
src/translator_core.h
|
||||
src/translator_libretranslate.h
|
||||
src/webhook_push.h
|
||||
src/core/database.h
|
||||
src/core/message_queue.h
|
||||
src/core/regex.h
|
||||
src/core/settings.h
|
||||
src/core/settings_types.h
|
||||
src/core/slashcommands.h
|
||||
src/core/submit_queue.h
|
||||
src/core/translator.h
|
||||
src/core/webhook_push.h
|
||||
src/database/file/file.h
|
||||
src/translator/deepl/deepl.h
|
||||
src/translator/mozhi/mozhi.h
|
||||
src/translator/libretranslate/libretranslate.h
|
||||
src/translator/lingvatranslate/lingvatranslate.h
|
||||
src/translator/stub/stub.h
|
||||
)
|
||||
set(DTRANSLATEBOT_SOURCES
|
||||
src/database_core.cpp
|
||||
src/database_file.cpp
|
||||
src/main.cpp
|
||||
src/message_queue.cpp
|
||||
src/settings.cpp
|
||||
src/slashcommands.cpp
|
||||
src/submit_queue.cpp
|
||||
src/translator_core.cpp
|
||||
src/translator_libretranslate.cpp
|
||||
src/webhook_push.cpp
|
||||
src/core/database.cpp
|
||||
src/core/main.cpp
|
||||
src/core/message_queue.cpp
|
||||
src/core/settings.cpp
|
||||
src/core/slashcommands.cpp
|
||||
src/core/submit_queue.cpp
|
||||
src/core/translator.cpp
|
||||
src/core/webhook_push.cpp
|
||||
src/database/file/file.cpp
|
||||
src/translator/deepl/deepl.cpp
|
||||
src/translator/mozhi/mozhi.cpp
|
||||
src/translator/libretranslate/libretranslate.cpp
|
||||
src/translator/lingvatranslate/lingvatranslate.cpp
|
||||
src/translator/stub/stub.cpp
|
||||
)
|
||||
|
||||
# dtranslatebot Module Path
|
||||
|
@ -63,21 +72,59 @@ if (WITH_BOOST)
|
|||
endif()
|
||||
|
||||
# D++ Discord API Library for Bots
|
||||
find_package(DPP REQUIRED)
|
||||
option(WITH_DPP_STATIC_BUNDLE "Build with DPP Static Bundle" OFF)
|
||||
if (WITH_DPP_STATIC_BUNDLE)
|
||||
include(DPPStaticBundle)
|
||||
else()
|
||||
find_package(DPP REQUIRED)
|
||||
endif()
|
||||
|
||||
# pthread Support
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# dtranslatebot Win32 Shared Resources
|
||||
if (WIN32)
|
||||
configure_file(src/resources/win32/dtranslatebot.rc.in "${dtranslatebot_BINARY_DIR}/resources/win32/dtranslatebot.rc" @ONLY)
|
||||
list(APPEND DTRANSLATEBOT_RESOURCES
|
||||
"${dtranslatebot_BINARY_DIR}/resources/win32/dtranslatebot.rc"
|
||||
)
|
||||
endif()
|
||||
|
||||
# dtranslatebot systemd Service
|
||||
if (UNIX AND NOT APPLE)
|
||||
option(WITH_SYSTEMD "Build with systemd Support" OFF)
|
||||
if (WITH_SYSTEMD)
|
||||
find_program(SYSTEMD_ESCAPE_EXECUTABLE NAMES systemd-escape)
|
||||
if (DEFINED SYSTEMD_ESCAPE_EXECUTABLE)
|
||||
execute_process(
|
||||
COMMAND "${SYSTEMD_ESCAPE_EXECUTABLE}" "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/dtranslatebot"
|
||||
OUTPUT_VARIABLE dtranslatebot_SERVICE_WORKDIR
|
||||
)
|
||||
string(STRIP "${dtranslatebot_SERVICE_WORKDIR}" dtranslatebot_SERVICE_WORKDIR)
|
||||
else()
|
||||
set(dtranslatebot_SERVICE_WORKDIR "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/dtranslatebot")
|
||||
endif()
|
||||
configure_file(src/systemd/dtranslatebot.service.in "${dtranslatebot_BINARY_DIR}/systemd/service/dtranslatebot.service" @ONLY)
|
||||
configure_file(src/systemd/dtranslatebot.sysusersd.in "${dtranslatebot_BINARY_DIR}/systemd/sysusers.d/dtranslatebot.conf" @ONLY)
|
||||
install(FILES "${dtranslatebot_BINARY_DIR}/systemd/service/dtranslatebot.service" DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/systemd/system")
|
||||
install(FILES "${dtranslatebot_BINARY_DIR}/systemd/sysusers.d/dtranslatebot.conf" DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/sysusers.d")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# dtranslatebot Target + Installs
|
||||
add_executable(dtranslatebot ${DTRANSLATEBOT_HEADERS} ${DTRANSLATEBOT_SOURCES})
|
||||
add_executable(dtranslatebot ${DTRANSLATEBOT_HEADERS} ${DTRANSLATEBOT_SOURCES} ${DTRANSLATEBOT_RESOURCES})
|
||||
if (WITH_DPP_STATIC_BUNDLE)
|
||||
add_dependencies(dtranslatebot DPP)
|
||||
endif()
|
||||
target_compile_definitions(dtranslatebot PRIVATE
|
||||
${DPP_DEFINITIONS}
|
||||
$<$<BOOL:${DTRANSLATEBOT_USE_BOOST_REGEX}>:DTRANSLATEBOT_USE_BOOST_REGEX>
|
||||
)
|
||||
if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914)
|
||||
target_compile_options(dtranslatebot PRIVATE $<$<COMPILE_LANGUAGE:CXX>:/Zc:__cplusplus>)
|
||||
endif()
|
||||
target_link_libraries(dtranslatebot PRIVATE Threads::Threads ${DPP_LIBRARIES} ${DTRANSLATEBOT_LIBRARIES})
|
||||
target_link_libraries(dtranslatebot PRIVATE ${DTRANSLATEBOT_LIBRARIES} ${DPP_LIBRARIES} Threads::Threads)
|
||||
target_include_directories(dtranslatebot PRIVATE ${DPP_INCLUDE_DIR})
|
||||
set_target_properties(dtranslatebot PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
|
|
13
README.md
13
README.md
|
@ -2,7 +2,7 @@
|
|||
Open Source Discord Translation Bot
|
||||
|
||||
- Translate incoming channel messages to a Webhook
|
||||
- Support configuration through slashcommands and JSON
|
||||
- Support configuration through slash commands and JSON
|
||||
- Cross-Platform
|
||||
|
||||
#### Build Dependencies
|
||||
|
@ -10,8 +10,11 @@ Open Source Discord Translation Bot
|
|||
- Compiler with C++17 Support
|
||||
- [D++: A C++ Discord API Library for Bots](https://dpp.dev/)
|
||||
|
||||
#### Runtime Dependencies
|
||||
- [LibreTranslate](https://libretranslate.com/)
|
||||
#### Supported Translation Engines
|
||||
- [LibreTranslate](https://libretranslate.com/) (Default)
|
||||
- [Lingva Translate](https://lingva.ml/)
|
||||
- [Mozhi](https://codeberg.org/aryak/mozhi)
|
||||
- [DeepL](https://deepl.com/) (Experimental)
|
||||
|
||||
#### Build dtranslatebot
|
||||
|
||||
|
@ -23,4 +26,6 @@ sudo cmake --install dtranslatebot-build
|
|||
```
|
||||
|
||||
##### Optional CMake flags
|
||||
`-DWITH_BOOST=TRUE`
|
||||
`-DWITH_BOOST=TRUE`
|
||||
`-DWITH_DPP_STATIC_BUNDLE=TRUE`
|
||||
`-DWITH_SYSTEMD=TRUE`
|
||||
|
|
65
cmake/ArgumentPassthrough.cmake
Normal file
65
cmake/ArgumentPassthrough.cmake
Normal file
|
@ -0,0 +1,65 @@
|
|||
#[[**************************************************************************
|
||||
* dtranslatebot Discord Translate Bot
|
||||
* Copyright (C) 2024 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.
|
||||
****************************************************************************]]
|
||||
|
||||
if (DEFINED CMAKE_BUILD_TYPE)
|
||||
list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
|
||||
endif()
|
||||
if (DEFINED CMAKE_C_COMPILER)
|
||||
list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}")
|
||||
list(APPEND CMAKE_PASSTHROUGH_ENV "CC=${CMAKE_C_COMPILER}")
|
||||
elseif ("$ENV{MSYSTEM}" STREQUAL "CLANG64")
|
||||
list(APPEND CMAKE_PASSTHROUGH_ENV "CC=clang")
|
||||
endif()
|
||||
if (DEFINED CMAKE_C_COMPILER_TARGET)
|
||||
list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_C_COMPILER_TARGET=${CMAKE_C_COMPILER_TARGET}")
|
||||
endif()
|
||||
if (DEFINED CMAKE_CXX_COMPILER)
|
||||
list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}")
|
||||
list(APPEND CMAKE_PASSTHROUGH_ENV "CXX=${CMAKE_CXX_COMPILER}")
|
||||
elseif ("$ENV{MSYSTEM}" STREQUAL "CLANG64")
|
||||
list(APPEND CMAKE_PASSTHROUGH_ENV "CXX=clang++")
|
||||
endif()
|
||||
if (DEFINED CMAKE_CXX_COMPILER_TARGET)
|
||||
list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_CXX_COMPILER_TARGET=${CMAKE_CXX_COMPILER_TARGET}")
|
||||
endif()
|
||||
if (DEFINED CMAKE_RC_COMPILER)
|
||||
list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_RC_COMPILER=${CMAKE_RC_COMPILER}")
|
||||
endif()
|
||||
if (DEFINED CMAKE_STRIP)
|
||||
list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_STRIP=${CMAKE_STRIP}")
|
||||
endif()
|
||||
if (DEFINED CMAKE_SYSROOT)
|
||||
list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_SYSROOT=${CMAKE_SYSROOT}")
|
||||
endif()
|
||||
if (DEFINED CMAKE_SYSTEM_NAME AND NOT CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME)
|
||||
list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}")
|
||||
endif()
|
||||
if (DEFINED CMAKE_SYSTEM_PROCESSOR AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL CMAKE_HOST_SYSTEM_PROCESSOR)
|
||||
list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
if (DEFINED CMAKE_SYSTEM_VERSION AND NOT CMAKE_SYSTEM_VERSION STREQUAL CMAKE_HOST_SYSTEM_VERSION)
|
||||
list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}")
|
||||
endif()
|
||||
if (DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||
list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}")
|
||||
endif()
|
||||
if (DEFINED CMAKE_PASSTHROUGH_ENV)
|
||||
set(CMAKE_PASSTHROUGH_ENV
|
||||
"${CMAKE_COMMAND}" -E env ${CMAKE_PASSTHROUGH_ENV}
|
||||
)
|
||||
endif()
|
119
cmake/DPPStaticBundle.cmake
Normal file
119
cmake/DPPStaticBundle.cmake
Normal file
|
@ -0,0 +1,119 @@
|
|||
#[[**************************************************************************
|
||||
* dtranslatebot Discord Translate Bot
|
||||
* Copyright (C) 2024 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(ArgumentPassthrough)
|
||||
|
||||
# OpenSSL needs to be configured with perl and build with make
|
||||
find_program(MAKE_EXECUTABLE NAMES make gmake)
|
||||
if (NOT DEFINED MAKE_EXECUTABLE)
|
||||
message(SEND_ERROR "make not found")
|
||||
endif()
|
||||
|
||||
find_program(NPROC_EXECUTABLE nproc)
|
||||
if (DEFINED NPROC_EXECUTABLE)
|
||||
execute_process(
|
||||
COMMAND "${NPROC_EXECUTABLE}"
|
||||
OUTPUT_VARIABLE NPROC
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
set(MAKE_JOBS_ARG "-j${NPROC}")
|
||||
endif()
|
||||
|
||||
find_program(PERL_EXECUTABLE NAMES perl)
|
||||
if (NOT DEFINED PERL_EXECUTABLE)
|
||||
message(SEND_ERROR "perl not found")
|
||||
endif()
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(ZLIB
|
||||
URL https://www.zlib.net/zlib-1.3.1.tar.xz
|
||||
URL_HASH SHA256=38ef96b8dfe510d42707d9c781877914792541133e1870841463bfa73f883e32
|
||||
CMAKE_ARGS
|
||||
-DBUILD_SHARED_LIBS=OFF
|
||||
${CMAKE_PASSTHROUGH_ARGS}
|
||||
"-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>"
|
||||
-DZLIB_BUILD_EXAMPLES=OFF
|
||||
${ZLIB_CONFIGURE_ARGS}
|
||||
)
|
||||
ExternalProject_Get_Property(ZLIB INSTALL_DIR)
|
||||
set(ZLIB_INSTALL_DIR "${INSTALL_DIR}")
|
||||
|
||||
set(OPENSSL_PLATFORM_ARG $<$<BOOL:$ENV{MSYSTEM}>:mingw64>)
|
||||
ExternalProject_Add(OpenSSL
|
||||
URL https://github.com/openssl/openssl/releases/download/openssl-3.0.17/openssl-3.0.17.tar.gz
|
||||
URL_HASH SHA256=dfdd77e4ea1b57ff3a6dbde6b0bdc3f31db5ac99e7fdd4eaf9e1fbb6ec2db8ce
|
||||
CONFIGURE_COMMAND
|
||||
${CMAKE_PASSTHROUGH_ENV}
|
||||
"${PERL_EXECUTABLE}"
|
||||
"<SOURCE_DIR>/Configure"
|
||||
"--prefix=<INSTALL_DIR>"
|
||||
$<$<CONFIG:Debug>:-d>
|
||||
no-dso
|
||||
no-dtls
|
||||
no-engine
|
||||
no-shared
|
||||
no-zlib
|
||||
${OPENSSL_PLATFORM_ARG}
|
||||
${OPENSSL_CONFIGURE_ARGS}
|
||||
BUILD_COMMAND "${MAKE_EXECUTABLE}" ${MAKE_JOBS_ARG} build_libs
|
||||
INSTALL_COMMAND "${MAKE_EXECUTABLE}" ${MAKE_JOBS_ARG} install_dev
|
||||
)
|
||||
ExternalProject_Get_Property(OpenSSL INSTALL_DIR)
|
||||
set(OpenSSL_INSTALL_DIR "${INSTALL_DIR}")
|
||||
|
||||
ExternalProject_Add(DPP
|
||||
URL https://github.com/brainboxdotcc/DPP/archive/refs/tags/v10.1.3.tar.gz
|
||||
URL_HASH SHA256=a32d94dcd6b23430afff82918234e4e28e0616bd2ddf743c5ab2f1778c5a600b
|
||||
CMAKE_ARGS
|
||||
-DAVX_TYPE=AVX0
|
||||
-DBUILD_SHARED_LIBS=OFF
|
||||
-DBUILD_VOICE_SUPPORT=OFF
|
||||
${CMAKE_PASSTHROUGH_ARGS}
|
||||
"-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>"
|
||||
-DDPP_BUILD_TEST=OFF
|
||||
-DDPP_NO_CORO=ON
|
||||
-DDPP_NO_VCPKG=ON
|
||||
-DRUN_LDCONFIG=OFF
|
||||
"-DOpenSSL_ROOT=${OpenSSL_INSTALL_DIR}"
|
||||
"-DZLIB_ROOT=${ZLIB_INSTALL_DIR}"
|
||||
${DPP_CONFIGURE_ARGS}
|
||||
DEPENDS OpenSSL ZLIB
|
||||
)
|
||||
ExternalProject_Get_Property(DPP INSTALL_DIR)
|
||||
set(DPP_INSTALL_DIR "${INSTALL_DIR}")
|
||||
set(DPP_INCLUDE_DIR "${DPP_INSTALL_DIR}/include")
|
||||
set(DPP_LIBRARIES
|
||||
-Wl,-Bstatic
|
||||
"-L${DPP_INSTALL_DIR}/lib"
|
||||
"-L${DPP_INSTALL_DIR}/lib64"
|
||||
dpp
|
||||
"-L${OpenSSL_INSTALL_DIR}/lib"
|
||||
"-L${OpenSSL_INSTALL_DIR}/lib64"
|
||||
ssl
|
||||
crypto
|
||||
"-L${ZLIB_INSTALL_DIR}/lib"
|
||||
"-L${ZLIB_INSTALL_DIR}/lib64"
|
||||
$<IF:$<BOOL:${WIN32}>,zlibstatic,z>
|
||||
-Wl,-Bdynamic
|
||||
)
|
||||
if (WIN32)
|
||||
set(DPP_DEFINITIONS DPP_STATIC)
|
||||
list(APPEND DPP_LIBRARIES
|
||||
ws2_32
|
||||
)
|
||||
endif()
|
|
@ -1,4 +1,4 @@
|
|||
find_path(DPP_INCLUDE_DIR NAMES dpp/dpp.h HINTS ${DPP_ROOT_DIR})
|
||||
find_library(DPP_LIBRARIES NAMES dpp "libdpp.a" HINTS ${DPP_ROOT_DIR})
|
||||
find_path(DPP_INCLUDE_DIR NAMES "dpp/dpp.h" HINTS "${DPP_ROOT_DIR}")
|
||||
find_library(DPP_LIBRARIES NAMES "dpp" "libdpp.a" HINTS "${DPP_ROOT_DIR}")
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(DPP DEFAULT_MSG DPP_LIBRARIES DPP_INCLUDE_DIR)
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
{
|
||||
"guilds": {
|
||||
"$guild1_id": {
|
||||
"$channel1_id": {
|
||||
"source": "en",
|
||||
"target": "de",
|
||||
"webhook": "https://discord.com/api/webhooks/$guild1_de_webhook_id/$guild1_de_webhook_token"
|
||||
},
|
||||
"$channel2_id": {
|
||||
"source": "de",
|
||||
"target": "en",
|
||||
"webhook": "https://discord.com/api/webhooks/$guild1_en_webhook_id/$guild1_en_webhook_token"
|
||||
}
|
||||
},
|
||||
"My Discord Guild": {
|
||||
"id": $guild2_id,
|
||||
"General English": {
|
||||
"id": $channel3_id,
|
||||
"source": "en",
|
||||
"target": {
|
||||
"de": "https://discord.com/api/webhooks/$guild2_de_webhook_id/$guild2_de_webhook_token",
|
||||
"fr": "https://discord.com/api/webhooks/$guild2_fr_webhook_id/$guild2_fr_webhook_token"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"preferred_lang": ["en", "de", "fr", ...],
|
||||
"storage": "$working_directory",
|
||||
"user": {
|
||||
"avatar_size": 256
|
||||
},
|
||||
"token": "$bot_token",
|
||||
"translator": {
|
||||
"url": "http://127.0.0.1:5000/",
|
||||
"apiKey": ""
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"token": "",
|
||||
"translator": {
|
||||
"url": "http://127.0.0.1:5000/",
|
||||
"apiKey": ""
|
||||
}
|
||||
}
|
14
rpmsrc/dtranslatebot.json
Normal file
14
rpmsrc/dtranslatebot.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
/*
|
||||
A DISCORD BOT TOKEN IS NECESSARY TO USE THIS APPLICATION!
|
||||
|
||||
You can get a Bot Token from the Discord Developer Portal
|
||||
by creating a New Application:
|
||||
https://discord.com/developers/applications
|
||||
*/
|
||||
|
||||
"token": "",
|
||||
"translator": {
|
||||
"type": "stub"
|
||||
}
|
||||
}
|
13
rpmsrc/dtranslatebot.service
Normal file
13
rpmsrc/dtranslatebot.service
Normal file
|
@ -0,0 +1,13 @@
|
|||
[Unit]
|
||||
Description=Discord Translation Bot
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
User=dtranslatebot
|
||||
Group=dtranslatebot
|
||||
WorkingDirectory=/var/lib/dtranslatebot
|
||||
ExecStart=/usr/bin/dtranslatebot /etc/dtranslatebot.json
|
||||
Restart=on-abnormal
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
96
rpmsrc/dtranslatebot.spec
Normal file
96
rpmsrc/dtranslatebot.spec
Normal file
|
@ -0,0 +1,96 @@
|
|||
%global _lto_cflags %{?_lto_cflags} -ffat-lto-objects
|
||||
|
||||
%if 0%{?rhel} && 0%{?rhel} < 8
|
||||
%global cmake %{?cmake3}
|
||||
%global cmake_build %{?cmake3_build}
|
||||
%global cmake_install %{?cmake3_install}
|
||||
%global cmake_suffix 3
|
||||
%global toolset_prefix devtoolset-9-
|
||||
%endif
|
||||
%if 0%{?rhel} && 0%{?rhel} == 8
|
||||
%global toolset_prefix gcc-toolset-9-
|
||||
%endif
|
||||
%if 0%{?suse_version} && 0%{?suse_version} < 1600
|
||||
%global toolset_version 9
|
||||
%endif
|
||||
|
||||
Name: dtranslatebot
|
||||
Version: 0.2.0
|
||||
Release: 1%{?dist}
|
||||
Summary: Discord Translation Bot
|
||||
License: BSD-2-Clause
|
||||
URL: https://github.com/Syping/%{name}
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
Source1: %{name}.json
|
||||
Source2: %{name}.service
|
||||
Source3: %{name}.sysusersd
|
||||
|
||||
%if 0%{?fedora} || 0%{?rhel}
|
||||
BuildRequires: %{?toolset_prefix}annobin
|
||||
%if 0%{?rhel} && 0%{?rhel} < 9
|
||||
BuildRequires: epel-rpm-macros-systemd
|
||||
%endif
|
||||
%endif
|
||||
BuildRequires: cmake%{?cmake_suffix}
|
||||
BuildRequires: %{?toolset_prefix}gcc%{?toolset_version}-c++
|
||||
BuildRequires: make
|
||||
BuildRequires: perl(IPC::Cmd)
|
||||
BuildRequires: systemd-rpm-macros
|
||||
%systemd_requires
|
||||
%if 0%{?fedora} || 0%{?rhel}
|
||||
%sysusers_requires_compat
|
||||
%endif
|
||||
|
||||
%description
|
||||
dtranslatebot is a Discord Bot which translate incoming Discord messages to Discord webhooks.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
%if 0%{?rhel} && 0%{?rhel} < 8
|
||||
source /opt/rh/devtoolset-9/enable
|
||||
%endif
|
||||
%if 0%{?rhel} && 0%{?rhel} == 8
|
||||
source /opt/rh/gcc-toolset-9/enable
|
||||
%endif
|
||||
%cmake \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
%if 0%{?toolset_version}
|
||||
-DCMAKE_C_COMPILER=gcc-%{toolset_version} \
|
||||
-DCMAKE_CXX_COMPILER=g++-%{toolset_version} \
|
||||
%endif
|
||||
-DWITH_DPP_STATIC_BUNDLE=TRUE \
|
||||
-DWITH_SYSTEMD=TRUE
|
||||
%cmake_build
|
||||
|
||||
%install
|
||||
%cmake_install
|
||||
mkdir -p %{buildroot}%{_localstatedir}/lib/%{name}
|
||||
install -p -D -m 0644 %{SOURCE1} %{buildroot}%{_sysconfdir}/%{name}.json
|
||||
install -p -D -m 0644 %{SOURCE2} %{buildroot}%{_unitdir}/%{name}.service
|
||||
install -p -D -m 0644 %{SOURCE3} %{buildroot}%{_sysusersdir}/%{name}.conf
|
||||
|
||||
%pre
|
||||
%if 0%{?fedora} || 0%{?rhel}
|
||||
%sysusers_create_compat %{SOURCE3}
|
||||
%endif
|
||||
%if 0%{?suse_version}
|
||||
%sysusers_create_package %{name} %{SOURCE3}
|
||||
%endif
|
||||
|
||||
%post
|
||||
%systemd_post %{name}.service
|
||||
|
||||
%preun
|
||||
%systemd_preun %{name}.service
|
||||
|
||||
%postun
|
||||
%systemd_postun_with_restart %{name}.service
|
||||
|
||||
%files
|
||||
%{_bindir}/%{name}
|
||||
%{_unitdir}/%{name}.service
|
||||
%{_sysusersdir}/%{name}.conf
|
||||
%config(noreplace) %attr(0640,root,%{name}) %{_sysconfdir}/%{name}.json
|
||||
%dir %attr(0750,%{name},%{name}) %{_localstatedir}/lib/%{name}
|
2
rpmsrc/dtranslatebot.sysusersd
Normal file
2
rpmsrc/dtranslatebot.sysusersd
Normal file
|
@ -0,0 +1,2 @@
|
|||
#Type Name ID GECOS Home directory Shell
|
||||
u dtranslatebot - "Discord Translation Bot" /var/lib/translatebot -
|
|
@ -19,17 +19,9 @@
|
|||
#ifndef NDEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
#include "database_core.h"
|
||||
#include "database.h"
|
||||
using namespace bot::database;
|
||||
|
||||
database::database()
|
||||
{
|
||||
}
|
||||
|
||||
database::~database()
|
||||
{
|
||||
}
|
||||
|
||||
void database::add_channel_target(dpp::snowflake guild_id, dpp::snowflake channel_id, const bot::settings::target &target)
|
||||
{
|
||||
#ifndef NDEBUG
|
|
@ -16,8 +16,8 @@
|
|||
* responsible for anything with use of the software, you are self responsible.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef DATABASE_CORE_H
|
||||
#define DATABASE_CORE_H
|
||||
#ifndef DATABASE_H
|
||||
#define DATABASE_H
|
||||
|
||||
#include "settings_types.h"
|
||||
|
||||
|
@ -30,8 +30,10 @@ namespace bot {
|
|||
|
||||
class database {
|
||||
public:
|
||||
explicit database();
|
||||
virtual ~database();
|
||||
explicit database() = default;
|
||||
database(const database&) = delete;
|
||||
database& operator=(const database&) = delete;
|
||||
virtual ~database() = default;
|
||||
virtual void add_channel_target(dpp::snowflake guild_id, dpp::snowflake channel_id, const bot::settings::target &target);
|
||||
virtual void delete_channel(dpp::snowflake guild_id, dpp::snowflake channel_id);
|
||||
virtual void delete_channel_target(dpp::snowflake guild_id, dpp::snowflake channel_id, const std::string &target);
|
||||
|
@ -52,4 +54,4 @@ namespace bot {
|
|||
}
|
||||
}
|
||||
|
||||
#endif // DATABASE_CORE_H
|
||||
#endif // DATABASE_H
|
|
@ -24,22 +24,39 @@
|
|||
#include "message_queue.h"
|
||||
#include "settings.h"
|
||||
#include "slashcommands.h"
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " [json]" << std::endl;
|
||||
bool flag_wait_for_translator = false;
|
||||
std::vector<std::string> args;
|
||||
for (size_t i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--wait-for-translator"))
|
||||
flag_wait_for_translator = true;
|
||||
else
|
||||
args.push_back(argv[i]);
|
||||
}
|
||||
if (args.size() != 1) {
|
||||
std::cout << "Usage: " << argv[0] << " [--wait-for-translator] [json]" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::cout << "[Launch] Processing configuration..." << std::endl;
|
||||
bot::settings::settings settings;
|
||||
if (!settings.parse_file(argv[1]))
|
||||
if (!settings.parse_file(args.at(0)))
|
||||
return 1;
|
||||
|
||||
std::cout << "[Launch] Requesting supported languages..." << std::endl;
|
||||
if (settings.get_translator()->get_languages().empty()) {
|
||||
std::cerr << "[Error] Failed to initialise translateable languages" << std::endl;
|
||||
return 2;
|
||||
for (;;) {
|
||||
std::cout << "[Launch] Requesting supported languages..." << std::endl;
|
||||
if (!settings.get_translator()->get_languages().empty()) {
|
||||
break;
|
||||
}
|
||||
else if (flag_wait_for_translator) {
|
||||
std::this_thread::sleep_for(5000ms);
|
||||
}
|
||||
else {
|
||||
std::cerr << "[Error] Failed to initialise translateable languages" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
dpp::cluster bot(settings.token(), dpp::i_default_intents | dpp::i_message_content);
|
||||
|
@ -55,7 +72,7 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
bot.on_message_create(std::bind(&bot::message_queue::process_message_event, &message_queue, &bot, &settings, std::placeholders::_1));
|
||||
bot.on_slashcommand(std::bind(&bot::slashcommands::process_command_event, &bot, &settings, std::placeholders::_1));
|
||||
bot.on_ready([&bot, &settings](const dpp::ready_t &event) {
|
||||
bot.on_ready([&bot, &settings]([[maybe_unused]] const dpp::ready_t &event) {
|
||||
if (dpp::run_once<struct register_bot_commands>()) {
|
||||
bot::slashcommands::register_commands(&bot, &settings);
|
||||
}
|
|
@ -19,7 +19,7 @@
|
|||
#include <thread>
|
||||
#include "message_queue.h"
|
||||
#include "settings.h"
|
||||
using namespace bot;
|
||||
using bot::message_queue;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
void message_queue::add(const message &message)
|
||||
|
@ -36,6 +36,10 @@ void message_queue::add(message &&message)
|
|||
|
||||
void message_queue::process_message_event(dpp::cluster *bot, bot::settings::settings *settings, const dpp::message_create_t &event)
|
||||
{
|
||||
// We check for conditions we want to skip translation for
|
||||
if (event.msg.author.id == bot->me.id || event.msg.content.empty() || event.msg.has_thread())
|
||||
return;
|
||||
|
||||
if (event.msg.webhook_id) {
|
||||
const std::lock_guard<bot::settings::settings> guard(*settings);
|
||||
|
||||
|
@ -44,10 +48,6 @@ void message_queue::process_message_event(dpp::cluster *bot, bot::settings::sett
|
|||
return;
|
||||
}
|
||||
|
||||
// Same as before, just without the involvement of webhooks
|
||||
if (event.msg.author.id == bot->me.id)
|
||||
return;
|
||||
|
||||
const std::lock_guard<bot::settings::settings> guard(*settings);
|
||||
if (const bot::settings::channel *channel = settings->get_channel(event.msg.guild_id, event.msg.channel_id)) {
|
||||
bot::message message;
|
|
@ -19,19 +19,23 @@
|
|||
#include <dpp/json.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "database_file.h"
|
||||
#include "settings.h"
|
||||
#include "translator_libretranslate.h"
|
||||
#include "../database/file/file.h"
|
||||
#include "../translator/deepl/deepl.h"
|
||||
#include "../translator/mozhi/mozhi.h"
|
||||
#include "../translator/libretranslate/libretranslate.h"
|
||||
#include "../translator/lingvatranslate/lingvatranslate.h"
|
||||
#include "../translator/stub/stub.h"
|
||||
using namespace bot::settings;
|
||||
|
||||
void process_database_channels(std::shared_ptr<bot::database::database> database, bot::settings::guild *guild, std::vector<dpp::snowflake> *webhookIds)
|
||||
void process_database_channels(std::shared_ptr<bot::database::database> database, bot::settings::guild &guild, std::vector<dpp::snowflake> &webhookIds)
|
||||
{
|
||||
const std::vector<dpp::snowflake> db_channels = database->get_channels(guild->id);
|
||||
const std::vector<dpp::snowflake> db_channels = database->get_channels(guild.id);
|
||||
for (auto db_channel_id = db_channels.begin(); db_channel_id != db_channels.end(); db_channel_id++) {
|
||||
bool channel_found = false;
|
||||
for (auto channel = guild->channel.begin(); channel != guild->channel.end(); channel++) {
|
||||
for (auto channel = guild.channel.begin(); channel != guild.channel.end(); channel++) {
|
||||
if (channel->id == *db_channel_id) {
|
||||
const bot::settings::channel db_channel = database->get_channel(guild->id, channel->id);
|
||||
const bot::settings::channel db_channel = database->get_channel(guild.id, channel->id);
|
||||
if (!db_channel.source.empty())
|
||||
channel->source = db_channel.source;
|
||||
for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++) {
|
||||
|
@ -39,14 +43,14 @@ void process_database_channels(std::shared_ptr<bot::database::database> database
|
|||
for (auto target = channel->targets.begin(); target != channel->targets.end(); target++) {
|
||||
if (target->target == db_target->target) {
|
||||
target->webhook = db_target->webhook;
|
||||
webhookIds->push_back(db_target->webhook.id);
|
||||
webhookIds.push_back(db_target->webhook.id);
|
||||
target_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!target_found) {
|
||||
channel->targets.push_back(*db_target);
|
||||
webhookIds->push_back(db_target->webhook.id);
|
||||
webhookIds.push_back(db_target->webhook.id);
|
||||
}
|
||||
}
|
||||
channel_found = true;
|
||||
|
@ -54,23 +58,23 @@ void process_database_channels(std::shared_ptr<bot::database::database> database
|
|||
}
|
||||
}
|
||||
if (!channel_found) {
|
||||
const bot::settings::channel db_channel = database->get_channel(guild->id, *db_channel_id);
|
||||
guild->channel.push_back(db_channel);
|
||||
const bot::settings::channel db_channel = database->get_channel(guild.id, *db_channel_id);
|
||||
guild.channel.push_back(db_channel);
|
||||
for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++)
|
||||
webhookIds->push_back(db_target->webhook.id);
|
||||
webhookIds.push_back(db_target->webhook.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void process_database(std::shared_ptr<bot::database::database> database, std::vector<guild> *guilds, std::vector<dpp::snowflake> *webhookIds)
|
||||
void process_database(std::shared_ptr<bot::database::database> database, std::vector<guild> &guilds, std::vector<dpp::snowflake> &webhookIds)
|
||||
{
|
||||
std::cout << "[Launch] Loading database..." << std::endl;
|
||||
const std::vector<dpp::snowflake> db_guilds = database->get_guilds();
|
||||
for (auto db_guild_id = db_guilds.begin(); db_guild_id != db_guilds.end(); db_guild_id++) {
|
||||
bool guild_found = false;
|
||||
for (auto guild = guilds->begin(); guild != guilds->end(); guild++) {
|
||||
for (auto guild = guilds.begin(); guild != guilds.end(); guild++) {
|
||||
if (guild->id == *db_guild_id) {
|
||||
process_database_channels(database, &*guild, webhookIds);
|
||||
process_database_channels(database, *guild, webhookIds);
|
||||
guild_found = true;
|
||||
break;
|
||||
}
|
||||
|
@ -78,13 +82,13 @@ void process_database(std::shared_ptr<bot::database::database> database, std::ve
|
|||
if (!guild_found) {
|
||||
bot::settings::guild guild;
|
||||
guild.id = *db_guild_id;
|
||||
process_database_channels(database, &guild, webhookIds);
|
||||
guilds->push_back(std::move(guild));
|
||||
process_database_channels(database, guild, webhookIds);
|
||||
guilds.push_back(std::move(guild));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void process_guild_settings(const dpp::json &json, std::vector<guild> *guilds, std::vector<dpp::snowflake> *webhookIds)
|
||||
void process_guild_settings(const dpp::json &json, std::vector<guild> &guilds, std::vector<dpp::snowflake> &webhookIds)
|
||||
{
|
||||
for (auto json_guild = json.begin(); json_guild != json.end(); json_guild++) {
|
||||
if (json_guild->is_object()) {
|
||||
|
@ -128,7 +132,7 @@ void process_guild_settings(const dpp::json &json, std::vector<guild> *guilds, s
|
|||
target target;
|
||||
target.target = *json_channel_target;
|
||||
target.webhook = dpp::webhook(json_channel->at("webhook"));
|
||||
webhookIds->push_back(target.webhook.id);
|
||||
webhookIds.push_back(target.webhook.id);
|
||||
channel.targets.push_back(std::move(target));
|
||||
}
|
||||
else if (json_channel_target->is_object()) {
|
||||
|
@ -136,7 +140,7 @@ void process_guild_settings(const dpp::json &json, std::vector<guild> *guilds, s
|
|||
target target;
|
||||
target.target = json_target.key();
|
||||
target.webhook = dpp::webhook(*json_target);
|
||||
webhookIds->push_back(target.webhook.id);
|
||||
webhookIds.push_back(target.webhook.id);
|
||||
channel.targets.push_back(std::move(target));
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +150,7 @@ void process_guild_settings(const dpp::json &json, std::vector<guild> *guilds, s
|
|||
guild.channel.push_back(std::move(channel));
|
||||
}
|
||||
}
|
||||
guilds->push_back(std::move(guild));
|
||||
guilds.push_back(std::move(guild));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -162,103 +166,162 @@ void process_preflang_settings(const dpp::json &json, std::vector<std::string> *
|
|||
}
|
||||
}
|
||||
|
||||
void process_user_settings(const dpp::json &json, uint16_t *avatar_size)
|
||||
{
|
||||
auto json_avatar_size = json.find("avatar_size");
|
||||
if (json_avatar_size != json.end()) {
|
||||
*avatar_size = *json_avatar_size;
|
||||
if (*avatar_size < 16)
|
||||
*avatar_size = 16;
|
||||
else if (*avatar_size > 4096)
|
||||
*avatar_size = 4096;
|
||||
}
|
||||
}
|
||||
|
||||
void process_url(const std::string &url, translator *translator)
|
||||
void process_server_url(const std::string &url, translator &translator)
|
||||
{
|
||||
std::string_view url_v = url;
|
||||
if (url_v.substr(0, 7) == "http://") {
|
||||
translator->tls = false;
|
||||
if (!translator->port)
|
||||
translator->port = 80;
|
||||
translator.tls = false;
|
||||
if (!translator.port)
|
||||
translator.port = 80;
|
||||
url_v = url_v.substr(7);
|
||||
}
|
||||
else if (url_v.substr(0, 8) == "https://") {
|
||||
translator->tls = true;
|
||||
if (!translator->port)
|
||||
translator->port = 443;
|
||||
translator.tls = true;
|
||||
if (!translator.port)
|
||||
translator.port = 443;
|
||||
url_v = url_v.substr(8);
|
||||
}
|
||||
else {
|
||||
translator->tls = false;
|
||||
if (!translator->port)
|
||||
translator->port = 80;
|
||||
translator.tls = false;
|
||||
if (!translator.port)
|
||||
translator.port = 80;
|
||||
}
|
||||
auto slash_pos = url_v.find_first_of('/');
|
||||
if (slash_pos != std::string_view::npos) {
|
||||
translator->url = url_v.substr(slash_pos);
|
||||
translator.url = url_v.substr(slash_pos);
|
||||
url_v = url_v.substr(0, slash_pos);
|
||||
}
|
||||
else {
|
||||
translator->url = "/";
|
||||
translator.url = "/";
|
||||
url_v = url_v.substr(0, slash_pos);
|
||||
}
|
||||
auto colon_pos = url_v.find_first_of(':');
|
||||
// We don't have IPv6 support here yet
|
||||
auto colon_pos = url_v.find_last_of(':');
|
||||
if (colon_pos != std::string_view::npos) {
|
||||
translator->hostname = url_v.substr(0, colon_pos);
|
||||
translator.hostname = url_v.substr(0, colon_pos);
|
||||
const int port = std::stoi(std::string(url_v.substr(colon_pos + 1)));
|
||||
if (port > 0 && port < 65536)
|
||||
translator->port = static_cast<uint16_t>(port);
|
||||
translator.port = static_cast<uint16_t>(port);
|
||||
else
|
||||
throw std::invalid_argument("Port is out of range");
|
||||
}
|
||||
else {
|
||||
translator->hostname = url_v;
|
||||
translator.hostname = url_v;
|
||||
}
|
||||
}
|
||||
|
||||
bool process_translator_settings(const dpp::json &json, translator *translator)
|
||||
bool process_server(const dpp::json &json, translator &translator)
|
||||
{
|
||||
auto json_hostname = json.find("hostname");
|
||||
if (json_hostname != json.end())
|
||||
translator.hostname = *json_hostname;
|
||||
|
||||
auto json_tls = json.find("tls");
|
||||
if (json_tls != json.end())
|
||||
translator.tls = *json_tls;
|
||||
else
|
||||
translator.tls = false;
|
||||
|
||||
auto json_port = json.find("port");
|
||||
if (json_port != json.end())
|
||||
translator.port = *json_port;
|
||||
else
|
||||
translator.port = 0;
|
||||
|
||||
auto json_url = json.find("url");
|
||||
if (json_url == json.end()) {
|
||||
std::cerr << "[Error] Value url not found in translator object" << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (translator.hostname.empty())
|
||||
process_server_url(*json_url, translator);
|
||||
else
|
||||
translator.url = *json_url;
|
||||
|
||||
auto json_apiKey = json.find("apiKey");
|
||||
if (json_apiKey != json.end())
|
||||
translator.apiKey = *json_apiKey;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void process_user_settings(const dpp::json &json, uint16_t &avatar_size)
|
||||
{
|
||||
auto json_avatar_size = json.find("avatar_size");
|
||||
if (json_avatar_size != json.end()) {
|
||||
avatar_size = *json_avatar_size;
|
||||
if (avatar_size < 16)
|
||||
avatar_size = 16;
|
||||
else if (avatar_size > 4096)
|
||||
avatar_size = 4096;
|
||||
}
|
||||
}
|
||||
|
||||
bool process_translator_settings(const dpp::json &json, std::shared_ptr<bot::translator::translator> &translator_instance)
|
||||
{
|
||||
if (!json.is_object()) {
|
||||
std::cerr << "[Error] Value translator needs to be a object" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto json_translate_hostname = json.find("hostname");
|
||||
if (json_translate_hostname != json.end())
|
||||
translator->hostname = *json_translate_hostname;
|
||||
else
|
||||
translator->hostname = {};
|
||||
|
||||
auto json_translate_tls = json.find("tls");
|
||||
if (json_translate_tls != json.end())
|
||||
translator->tls = *json_translate_tls;
|
||||
else
|
||||
translator->tls = false;
|
||||
|
||||
auto json_translate_port = json.find("port");
|
||||
if (json_translate_port != json.end())
|
||||
translator->port = *json_translate_port;
|
||||
else
|
||||
translator->port = 0;
|
||||
|
||||
auto json_translate_url = json.find("url");
|
||||
if (json_translate_url == json.end()) {
|
||||
std::cerr << "[Error] Value url not found in translator object" << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (translator->hostname.empty()) {
|
||||
process_url(*json_translate_url, translator);
|
||||
bot::settings::translator translator;
|
||||
auto json_translator_type = json.find("type");
|
||||
if (json_translator_type != json.end()) {
|
||||
translator.type = *json_translator_type;
|
||||
std::transform(translator.type.begin(), translator.type.end(), translator.type.begin(), ::tolower);
|
||||
}
|
||||
else {
|
||||
translator->url = *json_translate_url;
|
||||
translator.type = "libretranslate";
|
||||
}
|
||||
|
||||
auto json_translate_apiKey = json.find("apiKey");
|
||||
if (json_translate_apiKey != json.end())
|
||||
translator->apiKey = *json_translate_apiKey;
|
||||
else
|
||||
translator->apiKey.clear();
|
||||
if (translator.type == "deepl") {
|
||||
auto json_deepl_hostname = json.find("hostname");
|
||||
if (json_deepl_hostname != json.end())
|
||||
translator.hostname = *json_deepl_hostname;
|
||||
else
|
||||
translator.hostname = "api-free.deepl.com";
|
||||
|
||||
auto json_deepl_apiKey = json.find("apiKey");
|
||||
if (json_deepl_apiKey == json.end()) {
|
||||
std::cerr << "[Error] DeepL requires API key for authorization" << std::endl;
|
||||
return false;
|
||||
}
|
||||
translator.apiKey = *json_deepl_apiKey;
|
||||
|
||||
translator_instance = std::make_shared<bot::translator::deepl>(translator.hostname, translator.apiKey);
|
||||
}
|
||||
else if (translator.type == "mozhi") {
|
||||
if (!process_server(json, translator))
|
||||
return false;
|
||||
|
||||
std::string mozhi_engine;
|
||||
auto json_mozhi_engine = json.find("engine");
|
||||
if (json_mozhi_engine != json.end())
|
||||
mozhi_engine = *json_mozhi_engine;
|
||||
else
|
||||
mozhi_engine = "google";
|
||||
|
||||
translator_instance = std::make_shared<bot::translator::mozhi>(translator.hostname, translator.port, translator.url, translator.tls, mozhi_engine);
|
||||
}
|
||||
else if (translator.type == "libretranslate") {
|
||||
if (!process_server(json, translator))
|
||||
return false;
|
||||
|
||||
translator_instance = std::make_shared<bot::translator::libretranslate>(translator.hostname, translator.port, translator.url, translator.tls, translator.apiKey);
|
||||
}
|
||||
else if (translator.type == "lingvatranslate") {
|
||||
if (!process_server(json, translator))
|
||||
return false;
|
||||
|
||||
translator_instance = std::make_shared<bot::translator::lingvatranslate>(translator.hostname, translator.port, translator.url, translator.tls);
|
||||
}
|
||||
else if (translator.type == "stub") {
|
||||
translator_instance = std::make_shared<bot::translator::stub>();
|
||||
}
|
||||
else {
|
||||
std::cerr << "[Error] Translator " << translator.type << " is unknown" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -300,6 +363,27 @@ void settings::add_translatebot_webhook(dpp::snowflake webhook_id)
|
|||
m_webhookIds.push_back(webhook_id);
|
||||
}
|
||||
|
||||
void settings::erase_channel(guild &guild, dpp::snowflake channel_id)
|
||||
{
|
||||
for (auto channel = guild.channel.begin(); channel != guild.channel.end(); channel++) {
|
||||
if (channel->id == channel_id) {
|
||||
guild.channel.erase(channel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void settings::erase_guild(dpp::snowflake guild_id)
|
||||
{
|
||||
const std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
||||
for (auto guild = m_guilds.begin(); guild != m_guilds.end(); guild++) {
|
||||
if (guild->id == guild_id) {
|
||||
m_guilds.erase(guild);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void settings::erase_translatebot_webhook(dpp::snowflake webhook_id)
|
||||
{
|
||||
const std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
||||
|
@ -314,9 +398,9 @@ uint16_t settings::avatar_size()
|
|||
return m_avatarSize;
|
||||
}
|
||||
|
||||
channel* settings::get_channel(guild *guild, dpp::snowflake channel_id)
|
||||
channel* settings::get_channel(guild &guild, dpp::snowflake channel_id)
|
||||
{
|
||||
for (auto channel = guild->channel.begin(); channel != guild->channel.end(); channel++) {
|
||||
for (auto channel = guild.channel.begin(); channel != guild.channel.end(); channel++) {
|
||||
if (channel->id == channel_id)
|
||||
return &*channel;
|
||||
}
|
||||
|
@ -413,10 +497,10 @@ std::shared_ptr<bot::database::database> settings::get_database() const
|
|||
return m_database;
|
||||
}
|
||||
|
||||
std::unique_ptr<bot::translator::translator> settings::get_translator() const
|
||||
std::shared_ptr<bot::translator::translator> settings::get_translator() const
|
||||
{
|
||||
const std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
||||
return std::make_unique<bot::translator::libretranslate>(m_translator.hostname, m_translator.port, m_translator.url, m_translator.tls, m_translator.apiKey);
|
||||
return m_translator;
|
||||
}
|
||||
|
||||
const std::string settings::token() const
|
||||
|
@ -446,7 +530,7 @@ bool settings::parse(const std::string &data, bool initialize)
|
|||
try {
|
||||
dpp::json json;
|
||||
try {
|
||||
json = dpp::json::parse(data);
|
||||
json = dpp::json::parse(data, nullptr, true, true);
|
||||
}
|
||||
catch (const std::exception &exception) {
|
||||
std::cerr << "[Exception] " << exception.what() << std::endl;
|
||||
|
@ -454,21 +538,24 @@ bool settings::parse(const std::string &data, bool initialize)
|
|||
return false;
|
||||
}
|
||||
|
||||
const std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
||||
auto json_token = json.find("token");
|
||||
if (json_token == json.end()) {
|
||||
std::cerr << "[Error] Value token not found" << std::endl;
|
||||
if (json_token != json.end())
|
||||
m_token = *json_token;
|
||||
else if (char *token = getenv("DTRANSLATEBOT_TOKEN"))
|
||||
m_token = token;
|
||||
|
||||
if (m_token.empty()) {
|
||||
std::cerr << "[Error] Discord Bot Token is not configured" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
||||
m_token = *json_token;
|
||||
|
||||
std::filesystem::path storage_path;
|
||||
auto json_storage = json.find("storage");
|
||||
if (json_storage != json.end())
|
||||
storage_path = std::string(*json_storage);
|
||||
else if (char *storagepath = getenv("DTRANSLATEBOT_STORAGE"))
|
||||
storage_path = storagepath;
|
||||
storage_path = storagepath;
|
||||
|
||||
if (storage_path.empty())
|
||||
storage_path = std::filesystem::current_path();
|
||||
|
@ -480,14 +567,12 @@ bool settings::parse(const std::string &data, bool initialize)
|
|||
std::cerr << "[Error] Value translator not found" << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (!process_translator_settings(*json_translator, &m_translator))
|
||||
if (!process_translator_settings(*json_translator, m_translator))
|
||||
return false;
|
||||
|
||||
m_avatarSize = 256;
|
||||
|
||||
auto json_guilds = json.find("guilds");
|
||||
if (json_guilds != json.end() && json_guilds->is_object())
|
||||
process_guild_settings(*json_guilds, &m_guilds, &m_webhookIds);
|
||||
process_guild_settings(*json_guilds, m_guilds, m_webhookIds);
|
||||
|
||||
auto json_preflangs = json.find("preferred_lang");
|
||||
if (json_preflangs != json.end() && json_preflangs->is_array())
|
||||
|
@ -495,9 +580,9 @@ bool settings::parse(const std::string &data, bool initialize)
|
|||
|
||||
auto json_user = json.find("user");
|
||||
if (json_user != json.end() && json_user->is_object())
|
||||
process_user_settings(*json_user, &m_avatarSize);
|
||||
process_user_settings(*json_user, m_avatarSize);
|
||||
|
||||
process_database(m_database, &m_guilds, &m_webhookIds);
|
||||
process_database(m_database, m_guilds, m_webhookIds);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -19,9 +19,9 @@
|
|||
#ifndef SETTINGS_H
|
||||
#define SETTINGS_H
|
||||
#include <mutex>
|
||||
#include "database_core.h"
|
||||
#include "database.h"
|
||||
#include "settings_types.h"
|
||||
#include "translator_core.h"
|
||||
#include "translator.h"
|
||||
|
||||
namespace bot {
|
||||
namespace settings {
|
||||
|
@ -33,11 +33,13 @@ namespace bot {
|
|||
void add_translatebot_webhook(dpp::snowflake webhook_id);
|
||||
|
||||
/* erase functions */
|
||||
static void erase_channel(guild &guild, dpp::snowflake channel_id);
|
||||
void erase_guild(dpp::snowflake guild_id);
|
||||
void erase_translatebot_webhook(dpp::snowflake webhook_id);
|
||||
|
||||
/* get functions */
|
||||
uint16_t avatar_size();
|
||||
static channel* get_channel(guild *guild, dpp::snowflake channel_id);
|
||||
static channel* get_channel(guild &guild, dpp::snowflake channel_id);
|
||||
channel* get_channel(dpp::snowflake guild_id, dpp::snowflake channel_id);
|
||||
guild* get_guild(dpp::snowflake guild_id);
|
||||
target* get_target(dpp::snowflake guild_id, dpp::snowflake channel_id, const std::string &target);
|
||||
|
@ -45,7 +47,7 @@ namespace bot {
|
|||
static const target* get_target(const channel *channel, const std::string &target);
|
||||
const std::vector<std::string> preferred_languages() const;
|
||||
std::shared_ptr<bot::database::database> get_database() const;
|
||||
std::unique_ptr<bot::translator::translator> get_translator() const;
|
||||
std::shared_ptr<bot::translator::translator> get_translator() const;
|
||||
const std::string token() const;
|
||||
|
||||
/* is functions */
|
||||
|
@ -59,14 +61,19 @@ namespace bot {
|
|||
bool parse(const std::string &data, bool initialize = true);
|
||||
bool parse_file(const std::string &filename, bool initialize = true);
|
||||
|
||||
/* prevent copies */
|
||||
settings() = default;
|
||||
settings(const settings&) = delete;
|
||||
settings& operator=(const settings&) = delete;
|
||||
|
||||
private:
|
||||
mutable std::recursive_mutex m_mutex;
|
||||
size_t m_externallyLockedCount;
|
||||
uint16_t m_avatarSize;
|
||||
size_t m_externallyLockedCount = 0;
|
||||
uint16_t m_avatarSize = 256;
|
||||
std::shared_ptr<bot::database::database> m_database;
|
||||
std::vector<guild> m_guilds;
|
||||
std::vector<std::string> m_prefLangs;
|
||||
bot::settings::translator m_translator;
|
||||
std::shared_ptr<bot::translator::translator> m_translator;
|
||||
std::string m_token;
|
||||
std::vector<dpp::snowflake> m_webhookIds;
|
||||
};
|
|
@ -41,6 +41,7 @@ namespace bot {
|
|||
std::vector<bot::settings::channel> channel;
|
||||
};
|
||||
struct translator {
|
||||
std::string type;
|
||||
std::string hostname;
|
||||
uint16_t port;
|
||||
std::string url;
|
|
@ -18,19 +18,20 @@
|
|||
|
||||
#include <sstream>
|
||||
#include "slashcommands.h"
|
||||
using bot::slashcommands;
|
||||
using namespace std::string_literals;
|
||||
|
||||
void bot::slashcommands::process_command_event(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event)
|
||||
void slashcommands::process_command_event(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event)
|
||||
{
|
||||
if (event.command.get_command_name() == "edit")
|
||||
bot::slashcommands::process_edit_command(bot, settings, event);
|
||||
slashcommands::process_edit_command(bot, settings, event);
|
||||
else if (event.command.get_command_name() == "list")
|
||||
bot::slashcommands::process_list_command(bot, settings, event);
|
||||
slashcommands::process_list_command(bot, settings, event);
|
||||
else if (event.command.get_command_name() == "translate" || event.command.get_command_name() == "translate_pref")
|
||||
bot::slashcommands::process_translate_command(bot, settings, event);
|
||||
slashcommands::process_translate_command(bot, settings, event);
|
||||
}
|
||||
|
||||
void bot::slashcommands::process_edit_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event)
|
||||
void slashcommands::process_edit_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event)
|
||||
{
|
||||
try {
|
||||
dpp::permission user_permissions = event.command.get_resolved_permission(event.command.usr.id);
|
||||
|
@ -40,65 +41,84 @@ void bot::slashcommands::process_edit_command(dpp::cluster *bot, bot::settings::
|
|||
dpp::command_interaction interaction = event.command.get_command_interaction();
|
||||
if (interaction.options[0].name == "delete") {
|
||||
const std::lock_guard<bot::settings::settings> guard(*settings);
|
||||
if (bot::settings::channel *channel = settings->get_channel(event.command.guild_id, event.command.channel_id)) {
|
||||
const std::string target = std::get<std::string>(event.get_parameter("target"));
|
||||
if (bot::settings::guild *guild = settings->get_guild(event.command.guild_id)) {
|
||||
if (bot::settings::channel *channel = settings->get_channel(*guild, event.command.channel_id)) {
|
||||
const std::string target = std::get<std::string>(event.get_parameter("target"));
|
||||
|
||||
std::shared_ptr<bot::database::database> database = settings->get_database();
|
||||
const bot::settings::channel db_channel = database->get_channel(event.command.guild_id, event.command.channel_id);
|
||||
auto database = settings->get_database();
|
||||
const bot::settings::channel db_channel = database->get_channel(event.command.guild_id, event.command.channel_id);
|
||||
|
||||
if (db_channel.targets.empty()) {
|
||||
event.reply(dpp::message("The current channel has no deleteable targets!").set_flags(dpp::m_ephemeral));
|
||||
}
|
||||
else if (target == "**") {
|
||||
std::vector<std::string> targets;
|
||||
for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++) {
|
||||
targets.push_back(db_target->target);
|
||||
if (db_channel.targets.empty()) {
|
||||
event.reply(dpp::message("The current channel has no deleteable targets!").set_flags(dpp::m_ephemeral));
|
||||
}
|
||||
for (auto target = channel->targets.begin(); target != channel->targets.end();) {
|
||||
if (std::find(targets.begin(), targets.end(), target->target) != targets.end()) {
|
||||
bot->delete_webhook(target->webhook.id, std::bind(&bot::slashcommands::process_deleted_webhook, settings, target->webhook.id, std::placeholders::_1));
|
||||
target = channel->targets.erase(target);
|
||||
else if (target == "**") {
|
||||
std::vector<std::string> targets;
|
||||
for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++) {
|
||||
targets.push_back(db_target->target);
|
||||
}
|
||||
else {
|
||||
target++;
|
||||
for (auto target = channel->targets.begin(); target != channel->targets.end();) {
|
||||
if (std::find(targets.begin(), targets.end(), target->target) != targets.end()) {
|
||||
bot->delete_webhook(target->webhook.id, std::bind(&slashcommands::process_deleted_webhook, settings, target->webhook.id, std::placeholders::_1));
|
||||
target = channel->targets.erase(target);
|
||||
}
|
||||
else {
|
||||
target++;
|
||||
}
|
||||
}
|
||||
|
||||
database->delete_channel(event.command.guild_id, event.command.channel_id);
|
||||
database->sync();
|
||||
|
||||
if (channel->targets.empty()) {
|
||||
settings->erase_channel(*guild, event.command.channel_id);
|
||||
if (guild->channel.empty()) {
|
||||
settings->erase_guild(event.command.guild_id);
|
||||
}
|
||||
}
|
||||
|
||||
event.reply(dpp::message("Deleteable targets have being deleted!").set_flags(dpp::m_ephemeral));
|
||||
}
|
||||
|
||||
database->delete_channel(event.command.guild_id, event.command.channel_id);
|
||||
database->sync();
|
||||
|
||||
event.reply(dpp::message("Deleteable targets have being deleted!").set_flags(dpp::m_ephemeral));
|
||||
}
|
||||
else {
|
||||
bool target_found = false;
|
||||
for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++) {
|
||||
if (db_target->target == target) {
|
||||
target_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (target_found) {
|
||||
for (auto _target = channel->targets.begin(); _target != channel->targets.end(); _target++) {
|
||||
if (_target->target == target) {
|
||||
bot->delete_webhook(_target->webhook.id, std::bind(&bot::slashcommands::process_deleted_webhook, settings, _target->webhook.id, std::placeholders::_1));
|
||||
channel->targets.erase(_target);
|
||||
else {
|
||||
bool target_found = false;
|
||||
for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++) {
|
||||
if (db_target->target == target) {
|
||||
target_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (db_channel.targets.size() == 1)
|
||||
database->delete_channel(event.command.guild_id, event.command.channel_id);
|
||||
else
|
||||
database->delete_channel_target(event.command.guild_id, event.command.channel_id, target);
|
||||
database->sync();
|
||||
if (target_found) {
|
||||
for (auto _target = channel->targets.begin(); _target != channel->targets.end(); _target++) {
|
||||
if (_target->target == target) {
|
||||
bot->delete_webhook(_target->webhook.id, std::bind(&slashcommands::process_deleted_webhook, settings, _target->webhook.id, std::placeholders::_1));
|
||||
channel->targets.erase(_target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
event.reply(dpp::message("Target have being deleted!").set_flags(dpp::m_ephemeral));
|
||||
}
|
||||
else {
|
||||
event.reply(dpp::message("Target language is not being found or deleteable!").set_flags(dpp::m_ephemeral));
|
||||
if (db_channel.targets.size() == 1)
|
||||
database->delete_channel(event.command.guild_id, event.command.channel_id);
|
||||
else
|
||||
database->delete_channel_target(event.command.guild_id, event.command.channel_id, target);
|
||||
database->sync();
|
||||
|
||||
if (channel->targets.empty()) {
|
||||
settings->erase_channel(*guild, event.command.channel_id);
|
||||
if (guild->channel.empty()) {
|
||||
settings->erase_guild(event.command.guild_id);
|
||||
}
|
||||
}
|
||||
|
||||
event.reply(dpp::message("Target have being deleted!").set_flags(dpp::m_ephemeral));
|
||||
}
|
||||
else {
|
||||
event.reply(dpp::message("Target language is not being found or deleteable!").set_flags(dpp::m_ephemeral));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
event.reply(dpp::message("The current channel is not being translated!").set_flags(dpp::m_ephemeral));
|
||||
}
|
||||
}
|
||||
else {
|
||||
event.reply(dpp::message("The current channel is not being translated!").set_flags(dpp::m_ephemeral));
|
||||
|
@ -117,13 +137,13 @@ void bot::slashcommands::process_edit_command(dpp::cluster *bot, bot::settings::
|
|||
source_valid = true;
|
||||
break;
|
||||
}
|
||||
language_codes << " " << language.code;
|
||||
language_codes << ' ' << language.code;
|
||||
}
|
||||
|
||||
if (source_valid) {
|
||||
channel->source = source;
|
||||
|
||||
std::shared_ptr<bot::database::database> database = settings->get_database();
|
||||
auto database = settings->get_database();
|
||||
database->set_channel_source(event.command.guild_id, event.command.channel_id, source);
|
||||
database->sync();
|
||||
|
||||
|
@ -147,7 +167,7 @@ void bot::slashcommands::process_edit_command(dpp::cluster *bot, bot::settings::
|
|||
}
|
||||
}
|
||||
|
||||
void bot::slashcommands::process_deleted_webhook(bot::settings::settings *settings, dpp::snowflake webhook_id, const dpp::confirmation_callback_t &callback)
|
||||
void slashcommands::process_deleted_webhook(bot::settings::settings *settings, dpp::snowflake webhook_id, const dpp::confirmation_callback_t &callback)
|
||||
{
|
||||
if (callback.is_error()) {
|
||||
std::cerr << "[Error] Failed to delete Webhook " << webhook_id << std::endl;
|
||||
|
@ -156,7 +176,7 @@ void bot::slashcommands::process_deleted_webhook(bot::settings::settings *settin
|
|||
settings->erase_translatebot_webhook(webhook_id);
|
||||
}
|
||||
|
||||
void bot::slashcommands::process_list_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event)
|
||||
void slashcommands::process_list_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event)
|
||||
{
|
||||
try {
|
||||
dpp::command_interaction interaction = event.command.get_command_interaction();
|
||||
|
@ -171,7 +191,7 @@ void bot::slashcommands::process_list_command(dpp::cluster *bot, bot::settings::
|
|||
// We want give more information to users who can Manage Webhooks
|
||||
dpp::permission user_permissions = event.command.get_resolved_permission(event.command.usr.id);
|
||||
if (user_permissions.has(dpp::p_manage_webhooks)) {
|
||||
std::shared_ptr<bot::database::database> database = settings->get_database();
|
||||
auto database = settings->get_database();
|
||||
const bot::settings::channel db_channel = database->get_channel(event.command.guild_id, event.command.channel_id);
|
||||
|
||||
for (auto target = channel->targets.begin(); target != channel->targets.end(); target++) {
|
||||
|
@ -217,17 +237,44 @@ void bot::slashcommands::process_list_command(dpp::cluster *bot, bot::settings::
|
|||
event.reply(dpp::message("The current guild have no translated channel!").set_flags(dpp::m_ephemeral));
|
||||
}
|
||||
}
|
||||
else if (interaction.options[0].name == "languages") {
|
||||
dpp::permission user_permissions = event.command.get_resolved_permission(event.command.usr.id);
|
||||
if (user_permissions.has(dpp::p_manage_webhooks)) {
|
||||
const std::vector<bot::translator::language> languages = settings->get_translator()->get_languages();
|
||||
std::ostringstream reply_languages;
|
||||
reply_languages << "**Available Languages**\n";
|
||||
for (auto language = languages.begin(); language != languages.end();) {
|
||||
reply_languages << language->name << ": " << language->code;
|
||||
if (++language != languages.end())
|
||||
reply_languages << '\n';
|
||||
}
|
||||
if (reply_languages.str().length() <= 2000) {
|
||||
event.reply(dpp::message(reply_languages.str()).set_flags(dpp::m_ephemeral));
|
||||
}
|
||||
else {
|
||||
reply_languages.str({});
|
||||
reply_languages << "Available Languages:";
|
||||
for (auto language = languages.begin(); language != languages.end(); language++) {
|
||||
reply_languages << ' ' << language->code;
|
||||
}
|
||||
event.reply(dpp::message(reply_languages.str()).set_flags(dpp::m_ephemeral));
|
||||
}
|
||||
}
|
||||
else {
|
||||
event.reply(dpp::message("Unauthorized to list available languages!").set_flags(dpp::m_ephemeral));
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw std::invalid_argument("Option " + interaction.options[0].name + " is not known");
|
||||
}
|
||||
}
|
||||
catch (const std::exception& exception) {
|
||||
catch (const std::exception &exception) {
|
||||
std::cerr << "[Exception] " << exception.what() << std::endl;
|
||||
event.reply(dpp::message("Exception while processing command:\n"s + exception.what()).set_flags(dpp::m_ephemeral));
|
||||
}
|
||||
}
|
||||
|
||||
void bot::slashcommands::process_translate_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event)
|
||||
void slashcommands::process_translate_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event)
|
||||
{
|
||||
try {
|
||||
dpp::permission user_permissions = event.command.get_resolved_permission(event.command.usr.id);
|
||||
|
@ -241,13 +288,13 @@ void bot::slashcommands::process_translate_command(dpp::cluster *bot, bot::setti
|
|||
dpp::command_interaction interaction = event.command.get_command_interaction();
|
||||
if (interaction.options[0].name == "channel") {
|
||||
v_target = event.command.get_resolved_channel(
|
||||
std::get<dpp::snowflake>(event.get_parameter("channel")));
|
||||
std::get<dpp::snowflake>(event.get_parameter("channel")));
|
||||
}
|
||||
else if (interaction.options[0].name == "webhook") {
|
||||
v_target = dpp::webhook(std::get<std::string>(event.get_parameter("webhook")));
|
||||
}
|
||||
|
||||
const std::vector<bot::translator::language> languages = settings->get_translator()->get_languages();
|
||||
const auto languages = settings->get_translator()->get_languages();
|
||||
|
||||
std::ostringstream language_codes;
|
||||
bool source_valid = false, target_valid = false;
|
||||
|
@ -258,7 +305,7 @@ void bot::slashcommands::process_translate_command(dpp::cluster *bot, bot::setti
|
|||
target_valid = true;
|
||||
if (source_valid && target_valid)
|
||||
break;
|
||||
language_codes << " " << language.code;
|
||||
language_codes << ' ' << language.code;
|
||||
}
|
||||
|
||||
if (source_valid && target_valid) {
|
||||
|
@ -271,7 +318,7 @@ void bot::slashcommands::process_translate_command(dpp::cluster *bot, bot::setti
|
|||
webhook.guild_id = channel->guild_id;
|
||||
webhook.name = "Translate Bot Webhook <" + std::to_string(event.command.channel_id) + ":" + source + ":" + target + ">";
|
||||
|
||||
bot->create_webhook(webhook, std::bind(&bot::slashcommands::process_translate_webhook_new_channel, settings, event, source, target, std::placeholders::_1));
|
||||
bot->create_webhook(webhook, std::bind(&slashcommands::process_translate_webhook_new_channel, settings, event, source, target, std::placeholders::_1));
|
||||
}
|
||||
else if (dpp::webhook *webhook = std::get_if<dpp::webhook>(&v_target)) {
|
||||
const bot::settings::target s_target = { target, *webhook };
|
||||
|
@ -280,7 +327,7 @@ void bot::slashcommands::process_translate_command(dpp::cluster *bot, bot::setti
|
|||
settings->add_channel(s_channel, event.command.guild_id);
|
||||
settings->add_translatebot_webhook(webhook->id);
|
||||
|
||||
std::shared_ptr<bot::database::database> database = settings->get_database();
|
||||
auto database = settings->get_database();
|
||||
database->set_channel_source(event.command.guild_id, event.command.channel_id, source);
|
||||
database->add_channel_target(event.command.guild_id, event.command.channel_id, s_target);
|
||||
database->sync();
|
||||
|
@ -298,7 +345,7 @@ void bot::slashcommands::process_translate_command(dpp::cluster *bot, bot::setti
|
|||
webhook.guild_id = channel->guild_id;
|
||||
webhook.name = "Translate Bot Webhook <" + std::to_string(event.command.channel_id) + ":" + source + ":" + target + ">";
|
||||
|
||||
bot->create_webhook(webhook, std::bind(&bot::slashcommands::process_translate_webhook_add_target, settings, event, target, std::placeholders::_1));
|
||||
bot->create_webhook(webhook, std::bind(&slashcommands::process_translate_webhook_add_target, settings, event, target, std::placeholders::_1));
|
||||
}
|
||||
else if (dpp::webhook *webhook = std::get_if<dpp::webhook>(&v_target)) {
|
||||
const bot::settings::target s_target = { target, *webhook };
|
||||
|
@ -306,7 +353,7 @@ void bot::slashcommands::process_translate_command(dpp::cluster *bot, bot::setti
|
|||
settings->add_target(s_target, event.command.guild_id, event.command.channel_id);
|
||||
settings->add_translatebot_webhook(webhook->id);
|
||||
|
||||
std::shared_ptr<bot::database::database> database = settings->get_database();
|
||||
auto database = settings->get_database();
|
||||
database->add_channel_target(event.command.guild_id, event.command.channel_id, s_target);
|
||||
database->sync();
|
||||
|
||||
|
@ -333,7 +380,7 @@ void bot::slashcommands::process_translate_command(dpp::cluster *bot, bot::setti
|
|||
}
|
||||
}
|
||||
|
||||
void bot::slashcommands::process_translate_webhook_add_target(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &target, const dpp::confirmation_callback_t &callback)
|
||||
void slashcommands::process_translate_webhook_add_target(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &target, const dpp::confirmation_callback_t &callback)
|
||||
{
|
||||
if (callback.is_error()) {
|
||||
event.reply(dpp::message("Failed to generate webhook!").set_flags(dpp::m_ephemeral));
|
||||
|
@ -347,14 +394,14 @@ void bot::slashcommands::process_translate_webhook_add_target(bot::settings::set
|
|||
settings->add_target(s_target, event.command.guild_id, event.command.channel_id);
|
||||
settings->add_translatebot_webhook(webhook.id);
|
||||
|
||||
std::shared_ptr<bot::database::database> database = settings->get_database();
|
||||
auto database = settings->get_database();
|
||||
database->add_channel_target(event.command.guild_id, event.command.channel_id, s_target);
|
||||
database->sync();
|
||||
|
||||
event.reply(dpp::message("Channel will be now translated!").set_flags(dpp::m_ephemeral));
|
||||
}
|
||||
|
||||
void bot::slashcommands::process_translate_webhook_new_channel(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &source, const std::string &target, const dpp::confirmation_callback_t &callback)
|
||||
void slashcommands::process_translate_webhook_new_channel(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &source, const std::string &target, const dpp::confirmation_callback_t &callback)
|
||||
{
|
||||
if (callback.is_error()) {
|
||||
event.reply(dpp::message("Failed to generate webhook!").set_flags(dpp::m_ephemeral));
|
||||
|
@ -369,7 +416,7 @@ void bot::slashcommands::process_translate_webhook_new_channel(bot::settings::se
|
|||
settings->add_channel(s_channel, event.command.guild_id);
|
||||
settings->add_translatebot_webhook(webhook.id);
|
||||
|
||||
std::shared_ptr<bot::database::database> database = settings->get_database();
|
||||
auto database = settings->get_database();
|
||||
database->set_channel_source(event.command.guild_id, event.command.channel_id, source);
|
||||
database->add_channel_target(event.command.guild_id, event.command.channel_id, s_target);
|
||||
database->sync();
|
||||
|
@ -377,7 +424,7 @@ void bot::slashcommands::process_translate_webhook_new_channel(bot::settings::se
|
|||
event.reply(dpp::message("Channel will be now translated!").set_flags(dpp::m_ephemeral));
|
||||
}
|
||||
|
||||
void bot::slashcommands::register_commands(dpp::cluster *bot, bot::settings::settings *settings)
|
||||
void slashcommands::register_commands(dpp::cluster *bot, bot::settings::settings *settings)
|
||||
{
|
||||
settings->lock();
|
||||
const std::vector<bot::translator::language> languages = settings->get_translator()->get_languages();
|
||||
|
@ -387,9 +434,9 @@ void bot::slashcommands::register_commands(dpp::cluster *bot, bot::settings::set
|
|||
std::vector<dpp::slashcommand> commands;
|
||||
|
||||
dpp::command_option source_option(dpp::co_string, "source", "Source language (ISO 639-1)", true);
|
||||
source_option.set_max_length(static_cast<int64_t>(2)).set_min_length(static_cast<int64_t>(2));
|
||||
source_option.set_max_length(static_cast<int64_t>(5)).set_min_length(static_cast<int64_t>(2));
|
||||
dpp::command_option target_option(dpp::co_string, "target", "Target language (ISO 639-1)", true);
|
||||
target_option.set_max_length(static_cast<int64_t>(2)).set_min_length(static_cast<int64_t>(2));
|
||||
target_option.set_max_length(static_cast<int64_t>(5)).set_min_length(static_cast<int64_t>(2));
|
||||
|
||||
dpp::slashcommand command_edit("edit", "Edit current channel settings", bot->me.id);
|
||||
command_edit.set_default_permissions(dpp::p_manage_webhooks);
|
||||
|
@ -404,8 +451,10 @@ void bot::slashcommands::register_commands(dpp::cluster *bot, bot::settings::set
|
|||
dpp::slashcommand command_list("list", "List translation settings", bot->me.id);
|
||||
dpp::command_option channel_list_subcommand(dpp::co_sub_command, "channel", "List current channel translation settings");
|
||||
dpp::command_option guild_list_subcommand(dpp::co_sub_command, "guild", "List current guild translation settings");
|
||||
dpp::command_option languages_list_subcommand(dpp::co_sub_command, "languages", "List available languages to translate");
|
||||
command_list.add_option(channel_list_subcommand);
|
||||
command_list.add_option(guild_list_subcommand);
|
||||
command_list.add_option(languages_list_subcommand);
|
||||
commands.push_back(command_list);
|
||||
|
||||
dpp::slashcommand command_translate("translate", "Translate current channel", bot->me.id);
|
|
@ -23,16 +23,20 @@
|
|||
#include "settings.h"
|
||||
|
||||
namespace bot {
|
||||
namespace slashcommands {
|
||||
extern void process_command_event(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event);
|
||||
extern void process_edit_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event);
|
||||
extern void process_deleted_webhook(bot::settings::settings *settings, dpp::snowflake webhook_id, const dpp::confirmation_callback_t &callback);
|
||||
extern void process_list_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event);
|
||||
extern void process_translate_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event);
|
||||
extern void process_translate_webhook_add_target(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &target, const dpp::confirmation_callback_t &callback);
|
||||
extern void process_translate_webhook_new_channel(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &source, const std::string &target, const dpp::confirmation_callback_t &callback);
|
||||
extern void register_commands(dpp::cluster *bot, bot::settings::settings *settings);
|
||||
}
|
||||
class slashcommands {
|
||||
public:
|
||||
slashcommands() = delete;
|
||||
static void process_command_event(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event);
|
||||
static void register_commands(dpp::cluster *bot, bot::settings::settings *settings);
|
||||
|
||||
private:
|
||||
static void process_edit_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event);
|
||||
static void process_deleted_webhook(bot::settings::settings *settings, dpp::snowflake webhook_id, const dpp::confirmation_callback_t &callback);
|
||||
static void process_list_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event);
|
||||
static void process_translate_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event);
|
||||
static void process_translate_webhook_add_target(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &target, const dpp::confirmation_callback_t &callback);
|
||||
static void process_translate_webhook_new_channel(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &source, const std::string &target, const dpp::confirmation_callback_t &callback);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SLASHCOMMANDS_H
|
|
@ -19,7 +19,7 @@
|
|||
#include <thread>
|
||||
#include "submit_queue.h"
|
||||
#include "webhook_push.h"
|
||||
using namespace bot;
|
||||
using bot::submit_queue;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
void submit_queue::add(const translated_message &message)
|
|
@ -19,17 +19,9 @@
|
|||
#ifndef NDEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
#include "translator_core.h"
|
||||
#include "translator.h"
|
||||
using namespace bot::translator;
|
||||
|
||||
translator::translator()
|
||||
{
|
||||
}
|
||||
|
||||
translator::~translator()
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector<language> translator::get_languages()
|
||||
{
|
||||
#ifndef NDEBUG
|
|
@ -16,9 +16,10 @@
|
|||
* responsible for anything with use of the software, you are self responsible.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TRANSLATOR_CORE_H
|
||||
#define TRANSLATOR_CORE_H
|
||||
#ifndef TRANSLATOR_H
|
||||
#define TRANSLATOR_H
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -29,14 +30,21 @@ namespace bot {
|
|||
std::string name;
|
||||
};
|
||||
|
||||
struct supported_languages {
|
||||
std::vector<language> languages;
|
||||
std::chrono::system_clock::time_point query_time;
|
||||
};
|
||||
|
||||
class translator {
|
||||
public:
|
||||
explicit translator();
|
||||
virtual ~translator();
|
||||
explicit translator() = default;
|
||||
virtual ~translator() = default;
|
||||
translator(const translator&) = delete;
|
||||
translator& operator=(const translator&) = delete;
|
||||
virtual const std::vector<language> get_languages();
|
||||
virtual const std::string translate(const std::string &text, const std::string &source, const std::string &target);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TRANSLATOR_CORE_H
|
||||
#endif // TRANSLATOR_H
|
|
@ -25,10 +25,12 @@ using namespace std::string_view_literals;
|
|||
void bot::webhook_push::run(const bot::translated_message &message, dpp::cluster *bot)
|
||||
{
|
||||
dpp::json json_body = {
|
||||
{"username"s, message.author},
|
||||
{"avatar_url"s, message.avatar}
|
||||
{"username"s, message.author}
|
||||
};
|
||||
|
||||
if (!message.avatar.empty())
|
||||
json_body["avatar_url"] = message.avatar;
|
||||
|
||||
// We will split too long messages into multiple messages
|
||||
if (message.message.length() > 2000) {
|
||||
std::string_view message_v = message.message;
|
||||
|
@ -73,14 +75,18 @@ void bot::webhook_push::run(const bot::translated_message &message, dpp::cluster
|
|||
}
|
||||
}
|
||||
|
||||
void webhook_request_completed(std::promise<dpp::http_request_completion_t> &promise, dpp::json &json, const dpp::http_request_completion_t &event)
|
||||
{
|
||||
if (event.status != 204)
|
||||
std::cerr << "[Warning] Webhook push returned unexpected code " << event.status << std::endl;
|
||||
promise.set_value(event);
|
||||
}
|
||||
|
||||
void bot::webhook_push::push_request(dpp::snowflake webhook_id, const std::string &webhook_token, const std::string &json, dpp::cluster *bot)
|
||||
{
|
||||
std::promise<dpp::http_request_completion_t> _p;
|
||||
std::future<dpp::http_request_completion_t> _f = _p.get_future();
|
||||
bot->post_rest(API_PATH "/webhooks", std::to_string(webhook_id), dpp::utility::url_encode(webhook_token), dpp::m_post, json, [&bot, &_p](dpp::json &json, const dpp::http_request_completion_t &event) {
|
||||
if (event.status != 204)
|
||||
std::cerr << "[Warning] Webhook push returned unexpected code " << event.status << std::endl;
|
||||
_p.set_value(event);
|
||||
});
|
||||
_f.wait();
|
||||
std::promise<dpp::http_request_completion_t> promise;
|
||||
std::future<dpp::http_request_completion_t> future = promise.get_future();
|
||||
bot->post_rest(API_PATH "/webhooks", std::to_string(webhook_id), dpp::utility::url_encode(webhook_token), dpp::m_post, json,
|
||||
std::bind(&webhook_request_completed, std::ref(promise), std::placeholders::_1, std::placeholders::_2));
|
||||
future.wait();
|
||||
}
|
|
@ -26,6 +26,7 @@
|
|||
namespace bot {
|
||||
class webhook_push {
|
||||
public:
|
||||
webhook_push() = delete;
|
||||
static void run(const bot::translated_message &message, dpp::cluster *bot);
|
||||
|
||||
private:
|
|
@ -27,7 +27,7 @@
|
|||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include "database_file.h"
|
||||
#include "file.h"
|
||||
using namespace bot::database;
|
||||
using namespace std::string_literals;
|
||||
|
||||
|
@ -98,7 +98,7 @@ void file::add_channel_target(dpp::snowflake guild_id, dpp::snowflake channel_id
|
|||
}
|
||||
|
||||
bot::settings::channel channel;
|
||||
cache_get_channel(channel_id, &channel);
|
||||
cache_get_channel(channel_id, channel);
|
||||
channel.targets.push_back(target);
|
||||
cache_add_channel(guild_id, channel_id);
|
||||
guild->channel.push_back(std::move(channel));
|
||||
|
@ -107,7 +107,7 @@ void file::add_channel_target(dpp::snowflake guild_id, dpp::snowflake channel_id
|
|||
}
|
||||
|
||||
bot::settings::channel channel;
|
||||
cache_get_channel(channel_id, &channel);
|
||||
cache_get_channel(channel_id, channel);
|
||||
channel.targets.push_back(target);
|
||||
cache_add_channel(guild_id, channel_id);
|
||||
m_dataCache.push_back({ guild_id, { std::move(channel) } });
|
||||
|
@ -141,7 +141,7 @@ void file::delete_channel(dpp::snowflake guild_id, dpp::snowflake channel_id)
|
|||
}
|
||||
|
||||
std::vector<dpp::snowflake> channels;
|
||||
cache_guild(guild_id, &channels);
|
||||
cache_guild(guild_id, channels);
|
||||
for (auto channel = channels.begin(); channel != channels.end(); channel++) {
|
||||
if (*channel == channel_id) {
|
||||
channels.erase(channel);
|
||||
|
@ -175,7 +175,7 @@ void file::delete_channel_target(dpp::snowflake guild_id, dpp::snowflake channel
|
|||
}
|
||||
|
||||
bot::settings::channel channel;
|
||||
cache_get_channel(channel_id, &channel);
|
||||
cache_get_channel(channel_id, channel);
|
||||
for (auto _target = channel.targets.begin(); _target != channel.targets.end(); _target++) {
|
||||
if (_target->target == target) {
|
||||
channel.targets.erase(_target);
|
||||
|
@ -188,7 +188,7 @@ void file::delete_channel_target(dpp::snowflake guild_id, dpp::snowflake channel
|
|||
}
|
||||
|
||||
bot::settings::channel channel;
|
||||
cache_get_channel(channel_id, &channel);
|
||||
cache_get_channel(channel_id, channel);
|
||||
for (auto _target = channel.targets.begin(); _target != channel.targets.end(); _target++) {
|
||||
if (_target->target == target) {
|
||||
channel.targets.erase(_target);
|
||||
|
@ -266,7 +266,7 @@ bot::settings::channel file::get_channel(dpp::snowflake guild_id, dpp::snowflake
|
|||
}
|
||||
|
||||
bot::settings::channel channel;
|
||||
cache_get_channel(channel_id, &channel);
|
||||
cache_get_channel(channel_id, channel);
|
||||
return channel;
|
||||
}
|
||||
|
||||
|
@ -281,7 +281,7 @@ std::vector<dpp::snowflake> file::get_channels(dpp::snowflake guild_id)
|
|||
}
|
||||
|
||||
std::vector<dpp::snowflake> channels;
|
||||
cache_guild(guild_id, &channels);
|
||||
cache_guild(guild_id, channels);
|
||||
return channels;
|
||||
}
|
||||
|
||||
|
@ -330,7 +330,7 @@ std::vector<dpp::snowflake> file::get_guilds()
|
|||
{
|
||||
const std::lock_guard<std::mutex> guard(m_mutex);
|
||||
std::vector<dpp::snowflake> guilds;
|
||||
list_guilds(&guilds);
|
||||
list_guilds(guilds);
|
||||
return guilds;
|
||||
}
|
||||
|
||||
|
@ -348,7 +348,7 @@ void file::set_channel_source(dpp::snowflake guild_id, dpp::snowflake channel_id
|
|||
}
|
||||
|
||||
bot::settings::channel channel;
|
||||
cache_get_channel(channel_id, &channel);
|
||||
cache_get_channel(channel_id, channel);
|
||||
channel.source = source;
|
||||
cache_add_channel(guild_id, channel_id);
|
||||
guild->channel.push_back(std::move(channel));
|
||||
|
@ -357,7 +357,7 @@ void file::set_channel_source(dpp::snowflake guild_id, dpp::snowflake channel_id
|
|||
}
|
||||
|
||||
bot::settings::channel channel;
|
||||
cache_get_channel(channel_id, &channel);
|
||||
cache_get_channel(channel_id, channel);
|
||||
channel.source = source;
|
||||
cache_add_channel(guild_id, channel_id);
|
||||
m_dataCache.push_back({ guild_id, { std::move(channel) } });
|
||||
|
@ -390,16 +390,16 @@ void file::cache_add_channel(dpp::snowflake guild_id, dpp::snowflake channel_id)
|
|||
}
|
||||
|
||||
std::vector<dpp::snowflake> channels;
|
||||
cache_guild(guild_id, &channels);
|
||||
cache_guild(guild_id, channels);
|
||||
if (std::find(channels.begin(), channels.end(), channel_id) == channels.end())
|
||||
channels.push_back(channel_id);
|
||||
|
||||
m_channelCache.push_back({ guild_id, std::move(channels) });
|
||||
}
|
||||
|
||||
void file::cache_get_channel(dpp::snowflake channel_id, bot::settings::channel *channel)
|
||||
void file::cache_get_channel(dpp::snowflake channel_id, settings::channel &channel)
|
||||
{
|
||||
channel->id = channel_id;
|
||||
channel.id = channel_id;
|
||||
|
||||
const std::filesystem::path channel_file = m_storagePath / "channel" / (std::to_string(channel_id) + ".json");
|
||||
|
||||
|
@ -418,7 +418,7 @@ void file::cache_get_channel(dpp::snowflake channel_id, bot::settings::channel *
|
|||
if (json.is_object()) {
|
||||
auto json_channel_source = json.find("source");
|
||||
if (json_channel_source != json.end())
|
||||
channel->source = *json_channel_source;
|
||||
channel.source = *json_channel_source;
|
||||
|
||||
auto json_channel_target = json.find("target");
|
||||
if (json_channel_target != json.end()) {
|
||||
|
@ -433,7 +433,7 @@ void file::cache_get_channel(dpp::snowflake channel_id, bot::settings::channel *
|
|||
else if (json_target->is_string()) {
|
||||
target.webhook = dpp::webhook(*json_target);
|
||||
}
|
||||
channel->targets.push_back(std::move(target));
|
||||
channel.targets.push_back(std::move(target));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -444,7 +444,7 @@ void file::cache_get_channel(dpp::snowflake channel_id, bot::settings::channel *
|
|||
}
|
||||
}
|
||||
|
||||
void file::cache_guild(dpp::snowflake guild_id, std::vector<dpp::snowflake> *channels)
|
||||
void file::cache_guild(dpp::snowflake guild_id, std::vector<dpp::snowflake> &channels)
|
||||
{
|
||||
const std::filesystem::path guild_file = m_storagePath / "guild" / (std::to_string(guild_id) + ".json");
|
||||
|
||||
|
@ -463,9 +463,9 @@ void file::cache_guild(dpp::snowflake guild_id, std::vector<dpp::snowflake> *cha
|
|||
if (json.is_array()) {
|
||||
for (auto channel = json.begin(); channel != json.end(); channel++) {
|
||||
if (channel->is_number())
|
||||
channels->push_back(*channel);
|
||||
channels.push_back(*channel);
|
||||
else if (channel->is_string())
|
||||
channels->push_back(std::stoull(std::string(*channel)));
|
||||
channels.push_back(std::stoull(std::string(*channel)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -474,7 +474,7 @@ void file::cache_guild(dpp::snowflake guild_id, std::vector<dpp::snowflake> *cha
|
|||
}
|
||||
}
|
||||
|
||||
void file::list_guilds(std::vector<dpp::snowflake> *guilds)
|
||||
void file::list_guilds(std::vector<dpp::snowflake> &guilds)
|
||||
{
|
||||
const std::filesystem::path guild_dir = m_storagePath / "guild";
|
||||
|
||||
|
@ -488,7 +488,7 @@ void file::list_guilds(std::vector<dpp::snowflake> *guilds)
|
|||
if (std::all_of(guild_filename.begin(), guild_filename.end(), ::isdigit)) {
|
||||
try {
|
||||
dpp::snowflake guild_id = std::stoull(guild_filename);
|
||||
guilds->push_back(guild_id);
|
||||
guilds.push_back(guild_id);
|
||||
}
|
||||
catch (const std::exception &exception) {
|
||||
std::cerr << "[Exception] " << exception.what() << std::endl;
|
|
@ -26,7 +26,7 @@
|
|||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include "database_core.h"
|
||||
#include "../../core/database.h"
|
||||
|
||||
namespace bot {
|
||||
namespace database {
|
||||
|
@ -53,9 +53,9 @@ namespace bot {
|
|||
|
||||
private:
|
||||
void cache_add_channel(dpp::snowflake guild_id, dpp::snowflake channel_id);
|
||||
void cache_get_channel(dpp::snowflake channel_id, bot::settings::channel *channel);
|
||||
void cache_guild(dpp::snowflake guild_id, std::vector<dpp::snowflake> *channels);
|
||||
void list_guilds(std::vector<dpp::snowflake> *guilds);
|
||||
void cache_get_channel(dpp::snowflake channel_id, bot::settings::channel &channel);
|
||||
void cache_guild(dpp::snowflake guild_id, std::vector<dpp::snowflake> &channels);
|
||||
void list_guilds(std::vector<dpp::snowflake> &guilds);
|
||||
void sync_cache();
|
||||
#if defined(__unix__)
|
||||
int fd;
|
29
src/resources/win32/dtranslatebot.rc.in
Normal file
29
src/resources/win32/dtranslatebot.rc.in
Normal file
|
@ -0,0 +1,29 @@
|
|||
#include <windows.h>
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION @dtranslatebot_VERSION_MAJOR@, @dtranslatebot_VERSION_MINOR@, @dtranslatebot_VERSION_PATCH@, 0
|
||||
PRODUCTVERSION @dtranslatebot_VERSION_MAJOR@, @dtranslatebot_VERSION_MINOR@, @dtranslatebot_VERSION_PATCH@, 0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x0, 1200
|
||||
END
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Syping"
|
||||
VALUE "FileDescription", "Discord Translation Bot"
|
||||
VALUE "FileVersion", "@dtranslatebot_VERSION@"
|
||||
VALUE "InternalName", "dtranslatebot"
|
||||
VALUE "LegalCopyright", "Copyright © 2023-2024 Syping"
|
||||
VALUE "OriginalFilename", "dtranslatebot.exe"
|
||||
VALUE "ProductName", "dtranslatebot"
|
||||
VALUE "ProductVersion", "@dtranslatebot_VERSION@"
|
||||
END
|
||||
END
|
||||
END
|
13
src/systemd/dtranslatebot.service.in
Normal file
13
src/systemd/dtranslatebot.service.in
Normal file
|
@ -0,0 +1,13 @@
|
|||
[Unit]
|
||||
Description=Discord Translation Bot
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
User=dtranslatebot
|
||||
Group=dtranslatebot
|
||||
WorkingDirectory=@dtranslatebot_SERVICE_WORKDIR@
|
||||
ExecStart="@CMAKE_INSTALL_FULL_BINDIR@/dtranslatebot" "@CMAKE_INSTALL_FULL_SYSCONFDIR@/dtranslatebot.json"
|
||||
Restart=on-abnormal
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
1
src/systemd/dtranslatebot.sysusersd.in
Normal file
1
src/systemd/dtranslatebot.sysusersd.in
Normal file
|
@ -0,0 +1 @@
|
|||
u dtranslatebot - "Discord Translation Bot" "@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/lib/dtranslatebot" -
|
116
src/translator/deepl/deepl.cpp
Normal file
116
src/translator/deepl/deepl.cpp
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*****************************************************************************
|
||||
* dtranslatebot Discord Translate Bot
|
||||
* Copyright (C) 2024 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 <dpp/json.h>
|
||||
#include <dpp/httpsclient.h>
|
||||
#include "deepl.h"
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
deepl::~deepl()
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector<language> deepl::get_languages()
|
||||
{
|
||||
if (!m_languages.languages.empty()) {
|
||||
auto current_time = std::chrono::system_clock::now();
|
||||
auto threshold_time = m_languages.query_time + 24h;
|
||||
if (current_time <= threshold_time)
|
||||
return m_languages.languages;
|
||||
}
|
||||
|
||||
try {
|
||||
dpp::https_client http_request(&m_cluster, m_hostname, 443, "/v2/languages?type=target", "GET", {}, { {"Authorization"s, "DeepL-Auth-Key " + m_apiKey} }, false);
|
||||
if (http_request.get_status() == 200) {
|
||||
const dpp::json response = dpp::json::parse(http_request.get_content());
|
||||
if (response.is_array()) {
|
||||
m_languages.languages.clear();
|
||||
for (auto json_language = response.begin(); json_language != response.end(); json_language++) {
|
||||
if (json_language->is_object()) {
|
||||
language language;
|
||||
|
||||
auto json_lang_code = json_language->find("language");
|
||||
if (json_lang_code != json_language->end())
|
||||
language.code = *json_lang_code;
|
||||
|
||||
if (language.code.size() > 2)
|
||||
std::transform(language.code.begin(), language.code.begin() + 2, language.code.begin(), ::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())
|
||||
language.name = *json_lang_name;
|
||||
|
||||
if (!language.code.empty() && !language.name.empty())
|
||||
m_languages.languages.push_back(std::move(language));
|
||||
}
|
||||
}
|
||||
m_languages.query_time = std::chrono::system_clock::now();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception &exception) {
|
||||
std::cerr << "[Exception] " << exception.what() << std::endl;
|
||||
}
|
||||
|
||||
return m_languages.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 } },
|
||||
{"source_lang"s, source},
|
||||
{"target_lang"s, target},
|
||||
};
|
||||
|
||||
try {
|
||||
dpp::https_client http_request(&m_cluster, m_hostname, 443, "/v2/translate", "POST", json_body.dump(), http_headers, false);
|
||||
if (http_request.get_status() == 200) {
|
||||
const dpp::json response = dpp::json::parse(http_request.get_content());
|
||||
if (response.is_object()) {
|
||||
auto translations = response.find("translations");
|
||||
if (translations != response.end() && translations->is_array()) {
|
||||
for (auto translation = translations->begin(); translation != translations->end(); translation++) {
|
||||
auto tr_text = translation->find("text");
|
||||
if (tr_text != translation->end())
|
||||
return *tr_text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception &exception) {
|
||||
std::cerr << "[Exception] " << exception.what() << std::endl;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
43
src/translator/deepl/deepl.h
Normal file
43
src/translator/deepl/deepl.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*****************************************************************************
|
||||
* dtranslatebot Discord Translate Bot
|
||||
* Copyright (C) 2024 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 TRANSLATOR_DEEPL_H
|
||||
#define TRANSLATOR_DEEPL_H
|
||||
|
||||
#include <dpp/cluster.h>
|
||||
#include "../../core/translator.h"
|
||||
|
||||
namespace bot {
|
||||
namespace translator {
|
||||
class deepl : public translator {
|
||||
public:
|
||||
explicit deepl(const std::string &hostname, const std::string apiKey = {});
|
||||
~deepl() override;
|
||||
const std::vector<language> get_languages() override;
|
||||
const std::string translate(const std::string &text, const std::string &source, const std::string &target) override;
|
||||
|
||||
private:
|
||||
dpp::cluster m_cluster;
|
||||
std::string m_apiKey;
|
||||
std::string m_hostname;
|
||||
supported_languages m_languages;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TRANSLATOR_DEEPL_H
|
|
@ -18,8 +18,9 @@
|
|||
|
||||
#include <dpp/json.h>
|
||||
#include <dpp/httpsclient.h>
|
||||
#include "translator_libretranslate.h"
|
||||
#include "libretranslate.h"
|
||||
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) :
|
||||
|
@ -33,29 +34,36 @@ libretranslate::~libretranslate()
|
|||
|
||||
const std::vector<language> libretranslate::get_languages()
|
||||
{
|
||||
std::vector<language> languages;
|
||||
if (!m_languages.languages.empty()) {
|
||||
auto current_time = std::chrono::system_clock::now();
|
||||
auto threshold_time = m_languages.query_time + 24h;
|
||||
if (current_time <= threshold_time)
|
||||
return m_languages.languages;
|
||||
}
|
||||
|
||||
try {
|
||||
dpp::https_client http_request(m_hostname, m_port, m_url + "languages", "GET", {}, {}, !m_tls);
|
||||
dpp::https_client http_request(&m_cluster, m_hostname, m_port, m_url + "languages", "GET", {}, {}, !m_tls);
|
||||
if (http_request.get_status() == 200) {
|
||||
const dpp::json response = dpp::json::parse(http_request.get_content());
|
||||
if (response.is_array()) {
|
||||
for (const auto &json_language : response) {
|
||||
if (json_language.is_object()) {
|
||||
m_languages.languages.clear();
|
||||
for (auto json_language = response.begin(); json_language != response.end(); json_language++) {
|
||||
if (json_language->is_object()) {
|
||||
language language;
|
||||
|
||||
auto json_lang_code = json_language.find("code");
|
||||
if (json_lang_code != json_language.end())
|
||||
auto json_lang_code = json_language->find("code");
|
||||
if (json_lang_code != json_language->end())
|
||||
language.code = *json_lang_code;
|
||||
|
||||
auto json_lang_name = json_language.find("name");
|
||||
if (json_lang_name != json_language.end())
|
||||
auto json_lang_name = json_language->find("name");
|
||||
if (json_lang_name != json_language->end())
|
||||
language.name = *json_lang_name;
|
||||
|
||||
if (!language.code.empty() && !language.name.empty())
|
||||
languages.push_back(std::move(language));
|
||||
m_languages.languages.push_back(std::move(language));
|
||||
}
|
||||
}
|
||||
m_languages.query_time = std::chrono::system_clock::now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +71,7 @@ const std::vector<language> libretranslate::get_languages()
|
|||
std::cerr << "[Exception] " << exception.what() << std::endl;
|
||||
}
|
||||
|
||||
return languages;
|
||||
return m_languages.languages;
|
||||
}
|
||||
|
||||
const std::string libretranslate::translate(const std::string &text, const std::string &source, const std::string &target)
|
||||
|
@ -83,7 +91,7 @@ const std::string libretranslate::translate(const std::string &text, const std::
|
|||
json_body["apiKey"] = m_apiKey;
|
||||
|
||||
try {
|
||||
dpp::https_client http_request(m_hostname, m_port, m_url + "translate", "POST", json_body.dump(), http_headers, !m_tls);
|
||||
dpp::https_client http_request(&m_cluster, m_hostname, m_port, m_url + "translate", "POST", json_body.dump(), http_headers, !m_tls);
|
||||
if (http_request.get_status() == 200) {
|
||||
const dpp::json response = dpp::json::parse(http_request.get_content());
|
||||
if (response.is_object()) {
|
|
@ -20,12 +20,13 @@
|
|||
#define TRANSLATOR_LIBRETRANSLATE_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include "translator_core.h"
|
||||
#include <dpp/cluster.h>
|
||||
#include "../../core/translator.h"
|
||||
|
||||
namespace bot {
|
||||
namespace translator {
|
||||
class libretranslate : public translator {
|
||||
|
||||
public:
|
||||
explicit libretranslate(const std::string &hostname, uint16_t port, const std::string &url, bool tls, const std::string apiKey = {});
|
||||
~libretranslate() override;
|
||||
|
@ -33,8 +34,10 @@ namespace bot {
|
|||
const std::string translate(const std::string &text, const std::string &source, const std::string &target) override;
|
||||
|
||||
private:
|
||||
dpp::cluster m_cluster;
|
||||
std::string m_apiKey;
|
||||
std::string m_hostname;
|
||||
supported_languages m_languages;
|
||||
uint16_t m_port;
|
||||
std::string m_url;
|
||||
bool m_tls;
|
99
src/translator/lingvatranslate/lingvatranslate.cpp
Normal file
99
src/translator/lingvatranslate/lingvatranslate.cpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*****************************************************************************
|
||||
* dtranslatebot Discord Translate Bot
|
||||
* Copyright (C) 2024 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 <dpp/json.h>
|
||||
#include <dpp/httpsclient.h>
|
||||
#include <dpp/utility.h>
|
||||
#include "lingvatranslate.h"
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
lingvatranslate::~lingvatranslate()
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector<language> lingvatranslate::get_languages()
|
||||
{
|
||||
if (!m_languages.languages.empty()) {
|
||||
auto current_time = std::chrono::system_clock::now();
|
||||
auto threshold_time = m_languages.query_time + 24h;
|
||||
if (current_time <= threshold_time)
|
||||
return m_languages.languages;
|
||||
}
|
||||
|
||||
try {
|
||||
dpp::https_client http_request(&m_cluster, m_hostname, m_port, m_url + "api/v1/languages/target", "GET", {}, {}, !m_tls);
|
||||
if (http_request.get_status() == 200) {
|
||||
const dpp::json response = dpp::json::parse(http_request.get_content());
|
||||
if (response.is_object()) {
|
||||
auto languages = response.find("languages");
|
||||
if (languages != response.end()) {
|
||||
m_languages.languages.clear();
|
||||
for (auto json_language = languages->begin(); json_language != languages->end(); json_language++) {
|
||||
if (json_language->is_object()) {
|
||||
language language;
|
||||
|
||||
auto json_lang_code = json_language->find("code");
|
||||
if (json_lang_code != json_language->end())
|
||||
language.code = *json_lang_code;
|
||||
|
||||
auto json_lang_name = json_language->find("name");
|
||||
if (json_lang_name != json_language->end())
|
||||
language.name = *json_lang_name;
|
||||
|
||||
if (!language.code.empty() && !language.name.empty())
|
||||
m_languages.languages.push_back(std::move(language));
|
||||
}
|
||||
}
|
||||
m_languages.query_time = std::chrono::system_clock::now();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception &exception) {
|
||||
std::cerr << "[Exception] " << exception.what() << std::endl;
|
||||
}
|
||||
|
||||
return m_languages.languages;
|
||||
}
|
||||
|
||||
const std::string lingvatranslate::translate(const std::string &text, const std::string &source, const std::string &target)
|
||||
{
|
||||
try {
|
||||
dpp::https_client http_request(&m_cluster, m_hostname, m_port, m_url + "api/v1/" + source + "/" + target + "/" + dpp::utility::url_encode(text), "GET", {}, {}, !m_tls);
|
||||
if (http_request.get_status() == 200) {
|
||||
const dpp::json response = dpp::json::parse(http_request.get_content());
|
||||
if (response.is_object()) {
|
||||
auto tr_text = response.find("translation");
|
||||
if (tr_text != response.end())
|
||||
return *tr_text;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception &exception) {
|
||||
std::cerr << "[Exception] " << exception.what() << std::endl;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
47
src/translator/lingvatranslate/lingvatranslate.h
Normal file
47
src/translator/lingvatranslate/lingvatranslate.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*****************************************************************************
|
||||
* dtranslatebot Discord Translate Bot
|
||||
* Copyright (C) 2024 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 TRANSLATOR_LINGVATRANSLATE_H
|
||||
#define TRANSLATOR_LINGVATRANSLATE_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <dpp/cluster.h>
|
||||
#include "../../core/translator.h"
|
||||
|
||||
namespace bot {
|
||||
namespace translator {
|
||||
class lingvatranslate : public translator {
|
||||
|
||||
public:
|
||||
explicit lingvatranslate(const std::string &hostname, uint16_t port, const std::string &url, bool tls);
|
||||
~lingvatranslate() override;
|
||||
const std::vector<language> get_languages() override;
|
||||
const std::string translate(const std::string &text, const std::string &source, const std::string &target) override;
|
||||
|
||||
private:
|
||||
dpp::cluster m_cluster;
|
||||
std::string m_hostname;
|
||||
supported_languages m_languages;
|
||||
uint16_t m_port;
|
||||
std::string m_url;
|
||||
bool m_tls;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TRANSLATOR_LINGVATRANSLATE_H
|
105
src/translator/mozhi/mozhi.cpp
Normal file
105
src/translator/mozhi/mozhi.cpp
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*****************************************************************************
|
||||
* dtranslatebot Discord Translate Bot
|
||||
* Copyright (C) 2024 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 <dpp/json.h>
|
||||
#include <dpp/httpsclient.h>
|
||||
#include <dpp/utility.h>
|
||||
#include "mozhi.h"
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
mozhi::~mozhi()
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector<language> mozhi::get_languages()
|
||||
{
|
||||
if (!m_languages.languages.empty()) {
|
||||
auto current_time = std::chrono::system_clock::now();
|
||||
auto threshold_time = m_languages.query_time + 24h;
|
||||
if (current_time <= threshold_time)
|
||||
return m_languages.languages;
|
||||
}
|
||||
|
||||
try {
|
||||
const std::string parameters = dpp::utility::make_url_parameters({
|
||||
{"engine"s, m_engine}
|
||||
});
|
||||
dpp::https_client http_request(&m_cluster, m_hostname, m_port, m_url + "api/target_languages" + parameters, "GET", {}, {}, !m_tls);
|
||||
if (http_request.get_status() == 200) {
|
||||
const dpp::json response = dpp::json::parse(http_request.get_content());
|
||||
if (response.is_array()) {
|
||||
m_languages.languages.clear();
|
||||
for (auto json_language = response.begin(); json_language != response.end(); json_language++) {
|
||||
if (json_language->is_object()) {
|
||||
language language;
|
||||
|
||||
auto json_lang_code = json_language->find("Id");
|
||||
if (json_lang_code != json_language->end())
|
||||
language.code = *json_lang_code;
|
||||
|
||||
auto json_lang_name = json_language->find("Name");
|
||||
if (json_lang_name != json_language->end())
|
||||
language.name = *json_lang_name;
|
||||
|
||||
if (!language.code.empty() && !language.name.empty())
|
||||
m_languages.languages.push_back(std::move(language));
|
||||
}
|
||||
}
|
||||
m_languages.query_time = std::chrono::system_clock::now();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception &exception) {
|
||||
std::cerr << "[Exception] " << exception.what() << std::endl;
|
||||
}
|
||||
|
||||
return m_languages.languages;
|
||||
}
|
||||
|
||||
const std::string mozhi::translate(const std::string &text, const std::string &source, const std::string &target)
|
||||
{
|
||||
try {
|
||||
const std::string parameters = dpp::utility::make_url_parameters({
|
||||
{"engine"s, m_engine},
|
||||
{"from"s, source},
|
||||
{"to"s, target},
|
||||
{"text"s, text},
|
||||
});
|
||||
dpp::https_client http_request(&m_cluster, m_hostname, m_port, m_url + "api/translate" + parameters, "GET", {}, {}, !m_tls);
|
||||
if (http_request.get_status() == 200) {
|
||||
const dpp::json response = dpp::json::parse(http_request.get_content());
|
||||
if (response.is_object()) {
|
||||
auto tr_text = response.find("translated-text");
|
||||
if (tr_text != response.end())
|
||||
return *tr_text;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception &exception) {
|
||||
std::cerr << "[Exception] " << exception.what() << std::endl;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
48
src/translator/mozhi/mozhi.h
Normal file
48
src/translator/mozhi/mozhi.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*****************************************************************************
|
||||
* dtranslatebot Discord Translate Bot
|
||||
* Copyright (C) 2024 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 TRANSLATOR_MOZHI_H
|
||||
#define TRANSLATOR_MOZHI_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <dpp/cluster.h>
|
||||
#include "../../core/translator.h"
|
||||
|
||||
namespace bot {
|
||||
namespace translator {
|
||||
class mozhi : public translator {
|
||||
|
||||
public:
|
||||
explicit mozhi(const std::string &hostname, uint16_t port, const std::string &url, bool tls, const std::string &engine);
|
||||
~mozhi() override;
|
||||
const std::vector<language> get_languages() override;
|
||||
const std::string translate(const std::string &text, const std::string &source, const std::string &target) override;
|
||||
|
||||
private:
|
||||
dpp::cluster m_cluster;
|
||||
std::string m_engine;
|
||||
std::string m_hostname;
|
||||
supported_languages m_languages;
|
||||
uint16_t m_port;
|
||||
std::string m_url;
|
||||
bool m_tls;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TRANSLATOR_MOZHI_H
|
39
src/translator/stub/stub.cpp
Normal file
39
src/translator/stub/stub.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*****************************************************************************
|
||||
* dtranslatebot Discord Translate Bot
|
||||
* Copyright (C) 2024 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 "stub.h"
|
||||
using namespace bot::translator;
|
||||
using namespace std::string_literals;
|
||||
|
||||
stub::stub()
|
||||
{
|
||||
}
|
||||
|
||||
stub::~stub()
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector<language> stub::get_languages()
|
||||
{
|
||||
return { {"a*", "Any Language"} };
|
||||
}
|
||||
|
||||
const std::string stub::translate(const std::string &text, [[maybe_unused]] const std::string &source, [[maybe_unused]] const std::string &target)
|
||||
{
|
||||
return text;
|
||||
}
|
36
src/translator/stub/stub.h
Normal file
36
src/translator/stub/stub.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*****************************************************************************
|
||||
* dtranslatebot Discord Translate Bot
|
||||
* Copyright (C) 2024 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 TRANSLATOR_STUB_H
|
||||
#define TRANSLATOR_STUB_H
|
||||
|
||||
#include "../../core/translator.h"
|
||||
|
||||
namespace bot {
|
||||
namespace translator {
|
||||
class stub : public translator {
|
||||
public:
|
||||
explicit stub();
|
||||
~stub() override;
|
||||
const std::vector<language> get_languages() override;
|
||||
const std::string translate(const std::string &text, const std::string &source, const std::string &target) override;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TRANSLATOR_STUB_H
|
Loading…
Add table
Add a link
Reference in a new issue