ksaa 2025.6.8.0__py3-none-any.whl → 2025.6.28.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kotonebot/backend/context/context.py +29 -25
- kotonebot/backend/debug/server.py +0 -2
- kotonebot/backend/dispatch.py +1 -17
- kotonebot/backend/loop.py +277 -0
- kotonebot/client/__init__.py +4 -2
- kotonebot/client/device.py +178 -25
- kotonebot/client/host/__init__.py +2 -1
- kotonebot/client/host/adb_common.py +94 -0
- kotonebot/client/host/custom.py +33 -4
- kotonebot/client/host/leidian_host.py +17 -15
- kotonebot/client/host/mumu12_host.py +79 -11
- kotonebot/client/host/protocol.py +44 -19
- kotonebot/client/host/windows_common.py +55 -0
- kotonebot/client/implements/__init__.py +7 -0
- kotonebot/client/implements/adb.py +24 -7
- kotonebot/client/implements/adb_raw.py +3 -3
- kotonebot/client/implements/nemu_ipc/__init__.py +8 -0
- kotonebot/client/implements/nemu_ipc/external_renderer_ipc.py +280 -0
- kotonebot/client/implements/nemu_ipc/nemu_ipc.py +327 -0
- kotonebot/client/implements/remote_windows.py +17 -21
- kotonebot/client/implements/uiautomator2.py +5 -8
- kotonebot/client/implements/windows.py +28 -36
- kotonebot/client/protocol.py +13 -0
- kotonebot/client/registration.py +24 -0
- kotonebot/config/base_config.py +8 -2
- kotonebot/debug_entry.py +11 -4
- kotonebot/errors.py +7 -0
- kotonebot/kaa/game_ui/common.py +4 -7
- kotonebot/kaa/game_ui/dialog.py +24 -4
- kotonebot/kaa/game_ui/idols_overview.py +28 -12
- kotonebot/kaa/game_ui/primary_button.py +55 -0
- kotonebot/kaa/game_ui/scrollable.py +0 -5
- kotonebot/kaa/main/cli.py +9 -4
- kotonebot/kaa/main/dmm_host.py +15 -8
- kotonebot/kaa/main/gr.py +114 -27
- kotonebot/kaa/main/kaa.py +140 -41
- kotonebot/kaa/metadata.py +47 -0
- kotonebot/kaa/resources/__pycache__/__init__.cpython-310.pyc +0 -0
- kotonebot/kaa/resources/game.db +0 -0
- kotonebot/kaa/resources/game_ver.txt +0 -0
- kotonebot/kaa/resources/idol_cards/i_card-skin-kllj-3-012_0.png +0 -0
- kotonebot/kaa/resources/idol_cards/i_card-skin-kllj-3-012_1.png +0 -0
- kotonebot/kaa/resources/idol_cards/i_card-skin-ssmk-3-012_0.png +0 -0
- kotonebot/kaa/resources/idol_cards/i_card-skin-ssmk-3-012_1.png +0 -0
- kotonebot/kaa/sprites/24e99232-9434-457f-a9a0-69dd7ecf675f.png +0 -0
- kotonebot/kaa/sprites/2ededcf5-1d80-4e2a-9c83-2a31998331ce.png +0 -0
- kotonebot/kaa/sprites/3b473fe6-e147-477f-b088-9b8fb042a4f6.png +0 -0
- kotonebot/kaa/sprites/55f7db71-0a18-4b3d-b847-57959b8d2e32.png +0 -0
- kotonebot/kaa/sprites/6cd80be8-c9b3-4ba5-bf17-3ffc9b000743.png +0 -0
- kotonebot/kaa/sprites/74ec3510-583d-4a76-ac69-38480fbf1387.png +0 -0
- kotonebot/kaa/sprites/a0bd6a5f-784d-4f0a-9d66-10f4b80c8d3e.png +0 -0
- kotonebot/kaa/sprites/d3424d31-0502-4623-996e-f0194e5085ce.png +0 -0
- kotonebot/kaa/sprites/e6b45405-cd9f-4c6e-a9f1-6ec953747c65.png +0 -0
- kotonebot/kaa/sprites/f5c16d2f-ebc5-4617-9b96-971696af7c52.png +0 -0
- kotonebot/kaa/tasks/R.py +157 -135
- kotonebot/kaa/{clear_logs.py → tasks/clear_logs.py} +0 -3
- kotonebot/kaa/tasks/produce/in_purodyuusu.py +0 -4
- kotonebot/kaa/tasks/produce/non_lesson_actions.py +0 -3
- kotonebot/kaa/tasks/produce/produce.py +119 -70
- kotonebot/kaa/tasks/start_game.py +7 -6
- kotonebot/kaa/util/paths.py +6 -1
- kotonebot/tools/mirror.py +23 -13
- kotonebot/util.py +32 -0
- {ksaa-2025.6.8.0.dist-info → ksaa-2025.6.28.0.dist-info}/METADATA +4 -1
- {ksaa-2025.6.8.0.dist-info → ksaa-2025.6.28.0.dist-info}/RECORD +201 -181
- kotonebot/client/factory.py +0 -92
- kotonebot/kaa/sprites/38b8f119-8de1-49bf-8a5f-a44371de4569.png +0 -0
- /kotonebot/kaa/sprites/{5ca50448-cc21-499a-a685-c5e1c4240c48.png → 019273c4-22ce-486f-8a7d-dbc78f13dcac.png} +0 -0
- /kotonebot/kaa/sprites/{afa0f85f-dcb7-48a1-a1ae-624456b9b65c.png → 03e34ef7-36b5-4ddc-9545-5b70a2eba72e.png} +0 -0
- /kotonebot/kaa/sprites/{a00fcf77-2800-4f7d-993d-4636b36045bb.png → 06ea773b-e2b3-40d4-82f6-b119ce9ca00b.png} +0 -0
- /kotonebot/kaa/sprites/{d58d9987-b1ca-4669-a9a6-9a0fd1847fa6.png → 0769f8f4-1c47-4bad-a783-bba5e20250bf.png} +0 -0
- /kotonebot/kaa/sprites/{82a5e224-a161-43d4-8e15-2946480336dd.png → 08946997-4e9e-4242-95e1-e988fa96b919.png} +0 -0
- /kotonebot/kaa/sprites/{fb927b92-7a82-4869-8c61-581d49cd7201.png → 0d60ce10-20ce-4980-8172-b6bac08d6258.png} +0 -0
- /kotonebot/kaa/sprites/{b1e88fda-434a-4d06-8891-883a7beafa12.png → 0f40352f-6443-406e-8e2c-c40d5cfc6c59.png} +0 -0
- /kotonebot/kaa/sprites/{c4f28132-4aba-40ba-be6c-b1a31d014635.png → 0f6d7f89-bdb2-4235-9b6b-e65cb73a4167.png} +0 -0
- /kotonebot/kaa/sprites/{e866d8b1-4f61-45bf-8170-5229f53c047a.png → 14d09c44-3897-4c81-b615-19c35d0f3793.png} +0 -0
- /kotonebot/kaa/sprites/{a105d17d-d44c-4798-aeff-70808c91cb47.png → 15191dec-7e33-4721-8068-15c11978e885.png} +0 -0
- /kotonebot/kaa/sprites/{869b1771-b2ce-4872-ab75-2157c47c5b13.png → 15f8f31e-65ce-408d-8556-b799bcefc9d4.png} +0 -0
- /kotonebot/kaa/sprites/{994aa6a6-0189-4a79-8125-56136973b581.png → 20b01af5-907b-4d49-9f5b-a3700ca9c0c3.png} +0 -0
- /kotonebot/kaa/sprites/{92b7d830-3db5-434e-b156-0ac855db480d.png → 242c088b-bc73-4d11-aa31-ee7c71477fb4.png} +0 -0
- /kotonebot/kaa/sprites/{9c1fa1d4-2ae5-4093-abaa-cebb51135721.png → 2f2a7951-a30a-4835-b9f6-3205cfdd2f05.png} +0 -0
- /kotonebot/kaa/sprites/{a33ae1c3-ac69-4783-977e-9f0f1b1a2f8d.png → 3031397e-3d12-4f23-8377-006eca5d2627.png} +0 -0
- /kotonebot/kaa/sprites/{e7022542-4317-4a61-8098-f3f733d8400e.png → 312dbd82-5457-474a-91ce-511f0e4e9c80.png} +0 -0
- /kotonebot/kaa/sprites/{cd8d3d55-f102-419e-a6fd-2ad5ecc4fd2e.png → 31851ad1-df39-4a4f-9ae7-19c1d1c6b51a.png} +0 -0
- /kotonebot/kaa/sprites/{826bf80a-112e-4356-9111-4b7e692ccc82.png → 338b699a-d556-4b80-a577-123442c3db45.png} +0 -0
- /kotonebot/kaa/sprites/{d8136469-6d73-4f82-a79c-fee83c3e93a8.png → 35319890-98e3-4f75-b969-6b8576ef668d.png} +0 -0
- /kotonebot/kaa/sprites/{96cf0633-6531-499b-b1cc-6670ab710293.png → 3536f829-70d3-48f9-8fd4-b65eab7502f3.png} +0 -0
- /kotonebot/kaa/sprites/{31a52dc8-b7fb-4ff6-a261-eb90a918603c.png → 35516b69-a4f4-4ad4-8af4-35043475ee90.png} +0 -0
- /kotonebot/kaa/sprites/{d747239f-7620-4f23-9ac7-cf2d34889266.png → 36d71d33-09c9-4be8-b184-ccf40f700333.png} +0 -0
- /kotonebot/kaa/sprites/{b44f5e5b-e999-4427-8a9f-f76c6485f4a5.png → 379d5084-637f-45e8-8bd8-789eaa919821.png} +0 -0
- /kotonebot/kaa/sprites/{0a430873-8c12-4ce2-a5de-ab9790c08344.png → 3851303a-e3a0-46eb-aa7e-b47fb41946f7.png} +0 -0
- /kotonebot/kaa/sprites/{ff77d221-8444-4d0f-8c93-0223a97e2a98.png → 3d1aa368-e198-478f-a47f-49818efbaec8.png} +0 -0
- /kotonebot/kaa/sprites/{333fe6d3-0be7-40fb-a2a3-364f98758f2a.png → 3f5907a9-7fe4-4f46-8e46-a96ac7fa3923.png} +0 -0
- /kotonebot/kaa/sprites/{0decaa6a-b9a9-4d9b-829a-0fc1f67538b4.png → 40c0f296-d29e-4e05-aaff-a212339b742e.png} +0 -0
- /kotonebot/kaa/sprites/{c1ad996a-925e-41b5-b26c-d48b8ded21d2.png → 43e72796-a644-4d9b-a817-8add011d9a75.png} +0 -0
- /kotonebot/kaa/sprites/{e2fae2a4-bb19-4f49-b382-47e504ec26d3.png → 469c2b41-4171-4902-acc5-da0c807886ab.png} +0 -0
- /kotonebot/kaa/sprites/{559df9b9-e74d-45af-a300-77d3424e69c6.png → 497e7930-f423-457a-8168-b1a1532bb1e9.png} +0 -0
- /kotonebot/kaa/sprites/{e41bb5df-164d-4760-9db6-d5d5d763bb5f.png → 49a43af3-17e3-4434-ba4d-519775ccaea9.png} +0 -0
- /kotonebot/kaa/sprites/{f9b2f64d-f829-4b13-9704-c5f00fb956be.png → 49b9a298-e847-4322-99a2-c0588c3542fe.png} +0 -0
- /kotonebot/kaa/sprites/{645744c4-3bbf-4ea2-8f46-4725fff874b3.png → 4a1902aa-01db-46bb-bea5-88ac62c82562.png} +0 -0
- /kotonebot/kaa/sprites/{c0fc7de5-b842-4c70-9cf2-89d833bfe7a6.png → 4a96a728-6303-4ae3-8e0c-9f1e8e5f86a7.png} +0 -0
- /kotonebot/kaa/sprites/{73f4204e-8281-47cc-9dce-6bb8280c4ce5.png → 4b7c4221-a679-47f6-929d-0ef514894b27.png} +0 -0
- /kotonebot/kaa/sprites/{c1b1125f-542b-4e63-9c86-5d2e35a89a10.png → 4d355e36-9169-43e4-bd58-2836ee3e56e0.png} +0 -0
- /kotonebot/kaa/sprites/{ad8ee599-88a8-429c-8982-99086e552dcc.png → 4eb97d68-cd47-4100-9c3b-35b5c86b4bdf.png} +0 -0
- /kotonebot/kaa/sprites/{7a479871-547e-4098-9cdd-6c9bb9f7449a.png → 515a2ff0-36b8-4f2f-9902-e6c1b9796586.png} +0 -0
- /kotonebot/kaa/sprites/{02e0aa0d-4094-4bdc-8625-1a063733615b.png → 51a3ed29-92b9-4429-9e50-783d1b8dc6a7.png} +0 -0
- /kotonebot/kaa/sprites/{22d5a7d5-59a0-4137-b02e-1a7af86d4250.png → 52d3438b-afae-4c7a-abe5-7ed530c7558c.png} +0 -0
- /kotonebot/kaa/sprites/{5bf00cba-9aab-4ffe-b20b-8f5e74279276.png → 540ee3b5-ca8f-4091-80a6-ce774d95e5f7.png} +0 -0
- /kotonebot/kaa/sprites/{05ff5efd-0f76-47ce-bc89-237266bc17c0.png → 54a15298-ecaf-4cc5-b8a2-5b0d8f8add41.png} +0 -0
- /kotonebot/kaa/sprites/{1f9165e6-77ee-403e-9b76-99c114527dbb.png → 554c0ff6-0a05-419d-85f9-5ced260d0d2e.png} +0 -0
- /kotonebot/kaa/sprites/{79bc56c5-eae6-4389-9116-4a9e182d6bf3.png → 55e4ef75-ba8e-4230-819c-450cf14b08cd.png} +0 -0
- /kotonebot/kaa/sprites/{cd4cbd7b-df80-45bb-a053-cc333a806934.png → 5824ef5f-6776-402c-b78c-ae79cc4cc878.png} +0 -0
- /kotonebot/kaa/sprites/{804a4b05-1ca3-4915-bf23-a66ccdc34404.png → 5a393483-c631-47fd-805c-c460c23b8f9e.png} +0 -0
- /kotonebot/kaa/sprites/{e5d15c50-45ee-4de9-8b97-4630cbd8f01a.png → 5b75cae4-a853-402c-acec-edbfef94342a.png} +0 -0
- /kotonebot/kaa/sprites/{1a3d18a4-7d91-4182-9e40-e60d73fed365.png → 5c9ae62c-488f-4109-a4d2-d2385c32043d.png} +0 -0
- /kotonebot/kaa/sprites/{7344e180-251b-465a-a8cf-974477f7ad44.png → 5cdd71be-c8cd-4310-b6f4-5e97ddbeb46e.png} +0 -0
- /kotonebot/kaa/sprites/{67a81c23-4ce4-45e3-bfa8-1136fb14b831.png → 5d5cb13b-c1fd-4808-b352-b21291a9ff0b.png} +0 -0
- /kotonebot/kaa/sprites/{4e21f02d-d5e1-49eb-946a-8edc74d0f1f7.png → 5d6c4462-3d7c-42eb-ab3e-195ebf845a09.png} +0 -0
- /kotonebot/kaa/sprites/{d7f604a6-c663-44db-b1d3-c9792eb3daa4.png → 5d94e628-82ff-4531-b70a-b13297491bea.png} +0 -0
- /kotonebot/kaa/sprites/{74521b6f-de5e-4ba8-a3c9-c6ba01070498.png → 5dc2dca3-48bd-4eee-af89-1a1d30593bd5.png} +0 -0
- /kotonebot/kaa/sprites/{b604e25d-680a-4e02-a012-2e593b5bc276.png → 5f0c2a57-efd0-4094-9f71-6f6fe97316f6.png} +0 -0
- /kotonebot/kaa/sprites/{fd610de1-b023-4747-8c1b-72f89b1c5647.png → 610348f2-6262-4cd1-8fc3-e7470f85580c.png} +0 -0
- /kotonebot/kaa/sprites/{5be4f6c7-2baa-42f3-a5a5-99ca0830cc30.png → 613e9b10-b2eb-44ea-b6d9-9310c0e1bdcf.png} +0 -0
- /kotonebot/kaa/sprites/{72c1804f-db8c-40fa-bc79-6533f2861a5d.png → 618b21ad-ab8b-436a-8eb8-bd320a198c9f.png} +0 -0
- /kotonebot/kaa/sprites/{572077d4-7ee2-449a-b4f0-66239b0d7aff.png → 61a09df6-7443-436c-9ef0-1d5a1cae1509.png} +0 -0
- /kotonebot/kaa/sprites/{321b54c8-c69b-4437-931d-655882dabeed.png → 64be274e-e8ad-4938-84c1-5d8aabcd10d8.png} +0 -0
- /kotonebot/kaa/sprites/{22ee3f1b-ddcb-48bf-85dd-8423f85e3199.png → 671b4a55-023a-434d-b29a-e844fe528e6b.png} +0 -0
- /kotonebot/kaa/sprites/{668002b6-805b-467b-a703-203fb75444f4.png → 6e5e9cf9-80b0-4241-a222-ff50dbd89a0c.png} +0 -0
- /kotonebot/kaa/sprites/{4bd66b38-78d3-4a27-816b-d315039a8bb6.png → 6ef59649-bbb3-42b6-a6b0-eac4f35a3da4.png} +0 -0
- /kotonebot/kaa/sprites/{7b3c6860-fbbe-48aa-aadf-8062fa88f1fe.png → 75a2093d-8743-427e-8d24-ae9a69fa14c1.png} +0 -0
- /kotonebot/kaa/sprites/{371a3192-101c-45ef-9da4-2ed389770c0f.png → 76bde19a-4b1b-4e52-86d9-f56be7529c71.png} +0 -0
- /kotonebot/kaa/sprites/{ef39804e-8d2d-40f6-8d13-bd2877d1353a.png → 77d06f4d-8214-4306-9dc5-035c720f7256.png} +0 -0
- /kotonebot/kaa/sprites/{24cd42fd-bb3b-4fc6-b40d-d3e3e36fe9f1.png → 78b642d3-9a2c-4c17-8872-3cc78211f4a0.png} +0 -0
- /kotonebot/kaa/sprites/{0bab7080-9a37-4c27-9821-8df36d49b678.png → 7a9d1c39-b306-4cb0-be2f-7a5963099949.png} +0 -0
- /kotonebot/kaa/sprites/{b1d1dfab-51f5-4ae9-b718-cdf46774c0ff.png → 7ddda828-c8b0-4331-864f-99b85b7c5557.png} +0 -0
- /kotonebot/kaa/sprites/{5edef075-4843-4dc9-840f-ae445cbe0730.png → 81399fd9-f254-4d0e-9775-ad451c237a4e.png} +0 -0
- /kotonebot/kaa/sprites/{705d9ecf-faf8-40f4-b701-637cec822c1e.png → 81526e97-1b8d-433f-a5c9-907e4e8c85cd.png} +0 -0
- /kotonebot/kaa/sprites/{ecd44a4a-e1ca-4a86-ae0d-2306a672613f.png → 818e2370-8fb9-4e6c-ab78-58e86d6525b5.png} +0 -0
- /kotonebot/kaa/sprites/{4f58031c-36b9-4baf-bccf-11c05d83bd19.png → 8431cc52-0041-4425-808c-dcd4d196506c.png} +0 -0
- /kotonebot/kaa/sprites/{13535ecd-bdf5-4ff7-aa2c-6ecb20fe9c06.png → 85a49ff3-6075-4797-8b7f-35851a843698.png} +0 -0
- /kotonebot/kaa/sprites/{d22ca9e0-001d-43d6-a557-1c76c5a27c81.png → 86062e91-d6c1-44cf-9f8c-26a8b9dd8686.png} +0 -0
- /kotonebot/kaa/sprites/{0bbfb5b0-f0f7-4ad9-86f7-a2adb01a6371.png → 860c3d98-e263-482f-95fb-4fc9c472e8b8.png} +0 -0
- /kotonebot/kaa/sprites/{ed5d2bf3-405c-4165-88d0-9f8a4be968c6.png → 8669ce44-dec7-47c2-aafd-3f2fbfd1d083.png} +0 -0
- /kotonebot/kaa/sprites/{f0786a26-81b5-4e76-b577-db70ab3fab50.png → 86b15801-c932-4034-bed8-fd76b0f65916.png} +0 -0
- /kotonebot/kaa/sprites/{80fb515c-4323-422d-a24c-80a3bf702f1d.png → 893b015d-6894-4e74-880e-d22859a25662.png} +0 -0
- /kotonebot/kaa/sprites/{fdfecda8-2fe0-487e-b5fe-6358274bb9ff.png → 8c0fa5fa-cebb-4ae7-bd1c-b542c9cbf694.png} +0 -0
- /kotonebot/kaa/sprites/{73af305f-840f-4325-abae-b3519fba672a.png → 913a1d17-54fe-4c8f-ac50-ef7f39600b86.png} +0 -0
- /kotonebot/kaa/sprites/{c2667677-cbff-4dd4-a401-e0963e7224f4.png → 964c6b90-f526-4199-9523-d8124373a56b.png} +0 -0
- /kotonebot/kaa/sprites/{db94ffb7-a09d-4a51-b420-b930851c9db4.png → 97c281a9-ebb0-4f54-b644-b7ed7dd65f81.png} +0 -0
- /kotonebot/kaa/sprites/{48c257f8-3583-49f7-b01a-ba7d251086ac.png → 998fc84a-af71-4fa5-8aa4-e0bfeb9c53ea.png} +0 -0
- /kotonebot/kaa/sprites/{469006bc-a011-46e4-bcde-992be888456e.png → 9cbf7f6e-fe77-463b-9c60-495dc823510a.png} +0 -0
- /kotonebot/kaa/sprites/{4d6c198a-0e34-4c80-86d1-7789b2082d64.png → 9ce7d48e-295d-47b2-96eb-f3ce697c1b37.png} +0 -0
- /kotonebot/kaa/sprites/{a3c12040-2b11-4038-b830-215fb7b6f359.png → 9dcca89b-c92b-4708-8f19-facd40d09a65.png} +0 -0
- /kotonebot/kaa/sprites/{fbd816df-7ae6-40a4-b4d4-5708f5ba4a7c.png → 9e369992-ea8c-4c15-88d3-1344319978b0.png} +0 -0
- /kotonebot/kaa/sprites/{54bb5fcf-be61-4af8-bb19-a3c5113cf9e1.png → 9f9003ba-468f-406f-a82f-1b7a23ef347c.png} +0 -0
- /kotonebot/kaa/sprites/{309105d4-073a-47c9-8c5c-d593aa497723.png → a2bf4e11-fbc3-4172-bc0b-b16f8f59e68c.png} +0 -0
- /kotonebot/kaa/sprites/{111a03e6-e401-4ad5-b5dc-d5124e8f1ab0.png → a546e254-0490-43df-a291-a9a5c2b4c34a.png} +0 -0
- /kotonebot/kaa/sprites/{7736a171-9221-4cda-8288-908997abeff2.png → aacd229c-d307-4a20-a388-84d8f4afb4a5.png} +0 -0
- /kotonebot/kaa/sprites/{1bfce48a-b151-406e-a6f5-863cb68cbbf2.png → b003bef5-53db-4032-b1bd-d5075de365a8.png} +0 -0
- /kotonebot/kaa/sprites/{b2f7a430-5777-4861-8435-5419394e5ee8.png → b641a122-4734-43e1-b22f-468464a0cff1.png} +0 -0
- /kotonebot/kaa/sprites/{a82e06fb-a02e-4be5-a7b4-4d2758914fcf.png → bc7303f3-43e9-4ece-9206-5f9c779b813b.png} +0 -0
- /kotonebot/kaa/sprites/{f74fc514-61f1-4068-bdf4-754fcaf8ac89.png → bd7a6754-fffc-4315-987f-5ba32d95b697.png} +0 -0
- /kotonebot/kaa/sprites/{c7aa3f89-8a5e-4685-9297-4fc892bfdd81.png → c39f2006-442b-4ab7-99bb-3dfa0673f05d.png} +0 -0
- /kotonebot/kaa/sprites/{6bf5556a-8f4e-41d7-8ab5-d683ad1b47a8.png → c70f4634-6821-4480-a615-b5f9cdc578c1.png} +0 -0
- /kotonebot/kaa/sprites/{89c0e675-3fd4-456a-8ae7-3bfb248b7281.png → c774098e-d782-455c-80a9-5bad3713129d.png} +0 -0
- /kotonebot/kaa/sprites/{09433024-3dfe-4fcb-9d67-cf442b58f31b.png → c7e3736a-0e0f-474a-9386-f58292a45b92.png} +0 -0
- /kotonebot/kaa/sprites/{48d2f007-8c1b-43fc-bd3f-f0b10d2a0c88.png → c90b582c-8570-48b4-98c0-62d5b067ca2c.png} +0 -0
- /kotonebot/kaa/sprites/{9bb1a400-935a-4c5e-838b-fca502c49aba.png → c9d3699b-c8b1-4294-9b48-103df4ab6c65.png} +0 -0
- /kotonebot/kaa/sprites/{157dd58d-e319-4e0c-a37a-638e1a31c60b.png → cc9483c3-c895-4dcc-b3f2-0934ba1ad42e.png} +0 -0
- /kotonebot/kaa/sprites/{43d65b3f-bbae-4e29-a7bf-539379c1b072.png → cec49286-3d48-4fe0-8911-6a1b17d1ac20.png} +0 -0
- /kotonebot/kaa/sprites/{56a8c0ca-4659-4de2-9bce-55ce86a40d75.png → cef78712-d9ae-4d6e-8d7d-d047d48fbb98.png} +0 -0
- /kotonebot/kaa/sprites/{12e8d3f1-494a-46f5-908f-f621a0c57ec6.png → d06fd859-4678-4593-b096-c86b38810cb7.png} +0 -0
- /kotonebot/kaa/sprites/{ba955365-1328-4018-83a2-bfe818f8f172.png → d19c37ff-d5c1-4316-8424-e69ccb5c2523.png} +0 -0
- /kotonebot/kaa/sprites/{695f8d57-b2c9-4a6d-9ae9-1b49ee3eb22a.png → d26b60f7-d15c-4563-bedc-dd6e7e4078b2.png} +0 -0
- /kotonebot/kaa/sprites/{910d307b-6461-4950-badb-509975d0b797.png → d26bf52c-cb1b-4ebf-9c03-ff3f2d245959.png} +0 -0
- /kotonebot/kaa/sprites/{7e8164f6-a9e4-4600-b776-77b35a490933.png → d5fd6c73-4ad8-47b5-89be-c7b137a9950f.png} +0 -0
- /kotonebot/kaa/sprites/{05bfd235-2077-479a-8c43-11fb49316000.png → d696062b-9b58-4af1-835e-2cf5a0a0fbeb.png} +0 -0
- /kotonebot/kaa/sprites/{03458cf9-8ab0-4908-9a56-9c5c7e06bc9b.png → da7a329e-339e-4ee7-8775-bca505a1980d.png} +0 -0
- /kotonebot/kaa/sprites/{2f81e70a-f2af-420f-9b6b-6338c391911f.png → dedb8499-5881-4add-914f-ff0049285dae.png} +0 -0
- /kotonebot/kaa/sprites/{b3d1f8d4-1393-4206-b78e-a5495d8fb930.png → dedea21b-f21d-4621-a213-70ad03faec58.png} +0 -0
- /kotonebot/kaa/sprites/{f65a4495-f044-44de-bf0d-c869e637d5d3.png → dff74cce-ba2d-44aa-b924-183259080a32.png} +0 -0
- /kotonebot/kaa/sprites/{b3e72de2-e103-49a3-b0f2-8593cff87c4e.png → e0246b0d-f0cf-49d4-8423-7da46e75a575.png} +0 -0
- /kotonebot/kaa/sprites/{624555b9-31e3-46a3-8078-55619eaa40b9.png → e1b6b32b-c797-4f1d-aa2b-e7320083a9a6.png} +0 -0
- /kotonebot/kaa/sprites/{90a9c819-ee6b-4b3e-a0e4-ce484c6e413d.png → e23e3f19-03f6-4507-9128-115191272b90.png} +0 -0
- /kotonebot/kaa/sprites/{cc829886-23e8-4d47-b4c4-37ca20381180.png → e2eb3bae-6451-40b9-bbff-90f11dca1904.png} +0 -0
- /kotonebot/kaa/sprites/{6a7d061e-682b-42c1-97d5-121c52921e8b.png → e46e1b6d-6702-46bf-a07e-aec8d183453f.png} +0 -0
- /kotonebot/kaa/sprites/{de709296-e411-465f-86fc-5daf5ca83cef.png → e5297036-9934-44a4-a761-a6a49ae06e3e.png} +0 -0
- /kotonebot/kaa/sprites/{52620946-b92c-42c7-9fcc-0ff13388fd0d.png → e7da5988-0e83-44ad-888b-246365473f9e.png} +0 -0
- /kotonebot/kaa/sprites/{05f8f996-a38a-45d9-8ff9-720b6c4fd599.png → eb8d208a-dbcc-43ca-a8ac-098e1005ebfa.png} +0 -0
- /kotonebot/kaa/sprites/{8e8a0b57-0231-4ed6-958e-3196f7c9ca7b.png → ebe4ce64-98a9-40f2-9fde-3d5cdae673c7.png} +0 -0
- /kotonebot/kaa/sprites/{4a235eaa-46f1-4f71-b54d-ada0ade44572.png → ef2ad3df-3f89-4a48-8fc3-c70a8adc1044.png} +0 -0
- /kotonebot/kaa/sprites/{f8cbb089-a63e-4e40-9238-26d14da2c459.png → f05e410d-15b8-4831-bcc1-4cd8af07c882.png} +0 -0
- /kotonebot/kaa/sprites/{550fc45d-22c0-4a7c-a324-2c4ff107ab39.png → f1fac13a-84f3-42bd-9b52-e0ba90bc5255.png} +0 -0
- /kotonebot/kaa/sprites/{ad784a29-f0e2-4037-976b-45143db8441c.png → f7c34ab6-c165-48b7-ad5a-0b60613ce1bc.png} +0 -0
- /kotonebot/kaa/sprites/{0439399f-5fca-43f9-a105-99342ff04d2e.png → fa80b14e-953f-44bd-a4ad-99aefd276fd7.png} +0 -0
- /kotonebot/kaa/sprites/{7cea265a-fca5-43d0-b2da-067c8fff4d72.png → fe35655e-701b-4081-8df8-c17a7252acef.png} +0 -0
- /kotonebot/kaa/sprites/{da3e7cee-d77b-4e62-b703-ed257706dd39.png → fe853ac7-934e-4b4a-bcc7-b986e057dfcf.png} +0 -0
- /kotonebot/kaa/sprites/{1f8f8c46-43ec-4449-be9f-2e96da11da1e.png → ffda716c-2903-4ec7-8c59-aab5b8ad10bb.png} +0 -0
- /kotonebot/kaa/sprites/{4c72f39e-1182-4479-867f-8207744ee4fd.png → fff33200-c947-49f2-ab86-3ac98937fa36.png} +0 -0
- {ksaa-2025.6.8.0.dist-info → ksaa-2025.6.28.0.dist-info}/WHEEL +0 -0
- {ksaa-2025.6.8.0.dist-info → ksaa-2025.6.28.0.dist-info}/entry_points.txt +0 -0
- {ksaa-2025.6.8.0.dist-info → ksaa-2025.6.28.0.dist-info}/licenses/LICENSE +0 -0
- {ksaa-2025.6.8.0.dist-info → ksaa-2025.6.28.0.dist-info}/top_level.txt +0 -0
kotonebot/kaa/game_ui/common.py
CHANGED
|
@@ -2,10 +2,10 @@ import cv2
|
|
|
2
2
|
import numpy as np
|
|
3
3
|
from cv2.typing import MatLike
|
|
4
4
|
|
|
5
|
-
from kotonebot import
|
|
6
|
-
from kotonebot.backend.color import HsvColor
|
|
7
|
-
from kotonebot.primitives import RectTuple, Rect
|
|
5
|
+
from kotonebot.primitives import Rect
|
|
8
6
|
from kotonebot.backend.core import Image
|
|
7
|
+
from kotonebot.backend.color import HsvColor
|
|
8
|
+
from kotonebot import action, color, image, device
|
|
9
9
|
from kotonebot.backend.preprocessor import HsvColorFilter
|
|
10
10
|
|
|
11
11
|
|
|
@@ -88,7 +88,4 @@ class WhiteFilter(HsvColorFilter):
|
|
|
88
88
|
|
|
89
89
|
|
|
90
90
|
if __name__ == '__main__':
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
init_context()
|
|
94
|
-
manual_context().begin()
|
|
91
|
+
pass
|
kotonebot/kaa/game_ui/dialog.py
CHANGED
|
@@ -1,45 +1,65 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
1
3
|
from kotonebot.kaa.tasks import R
|
|
2
4
|
from kotonebot import device, image
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
def expect_yes(*, msg: str | None = None):
|
|
5
9
|
"""
|
|
6
10
|
点击对话框上的✔️按钮。若不存在,会等待其出现,直至超时异常。
|
|
7
11
|
|
|
8
12
|
前置条件:当前打开了任意对话框\n
|
|
9
13
|
结束状态:点击了肯定意义按钮(✔️图标,橙色背景)后瞬间
|
|
14
|
+
|
|
15
|
+
:param msg: 成功点击后输出的日志信息。信息中的动词建议使用过去式。
|
|
10
16
|
"""
|
|
11
17
|
device.click(image.expect(R.Common.IconButtonCheck))
|
|
18
|
+
if msg is not None:
|
|
19
|
+
logger.debug(msg)
|
|
12
20
|
|
|
13
|
-
def yes() -> bool:
|
|
21
|
+
def yes(*, msg: str | None = None) -> bool:
|
|
14
22
|
"""
|
|
15
23
|
点击对话框上的✔️按钮。
|
|
16
24
|
|
|
17
25
|
前置条件:当前打开了任意对话框\n
|
|
18
26
|
结束状态:点击了肯定意义按钮(✔️图标,橙色背景)后瞬间
|
|
27
|
+
|
|
28
|
+
:param msg: 成功点击后输出的日志信息。信息中的动词建议使用过去式。
|
|
19
29
|
"""
|
|
20
30
|
if image.find(R.Common.IconButtonCheck):
|
|
21
31
|
device.click()
|
|
32
|
+
if msg is not None:
|
|
33
|
+
logger.debug(msg)
|
|
22
34
|
return True
|
|
23
35
|
return False
|
|
24
36
|
|
|
25
|
-
def expect_no():
|
|
37
|
+
def expect_no(*, msg: str | None = None):
|
|
26
38
|
"""
|
|
27
39
|
点击对话框上的✖️按钮。若不存在,会等待其出现,直至超时异常。
|
|
28
40
|
|
|
29
41
|
前置条件:当前打开了任意对话框\n
|
|
30
42
|
结束状态:点击了否定意义按钮(✖️图标,白色背景)后瞬间
|
|
43
|
+
|
|
44
|
+
:param msg: 成功点击后输出的日志信息。信息中的动词建议使用过去式。
|
|
31
45
|
"""
|
|
32
46
|
device.click(image.expect(R.Common.IconButtonCross))
|
|
47
|
+
if msg is not None:
|
|
48
|
+
logger.debug(msg)
|
|
33
49
|
|
|
34
|
-
def no():
|
|
50
|
+
def no(*, msg: str | None = None):
|
|
35
51
|
"""
|
|
36
52
|
点击对话框上的✖️按钮。
|
|
37
53
|
|
|
38
54
|
前置条件:当前打开了任意对话框\n
|
|
39
55
|
结束状态:点击了否定意义按钮(✖️图标,白色背景)后瞬间
|
|
56
|
+
|
|
57
|
+
:param msg: 成功点击后输出的日志信息。信息中的动词建议使用过去式。
|
|
40
58
|
"""
|
|
41
59
|
if image.find(R.Common.IconButtonCross):
|
|
42
60
|
device.click()
|
|
61
|
+
if msg is not None:
|
|
62
|
+
logger.debug(msg)
|
|
43
63
|
return True
|
|
44
64
|
return False
|
|
45
65
|
|
|
@@ -10,7 +10,8 @@ from kotonebot.kaa.util import paths
|
|
|
10
10
|
from kotonebot.primitives import RectTuple, Rect
|
|
11
11
|
from kotonebot.kaa.game_ui import Scrollable
|
|
12
12
|
from kotonebot import device, action
|
|
13
|
-
from kotonebot.
|
|
13
|
+
from kotonebot.util import cv2_imread
|
|
14
|
+
from kotonebot.kaa.image_db import ImageDatabase, HistDescriptor, FileDataSource, DatabaseQueryResult
|
|
14
15
|
from kotonebot.backend.preprocessor import HsvColorsRemover
|
|
15
16
|
|
|
16
17
|
logger = logging.getLogger(__name__)
|
|
@@ -106,8 +107,32 @@ def idols_db() -> ImageDatabase:
|
|
|
106
107
|
_db = ImageDatabase(FileDataSource(str(path)), db_path, HistDescriptor(8), name='idols')
|
|
107
108
|
return _db
|
|
108
109
|
|
|
110
|
+
def match_idol(skin_id: str, idol_img: MatLike) -> DatabaseQueryResult | None:
|
|
111
|
+
"""
|
|
112
|
+
将给定图像与指定偶像 ID 进行匹配。
|
|
113
|
+
|
|
114
|
+
:param skin_id: 偶像 ID。
|
|
115
|
+
:param idol_img: 待匹配偶像图像。
|
|
116
|
+
:return: 若匹配成功,则返回匹配结果,否则返回 None。
|
|
117
|
+
"""
|
|
118
|
+
db = idols_db()
|
|
119
|
+
match = db.match(idol_img, 20)
|
|
120
|
+
if match and match.key.startswith(skin_id):
|
|
121
|
+
return match
|
|
122
|
+
else:
|
|
123
|
+
return None
|
|
124
|
+
|
|
109
125
|
@action('定位偶像', screenshot_mode='manual-inherit')
|
|
110
|
-
def locate_idol(skin_id: str):
|
|
126
|
+
def locate_idol(skin_id: str) -> Rect | None:
|
|
127
|
+
"""
|
|
128
|
+
定位并选中指定偶像。
|
|
129
|
+
|
|
130
|
+
前置条件:位于偶像总览界面。\n
|
|
131
|
+
结束状态:位于偶像总览界面。
|
|
132
|
+
|
|
133
|
+
:param skin_id: 目标偶像的 Skin ID
|
|
134
|
+
:return: 若成功,返回目标偶像的范围 (x, y, w, h),否则返回 None。
|
|
135
|
+
"""
|
|
111
136
|
device.screenshot()
|
|
112
137
|
logger.info('Locating idol %s', skin_id)
|
|
113
138
|
x, y, w, h = R.Produce.BoxIdolOverviewIdols.xywh
|
|
@@ -146,15 +171,6 @@ def locate_idol(skin_id: str):
|
|
|
146
171
|
|
|
147
172
|
# # 使用新函数绘制预览图
|
|
148
173
|
# preview_img = draw_idol_preview(img, rects, db, path)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
def test():
|
|
152
|
-
from kotonebot.backend.context import init_context, manual_context
|
|
153
|
-
init_context()
|
|
154
|
-
manual_context().begin()
|
|
155
|
-
locate_idol('i_card-skin-fktn-3-006')
|
|
156
174
|
|
|
157
175
|
if __name__ == '__main__':
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
test()
|
|
176
|
+
locate_idol('i_card-skin-fktn-3-006')
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import cv2
|
|
2
|
+
import numpy as np
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from cv2.typing import MatLike
|
|
5
|
+
|
|
6
|
+
from kotonebot import action, image, device
|
|
7
|
+
from kotonebot.backend.core import Image
|
|
8
|
+
from kotonebot.backend.image import TemplateMatchResult
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def primary_button_state(img: MatLike) -> Optional[bool]:
|
|
12
|
+
"""
|
|
13
|
+
分析按钮图像并根据红色通道直方图返回按钮状态
|
|
14
|
+
|
|
15
|
+
:param img: 输入的按钮图像 (BGR格式)
|
|
16
|
+
:return: True - 启用状态
|
|
17
|
+
False - 禁用状态
|
|
18
|
+
None - 未知状态或输入无效
|
|
19
|
+
"""
|
|
20
|
+
# 确保图像有效
|
|
21
|
+
if img is None or img.size == 0:
|
|
22
|
+
return None
|
|
23
|
+
|
|
24
|
+
# 计算红色通道直方图(五箱)
|
|
25
|
+
_, _, r = cv2.split(img)
|
|
26
|
+
hist = cv2.calcHist([r], [0], None, [5], [0, 256])
|
|
27
|
+
# 归一化并找出红色集中在哪一箱
|
|
28
|
+
hist = hist.ravel() / hist.sum()
|
|
29
|
+
max_idx = np.argmax(hist)
|
|
30
|
+
|
|
31
|
+
if max_idx == 3:
|
|
32
|
+
return False
|
|
33
|
+
elif max_idx == 4:
|
|
34
|
+
return True
|
|
35
|
+
else:
|
|
36
|
+
return None
|
|
37
|
+
|
|
38
|
+
@action('寻找按钮', screenshot_mode='manual-inherit')
|
|
39
|
+
def find_button(template: MatLike | Image, state: Optional[bool] = None) -> Optional[bool]:
|
|
40
|
+
"""
|
|
41
|
+
在图像中寻找按钮并返回其状态
|
|
42
|
+
|
|
43
|
+
:param template: 按钮模板图像 (BGR格式)
|
|
44
|
+
:param state: 按钮状态 (True - 启用, False - 禁用, None - 任意)
|
|
45
|
+
:return: True - 启用状态
|
|
46
|
+
False - 禁用状态
|
|
47
|
+
None - 未找到按钮或状态未知
|
|
48
|
+
"""
|
|
49
|
+
img = device.screenshot()
|
|
50
|
+
result = image.find(template)
|
|
51
|
+
if result is None:
|
|
52
|
+
return None
|
|
53
|
+
x, y, w, h = result.rect.xywh
|
|
54
|
+
button_img = img[y:y+h, x:x+w]
|
|
55
|
+
return primary_button_state(button_img)
|
|
@@ -327,12 +327,7 @@ class Scrollable:
|
|
|
327
327
|
return ScrollableIterator(self, int(self.track_height * step), start, end, skip_first)
|
|
328
328
|
|
|
329
329
|
if __name__ == '__main__':
|
|
330
|
-
from kotonebot.backend.context import init_context, manual_context, device
|
|
331
|
-
init_context()
|
|
332
|
-
manual_context().begin()
|
|
333
|
-
from kotonebot import device
|
|
334
330
|
import cv2
|
|
335
|
-
from kotonebot.util import cv2_imread
|
|
336
331
|
import time
|
|
337
332
|
logger.setLevel(logging.DEBUG)
|
|
338
333
|
|
kotonebot/kaa/main/cli.py
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import sys
|
|
3
|
-
import runpy
|
|
4
3
|
import logging
|
|
5
4
|
import argparse
|
|
6
5
|
import importlib.metadata
|
|
7
6
|
from datetime import datetime
|
|
8
7
|
|
|
9
8
|
from .kaa import Kaa
|
|
9
|
+
from ..util.paths import get_ahk_path
|
|
10
|
+
from kotonebot.client.implements.windows import WindowsImplConfig
|
|
10
11
|
from kotonebot.backend.context import tasks_from_id, task_registry
|
|
12
|
+
from kotonebot.client.implements.remote_windows import RemoteWindowsServer
|
|
11
13
|
|
|
12
14
|
version = importlib.metadata.version('ksaa')
|
|
13
15
|
|
|
@@ -90,9 +92,12 @@ def task_list() -> int:
|
|
|
90
92
|
def remote_server() -> int:
|
|
91
93
|
args = psr.parse_args()
|
|
92
94
|
try:
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
95
|
+
ahk_path = get_ahk_path()
|
|
96
|
+
server = RemoteWindowsServer(WindowsImplConfig(window_title='gakumas', ahk_exe_path=ahk_path), args.host, args.port)
|
|
97
|
+
server.start()
|
|
98
|
+
return 0
|
|
99
|
+
except KeyboardInterrupt:
|
|
100
|
+
print("Server stopped by user")
|
|
96
101
|
return 0
|
|
97
102
|
except Exception as e:
|
|
98
103
|
print(f'Error starting remote server: {e}')
|
kotonebot/kaa/main/dmm_host.py
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
from typing_extensions import override
|
|
2
2
|
|
|
3
|
-
from kotonebot.client import Device
|
|
4
|
-
from kotonebot.client import DeviceImpl, Device
|
|
3
|
+
from kotonebot.client import Device
|
|
5
4
|
from kotonebot.client.host import HostProtocol, Instance
|
|
5
|
+
from kotonebot.client.host.windows_common import WindowsRecipes, WindowsHostConfigs, CommonWindowsCreateDeviceMixin
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
DmmHostConfigs = WindowsHostConfigs
|
|
9
|
+
DmmRecipes = WindowsRecipes
|
|
6
10
|
|
|
7
11
|
# TODO: 可能应该把 start_game 和 end_game 里对启停的操作移动到这里来
|
|
8
|
-
class DmmInstance(Instance):
|
|
12
|
+
class DmmInstance(CommonWindowsCreateDeviceMixin, Instance[DmmHostConfigs]):
|
|
9
13
|
def __init__(self):
|
|
10
14
|
super().__init__('dmm', 'gakumas')
|
|
11
15
|
|
|
@@ -30,12 +34,11 @@ class DmmInstance(Instance):
|
|
|
30
34
|
raise NotImplementedError()
|
|
31
35
|
|
|
32
36
|
@override
|
|
33
|
-
def create_device(self, impl:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return create_device('', impl, timeout=timeout)
|
|
37
|
+
def create_device(self, impl: DmmRecipes, host_config: DmmHostConfigs) -> Device:
|
|
38
|
+
"""为 DMM 实例创建 Device。"""
|
|
39
|
+
return super().create_device(impl, host_config)
|
|
37
40
|
|
|
38
|
-
class DmmHost(HostProtocol):
|
|
41
|
+
class DmmHost(HostProtocol[DmmRecipes]):
|
|
39
42
|
instance = DmmInstance()
|
|
40
43
|
"""DmmInstance 单例。"""
|
|
41
44
|
|
|
@@ -51,3 +54,7 @@ class DmmHost(HostProtocol):
|
|
|
51
54
|
@staticmethod
|
|
52
55
|
def query(*, id: str) -> Instance | None:
|
|
53
56
|
raise NotImplementedError()
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def recipes() -> 'list[DmmRecipes]':
|
|
60
|
+
return ['windows', 'remote_windows']
|
kotonebot/kaa/main/gr.py
CHANGED
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
import traceback
|
|
3
3
|
import zipfile
|
|
4
4
|
import logging
|
|
5
|
+
import copy
|
|
5
6
|
from functools import partial
|
|
6
7
|
from itertools import chain
|
|
7
8
|
from datetime import datetime, timedelta
|
|
@@ -33,6 +34,7 @@ ConfigKey = Literal[
|
|
|
33
34
|
'check_emulator', 'emulator_path',
|
|
34
35
|
'adb_emulator_name', 'emulator_args',
|
|
35
36
|
'_mumu_index', '_leidian_index',
|
|
37
|
+
'mumu_background_mode',
|
|
36
38
|
|
|
37
39
|
# purchase
|
|
38
40
|
'purchase_enabled',
|
|
@@ -94,17 +96,30 @@ ConfigSetFunction = Callable[[BaseConfig, Dict[ConfigKey, Any]], None]
|
|
|
94
96
|
ConfigBuilderReturnValue = Tuple[ConfigSetFunction, Dict[ConfigKey, GradioInput]]
|
|
95
97
|
|
|
96
98
|
def _save_bug_report(
|
|
99
|
+
title: str,
|
|
100
|
+
description: str,
|
|
97
101
|
version: str,
|
|
102
|
+
upload: bool,
|
|
98
103
|
path: str | None = None
|
|
99
104
|
) -> Generator[str, None, str]:
|
|
100
105
|
"""
|
|
101
106
|
保存报告
|
|
102
107
|
|
|
103
|
-
:param
|
|
108
|
+
:param title: 标题
|
|
109
|
+
:param description: 描述
|
|
110
|
+
:param version: 版本号
|
|
111
|
+
:param upload: 是否上传
|
|
112
|
+
:param path: 保存的路径。若为 `None`,则保存到 `./reports/bug-YY-MM-DD HH-MM-SS_标题.zip`。
|
|
104
113
|
:return: 保存的路径
|
|
105
114
|
"""
|
|
106
115
|
from kotonebot import device
|
|
107
116
|
from kotonebot.backend.context import ContextStackVars
|
|
117
|
+
import re
|
|
118
|
+
|
|
119
|
+
# 过滤标题中的非法文件名字符
|
|
120
|
+
def sanitize_filename(s: str) -> str:
|
|
121
|
+
# 替换 \/:*?"<>| 为空或下划线
|
|
122
|
+
return re.sub(r'[\\/:*?"<>|]', '_', s)
|
|
108
123
|
|
|
109
124
|
# 确保目录存在
|
|
110
125
|
os.makedirs('logs', exist_ok=True)
|
|
@@ -112,8 +127,18 @@ def _save_bug_report(
|
|
|
112
127
|
|
|
113
128
|
error = ""
|
|
114
129
|
if path is None:
|
|
115
|
-
|
|
130
|
+
safe_title = sanitize_filename(title)[:30] or "无标题"
|
|
131
|
+
timestamp = datetime.now().strftime("%y-%m-%d-%H-%M-%S")
|
|
132
|
+
path = f'./reports/bug_{timestamp}_{safe_title}.zip'
|
|
116
133
|
with zipfile.ZipFile(path, 'w', zipfile.ZIP_DEFLATED, compresslevel=9) as zipf:
|
|
134
|
+
# 打包描述文件
|
|
135
|
+
yield "### 打包描述文件..."
|
|
136
|
+
try:
|
|
137
|
+
description_content = f"标题:{title}\n类型:bug\n内容:\n{description}"
|
|
138
|
+
zipf.writestr('description.txt', description_content.encode('utf-8'))
|
|
139
|
+
except Exception as e:
|
|
140
|
+
error += f"保存描述文件失败:{str(e)}\n"
|
|
141
|
+
|
|
117
142
|
# 打包截图
|
|
118
143
|
yield "### 打包上次截图..."
|
|
119
144
|
try:
|
|
@@ -158,12 +183,16 @@ def _save_bug_report(
|
|
|
158
183
|
# 写出版本号
|
|
159
184
|
zipf.writestr('version.txt', version)
|
|
160
185
|
|
|
186
|
+
if not upload:
|
|
187
|
+
yield f"### 报告已保存至 {os.path.abspath(path)}"
|
|
188
|
+
return path
|
|
189
|
+
|
|
161
190
|
# 上传报告
|
|
162
|
-
from kotonebot.ui.file_host.sensio import upload
|
|
191
|
+
from kotonebot.ui.file_host.sensio import upload as upload_file
|
|
163
192
|
yield "### 上传报告..."
|
|
164
193
|
url = ''
|
|
165
194
|
try:
|
|
166
|
-
url =
|
|
195
|
+
url = upload_file(path)
|
|
167
196
|
except Exception as e:
|
|
168
197
|
yield f"### 上传报告失败:{str(e)}\n\n"
|
|
169
198
|
return ''
|
|
@@ -371,9 +400,41 @@ class KotoneBotUI:
|
|
|
371
400
|
assert key in CONFIG_KEY_VALUE, f"未知的配置项:{key}"
|
|
372
401
|
key = cast(ConfigKey, key)
|
|
373
402
|
data[key] = value
|
|
374
|
-
|
|
403
|
+
|
|
404
|
+
# 先设置options
|
|
375
405
|
for (set_func, _) in return_values:
|
|
376
406
|
set_func(options, data)
|
|
407
|
+
|
|
408
|
+
# 验证规则1:截图方法验证
|
|
409
|
+
screenshot_method = self.current_config.backend.screenshot_impl
|
|
410
|
+
backend_type = self.current_config.backend.type
|
|
411
|
+
|
|
412
|
+
valid_screenshot_methods = {
|
|
413
|
+
'mumu12': ['adb', 'adb_raw', 'uiautomator2', 'nemu_ipc'],
|
|
414
|
+
'leidian': ['adb', 'adb_raw', 'uiautomator2'],
|
|
415
|
+
'custom': ['adb', 'adb_raw', 'uiautomator2'],
|
|
416
|
+
'dmm': ['remote_windows', 'windows']
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if screenshot_method not in valid_screenshot_methods.get(backend_type, []):
|
|
420
|
+
gr.Warning(f"截图方法 '{screenshot_method}' 不适用于当前选择的模拟器类型,配置未保存。")
|
|
421
|
+
return ""
|
|
422
|
+
|
|
423
|
+
# 验证规则2:若启用培育,那么培育偶像不能为空
|
|
424
|
+
if options.produce.enabled and not options.produce.idols:
|
|
425
|
+
gr.Warning("启用培育时,培育偶像不能为空,配置未保存。")
|
|
426
|
+
return ""
|
|
427
|
+
|
|
428
|
+
# 验证规则3:若启用AP/金币购买,对应的商品不能为空
|
|
429
|
+
if options.purchase.ap_enabled and not options.purchase.ap_items:
|
|
430
|
+
gr.Warning("启用AP购买时,AP商店购买物品不能为空,配置未保存。")
|
|
431
|
+
return ""
|
|
432
|
+
|
|
433
|
+
if options.purchase.money_enabled and not options.purchase.money_items:
|
|
434
|
+
gr.Warning("启用金币购买时,金币商店购买物品不能为空,配置未保存。")
|
|
435
|
+
return ""
|
|
436
|
+
|
|
437
|
+
# 验证通过,保存配置
|
|
377
438
|
self.current_config.options = options
|
|
378
439
|
try:
|
|
379
440
|
save_config(self.config, "config.json")
|
|
@@ -393,7 +454,14 @@ class KotoneBotUI:
|
|
|
393
454
|
if self._kaa.upgrade_msg:
|
|
394
455
|
gr.Markdown('### 配置升级报告')
|
|
395
456
|
gr.Markdown(self._kaa.upgrade_msg)
|
|
396
|
-
gr.Markdown('
|
|
457
|
+
gr.Markdown('脚本报错或者卡住?前往"反馈"选项卡可以快速导出报告!')
|
|
458
|
+
|
|
459
|
+
# 添加调试模式警告
|
|
460
|
+
if self.current_config.keep_screenshots:
|
|
461
|
+
gr.Markdown(
|
|
462
|
+
'<div style="color: red; font-size: larger;">当前启用了调试功能「保留截图数据」,调试结束后正常使用时建议关闭此选项!</div>',
|
|
463
|
+
elem_classes=["debug-warning"]
|
|
464
|
+
)
|
|
397
465
|
|
|
398
466
|
task_status = gr.Dataframe(
|
|
399
467
|
headers=["任务", "状态"],
|
|
@@ -555,7 +623,9 @@ class KotoneBotUI:
|
|
|
555
623
|
# choices = ['windows', 'remote_windows']
|
|
556
624
|
# else: # Mumu, Leidian, Custom
|
|
557
625
|
# choices = ['adb', 'adb_raw', 'uiautomator2']
|
|
558
|
-
|
|
626
|
+
# else:
|
|
627
|
+
# raise ValueError(f'Unsupported backend type: {type_in_config}')
|
|
628
|
+
choices = ['adb', 'adb_raw', 'uiautomator2', 'windows', 'remote_windows', 'nemu_ipc']
|
|
559
629
|
if impl_value not in choices:
|
|
560
630
|
new_value = choices[0]
|
|
561
631
|
else:
|
|
@@ -576,13 +646,21 @@ class KotoneBotUI:
|
|
|
576
646
|
choices=[(i.name, i.id) for i in instances],
|
|
577
647
|
interactive=True
|
|
578
648
|
)
|
|
649
|
+
mumu_background_mode = gr.Checkbox(
|
|
650
|
+
label="MuMu12 模拟器后台保活模式",
|
|
651
|
+
value=self.current_config.backend.mumu_background_mode,
|
|
652
|
+
info=BackendConfig.model_fields['mumu_background_mode'].description,
|
|
653
|
+
interactive=True
|
|
654
|
+
)
|
|
579
655
|
except: # noqa: E722
|
|
580
656
|
logger.exception('Failed to list installed MuMu12')
|
|
581
657
|
gr.Markdown('获取 MuMu12 模拟器列表失败,请升级模拟器到最新版本。若问题依旧,前往 QQ 群、QQ 频道或 Github 反馈 bug。')
|
|
582
658
|
mumu_instance = gr.Dropdown(visible=False)
|
|
659
|
+
mumu_background_mode = gr.Checkbox(visible=False)
|
|
583
660
|
else:
|
|
584
661
|
# 为了让 return 收集组件时不报错
|
|
585
662
|
mumu_instance = gr.Dropdown(visible=False)
|
|
663
|
+
mumu_background_mode = gr.Checkbox(visible=False)
|
|
586
664
|
|
|
587
665
|
with gr.Tab("雷电", interactive=has_leidian, id="leidian") as tab_leidian:
|
|
588
666
|
gr.Markdown("已选中雷电模拟器")
|
|
@@ -661,7 +739,7 @@ class KotoneBotUI:
|
|
|
661
739
|
# choices = ['adb', 'adb_raw', 'uiautomator2']
|
|
662
740
|
# else:
|
|
663
741
|
# raise ValueError(f'Unsupported backend type: {type_in_config}')
|
|
664
|
-
choices = ['adb', 'adb_raw', 'uiautomator2', 'windows', 'remote_windows']
|
|
742
|
+
choices = ['adb', 'adb_raw', 'uiautomator2', 'windows', 'remote_windows', 'nemu_ipc']
|
|
665
743
|
screenshot_impl = gr.Dropdown(
|
|
666
744
|
choices=choices,
|
|
667
745
|
value=self.current_config.backend.screenshot_impl,
|
|
@@ -711,6 +789,7 @@ class KotoneBotUI:
|
|
|
711
789
|
if current_tab == 0: # Mumu
|
|
712
790
|
self.current_config.backend.type = 'mumu12'
|
|
713
791
|
self.current_config.backend.instance_id = data['_mumu_index']
|
|
792
|
+
self.current_config.backend.mumu_background_mode = data['mumu_background_mode']
|
|
714
793
|
elif current_tab == 1: # Leidian
|
|
715
794
|
self.current_config.backend.type = 'leidian'
|
|
716
795
|
self.current_config.backend.instance_id = data['_leidian_index']
|
|
@@ -741,7 +820,8 @@ class KotoneBotUI:
|
|
|
741
820
|
'adb_emulator_name': adb_emulator_name,
|
|
742
821
|
'emulator_args': emulator_args,
|
|
743
822
|
'_mumu_index': mumu_instance,
|
|
744
|
-
'_leidian_index': leidian_instance
|
|
823
|
+
'_leidian_index': leidian_instance,
|
|
824
|
+
'mumu_background_mode': mumu_background_mode
|
|
745
825
|
}
|
|
746
826
|
|
|
747
827
|
def _create_purchase_settings(self) -> ConfigBuilderReturnValue:
|
|
@@ -1460,27 +1540,33 @@ class KotoneBotUI:
|
|
|
1460
1540
|
)
|
|
1461
1541
|
|
|
1462
1542
|
def _create_log_tab(self) -> None:
|
|
1463
|
-
with gr.Tab("
|
|
1464
|
-
gr.Markdown("##
|
|
1465
|
-
|
|
1543
|
+
with gr.Tab("反馈"):
|
|
1544
|
+
gr.Markdown("## 反馈")
|
|
1545
|
+
gr.Markdown('脚本报错或者卡住?在这里填写信息可以快速反馈!')
|
|
1466
1546
|
with gr.Column():
|
|
1547
|
+
report_title = gr.Textbox(label="标题", placeholder="用一句话概括问题")
|
|
1548
|
+
report_type = gr.Dropdown(label="反馈类型", choices=["bug"], value="bug", interactive=False)
|
|
1549
|
+
report_description = gr.Textbox(label="描述", lines=5, placeholder="详细描述问题。例如:什么时候出错、是否每次都出错、出错时的步骤是什么")
|
|
1467
1550
|
with gr.Row():
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
save_report_btn = gr.Button("一键导出报告")
|
|
1551
|
+
upload_report_btn = gr.Button("上传")
|
|
1552
|
+
save_local_report_btn = gr.Button("保存至本地")
|
|
1553
|
+
|
|
1472
1554
|
result_text = gr.Markdown("等待操作\n\n\n")
|
|
1473
1555
|
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
)
|
|
1478
|
-
|
|
1479
|
-
|
|
1556
|
+
def on_upload_click(title: str, description: str):
|
|
1557
|
+
yield from _save_bug_report(title, description, self._kaa.version, upload=True)
|
|
1558
|
+
|
|
1559
|
+
def on_save_local_click(title: str, description: str):
|
|
1560
|
+
yield from _save_bug_report(title, description, self._kaa.version, upload=False)
|
|
1561
|
+
|
|
1562
|
+
upload_report_btn.click(
|
|
1563
|
+
fn=on_upload_click,
|
|
1564
|
+
inputs=[report_title, report_description],
|
|
1480
1565
|
outputs=[result_text]
|
|
1481
1566
|
)
|
|
1482
|
-
|
|
1483
|
-
fn=
|
|
1567
|
+
save_local_report_btn.click(
|
|
1568
|
+
fn=on_save_local_click,
|
|
1569
|
+
inputs=[report_title, report_description],
|
|
1484
1570
|
outputs=[result_text]
|
|
1485
1571
|
)
|
|
1486
1572
|
|
|
@@ -1493,6 +1579,7 @@ class KotoneBotUI:
|
|
|
1493
1579
|
def _create_screen_tab(self) -> None:
|
|
1494
1580
|
with gr.Tab("画面"):
|
|
1495
1581
|
gr.Markdown("## 当前设备画面")
|
|
1582
|
+
refresh_btn = gr.Button("刷新画面", variant="primary")
|
|
1496
1583
|
WIDTH = 720 // 3
|
|
1497
1584
|
HEIGHT = 1280 // 3
|
|
1498
1585
|
last_update_text = gr.Markdown("上次更新时间:无数据")
|
|
@@ -1501,14 +1588,14 @@ class KotoneBotUI:
|
|
|
1501
1588
|
def update_screenshot():
|
|
1502
1589
|
ctx = ContextStackVars.current()
|
|
1503
1590
|
if ctx is None:
|
|
1504
|
-
return [None,
|
|
1591
|
+
return [None, "上次更新时间:无上下文数据"]
|
|
1505
1592
|
screenshot = ctx._screenshot
|
|
1506
1593
|
if screenshot is None:
|
|
1507
|
-
return [None,
|
|
1594
|
+
return [None, "上次更新时间:无截图数据"]
|
|
1508
1595
|
screenshot = cv2.cvtColor(screenshot, cv2.COLOR_BGR2RGB)
|
|
1509
1596
|
return screenshot, f"上次更新时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
|
|
1510
1597
|
|
|
1511
|
-
|
|
1598
|
+
refresh_btn.click(
|
|
1512
1599
|
fn=update_screenshot,
|
|
1513
1600
|
outputs=[screenshot_display, last_update_text]
|
|
1514
1601
|
)
|