ksaa 2025.5.23.3__py3-none-any.whl → 2025.6.23.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.
Files changed (202) hide show
  1. kotonebot/backend/bot.py +3 -3
  2. kotonebot/backend/context/context.py +52 -36
  3. kotonebot/backend/debug/server.py +3 -5
  4. kotonebot/backend/dispatch.py +1 -17
  5. kotonebot/backend/flow_controller.py +195 -0
  6. kotonebot/backend/loop.py +277 -0
  7. kotonebot/client/__init__.py +4 -1
  8. kotonebot/client/device.py +23 -21
  9. kotonebot/client/host/__init__.py +2 -1
  10. kotonebot/client/host/custom.py +26 -3
  11. kotonebot/client/host/leidian_host.py +22 -11
  12. kotonebot/client/host/mumu12_host.py +25 -3
  13. kotonebot/client/host/protocol.py +40 -18
  14. kotonebot/client/implements/__init__.py +6 -0
  15. kotonebot/client/implements/adb.py +67 -7
  16. kotonebot/client/implements/adb_raw.py +12 -5
  17. kotonebot/client/implements/remote_windows.py +20 -18
  18. kotonebot/client/implements/uiautomator2.py +8 -0
  19. kotonebot/client/implements/windows.py +56 -28
  20. kotonebot/client/protocol.py +13 -0
  21. kotonebot/client/registration.py +89 -0
  22. kotonebot/config/base_config.py +5 -1
  23. kotonebot/debug_entry.py +7 -2
  24. kotonebot/kaa/clear_logs.py +0 -3
  25. kotonebot/kaa/common.py +21 -0
  26. kotonebot/kaa/game_ui/common.py +4 -7
  27. kotonebot/kaa/game_ui/dialog.py +24 -4
  28. kotonebot/kaa/game_ui/idols_overview.py +28 -12
  29. kotonebot/kaa/game_ui/primary_button.py +55 -0
  30. kotonebot/kaa/game_ui/scrollable.py +0 -5
  31. kotonebot/kaa/main/cli.py +9 -4
  32. kotonebot/kaa/main/dmm_host.py +33 -7
  33. kotonebot/kaa/main/gr.py +156 -26
  34. kotonebot/kaa/main/kaa.py +113 -41
  35. kotonebot/kaa/metadata.py +27 -0
  36. kotonebot/kaa/resources/__pycache__/__init__.cpython-310.pyc +0 -0
  37. kotonebot/kaa/resources/game.db +0 -0
  38. kotonebot/kaa/resources/game_ver.txt +0 -0
  39. kotonebot/kaa/resources/idol_cards/i_card-skin-kllj-3-012_0.png +0 -0
  40. kotonebot/kaa/resources/idol_cards/i_card-skin-kllj-3-012_1.png +0 -0
  41. kotonebot/kaa/resources/idol_cards/i_card-skin-ssmk-3-012_0.png +0 -0
  42. kotonebot/kaa/resources/idol_cards/i_card-skin-ssmk-3-012_1.png +0 -0
  43. kotonebot/kaa/sprites/24e99232-9434-457f-a9a0-69dd7ecf675f.png +0 -0
  44. kotonebot/kaa/sprites/2ededcf5-1d80-4e2a-9c83-2a31998331ce.png +0 -0
  45. kotonebot/kaa/sprites/3b473fe6-e147-477f-b088-9b8fb042a4f6.png +0 -0
  46. kotonebot/kaa/sprites/55f7db71-0a18-4b3d-b847-57959b8d2e32.png +0 -0
  47. kotonebot/kaa/sprites/6cd80be8-c9b3-4ba5-bf17-3ffc9b000743.png +0 -0
  48. kotonebot/kaa/sprites/74ec3510-583d-4a76-ac69-38480fbf1387.png +0 -0
  49. kotonebot/kaa/sprites/a0bd6a5f-784d-4f0a-9d66-10f4b80c8d3e.png +0 -0
  50. kotonebot/kaa/sprites/d3424d31-0502-4623-996e-f0194e5085ce.png +0 -0
  51. kotonebot/kaa/sprites/e6b45405-cd9f-4c6e-a9f1-6ec953747c65.png +0 -0
  52. kotonebot/kaa/sprites/f5c16d2f-ebc5-4617-9b96-971696af7c52.png +0 -0
  53. kotonebot/kaa/tasks/R.py +157 -135
  54. kotonebot/kaa/tasks/end_game.py +14 -0
  55. kotonebot/kaa/tasks/produce/common.py +1 -0
  56. kotonebot/kaa/tasks/produce/in_purodyuusu.py +0 -4
  57. kotonebot/kaa/tasks/produce/non_lesson_actions.py +1 -4
  58. kotonebot/kaa/tasks/produce/produce.py +119 -70
  59. kotonebot/kaa/tasks/start_game.py +56 -7
  60. kotonebot/kaa/util/paths.py +6 -1
  61. kotonebot/tools/mirror.py +23 -13
  62. kotonebot/util.py +32 -0
  63. {ksaa-2025.5.23.3.dist-info → ksaa-2025.6.23.0.dist-info}/METADATA +38 -1
  64. {ksaa-2025.5.23.3.dist-info → ksaa-2025.6.23.0.dist-info}/RECORD +200 -183
  65. ksaa-2025.6.23.0.dist-info/licenses/LICENSE +674 -0
  66. kotonebot/client/factory.py +0 -92
  67. kotonebot/kaa/sprites/b260d390-2b1a-4974-92db-d68ff7b5b8e6.png +0 -0
  68. /kotonebot/kaa/sprites/{f6d36222-847e-4300-8f90-c98c7a8f36e3.png → 0235ae3d-1741-4a81-8053-f60bc395ee85.png} +0 -0
  69. /kotonebot/kaa/sprites/{48a02c33-b7af-4ab5-bda1-3a2ec62a7076.png → 038c69e6-7cb0-4c8d-99da-b537e48a86b7.png} +0 -0
  70. /kotonebot/kaa/sprites/{b99f0684-8200-4080-9b54-808c4ec12c99.png → 080b3cf5-ce35-4382-9bfa-d6a12efb09b3.png} +0 -0
  71. /kotonebot/kaa/sprites/{7c65fc91-602b-4d1b-82f9-c9b561a55d9b.png → 09fb5e41-6caa-4246-a415-8317b12d8d81.png} +0 -0
  72. /kotonebot/kaa/sprites/{5e74dc61-0ad5-4e57-b331-e3d2ed67b6d2.png → 0a6c6b1e-7a80-428e-a483-1858bfb8ac59.png} +0 -0
  73. /kotonebot/kaa/sprites/{aad29ac0-b9ad-4c38-93f5-e8036ad7b96b.png → 0ad2f603-a3ad-4a92-a398-c411145fd8e9.png} +0 -0
  74. /kotonebot/kaa/sprites/{e98037f8-3b4a-4de8-adc1-ca0f736b6c98.png → 0d4b669e-5e43-4458-b65a-5565797335ae.png} +0 -0
  75. /kotonebot/kaa/sprites/{382bc600-72f6-433f-809e-9fe2fdb31b32.png → 0fbcb3f6-9ca0-43c7-975b-e7c15c26c897.png} +0 -0
  76. /kotonebot/kaa/sprites/{6d39d7a2-0b1f-4f49-9ab8-062bca9b5470.png → 15465879-eb84-4ca6-ae0f-d3c5ac71e723.png} +0 -0
  77. /kotonebot/kaa/sprites/{474ce25b-8a3d-435e-8d7a-ab6566ae61a0.png → 1639278d-67e0-4452-a2b5-ec4cf4011f42.png} +0 -0
  78. /kotonebot/kaa/sprites/{7d4f53fb-02bc-4139-b32c-3345a5f92a79.png → 17414e9e-b046-49e0-9596-cad1f4673a9e.png} +0 -0
  79. /kotonebot/kaa/sprites/{9a72b63e-8bd1-47dc-8298-cdf02220201e.png → 17a8b0a5-5b71-4612-8a68-16c51f03c71b.png} +0 -0
  80. /kotonebot/kaa/sprites/{a1610e9f-93f0-4ef2-b32a-b2effd1673e8.png → 1aaceb21-dc5c-4a58-96d3-d2c66b2fb357.png} +0 -0
  81. /kotonebot/kaa/sprites/{237636f2-aec0-40be-b7bb-e08607a89307.png → 1aae0ab3-f619-47e0-8bf6-3d3791f7d445.png} +0 -0
  82. /kotonebot/kaa/sprites/{872c37e7-e596-4449-86f4-5ba65836a7a7.png → 1b6be6dd-2711-441a-9fa6-3281a6ad10c7.png} +0 -0
  83. /kotonebot/kaa/sprites/{a829f038-5421-4cc4-a494-105a973351e2.png → 1bb00a74-2fdc-4973-84ae-dc1edee15f81.png} +0 -0
  84. /kotonebot/kaa/sprites/{e5922ce7-9aa7-4806-acdd-9c35408a0f37.png → 1ccdcacf-4f7d-442c-8e2f-09aa7fe14e56.png} +0 -0
  85. /kotonebot/kaa/sprites/{1df6ff4b-17f8-4ee6-8df0-0b53e26b7f1e.png → 1d5f7454-672d-4e87-a368-ec4bb32f9b1f.png} +0 -0
  86. /kotonebot/kaa/sprites/{51f38e84-56c8-4c80-9a67-35196ef54b89.png → 1f2981d8-5eb6-4332-aa9b-17f4db2d4163.png} +0 -0
  87. /kotonebot/kaa/sprites/{f4b226eb-ed9e-4e5e-9ba0-1b777e401aa3.png → 25910d8e-d57f-409f-b0be-ee68c5af4920.png} +0 -0
  88. /kotonebot/kaa/sprites/{e9e399f7-4e2f-4392-bb8f-850c4a272dfa.png → 264e056f-3bcc-4b16-94d4-f767c78ab6f5.png} +0 -0
  89. /kotonebot/kaa/sprites/{cc0ac4cf-01fd-48f9-8707-2d6a2aa0ba8c.png → 26580772-ff20-4dcf-8496-f939e0f2890d.png} +0 -0
  90. /kotonebot/kaa/sprites/{7dd31493-9f3b-4382-a43a-f8eb1c745ad8.png → 29cb7b0f-5684-4516-8fae-4439f7f28e08.png} +0 -0
  91. /kotonebot/kaa/sprites/{415c45a8-9b71-4e0b-8cd2-f80a0a4aafb7.png → 2d145ade-b926-4276-b872-baec4ef78308.png} +0 -0
  92. /kotonebot/kaa/sprites/{d2732870-dd6b-4b7b-b21e-4ff2a4958b32.png → 2dd34393-ee6f-4b19-8a9c-76556d1bd7d7.png} +0 -0
  93. /kotonebot/kaa/sprites/{0d1918db-e000-4452-8490-ace623127e76.png → 2e00ac54-d23a-4d51-82f2-829c012552a6.png} +0 -0
  94. /kotonebot/kaa/sprites/{267fcd93-6a5c-4954-a06b-e97f327e9141.png → 2f74b04f-1992-4584-8dc6-e789b081ddc3.png} +0 -0
  95. /kotonebot/kaa/sprites/{08c2352f-0150-453a-aa0e-948dd0deef49.png → 302fde7d-de85-44c7-ba57-fe4b5f6db5fa.png} +0 -0
  96. /kotonebot/kaa/sprites/{e508161a-e595-4daf-a364-625aaf67e481.png → 3cc9685d-6347-4114-9d39-7683c2dc9df6.png} +0 -0
  97. /kotonebot/kaa/sprites/{d0c085fa-3089-4adf-979c-d4b274b32c3b.png → 42d8b5dc-ef27-4411-b8b5-d981e562990b.png} +0 -0
  98. /kotonebot/kaa/sprites/{2ef87b7f-d69e-4da2-878f-1cc35e48b15c.png → 448ea37d-a10d-4102-ac9f-a58403ee8914.png} +0 -0
  99. /kotonebot/kaa/sprites/{6dcc0bb3-984f-4c92-b0a3-74281d684182.png → 4a310bdd-0a7d-4669-9d57-6ae69bc8f022.png} +0 -0
  100. /kotonebot/kaa/sprites/{52e2b832-7837-47ca-a089-1f1593a99b08.png → 4b20b364-5f5f-4b34-960e-b0cfd08b1662.png} +0 -0
  101. /kotonebot/kaa/sprites/{34ec068a-d6fd-47ac-bd2f-0c31f93c19f3.png → 4e8f3e59-edfa-4523-939d-bc46988fc909.png} +0 -0
  102. /kotonebot/kaa/sprites/{157cfa99-d40c-48c2-8cf4-70835535522f.png → 4eaa5db2-d624-4df4-b2e4-01f72755f1a4.png} +0 -0
  103. /kotonebot/kaa/sprites/{56a70bc5-bd16-493b-b5b6-770f42f13de5.png → 5152e3fa-079c-4592-8df7-656101694df8.png} +0 -0
  104. /kotonebot/kaa/sprites/{b5009ffd-7e53-41ae-b78d-918ba0e7eda4.png → 52f7c8b1-af88-43c5-a999-de4da3caa03a.png} +0 -0
  105. /kotonebot/kaa/sprites/{465f1030-e538-4b22-a6f7-0087287b2e12.png → 534d1310-3503-46d3-8ecd-426d9bcf183e.png} +0 -0
  106. /kotonebot/kaa/sprites/{465d4e1a-c5f9-41b7-aa31-ce26d5c69c45.png → 5868ebfb-5e61-4ac6-b270-acb1e89b738f.png} +0 -0
  107. /kotonebot/kaa/sprites/{3e10014e-2063-424c-aeda-df985d351c12.png → 58a5f51d-d1a3-480b-8dde-ecead34d9f02.png} +0 -0
  108. /kotonebot/kaa/sprites/{4ffd7c97-86dd-4171-92e7-8e8e83e8f394.png → 5d3d61e9-bf13-4668-b0c7-fed730ea2ed6.png} +0 -0
  109. /kotonebot/kaa/sprites/{f4a1201f-9305-4ec5-8962-2bef0144ab46.png → 5dd0cc39-4102-4f0f-8ad3-342bbf825977.png} +0 -0
  110. /kotonebot/kaa/sprites/{dc17dea0-7749-4ecb-bbc0-1a52fb992dcf.png → 5ee8e9a8-b133-4ab7-a52c-e7e4e1d1ce7b.png} +0 -0
  111. /kotonebot/kaa/sprites/{172318e0-5e7b-4b61-9a17-6e2e66b27e69.png → 60be53a6-98e9-4fc6-9285-85506dc0e335.png} +0 -0
  112. /kotonebot/kaa/sprites/{8da0b45e-3d90-40f0-9781-c1ff4cd0e060.png → 6114d53e-dd69-4cee-82a7-7e43b338ff8d.png} +0 -0
  113. /kotonebot/kaa/sprites/{26433c9e-0ea2-4da4-9207-8f3fbad04235.png → 6156116e-56dd-4b41-a6de-ccec55dab7c8.png} +0 -0
  114. /kotonebot/kaa/sprites/{bdb09790-f702-4af2-ab67-0b3f05fd93ca.png → 65d2a5e5-48aa-4390-bb87-bfd8e044e4f6.png} +0 -0
  115. /kotonebot/kaa/sprites/{5a4a763f-b69b-4405-994d-470a78476f67.png → 66172bc0-3869-4a48-a26d-0dc3fa404ab8.png} +0 -0
  116. /kotonebot/kaa/sprites/{e0a5c772-49d3-468a-bcf5-0e3f24365253.png → 66678caa-7b25-4ff7-8c3a-017f67279349.png} +0 -0
  117. /kotonebot/kaa/sprites/{7f0783fe-89d9-4405-b7a3-6334ba543826.png → 68838f92-5916-424e-a37e-47e0b3834eb3.png} +0 -0
  118. /kotonebot/kaa/sprites/{c4fed66b-e195-4288-8b1f-ef4b0ef35174.png → 694d3a07-9697-4bda-984d-967779d530f7.png} +0 -0
  119. /kotonebot/kaa/sprites/{37e3a757-bcbc-4a37-bbf9-a38162a8627e.png → 69b022a8-e42f-4985-bd16-b4a530ad8a20.png} +0 -0
  120. /kotonebot/kaa/sprites/{5eddc669-dff6-462c-a495-81ddf951429e.png → 6aa34982-e7ab-4001-808f-8c5cf370d087.png} +0 -0
  121. /kotonebot/kaa/sprites/{428f770b-e149-417e-bb8a-38c1cba024e1.png → 7516c9a1-87ec-4d2f-ac5e-40d1aec27104.png} +0 -0
  122. /kotonebot/kaa/sprites/{63bfee9f-546e-4c3c-a82f-c2707bc62b90.png → 7aa2435c-da90-4d52-b831-88dbec57dde9.png} +0 -0
  123. /kotonebot/kaa/sprites/{d3b97b8f-f13a-413d-a097-5c456b8aea0d.png → 7b7dad18-a838-4267-b3c7-6ab43b8361f0.png} +0 -0
  124. /kotonebot/kaa/sprites/{ef539419-d100-43d5-83a1-14e65b85d816.png → 7cabdf91-2f15-4991-b165-eb9cdd557af6.png} +0 -0
  125. /kotonebot/kaa/sprites/{12356f5d-4188-4aa5-abb3-d219ca0167ca.png → 7f6cb60e-6ab3-4db4-86e1-8558250062a4.png} +0 -0
  126. /kotonebot/kaa/sprites/{1d6d5160-9525-42bf-a8d4-43c347d213eb.png → 83acbca8-3567-4262-a1e7-50f158348d45.png} +0 -0
  127. /kotonebot/kaa/sprites/{4b121018-f5c8-4c31-a5d9-48947982b191.png → 83cf48ba-d1af-4674-a52e-6bb80a626db7.png} +0 -0
  128. /kotonebot/kaa/sprites/{76c07ba7-afea-405c-806a-7691ce73f83a.png → 83f17b06-2792-4035-bc90-1800279ae131.png} +0 -0
  129. /kotonebot/kaa/sprites/{c287899b-b9a3-4ee2-a8fd-ebda89099b4b.png → 84bb4986-0295-4a45-9486-86e31fcdf1f1.png} +0 -0
  130. /kotonebot/kaa/sprites/{7b46a3e5-18d3-45a0-9500-1d7c854a12bb.png → 8b9c115b-d4ce-492e-88cb-08bd01c43570.png} +0 -0
  131. /kotonebot/kaa/sprites/{263708c5-0177-4c6a-8df3-611ec314fa56.png → 8e48af2b-c083-4480-a27c-c59c31a7ede1.png} +0 -0
  132. /kotonebot/kaa/sprites/{ced345fa-b375-457d-8b72-802424512e6c.png → 8f1e5644-1079-44b1-9d44-97bae3817bc5.png} +0 -0
  133. /kotonebot/kaa/sprites/{c94488b2-0ff0-4467-bbb0-405d3a2c55a3.png → 90def878-cd6e-46e5-9dc4-9c92dd904b80.png} +0 -0
  134. /kotonebot/kaa/sprites/{a69febc4-2d01-4628-be92-29b421604c4d.png → 920a3974-4875-4d2b-bbac-caa175c03ce0.png} +0 -0
  135. /kotonebot/kaa/sprites/{ddb2e9ee-e16a-4745-8598-b3f9c2f011be.png → 94433cf2-dd04-4b74-ae14-e5e3d945f579.png} +0 -0
  136. /kotonebot/kaa/sprites/{4ddc656f-ef7e-4580-ad12-9e382ea76e4f.png → 969eb98c-f761-4007-b8bd-2b3fb8d1f08c.png} +0 -0
  137. /kotonebot/kaa/sprites/{7d968a7f-f4a8-40a0-b9bf-e73ec1f2d7b5.png → 97adee05-1586-4589-93e6-c6c3a9cdae9d.png} +0 -0
  138. /kotonebot/kaa/sprites/{d364470a-d077-405f-a242-0d4fad32bc40.png → 9aef1aa8-41e1-42a7-83ad-b4e212ee3976.png} +0 -0
  139. /kotonebot/kaa/sprites/{9ce49f31-6b3a-4bc7-a9c8-9330d6f650f7.png → 9c7f1bcc-0bc8-454b-95fb-56a803030771.png} +0 -0
  140. /kotonebot/kaa/sprites/{99c36126-0173-49f3-a6b8-819bf9bd9306.png → 9cd7e1f1-13c4-471e-abee-223ffd9126cb.png} +0 -0
  141. /kotonebot/kaa/sprites/{370afc82-eea9-4063-afb7-5d5fec075510.png → 9d5dd50c-3341-41a4-a3dd-ccc00edcf201.png} +0 -0
  142. /kotonebot/kaa/sprites/{a5d05106-5a60-414c-972d-a886664abde4.png → 9f99b0e9-8cc0-4877-8f8a-d26257ef5386.png} +0 -0
  143. /kotonebot/kaa/sprites/{3720275d-cbf7-4513-a4a4-09f712b2286a.png → a1853223-d6b9-4660-af4e-91e59bdddc3c.png} +0 -0
  144. /kotonebot/kaa/sprites/{588f3405-4110-48dd-99ec-f89c004cf02e.png → a1bba683-a740-4eaf-8c37-3b1042b963b0.png} +0 -0
  145. /kotonebot/kaa/sprites/{60e43a33-18ee-45f1-bd9a-57bb6539611b.png → a1cf80ee-64bf-4d54-a7db-ffadf3c97026.png} +0 -0
  146. /kotonebot/kaa/sprites/{14cc953d-0ff6-493f-9478-691b5cbd0d07.png → a3b15425-0bfd-4668-a3a9-2ab64da8505f.png} +0 -0
  147. /kotonebot/kaa/sprites/{f400e1fe-a04d-442b-a6de-a448813443fd.png → a4075991-98da-4d06-bcde-28054cd124d2.png} +0 -0
  148. /kotonebot/kaa/sprites/{cecd2638-070f-4710-9142-2dc492660241.png → a7da51c2-8444-4770-a16b-b6543e40197f.png} +0 -0
  149. /kotonebot/kaa/sprites/{9d7a7bbb-b48b-458c-9964-963a57e10a7d.png → a8b3fdce-9e4a-495c-839e-0142f67fee69.png} +0 -0
  150. /kotonebot/kaa/sprites/{e55da40e-5fb5-48e0-91b1-2db0b3b32750.png → aa3b717f-67f8-445f-a6bf-b89f7200d95b.png} +0 -0
  151. /kotonebot/kaa/sprites/{8cc764de-f162-40a4-ba6f-40d60eac5633.png → abcc709c-1f4d-4832-a063-eafbad94ac31.png} +0 -0
  152. /kotonebot/kaa/sprites/{e6e66cdf-69c8-4862-a770-1f81c62f96ac.png → ad172750-d1a6-4a25-8ce8-9483f4b5affb.png} +0 -0
  153. /kotonebot/kaa/sprites/{eb229797-bffc-4a48-96de-85480af1608a.png → aefdec38-e3b6-4762-aed8-33107686ddac.png} +0 -0
  154. /kotonebot/kaa/sprites/{23217053-c549-4ac7-b8c0-3324728e6acd.png → b01c25d2-21bf-4db9-b5b2-ec35817f1b04.png} +0 -0
  155. /kotonebot/kaa/sprites/{9d908390-6f0f-46e6-a8fc-a7dfe23eda18.png → b1e7f24e-f246-406e-9073-58e2f3e4e819.png} +0 -0
  156. /kotonebot/kaa/sprites/{863550ee-e9b8-4aa2-8ebb-e906b09dde3b.png → b5d4265c-82e0-470d-a48e-8aa4edbdef5a.png} +0 -0
  157. /kotonebot/kaa/sprites/{608de0a3-ce93-4344-8f9b-3cb3fab5ad12.png → b65724b4-ec8f-48a9-9ab2-e7ce5b8f35b2.png} +0 -0
  158. /kotonebot/kaa/sprites/{22ab93e6-0192-48e1-a85f-73ee8db00395.png → b8aada91-eedd-4c53-99f3-f903d547235e.png} +0 -0
  159. /kotonebot/kaa/sprites/{09a01092-0d32-4894-a47e-9983b39753df.png → ba759205-ce99-4417-8cab-d32fe55dff4c.png} +0 -0
  160. /kotonebot/kaa/sprites/{934e5383-b63c-472e-afdb-d184c92bdfe3.png → bb0ae68d-44d5-47c6-91dd-a529bc34225b.png} +0 -0
  161. /kotonebot/kaa/sprites/{55d105dc-c488-47d8-9b95-aba5707cfc2a.png → bed9575d-ccad-4f4e-825e-47b2a9cb0925.png} +0 -0
  162. /kotonebot/kaa/sprites/{3a0e917b-f419-4398-8638-77f696d47cd4.png → bfec58df-2628-454f-92aa-769cad186448.png} +0 -0
  163. /kotonebot/kaa/sprites/{1e9e795c-5dc1-4851-8d49-86181b9f4efe.png → c25c7ce5-ad8d-4b2c-83eb-ae6d4871a6c3.png} +0 -0
  164. /kotonebot/kaa/sprites/{c30d08f7-5c07-487a-86c3-122c082bb07b.png → c3ec61aa-f62e-46fd-b359-48864ea7a150.png} +0 -0
  165. /kotonebot/kaa/sprites/{685a7a90-8196-4a6a-a67a-4e7078965982.png → c484ca57-6b19-46b5-a107-1805a7488d48.png} +0 -0
  166. /kotonebot/kaa/sprites/{9e74a9e6-6ea5-4551-9578-8e561195bd3d.png → c571e1c0-ff85-4b2e-97ed-97d33b8d92e3.png} +0 -0
  167. /kotonebot/kaa/sprites/{a2ea2e0f-4f92-4769-9bc4-1ee10c43712c.png → c5e16f75-9b5a-4853-a144-275f3d20c186.png} +0 -0
  168. /kotonebot/kaa/sprites/{37f421f8-f615-43d1-a10f-f9a915a940d1.png → c5ea3dfd-6761-466e-b44c-86592ef05323.png} +0 -0
  169. /kotonebot/kaa/sprites/{276a66cc-95b1-4f86-b700-afa9c9f18149.png → ca2adfb8-1e88-4a31-b3cc-1f70568ce4a3.png} +0 -0
  170. /kotonebot/kaa/sprites/{bbfcc1ea-b441-4e81-85d2-52ce3bf4eb62.png → cb24b3df-1ec3-4ffd-95f1-ca4b0dd5b7da.png} +0 -0
  171. /kotonebot/kaa/sprites/{9f6aef36-f2e5-4208-9748-b6bbdb5546fd.png → cdbbb5ba-5117-488a-8172-48cfc92c14c6.png} +0 -0
  172. /kotonebot/kaa/sprites/{3851e552-fd41-4a15-a6b6-9636c773f67a.png → cf66ae12-48bc-4512-a988-0e5de337c76d.png} +0 -0
  173. /kotonebot/kaa/sprites/{74db3d1c-d6be-4d1f-92be-9bb3ffad7f51.png → d1699baa-467b-46d1-9276-aae78fe8f589.png} +0 -0
  174. /kotonebot/kaa/sprites/{8383a31c-a075-4b5f-b839-cbeb63a7aef3.png → d3e6e2e9-c5b5-463f-98f4-de72c9320d9d.png} +0 -0
  175. /kotonebot/kaa/sprites/{51b836ff-5f2c-4612-85f1-9db74761f300.png → d4c47cc7-5b3e-4c3e-8e80-78cb94e7eed9.png} +0 -0
  176. /kotonebot/kaa/sprites/{2e0f97d4-ce0b-4930-addd-cbdaedffc918.png → d5d854fc-1b87-43d4-b32d-66eccb66fa41.png} +0 -0
  177. /kotonebot/kaa/sprites/{593f4c04-4ca4-4bb0-8fea-ad3af32316f7.png → d60a395b-d907-416a-b091-36bfee4948b3.png} +0 -0
  178. /kotonebot/kaa/sprites/{19fae7eb-addd-4ea2-99ac-0f9262a4d9d6.png → dad4ff8c-07f4-4b07-abd3-5d02bbcc4562.png} +0 -0
  179. /kotonebot/kaa/sprites/{8778f70d-6bb8-4378-aed7-d77c798ab032.png → dbd537c7-d1d3-4d64-9ccd-43dd4519bedd.png} +0 -0
  180. /kotonebot/kaa/sprites/{7250e776-3195-406c-ac6f-ec7dbed49cbe.png → dde03640-6c3a-4b13-a783-f672816bfec4.png} +0 -0
  181. /kotonebot/kaa/sprites/{4b87be27-868a-40fb-b7e4-67c963c6c4b2.png → df97421e-4b74-430e-b3d1-ed9bac6918a7.png} +0 -0
  182. /kotonebot/kaa/sprites/{7079f76b-e2a3-487c-8616-28ce505f5a0e.png → dfb14c98-f672-4906-80bd-d2a18bdd62cd.png} +0 -0
  183. /kotonebot/kaa/sprites/{b3f1b38f-77d0-4dd5-8c19-8a35bbc39516.png → e1e0d751-9006-4fa4-a933-4c0dc5e1f3d2.png} +0 -0
  184. /kotonebot/kaa/sprites/{aa8c4533-bd58-496e-a460-6fa47f7ded83.png → e394ff91-09d3-41e1-bbf5-bc42a71a623b.png} +0 -0
  185. /kotonebot/kaa/sprites/{72b7124a-baf2-4d60-9553-2634370a6d49.png → e5259dfb-3a49-4cfc-9f89-b42958ce6eec.png} +0 -0
  186. /kotonebot/kaa/sprites/{c072da5f-bd35-4e8b-8f32-6c5df18c3aea.png → e5eeb9af-8003-4981-bf56-2e32e76cec5d.png} +0 -0
  187. /kotonebot/kaa/sprites/{46ed11a3-f89e-4d5c-b534-da88d38b382b.png → e9c45a73-2011-4584-87b7-c4e566eba87f.png} +0 -0
  188. /kotonebot/kaa/sprites/{e3cfea3a-3dc4-412b-b226-f9034f5b51f1.png → eae83523-e58c-4db9-a356-4335a5da3dc8.png} +0 -0
  189. /kotonebot/kaa/sprites/{f3b4bb3b-f8d6-4ed0-8bde-0d3322bd8391.png → ed6d3e3d-0f04-4fa4-b0f9-fdbf324649f6.png} +0 -0
  190. /kotonebot/kaa/sprites/{fe031296-8000-4fdc-ab3f-b4aae2af6e5d.png → efb28e1d-7b52-4e20-aec5-117c798b7fbe.png} +0 -0
  191. /kotonebot/kaa/sprites/{b4afb6bd-e049-4b2e-b1ca-26333c7afcb0.png → f025027f-daa0-4943-8395-5d7d44cc7f15.png} +0 -0
  192. /kotonebot/kaa/sprites/{cd53bad6-81fa-4e15-8fe7-5a992367bf90.png → f12c2b0b-8273-4197-a8c6-2a8ef2788a9b.png} +0 -0
  193. /kotonebot/kaa/sprites/{86bcda3a-c7a6-4abf-ae4c-968788f3c667.png → f528ea0e-1e55-4e41-844f-bb1db9185ef8.png} +0 -0
  194. /kotonebot/kaa/sprites/{9b798f35-e745-4964-931d-3e0ae811174d.png → f611bbd9-c062-4989-96a4-65ff6c59673c.png} +0 -0
  195. /kotonebot/kaa/sprites/{de0b3d75-7dc8-4433-a275-2584e9d7ed0b.png → f6bfbf6a-6e53-4563-9345-3f3756d6ea9a.png} +0 -0
  196. /kotonebot/kaa/sprites/{6e338dd7-6834-4e9b-8ac1-afecdff16c43.png → f72bd3d6-850d-4190-9775-938f474d263c.png} +0 -0
  197. /kotonebot/kaa/sprites/{86501f18-e5fd-4a66-a360-20e34935f1a9.png → f8eec9b2-55ca-4195-b098-a5393d02a98a.png} +0 -0
  198. /kotonebot/kaa/sprites/{a1a03d83-6a3b-481a-a807-931f2b0f7cd2.png → faf069e1-f623-47c1-b879-cfa246fbc7df.png} +0 -0
  199. /kotonebot/kaa/sprites/{8e04cb5c-ce45-49d9-81a9-2e5f717d3eb2.png → faf360e8-7845-4fcf-b0a6-0f5f93c050f1.png} +0 -0
  200. {ksaa-2025.5.23.3.dist-info → ksaa-2025.6.23.0.dist-info}/WHEEL +0 -0
  201. {ksaa-2025.5.23.3.dist-info → ksaa-2025.6.23.0.dist-info}/entry_points.txt +0 -0
  202. {ksaa-2025.5.23.3.dist-info → ksaa-2025.6.23.0.dist-info}/top_level.txt +0 -0
@@ -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.kaa.image_db import ImageDatabase, HistDescriptor, FileDataSource
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
- from kotonebot.util import cv2_imread
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
- # 使用runpy运行remote_windows.py模块
94
- sys.argv = ['remote_windows.py', f'--host={args.host}', f'--port={args.port}']
95
- runpy.run_module('kotonebot.client.implements.remote_windows', run_name='__main__')
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}')
@@ -1,11 +1,18 @@
1
+ from importlib import resources
1
2
  from typing_extensions import override
2
3
 
3
- from kotonebot.client import Device, create_device
4
- from kotonebot.client import DeviceImpl, Device
4
+ from kotonebot.client import Device, DeviceImpl
5
+ from kotonebot.client.registration import create_device
6
+ from kotonebot.client.implements.windows import WindowsImplConfig
7
+ from kotonebot.client.implements.remote_windows import RemoteWindowsImplConfig
5
8
  from kotonebot.client.host import HostProtocol, Instance
9
+ from kotonebot.client.host.protocol import WindowsHostConfig, RemoteWindowsHostConfig
10
+
11
+
12
+ DmmHostConfigs = WindowsHostConfig | RemoteWindowsHostConfig
6
13
 
7
14
  # TODO: 可能应该把 start_game 和 end_game 里对启停的操作移动到这里来
8
- class DmmInstance(Instance):
15
+ class DmmInstance(Instance[DmmHostConfigs]):
9
16
  def __init__(self):
10
17
  super().__init__('dmm', 'gakumas')
11
18
 
@@ -30,10 +37,29 @@ class DmmInstance(Instance):
30
37
  raise NotImplementedError()
31
38
 
32
39
  @override
33
- def create_device(self, impl: DeviceImpl, *, timeout: float = 180) -> Device:
34
- if impl not in ['windows', 'remote_windows']:
35
- raise ValueError(f'Unsupported device implementation: {impl}')
36
- return create_device('', impl, timeout=timeout)
40
+ def create_device(self, impl: DeviceImpl, host_config: DmmHostConfigs) -> Device:
41
+ if impl == 'windows':
42
+ assert isinstance(host_config, WindowsHostConfig)
43
+ win_config = WindowsImplConfig(
44
+ window_title=host_config.window_title,
45
+ ahk_exe_path=host_config.ahk_exe_path
46
+ )
47
+ return create_device(impl, win_config)
48
+
49
+ elif impl == 'remote_windows':
50
+ assert isinstance(host_config, RemoteWindowsHostConfig)
51
+ config = RemoteWindowsImplConfig(
52
+ windows_impl_config=WindowsImplConfig(
53
+ window_title=host_config.windows_host_config.window_title,
54
+ ahk_exe_path=host_config.windows_host_config.ahk_exe_path
55
+ ),
56
+ host=host_config.host,
57
+ port=host_config.port
58
+ )
59
+ return create_device(impl, config)
60
+
61
+ else:
62
+ raise ValueError(f'Unsupported impl for DMM: {impl}')
37
63
 
38
64
  class DmmHost(HostProtocol):
39
65
  instance = DmmInstance()
kotonebot/kaa/main/gr.py CHANGED
@@ -15,6 +15,7 @@ from kotonebot.kaa.db import IdolCard
15
15
  from kotonebot.config.manager import load_config, save_config
16
16
  from kotonebot.config.base_config import UserConfig, BackendConfig
17
17
  from kotonebot.backend.context import task_registry, ContextStackVars
18
+ from kotonebot.backend.context.context import vars
18
19
  from kotonebot.client.host import Mumu12Host, LeidianHost
19
20
  from kotonebot.kaa.common import (
20
21
  BaseConfig, APShopItems, CapsuleToysConfig, ClubRewardConfig, PurchaseConfig, ActivityFundsConfig,
@@ -69,12 +70,14 @@ ConfigKey = Literal[
69
70
  'anomaly_capsule_toys_count',
70
71
 
71
72
  # start game
72
- 'start_game_enabled', 'start_through_kuyo',
73
+ 'start_game_enabled', 'start_through_kuyo',
73
74
  'game_package_name', 'kuyo_package_name',
74
-
75
+ 'disable_gakumas_localify', 'dmm_game_path',
76
+
75
77
  # end game
76
- 'exit_kaa', 'kill_game', 'kill_dmm',
78
+ 'exit_kaa', 'kill_game', 'kill_dmm',
77
79
  'kill_emulator', 'shutdown', 'hibernate',
80
+ 'restore_gakumas_localify',
78
81
 
79
82
  'activity_funds',
80
83
  'presents',
@@ -180,6 +183,8 @@ class KotoneBotUI:
180
183
  def __init__(self, kaa: Kaa) -> None:
181
184
  self.is_running: bool = False
182
185
  self.single_task_running: bool = False
186
+ self.is_stopping: bool = False # 新增:标记是否正在停止过程中
187
+ self.is_single_task_stopping: bool = False # 新增:标记单个任务是否正在停止
183
188
  self._kaa = kaa
184
189
  self._load_config()
185
190
  self._setup_kaa()
@@ -230,14 +235,20 @@ class KotoneBotUI:
230
235
 
231
236
  return f"已导出到 {zip_filename}"
232
237
 
233
- def get_button_status(self) -> str:
238
+ def get_button_status(self) -> Tuple[str, bool]:
239
+ """获取按钮状态和交互性"""
234
240
  if not hasattr(self, 'run_status'):
235
- return "启动"
241
+ return "启动", True
236
242
 
237
243
  if not self.run_status.running:
238
244
  self.is_running = False
239
- return "启动"
240
- return "停止"
245
+ self.is_stopping = False # 重置停止状态
246
+ return "启动", True
247
+
248
+ if self.is_stopping:
249
+ return "停止中...", False # 停止中时禁用按钮
250
+
251
+ return "停止", True
241
252
 
242
253
  def update_task_status(self) -> List[List[str]]:
243
254
  status_list: List[List[str]] = []
@@ -260,6 +271,11 @@ class KotoneBotUI:
260
271
  def toggle_run(self) -> Tuple[str, List[List[str]]]:
261
272
  if not self.is_running:
262
273
  return self.start_run()
274
+
275
+ # 如果正在停止过程中,忽略重复点击
276
+ if self.is_stopping:
277
+ return "停止中...", self.update_task_status()
278
+
263
279
  return self.stop_run()
264
280
 
265
281
  def start_run(self) -> Tuple[str, List[List[str]]]:
@@ -268,10 +284,19 @@ class KotoneBotUI:
268
284
  return "停止", self.update_task_status()
269
285
 
270
286
  def stop_run(self) -> Tuple[str, List[List[str]]]:
287
+ self.is_stopping = True # 设置停止状态
288
+
289
+ # 如果当前处于暂停状态,先恢复再停止
290
+ if vars.flow.is_paused:
291
+ gr.Info("检测到任务暂停,正在恢复后停止...")
292
+ vars.flow.request_resume()
293
+
271
294
  self.is_running = False
272
295
  if self._kaa:
273
296
  self.run_status.interrupt()
274
- return "启动", self.update_task_status()
297
+ gr.Info("正在停止任务...")
298
+
299
+ return "停止中...", self.update_task_status()
275
300
 
276
301
  def start_single_task(self, task_name: str) -> Tuple[str, str]:
277
302
  if not task_name:
@@ -292,11 +317,48 @@ class KotoneBotUI:
292
317
  return "停止任务", f"正在执行任务: {task_name}"
293
318
 
294
319
  def stop_single_task(self) -> Tuple[str, str]:
320
+ self.is_single_task_stopping = True # 设置单个任务停止状态
321
+
322
+ # 如果当前处于暂停状态,先恢复再停止
323
+ if vars.flow.is_paused:
324
+ gr.Info("检测到任务暂停,正在恢复后停止...")
325
+ vars.flow.request_resume()
326
+
295
327
  self.single_task_running = False
296
328
  if hasattr(self, 'run_status') and self._kaa:
297
329
  self.run_status.interrupt()
298
- gr.Info("任务已停止")
299
- return "执行任务", "任务已停止"
330
+ gr.Info("正在停止任务...")
331
+ return "停止中...", "正在停止任务..."
332
+
333
+ def toggle_pause(self) -> str:
334
+ """切换暂停/恢复状态"""
335
+ if vars.flow.is_paused:
336
+ vars.flow.request_resume()
337
+ gr.Info("任务已恢复")
338
+ return "暂停"
339
+ else:
340
+ vars.flow.request_pause()
341
+ gr.Info("任务已暂停")
342
+ return "恢复"
343
+
344
+ def get_pause_button_status(self) -> str:
345
+ """获取暂停按钮的状态"""
346
+ if vars.flow.is_paused:
347
+ return "恢复"
348
+ else:
349
+ return "暂停"
350
+
351
+ def get_pause_button_with_interactive(self) -> gr.Button:
352
+ """获取暂停按钮的状态和交互性"""
353
+ try:
354
+ text = "恢复" if vars.flow.is_paused else "暂停"
355
+ except ValueError:
356
+ # ValueError: Forwarded object vars called before initialization.
357
+ # TODO: vars.flow.is_paused 应该要可以在脚本正式启动前就能访问
358
+ text = '未启动'
359
+ # 如果正在停止过程中,禁用暂停按钮
360
+ interactive = not (self.is_stopping or self.is_single_task_stopping)
361
+ return gr.Button(value=text, interactive=interactive)
300
362
 
301
363
  def save_settings2(self, return_values: list[ConfigBuilderReturnValue], *args) -> str:
302
364
  options = BaseConfig()
@@ -326,7 +388,8 @@ class KotoneBotUI:
326
388
  gr.Markdown("## 状态")
327
389
 
328
390
  with gr.Row():
329
- run_btn = gr.Button("启动", scale=1)
391
+ run_btn = gr.Button("启动", scale=2)
392
+ pause_btn = gr.Button("暂停", scale=1)
330
393
  if self._kaa.upgrade_msg:
331
394
  gr.Markdown('### 配置升级报告')
332
395
  gr.Markdown(self._kaa.upgrade_msg)
@@ -338,19 +401,39 @@ class KotoneBotUI:
338
401
  label="任务状态"
339
402
  )
340
403
 
341
- def on_run_click(evt: gr.EventData) -> Tuple[str, List[List[str]]]:
342
- return self.toggle_run()
404
+ def on_run_click(evt: gr.EventData) -> Tuple[gr.Button, List[List[str]]]:
405
+ result = self.toggle_run()
406
+ # 如果正在停止,禁用按钮
407
+ interactive = not self.is_stopping
408
+ button = gr.Button(value=result[0], interactive=interactive)
409
+ return button, result[1]
410
+
411
+ def on_pause_click(evt: gr.EventData) -> str:
412
+ return self.toggle_pause()
343
413
 
344
414
  run_btn.click(
345
415
  fn=on_run_click,
346
416
  outputs=[run_btn, task_status]
347
417
  )
348
418
 
419
+ pause_btn.click(
420
+ fn=on_pause_click,
421
+ outputs=[pause_btn]
422
+ )
423
+
349
424
  # 添加定时器,分别更新按钮状态和任务状态
425
+ def update_run_button_status():
426
+ text, interactive = self.get_button_status()
427
+ return gr.Button(value=text, interactive=interactive)
428
+
350
429
  gr.Timer(1.0).tick(
351
- fn=self.get_button_status,
430
+ fn=update_run_button_status,
352
431
  outputs=[run_btn]
353
432
  )
433
+ gr.Timer(1.0).tick(
434
+ fn=self.get_pause_button_with_interactive,
435
+ outputs=[pause_btn]
436
+ )
354
437
  gr.Timer(1.0).tick(
355
438
  fn=self.update_task_status,
356
439
  outputs=[task_status]
@@ -370,21 +453,34 @@ class KotoneBotUI:
370
453
  value=None
371
454
  )
372
455
 
373
- # 创建执行按钮
374
- execute_btn = gr.Button("执行任务")
456
+ # 创建执行按钮和暂停按钮
457
+ with gr.Row():
458
+ execute_btn = gr.Button("执行任务", scale=2)
459
+ pause_btn = gr.Button("暂停", scale=1)
375
460
  task_result = gr.Markdown("")
376
461
 
377
- def toggle_single_task(task_name: str) -> Tuple[str, str]:
462
+ def toggle_single_task(task_name: str) -> Tuple[gr.Button, str]:
378
463
  if self.single_task_running:
379
- return self.stop_single_task()
464
+ # 如果正在停止过程中,忽略重复点击
465
+ if self.is_single_task_stopping:
466
+ return gr.Button(value="停止中...", interactive=False), "正在停止任务..."
467
+
468
+ result = self.stop_single_task()
469
+ return gr.Button(value=result[0], interactive=False), result[1]
380
470
  else:
381
- return self.start_single_task(task_name)
471
+ result = self.start_single_task(task_name)
472
+ return gr.Button(value=result[0], interactive=True), result[1]
382
473
 
383
- def get_task_button_status() -> str:
474
+ def get_task_button_status() -> gr.Button:
384
475
  if not hasattr(self, 'run_status') or not self.run_status.running:
385
476
  self.single_task_running = False
386
- return "执行任务"
387
- return "停止任务"
477
+ self.is_single_task_stopping = False # 重置停止状态
478
+ return gr.Button(value="执行任务", interactive=True)
479
+
480
+ if self.is_single_task_stopping:
481
+ return gr.Button(value="停止中...", interactive=False) # 停止中时禁用按钮
482
+
483
+ return gr.Button(value="停止任务", interactive=True)
388
484
 
389
485
  def get_single_task_status() -> str:
390
486
  if not hasattr(self, 'run_status'):
@@ -417,17 +513,29 @@ class KotoneBotUI:
417
513
 
418
514
  return ""
419
515
 
516
+ def on_pause_click(evt: gr.EventData) -> str:
517
+ return self.toggle_pause()
518
+
420
519
  execute_btn.click(
421
520
  fn=toggle_single_task,
422
521
  inputs=[task_dropdown],
423
522
  outputs=[execute_btn, task_result]
424
523
  )
425
524
 
525
+ pause_btn.click(
526
+ fn=on_pause_click,
527
+ outputs=[pause_btn]
528
+ )
529
+
426
530
  # 添加定时器更新按钮状态和任务状态
427
531
  gr.Timer(1.0).tick(
428
532
  fn=get_task_button_status,
429
533
  outputs=[execute_btn]
430
534
  )
535
+ gr.Timer(1.0).tick(
536
+ fn=self.get_pause_button_with_interactive,
537
+ outputs=[pause_btn]
538
+ )
431
539
  gr.Timer(1.0).tick(
432
540
  fn=get_single_task_status,
433
541
  outputs=[task_result]
@@ -1106,6 +1214,17 @@ class KotoneBotUI:
1106
1214
  label="Kuyo包名",
1107
1215
  info=StartGameConfig.model_fields['kuyo_package_name'].description
1108
1216
  )
1217
+ disable_gakumas_localify = gr.Checkbox(
1218
+ label="禁用 Gakumas Localify 汉化插件",
1219
+ value=self.current_config.options.start_game.disable_gakumas_localify,
1220
+ info=StartGameConfig.model_fields['disable_gakumas_localify'].description
1221
+ )
1222
+ dmm_game_path = gr.Textbox(
1223
+ value=self.current_config.options.start_game.dmm_game_path or "",
1224
+ label="DMM 版游戏路径",
1225
+ info=StartGameConfig.model_fields['dmm_game_path'].description,
1226
+ placeholder="例:F:\\Games\\gakumas\\gakumas.exe"
1227
+ )
1109
1228
  start_game_enabled.change(
1110
1229
  fn=lambda x: gr.Group(visible=x),
1111
1230
  inputs=[start_game_enabled],
@@ -1117,12 +1236,16 @@ class KotoneBotUI:
1117
1236
  config.start_game.start_through_kuyo = data['start_through_kuyo']
1118
1237
  config.start_game.game_package_name = data['game_package_name']
1119
1238
  config.start_game.kuyo_package_name = data['kuyo_package_name']
1120
-
1239
+ config.start_game.disable_gakumas_localify = data['disable_gakumas_localify']
1240
+ config.start_game.dmm_game_path = data['dmm_game_path'] if data['dmm_game_path'] else None
1241
+
1121
1242
  return set_config, {
1122
1243
  'start_game_enabled': start_game_enabled,
1123
1244
  'start_through_kuyo': start_through_kuyo,
1124
1245
  'game_package_name': game_package_name,
1125
- 'kuyo_package_name': kuyo_package_name
1246
+ 'kuyo_package_name': kuyo_package_name,
1247
+ 'disable_gakumas_localify': disable_gakumas_localify,
1248
+ 'dmm_game_path': dmm_game_path
1126
1249
  }
1127
1250
 
1128
1251
 
@@ -1160,6 +1283,11 @@ class KotoneBotUI:
1160
1283
  value=self.current_config.options.end_game.hibernate,
1161
1284
  info=EndGameConfig.model_fields['hibernate'].description
1162
1285
  )
1286
+ restore_gakumas_localify = gr.Checkbox(
1287
+ label="恢复 Gakumas Localify 汉化插件状态",
1288
+ value=self.current_config.options.end_game.restore_gakumas_localify,
1289
+ info=EndGameConfig.model_fields['restore_gakumas_localify'].description
1290
+ )
1163
1291
 
1164
1292
  def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
1165
1293
  config.end_game.exit_kaa = data['exit_kaa']
@@ -1168,14 +1296,16 @@ class KotoneBotUI:
1168
1296
  config.end_game.kill_emulator = data['kill_emulator']
1169
1297
  config.end_game.shutdown = data['shutdown']
1170
1298
  config.end_game.hibernate = data['hibernate']
1171
-
1299
+ config.end_game.restore_gakumas_localify = data['restore_gakumas_localify']
1300
+
1172
1301
  return set_config, {
1173
1302
  'exit_kaa': exit_kaa,
1174
1303
  'kill_game': kill_game,
1175
1304
  'kill_dmm': kill_dmm,
1176
1305
  'kill_emulator': kill_emulator,
1177
1306
  'shutdown': shutdown,
1178
- 'hibernate': hibernate
1307
+ 'hibernate': hibernate,
1308
+ 'restore_gakumas_localify': restore_gakumas_localify
1179
1309
  }
1180
1310
 
1181
1311
  def _create_activity_funds_settings(self) -> ConfigBuilderReturnValue: