mirror of
https://github.com/Artikash/Textractor.git
synced 2024-12-23 17:04:12 +08:00
performance improvements and autoselect native language for translations
This commit is contained in:
parent
2e23d4016d
commit
dc48f2a3c8
@ -68,10 +68,8 @@ namespace
|
|||||||
void RemoveThreads(std::function<bool(ThreadParam)> removeIf)
|
void RemoveThreads(std::function<bool(ThreadParam)> removeIf)
|
||||||
{
|
{
|
||||||
std::vector<TextThread*> threadsToRemove;
|
std::vector<TextThread*> threadsToRemove;
|
||||||
{
|
for (auto& [tp, thread] : textThreadsByParams.Acquire().contents)
|
||||||
auto textThreadsByParams = ::textThreadsByParams.Acquire();
|
if (removeIf(tp)) threadsToRemove.push_back(&thread);
|
||||||
std::for_each(textThreadsByParams->begin(), textThreadsByParams->end(), [&](auto& it) { if (removeIf(it.first)) threadsToRemove.push_back(&it.second); });
|
|
||||||
}
|
|
||||||
for (auto thread : threadsToRemove)
|
for (auto thread : threadsToRemove)
|
||||||
{
|
{
|
||||||
OnDestroy(*thread);
|
OnDestroy(*thread);
|
||||||
@ -131,14 +129,14 @@ namespace
|
|||||||
{
|
{
|
||||||
auto tp = *(ThreadParam*)buffer;
|
auto tp = *(ThreadParam*)buffer;
|
||||||
auto textThreadsByParams = ::textThreadsByParams.Acquire();
|
auto textThreadsByParams = ::textThreadsByParams.Acquire();
|
||||||
auto textThread = textThreadsByParams->find(tp);
|
auto thread = textThreadsByParams->find(tp);
|
||||||
if (textThread == textThreadsByParams->end())
|
if (thread == textThreadsByParams->end())
|
||||||
{
|
{
|
||||||
try { textThread = textThreadsByParams->try_emplace(tp, tp, processRecordsByIds->at(tp.processId).GetHook(tp.addr).hp).first; }
|
try { thread = textThreadsByParams->try_emplace(tp, tp, processRecordsByIds->at(tp.processId).GetHook(tp.addr).hp).first; }
|
||||||
catch (std::out_of_range) { continue; } // probably garbage data in pipe, try again
|
catch (std::out_of_range) { continue; } // probably garbage data in pipe, try again
|
||||||
OnCreate(textThread->second);
|
OnCreate(thread->second);
|
||||||
}
|
}
|
||||||
textThread->second.Push(buffer + sizeof(tp), bytesRead - sizeof(tp));
|
thread->second.Push(buffer + sizeof(tp), bytesRead - sizeof(tp));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -247,9 +245,9 @@ namespace Host
|
|||||||
|
|
||||||
TextThread* GetThread(int64_t handle)
|
TextThread* GetThread(int64_t handle)
|
||||||
{
|
{
|
||||||
auto textThreadsByParams = ::textThreadsByParams.Acquire();
|
for (auto& [tp, thread] : textThreadsByParams.Acquire().contents)
|
||||||
auto thread = std::find_if(textThreadsByParams->begin(), textThreadsByParams->end(), [&](const auto& thread) { return thread.second.handle == handle; });
|
if (thread.handle == handle) return &thread;
|
||||||
return thread != textThreadsByParams->end() ? &thread->second : nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddConsoleOutput(std::wstring text)
|
void AddConsoleOutput(std::wstring text)
|
||||||
|
@ -9,7 +9,6 @@ extern Synchronized<std::wstring> translateTo;
|
|||||||
const char* TRANSLATION_PROVIDER = "Bing";
|
const char* TRANSLATION_PROVIDER = "Bing";
|
||||||
QStringList languages
|
QStringList languages
|
||||||
{
|
{
|
||||||
"English: en",
|
|
||||||
"Arabic: ar",
|
"Arabic: ar",
|
||||||
"Bosnian: bs-Latn",
|
"Bosnian: bs-Latn",
|
||||||
"Bulgarian: bg",
|
"Bulgarian: bg",
|
||||||
@ -20,6 +19,7 @@ QStringList languages
|
|||||||
"Czech: cs",
|
"Czech: cs",
|
||||||
"Danish: da",
|
"Danish: da",
|
||||||
"Dutch: nl",
|
"Dutch: nl",
|
||||||
|
"English: en",
|
||||||
"Estonian: et",
|
"Estonian: et",
|
||||||
"Finnish: fi",
|
"Finnish: fi",
|
||||||
"French: fr",
|
"French: fr",
|
||||||
|
@ -3,53 +3,57 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include <istream>
|
#include <istream>
|
||||||
|
|
||||||
template <typename C, int DelimiterCount, int bufferStartSize = 200>
|
template <typename C, int delimiterCount, int blockSize = 0x1000 / sizeof(C)> // windows file block size
|
||||||
class BlockMarkupIterator
|
class BlockMarkupIterator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BlockMarkupIterator(std::istreambuf_iterator<char> it, const std::basic_string_view<C> (&delimiters)[DelimiterCount]) :
|
BlockMarkupIterator(const std::istream& it, const std::basic_string_view<C>(&delimiters)[delimiterCount]) :
|
||||||
it(it)
|
streambuf(*it.rdbuf())
|
||||||
{
|
{
|
||||||
std::copy_n(delimiters, DelimiterCount, this->delimiters.begin());
|
std::copy_n(delimiters, delimiterCount, this->delimiters.begin());
|
||||||
}
|
}
|
||||||
std::optional<std::array<std::basic_string<C>, DelimiterCount>> Next()
|
|
||||||
|
std::optional<std::array<std::basic_string<C>, delimiterCount>> Next()
|
||||||
{
|
{
|
||||||
std::array<std::basic_string<C>, DelimiterCount> results;
|
std::array<std::basic_string<C>, delimiterCount> results;
|
||||||
std::basic_string<C> buffer;
|
Find(delimiters[0], true);
|
||||||
buffer.reserve(bufferStartSize);
|
for (int i = 0; i < delimiterCount; ++i)
|
||||||
Find(buffer, delimiters[0]);
|
|
||||||
buffer.clear();
|
|
||||||
for (int i = 0; i < DelimiterCount; ++i)
|
|
||||||
{
|
{
|
||||||
const auto delimiter = i + 1 < DelimiterCount ? delimiters[i + 1] : end;
|
const auto delimiter = i + 1 < delimiterCount ? delimiters[i + 1] : end;
|
||||||
if (!Find(buffer, delimiter)) return {};
|
if (auto found = Find(delimiter, false)) results[i] = std::move(found.value());
|
||||||
buffer.erase(buffer.size() - delimiter.size());
|
else return {};
|
||||||
results[i] = std::move(buffer);
|
|
||||||
(buffer = {}).reserve(bufferStartSize);
|
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool Find(std::basic_string<C>& result, std::basic_string_view<C> delimiter)
|
std::optional<std::basic_string<C>> Find(std::basic_string_view<C> delimiter, bool discard)
|
||||||
{
|
{
|
||||||
while (Read((result += C{}).back())) if (result.back() == '|' && result.find(delimiter, result.size() - delimiter.size()) != std::string::npos) return true;
|
for (int i = 0; ;)
|
||||||
return false;
|
{
|
||||||
}
|
int pos = buffer.find(delimiter, i);
|
||||||
|
if (pos != std::string::npos)
|
||||||
bool Read(C& out)
|
{
|
||||||
{
|
auto result = !discard ? std::optional(std::basic_string(buffer.begin(), buffer.begin() + pos)) : std::nullopt;
|
||||||
BYTE buffer[sizeof(C)];
|
buffer.erase(buffer.begin(), buffer.begin() + pos + delimiter.size());
|
||||||
for (int i = 0; i < sizeof(C); ++i, ++it)
|
return result;
|
||||||
if (it.equal({})) return false;
|
}
|
||||||
else buffer[i] = *it;
|
int oldSize = buffer.size();
|
||||||
out = reinterpret_cast<C&>(buffer);
|
buffer.resize(oldSize + blockSize);
|
||||||
return true;
|
if (!streambuf.sgetn((char*)buffer.data() + oldSize, blockSize * sizeof(C))) return {};
|
||||||
|
i = max(0, oldSize - (int)delimiter.size());
|
||||||
|
if (discard)
|
||||||
|
{
|
||||||
|
buffer.erase(0, i);
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr C endImpl[5] = { '|', 'E', 'N', 'D', '|' };
|
static constexpr C endImpl[5] = { '|', 'E', 'N', 'D', '|' };
|
||||||
static constexpr std::basic_string_view end{ endImpl, 5 };
|
static constexpr std::basic_string_view end{ endImpl, 5 };
|
||||||
|
|
||||||
std::istreambuf_iterator<char> it;
|
std::basic_streambuf<char>& streambuf;
|
||||||
std::array<std::basic_string_view<C>, DelimiterCount> delimiters;
|
std::basic_string<C> buffer;
|
||||||
|
std::array<std::basic_string_view<C>, delimiterCount> delimiters;
|
||||||
};
|
};
|
||||||
|
@ -11,7 +11,6 @@ extern Synchronized<std::wstring> translateTo;
|
|||||||
const char* TRANSLATION_PROVIDER = "Google";
|
const char* TRANSLATION_PROVIDER = "Google";
|
||||||
QStringList languages
|
QStringList languages
|
||||||
{
|
{
|
||||||
"English: en",
|
|
||||||
"Afrikaans: af",
|
"Afrikaans: af",
|
||||||
"Arabic: ar",
|
"Arabic: ar",
|
||||||
"Albanian: sq",
|
"Albanian: sq",
|
||||||
@ -26,6 +25,7 @@ QStringList languages
|
|||||||
"Czech: cs",
|
"Czech: cs",
|
||||||
"Danish: da",
|
"Danish: da",
|
||||||
"Dutch: nl",
|
"Dutch: nl",
|
||||||
|
"English: en",
|
||||||
"Esperanto: eo",
|
"Esperanto: eo",
|
||||||
"Estonian: et",
|
"Estonian: et",
|
||||||
"Filipino: tl",
|
"Filipino: tl",
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
#include "qtcommon.h"
|
#include "qtcommon.h"
|
||||||
#include "extension.h"
|
#include "extension.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "blockmarkup.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include <map>
|
#include <fstream>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
extern const char* NATIVE_LANGUAGE;
|
||||||
extern const char* SELECT_LANGUAGE;
|
extern const char* SELECT_LANGUAGE;
|
||||||
extern const char* SELECT_LANGUAGE_MESSAGE;
|
extern const char* SELECT_LANGUAGE_MESSAGE;
|
||||||
extern const char* LANGUAGE_SAVED;
|
extern const char* LANGUAGE_SAVED;
|
||||||
@ -15,19 +18,25 @@ extern QStringList languages;
|
|||||||
std::pair<bool, std::wstring> Translate(const std::wstring& text);
|
std::pair<bool, std::wstring> Translate(const std::wstring& text);
|
||||||
|
|
||||||
const char* LANGUAGE = u8"Language";
|
const char* LANGUAGE = u8"Language";
|
||||||
const QString CACHE_FILE = QString("%1 Cache.txt").arg(TRANSLATION_PROVIDER);
|
const std::string TRANSLATION_CACHE_FILE = FormatString("%sCache.txt", TRANSLATION_PROVIDER);
|
||||||
|
|
||||||
Synchronized<std::wstring> translateTo = L"en";
|
Synchronized<std::wstring> translateTo = L"en";
|
||||||
QSettings settings(CONFIG_FILE, QSettings::IniFormat);
|
QSettings settings(CONFIG_FILE, QSettings::IniFormat);
|
||||||
|
|
||||||
|
struct Translation
|
||||||
|
{
|
||||||
|
std::wstring original, translation;
|
||||||
|
bool operator<(const Translation& other) const { return original < other.original; }
|
||||||
|
};
|
||||||
|
Synchronized<std::vector<Translation>> translationCache;
|
||||||
int savedSize;
|
int savedSize;
|
||||||
Synchronized<std::map<std::wstring, std::wstring>> translationCache;
|
|
||||||
|
|
||||||
void SaveCache()
|
void SaveCache()
|
||||||
{
|
{
|
||||||
QTextFile file(CACHE_FILE, QIODevice::WriteOnly | QIODevice::Truncate);
|
std::wstring allTranslations(L"\xfeff");
|
||||||
auto translationCache = ::translationCache.Acquire();
|
for (const auto& [original, translation] : translationCache.Acquire().contents)
|
||||||
for (const auto& [original, translation] : translationCache.contents)
|
allTranslations.append(L"|SENTENCE|").append(original).append(L"|TRANSLATION|").append(translation).append(L"|END|\r\n");
|
||||||
file.write(S(FormatString(L"%s|T|\n%s|T|\n", original, translation)).toUtf8());
|
std::ofstream(TRANSLATION_CACHE_FILE, std::ios::binary | std::ios::trunc).write((const char*)allTranslations.c_str(), allTranslations.size() * sizeof(wchar_t));
|
||||||
savedSize = translationCache->size();
|
savedSize = translationCache->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +55,7 @@ BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved
|
|||||||
SELECT_LANGUAGE,
|
SELECT_LANGUAGE,
|
||||||
QString(SELECT_LANGUAGE_MESSAGE).arg(TRANSLATION_PROVIDER),
|
QString(SELECT_LANGUAGE_MESSAGE).arg(TRANSLATION_PROVIDER),
|
||||||
languages,
|
languages,
|
||||||
0,
|
std::find_if(languages.begin(), languages.end(), [](QString language) { return language.startsWith(NATIVE_LANGUAGE); }) - languages.begin(),
|
||||||
false,
|
false,
|
||||||
nullptr,
|
nullptr,
|
||||||
Qt::WindowCloseButtonHint
|
Qt::WindowCloseButtonHint
|
||||||
@ -56,10 +65,16 @@ BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved
|
|||||||
QMessageBox::information(nullptr, SELECT_LANGUAGE, QString(LANGUAGE_SAVED).arg(CONFIG_FILE));
|
QMessageBox::information(nullptr, SELECT_LANGUAGE, QString(LANGUAGE_SAVED).arg(CONFIG_FILE));
|
||||||
});
|
});
|
||||||
|
|
||||||
QStringList savedCache = QString(QTextFile(CACHE_FILE, QIODevice::ReadOnly).readAll()).split("|T|\n", QString::SkipEmptyParts);
|
std::ifstream stream(TRANSLATION_CACHE_FILE, std::ios::binary);
|
||||||
for (int i = 0; i < savedCache.size() - 1; i += 2)
|
BlockMarkupIterator savedTranslations(stream, Array<std::wstring_view>{ L"|SENTENCE|", L"|TRANSLATION|" });
|
||||||
translationCache->insert({ S(savedCache[i]), S(savedCache[i + 1]) });
|
auto translationCache = ::translationCache.Acquire();
|
||||||
|
while (auto read = savedTranslations.Next())
|
||||||
|
{
|
||||||
|
const auto& [original, translation] = read.value();
|
||||||
|
translationCache->push_back({ original, translation });
|
||||||
|
}
|
||||||
savedSize = translationCache->size();
|
savedSize = translationCache->size();
|
||||||
|
std::sort(translationCache->begin(), translationCache->end());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
@ -94,14 +109,15 @@ bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)
|
|||||||
|
|
||||||
bool cache = false;
|
bool cache = false;
|
||||||
std::wstring translation;
|
std::wstring translation;
|
||||||
if (translationCache->count(sentence) != 0) translation = translationCache->at(sentence);
|
|
||||||
else if (!(rateLimiter.Request() || sentenceInfo["current select"])) translation = TOO_MANY_TRANS_REQUESTS;
|
|
||||||
else std::tie(cache, translation) = Translate(sentence);
|
|
||||||
if (cache && sentenceInfo["current select"])
|
|
||||||
{
|
{
|
||||||
translationCache->insert({ sentence, translation });
|
auto translationCache = ::translationCache.Acquire();
|
||||||
if (translationCache->size() > savedSize + 50) SaveCache();
|
auto translationLocation = std::lower_bound(translationCache->begin(), translationCache->end(), Translation{ sentence });
|
||||||
|
if (translationLocation != translationCache->end() && translationLocation->original == sentence) translation = translationLocation->translation;
|
||||||
|
else if (!(rateLimiter.Request() || sentenceInfo["current select"])) translation = TOO_MANY_TRANS_REQUESTS;
|
||||||
|
else std::tie(cache, translation) = Translate(sentence);
|
||||||
|
if (cache && sentenceInfo["current select"]) translationCache->insert(translationLocation, { sentence, translation });
|
||||||
}
|
}
|
||||||
|
if (cache && translationCache->size() > savedSize + 50) SaveCache();
|
||||||
|
|
||||||
Unescape(translation);
|
Unescape(translation);
|
||||||
sentence += L"\n" + translation;
|
sentence += L"\n" + translation;
|
||||||
|
9
text.cpp
9
text.cpp
@ -4,6 +4,7 @@
|
|||||||
#define ARCH "x86"
|
#define ARCH "x86"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const char* NATIVE_LANGUAGE = "English";
|
||||||
const char* ATTACH = u8"Attach to game";
|
const char* ATTACH = u8"Attach to game";
|
||||||
const char* LAUNCH = u8"Launch game";
|
const char* LAUNCH = u8"Launch game";
|
||||||
const char* DETACH = u8"Detach from game";
|
const char* DETACH = u8"Detach from game";
|
||||||
@ -185,6 +186,7 @@ const char* HEXADECIMAL = u8"Hexadecimal";
|
|||||||
static auto _ = []
|
static auto _ = []
|
||||||
{
|
{
|
||||||
#ifdef TURKISH
|
#ifdef TURKISH
|
||||||
|
NATIVE_LANGUAGE = "Turkish";
|
||||||
ATTACH = u8"Oyuna bağla";
|
ATTACH = u8"Oyuna bağla";
|
||||||
DETACH = u8"Oyundan kopar";
|
DETACH = u8"Oyundan kopar";
|
||||||
ADD_HOOK = u8"Kanca ekle";
|
ADD_HOOK = u8"Kanca ekle";
|
||||||
@ -218,6 +220,7 @@ Kaynak kodu GKLv3 koruması altında proje ana sayfasında mevcut)";
|
|||||||
#endif // TURKISH
|
#endif // TURKISH
|
||||||
|
|
||||||
#ifdef SPANISH
|
#ifdef SPANISH
|
||||||
|
NATIVE_LANGUAGE = "Spanish";
|
||||||
ATTACH = u8"Adjuntar juego";
|
ATTACH = u8"Adjuntar juego";
|
||||||
LAUNCH = u8"Iniciar juego";
|
LAUNCH = u8"Iniciar juego";
|
||||||
DETACH = u8"Desconectar juego";
|
DETACH = u8"Desconectar juego";
|
||||||
@ -280,6 +283,7 @@ Clic y arrastra los bordes de la ventana para moverla, o en la esquina inferior
|
|||||||
#endif // SPANISH
|
#endif // SPANISH
|
||||||
|
|
||||||
#ifdef SIMPLIFIED_CHINESE
|
#ifdef SIMPLIFIED_CHINESE
|
||||||
|
NATIVE_LANGUAGE = "Chinese(Simplified)"
|
||||||
ATTACH = u8"附加到游戏";
|
ATTACH = u8"附加到游戏";
|
||||||
LAUNCH = u8"启动游戏";
|
LAUNCH = u8"启动游戏";
|
||||||
DETACH = u8"从游戏分离";
|
DETACH = u8"从游戏分离";
|
||||||
@ -344,6 +348,7 @@ Clic y arrastra los bordes de la ventana para moverla, o en la esquina inferior
|
|||||||
#endif // SIMPLIFIED_CHINESE
|
#endif // SIMPLIFIED_CHINESE
|
||||||
|
|
||||||
#ifdef RUSSIAN
|
#ifdef RUSSIAN
|
||||||
|
NATIVE_LANGUAGE = "Russian";
|
||||||
ATTACH = u8"Присоединить к игре";
|
ATTACH = u8"Присоединить к игре";
|
||||||
LAUNCH = u8"Запустить игру";
|
LAUNCH = u8"Запустить игру";
|
||||||
DETACH = u8"Отсоединить от игры";
|
DETACH = u8"Отсоединить от игры";
|
||||||
@ -475,6 +480,7 @@ end)";
|
|||||||
#endif // RUSSIAN
|
#endif // RUSSIAN
|
||||||
|
|
||||||
#ifdef INDONESIAN
|
#ifdef INDONESIAN
|
||||||
|
NATIVE_LANGUAGE = "Indonesian";
|
||||||
ATTACH = u8"Tempelkan kedalam game";
|
ATTACH = u8"Tempelkan kedalam game";
|
||||||
LAUNCH = u8"Mulai game";
|
LAUNCH = u8"Mulai game";
|
||||||
DETACH = u8"Lepaskan dari game";
|
DETACH = u8"Lepaskan dari game";
|
||||||
@ -539,6 +545,7 @@ Klik dan tarik pinggiran jendela untuk memindahkan, atau sudut kanan bawah untuk
|
|||||||
#endif // INDONESIAN
|
#endif // INDONESIAN
|
||||||
|
|
||||||
#ifdef PORTUGUESE
|
#ifdef PORTUGUESE
|
||||||
|
NATIVE_LANGUAGE = "Portuguese";
|
||||||
ATTACH = u8"Anexar ao Jogo";
|
ATTACH = u8"Anexar ao Jogo";
|
||||||
LAUNCH = u8"Iniciar Jogo";
|
LAUNCH = u8"Iniciar Jogo";
|
||||||
DETACH = u8"Desconectar do Jogo";
|
DETACH = u8"Desconectar do Jogo";
|
||||||
@ -626,6 +633,7 @@ Esse arquívo deve ser codifícado em (UTF-16 little endian).)";
|
|||||||
#endif // PORTUGUESE
|
#endif // PORTUGUESE
|
||||||
|
|
||||||
#ifdef THAI
|
#ifdef THAI
|
||||||
|
NATIVE_LANGUAGE = "Thai";
|
||||||
ATTACH = u8"เชื่อมเกม";
|
ATTACH = u8"เชื่อมเกม";
|
||||||
LAUNCH = u8"เริ่มเกม";
|
LAUNCH = u8"เริ่มเกม";
|
||||||
DETACH = u8"ยกเลิกการเชื่อม";
|
DETACH = u8"ยกเลิกการเชื่อม";
|
||||||
@ -687,6 +695,7 @@ Source code สามารถหาได้จากส่วนของ GPLv
|
|||||||
#endif // THAI
|
#endif // THAI
|
||||||
|
|
||||||
#ifdef KOREAN
|
#ifdef KOREAN
|
||||||
|
NATIVE_LANGUAGE = "Korean";
|
||||||
ATTACH = u8"게임에 부착";
|
ATTACH = u8"게임에 부착";
|
||||||
LAUNCH = u8"게임 실행";
|
LAUNCH = u8"게임 실행";
|
||||||
DETACH = u8"게임에서 탈착";
|
DETACH = u8"게임에서 탈착";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user