mirror of
https://github.com/Syping/dtranslatebot.git
synced 2025-12-12 22:56:25 +01: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
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)
|
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)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
# dtranslatebot Source files
|
# dtranslatebot Source files
|
||||||
set(DTRANSLATEBOT_HEADERS
|
set(DTRANSLATEBOT_HEADERS
|
||||||
src/database_core.h
|
src/core/database.h
|
||||||
src/database_file.h
|
src/core/message_queue.h
|
||||||
src/message_queue.h
|
src/core/regex.h
|
||||||
src/regex.h
|
src/core/settings.h
|
||||||
src/settings.h
|
src/core/settings_types.h
|
||||||
src/settings_types.h
|
src/core/slashcommands.h
|
||||||
src/slashcommands.h
|
src/core/submit_queue.h
|
||||||
src/submit_queue.h
|
src/core/translator.h
|
||||||
src/translator_core.h
|
src/core/webhook_push.h
|
||||||
src/translator_libretranslate.h
|
src/database/file/file.h
|
||||||
src/webhook_push.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
|
set(DTRANSLATEBOT_SOURCES
|
||||||
src/database_core.cpp
|
src/core/database.cpp
|
||||||
src/database_file.cpp
|
src/core/main.cpp
|
||||||
src/main.cpp
|
src/core/message_queue.cpp
|
||||||
src/message_queue.cpp
|
src/core/settings.cpp
|
||||||
src/settings.cpp
|
src/core/slashcommands.cpp
|
||||||
src/slashcommands.cpp
|
src/core/submit_queue.cpp
|
||||||
src/submit_queue.cpp
|
src/core/translator.cpp
|
||||||
src/translator_core.cpp
|
src/core/webhook_push.cpp
|
||||||
src/translator_libretranslate.cpp
|
src/database/file/file.cpp
|
||||||
src/webhook_push.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
|
# dtranslatebot Module Path
|
||||||
|
|
@ -63,21 +72,59 @@ if (WITH_BOOST)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# D++ Discord API Library for Bots
|
# 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
|
# pthread Support
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
find_package(Threads REQUIRED)
|
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
|
# 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
|
target_compile_definitions(dtranslatebot PRIVATE
|
||||||
|
${DPP_DEFINITIONS}
|
||||||
$<$<BOOL:${DTRANSLATEBOT_USE_BOOST_REGEX}>:DTRANSLATEBOT_USE_BOOST_REGEX>
|
$<$<BOOL:${DTRANSLATEBOT_USE_BOOST_REGEX}>:DTRANSLATEBOT_USE_BOOST_REGEX>
|
||||||
)
|
)
|
||||||
if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914)
|
if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914)
|
||||||
target_compile_options(dtranslatebot PRIVATE $<$<COMPILE_LANGUAGE:CXX>:/Zc:__cplusplus>)
|
target_compile_options(dtranslatebot PRIVATE $<$<COMPILE_LANGUAGE:CXX>:/Zc:__cplusplus>)
|
||||||
endif()
|
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})
|
target_include_directories(dtranslatebot PRIVATE ${DPP_INCLUDE_DIR})
|
||||||
set_target_properties(dtranslatebot PROPERTIES
|
set_target_properties(dtranslatebot PROPERTIES
|
||||||
CXX_STANDARD 17
|
CXX_STANDARD 17
|
||||||
|
|
|
||||||
13
README.md
13
README.md
|
|
@ -2,7 +2,7 @@
|
||||||
Open Source Discord Translation Bot
|
Open Source Discord Translation Bot
|
||||||
|
|
||||||
- Translate incoming channel messages to a Webhook
|
- Translate incoming channel messages to a Webhook
|
||||||
- Support configuration through slashcommands and JSON
|
- Support configuration through slash commands and JSON
|
||||||
- Cross-Platform
|
- Cross-Platform
|
||||||
|
|
||||||
#### Build Dependencies
|
#### Build Dependencies
|
||||||
|
|
@ -10,8 +10,11 @@ Open Source Discord Translation Bot
|
||||||
- Compiler with C++17 Support
|
- Compiler with C++17 Support
|
||||||
- [D++: A C++ Discord API Library for Bots](https://dpp.dev/)
|
- [D++: A C++ Discord API Library for Bots](https://dpp.dev/)
|
||||||
|
|
||||||
#### Runtime Dependencies
|
#### Supported Translation Engines
|
||||||
- [LibreTranslate](https://libretranslate.com/)
|
- [LibreTranslate](https://libretranslate.com/) (Default)
|
||||||
|
- [Lingva Translate](https://lingva.ml/)
|
||||||
|
- [Mozhi](https://codeberg.org/aryak/mozhi)
|
||||||
|
- [DeepL](https://deepl.com/) (Experimental)
|
||||||
|
|
||||||
#### Build dtranslatebot
|
#### Build dtranslatebot
|
||||||
|
|
||||||
|
|
@ -23,4 +26,6 @@ sudo cmake --install dtranslatebot-build
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Optional CMake flags
|
##### 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_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_library(DPP_LIBRARIES NAMES "dpp" "libdpp.a" HINTS "${DPP_ROOT_DIR}")
|
||||||
include(FindPackageHandleStandardArgs)
|
include(FindPackageHandleStandardArgs)
|
||||||
find_package_handle_standard_args(DPP DEFAULT_MSG DPP_LIBRARIES DPP_INCLUDE_DIR)
|
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
|
#ifndef NDEBUG
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#endif
|
#endif
|
||||||
#include "database_core.h"
|
#include "database.h"
|
||||||
using namespace bot::database;
|
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)
|
void database::add_channel_target(dpp::snowflake guild_id, dpp::snowflake channel_id, const bot::settings::target &target)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
@ -16,8 +16,8 @@
|
||||||
* responsible for anything with use of the software, you are self responsible.
|
* responsible for anything with use of the software, you are self responsible.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#ifndef DATABASE_CORE_H
|
#ifndef DATABASE_H
|
||||||
#define DATABASE_CORE_H
|
#define DATABASE_H
|
||||||
|
|
||||||
#include "settings_types.h"
|
#include "settings_types.h"
|
||||||
|
|
||||||
|
|
@ -30,8 +30,10 @@ namespace bot {
|
||||||
|
|
||||||
class database {
|
class database {
|
||||||
public:
|
public:
|
||||||
explicit database();
|
explicit database() = default;
|
||||||
virtual ~database();
|
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 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(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);
|
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 "message_queue.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "slashcommands.h"
|
#include "slashcommands.h"
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
if (argc != 2) {
|
bool flag_wait_for_translator = false;
|
||||||
std::cout << "Usage: " << argv[0] << " [json]" << std::endl;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "[Launch] Processing configuration..." << std::endl;
|
std::cout << "[Launch] Processing configuration..." << std::endl;
|
||||||
bot::settings::settings settings;
|
bot::settings::settings settings;
|
||||||
if (!settings.parse_file(argv[1]))
|
if (!settings.parse_file(args.at(0)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
std::cout << "[Launch] Requesting supported languages..." << std::endl;
|
for (;;) {
|
||||||
if (settings.get_translator()->get_languages().empty()) {
|
std::cout << "[Launch] Requesting supported languages..." << std::endl;
|
||||||
std::cerr << "[Error] Failed to initialise translateable languages" << std::endl;
|
if (!settings.get_translator()->get_languages().empty()) {
|
||||||
return 2;
|
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);
|
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_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_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>()) {
|
if (dpp::run_once<struct register_bot_commands>()) {
|
||||||
bot::slashcommands::register_commands(&bot, &settings);
|
bot::slashcommands::register_commands(&bot, &settings);
|
||||||
}
|
}
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include "message_queue.h"
|
#include "message_queue.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
using namespace bot;
|
using bot::message_queue;
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
void message_queue::add(const message &message)
|
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)
|
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) {
|
if (event.msg.webhook_id) {
|
||||||
const std::lock_guard<bot::settings::settings> guard(*settings);
|
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;
|
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);
|
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)) {
|
if (const bot::settings::channel *channel = settings->get_channel(event.msg.guild_id, event.msg.channel_id)) {
|
||||||
bot::message message;
|
bot::message message;
|
||||||
|
|
@ -19,19 +19,23 @@
|
||||||
#include <dpp/json.h>
|
#include <dpp/json.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "database_file.h"
|
|
||||||
#include "settings.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;
|
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++) {
|
for (auto db_channel_id = db_channels.begin(); db_channel_id != db_channels.end(); db_channel_id++) {
|
||||||
bool channel_found = false;
|
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) {
|
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())
|
if (!db_channel.source.empty())
|
||||||
channel->source = db_channel.source;
|
channel->source = db_channel.source;
|
||||||
for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++) {
|
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++) {
|
for (auto target = channel->targets.begin(); target != channel->targets.end(); target++) {
|
||||||
if (target->target == db_target->target) {
|
if (target->target == db_target->target) {
|
||||||
target->webhook = db_target->webhook;
|
target->webhook = db_target->webhook;
|
||||||
webhookIds->push_back(db_target->webhook.id);
|
webhookIds.push_back(db_target->webhook.id);
|
||||||
target_found = true;
|
target_found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!target_found) {
|
if (!target_found) {
|
||||||
channel->targets.push_back(*db_target);
|
channel->targets.push_back(*db_target);
|
||||||
webhookIds->push_back(db_target->webhook.id);
|
webhookIds.push_back(db_target->webhook.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
channel_found = true;
|
channel_found = true;
|
||||||
|
|
@ -54,23 +58,23 @@ void process_database_channels(std::shared_ptr<bot::database::database> database
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!channel_found) {
|
if (!channel_found) {
|
||||||
const bot::settings::channel db_channel = database->get_channel(guild->id, *db_channel_id);
|
const bot::settings::channel db_channel = database->get_channel(guild.id, *db_channel_id);
|
||||||
guild->channel.push_back(db_channel);
|
guild.channel.push_back(db_channel);
|
||||||
for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++)
|
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;
|
std::cout << "[Launch] Loading database..." << std::endl;
|
||||||
const std::vector<dpp::snowflake> db_guilds = database->get_guilds();
|
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++) {
|
for (auto db_guild_id = db_guilds.begin(); db_guild_id != db_guilds.end(); db_guild_id++) {
|
||||||
bool guild_found = false;
|
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) {
|
if (guild->id == *db_guild_id) {
|
||||||
process_database_channels(database, &*guild, webhookIds);
|
process_database_channels(database, *guild, webhookIds);
|
||||||
guild_found = true;
|
guild_found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -78,13 +82,13 @@ void process_database(std::shared_ptr<bot::database::database> database, std::ve
|
||||||
if (!guild_found) {
|
if (!guild_found) {
|
||||||
bot::settings::guild guild;
|
bot::settings::guild guild;
|
||||||
guild.id = *db_guild_id;
|
guild.id = *db_guild_id;
|
||||||
process_database_channels(database, &guild, webhookIds);
|
process_database_channels(database, guild, webhookIds);
|
||||||
guilds->push_back(std::move(guild));
|
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++) {
|
for (auto json_guild = json.begin(); json_guild != json.end(); json_guild++) {
|
||||||
if (json_guild->is_object()) {
|
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;
|
||||||
target.target = *json_channel_target;
|
target.target = *json_channel_target;
|
||||||
target.webhook = dpp::webhook(json_channel->at("webhook"));
|
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));
|
channel.targets.push_back(std::move(target));
|
||||||
}
|
}
|
||||||
else if (json_channel_target->is_object()) {
|
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;
|
||||||
target.target = json_target.key();
|
target.target = json_target.key();
|
||||||
target.webhook = dpp::webhook(*json_target);
|
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));
|
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));
|
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)
|
void process_server_url(const std::string &url, translator &translator)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
std::string_view url_v = url;
|
std::string_view url_v = url;
|
||||||
if (url_v.substr(0, 7) == "http://") {
|
if (url_v.substr(0, 7) == "http://") {
|
||||||
translator->tls = false;
|
translator.tls = false;
|
||||||
if (!translator->port)
|
if (!translator.port)
|
||||||
translator->port = 80;
|
translator.port = 80;
|
||||||
url_v = url_v.substr(7);
|
url_v = url_v.substr(7);
|
||||||
}
|
}
|
||||||
else if (url_v.substr(0, 8) == "https://") {
|
else if (url_v.substr(0, 8) == "https://") {
|
||||||
translator->tls = true;
|
translator.tls = true;
|
||||||
if (!translator->port)
|
if (!translator.port)
|
||||||
translator->port = 443;
|
translator.port = 443;
|
||||||
url_v = url_v.substr(8);
|
url_v = url_v.substr(8);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
translator->tls = false;
|
translator.tls = false;
|
||||||
if (!translator->port)
|
if (!translator.port)
|
||||||
translator->port = 80;
|
translator.port = 80;
|
||||||
}
|
}
|
||||||
auto slash_pos = url_v.find_first_of('/');
|
auto slash_pos = url_v.find_first_of('/');
|
||||||
if (slash_pos != std::string_view::npos) {
|
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);
|
url_v = url_v.substr(0, slash_pos);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
translator->url = "/";
|
translator.url = "/";
|
||||||
url_v = url_v.substr(0, slash_pos);
|
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) {
|
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)));
|
const int port = std::stoi(std::string(url_v.substr(colon_pos + 1)));
|
||||||
if (port > 0 && port < 65536)
|
if (port > 0 && port < 65536)
|
||||||
translator->port = static_cast<uint16_t>(port);
|
translator.port = static_cast<uint16_t>(port);
|
||||||
else
|
else
|
||||||
throw std::invalid_argument("Port is out of range");
|
throw std::invalid_argument("Port is out of range");
|
||||||
}
|
}
|
||||||
else {
|
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()) {
|
if (!json.is_object()) {
|
||||||
std::cerr << "[Error] Value translator needs to be a object" << std::endl;
|
std::cerr << "[Error] Value translator needs to be a object" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto json_translate_hostname = json.find("hostname");
|
bot::settings::translator translator;
|
||||||
if (json_translate_hostname != json.end())
|
auto json_translator_type = json.find("type");
|
||||||
translator->hostname = *json_translate_hostname;
|
if (json_translator_type != json.end()) {
|
||||||
else
|
translator.type = *json_translator_type;
|
||||||
translator->hostname = {};
|
std::transform(translator.type.begin(), translator.type.end(), translator.type.begin(), ::tolower);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
translator->url = *json_translate_url;
|
translator.type = "libretranslate";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto json_translate_apiKey = json.find("apiKey");
|
if (translator.type == "deepl") {
|
||||||
if (json_translate_apiKey != json.end())
|
auto json_deepl_hostname = json.find("hostname");
|
||||||
translator->apiKey = *json_translate_apiKey;
|
if (json_deepl_hostname != json.end())
|
||||||
else
|
translator.hostname = *json_deepl_hostname;
|
||||||
translator->apiKey.clear();
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -300,6 +363,27 @@ void settings::add_translatebot_webhook(dpp::snowflake webhook_id)
|
||||||
m_webhookIds.push_back(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)
|
void settings::erase_translatebot_webhook(dpp::snowflake webhook_id)
|
||||||
{
|
{
|
||||||
const std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
const std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
||||||
|
|
@ -314,9 +398,9 @@ uint16_t settings::avatar_size()
|
||||||
return m_avatarSize;
|
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)
|
if (channel->id == channel_id)
|
||||||
return &*channel;
|
return &*channel;
|
||||||
}
|
}
|
||||||
|
|
@ -413,10 +497,10 @@ std::shared_ptr<bot::database::database> settings::get_database() const
|
||||||
return m_database;
|
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);
|
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
|
const std::string settings::token() const
|
||||||
|
|
@ -446,7 +530,7 @@ bool settings::parse(const std::string &data, bool initialize)
|
||||||
try {
|
try {
|
||||||
dpp::json json;
|
dpp::json json;
|
||||||
try {
|
try {
|
||||||
json = dpp::json::parse(data);
|
json = dpp::json::parse(data, nullptr, true, true);
|
||||||
}
|
}
|
||||||
catch (const std::exception &exception) {
|
catch (const std::exception &exception) {
|
||||||
std::cerr << "[Exception] " << exception.what() << std::endl;
|
std::cerr << "[Exception] " << exception.what() << std::endl;
|
||||||
|
|
@ -454,21 +538,24 @@ bool settings::parse(const std::string &data, bool initialize)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
||||||
auto json_token = json.find("token");
|
auto json_token = json.find("token");
|
||||||
if (json_token == json.end()) {
|
if (json_token != json.end())
|
||||||
std::cerr << "[Error] Value token not found" << std::endl;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
|
||||||
m_token = *json_token;
|
|
||||||
|
|
||||||
std::filesystem::path storage_path;
|
std::filesystem::path storage_path;
|
||||||
auto json_storage = json.find("storage");
|
auto json_storage = json.find("storage");
|
||||||
if (json_storage != json.end())
|
if (json_storage != json.end())
|
||||||
storage_path = std::string(*json_storage);
|
storage_path = std::string(*json_storage);
|
||||||
else if (char *storagepath = getenv("DTRANSLATEBOT_STORAGE"))
|
else if (char *storagepath = getenv("DTRANSLATEBOT_STORAGE"))
|
||||||
storage_path = storagepath;
|
storage_path = storagepath;
|
||||||
|
|
||||||
if (storage_path.empty())
|
if (storage_path.empty())
|
||||||
storage_path = std::filesystem::current_path();
|
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;
|
std::cerr << "[Error] Value translator not found" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!process_translator_settings(*json_translator, &m_translator))
|
if (!process_translator_settings(*json_translator, m_translator))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_avatarSize = 256;
|
|
||||||
|
|
||||||
auto json_guilds = json.find("guilds");
|
auto json_guilds = json.find("guilds");
|
||||||
if (json_guilds != json.end() && json_guilds->is_object())
|
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");
|
auto json_preflangs = json.find("preferred_lang");
|
||||||
if (json_preflangs != json.end() && json_preflangs->is_array())
|
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");
|
auto json_user = json.find("user");
|
||||||
if (json_user != json.end() && json_user->is_object())
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -19,9 +19,9 @@
|
||||||
#ifndef SETTINGS_H
|
#ifndef SETTINGS_H
|
||||||
#define SETTINGS_H
|
#define SETTINGS_H
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include "database_core.h"
|
#include "database.h"
|
||||||
#include "settings_types.h"
|
#include "settings_types.h"
|
||||||
#include "translator_core.h"
|
#include "translator.h"
|
||||||
|
|
||||||
namespace bot {
|
namespace bot {
|
||||||
namespace settings {
|
namespace settings {
|
||||||
|
|
@ -33,11 +33,13 @@ namespace bot {
|
||||||
void add_translatebot_webhook(dpp::snowflake webhook_id);
|
void add_translatebot_webhook(dpp::snowflake webhook_id);
|
||||||
|
|
||||||
/* erase functions */
|
/* 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);
|
void erase_translatebot_webhook(dpp::snowflake webhook_id);
|
||||||
|
|
||||||
/* get functions */
|
/* get functions */
|
||||||
uint16_t avatar_size();
|
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);
|
channel* get_channel(dpp::snowflake guild_id, dpp::snowflake channel_id);
|
||||||
guild* get_guild(dpp::snowflake guild_id);
|
guild* get_guild(dpp::snowflake guild_id);
|
||||||
target* get_target(dpp::snowflake guild_id, dpp::snowflake channel_id, const std::string &target);
|
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);
|
static const target* get_target(const channel *channel, const std::string &target);
|
||||||
const std::vector<std::string> preferred_languages() const;
|
const std::vector<std::string> preferred_languages() const;
|
||||||
std::shared_ptr<bot::database::database> get_database() 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;
|
const std::string token() const;
|
||||||
|
|
||||||
/* is functions */
|
/* is functions */
|
||||||
|
|
@ -59,14 +61,19 @@ namespace bot {
|
||||||
bool parse(const std::string &data, bool initialize = true);
|
bool parse(const std::string &data, bool initialize = true);
|
||||||
bool parse_file(const std::string &filename, 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:
|
private:
|
||||||
mutable std::recursive_mutex m_mutex;
|
mutable std::recursive_mutex m_mutex;
|
||||||
size_t m_externallyLockedCount;
|
size_t m_externallyLockedCount = 0;
|
||||||
uint16_t m_avatarSize;
|
uint16_t m_avatarSize = 256;
|
||||||
std::shared_ptr<bot::database::database> m_database;
|
std::shared_ptr<bot::database::database> m_database;
|
||||||
std::vector<guild> m_guilds;
|
std::vector<guild> m_guilds;
|
||||||
std::vector<std::string> m_prefLangs;
|
std::vector<std::string> m_prefLangs;
|
||||||
bot::settings::translator m_translator;
|
std::shared_ptr<bot::translator::translator> m_translator;
|
||||||
std::string m_token;
|
std::string m_token;
|
||||||
std::vector<dpp::snowflake> m_webhookIds;
|
std::vector<dpp::snowflake> m_webhookIds;
|
||||||
};
|
};
|
||||||
|
|
@ -41,6 +41,7 @@ namespace bot {
|
||||||
std::vector<bot::settings::channel> channel;
|
std::vector<bot::settings::channel> channel;
|
||||||
};
|
};
|
||||||
struct translator {
|
struct translator {
|
||||||
|
std::string type;
|
||||||
std::string hostname;
|
std::string hostname;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
std::string url;
|
std::string url;
|
||||||
|
|
@ -18,19 +18,20 @@
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "slashcommands.h"
|
#include "slashcommands.h"
|
||||||
|
using bot::slashcommands;
|
||||||
using namespace std::string_literals;
|
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")
|
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")
|
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")
|
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 {
|
try {
|
||||||
dpp::permission user_permissions = event.command.get_resolved_permission(event.command.usr.id);
|
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();
|
dpp::command_interaction interaction = event.command.get_command_interaction();
|
||||||
if (interaction.options[0].name == "delete") {
|
if (interaction.options[0].name == "delete") {
|
||||||
const std::lock_guard<bot::settings::settings> guard(*settings);
|
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)) {
|
if (bot::settings::guild *guild = settings->get_guild(event.command.guild_id)) {
|
||||||
const std::string target = std::get<std::string>(event.get_parameter("target"));
|
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();
|
auto database = settings->get_database();
|
||||||
const bot::settings::channel db_channel = database->get_channel(event.command.guild_id, event.command.channel_id);
|
const bot::settings::channel db_channel = database->get_channel(event.command.guild_id, event.command.channel_id);
|
||||||
|
|
||||||
if (db_channel.targets.empty()) {
|
if (db_channel.targets.empty()) {
|
||||||
event.reply(dpp::message("The current channel has no deleteable targets!").set_flags(dpp::m_ephemeral));
|
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);
|
|
||||||
}
|
}
|
||||||
for (auto target = channel->targets.begin(); target != channel->targets.end();) {
|
else if (target == "**") {
|
||||||
if (std::find(targets.begin(), targets.end(), target->target) != targets.end()) {
|
std::vector<std::string> targets;
|
||||||
bot->delete_webhook(target->webhook.id, std::bind(&bot::slashcommands::process_deleted_webhook, settings, target->webhook.id, std::placeholders::_1));
|
for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++) {
|
||||||
target = channel->targets.erase(target);
|
targets.push_back(db_target->target);
|
||||||
}
|
}
|
||||||
else {
|
for (auto target = channel->targets.begin(); target != channel->targets.end();) {
|
||||||
target++;
|
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));
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
database->delete_channel(event.command.guild_id, event.command.channel_id);
|
bool target_found = false;
|
||||||
database->sync();
|
for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++) {
|
||||||
|
if (db_target->target == target) {
|
||||||
event.reply(dpp::message("Deleteable targets have being deleted!").set_flags(dpp::m_ephemeral));
|
target_found = true;
|
||||||
}
|
|
||||||
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);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (db_channel.targets.size() == 1)
|
if (target_found) {
|
||||||
database->delete_channel(event.command.guild_id, event.command.channel_id);
|
for (auto _target = channel->targets.begin(); _target != channel->targets.end(); _target++) {
|
||||||
else
|
if (_target->target == target) {
|
||||||
database->delete_channel_target(event.command.guild_id, event.command.channel_id, target);
|
bot->delete_webhook(_target->webhook.id, std::bind(&slashcommands::process_deleted_webhook, settings, _target->webhook.id, std::placeholders::_1));
|
||||||
database->sync();
|
channel->targets.erase(_target);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
event.reply(dpp::message("Target have being deleted!").set_flags(dpp::m_ephemeral));
|
if (db_channel.targets.size() == 1)
|
||||||
}
|
database->delete_channel(event.command.guild_id, event.command.channel_id);
|
||||||
else {
|
else
|
||||||
event.reply(dpp::message("Target language is not being found or deleteable!").set_flags(dpp::m_ephemeral));
|
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 {
|
else {
|
||||||
event.reply(dpp::message("The current channel is not being translated!").set_flags(dpp::m_ephemeral));
|
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;
|
source_valid = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
language_codes << " " << language.code;
|
language_codes << ' ' << language.code;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source_valid) {
|
if (source_valid) {
|
||||||
channel->source = source;
|
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->set_channel_source(event.command.guild_id, event.command.channel_id, source);
|
||||||
database->sync();
|
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()) {
|
if (callback.is_error()) {
|
||||||
std::cerr << "[Error] Failed to delete Webhook " << webhook_id << std::endl;
|
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);
|
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 {
|
try {
|
||||||
dpp::command_interaction interaction = event.command.get_command_interaction();
|
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
|
// We want give more information to users who can Manage Webhooks
|
||||||
dpp::permission user_permissions = event.command.get_resolved_permission(event.command.usr.id);
|
dpp::permission user_permissions = event.command.get_resolved_permission(event.command.usr.id);
|
||||||
if (user_permissions.has(dpp::p_manage_webhooks)) {
|
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);
|
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++) {
|
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));
|
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 {
|
else {
|
||||||
throw std::invalid_argument("Option " + interaction.options[0].name + " is not known");
|
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;
|
std::cerr << "[Exception] " << exception.what() << std::endl;
|
||||||
event.reply(dpp::message("Exception while processing command:\n"s + exception.what()).set_flags(dpp::m_ephemeral));
|
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 {
|
try {
|
||||||
dpp::permission user_permissions = event.command.get_resolved_permission(event.command.usr.id);
|
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();
|
dpp::command_interaction interaction = event.command.get_command_interaction();
|
||||||
if (interaction.options[0].name == "channel") {
|
if (interaction.options[0].name == "channel") {
|
||||||
v_target = event.command.get_resolved_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") {
|
else if (interaction.options[0].name == "webhook") {
|
||||||
v_target = dpp::webhook(std::get<std::string>(event.get_parameter("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;
|
std::ostringstream language_codes;
|
||||||
bool source_valid = false, target_valid = false;
|
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;
|
target_valid = true;
|
||||||
if (source_valid && target_valid)
|
if (source_valid && target_valid)
|
||||||
break;
|
break;
|
||||||
language_codes << " " << language.code;
|
language_codes << ' ' << language.code;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source_valid && target_valid) {
|
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.guild_id = channel->guild_id;
|
||||||
webhook.name = "Translate Bot Webhook <" + std::to_string(event.command.channel_id) + ":" + source + ":" + target + ">";
|
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)) {
|
else if (dpp::webhook *webhook = std::get_if<dpp::webhook>(&v_target)) {
|
||||||
const bot::settings::target s_target = { target, *webhook };
|
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_channel(s_channel, event.command.guild_id);
|
||||||
settings->add_translatebot_webhook(webhook->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->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->add_channel_target(event.command.guild_id, event.command.channel_id, s_target);
|
||||||
database->sync();
|
database->sync();
|
||||||
|
|
@ -298,7 +345,7 @@ void bot::slashcommands::process_translate_command(dpp::cluster *bot, bot::setti
|
||||||
webhook.guild_id = channel->guild_id;
|
webhook.guild_id = channel->guild_id;
|
||||||
webhook.name = "Translate Bot Webhook <" + std::to_string(event.command.channel_id) + ":" + source + ":" + target + ">";
|
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)) {
|
else if (dpp::webhook *webhook = std::get_if<dpp::webhook>(&v_target)) {
|
||||||
const bot::settings::target s_target = { target, *webhook };
|
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_target(s_target, event.command.guild_id, event.command.channel_id);
|
||||||
settings->add_translatebot_webhook(webhook->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->add_channel_target(event.command.guild_id, event.command.channel_id, s_target);
|
||||||
database->sync();
|
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()) {
|
if (callback.is_error()) {
|
||||||
event.reply(dpp::message("Failed to generate webhook!").set_flags(dpp::m_ephemeral));
|
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_target(s_target, event.command.guild_id, event.command.channel_id);
|
||||||
settings->add_translatebot_webhook(webhook.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->add_channel_target(event.command.guild_id, event.command.channel_id, s_target);
|
||||||
database->sync();
|
database->sync();
|
||||||
|
|
||||||
event.reply(dpp::message("Channel will be now translated!").set_flags(dpp::m_ephemeral));
|
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()) {
|
if (callback.is_error()) {
|
||||||
event.reply(dpp::message("Failed to generate webhook!").set_flags(dpp::m_ephemeral));
|
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_channel(s_channel, event.command.guild_id);
|
||||||
settings->add_translatebot_webhook(webhook.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->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->add_channel_target(event.command.guild_id, event.command.channel_id, s_target);
|
||||||
database->sync();
|
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));
|
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();
|
settings->lock();
|
||||||
const std::vector<bot::translator::language> languages = settings->get_translator()->get_languages();
|
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;
|
std::vector<dpp::slashcommand> commands;
|
||||||
|
|
||||||
dpp::command_option source_option(dpp::co_string, "source", "Source language (ISO 639-1)", true);
|
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);
|
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);
|
dpp::slashcommand command_edit("edit", "Edit current channel settings", bot->me.id);
|
||||||
command_edit.set_default_permissions(dpp::p_manage_webhooks);
|
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::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 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 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(channel_list_subcommand);
|
||||||
command_list.add_option(guild_list_subcommand);
|
command_list.add_option(guild_list_subcommand);
|
||||||
|
command_list.add_option(languages_list_subcommand);
|
||||||
commands.push_back(command_list);
|
commands.push_back(command_list);
|
||||||
|
|
||||||
dpp::slashcommand command_translate("translate", "Translate current channel", bot->me.id);
|
dpp::slashcommand command_translate("translate", "Translate current channel", bot->me.id);
|
||||||
|
|
@ -23,16 +23,20 @@
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
namespace bot {
|
namespace bot {
|
||||||
namespace slashcommands {
|
class slashcommands {
|
||||||
extern void process_command_event(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event);
|
public:
|
||||||
extern void process_edit_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event);
|
slashcommands() = delete;
|
||||||
extern void process_deleted_webhook(bot::settings::settings *settings, dpp::snowflake webhook_id, const dpp::confirmation_callback_t &callback);
|
static void process_command_event(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event);
|
||||||
extern void process_list_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event);
|
static void register_commands(dpp::cluster *bot, bot::settings::settings *settings);
|
||||||
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);
|
private:
|
||||||
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);
|
static void process_edit_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event);
|
||||||
extern void register_commands(dpp::cluster *bot, bot::settings::settings *settings);
|
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
|
#endif // SLASHCOMMANDS_H
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include "submit_queue.h"
|
#include "submit_queue.h"
|
||||||
#include "webhook_push.h"
|
#include "webhook_push.h"
|
||||||
using namespace bot;
|
using bot::submit_queue;
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
void submit_queue::add(const translated_message &message)
|
void submit_queue::add(const translated_message &message)
|
||||||
|
|
@ -19,17 +19,9 @@
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#endif
|
#endif
|
||||||
#include "translator_core.h"
|
#include "translator.h"
|
||||||
using namespace bot::translator;
|
using namespace bot::translator;
|
||||||
|
|
||||||
translator::translator()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
translator::~translator()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<language> translator::get_languages()
|
const std::vector<language> translator::get_languages()
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
@ -16,9 +16,10 @@
|
||||||
* responsible for anything with use of the software, you are self responsible.
|
* responsible for anything with use of the software, you are self responsible.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#ifndef TRANSLATOR_CORE_H
|
#ifndef TRANSLATOR_H
|
||||||
#define TRANSLATOR_CORE_H
|
#define TRANSLATOR_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -29,14 +30,21 @@ namespace bot {
|
||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct supported_languages {
|
||||||
|
std::vector<language> languages;
|
||||||
|
std::chrono::system_clock::time_point query_time;
|
||||||
|
};
|
||||||
|
|
||||||
class translator {
|
class translator {
|
||||||
public:
|
public:
|
||||||
explicit translator();
|
explicit translator() = default;
|
||||||
virtual ~translator();
|
virtual ~translator() = default;
|
||||||
|
translator(const translator&) = delete;
|
||||||
|
translator& operator=(const translator&) = delete;
|
||||||
virtual const std::vector<language> get_languages();
|
virtual const std::vector<language> get_languages();
|
||||||
virtual const std::string translate(const std::string &text, const std::string &source, const std::string &target);
|
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)
|
void bot::webhook_push::run(const bot::translated_message &message, dpp::cluster *bot)
|
||||||
{
|
{
|
||||||
dpp::json json_body = {
|
dpp::json json_body = {
|
||||||
{"username"s, message.author},
|
{"username"s, message.author}
|
||||||
{"avatar_url"s, message.avatar}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!message.avatar.empty())
|
||||||
|
json_body["avatar_url"] = message.avatar;
|
||||||
|
|
||||||
// We will split too long messages into multiple messages
|
// We will split too long messages into multiple messages
|
||||||
if (message.message.length() > 2000) {
|
if (message.message.length() > 2000) {
|
||||||
std::string_view message_v = message.message;
|
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)
|
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::promise<dpp::http_request_completion_t> promise;
|
||||||
std::future<dpp::http_request_completion_t> _f = _p.get_future();
|
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, [&bot, &_p](dpp::json &json, const dpp::http_request_completion_t &event) {
|
bot->post_rest(API_PATH "/webhooks", std::to_string(webhook_id), dpp::utility::url_encode(webhook_token), dpp::m_post, json,
|
||||||
if (event.status != 204)
|
std::bind(&webhook_request_completed, std::ref(promise), std::placeholders::_1, std::placeholders::_2));
|
||||||
std::cerr << "[Warning] Webhook push returned unexpected code " << event.status << std::endl;
|
future.wait();
|
||||||
_p.set_value(event);
|
|
||||||
});
|
|
||||||
_f.wait();
|
|
||||||
}
|
}
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
namespace bot {
|
namespace bot {
|
||||||
class webhook_push {
|
class webhook_push {
|
||||||
public:
|
public:
|
||||||
|
webhook_push() = delete;
|
||||||
static void run(const bot::translated_message &message, dpp::cluster *bot);
|
static void run(const bot::translated_message &message, dpp::cluster *bot);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include "database_file.h"
|
#include "file.h"
|
||||||
using namespace bot::database;
|
using namespace bot::database;
|
||||||
using namespace std::string_literals;
|
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;
|
bot::settings::channel channel;
|
||||||
cache_get_channel(channel_id, &channel);
|
cache_get_channel(channel_id, channel);
|
||||||
channel.targets.push_back(target);
|
channel.targets.push_back(target);
|
||||||
cache_add_channel(guild_id, channel_id);
|
cache_add_channel(guild_id, channel_id);
|
||||||
guild->channel.push_back(std::move(channel));
|
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;
|
bot::settings::channel channel;
|
||||||
cache_get_channel(channel_id, &channel);
|
cache_get_channel(channel_id, channel);
|
||||||
channel.targets.push_back(target);
|
channel.targets.push_back(target);
|
||||||
cache_add_channel(guild_id, channel_id);
|
cache_add_channel(guild_id, channel_id);
|
||||||
m_dataCache.push_back({ guild_id, { std::move(channel) } });
|
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;
|
std::vector<dpp::snowflake> channels;
|
||||||
cache_guild(guild_id, &channels);
|
cache_guild(guild_id, channels);
|
||||||
for (auto channel = channels.begin(); channel != channels.end(); channel++) {
|
for (auto channel = channels.begin(); channel != channels.end(); channel++) {
|
||||||
if (*channel == channel_id) {
|
if (*channel == channel_id) {
|
||||||
channels.erase(channel);
|
channels.erase(channel);
|
||||||
|
|
@ -175,7 +175,7 @@ void file::delete_channel_target(dpp::snowflake guild_id, dpp::snowflake channel
|
||||||
}
|
}
|
||||||
|
|
||||||
bot::settings::channel 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++) {
|
for (auto _target = channel.targets.begin(); _target != channel.targets.end(); _target++) {
|
||||||
if (_target->target == target) {
|
if (_target->target == target) {
|
||||||
channel.targets.erase(_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;
|
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++) {
|
for (auto _target = channel.targets.begin(); _target != channel.targets.end(); _target++) {
|
||||||
if (_target->target == target) {
|
if (_target->target == target) {
|
||||||
channel.targets.erase(_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;
|
bot::settings::channel channel;
|
||||||
cache_get_channel(channel_id, &channel);
|
cache_get_channel(channel_id, channel);
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -281,7 +281,7 @@ std::vector<dpp::snowflake> file::get_channels(dpp::snowflake guild_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<dpp::snowflake> channels;
|
std::vector<dpp::snowflake> channels;
|
||||||
cache_guild(guild_id, &channels);
|
cache_guild(guild_id, channels);
|
||||||
return channels;
|
return channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -330,7 +330,7 @@ std::vector<dpp::snowflake> file::get_guilds()
|
||||||
{
|
{
|
||||||
const std::lock_guard<std::mutex> guard(m_mutex);
|
const std::lock_guard<std::mutex> guard(m_mutex);
|
||||||
std::vector<dpp::snowflake> guilds;
|
std::vector<dpp::snowflake> guilds;
|
||||||
list_guilds(&guilds);
|
list_guilds(guilds);
|
||||||
return guilds;
|
return guilds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -348,7 +348,7 @@ void file::set_channel_source(dpp::snowflake guild_id, dpp::snowflake channel_id
|
||||||
}
|
}
|
||||||
|
|
||||||
bot::settings::channel channel;
|
bot::settings::channel channel;
|
||||||
cache_get_channel(channel_id, &channel);
|
cache_get_channel(channel_id, channel);
|
||||||
channel.source = source;
|
channel.source = source;
|
||||||
cache_add_channel(guild_id, channel_id);
|
cache_add_channel(guild_id, channel_id);
|
||||||
guild->channel.push_back(std::move(channel));
|
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;
|
bot::settings::channel channel;
|
||||||
cache_get_channel(channel_id, &channel);
|
cache_get_channel(channel_id, channel);
|
||||||
channel.source = source;
|
channel.source = source;
|
||||||
cache_add_channel(guild_id, channel_id);
|
cache_add_channel(guild_id, channel_id);
|
||||||
m_dataCache.push_back({ guild_id, { std::move(channel) } });
|
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;
|
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())
|
if (std::find(channels.begin(), channels.end(), channel_id) == channels.end())
|
||||||
channels.push_back(channel_id);
|
channels.push_back(channel_id);
|
||||||
|
|
||||||
m_channelCache.push_back({ guild_id, std::move(channels) });
|
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");
|
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()) {
|
if (json.is_object()) {
|
||||||
auto json_channel_source = json.find("source");
|
auto json_channel_source = json.find("source");
|
||||||
if (json_channel_source != json.end())
|
if (json_channel_source != json.end())
|
||||||
channel->source = *json_channel_source;
|
channel.source = *json_channel_source;
|
||||||
|
|
||||||
auto json_channel_target = json.find("target");
|
auto json_channel_target = json.find("target");
|
||||||
if (json_channel_target != json.end()) {
|
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()) {
|
else if (json_target->is_string()) {
|
||||||
target.webhook = dpp::webhook(*json_target);
|
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");
|
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()) {
|
if (json.is_array()) {
|
||||||
for (auto channel = json.begin(); channel != json.end(); channel++) {
|
for (auto channel = json.begin(); channel != json.end(); channel++) {
|
||||||
if (channel->is_number())
|
if (channel->is_number())
|
||||||
channels->push_back(*channel);
|
channels.push_back(*channel);
|
||||||
else if (channel->is_string())
|
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";
|
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)) {
|
if (std::all_of(guild_filename.begin(), guild_filename.end(), ::isdigit)) {
|
||||||
try {
|
try {
|
||||||
dpp::snowflake guild_id = std::stoull(guild_filename);
|
dpp::snowflake guild_id = std::stoull(guild_filename);
|
||||||
guilds->push_back(guild_id);
|
guilds.push_back(guild_id);
|
||||||
}
|
}
|
||||||
catch (const std::exception &exception) {
|
catch (const std::exception &exception) {
|
||||||
std::cerr << "[Exception] " << exception.what() << std::endl;
|
std::cerr << "[Exception] " << exception.what() << std::endl;
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
#include "database_core.h"
|
#include "../../core/database.h"
|
||||||
|
|
||||||
namespace bot {
|
namespace bot {
|
||||||
namespace database {
|
namespace database {
|
||||||
|
|
@ -53,9 +53,9 @@ namespace bot {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void cache_add_channel(dpp::snowflake guild_id, dpp::snowflake channel_id);
|
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_get_channel(dpp::snowflake channel_id, bot::settings::channel &channel);
|
||||||
void cache_guild(dpp::snowflake guild_id, std::vector<dpp::snowflake> *channels);
|
void cache_guild(dpp::snowflake guild_id, std::vector<dpp::snowflake> &channels);
|
||||||
void list_guilds(std::vector<dpp::snowflake> *guilds);
|
void list_guilds(std::vector<dpp::snowflake> &guilds);
|
||||||
void sync_cache();
|
void sync_cache();
|
||||||
#if defined(__unix__)
|
#if defined(__unix__)
|
||||||
int fd;
|
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/json.h>
|
||||||
#include <dpp/httpsclient.h>
|
#include <dpp/httpsclient.h>
|
||||||
#include "translator_libretranslate.h"
|
#include "libretranslate.h"
|
||||||
using namespace bot::translator;
|
using namespace bot::translator;
|
||||||
|
using namespace std::chrono_literals;
|
||||||
using namespace std::string_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) :
|
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()
|
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 {
|
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) {
|
if (http_request.get_status() == 200) {
|
||||||
const dpp::json response = dpp::json::parse(http_request.get_content());
|
const dpp::json response = dpp::json::parse(http_request.get_content());
|
||||||
if (response.is_array()) {
|
if (response.is_array()) {
|
||||||
for (const auto &json_language : response) {
|
m_languages.languages.clear();
|
||||||
if (json_language.is_object()) {
|
for (auto json_language = response.begin(); json_language != response.end(); json_language++) {
|
||||||
|
if (json_language->is_object()) {
|
||||||
language language;
|
language language;
|
||||||
|
|
||||||
auto json_lang_code = json_language.find("code");
|
auto json_lang_code = json_language->find("code");
|
||||||
if (json_lang_code != json_language.end())
|
if (json_lang_code != json_language->end())
|
||||||
language.code = *json_lang_code;
|
language.code = *json_lang_code;
|
||||||
|
|
||||||
auto json_lang_name = json_language.find("name");
|
auto json_lang_name = json_language->find("name");
|
||||||
if (json_lang_name != json_language.end())
|
if (json_lang_name != json_language->end())
|
||||||
language.name = *json_lang_name;
|
language.name = *json_lang_name;
|
||||||
|
|
||||||
if (!language.code.empty() && !language.name.empty())
|
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;
|
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)
|
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;
|
json_body["apiKey"] = m_apiKey;
|
||||||
|
|
||||||
try {
|
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) {
|
if (http_request.get_status() == 200) {
|
||||||
const dpp::json response = dpp::json::parse(http_request.get_content());
|
const dpp::json response = dpp::json::parse(http_request.get_content());
|
||||||
if (response.is_object()) {
|
if (response.is_object()) {
|
||||||
|
|
@ -20,12 +20,13 @@
|
||||||
#define TRANSLATOR_LIBRETRANSLATE_H
|
#define TRANSLATOR_LIBRETRANSLATE_H
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <dpp/cluster.h>
|
||||||
#include "translator_core.h"
|
#include "../../core/translator.h"
|
||||||
|
|
||||||
namespace bot {
|
namespace bot {
|
||||||
namespace translator {
|
namespace translator {
|
||||||
class libretranslate : public translator {
|
class libretranslate : public translator {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit libretranslate(const std::string &hostname, uint16_t port, const std::string &url, bool tls, const std::string apiKey = {});
|
explicit libretranslate(const std::string &hostname, uint16_t port, const std::string &url, bool tls, const std::string apiKey = {});
|
||||||
~libretranslate() override;
|
~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;
|
const std::string translate(const std::string &text, const std::string &source, const std::string &target) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
dpp::cluster m_cluster;
|
||||||
std::string m_apiKey;
|
std::string m_apiKey;
|
||||||
std::string m_hostname;
|
std::string m_hostname;
|
||||||
|
supported_languages m_languages;
|
||||||
uint16_t m_port;
|
uint16_t m_port;
|
||||||
std::string m_url;
|
std::string m_url;
|
||||||
bool m_tls;
|
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