From e8f7a507121617a069a3e4ba03215e6e215638c5 Mon Sep 17 00:00:00 2001 From: Joey <17505625+jmctune@users.noreply.github.com> Date: Wed, 10 Jul 2024 02:06:28 -0500 Subject: [PATCH 1/6] update signatures for 7.1.0. (#245) --- app/clarity.py | 6 ++--- app/common/signatures.py | 56 +++++++++++++++++++++------------------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/app/clarity.py b/app/clarity.py index 5fe3f461..6916cd9a 100644 --- a/app/clarity.py +++ b/app/clarity.py @@ -192,11 +192,11 @@ def scan_for_npc_names(monsters: dict, npcs: dict): if npc_list := writer.pattern_scan(pattern=npc_monster_pattern, return_multiple=True, data_only=True): for address in npc_list: npc_type = writer.read_bytes(address + 36, 2) - if npc_type == b"\xB8\xEF": + if npc_type == b"\x54\x75": data = "NPC" - elif npc_type == b"\x14\xDD": + elif npc_type == b"\x8C\x62": data = "MONSTER" - elif npc_type == b"\x88\xDF": + elif npc_type == b"\x04\x65": data = "AI_NAME" else: continue diff --git a/app/common/signatures.py b/app/common/signatures.py index c0ed170b..a7110954 100644 --- a/app/common/signatures.py +++ b/app/common/signatures.py @@ -100,23 +100,24 @@ network_text_trigger = rb"\x8D\x71\x01\x8B\xFF\x8A\x01\x41\x84\xC0\x75\xF9\x2B\xCE\x51\x51" # player and sibling names on login. use this to figure out what the player is logged in as -# 55 8B EC 56 8B F1 57 8B 46 60 85 C0 -# DQXGame.exe.text+421150 - 55 - push ebp -# DQXGame.exe.text+421151 - 8B EC - mov ebp,esp -# DQXGame.exe.text+421153 - 56 - push esi -# DQXGame.exe.text+421154 - 8B F1 - mov esi,ecx -# DQXGame.exe.text+421156 - 57 - push edi -# DQXGame.exe.text+421157 - 8B 46 60 - mov eax,[esi+60] -# DQXGame.exe.text+42115A - 85 C0 - test eax,eax -# DQXGame.exe.text+42115C - 74 10 - je DQXGame.exe.text+42116E -# DQXGame.exe.text+42115E - 50 - push eax -# DQXGame.exe.text+42115F - E8 CCC1C1FF - call DQXGame.exe.text+3D330 -# DQXGame.exe.text+421164 - 83 C4 04 - add esp,04 -# DQXGame.exe.text+421167 - C7 46 60 00000000 - mov [esi+60],00000000 -# DQXGame.exe.text+42116E - 6A 02 - push 02 -# DQXGame.exe.text+421170 - 68 B0000000 - push 000000B0 -# DQXGame.exe.text+421175 - E8 C6C1C1FF - call DQXGame.exe.text+3D340 -player_sibling_name_trigger = rb"\x55\x8B\xEC\x56\x8B\xF1\x57\x8B\x46\x60\x85\xC0" +# 55 8B EC 56 8B F1 57 8B 46 58 85 C0 +# DQXGame.exe+422C70 - 55 - push ebp +# DQXGame.exe+422C71 - 8B EC - mov ebp,esp +# DQXGame.exe+422C73 - 56 - push esi +# DQXGame.exe+422C74 - 8B F1 - mov esi,ecx +# DQXGame.exe+422C76 - 57 - push edi +# DQXGame.exe+422C77 - 8B 46 58 - mov eax,[esi+58] +# DQXGame.exe+422C7A - 85 C0 - test eax,eax +# DQXGame.exe+422C7C - 74 10 - je DQXGame.exe+422C8E +# DQXGame.exe+422C7E - 50 - push eax +# DQXGame.exe+422C7F - E8 9CAEC1FF - call DQXGame.exe+3DB20 +# DQXGame.exe+422C84 - 83 C4 04 - add esp,04 +# DQXGame.exe+422C87 - C7 46 58 00000000 - mov [esi+58],00000000 +# DQXGame.exe+422C8E - 6A 02 - push 02 +# DQXGame.exe+422C90 - 68 B0000000 - push 000000B0 +# DQXGame.exe+422C95 - E8 F6ADC1FF - call DQXGame.exe+3DA90 + +player_sibling_name_trigger = rb"\x55\x8B\xEC\x56\x8B\xF1\x57\x8B\x46\x58\x85\xC0" # party member data hits this code. used to detour and overwrite name. # how it was found: @@ -176,24 +177,25 @@ # - Monster names appearing in the battle menu # - Party nameplates (don't confuse with party names on the right side of the screen) # - Does not do the player's nameplate -# npc: BC 6B ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 ?? 00 00 00 B8 EF ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E? -# monster: BC 6B ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 ?? 00 00 00 14 DD ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E? -# party: BC 6B ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 ?? 00 00 00 88 DF ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E? -npc_monster_pattern = rb"\xBC\x6B..\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00....\x00.......\x00\x00\x00\x00.\x00\x00\x00[\xB8\x14\x88][\xEF\xDD\xDF]..........[\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEF]" +# npc: 70 D6 ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 ?? 00 00 00 54 75 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E? +# monster: 70 D6 ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 ?? 00 00 00 8C 62 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E? +# party: 70 D6 ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 ?? 00 00 00 04 65 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E? +npc_monster_pattern = rb"\x70\xD6..\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00....\x00.......\x00\x00\x00\x00.\x00\x00\x00[\x54\x8C\x04][\x75\x62\x65]..........[\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEF]" # pattern for concierge names (13 bytes) -# D0 D5 ?? ?? ?? ?? ?? ?? F4 EF ?? ?? E? -concierge_name_pattern = rb"\xD0\xD5......\xF4\xEF..[\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEF]" +# B0 5A ?? ?? ?? ?? ?? ?? 28 5B ?? ?? E? +concierge_name_pattern = rb"\xB0\x5A......\x28\x5B..[\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEF]" # pattern for player names to rename. (49 bytes) -# BC 6B ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 B8 C5 ?? 0? ?? ?? ?? ?? ?? ?? ?? 0? E? -player_name_pattern = rb"\xBC\x6B..\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00....\x00...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xB8\xC5.[\x01\x02].......[\x01\x02][\xE3\xEF]" +# 70 D6 ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 C8 51 ?? 0? ?? ?? ?? ?? ?? ?? ?? 0? E? +player_name_pattern = rb"\x70\xD6..\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00....\x00...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xC8\x51.[\x01\x02].......[\x01\x02][\xE3\xEF]" # pattern for sibling names to rename. (52 bytes) # 0? ?? 00 ?? 00 00 00 ?? ?? 00 02 ?? 00 ?? 00 ?? 00 00 00 00 00 ?? 00 ?? ?? 00 00 ?? ?? ?? 00 ?? 00 ?? ?? ?? 00 ?? 00 ?? ?? 00 00 00 00 ?? ?? 00 00 00 00 E? sibling_name_pattern = rb"[\x01\x02].\x00.\x00\x00\x00..\x00\x02.\x00.\x00.\x00\x00\x00\x00\x00.\x00..\x00\x00...\x00.\x00...\x00.\x00..\x00\x00\x00\x00..\x00\x00\x00\x00[\xE3\xEF]" # pattern for menu ai to rename. (58 bytes) # 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? 00 00 ?? ?? ?? ?? ?? 00 00 00 ?? 1? ?? ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? 00 ?? ?? E? +# 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 58 1B 4F 01 00 00 00 00 00 00 00 00 00 00 01 00 E3 menu_ai_name_pattern = rb"\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00...........\x00..\x00\x00.....\x00\x00\x00.[\x1B\x1C].....\x00.....\x00..[\xE3\xEF]" # pattern for comm_names. @@ -204,8 +206,8 @@ # Main walkthrough text that loads on login. I can't figure out what function loads this on login, # so scanning for this for now. AC is also preventing this from just being accessible via hooks. (17 bytes) -# 30 ?? ?? ?? 00 00 00 00 04 02 00 00 10 00 00 00 E? -walkthrough_pattern = rb"\x30...\x00\x00\x00\x00\x04\x02\x00\x00\x10\x00\x00\x00[\xE3\xE4\xE5\xE6\xE7\xE8\xE9]" +# 50 ?? ?? ?? 00 00 00 00 04 02 00 00 10 00 00 00 E? +walkthrough_pattern = rb"\x50...\x00\x00\x00\x00\x04\x02\x00\x00\x10\x00\x00\x00[\xE3\xE4\xE5\xE6\xE7\xE8\xE9]" # player name in cutscenes. not used at the moment, but holding onto it for now. # EF ?? 01 ?? ?? ?? ?? 3C EF ?? 01 From efc0c3d3c45d4eb8b21a39e1cf5b9e715768bd3f Mon Sep 17 00:00:00 2001 From: jmctune Date: Wed, 10 Jul 2024 07:10:16 +0000 Subject: [PATCH 2/6] Automated bump of version.update --- version.update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.update b/version.update index 53cf85e1..813b83b6 100644 --- a/version.update +++ b/version.update @@ -1 +1 @@ -4.12.1 +4.13.0 From 67a30c956afb4d7ba995bb20f98724c61f60215e Mon Sep 17 00:00:00 2001 From: Joey <17505625+jmctune@users.noreply.github.com> Date: Fri, 12 Jul 2024 12:33:05 -0500 Subject: [PATCH 3/6] fix: regenerate glossary table contents every update. (#246) Ensure the database only consists of contents in the glossary.csv file and nothing more. --- app/common/update.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/common/update.py b/app/common/update.py index 94364bfc..e89d339c 100644 --- a/app/common/update.py +++ b/app/common/update.py @@ -257,9 +257,13 @@ def read_glossary_and_import(data: str): query_list.append(query_value) + + drop_query = "DELETE FROM glossary;" + db_query(drop_query) + insert_values = ','.join(query_list) - query = f"INSERT OR REPLACE INTO glossary (ja, en) VALUES {insert_values};" - db_query(query) + insert_query = f"INSERT OR REPLACE INTO glossary (ja, en) VALUES {insert_values};" + db_query(insert_query) def download_dat_files(): From 6a861ff1a33de56712ce78611d72dc250e1233ca Mon Sep 17 00:00:00 2001 From: jmctune Date: Fri, 12 Jul 2024 17:37:12 +0000 Subject: [PATCH 4/6] Automated bump of version.update --- version.update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.update b/version.update index 813b83b6..56d2fb54 100644 --- a/version.update +++ b/version.update @@ -1 +1 @@ -4.13.0 +4.13.1 From f478aedcbd0f74984e1546daa12a42f966f7e15b Mon Sep 17 00:00:00 2001 From: Joey <17505625+jmctune@users.noreply.github.com> Date: Fri, 12 Jul 2024 12:45:02 -0500 Subject: [PATCH 5/6] ci: disable unit tests for pymem (#247) these tests are very inconsistent at the moment. this is a forked library and was a best effort, but need to revisit sometime. --- app/tests/test_memory.py | 174 +++++++++++++++++++-------------------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/app/tests/test_memory.py b/app/tests/test_memory.py index d961fce6..22aab6be 100644 --- a/app/tests/test_memory.py +++ b/app/tests/test_memory.py @@ -1,145 +1,145 @@ -import os -import subprocess -import sys +# import os +# import subprocess +# import sys -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) -from common.memory import * +# sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) +# from common.memory import * -import unittest +# import unittest -class TestMemory(unittest.TestCase): +# class TestMemory(unittest.TestCase): - process = None - python = None +# process = None +# python = None - @classmethod - def setUpClass(cls): - def start_testing_process(): - info = subprocess.STARTUPINFO() - info.dwFlags = subprocess.STARTF_USESHOWWINDOW - info.wShowWindow = subprocess.SW_HIDE - python = subprocess.Popen("python.exe", startupinfo=info) - return python +# @classmethod +# def setUpClass(cls): +# def start_testing_process(): +# info = subprocess.STARTUPINFO() +# info.dwFlags = subprocess.STARTF_USESHOWWINDOW +# info.wShowWindow = subprocess.SW_HIDE +# python = subprocess.Popen("python.exe", startupinfo=info) +# return python - cls.python = start_testing_process() - cls.process = MemWriter(cls.python.pid) +# cls.python = start_testing_process() +# cls.process = MemWriter(cls.python.pid) - @classmethod - def tearDownClass(cls): - cls.process.close() - cls.python.kill() +# @classmethod +# def tearDownClass(cls): +# cls.process.close() +# cls.python.kill() - def test_attach(self): - self.process.attach("python.exe") +# def test_attach(self): +# self.process.attach("python.exe") - def test_allocate_memory(self): - address = self.process.allocate_memory(4) +# def test_allocate_memory(self): +# address = self.process.allocate_memory(4) - self.assertTrue(address) +# self.assertTrue(address) - def test_allocate_read_and_write_bytes(self): - address = self.process.allocate_memory(4) - self.process.write_bytes(address=address, value=b"\x00\x01\x02\x03") - value = self.process.read_bytes(address=address, size=4) +# def test_allocate_read_and_write_bytes(self): +# address = self.process.allocate_memory(4) +# self.process.write_bytes(address=address, value=b"\x00\x01\x02\x03") +# value = self.process.read_bytes(address=address, size=4) - self.assertTrue(value == b"\x00\x01\x02\x03") +# self.assertTrue(value == b"\x00\x01\x02\x03") - def test_allocate_read_and_write_string(self): - address = self.process.allocate_memory(4) - self.process.write_string(address=address, text="this is a test") - value = self.process.read_string(address=address) +# def test_allocate_read_and_write_string(self): +# address = self.process.allocate_memory(4) +# self.process.write_string(address=address, text="this is a test") +# value = self.process.read_string(address=address) - self.assertTrue(value == "this is a test") +# self.assertTrue(value == "this is a test") - def test_pattern_scan_all(self): - address = self.process.allocate_memory(4) +# def test_pattern_scan_all(self): +# address = self.process.allocate_memory(4) - to_write = b"This is a test of the emergency broadcasting system." - self.process.write_bytes(address=address, value=to_write) +# to_write = b"This is a test of the emergency broadcasting system." +# self.process.write_bytes(address=address, value=to_write) - # all_protections is required as allocate_memory adds RWE to the address - result = self.process.pattern_scan(pattern=to_write, all_protections=True) +# # all_protections is required as allocate_memory adds RWE to the address +# result = self.process.pattern_scan(pattern=to_write, all_protections=True) - self.assertTrue(result == address) +# self.assertTrue(result == address) - def test_pattern_scan_module(self): - # first few bytes of Py_InitializeEx - to_search = b"\x55\x8B\xEC\x83\xE4\xF0\x81\xEC\x30\x01\x00\x00" - result = self.process.pattern_scan(pattern=to_search, all_protections=True, module="python311.dll") +# def test_pattern_scan_module(self): +# # first few bytes of Py_InitializeEx +# to_search = b"\x55\x8B\xEC\x83\xE4\xF0\x81\xEC\x30\x01\x00\x00" +# result = self.process.pattern_scan(pattern=to_search, all_protections=True, module="python311.dll") - self.assertTrue(result) +# self.assertTrue(result) - def test_get_ptr_address(self): - address = self.process.allocate_memory(4) - fake_address = b"\x01\x23\x45\x67" +# def test_get_ptr_address(self): +# address = self.process.allocate_memory(4) +# fake_address = b"\x01\x23\x45\x67" - self.process.write_bytes(address, fake_address) - pointer = self.process.get_ptr_address(address, offsets=[0x0, 0x0, 0x0]) +# self.process.write_bytes(address, fake_address) +# pointer = self.process.get_ptr_address(address, offsets=[0x0, 0x0, 0x0]) - self.assertTrue(hex(pointer) == "0x67452301") +# self.assertTrue(hex(pointer) == "0x67452301") - def test_get_base_address(self): - address = self.process.get_base_address("python311.dll") +# def test_get_base_address(self): +# address = self.process.get_base_address("python311.dll") - self.assertTrue(address) +# self.assertTrue(address) - def test_pack_to_int(self): - address = 0x01234567 - result = self.process.pack_to_int(address) +# def test_pack_to_int(self): +# address = 0x01234567 +# result = self.process.pack_to_int(address) - self.assertTrue(result.hex(" ") == "67 45 23 01") +# self.assertTrue(result.hex(" ") == "67 45 23 01") - def test_unpack_to_int(self): - address = self.process.allocate_memory(4) - self.process.write_bytes(address, b"\x01\x23\x45\x67") - result = self.process.unpack_to_int(address) +# def test_unpack_to_int(self): +# address = self.process.allocate_memory(4) +# self.process.write_bytes(address, b"\x01\x23\x45\x67") +# result = self.process.unpack_to_int(address) - self.assertTrue(hex(result) == "0x67452301") +# self.assertTrue(hex(result) == "0x67452301") - def test_allocate_memory(self): - address = self.process.allocate_memory(4) +# def test_allocate_memory(self): +# address = self.process.allocate_memory(4) - self.assertTrue(address) +# self.assertTrue(address) - def test_calc_rel_addr_forwards(self): - offset = self.process.calc_rel_addr(origin_address=0x10000000, destination_address=0x20000000) +# def test_calc_rel_addr_forwards(self): +# offset = self.process.calc_rel_addr(origin_address=0x10000000, destination_address=0x20000000) - self.assertTrue(offset == b"\xfb\xff\xff\x0f") +# self.assertTrue(offset == b"\xfb\xff\xff\x0f") - def test_calc_rel_addr_backwards(self): - offset = self.process.calc_rel_addr(origin_address=0x20000000, destination_address=0x10000000) +# def test_calc_rel_addr_backwards(self): +# offset = self.process.calc_rel_addr(origin_address=0x20000000, destination_address=0x10000000) - self.assertTrue(offset == b"\x00\x00\x00\xf0") +# self.assertTrue(offset == b"\x00\x00\x00\xf0") - def test_get_hook_bytecode(self): - jump_bytes = self.process.get_hook_bytecode(0x01234567) +# def test_get_hook_bytecode(self): +# jump_bytes = self.process.get_hook_bytecode(0x01234567) - self.assertTrue(jump_bytes.hex(" ") == "e9 67 45 23 01") +# self.assertTrue(jump_bytes.hex(" ") == "e9 67 45 23 01") - # this test needs to run last as it can hose other tests since we're sharing the same process. - def test_zzz_inject_python(self): - self.process.inject_python() +# # this test needs to run last as it can hose other tests since we're sharing the same process. +# def test_zzz_inject_python(self): +# self.process.inject_python() - self.assertTrue(self.process.proc._python_injected) - self.assertTrue(self.process.proc.py_run_simple_string) +# self.assertTrue(self.process.proc._python_injected) +# self.assertTrue(self.process.proc.py_run_simple_string) -if __name__ == '__main__': - unittest.main() +# if __name__ == '__main__': +# unittest.main() From 81b25ae4b6a223640eb377f44cadf33635a20452 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 Jul 2024 12:45:13 -0500 Subject: [PATCH 6/6] chore(deps): update dependency frida to v16.4.2 (#244) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [frida](https://frida.re) | `==16.3.3` -> `==16.4.2` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/frida/16.4.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/frida/16.4.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/frida/16.3.3/16.4.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/frida/16.3.3/16.4.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/dqx-translation-project/dqxclarity). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a3bf053c..4b3b5b5f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ click==8.1.7 configparser==7.0.0 deepl==1.18.0 -frida==16.3.3 +frida==16.4.2 google-api-python-client==2.133.0 langdetect==1.0.9 loguru==0.7.2